]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'todor/release/qcomlt-4.4-camss-demo2' into release...
authorNicolas Dechesne <nicolas.dechesne@linaro.org>
Thu, 23 Jun 2016 20:35:25 +0000 (22:35 +0200)
committerNicolas Dechesne <nicolas.dechesne@linaro.org>
Thu, 23 Jun 2016 20:35:25 +0000 (22:35 +0200)
103 files changed:
.gitignore
Documentation/devicetree/bindings/clock/qcom,rpmcc.txt
Documentation/devicetree/bindings/sound/qcom,msm8916-wcd.txt [new file with mode: 0644]
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval-pins.dtsi [moved from arch/arm/boot/dts/qcom-apq8064-arrow-db600c-pins.dtsi with 70% similarity]
arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts [moved from arch/arm/boot/dts/qcom-apq8064-arrow-db600c.dts with 89% similarity]
arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
arch/arm/boot/dts/qcom-apq8064.dtsi
arch/arm/configs/qcom_defconfig
arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
arch/arm64/boot/dts/qcom/msm8916-bus.dtsi
arch/arm64/boot/dts/qcom/msm8916-coresight.dtsi
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/boot/dts/qcom/pm8916.dtsi
arch/arm64/configs/defconfig
drivers/bluetooth/Kconfig
drivers/bluetooth/btqcomsmd.c
drivers/clk/qcom/Kconfig
drivers/clk/qcom/Makefile
drivers/clk/qcom/clk-rpm.c
drivers/clk/qcom/clk-rpm.h [deleted file]
drivers/clk/qcom/clk-smd-rpm.c
drivers/clk/qcom/clk-smd-rpm.h [deleted file]
drivers/firmware/qcom_scm-32.c
drivers/firmware/qcom_scm-64.c
drivers/firmware/qcom_scm.c
drivers/firmware/qcom_scm.h
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-qcom-smp2p.c [deleted file]
drivers/gpio/gpio-qcom-smsm.c [deleted file]
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi.h
drivers/gpu/drm/msm/mdp/mdp_format.c
drivers/mmc/host/sdhci-msm.c
drivers/net/wireless/ath/wcn36xx/Kconfig
drivers/net/wireless/ath/wcn36xx/Makefile
drivers/net/wireless/ath/wcn36xx/dxe.c
drivers/net/wireless/ath/wcn36xx/dxe.h
drivers/net/wireless/ath/wcn36xx/hal.h
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/smd.h
drivers/net/wireless/ath/wcn36xx/txrx.c
drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c [deleted file]
drivers/net/wireless/ath/wcn36xx/wcn36xx.h
drivers/net/wireless/ath/wcn36xx/wcnss_core.c [deleted file]
drivers/net/wireless/ath/wcn36xx/wcnss_core.h [deleted file]
drivers/regulator/qcom_smd-regulator.c
drivers/remoteproc/Kconfig
drivers/remoteproc/Makefile
drivers/remoteproc/qcom_mdt_loader.c [new file with mode: 0644]
drivers/remoteproc/qcom_mdt_loader.h [new file with mode: 0644]
drivers/remoteproc/qcom_q6v5_pil.c
drivers/remoteproc/qcom_tz_pil.c
drivers/remoteproc/qcom_wcnss.c [new file with mode: 0644]
drivers/remoteproc/qcom_wcnss.h [new file with mode: 0644]
drivers/remoteproc/qcom_wcnss_iris.c [new file with mode: 0644]
drivers/remoteproc/remoteproc_debugfs.c
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/gps_proxy.c [new file with mode: 0644]
drivers/soc/qcom/ipcrtr_stub.c [deleted file]
drivers/soc/qcom/smd-rpm.c
drivers/soc/qcom/smd.c
drivers/soc/qcom/smem.c
drivers/soc/qcom/wcnss_ctrl.c
drivers/spi/spi-qup.c
drivers/tty/serial/msm_serial.c
include/dt-bindings/clock/qcom,rpmcc.h
include/dt-bindings/sound/msm8916-wcd.h [new file with mode: 0644]
include/linux/qcom_scm.h
include/linux/soc/qcom/smd.h
include/linux/soc/qcom/wcnss_ctrl.h [new file with mode: 0644]
include/linux/socket.h
include/net/kcm.h [new file with mode: 0644]
include/net/mac80211.h
include/sound/soc.h
include/uapi/linux/gps_proxy.h [new file with mode: 0644]
include/uapi/linux/kcm.h [new file with mode: 0644]
include/uapi/linux/qrtr.h [new file with mode: 0644]
kernel/configs/debug.config [new file with mode: 0644]
kernel/configs/distro.config
net/Kconfig
net/Makefile
net/kcm/Kconfig [new file with mode: 0644]
net/kcm/Makefile [new file with mode: 0644]
net/kcm/kcmsock.c [new file with mode: 0644]
net/qrtr/Kconfig [new file with mode: 0644]
net/qrtr/Makefile [new file with mode: 0644]
net/qrtr/qrtr.c [new file with mode: 0644]
net/qrtr/qrtr.h [new file with mode: 0644]
net/qrtr/smd.c [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/msm8916-wcd-registers.h [new file with mode: 0644]
sound/soc/codecs/msm8916-wcd.c [new file with mode: 0644]
sound/soc/codecs/msm8916-wcd.h [new file with mode: 0644]
sound/soc/codecs/msm8x16-wcd-tables.c [deleted file]
sound/soc/codecs/msm8x16-wcd.c [deleted file]
sound/soc/codecs/msm8x16-wcd.h [deleted file]
sound/soc/codecs/msm8x16_wcd_registers.h [deleted file]
sound/soc/qcom/qdsp6/core/apr_tal.c

index fd3a355925432f58c1bcf84b16ec3ec8bc8c5457..18d3c2a10a3f836b8938bfd9f182f8f5b2c728ea 100644 (file)
@@ -55,6 +55,8 @@ Module.symvers
 # Debian directory (make deb-pkg)
 #
 /debian/
+/*.deb
+/*.changes
 
 #
 # tar directory (make tar*-pkg)
index 5904902862de620696ed2f2998491850660357f9..87d3714b956a281e4e8ea68d086d11a5f9a09516 100644 (file)
@@ -11,9 +11,7 @@ Required properties :
                compatible "qcom,rpmcc" should be also included.
 
                        "qcom,rpmcc-msm8916", "qcom,rpmcc"
-                       "qcom,rpmcc-msm8974", "qcom,rpmcc"
                        "qcom,rpmcc-apq8064", "qcom,rpmcc"
-                       "qcom,rpmcc-apq8084", "qcom,rpmcc"
 
 - #clock-cells : shall contain 1
 
@@ -30,7 +28,7 @@ Example:
                                compatible = "qcom,rpm-msm8916";
                                qcom,smd-channels = "rpm_requests";
 
-                               rpmcc: qcom,rpmcc {
+                               rpmcc: clock-controller {
                                        compatible = "qcom,rpmcc-msm8916", "qcom,rpmcc";
                                        #clock-cells = <1>;
                                };
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd.txt
new file mode 100644 (file)
index 0000000..4e3826d
--- /dev/null
@@ -0,0 +1,101 @@
+msm8916 audio CODEC aka Tombak audio CODEC
+
+Codec IP is divided into two parts, first analog which is integrated in pmic pm8916
+and secondly digital part which is integrated into application processor. Codec register
+controls are also split across pmic an lpass. Analog part is controlled via spmi bus to pmic.
+
+## Bindings for codec core on pmic:
+
+Required properties
+ - compatible = "qcom,msm8916-wcd-codec";
+ - reg: represents the slave base address provided to the peripheral.
+ - interrupt-parent : The parent interrupt controller.
+ - interrupts: List of interrupts in given SPMI peripheral.
+ - interrupt-names: Names specified to above list of interrupts in same
+                   order. List of supported interrupt names are:
+  "spk_cnp_int" - Speaker click and pop interrupt
+  "spk_clip_int" - Speaker clip interrupt
+  "spk_ocp_int" - Speaker over current protect interrupt.
+  "ins_rem_det1" - jack insert removal detect interrupt 1.
+  "but_rel_det" - button release interrupt
+  "but_press_det" - button press event
+  "ins_rem_det" - jack insert removal detect interrup
+  "mbhc_int"   - multi button headset interrupt.
+  "ear_ocp_int" - Earphone over current protect interrupt.
+  "hphr_ocp_int" - Headphone R over current protect interrupt.
+  "hphl_ocp_det" - Headphone L over current protect interrupt
+  "ear_cnp_int" - earphone cnp interrupt.
+  "hphr_cnp_int" - hphr click and pop interrupt.
+  "hphl_cnp_int" - hphl click and pop interrupt
+
+ - vddio-supply: phandle to VDD_CDC_IO regulator device tree node.
+ - vdd-tx-rx-supply: phandle to VDD_CDC_TX/RX/CX regulator device tree node.
+ - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator device tree
+                           node.
+- qcom,lpass-codec-core: phandle to syscon node of lpass code core.
+
+Optional Properties:
+- qcom,micbias1-ext-cap: present if micbias1 has external capacitor connected.
+- qcom,micbias2-ext-cap: present if micbias2 has external capacitor connected.
+
+## Bindings codec core on lpass:
+
+Required properties
+ - compatible: should be "qcom,msm8916-lpass-codec" followed by "syscon".
+ - reg: represents the lpass codec core register map.
+
+Example:
+
+spmi_bus {
+       ...
+       msm8916_wcd_codec@f000{
+               compatible = "qcom,msm8916-wcd-codec";
+               reg = <0xf000 0x200>;
+               reg-names = "pmic-codec-core";
+               clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
+               clock-names = "mclk";
+               interrupt-parent = <&spmi_bus>;
+               interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+                            <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+                            <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+               interrupt-names = "spk_cnp_int",
+                                 "spk_clip_int",
+                                 "spk_ocp_int",
+                                 "ins_rem_det1",
+                                 "but_rel_det",
+                                 "but_press_det",
+                                 "ins_rem_det",
+                                 "mbhc_int",
+                                 "ear_ocp_int",
+                                 "hphr_ocp_int",
+                                 "hphl_ocp_det",
+                                 "ear_cnp_int",
+                                 "hphr_cnp_int",
+                                 "hphl_cnp_int";
+               vddio-supply = <&pm8916_l5>;
+               vdd-tx-rx-supply = <&pm8916_l5>;
+               vdd-micbias-supply = <&pm8916_l13>;
+               qcom,lpass-codec-core = <&lpass_codec_core>;
+               #sound-dai-cells = <1>;
+       };
+};
+
+soc {
+       ...
+       lpass_codec_core: lpass-codec{
+               compatible = "qcom,msm8916-lpass-codec", "syscon";
+               reg = <0x0771c000 0x400>;
+       };
+
+};
index 11c676eb8dc3415ad4e2c72505ba4154cff99929..f0581b00b479fe2dc44be9748b61aad9114a6944 100644 (file)
@@ -500,7 +500,7 @@ dtb-$(CONFIG_ARCH_ORION5X) += \
 dtb-$(CONFIG_ARCH_PRIMA2) += \
        prima2-evb.dtb
 dtb-$(CONFIG_ARCH_QCOM) += \
-       qcom-apq8064-arrow-db600c.dtb \
+       qcom-apq8064-arrow-sd-600eval.dtb \
        qcom-apq8064-eI_ERAGON600.dtb \
        qcom-apq8064-cm-qs600.dtb \
        qcom-apq8064-ifc6410.dtb \
similarity index 70%
rename from arch/arm/boot/dts/qcom-apq8064-arrow-db600c-pins.dtsi
rename to arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval-pins.dtsi
index a3efb9704fcd964e0eaa1aa6ed0f2f41dac367ee..b6f2444047d23d65729c0ae9837b5ba83613647c 100644 (file)
                        bias-disable;
                };
        };
+
+       wcnss_pin_a: wcnss {
+               bt {
+                       function = "riva_bt";
+                       pins = "gpio16", "gpio17";
+               };
+
+               fm {
+                       function = "riva_fm";
+                       pins = "gpio14", "gpio15";
+               };
+
+               wlan {
+                       function = "riva_wlan";
+                       pins = "gpio64", "gpio65", "gpio66", "gpio67", "gpio68";
+                       drive-strength = <6>;
+                       bias-pull-up;
+               };
+       };
 };
 
 &pm8921_mpps {
similarity index 89%
rename from arch/arm/boot/dts/qcom-apq8064-arrow-db600c.dts
rename to arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
index e12d7f55f5cdd769ff025552c84f0e827d86eaa1..10b7f570a4539b486920c07f7de7568c899c6b17 100644 (file)
@@ -1,10 +1,11 @@
 #include "qcom-apq8064-v2.0.dtsi"
-#include "qcom-apq8064-arrow-db600c-pins.dtsi"
+#include "qcom-apq8064-arrow-sd-600eval-pins.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/mfd/qcom-rpm.h>
 
 / {
-       model = "Arrow Electronics, APQ8064 DB600c";
-       compatible = "arrow,db600c", "qcom,apq8064";
+       model = "Arrow Electronics, APQ8064 SD_600eval";
+       compatible = "arrow,sd_600eval", "qcom,apq8064";
 
        aliases {
                serial0 = &gsbi7_serial;
 
        };
 
+       smd {
+               q6@1 {
+                       status = "ok";
+               };
+
+               riva@6 {
+                       status = "ok";
+               };
+       };
+
        soc {
                rpm@108000 {
                        regulators {
                                        bias-pull-down;
                                };
 
+                               s2 {
+                                       regulator-min-microvolt = <1300000>;
+                                       regulator-max-microvolt = <1300000>;
+                                       qcom,switch-mode-frequency = <1600000>;
+                                       bias-pull-down;
+                                       regulator-always-on;
+                               };
+
                                s3 {
                                        regulator-min-microvolt = <1000000>;
                                        regulator-max-microvolt = <1400000>;
                                s4 {
                                        regulator-min-microvolt = <1800000>;
                                        regulator-max-microvolt = <1800000>;
-                                       qcom,switch-mode-frequency = <3200000>;
+                                       qcom,switch-mode-frequency = <1600000>;
+                                       qcom,force-mode = <QCOM_RPM_FORCE_MODE_AUTO>;
                                        bias-pull-down;
                                        regulator-always-on;
                                };
                                        bias-pull-down;
                                };
 
+                               l26 {
+                                       regulator-min-microvolt = < 375000>;
+                                       regulator-max-microvolt = <1050000>;
+                                       bias-pull-down;
+                               };
                                lvs6 {
                                        bias-pull-down;
                                };
 
                                lvs7 {
                                        bias-pull-down;
+                                       regulator-always-on;
                                };
                        };
                };
                        target-supply   = <&pm8921_lvs7>;
                };
 
+               wcnss@3204000 {
+                       status = "ok";
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&wcnss_pin_a>;
+               };
+
                /* OTG */
                phy@12500000 {
                        status          = "okay";
                usb@12530000 {
                        status = "okay";
                };
+               pil_q6v4: pil@28800000 {
+                       qcom,pll-supply = <&pm8921_l26>;
+                       qcom,pll-uV = <1050000>;
+               };
 
                hdmi: qcom,hdmi-tx@4a00000 {
                        status = "okay";
index 91e497adb5bb3fd83441571d2e72aff23ed5269c..5b6d7072acb651f166447a353671c94cf59995fc 100644 (file)
                };
        };
 
+       smd {
+               q6@1 {
+                       status = "okay";
+               };
+       };
+
        soc {
                pinctrl@800000 {
                        card_detect: card_detect {
index 5b46c1054b756ab2bd221e62e81f4cf216e46c71..ac4e7f91db2dd8430872047b42ef798f72d130ac 100644 (file)
                        reg = <0x80000000 0x200000>;
                        no-map;
                };
+
+               wcnss_mem: wcnss@8f000000 {
+                       reg = <0x8f000000 0x700000>;
+                       no-map;
+               };
        };
 
        cpus {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens 7>;
+                       thermal-sensors = <&gcc 7>;
 
                        trips {
                                cpu_alert0: trip@0 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens 8>;
+                       thermal-sensors = <&gcc 8>;
 
                        trips {
                                cpu_alert1: trip@0 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens 9>;
+                       thermal-sensors = <&gcc 9>;
 
                        trips {
                                cpu_alert2: trip@0 {
                        polling-delay-passive = <250>;
                        polling-delay = <1000>;
 
-                       thermal-sensors = <&tsens 10>;
+                       thermal-sensors = <&gcc 10>;
 
                        trips {
                                cpu_alert3: trip@0 {
                };
        };
 
-       thermal-zones {
-               cpu-thermal0 {
-                       polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&gcc 7>;
-
-                       trips {
-                               cpu_alert0: trip@0 {
-                                       temperature = <75000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu_crit0: trip@1 {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "critical";
-                               };
-                       };
-               };
-
-               cpu-thermal1 {
-                       polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&gcc 8>;
-
-                       trips {
-                               cpu_alert1: trip@0 {
-                                       temperature = <75000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu_crit1: trip@1 {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "critical";
-                               };
-                       };
-               };
-
-               cpu-thermal2 {
-                       polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&gcc 9>;
-
-                       trips {
-                               cpu_alert2: trip@0 {
-                                       temperature = <75000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu_crit2: trip@1 {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "critical";
-                               };
-                       };
-               };
-
-               cpu-thermal3 {
-                       polling-delay-passive = <250>;
-                       polling-delay = <1000>;
-
-                       thermal-sensors = <&gcc 10>;
-
-                       trips {
-                               cpu_alert3: trip@0 {
-                                       temperature = <75000>;
-                                       hysteresis = <2000>;
-                                       type = "passive";
-                               };
-                               cpu_crit3: trip@1 {
-                                       temperature = <95000>;
-                                       hysteresis = <2000>;
-                                       type = "critical";
-                               };
-                       };
-               };
-       };
-
        cpu-pmu {
                compatible = "qcom,krait-pmu";
                interrupts = <1 10 0x304>;
                };
        };
 
+       smd {
+               compatible = "qcom,smd";
+
+               modem@0 {
+                       interrupts = <0 37 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&l2cc 8 3>;
+                       qcom,smd-edge = <0>;
+
+                       status = "disabled";
+               };
+
+               q6@1 {
+                       interrupts = <0 90 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&l2cc 8 15>;
+                       qcom,smd-edge = <1>;
+
+                       status = "disabled";
+
+                       apr {
+                               compatible = "qcom,apr";
+                               qcom,smd-channels = "apr_audio_svc";
+                               rproc = <&pil_q6v4>;
+                       };
+               };
+
+               dsps@3 {
+                       interrupts = <0 138 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&sps_sic_non_secure 0x4080 0>;
+                       qcom,smd-edge = <3>;
+
+                       status = "disabled";
+               };
+
+               riva@6 {
+                       interrupts = <0 198 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&l2cc 8 25>;
+                       qcom,smd-edge = <6>;
+
+                       status = "disabled";
+
+                       wcnss {
+                               compatible = "qcom,wcnss";
+                               qcom,smd-channels = "WCNSS_CTRL";
+
+                               qcom,mmio = <&riva>;
+
+                               bt {
+                                       compatible = "qcom,wcnss-bt";
+                               };
+
+                               wifi {
+                                       compatible = "qcom,wcnss-wlan";
+
+                                       interrupts = <0 203 0>, <0 202 0>;
+                                       interrupt-names = "tx", "rx";
+
+                                       qcom,state = <&apps_smsm 10>, <&apps_smsm 9>;
+                                       qcom,state-names = "tx-enable", "tx-rings-empty";
+
+                                       local-mac-address = [ 18 00 2d 88 9c a9 ];
+                               };
+                       };
+               };
+       };
+
+       smsm {
+               compatible = "qcom,smsm";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               qcom,ipc-1 = <&l2cc 8 4>;
+               qcom,ipc-2 = <&l2cc 8 14>;
+               qcom,ipc-3 = <&l2cc 8 23>;
+               qcom,ipc-4 = <&sps_sic_non_secure 0x4094 0>;
+
+               apps_smsm: apps@0 {
+                       reg = <0>;
+                       #qcom,state-cells = <1>;
+               };
+
+               modem_smsm: modem@1 {
+                       reg = <1>;
+                       interrupts = <0 38 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               q6_smsm: q6@2 {
+                       reg = <2>;
+                       interrupts = <0 89 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               wcnss_smsm: wcnss@3 {
+                       reg = <3>;
+                       interrupts = <0 204 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               dsps_smsm: dsps@4 {
+                       reg = <4>;
+                       interrupts = <0 137 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
        soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                        regulator-max-microvolt = <1250000>;
                };
 
+               sps_sic_non_secure: sps-sic-non-secure@12100000 {
+                       compatible      = "syscon";
+                       reg             = <0x12100000 0x10000>;
+               };
+
                gsbi1: gsbi@12440000 {
                        status = "disabled";
                        compatible = "qcom,gsbi-v1.0.0";
                        };
                };
 
+               riva: wcnss@3204000 {
+                       compatible = "qcom,riva-pil", "qcom,riva";
+                       reg = <0x03200800 0x1000>, <0x03202000 0x2000>, <0x03204000 0x100>;
+                       reg-names = "ccu", "dxe", "pmu";
+
+                       interrupts-extended = <&intc 0 199 IRQ_TYPE_EDGE_RISING>,
+                                             <&wcnss_smsm 6 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal";
+
+                       memory-region = <&wcnss_mem>;
+
+                       vddcx-supply = <&pm8921_s3>;
+                       vddmx-supply = <&pm8921_l24>;
+                       vddpx-supply = <&pm8921_s4>;
+
+                       status = "disabled";
+
+                       iris {
+                               compatible = "qcom,wcn3660";
+
+                               clocks = <&rpmcc 9>;
+                               clock-names = "xo";
+
+                               vddxo-supply = <&pm8921_l4>;
+                               vddrfa-supply = <&pm8921_s2>;
+                               vddpa-supply = <&pm8921_l10>;
+                               vdddig-supply = <&pm8921_lvs2>;
+                       };
+               };
+
+
                usb1_phy: phy@12500000 {
                        compatible      = "qcom,usb-otg-ci";
                        reg             = <0x12500000 0x400>;
                        qcom,pas-id             = <1>; /* PAS_Q6 */
                };
 
-               smd {
-                       compatible = "qcom,smd";
-                       adsp_a11 {
-                               interrupts = <0 90 IRQ_TYPE_EDGE_RISING>;
-                               qcom,ipc = <&l2cc 8 15>;
-                               qcom,smd-edge = <1>;
-                               qcom,remote-pid = <0x2>;
-                               q6_requests {
-                                       compatible      = "qcom,apr";
-                                       qcom,smd-channels = "apr_audio_svc";
-                                       rproc = <&pil_q6v4>;
-                               };
-                       };
-               };
-
                dai_fe: dai_fe {
                        compatible      = "qcom,msm-dai-fe";
                        #sound-dai-cells = <0>;
index fa04d74c2ea1e2f6c53c84ef400a3bd2398c3f3b..92d69dcae6238a05ada79002e90274e2c83ad71a 100644 (file)
@@ -73,6 +73,7 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_QCOMSMD=y
 CONFIG_CFG80211=m
 CONFIG_CFG80211_WEXT=y
 CONFIG_MAC80211=m
@@ -113,6 +114,8 @@ CONFIG_USB_USBNET=y
 CONFIG_ATH_CARDS=m
 CONFIG_ATH6KL=m
 CONFIG_ATH6KL_SDIO=m
+CONFIG_WCN36XX=m
+CONFIG_WCN36XX_DEBUGFS=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 # CONFIG_MOUSE_PS2 is not set
@@ -246,7 +249,6 @@ CONFIG_USB_CHIPIDEA_HOST=y
 CONFIG_USB_SERIAL=y
 CONFIG_USB_MSM_OTG=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_ETH=m
 CONFIG_USB_GADGETFS=m
@@ -278,12 +280,17 @@ CONFIG_KPSS_XCC=y
 CONFIG_KRAITCC=y
 CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_MSM_IOMMU=y
+CONFIG_QCOM_Q6V5_PIL=y
 CONFIG_QCOM_TZ_PIL=y
+CONFIG_QCOM_WCNSS_PIL=y
 CONFIG_QCOM_GSBI=y
 CONFIG_QCOM_PM=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SMD_RPM=y
+CONFIG_QCOM_SMP2P=y
+CONFIG_QCOM_SMSM=y
+CONFIG_QCOM_WCNSS_CTRL=y
 CONFIG_PHY_QCOM_APQ8064_SATA=y
 CONFIG_PHY_QCOM_IPQ806X_SATA=y
 CONFIG_NVMEM=y
index ab0df21a877ffa49af48e23ed5090356799fff6b..aeed8161fc05a842a9a6430d217fb2f6eff5b040 100644 (file)
                                        s1 {
                                                regulator-min-microvolt = <375000>;
                                                regulator-max-microvolt = <1562000>;
-                                               
+
                                        };
                                        s2 {
                                                regulator-min-microvolt = <375000>;
                                                regulator-max-microvolt = <1562000>;
-                                               
+
                                        };
                                        s3 {
                                                regulator-min-microvolt = <375000>;
                                                regulator-max-microvolt = <1562000>;
-                                               
+
                                        };
                                        s4 {
                                                regulator-min-microvolt = <1800000>;
                                                regulator-max-microvolt = <1800000>;
-                                               
+
                                                regulator-always-on;
                                                regulator-boot-on;
                                        };
                                        l1 {
                                                regulator-min-microvolt = <375000>;
                                                regulator-max-microvolt = <1525000>;
-                                               
+
                                        };
                                        l2 {
                                                regulator-min-microvolt = <375000>;
                                                regulator-max-microvolt = <1525000>;
-                                               
+
                                        };
                                        l3 {
                                                regulator-min-microvolt = <375000>;
                                                regulator-max-microvolt = <1525000>;
-                                               
+
                                        };
                                        l4 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l5 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l6 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l7 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l8 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l9 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l10 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l11 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l12 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l13 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l14 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l15 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l16 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l17 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                        l18 {
                                                regulator-min-microvolt = <1750000>;
                                                regulator-max-microvolt = <3337000>;
-                                               
+
                                        };
                                };
                        };
        status = "okay";
        clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>;
        clock-names = "mclk";
-       digital = <&wcd_digital>;
+       qcom,lpass-codec-core = <&lpass_codec_core>;
 };
        /*
        Internal Codec
        pinctrl-names = "default", "sleep";
        qcom,model = "DB410c";
        qcom,audio-routing =
-               "MIC BIAS External", "Handset Mic",
-               "MIC BIAS Internal2", "Headset Mic",
-               "MIC BIAS External", "Secondary Mic",
                "AMIC1", "MIC BIAS External",
                "AMIC2", "MIC BIAS Internal2",
                "AMIC3", "MIC BIAS External",
-               "DMIC1", "MIC BIAS Internal1",
-               "MIC BIAS Internal1", "Digital Mic1",
-               "DMIC2", "MIC BIAS Internal1",
-               "MIC BIAS Internal1", "Digital Mic2";
+               "DMIC1", "MIC BIAS Internal1";
 
        /* External Primary or External Secondary -ADV7533 HDMI */
        external-dai-link@0 {
index 77f76fd37fa4b11b5ad5d292e3e6006cd86eb4a2..11e707cef476f1e7a07556d3a01dd7c06f199f18 100644 (file)
@@ -95,8 +95,8 @@
                qcom,qos-off = <0x1000>;
                qcom,bus-type = <1>;
                clock-names = "bus_clk", "bus_a_clk";
-               clocks = <&rpmcc  RPM_SNOC_CLK>,
-                      <&rpmcc  RPM_SNOC_A_CLK>;
+               clocks = <&rpmcc  RPM_SMD_SNOC_CLK>,
+                      <&rpmcc  RPM_SMD_SNOC_A_CLK>;
        };
 
        fab_bimc: fab-bimc {
                qcom,base-name = "bimc-base";
                qcom,bus-type = <2>;
                clock-names = "bus_clk", "bus_a_clk";
-               clocks = <&rpmcc  RPM_BIMC_CLK>,
-                      <&rpmcc  RPM_BIMC_A_CLK>;
+               clocks = <&rpmcc  RPM_SMD_BIMC_CLK>,
+                      <&rpmcc  RPM_SMD_BIMC_A_CLK>;
        };
 
        fab_pnoc: fab-pnoc {
                qcom,qos-delta = <0x1000>;
                qcom,bus-type = <1>;
                clock-names = "bus_clk", "bus_a_clk";
-               clocks = <&rpmcc  RPM_PCNOC_CLK>,
-                      <&rpmcc  RPM_PCNOC_A_CLK>;
+               clocks = <&rpmcc  RPM_SMD_PCNOC_CLK>,
+                      <&rpmcc  RPM_SMD_PCNOC_A_CLK>;
        };
 
        /* SNOC Devices */
index c008dc7a32bb9495262f004d7162a3f4e310390d..9cac742817aae5024200851ce0cc585d5ae26136 100644 (file)
@@ -17,7 +17,7 @@
                compatible = "arm,coresight-tpiu", "arm,primecell";
                reg = <0x820000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                port {
@@ -32,7 +32,7 @@
                compatible = "arm,coresight-funnel", "arm,primecell";
                reg = <0x821000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
@@ -69,7 +69,7 @@
                compatible = "qcom,coresight-replicator1x", "arm,primecell";
                reg = <0x824000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
                compatible = "arm,coresight-tmc", "arm,primecell";
                reg = <0x825000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
                compatible = "arm,coresight-tmc", "arm,primecell";
                reg = <0x826000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                port {
                compatible = "arm,coresight-funnel", "arm,primecell";
                reg = <0x841000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85c000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU0>;
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85d000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU1>;
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85e000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU2>;
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85f000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU3>;
index 29a4774f757dff2dd7dcffc01c60e817d328d760..f6091aafc984dd541757059b3b32920e086b3e75 100644 (file)
                        reg = <0x0 0x86800000 0x0 0x04800000>;
                };
 
+               rmtfs@86700000 {
+                       reg = <0x0 0x86700000 0x0 0xe0000>;
+                       no-map;
+               };
+
                 peripheral_mem: peripheral_region@8b600000 {
                         no-map;
                         reg = <0x0 0x8b600000 0x0 0x0600000>;
                 };
 
+               wcnss_mem: wcnss@89300000 {
+                       reg = <0x0 0x89300000 0x0 0x600000>;
+                       no-map;
+               };
+
                vidc_mem: vidc_region@8f800000 {
                        no-map;
                        reg = <0 0x8f800000 0 0x800000>;
                };
+
+               mba_mem: mba@8ea00000 {
+                       no-map;
+                       reg = <0 0x8ea00000 0 0x100000>;
+               };
        };
 
        cpus {
        firmware {
                compatible = "simple-bus";
 
-               scm {
+               scm: scm {
                        compatible = "qcom,scm";
                        clocks = <&gcc GCC_CRYPTO_CLK> , <&gcc GCC_CRYPTO_AXI_CLK>, <&gcc GCC_CRYPTO_AHB_CLK>;
                        clock-names = "core", "bus", "iface";
+                       #reset-cells = <1>;
                };
        };
 
 
                /* Audio */
 
-               wcd_digital: codec-digital{
-                       compatible = "syscon", "qcom,apq8016-wcd-digital-codec";
+               lpass_codec_core: lpass-codec{
+                       compatible = "syscon", "qcom,msm8916-lpass-codec";
                        reg = <0x0771c000 0x400>;
                };
 
                        #thermal-sensor-cells = <1>;
                };
 
-               q6-smp2p {
-                       compatible = "qcom,smp2p";
-                       qcom,smem = <435>, <428>;
-                       interrupts = <0 27 1>;
-                       qcom,ipc = <&apcs 8 14>;
-
-                       qcom,local-pid = <0>;
-                       qcom,remote-pid = <1>;
-
-                       q6_smp2p_out: master-kernel {
-                               qcom,entry-name = "master-kernel";
-                               qcom,outbound;
-
-                               gpio-controller;
-                               #gpio-cells = <2>;
-                       };
+               hexagon@4080000 {
+                       compatible = "qcom,pil-q6v56-mss", "qcom,q6v5-pil";
+                       reg = <0x04080000 0x100>,
+                             <0x04020000 0x040>;
 
-                       q6_smp2p_in: slave-kernel {
-                               qcom,entry-name = "slave-kernel";
-                               qcom,inbound;
+                       reg-names = "qdsp6", "rmb";
 
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
-               };
+                       interrupts-extended = <&intc 0 24 1>,
+                                             <&hexagon_smp2p_in 0 0>,
+                                             <&hexagon_smp2p_in 1 0>,
+                                             <&hexagon_smp2p_in 2 0>,
+                                             <&hexagon_smp2p_in 3 0>;
+                       interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
 
-               wcnss-smp2p {
-                       compatible = "qcom,smp2p";
-                       qcom,smem = <451>, <431>;
+                       clocks = <&gcc GCC_MSS_CFG_AHB_CLK>, <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, <&gcc GCC_BOOT_ROM_AHB_CLK>;
+                       clock-names = "iface", "bus", "mem";
 
-                       interrupts = <0 143 1>;
+                       qcom,state = <&hexagon_smp2p_out 0>;
+                       qcom,state-names = "stop";
 
-                       qcom,ipc = <&apcs 8 18>;
+                       resets = <&scm 0>;
+                       reset-names = "mss_restart";
 
-                       qcom,local-pid = <0>;
-                       qcom,remote-pid = <4>;
+                       mx-supply = <&pm8916_l3>;
+                       pll-supply = <&pm8916_l7>;
 
-                       wcnss_smp2p_out: master-kernel {
-                               qcom,entry-name = "master-kernel";
-                               qcom,outbound;
+                       qcom,halt-regs = <&tcsr 0x18000 0x19000 0x1a000>;
 
-                               gpio-controller;
-                               #gpio-cells = <2>;
+                       mba {
+                               memory-region = <&mba_mem>;
                        };
 
-                       wcnss_smp2p_in: slave-kernel {
-                               qcom,entry-name = "slave-kernel";
-                               qcom,inbound;
-
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
+                       mpss {
+                               memory-region = <&modem_adsp_mem>;
                        };
                };
 
-               qcom,mss@4080000 {
-                       compatible = "qcom,pil-q6v56-mss", "qcom,q6v5-pil";
-                       reg = <0x04080000 0x100>,
-                             <0x04020000 0x040>,
-                             <0x01810000 0x004>,
-                             <0x01810000 0x004>,
-                             <0x0194f000 0x010>,
-                             <0x01950000 0x008>,
-                             <0x01951000 0x008>;
-       
-                       reg-names = "qdsp6_base", "rmb_base", "restart_reg_sec",
-                                       "halt_q6", "halt_modem", "halt_nc";
-       
-                       interrupts-extended = <&intc 0 24 1>,
-                                             <&q6_smp2p_in 0 0>,
-                                             <&q6_smp2p_in 1 0>,
-                                             <&q6_smp2p_in 2 0>,
-                                             <&q6_smp2p_in 3 0>;
-                       interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
-       
-                       clocks = <&gcc GCC_MSS_CFG_AHB_CLK>, <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, <&gcc GCC_BOOT_ROM_AHB_CLK>;
-                       
-                       clock-names = "iface", "bus", "mem";
+               pronto: wcnss@a21b000 {
+                       compatible = "qcom,pronto-v2-pil", "qcom,pronto";
+                       reg = <0x0a204000 0x2000>, <0x0a202000 0x1000>, <0x0a21b000 0x3000>;
+                       reg-names = "ccu", "dxe", "pmu";
 
-                       qcom,mx-supply = <&pm8916_l3>;
-                       qcom,mx-uV = <1050000>;
-                       qcom,pll-supply = <&pm8916_l7>;
-                       qcom,pll-uV = <1800000>;
-                       qcom,proxy-clock-names = "xo";
-                       qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk";
-                       qcom,is-loadable;
-                       qcom,firmware-name = "modem";
-                       qcom,pil-self-auth;
-                       
-       
-                       /* GPIO inputs from mss */
-                       qcom,gpio-err-fatal = <&q6_smp2p_in 0 0>;
-                       qcom,gpio-err-ready = <&q6_smp2p_in 1 0>;
-                       qcom,gpio-proxy-unvote = <&q6_smp2p_in 2 0>;
-                       qcom,gpio-stop-ack = <&q6_smp2p_in 3 0>;
-                       qcom,gpio-ramdump-disable = <&q6_smp2p_in 15 0>;
-                       /* GPIO output to mss */
-                       qcom,gpio-force-stop = <&q6_smp2p_out 0 0>;
-                       qcom,stop-gpio = <&q6_smp2p_out 0 0>;
-                       memory-region = <&modem_adsp_mem>;
-               };
-
-               pronto_rproc:pronto_rproc {
-                       compatible = "qcom,tz-pil";
+                       memory-region = <&wcnss_mem>;
 
-                       interrupts-extended = <&intc 0 149 1>,
-                                             <&wcnss_smp2p_in 0 0>,
-                                             <&wcnss_smp2p_in 1 0>,
-                                             <&wcnss_smp2p_in 2 0>,
-                                             <&wcnss_smp2p_in 3 0>;
+                       interrupts-extended = <&intc 0 149 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
                        interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
 
-                       clocks = <&gcc GCC_CRYPTO_CLK>,
-                                <&gcc GCC_CRYPTO_AHB_CLK>,
-                                <&gcc GCC_CRYPTO_AXI_CLK>,
-                                <&gcc CRYPTO_CLK_SRC>;
-                       clock-names = "scm_core_clk", "scm_iface_clk", "scm_bus_clk", "scm_src_clk";
-
-                       qcom,firmware-name = "wcnss";
-                       qcom,pas-id = <6>;
-
-                       qcom,crash-reason = <422>;
-                       qcom,smd-edges = <&pronto_smd_edge>;
+                       vddmx-supply = <&pm8916_l3>;
+                       vddpx-supply = <&pm8916_l7>;
 
-                       qcom,pll-supply = <&pm8916_l7>;
-                       qcom,pll-uV = <1800000>;
-                       qcom,pll-uA = <18000>;
-
-                       qcom,stop-gpio = <&wcnss_smp2p_out 0 0>;
+                       qcom,state = <&wcnss_smp2p_out 0>;
+                       qcom,state-names = "stop";
 
                        pinctrl-names = "default";
                        pinctrl-0 = <&wcnss_default>;
 
-                       memory-region = <&peripheral_mem>;
-               };
-
-                qcom,wcn36xx@0a000000 {
-                        compatible = "qcom,wcn3620";
-                        reg = <0x0a000000 0x280000>,
-                                <0xb011008 0x04>,
-                                <0x0a21b000 0x3000>,
-                                <0x03204000 0x00000100>,
-                                <0x03200800 0x00000200>,
-                                <0x0A100400 0x00000200>,
-                                <0x0A205050 0x00000200>,
-                                <0x0A219000 0x00000020>,
-                                <0x0A080488 0x00000008>,
-                                <0x0A080fb0 0x00000008>,
-                                <0x0A08040c 0x00000008>,
-                                <0x0A0120a8 0x00000008>,
-                                <0x0A012448 0x00000008>,
-                                <0x0A080c00 0x00000001>;
-
-                        reg-names = "wcnss_mmio", "wcnss_fiq",
-                                    "pronto_phy_base", "riva_phy_base",
-                                    "riva_ccu_base", "pronto_a2xb_base",
-                                    "pronto_ccpu_base", "pronto_saw2_base",
-                                    "wlan_tx_phy_aborts","wlan_brdg_err_source",
-                                    "wlan_tx_status", "alarms_txctl",
-                                    "alarms_tactl", "pronto_mcu_base";
-
-                        interrupts = <0 145 0 0 146 0>;
-                        interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
-
-                        // qcom,pronto-vddmx-supply = <&pm8916_l3>;
-                        // qcom,pronto-vddcx-supply = <&pm8916_s1_corner>;
-                        // qcom,pronto-vddpx-supply = <&pm8916_l7>;
-                        // qcom,iris-vddxo-supply   = <&pm8916_l7>;
-                        // qcom,iris-vddrfa-supply  = <&pm8916_s3>;
-                        // qcom,iris-vddpa-supply   = <&pm8916_l9>;
-                        // qcom,iris-vdddig-supply  = <&pm8916_l5>;
-
-                        pinctrl-names = "wcnss_default";
-                        // pinctrl-names = "wcnss_default", "wcnss_sleep",
-                        //                                "wcnss_gpio_default";
-                        pinctrl-0 = <&wcnss_default>;
-                        // pinctrl-1 = <&wcnss_sleep>;
-                        // pinctrl-2 = <&wcnss_gpio_default>;
-
-                        // clocks = <&rpmcc RPM_XO_CLK_SRC>,
-                        //         <&rpmcc RPM_RF_CLK2>;
-                        //clock-names = "xo", "rf_clk";
-
-                       rproc = <&pronto_rproc>;
-                        qcom,has-autodetect-xo;
-                        qcom,wlan-rx-buff-count = <512>;
-                        qcom,is-pronto-vt;
-                        qcom,has-pronto-hw;
-                        // qcom,wcnss-adc_tm = <&pm8916_adc_tm>;
-                };
+                       iris {
+                               compatible = "qcom,wcn3620";
 
+                               clocks = <&rpmcc RPM_SMD_RF_CLK2>;
+                               clock-names = "xo";
 
+                               vddxo-supply = <&pm8916_l7>;
+                               vddrfa-supply = <&pm8916_s3>;
+                               vddpa-supply = <&pm8916_l9>;
+                               vdddig-supply = <&pm8916_l5>;
+                       };
+               };
 
                qcom,rpm-log@29dc00 {
                        compatible = "qcom,rpm-log";
                                compatible = "qcom,rpm-msm8916";
                                qcom,smd-channels = "rpm_requests";
                                rpmcc: qcom,rpmcc {
-                                       compatible = "qcom,rpmcc-msm8916", "qcom,rpmcc";
+                                       compatible = "qcom,rpmcc-msm8916";
                                        #clock-cells = <1>;
                                };
 
                        };
                };
 
-               pronto_smd_edge: pronto {
+               pronto {
                        interrupts = <0 142 1>;
 
                        qcom,ipc = <&apcs 8 17>;
                        qcom,smd-edge = <6>;
                        qcom,remote-pid = <4>;
 
-                               bt {
-                               compatible = "qcom,hci-smd";
-                               qcom,smd-channels = "APPS_RIVA_BT_CMD", "APPS_RIVA_BT_ACL";
-                               qcom,smd-channel-names = "event", "data";
-                       };
+                       wcnss {
+                               compatible = "qcom,wcnss";
+                               qcom,smd-channels = "WCNSS_CTRL";
 
-                       ipcrtr {
-                               compatible = "qcom,ipcrtr";
-                               qcom,smd-channels = "IPCRTR";
-                       };
+                               qcom,mmio = <&pronto>;
 
-                       wifi {
-                               compatible = "qcom,wlan-ctrl";
-                               qcom,smd-channels = "WLAN_CTRL";
+                               bt {
+                                       compatible = "qcom,wcnss-bt";
+                               };
 
-                               interrupts = <0 145 0>, <0 146 0>;
-                               interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+                               wifi {
+                                       compatible = "qcom,wcnss-wlan";
 
-                               qcom,wcnss_mmio = <0xfb000000 0x21b000>;
+                                       interrupts = <0 145 0>, <0 146 0>;
+                                       interrupt-names = "tx", "rx";
 
-                               // qcom,tx-enable-gpios = <&apps_smsm 10 0>;
-                               // qcom,tx-rings-empty-gpios = <&apps_smsm 9 0>;
+                                       qcom,state = <&apps_smsm 10>, <&apps_smsm 9>;
+                                       qcom,state-names = "tx-enable", "tx-rings-empty";
+                               };
                        };
+               };
+       };
 
-                       wcnss_ctrl {
-                               compatible = "qcom,wcnss-ctrl";
-                               qcom,smd-channels = "WCNSS_CTRL";
+       hexagon-smp2p {
+               compatible = "qcom,smp2p";
+               qcom,smem = <435>, <428>;
 
-                               qcom,wcnss_mmio = <0xfb21b000 0x3000>;
-                       };
+               interrupts = <0 27 IRQ_TYPE_EDGE_RISING>;
+
+               qcom,ipc = <&apcs 8 14>;
+
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <1>;
+
+               hexagon_smp2p_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+
+                       #qcom,state-cells = <1>;
+               };
+
+               hexagon_smp2p_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       wcnss-smp2p {
+               compatible = "qcom,smp2p";
+               qcom,smem = <451>, <431>;
+
+               interrupts = <0 143 IRQ_TYPE_EDGE_RISING>;
+
+               qcom,ipc = <&apcs 8 18>;
+
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <4>;
+
+               wcnss_smp2p_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+
+                       #qcom,state-cells = <1>;
+               };
+
+               wcnss_smp2p_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
        };
 
+       smsm {
+               compatible = "qcom,smsm";
 
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               qcom,ipc-1 = <&apcs 0 13>;
+               qcom,ipc-6 = <&apcs 0 19>;
+
+               apps_smsm: apps@0 {
+                       reg = <0>;
+
+                       #qcom,state-cells = <1>;
+               };
+
+               hexagon_smsm: hexagon@1 {
+                       reg = <1>;
+                       interrupts = <0 26 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               wcnss_smsm: wcnss@6 {
+                       reg = <6>;
+                       interrupts = <0 144 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
 };
 
 &i2c_freq_100Khz {
index 113ccb3fa8868abe1fd142ec8dadd9c039729e7c..48d206867029efff37e8b7a84873943765108eab 100644 (file)
                };
 
                wcd_codec: codec@f000 {
-                       compatible = "qcom,apq8016-wcd-codec";
+                       compatible = "qcom,msm8916-wcd-codec";
                        reg = <0xf000 0x200>;
-                       #sound-dai-cells = <1>;
+                       reg-names = "pmic-codec-core";
+                       interrupt-parent = <&spmi_bus>;
+                       interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>,
+                                    <0x1 0xf0 0x1 IRQ_TYPE_NONE>,
+                                    <0x1 0xf0 0x2 IRQ_TYPE_NONE>,
+                                    <0x1 0xf0 0x3 IRQ_TYPE_NONE>,
+                                    <0x1 0xf0 0x4 IRQ_TYPE_NONE>,
+                                    <0x1 0xf0 0x5 IRQ_TYPE_NONE>,
+                                    <0x1 0xf0 0x6 IRQ_TYPE_NONE>,
+                                    <0x1 0xf0 0x7 IRQ_TYPE_NONE>,
+                                    <0x1 0xf1 0x0 IRQ_TYPE_NONE>,
+                                    <0x1 0xf1 0x1 IRQ_TYPE_NONE>,
+                                    <0x1 0xf1 0x2 IRQ_TYPE_NONE>,
+                                    <0x1 0xf1 0x3 IRQ_TYPE_NONE>,
+                                    <0x1 0xf1 0x4 IRQ_TYPE_NONE>,
+                                    <0x1 0xf1 0x5 IRQ_TYPE_NONE>;
+                       interrupt-names = "spk_cnp_int",
+                                         "spk_clip_int",
+                                         "spk_ocp_int",
+                                         "ins_rem_det1",
+                                         "but_rel_det",
+                                         "but_press_det",
+                                         "ins_rem_det",
+                                         "mbhc_int",
+                                         "ear_ocp_int",
+                                         "hphr_ocp_int",
+                                         "hphl_ocp_det",
+                                         "ear_cnp_int",
+                                         "hphr_cnp_int",
+                                         "hphl_cnp_int";
+
                        vddio-supply = <&pm8916_l5>;
-                       vdd-pa-supply = <&pm8916_s4>;
-                       vdd-mic-bias-supply = <&pm8916_l13>;
+                       vdd-tx-rx-supply = <&pm8916_l5>;
+                       vdd-micbias-supply = <&pm8916_l13>;
+                       #sound-dai-cells = <1>;
                };
        };
 };
index 9eb4230f513e86d0042e6de5310ab880ef85b11d..a344b42f3ce5bdf1e897f160e3d4f3543c69d244 100644 (file)
@@ -23,6 +23,7 @@ CONFIG_CGROUP_HUGETLB=y
 # CONFIG_NET_NS is not set
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
 CONFIG_JUMP_LABEL=y
@@ -77,6 +78,8 @@ CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+CONFIG_QRTR=y
+CONFIG_QRTR_SMD=y
 CONFIG_BPF_JIT=y
 CONFIG_BT=y
 CONFIG_BT_RFCOMM=y
@@ -153,8 +156,6 @@ CONFIG_SPMI=y
 CONFIG_PINCTRL_MSM8916=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_PL061=y
-CONFIG_GPIO_QCOM_SMSM=y
-CONFIG_GPIO_QCOM_SMP2P=y
 CONFIG_GPIO_XGENE=y
 CONFIG_POWER_RESET_MSM=y
 CONFIG_POWER_RESET_XGENE=y
@@ -186,7 +187,7 @@ CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_QCOM=y
 CONFIG_SND_SOC_APQ8016_SBC=y
-CONFIG_SND_SOC_MSM8x16_WCD=y
+CONFIG_SND_SOC_MSM8916_WCD=y
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_DYNAMIC_MINORS=y
@@ -212,9 +213,6 @@ CONFIG_USB_TEST=m
 CONFIG_USB_HSIC_USB3503=y
 CONFIG_USB_MSM_OTG=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_VERBOSE=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_CONFIGFS=m
 CONFIG_USB_ZERO=m
@@ -255,11 +253,16 @@ CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_QCOM_IOMMU_V1=y
 CONFIG_QCOM_Q6V5_PIL=y
 CONFIG_QCOM_TZ_PIL=y
+CONFIG_QCOM_WCNSS_PIL=y
 CONFIG_QCOM_GSBI=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SMD_RPM=y
+CONFIG_QCOM_SMP2P=y
+CONFIG_QCOM_SMSM=y
+CONFIG_QCOM_WCNSS_CTRL=y
 CONFIG_MSM_BUS_SCALING=y
+CONFIG_QTI_LNX_GPS_PROXY=y
 CONFIG_BUS_TOPOLOGY_ADHOC=y
 CONFIG_EXTCON_USB_GPIO=y
 CONFIG_PHY_XGENE=y
@@ -292,7 +295,6 @@ CONFIG_LOCKUP_DETECTOR=y
 # CONFIG_DETECT_HUNG_TASK is not set
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
-CONFIG_PROVE_LOCKING=y
 # CONFIG_FTRACE is not set
 CONFIG_MEMTEST=y
 CONFIG_CORESIGHT=y
index bd2aba113cfcc253be2ca058d4df624f55418d66..ab8951c40fee8859fecce2e887208853ef2643a9 100644 (file)
@@ -172,6 +172,7 @@ config BT_HCIUART_QCA
 config BT_QCOMSMD
        tristate "Qualcomm SMD based HCI support"
        depends on QCOM_SMD
+       select BT_QCA
        help
          Qualcomm SMD based HCI driver.
          This driver is used to bridge HCI data onto the shared memory
index 4b91c830531ea921ba6aab02d0f76e0c1ff5fe94..0cf759b208f28cfaf2b85e74c6fc6533f879c2be 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2016, Linaro Ltd.
  * Copyright (c) 2015, Sony Mobile Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
+#include <linux/platform_device.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci.h>
-
-#define EDL_NVM_ACCESS_SET_REQ_CMD     0x01
-#define EDL_NVM_ACCESS_OPCODE          0xfc0b
+#include "btqca.h"
 
 struct btqcomsmd {
+       struct hci_dev *hdev;
+
        struct qcom_smd_channel *acl_channel;
        struct qcom_smd_channel *cmd_channel;
 };
 
-static int btqcomsmd_recv(struct hci_dev *hdev,
-                         unsigned type,
-                         const void *data,
+static int btqcomsmd_recv(struct hci_dev *hdev, unsigned type, const void *data,
                          size_t count)
 {
        struct sk_buff *skb;
-       void *buf;
 
        /* Use GFP_ATOMIC as we're in IRQ context */
        skb = bt_skb_alloc(count, GFP_ATOMIC);
-       if (!skb)
+       if (!skb) {
+               hdev->stat.err_rx++;
                return -ENOMEM;
+       }
 
        bt_cb(skb)->pkt_type = type;
-
-       /* Use io accessor as data might be ioremapped */
-       buf = skb_put(skb, count);
-       memcpy_fromio(buf, data, count);
+       memcpy(skb_put(skb, count), data, count);
 
        return hci_recv_frame(hdev, skb);
 }
 
-static int btqcomsmd_acl_callback(struct qcom_smd_device *qsdev,
+static int btqcomsmd_acl_callback(struct qcom_smd_channel *channel,
                                  const void *data,
                                  size_t count)
 {
-       struct hci_dev *hdev = dev_get_drvdata(&qsdev->dev);
+       struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
 
-       return btqcomsmd_recv(hdev, HCI_ACLDATA_PKT, data, count);
+       btq->hdev->stat.byte_rx += count;
+       return btqcomsmd_recv(btq->hdev, HCI_ACLDATA_PKT, data, count);
 }
 
-static int btqcomsmd_cmd_callback(struct qcom_smd_device *qsdev,
+static int btqcomsmd_cmd_callback(struct qcom_smd_channel *channel,
                                  const void *data,
                                  size_t count)
 {
-       struct hci_dev *hdev = dev_get_drvdata(&qsdev->dev);
+       struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
 
-       return btqcomsmd_recv(hdev, HCI_EVENT_PKT, data, count);
+       return btqcomsmd_recv(btq->hdev, HCI_EVENT_PKT, data, count);
 }
 
 static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
@@ -73,14 +73,16 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_ACLDATA_PKT:
-       case HCI_SCODATA_PKT:
                ret = qcom_smd_send(btq->acl_channel, skb->data, skb->len);
+               hdev->stat.acl_tx++;
+               hdev->stat.byte_tx += skb->len;
                break;
        case HCI_COMMAND_PKT:
                ret = qcom_smd_send(btq->cmd_channel, skb->data, skb->len);
+               hdev->stat.cmd_tx++;
                break;
        default:
-               ret = -ENODEV;
+               ret = -EILSEQ;
                break;
        }
 
@@ -89,72 +91,53 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
 
 static int btqcomsmd_open(struct hci_dev *hdev)
 {
-       set_bit(HCI_RUNNING, &hdev->flags);
        return 0;
 }
 
 static int btqcomsmd_close(struct hci_dev *hdev)
 {
-       clear_bit(HCI_RUNNING, &hdev->flags);
-       return 0;
-}
-
-static int btqcomsmd_set_bdaddr(struct hci_dev *hdev,
-                             const bdaddr_t *bdaddr)
-{
-       struct sk_buff *skb;
-       u8 cmd[9];
-       int err;
-
-       cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD;
-       cmd[1] = 0x02;                  /* TAG ID */
-       cmd[2] = sizeof(bdaddr_t);      /* size */
-       memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t));
-       skb = __hci_cmd_sync_ev(hdev,
-                               EDL_NVM_ACCESS_OPCODE,
-                               sizeof(cmd), cmd,
-                               HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               BT_ERR("%s: Change address command failed (%d)",
-                      hdev->name, err);
-               return err;
-       }
-
-       kfree_skb(skb);
-
        return 0;
 }
 
-static int btqcomsmd_probe(struct qcom_smd_device *sdev)
+static int btqcomsmd_probe(struct platform_device *pdev)
 {
-       struct qcom_smd_channel *acl;
        struct btqcomsmd *btq;
        struct hci_dev *hdev;
+       void *wcnss;
        int ret;
 
-       acl = qcom_smd_open_channel(sdev,
-                                   "APPS_RIVA_BT_ACL",
-                                   btqcomsmd_acl_callback);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-
-       btq = devm_kzalloc(&sdev->dev, sizeof(*btq), GFP_KERNEL);
+       btq = devm_kzalloc(&pdev->dev, sizeof(*btq), GFP_KERNEL);
        if (!btq)
                return -ENOMEM;
 
-       btq->acl_channel = acl;
-       btq->cmd_channel = sdev->channel;
+       wcnss = dev_get_drvdata(pdev->dev.parent);
+
+       btq->acl_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_ACL",
+                                                  btqcomsmd_acl_callback);
+       if (IS_ERR(btq->acl_channel))
+               return PTR_ERR(btq->acl_channel);
+
+       btq->cmd_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_CMD",
+                                                  btqcomsmd_cmd_callback);
+       if (IS_ERR(btq->cmd_channel))
+               return PTR_ERR(btq->cmd_channel);
+
+       qcom_smd_set_drvdata(btq->acl_channel, btq);
+       qcom_smd_set_drvdata(btq->cmd_channel, btq);
 
        hdev = hci_alloc_dev();
        if (!hdev)
                return -ENOMEM;
 
+       hci_set_drvdata(hdev, btq);
+       btq->hdev = hdev;
+       SET_HCIDEV_DEV(hdev, &pdev->dev);
+
        hdev->bus = HCI_SMD;
        hdev->open = btqcomsmd_open;
        hdev->close = btqcomsmd_close;
        hdev->send = btqcomsmd_send;
-       hdev->set_bdaddr = btqcomsmd_set_bdaddr;
+       hdev->set_bdaddr = qca_set_bdaddr_rome;
 
        ret = hci_register_dev(hdev);
        if (ret < 0) {
@@ -162,37 +145,37 @@ static int btqcomsmd_probe(struct qcom_smd_device *sdev)
                return ret;
        }
 
-       hci_set_drvdata(hdev, btq);
-       dev_set_drvdata(&sdev->dev, hdev);
+       platform_set_drvdata(pdev, btq);
 
        return 0;
 }
 
-static void btqcomsmd_remove(struct qcom_smd_device *sdev)
+static int btqcomsmd_remove(struct platform_device *pdev)
 {
-       struct hci_dev *hdev = dev_get_drvdata(&sdev->dev);;
+       struct btqcomsmd *btq = platform_get_drvdata(pdev);
 
-       hci_unregister_dev(hdev);
-       hci_free_dev(hdev);
+       hci_unregister_dev(btq->hdev);
+       hci_free_dev(btq->hdev);
+
+       return 0;
 }
 
-static const struct qcom_smd_id btqcomsmd_match[] = {
-       { .name = "APPS_RIVA_BT_CMD" },
-       {}
+static const struct of_device_id btqcomsmd_of_match[] = {
+       { .compatible = "qcom,wcnss-bt", },
+       { },
 };
 
-static struct qcom_smd_driver btqcomsmd_cmd_driver = {
+static struct platform_driver btqcomsmd_driver = {
        .probe = btqcomsmd_probe,
        .remove = btqcomsmd_remove,
-       .callback = btqcomsmd_cmd_callback,
-       .smd_match_table = btqcomsmd_match,
        .driver  = {
                .name  = "btqcomsmd",
-               .owner = THIS_MODULE,
+               .of_match_table = btqcomsmd_of_match,
        },
 };
 
-module_qcom_smd_driver(btqcomsmd_cmd_driver);
+module_platform_driver(btqcomsmd_driver);
 
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
 MODULE_DESCRIPTION("Qualcomm SMD HCI driver");
 MODULE_LICENSE("GPL v2");
index 9e850a5392d1ac46001215aad8cd232e5f0a5bfc..12fea623c189da6b8c9881c2c889bf39439960e1 100644 (file)
@@ -12,21 +12,31 @@ config COMMON_CLK_QCOM
        select REGMAP_MMIO
        select RESET_CONTROLLER
 
-config QCOM_CLK_SMD_RPM
-       tristate "RPM over SMD based Clock Controller"
-       depends on COMMON_CLK_QCOM && QCOM_SMD_RPM
-       select QCOM_RPMCC
-       help
-         Support for the clocks exposed by the Resource Power Manager
-         processor on devices like apq8016, apq8084 and msm8974.
-
 config QCOM_CLK_RPM
        tristate "RPM based Clock Controller"
        depends on COMMON_CLK_QCOM && MFD_QCOM_RPM
        select QCOM_RPMCC
        help
-         Support for the clocks exposed by the Resource Power Manager
-         processor on devices like apq8064.
+         The RPM (Resource Power Manager) is a dedicated hardware engine for
+         managing the shared SoC resources in order to keep the lowest power
+         profile. It communicates with other hardware subsystems via shared
+         memory and accepts clock requests, aggregates the requests and turns
+         the clocks on/off or scales them on demand.
+         Say Y if you want to support the clocks exposed by the RPM on
+         platforms such as apq8064, msm8660, msm8960 etc.
+
+config QCOM_CLK_SMD_RPM
+       tristate "RPM over SMD based Clock Controller"
+       depends on COMMON_CLK_QCOM && QCOM_SMD_RPM
+       select QCOM_RPMCC
+       help
+         The RPM (Resource Power Manager) is a dedicated hardware engine for
+         managing the shared SoC resources in order to keep the lowest power
+         profile. It communicates with other hardware subsystems via shared
+         memory and accepts clock requests, aggregates the requests and turns
+         the clocks on/off or scales them on demand.
+         Say Y if you want to support the clocks exposed by the RPM on
+         platforms such as apq8016, apq8084, msm8974 etc.
 
 config APQ_GCC_8084
        tristate "APQ8084 Global Clock Controller"
index 400007b13f27819a42981b881e5d3eadf2647857..93e127bca238936ef99ce55b253bcca350aa05cd 100644 (file)
@@ -12,8 +12,6 @@ clk-qcom-y += clk-regmap-mux-div.o
 clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
 clk-qcom-y += clk-hfpll.o
 clk-qcom-y += reset.o
-clk-qcom-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
-clk-qcom-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
 
 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
@@ -31,3 +29,6 @@ obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
 obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
 obj-$(CONFIG_KRAITCC) += krait-cc.o
 obj-$(CONFIG_QCOM_A53) += clk-a53.o
+obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
+obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
index 416aa68339d82fe23ed54365dc00e0f2a9a0eb91..05cf83c2ca833c492f52b9a721840dd2521279a7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2016, Linaro Limited
  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
@@ -12,7 +12,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-#include "clk-rpm.h"
 #include <dt-bindings/mfd/qcom-rpm.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+
+#define QCOM_RPM_MISC_CLK_TYPE                         0x306b6c63
+#define QCOM_RPM_SCALING_ENABLE_ID                     0x2
+
+#define DEFINE_CLK_RPM(_platform, _name, _active, r_id)                              \
+       static struct clk_rpm _platform##_##_active;                          \
+       static struct clk_rpm _platform##_##_name = {                         \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_active,                               \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_ops,                                  \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_rpm _platform##_##_active = {                       \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_name,                                 \
+               .active_only = true,                                          \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_ops,                                  \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define DEFINE_CLK_RPM_PXO_BRANCH(_platform, _name, _active, r_id, r)        \
+       static struct clk_rpm _platform##_##_active;                          \
+       static struct clk_rpm _platform##_##_name = {                         \
+               .rpm_clk_id = (r_id),                                         \
+               .active_only = true,                                          \
+               .peer = &_platform##_##_active,                               \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_rpm _platform##_##_active = {                       \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_name,                                 \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define DEFINE_CLK_RPM_CXO_BRANCH(_platform, _name, _active, r_id, r)        \
+       static struct clk_rpm _platform##_##_active;                          \
+       static struct clk_rpm _platform##_##_name = {                         \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_active,                               \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "cxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_rpm _platform##_##_active = {                       \
+               .rpm_clk_id = (r_id),                                         \
+               .active_only = true,                                          \
+               .peer = &_platform##_##_name,                                 \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "cxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
 
 #define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw)
 
+struct clk_rpm {
+       const int rpm_clk_id;
+       const bool active_only;
+       unsigned long rate;
+       bool enabled;
+       bool branch;
+       struct clk_rpm *peer;
+       struct clk_hw hw;
+       struct qcom_rpm *rpm;
+};
+
+struct rpm_cc {
+       struct qcom_rpm *rpm;
+       struct clk_onecell_data data;
+       struct clk *clks[];
+};
+
+struct rpm_clk_desc {
+       struct clk_rpm **clks;
+       size_t num_clks;
+};
+
 static DEFINE_MUTEX(rpm_clk_lock);
 
+static int clk_rpm_handoff(struct clk_rpm *r)
+{
+       int ret;
+       u32 value = INT_MAX;
+
+       ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE,
+                            r->rpm_clk_id, &value, 1);
+       if (ret)
+               return ret;
+       ret = qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE,
+                            r->rpm_clk_id, &value, 1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int clk_rpm_set_rate_active(struct clk_rpm *r, unsigned long rate)
 {
        u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */
@@ -40,25 +163,69 @@ static int clk_rpm_set_rate_active(struct clk_rpm *r, unsigned long rate)
                              r->rpm_clk_id, &value, 1);
 }
 
+static int clk_rpm_set_rate_sleep(struct clk_rpm *r, unsigned long rate)
+{
+       u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */
+
+       return qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE,
+                             r->rpm_clk_id, &value, 1);
+}
+
+static void to_active_sleep(struct clk_rpm *r, unsigned long rate,
+                           unsigned long *active, unsigned long *sleep)
+{
+       *active = rate;
+
+       /*
+        * Active-only clocks don't care what the rate is during sleep. So,
+        * they vote for zero.
+        */
+       if (r->active_only)
+               *sleep = 0;
+       else
+               *sleep = *active;
+}
+
 static int clk_rpm_prepare(struct clk_hw *hw)
 {
        struct clk_rpm *r = to_clk_rpm(hw);
-       unsigned long rate = r->rate;
+       struct clk_rpm *peer = r->peer;
+       unsigned long this_rate = 0, this_sleep_rate = 0;
+       unsigned long peer_rate = 0, peer_sleep_rate = 0;
+       unsigned long active_rate, sleep_rate;
        int ret = 0;
 
        mutex_lock(&rpm_clk_lock);
 
-       if (!rate)
+       /* Don't send requests to the RPM if the rate has not been set. */
+       if (!r->rate)
                goto out;
 
-       if (r->branch)
-               rate = !!rate;
+       to_active_sleep(r, r->rate, &this_rate, &this_sleep_rate);
+
+       /* Take peer clock's rate into account only if it's enabled. */
+       if (peer->enabled)
+               to_active_sleep(peer, peer->rate,
+                               &peer_rate, &peer_sleep_rate);
 
-       ret = clk_rpm_set_rate_active(r, rate);
+       active_rate = max(this_rate, peer_rate);
+
+       if (r->branch)
+               active_rate = !!active_rate;
 
+       ret = clk_rpm_set_rate_active(r, active_rate);
        if (ret)
                goto out;
 
+       sleep_rate = max(this_sleep_rate, peer_sleep_rate);
+       if (r->branch)
+               sleep_rate = !!sleep_rate;
+
+       ret = clk_rpm_set_rate_sleep(r, sleep_rate);
+       if (ret)
+               /* Undo the active set vote and restore it */
+               ret = clk_rpm_set_rate_active(r, peer_rate);
+
 out:
        if (!ret)
                r->enabled = true;
@@ -71,6 +238,9 @@ out:
 static void clk_rpm_unprepare(struct clk_hw *hw)
 {
        struct clk_rpm *r = to_clk_rpm(hw);
+       struct clk_rpm *peer = r->peer;
+       unsigned long peer_rate = 0, peer_sleep_rate = 0;
+       unsigned long active_rate, sleep_rate;
        int ret;
 
        mutex_lock(&rpm_clk_lock);
@@ -78,7 +248,18 @@ static void clk_rpm_unprepare(struct clk_hw *hw)
        if (!r->rate)
                goto out;
 
-       ret = clk_rpm_set_rate_active(r, r->rate);
+       /* Take peer clock's rate into account only if it's enabled. */
+       if (peer->enabled)
+               to_active_sleep(peer, peer->rate, &peer_rate,
+                               &peer_sleep_rate);
+
+       active_rate = r->branch ? !!peer_rate : peer_rate;
+       ret = clk_rpm_set_rate_active(r, active_rate);
+       if (ret)
+               goto out;
+
+       sleep_rate = r->branch ? !!peer_sleep_rate : peer_sleep_rate;
+       ret = clk_rpm_set_rate_sleep(r, sleep_rate);
        if (ret)
                goto out;
 
@@ -89,23 +270,45 @@ out:
 }
 
 static int clk_rpm_set_rate(struct clk_hw *hw,
-                    unsigned long rate, unsigned long parent_rate)
+                           unsigned long rate, unsigned long parent_rate)
 {
        struct clk_rpm *r = to_clk_rpm(hw);
+       struct clk_rpm *peer = r->peer;
+       unsigned long active_rate, sleep_rate;
+       unsigned long this_rate = 0, this_sleep_rate = 0;
+       unsigned long peer_rate = 0, peer_sleep_rate = 0;
        int ret = 0;
 
        mutex_lock(&rpm_clk_lock);
 
-       if (r->enabled)
-               ret = clk_rpm_set_rate_active(r, rate);
+       if (!r->enabled)
+               goto out;
+
+       to_active_sleep(r, rate, &this_rate, &this_sleep_rate);
 
-       if (!ret)
-               r->rate = rate;
+       /* Take peer clock's rate into account only if it's enabled. */
+       if (peer->enabled)
+               to_active_sleep(peer, peer->rate,
+                               &peer_rate, &peer_sleep_rate);
 
+       active_rate = max(this_rate, peer_rate);
+       ret = clk_rpm_set_rate_active(r, active_rate);
+       if (ret)
+               goto out;
+
+       sleep_rate = max(this_sleep_rate, peer_sleep_rate);
+       ret = clk_rpm_set_rate_sleep(r, sleep_rate);
+       if (ret)
+               goto out;
+
+       r->rate = rate;
+
+out:
        mutex_unlock(&rpm_clk_lock);
 
        return ret;
 }
+
 static long clk_rpm_round_rate(struct clk_hw *hw, unsigned long rate,
                               unsigned long *parent_rate)
 {
@@ -130,59 +333,57 @@ static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw,
        return r->rate;
 }
 
-const struct clk_ops clk_rpm_ops = {
+static const struct clk_ops clk_rpm_ops = {
        .prepare        = clk_rpm_prepare,
        .unprepare      = clk_rpm_unprepare,
        .set_rate       = clk_rpm_set_rate,
        .round_rate     = clk_rpm_round_rate,
        .recalc_rate    = clk_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_rpm_ops);
 
-const struct clk_ops clk_rpm_branch_ops = {
+static const struct clk_ops clk_rpm_branch_ops = {
        .prepare        = clk_rpm_prepare,
        .unprepare      = clk_rpm_unprepare,
        .round_rate     = clk_rpm_round_rate,
        .recalc_rate    = clk_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_rpm_branch_ops);
-
-struct rpm_cc {
-       struct qcom_rpm *rpm;
-       struct clk_onecell_data data;
-       struct clk *clks[];
-};
-
-struct rpm_clk_desc {
-       struct clk_rpm **clks;
-       size_t num_clks;
-};
 
 /* apq8064 */
-DEFINE_CLK_RPM_PXO_BRANCH(apq8064, pxo, QCOM_RPM_PXO_CLK, 27000000);
-DEFINE_CLK_RPM_CXO_BRANCH(apq8064, cxo, QCOM_RPM_CXO_CLK, 19200000);
-DEFINE_CLK_RPM(apq8064, afab_clk, QCOM_RPM_APPS_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, cfpb_clk, QCOM_RPM_CFPB_CLK);
-DEFINE_CLK_RPM(apq8064, daytona_clk, QCOM_RPM_DAYTONA_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, ebi1_clk, QCOM_RPM_EBI1_CLK);
-DEFINE_CLK_RPM(apq8064, mmfab_clk, QCOM_RPM_MM_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, mmfpb_clk, QCOM_RPM_MMFPB_CLK);
-DEFINE_CLK_RPM(apq8064, sfab_clk, QCOM_RPM_SYS_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, sfpb_clk, QCOM_RPM_SFPB_CLK);
-DEFINE_CLK_RPM(apq8064, qdss_clk, QCOM_RPM_QDSS_CLK);
+DEFINE_CLK_RPM_PXO_BRANCH(apq8064, pxo, pxo_a_clk, QCOM_RPM_PXO_CLK, 27000000);
+DEFINE_CLK_RPM_CXO_BRANCH(apq8064, cxo, cxo_a_clk, QCOM_RPM_CXO_CLK, 19200000);
+DEFINE_CLK_RPM(apq8064, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK);
+DEFINE_CLK_RPM(apq8064, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK);
+DEFINE_CLK_RPM(apq8064, mmfab_clk, mmfab_a_clk, QCOM_RPM_MM_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK);
+DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK);
+DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK);
 
 static struct clk_rpm *apq8064_clks[] = {
-       [QCOM_RPM_PXO_CLK] = &apq8064_pxo,
-       [QCOM_RPM_CXO_CLK] = &apq8064_cxo,
-       [QCOM_RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk,
-       [QCOM_RPM_CFPB_CLK] = &apq8064_cfpb_clk,
-       [QCOM_RPM_DAYTONA_FABRIC_CLK] = &apq8064_daytona_clk,
-       [QCOM_RPM_EBI1_CLK] = &apq8064_ebi1_clk,
-       [QCOM_RPM_MM_FABRIC_CLK] = &apq8064_mmfab_clk,
-       [QCOM_RPM_MMFPB_CLK] = &apq8064_mmfpb_clk,
-       [QCOM_RPM_SYS_FABRIC_CLK] = &apq8064_sfab_clk,
-       [QCOM_RPM_SFPB_CLK] = &apq8064_sfpb_clk,
-       [QCOM_RPM_QDSS_CLK] = &apq8064_qdss_clk,
+       [RPM_PXO_CLK] = &apq8064_pxo,
+       [RPM_PXO_A_CLK] = &apq8064_pxo_a_clk,
+       [RPM_CXO_CLK] = &apq8064_cxo,
+       [RPM_CXO_A_CLK] = &apq8064_cxo_a_clk,
+       [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk,
+       [RPM_APPS_FABRIC_A_CLK] = &apq8064_afab_a_clk,
+       [RPM_CFPB_CLK] = &apq8064_cfpb_clk,
+       [RPM_CFPB_A_CLK] = &apq8064_cfpb_a_clk,
+       [RPM_DAYTONA_FABRIC_CLK] = &apq8064_daytona_clk,
+       [RPM_DAYTONA_FABRIC_A_CLK] = &apq8064_daytona_a_clk,
+       [RPM_EBI1_CLK] = &apq8064_ebi1_clk,
+       [RPM_EBI1_A_CLK] = &apq8064_ebi1_a_clk,
+       [RPM_MM_FABRIC_CLK] = &apq8064_mmfab_clk,
+       [RPM_MM_FABRIC_A_CLK] = &apq8064_mmfab_a_clk,
+       [RPM_MMFPB_CLK] = &apq8064_mmfpb_clk,
+       [RPM_MMFPB_A_CLK] = &apq8064_mmfpb_a_clk,
+       [RPM_SYS_FABRIC_CLK] = &apq8064_sfab_clk,
+       [RPM_SYS_FABRIC_A_CLK] = &apq8064_sfab_a_clk,
+       [RPM_SFPB_CLK] = &apq8064_sfpb_clk,
+       [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk,
+       [RPM_QDSS_CLK] = &apq8064_qdss_clk,
+       [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk,
 };
 
 static const struct rpm_clk_desc rpm_clk_apq8064 = {
@@ -202,10 +403,10 @@ static int rpm_clk_probe(struct platform_device *pdev)
        struct clk *clk;
        struct rpm_cc *rcc;
        struct clk_onecell_data *data;
-       int ret, i;
-       size_t num_clks;
+       int ret;
+       size_t num_clks, i;
        struct qcom_rpm *rpm;
-       struct clk_rpm  **rpm_clks;
+       struct clk_rpm **rpm_clks;
        const struct rpm_clk_desc *desc;
 
        rpm = dev_get_drvdata(pdev->dev.parent);
@@ -238,6 +439,18 @@ static int rpm_clk_probe(struct platform_device *pdev)
                }
 
                rpm_clks[i]->rpm = rpm;
+
+               ret = clk_rpm_handoff(rpm_clks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       for (i = 0; i < num_clks; i++) {
+               if (!rpm_clks[i]) {
+                       clks[i] = ERR_PTR(-ENOENT);
+                       continue;
+               }
+
                clk = devm_clk_register(&pdev->dev, &rpm_clks[i]->hw);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
@@ -252,10 +465,7 @@ static int rpm_clk_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       clk_prepare_enable(apq8064_afab_clk.hw.clk);
-
        return 0;
-
 err:
        dev_err(&pdev->dev, "Error registering RPM Clock driver (%d)\n", ret);
        return ret;
diff --git a/drivers/clk/qcom/clk-rpm.h b/drivers/clk/qcom/clk-rpm.h
deleted file mode 100644 (file)
index c0ac30f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2015, Linaro Limited
- * Copyright (c) 2014, 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
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __QCOM_CLK_RPM_H__
-#define __QCOM_CLK_RPM_H__
-
-#include <linux/clk-provider.h>
-
-struct qcom_rpm;
-
-struct clk_rpm {
-       const int rpm_clk_id;
-       unsigned long rate;
-       bool enabled;
-       bool branch;
-       struct clk_hw hw;
-       struct qcom_rpm *rpm;
-};
-
-extern const struct clk_ops clk_rpm_ops;
-extern const struct clk_ops clk_rpm_branch_ops;
-
-#define DEFINE_CLK_RPM(_platform, _name, r_id)                              \
-       static struct clk_rpm _platform##_##_name = {                        \
-               .rpm_clk_id = (r_id),                                        \
-               .rate = INT_MAX,                                             \
-               .hw.init = &(struct clk_init_data){                          \
-                       .name = #_name,                                      \
-                       .parent_names = (const char *[]){ "pxo_board" },     \
-                       .num_parents = 1,                                    \
-                       .ops = &clk_rpm_ops,                                 \
-               },                                                           \
-       }
-
-#define DEFINE_CLK_RPM_PXO_BRANCH(_platform, _name, r_id, r)                \
-       static struct clk_rpm _platform##_##_name = {                        \
-               .rpm_clk_id = (r_id),                                        \
-               .branch = true,                                              \
-               .rate = (r),                                                 \
-               .hw.init = &(struct clk_init_data){                          \
-                       .name = #_name,                                      \
-                       .parent_names = (const char *[]){ "pxo_board" },     \
-                       .num_parents = 1,                                    \
-                       .ops = &clk_rpm_branch_ops,                          \
-               },                                                           \
-       }
-
-#define DEFINE_CLK_RPM_CXO_BRANCH(_platform, _name, r_id, r)                \
-       static struct clk_rpm _platform##_##_name = {                        \
-               .rpm_clk_id = (r_id),                                        \
-               .branch = true,                                              \
-               .rate = (r),                                                 \
-               .hw.init = &(struct clk_init_data){                          \
-                       .name = #_name,                                      \
-                       .parent_names = (const char *[]){ "cxo_board" },     \
-                       .num_parents = 1,                                    \
-                       .ops = &clk_rpm_branch_ops,                          \
-               },                                                           \
-       }
-#endif
index 749798207bb81f5825467cc29a558b8c59996657..adfb58f5135161835d4fcb23dfc701f144007e40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2016, Linaro Limited
  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
 #include <linux/platform_device.h>
 #include <linux/soc/qcom/smd-rpm.h>
 
-#include "clk-smd-rpm.h"
 #include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/mfd/qcom-rpm.h>
+
+#define QCOM_RPM_KEY_SOFTWARE_ENABLE                   0x6e657773
+#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY    0x62636370
+#define QCOM_RPM_SMD_KEY_RATE                          0x007a484b
+#define QCOM_RPM_SMD_KEY_ENABLE                                0x62616e45
+#define QCOM_RPM_SMD_KEY_STATE                         0x54415453
+#define QCOM_RPM_SCALING_ENABLE_ID                     0x2
+
+#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id,  \
+                            key)                                             \
+       static struct clk_smd_rpm _platform##_##_active;                      \
+       static struct clk_smd_rpm _platform##_##_name = {                     \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .rpm_key = (key),                                             \
+               .peer = &_platform##_##_active,                               \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_ops,                              \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_smd_rpm _platform##_##_active = {                   \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .active_only = true,                                          \
+               .rpm_key = (key),                                             \
+               .peer = &_platform##_##_name,                                 \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_ops,                              \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id,    \
+                                   stat_id, r, key)                          \
+       static struct clk_smd_rpm _platform##_##_active;                      \
+       static struct clk_smd_rpm _platform##_##_name = {                     \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .rpm_key = (key),                                             \
+               .branch = true,                                               \
+               .peer = &_platform##_##_active,                               \
+               .rate = (r),                                                  \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_branch_ops,                       \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_smd_rpm _platform##_##_active = {                   \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .active_only = true,                                          \
+               .rpm_key = (key),                                             \
+               .branch = true,                                               \
+               .peer = &_platform##_##_name,                                 \
+               .rate = (r),                                                  \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_branch_ops,                       \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id)            \
+               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
+               0, QCOM_RPM_SMD_KEY_RATE)
+
+#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r)   \
+               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type,  \
+               r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE)
+
+#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id)       \
+               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
+               0, QCOM_RPM_SMD_KEY_STATE)
+
+#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id)        \
+               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
+               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
+               QCOM_RPM_KEY_SOFTWARE_ENABLE)
+
+#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, r_id) \
+               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
+               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
+               QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY)
 
 #define to_clk_smd_rpm(_hw) container_of(_hw, struct clk_smd_rpm, hw)
 
+struct clk_smd_rpm {
+       const int rpm_res_type;
+       const int rpm_key;
+       const int rpm_clk_id;
+       const int rpm_status_id;
+       const bool active_only;
+       bool enabled;
+       bool branch;
+       struct clk_smd_rpm *peer;
+       struct clk_hw hw;
+       unsigned long rate;
+       struct qcom_smd_rpm *rpm;
+};
+
+struct clk_smd_rpm_req {
+       __le32 key;
+       __le32 nbytes;
+       __le32 value;
+};
+
+struct rpm_cc {
+       struct qcom_rpm *rpm;
+       struct clk_onecell_data data;
+       struct clk *clks[];
+};
+
+struct rpm_smd_clk_desc {
+       struct clk_smd_rpm **clks;
+       size_t num_clks;
+};
+
 static DEFINE_MUTEX(rpm_smd_clk_lock);
 
+static int clk_smd_rpm_handoff(struct clk_smd_rpm *r)
+{
+       int ret;
+       struct clk_smd_rpm_req req = {
+               .key = cpu_to_le32(r->rpm_key),
+               .nbytes = cpu_to_le32(sizeof(u32)),
+               .value = cpu_to_le32(INT_MAX),
+       };
+
+       ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
+                                r->rpm_res_type, r->rpm_clk_id, &req,
+                                sizeof(req));
+       if (ret)
+               return ret;
+       ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE,
+                                r->rpm_res_type, r->rpm_clk_id, &req,
+                                sizeof(req));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int clk_smd_rpm_set_rate_active(struct clk_smd_rpm *r,
                                       unsigned long rate)
 {
@@ -250,39 +401,25 @@ static int clk_smd_rpm_enable_scaling(struct qcom_smd_rpm *rpm)
        return 0;
 }
 
-const struct clk_ops clk_smd_rpm_ops = {
+static const struct clk_ops clk_smd_rpm_ops = {
        .prepare        = clk_smd_rpm_prepare,
        .unprepare      = clk_smd_rpm_unprepare,
        .set_rate       = clk_smd_rpm_set_rate,
        .round_rate     = clk_smd_rpm_round_rate,
        .recalc_rate    = clk_smd_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_smd_rpm_ops);
 
-const struct clk_ops clk_smd_rpm_branch_ops = {
+static const struct clk_ops clk_smd_rpm_branch_ops = {
        .prepare        = clk_smd_rpm_prepare,
        .unprepare      = clk_smd_rpm_unprepare,
        .round_rate     = clk_smd_rpm_round_rate,
        .recalc_rate    = clk_smd_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_smd_rpm_branch_ops);
-
-struct rpm_cc {
-       struct qcom_rpm *rpm;
-       struct clk_onecell_data data;
-       struct clk *clks[];
-};
-
-struct rpm_smd_clk_desc {
-       struct clk_smd_rpm **clks;
-       size_t num_clks;
-};
 
 /* msm8916 */
 DEFINE_CLK_SMD_RPM(msm8916, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
 DEFINE_CLK_SMD_RPM(msm8916, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 DEFINE_CLK_SMD_RPM(msm8916, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8916, xo, xo_a, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
 DEFINE_CLK_SMD_RPM_QDSS(msm8916, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
 DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk1, bb_clk1_a, 1);
 DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk2, bb_clk2_a, 2);
@@ -294,32 +431,30 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk1_pin, rf_clk1_a_pin, 4);
 DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk2_pin, rf_clk2_a_pin, 5);
 
 static struct clk_smd_rpm *msm8916_clks[] = {
-       [RPM_XO_CLK_SRC]        = &msm8916_xo,
-       [RPM_XO_A_CLK_SRC]      = &msm8916_xo_a,
-       [RPM_PCNOC_CLK]         = &msm8916_pcnoc_clk,
-       [RPM_PCNOC_A_CLK]       = &msm8916_pcnoc_a_clk,
-       [RPM_SNOC_CLK]          = &msm8916_snoc_clk,
-       [RPM_SNOC_A_CLK]        = &msm8916_snoc_a_clk,
-       [RPM_BIMC_CLK]          = &msm8916_bimc_clk,
-       [RPM_BIMC_A_CLK]        = &msm8916_bimc_a_clk,
-       [RPM_QDSS_CLK]          = &msm8916_qdss_clk,
-       [RPM_QDSS_A_CLK]        = &msm8916_qdss_a_clk,
-       [RPM_BB_CLK1]           = &msm8916_bb_clk1,
-       [RPM_BB_CLK1_A]         = &msm8916_bb_clk1_a,
-       [RPM_BB_CLK2]           = &msm8916_bb_clk2,
-       [RPM_BB_CLK2_A]         = &msm8916_bb_clk2_a,
-       [RPM_RF_CLK1]           = &msm8916_rf_clk1,
-       [RPM_RF_CLK1_A]         = &msm8916_rf_clk1_a,
-       [RPM_RF_CLK2]           = &msm8916_rf_clk2,
-       [RPM_RF_CLK2_A]         = &msm8916_rf_clk2_a,
-       [RPM_BB_CLK1_PIN]       = &msm8916_bb_clk1_pin,
-       [RPM_BB_CLK1_A_PIN]     = &msm8916_bb_clk1_a_pin,
-       [RPM_BB_CLK2_PIN]       = &msm8916_bb_clk2_pin,
-       [RPM_BB_CLK2_A_PIN]     = &msm8916_bb_clk2_a_pin,
-       [RPM_RF_CLK1_PIN]       = &msm8916_rf_clk1_pin,
-       [RPM_RF_CLK1_A_PIN]     = &msm8916_rf_clk1_a_pin,
-       [RPM_RF_CLK2_PIN]       = &msm8916_rf_clk2_pin,
-       [RPM_RF_CLK2_A_PIN]     = &msm8916_rf_clk2_a_pin,
+       [RPM_SMD_PCNOC_CLK]             = &msm8916_pcnoc_clk,
+       [RPM_SMD_PCNOC_A_CLK]           = &msm8916_pcnoc_a_clk,
+       [RPM_SMD_SNOC_CLK]              = &msm8916_snoc_clk,
+       [RPM_SMD_SNOC_A_CLK]            = &msm8916_snoc_a_clk,
+       [RPM_SMD_BIMC_CLK]              = &msm8916_bimc_clk,
+       [RPM_SMD_BIMC_A_CLK]            = &msm8916_bimc_a_clk,
+       [RPM_SMD_QDSS_CLK]              = &msm8916_qdss_clk,
+       [RPM_SMD_QDSS_A_CLK]            = &msm8916_qdss_a_clk,
+       [RPM_SMD_BB_CLK1]               = &msm8916_bb_clk1,
+       [RPM_SMD_BB_CLK1_A]             = &msm8916_bb_clk1_a,
+       [RPM_SMD_BB_CLK2]               = &msm8916_bb_clk2,
+       [RPM_SMD_BB_CLK2_A]             = &msm8916_bb_clk2_a,
+       [RPM_SMD_RF_CLK1]               = &msm8916_rf_clk1,
+       [RPM_SMD_RF_CLK1_A]             = &msm8916_rf_clk1_a,
+       [RPM_SMD_RF_CLK2]               = &msm8916_rf_clk2,
+       [RPM_SMD_RF_CLK2_A]             = &msm8916_rf_clk2_a,
+       [RPM_SMD_BB_CLK1_PIN]           = &msm8916_bb_clk1_pin,
+       [RPM_SMD_BB_CLK1_A_PIN]         = &msm8916_bb_clk1_a_pin,
+       [RPM_SMD_BB_CLK2_PIN]           = &msm8916_bb_clk2_pin,
+       [RPM_SMD_BB_CLK2_A_PIN]         = &msm8916_bb_clk2_a_pin,
+       [RPM_SMD_RF_CLK1_PIN]           = &msm8916_rf_clk1_pin,
+       [RPM_SMD_RF_CLK1_A_PIN]         = &msm8916_rf_clk1_a_pin,
+       [RPM_SMD_RF_CLK2_PIN]           = &msm8916_rf_clk2_pin,
+       [RPM_SMD_RF_CLK2_A_PIN]         = &msm8916_rf_clk2_a_pin,
 };
 
 static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
@@ -327,167 +462,8 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
        .num_clks = ARRAY_SIZE(msm8916_clks),
 };
 
-/* msm8974 */
-DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8974, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8974, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM(msm8974, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8974, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8974, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8974, cxo_clk_src, cxo_a_clk_src, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
-DEFINE_CLK_SMD_RPM_QDSS(msm8974, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d0, cxo_d0_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d1, cxo_d1_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a0, cxo_a0_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a1, cxo_a1_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a2, cxo_a2_a, 6);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk1, div_a_clk1, 11);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk2, div_a_clk2, 12);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, diff_clk, diff_a_clk, 7);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d0_pin, cxo_d0_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d1_pin, cxo_d1_a_pin, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a0_pin, cxo_a0_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a1_pin, cxo_a1_a_pin, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a2_pin, cxo_a2_a_pin, 6);
-
-static struct clk_smd_rpm *msm8974_clks[] = {
-       [RPM_CXO_CLK_SRC]       = &msm8974_cxo_clk_src,
-       [RPM_CXO_A_CLK_SRC]     = &msm8974_cxo_a_clk_src,
-       [RPM_PNOC_CLK]          = &msm8974_pnoc_clk,
-       [RPM_PNOC_A_CLK]        = &msm8974_pnoc_a_clk,
-       [RPM_SNOC_CLK]          = &msm8974_snoc_clk,
-       [RPM_SNOC_A_CLK]        = &msm8974_snoc_a_clk,
-       [RPM_BIMC_CLK]          = &msm8974_bimc_clk,
-       [RPM_BIMC_A_CLK]        = &msm8974_bimc_a_clk,
-       [RPM_QDSS_CLK]          = &msm8974_qdss_clk,
-       [RPM_QDSS_A_CLK]        = &msm8974_qdss_a_clk,
-       [RPM_CNOC_CLK]          = &msm8974_cnoc_clk,
-       [RPM_CNOC_A_CLK]        = &msm8974_cnoc_a_clk,
-       [RPM_MMSSNOC_AHB_CLK]   = &msm8974_mmssnoc_ahb_clk,
-       [RPM_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
-       [RPM_OCMEMGX_CLK]       = &msm8974_ocmemgx_clk,
-       [RPM_OCMEMGX_A_CLK]     = &msm8974_ocmemgx_a_clk,
-       [RPM_GFX3D_CLK_SRC]     = &msm8974_gfx3d_clk_src,
-       [RPM_GFX3D_A_CLK_SRC]   = &msm8974_gfx3d_a_clk_src,
-       [RPM_CXO_D0]            = &msm8974_cxo_d0,
-       [RPM_CXO_D0_A]          = &msm8974_cxo_d0_a,
-       [RPM_CXO_D1]            = &msm8974_cxo_d1,
-       [RPM_CXO_D1_A]          = &msm8974_cxo_d1_a,
-       [RPM_CXO_A0]            = &msm8974_cxo_a0,
-       [RPM_CXO_A0_A]          = &msm8974_cxo_a0_a,
-       [RPM_CXO_A1]            = &msm8974_cxo_a1,
-       [RPM_CXO_A1_A]          = &msm8974_cxo_a1_a,
-       [RPM_CXO_A2]            = &msm8974_cxo_a2,
-       [RPM_CXO_A2_A]          = &msm8974_cxo_a2_a,
-       [RPM_DIV_CLK1]          = &msm8974_div_clk1,
-       [RPM_DIV_A_CLK1]        = &msm8974_div_a_clk1,
-       [RPM_DIV_CLK2]          = &msm8974_div_clk2,
-       [RPM_DIV_A_CLK2]        = &msm8974_div_a_clk2,
-       [RPM_DIFF_CLK]          = &msm8974_diff_clk,
-       [RPM_DIFF_A_CLK]        = &msm8974_diff_a_clk,
-       [RPM_CXO_D0_PIN]        = &msm8974_cxo_d0_pin,
-       [RPM_CXO_D0_A_PIN]      = &msm8974_cxo_d0_a_pin,
-       [RPM_CXO_D1_PIN]        = &msm8974_cxo_d1_pin,
-       [RPM_CXO_D1_A_PIN]      = &msm8974_cxo_d1_a_pin,
-       [RPM_CXO_A0_PIN]        = &msm8974_cxo_a0_pin,
-       [RPM_CXO_A0_A_PIN]      = &msm8974_cxo_a0_a_pin,
-       [RPM_CXO_A1_PIN]        = &msm8974_cxo_a1_pin,
-       [RPM_CXO_A1_A_PIN]      = &msm8974_cxo_a1_a_pin,
-       [RPM_CXO_A2_PIN]        = &msm8974_cxo_a2_pin,
-       [RPM_CXO_A2_A_PIN]      = &msm8974_cxo_a2_a_pin,
-};
-
-static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
-       .clks = msm8974_clks,
-       .num_clks = ARRAY_SIZE(msm8974_clks),
-};
-
-/* apq8084 */
-DEFINE_CLK_SMD_RPM(apq8084, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(apq8084, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(apq8084, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(apq8084, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM(apq8084, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(apq8084, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM(apq8084, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM_BRANCH(apq8084, xo_clk_src, xo_a_clk_src, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
-DEFINE_CLK_SMD_RPM_QDSS(apq8084, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, bb_clk1, bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, bb_clk2, bb_clk2_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, rf_clk2, rf_clk2_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, rf_clk3, rf_clk3_a, 6);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, diff_clk1, diff_clk1_a, 7);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, div_clk1, div_clk1_a, 11);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, div_clk2, div_clk2_a, 12);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, div_clk3, div_clk3_a, 13);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, bb_clk1_pin, bb_clk1_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, bb_clk2_pin, bb_clk2_a_pin, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, rf_clk1_pin, rf_clk1_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, rf_clk2_pin, rf_clk2_a_pin, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, rf_clk3_pin, rf_clk3_a_pin, 6);
-
-static struct clk_smd_rpm *apq8084_clks[] = {
-       [RPM_XO_CLK_SRC]        = &apq8084_xo_clk_src,
-       [RPM_XO_A_CLK_SRC]      = &apq8084_xo_a_clk_src,
-       [RPM_PNOC_CLK]          = &apq8084_pnoc_clk,
-       [RPM_PNOC_A_CLK]        = &apq8084_pnoc_a_clk,
-       [RPM_SNOC_CLK]          = &apq8084_snoc_clk,
-       [RPM_SNOC_A_CLK]        = &apq8084_snoc_a_clk,
-       [RPM_BIMC_CLK]          = &apq8084_bimc_clk,
-       [RPM_BIMC_A_CLK]        = &apq8084_bimc_a_clk,
-       [RPM_QDSS_CLK]          = &apq8084_qdss_clk,
-       [RPM_QDSS_A_CLK]        = &apq8084_qdss_a_clk,
-       [RPM_CNOC_CLK]          = &apq8084_cnoc_clk,
-       [RPM_CNOC_A_CLK]        = &apq8084_cnoc_a_clk,
-       [RPM_MMSSNOC_AHB_CLK]   = &apq8084_mmssnoc_ahb_clk,
-       [RPM_MMSSNOC_AHB_A_CLK] = &apq8084_mmssnoc_ahb_a_clk,
-       [RPM_OCMEMGX_CLK]       = &apq8084_ocmemgx_clk,
-       [RPM_OCMEMGX_A_CLK]     = &apq8084_ocmemgx_a_clk,
-       [RPM_GFX3D_CLK_SRC]     = &apq8084_gfx3d_clk_src,
-       [RPM_GFX3D_A_CLK_SRC]   = &apq8084_gfx3d_a_clk_src,
-       [RPM_BB_CLK1]           = &apq8084_bb_clk1,
-       [RPM_BB_CLK1_A]         = &apq8084_bb_clk1_a,
-       [RPM_BB_CLK2]           = &apq8084_bb_clk2,
-       [RPM_BB_CLK2_A]         = &apq8084_bb_clk2_a,
-       [RPM_RF_CLK1]           = &apq8084_rf_clk1,
-       [RPM_RF_CLK1_A]         = &apq8084_rf_clk1_a,
-       [RPM_RF_CLK2]           = &apq8084_rf_clk2,
-       [RPM_RF_CLK2_A]         = &apq8084_rf_clk2_a,
-       [RPM_RF_CLK3]           = &apq8084_rf_clk3,
-       [RPM_RF_CLK3_A]         = &apq8084_rf_clk3_a,
-       [RPM_DIFF_CLK1]         = &apq8084_diff_clk1,
-       [RPM_DIFF_CLK1_A]       = &apq8084_diff_clk1_a,
-       [RPM_DIV_CLK1]          = &apq8084_div_clk1,
-       [RPM_DIV_CLK1_A]        = &apq8084_div_clk1_a,
-       [RPM_DIV_CLK2]          = &apq8084_div_clk2,
-       [RPM_DIV_CLK2_A]        = &apq8084_div_clk2_a,
-       [RPM_DIV_CLK3]          = &apq8084_div_clk3,
-       [RPM_DIV_CLK3_A]        = &apq8084_div_clk3_a,
-       [RPM_BB_CLK1_PIN]       = &apq8084_bb_clk1_pin,
-       [RPM_BB_CLK1_A_PIN]     = &apq8084_bb_clk1_a_pin,
-       [RPM_BB_CLK2_PIN]       = &apq8084_bb_clk2_pin,
-       [RPM_BB_CLK2_A_PIN]     = &apq8084_bb_clk2_a_pin,
-       [RPM_RF_CLK1_PIN]       = &apq8084_rf_clk1_pin,
-       [RPM_RF_CLK1_A_PIN]     = &apq8084_rf_clk1_a_pin,
-       [RPM_RF_CLK2_PIN]       = &apq8084_rf_clk2_pin,
-       [RPM_RF_CLK2_A_PIN]     = &apq8084_rf_clk2_a_pin,
-       [RPM_RF_CLK3_PIN]       = &apq8084_rf_clk3_pin,
-       [RPM_RF_CLK3_A_PIN]     = &apq8084_rf_clk3_a_pin,
-};
-
-static const struct rpm_smd_clk_desc rpm_clk_apq8084 = {
-       .clks = apq8084_clks,
-       .num_clks = ARRAY_SIZE(apq8084_clks),
-};
-
 static const struct of_device_id rpm_smd_clk_match_table[] = {
        { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916},
-       { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974},
-       { .compatible = "qcom,rpmcc-apq8084", .data = &rpm_clk_apq8084},
        { }
 };
 MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table);
@@ -498,8 +474,8 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
        struct clk *clk;
        struct rpm_cc *rcc;
        struct clk_onecell_data *data;
-       int ret, i;
-       size_t num_clks;
+       int ret;
+       size_t num_clks, i;
        struct qcom_smd_rpm *rpm;
        struct clk_smd_rpm **rpm_smd_clks;
        const struct rpm_smd_clk_desc *desc;
@@ -534,6 +510,22 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
                }
 
                rpm_smd_clks[i]->rpm = rpm;
+
+               ret = clk_smd_rpm_handoff(rpm_smd_clks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       ret = clk_smd_rpm_enable_scaling(rpm);
+       if (ret)
+               goto err;
+
+       for (i = 0; i < num_clks; i++) {
+               if (!rpm_smd_clks[i]) {
+                       clks[i] = ERR_PTR(-ENOENT);
+                       continue;
+               }
+
                clk = devm_clk_register(&pdev->dev, &rpm_smd_clks[i]->hw);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
@@ -548,12 +540,6 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       ret = clk_smd_rpm_enable_scaling(rpm);
-       if (ret) {
-               of_clk_del_provider(pdev->dev.of_node);
-               goto err;
-       }
-
        return 0;
 err:
        dev_err(&pdev->dev, "Error registering SMD clock driver (%d)\n", ret);
diff --git a/drivers/clk/qcom/clk-smd-rpm.h b/drivers/clk/qcom/clk-smd-rpm.h
deleted file mode 100644 (file)
index 7ac5829..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2015, Linaro Limited
- * Copyright (c) 2014, 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
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __QCOM_CLK_SMD_RPM_H__
-#define __QCOM_CLK_SMD_RPM_H__
-
-#include <linux/clk-provider.h>
-
-#define QCOM_RPM_KEY_SOFTWARE_ENABLE                   0x6e657773
-#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY    0x62636370
-#define QCOM_RPM_SMD_KEY_RATE                          0x007a484b
-#define QCOM_RPM_SMD_KEY_ENABLE                                0x62616e45
-#define QCOM_RPM_SMD_KEY_STATE                         0x54415453
-#define QCOM_RPM_SCALING_ENABLE_ID                     0x2
-
-struct qcom_smd_rpm;
-
-struct clk_smd_rpm {
-       const int rpm_res_type;
-       const int rpm_key;
-       const int rpm_clk_id;
-       const int rpm_status_id;
-       const bool active_only;
-       bool enabled;
-       bool branch;
-       struct clk_smd_rpm *peer;
-       struct clk_hw hw;
-       unsigned long rate;
-       struct qcom_smd_rpm *rpm;
-};
-
-struct clk_smd_rpm_req {
-       __le32 key;
-       __le32 nbytes;
-       __le32 value;
-};
-
-extern const struct clk_ops clk_smd_rpm_ops;
-extern const struct clk_ops clk_smd_rpm_branch_ops;
-
-#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id,  \
-                            key)                                             \
-       static struct clk_smd_rpm _platform##_##_active;                      \
-       static struct clk_smd_rpm _platform##_##_name = {                     \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_active,                               \
-               .rate = INT_MAX,                                              \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_ops,                              \
-                       .name = #_name,                                       \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       };                                                                    \
-       static struct clk_smd_rpm _platform##_##_active = {                   \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_name,                                 \
-               .active_only = true,                                          \
-               .rate = INT_MAX,                                              \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_ops,                              \
-                       .name = #_active,                                     \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       }
-
-#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id,    \
-                                   stat_id, r, key)                          \
-       static struct clk_smd_rpm _platform##_##_active;                      \
-       static struct clk_smd_rpm _platform##_##_name = {                     \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_active,                               \
-               .branch = true,                                               \
-               .rate = (r),                                                  \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_branch_ops,                       \
-                       .name = #_name,                                       \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       };                                                                    \
-       static struct clk_smd_rpm _platform##_##_active = {                   \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_name,                                 \
-               .active_only = true,                                          \
-               .branch = true,                                               \
-               .rate = (r),                                                  \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_branch_ops,                       \
-                       .name = #_active,                                     \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       }
-
-#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id)            \
-               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
-               0, QCOM_RPM_SMD_KEY_RATE)
-
-#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r)   \
-               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type,  \
-               r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE)
-
-#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id)       \
-               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
-               0, QCOM_RPM_SMD_KEY_STATE)
-
-#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id)        \
-               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
-               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
-               QCOM_RPM_KEY_SOFTWARE_ENABLE)
-
-#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, r_id) \
-               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
-               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
-               QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY)
-
-#endif
index cabbe1f7e397d54d38f2061510411f22a75207c6..ca24cb6bf012bd3b71ef2946ec39e4d54a67a7f2 100644 (file)
@@ -501,11 +501,13 @@ int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
                req, req_cnt * sizeof(*req), resp, sizeof(*resp));
 }
 
-int __qcom_scm_restart_proc(u32 proc_id, int restart, u32 *resp)
+int __qcom_scm_pas_mss_reset(bool reset)
 {
+       __le32 val = cpu_to_le32(reset);
+       __le32 resp;
 
-       return qcom_scm_call(QCOM_SCM_SVC_PIL, proc_id,
-                               &restart, sizeof(restart),
+       return qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET,
+                               &val, sizeof(val),
                                &resp, sizeof(resp));
 }
 
@@ -521,39 +523,23 @@ bool __qcom_scm_pas_supported(u32 peripheral)
        return ret ? false : !!ret_val;
 }
 
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size)
+int __qcom_scm_pas_init_image(u32 peripheral, dma_addr_t metadata_phys)
 {
-       dma_addr_t mdata_phys;
-       void *mdata_buf;
-       u32 scm_ret;
+       __le32 scm_ret;
        int ret;
-       struct pas_init_image_req {
-               u32 proc;
-               u32 image_addr;
+       struct {
+               __le32 proc;
+               __le32 image_addr;
        } request;
 
-       /*
-        * During the scm call memory protection will be enabled for the meta
-        * data blob, so make sure it's physically contiguous, 4K aligned and
-        * non-cachable to avoid XPU violations.
-        */
-       mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
-       if (!mdata_buf) {
-               pr_err("Allocation of metadata buffer failed.\n");
-               return -ENOMEM;
-       }
-       memcpy(mdata_buf, metadata, size);
-
-       request.proc = peripheral;
-       request.image_addr = mdata_phys;
+       request.proc = cpu_to_le32(peripheral);
+       request.image_addr = cpu_to_le32(metadata_phys);
 
        ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
                            &request, sizeof(request),
                            &scm_ret, sizeof(scm_ret));
 
-       dma_free_coherent(dev, size, mdata_buf, mdata_phys);
-
-       return ret ? : scm_ret;
+       return ret ? : le32_to_cpu(scm_ret);
 }
 
 int __qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
index dc64858935fa7f977ef624e382691783fc7b6aba..7784f1dc8977feb7817ae8961ebbdef31a1dedd0 100644 (file)
@@ -472,20 +472,15 @@ int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
        return ret;
 }
 
-int __qcom_scm_restart_proc(u32 proc_id, int restart, u32 *resp)
+int __qcom_scm_pas_mss_reset(bool reset)
 {
-       int ret;
        struct qcom_scm_desc desc = {0};
 
-       desc.args[0] = restart;
+       desc.args[0] = reset;
        desc.args[1] = 0;
        desc.arginfo = QCOM_SCM_ARGS(2);
 
-       ret = qcom_scm_call(QCOM_SCM_SVC_PIL, proc_id,
-                               &desc);
-       *resp = desc.ret[0];
-
-       return ret;
+       return qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc);
 }
 
 bool __qcom_scm_pas_supported(u32 peripheral)
@@ -502,37 +497,20 @@ bool __qcom_scm_pas_supported(u32 peripheral)
        return ret ? false : !!desc.ret[0];
 }
 
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size)
+int __qcom_scm_pas_init_image(u32 peripheral, dma_addr_t metadata_phys)
 {
        int ret;
        struct qcom_scm_desc desc = {0};
        u32 scm_ret;
-       dma_addr_t mdata_phys;
-       void *mdata_buf;
-
-dev->coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
-
-       /*
-        * During the scm call memory protection will be enabled for the meta
-        * data blob, so make sure it's physically contiguous, 4K aligned and
-        * non-cachable to avoid XPU violations.
-        */
-       mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
-       if (!mdata_buf) {
-               pr_err("Allocation of metadata buffer failed.\n");
-               return -ENOMEM;
-       }
-       memcpy(mdata_buf, metadata, size);
 
        desc.args[0] = peripheral;
-       desc.args[1] = mdata_phys;
+       desc.args[1] = metadata_phys;
        desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
 
        ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
                                &desc);
        scm_ret = desc.ret[0];
 
-       dma_free_coherent(dev, size, mdata_buf, mdata_phys);
        return ret ? : scm_ret;
 }
 
index a1a25185a867e786c4dace4cb693d0051a53b628..b760fae77d194d0d6eed716068d058e06813fe52 100644 (file)
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/export.h>
+#include <linux/dma-mapping.h>
 #include <linux/types.h>
 #include <linux/qcom_scm.h>
 #include <linux/of.h>
 #include <linux/clk.h>
+#include <linux/reset-controller.h>
 
 #include "qcom_scm.h"
 
 struct qcom_scm {
+       struct device *dev;
        struct clk *core_clk;
        struct clk *iface_clk;
        struct clk *bus_clk;
+
+       struct reset_controller_dev reset;
 };
 
 static struct qcom_scm *__scm;
@@ -34,44 +39,31 @@ static int qcom_scm_clk_enable(void)
 {
        int ret;
 
-       if(__scm->core_clk) {
-               ret = clk_prepare_enable(__scm->core_clk);
-               if (ret)
-                       goto bail;
-       }
-
-       if(__scm->iface_clk) {
-               ret = clk_prepare_enable(__scm->iface_clk);
-               if (ret)
-                       goto disable_core;
-       }
-
-       if(__scm->bus_clk) {
-               ret = clk_prepare_enable(__scm->bus_clk);
-               if (ret)
-                       goto disable_iface;
-       }
+       ret = clk_prepare_enable(__scm->core_clk);
+       if (ret)
+               goto bail;
+       ret = clk_prepare_enable(__scm->iface_clk);
+       if (ret)
+               goto disable_core;
+       ret = clk_prepare_enable(__scm->bus_clk);
+       if (ret)
+               goto disable_iface;
 
        return 0;
 
 disable_iface:
-       if(__scm->iface_clk)
-               clk_disable_unprepare(__scm->iface_clk);
+       clk_disable_unprepare(__scm->iface_clk);
 disable_core:
-       if(__scm->core_clk)
-               clk_disable_unprepare(__scm->core_clk);
+       clk_disable_unprepare(__scm->core_clk);
 bail:
        return ret;
 }
 
 static void qcom_scm_clk_disable(void)
 {
-       if(__scm->core_clk)
-               clk_disable_unprepare(__scm->core_clk);
-       if(__scm->iface_clk)
-               clk_disable_unprepare(__scm->iface_clk);
-       if(__scm->bus_clk)
-               clk_disable_unprepare(__scm->bus_clk);
+       clk_disable_unprepare(__scm->core_clk);
+       clk_disable_unprepare(__scm->iface_clk);
+       clk_disable_unprepare(__scm->bus_clk);
 }
 
 /**
@@ -159,11 +151,6 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
 }
 EXPORT_SYMBOL(qcom_scm_hdcp_req);
 
-int qcom_scm_restart_proc(u32 pid, int restart, u32 *resp)
-{
-       return __qcom_scm_restart_proc(pid, restart, resp);
-}
-EXPORT_SYMBOL(qcom_scm_restart_proc);
 /**
  * qcom_scm_pas_supported() - Check if the peripheral authentication service is
  *                           available for the given peripherial
@@ -196,9 +183,36 @@ EXPORT_SYMBOL(qcom_scm_pas_supported);
  *
  * Returns 0 on success.
  */
-int qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size)
+int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
 {
-       return __qcom_scm_pas_init_image(dev, peripheral, metadata, size);
+       dma_addr_t mdata_phys;
+       void *mdata_buf;
+       int ret;
+
+       /*
+        * During the scm call memory protection will be enabled for the meta
+        * data blob, so make sure it's physically contiguous, 4K aligned and
+        * non-cachable to avoid XPU violations.
+        */
+       mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, GFP_KERNEL);
+       if (!mdata_buf) {
+               dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
+               return -ENOMEM;
+       }
+       memcpy(mdata_buf, metadata, size);
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               goto free_metadata;
+
+       ret = __qcom_scm_pas_init_image(peripheral, mdata_phys);
+
+       qcom_scm_clk_disable();
+
+free_metadata:
+       dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_init_image);
 
@@ -213,7 +227,16 @@ EXPORT_SYMBOL(qcom_scm_pas_init_image);
  */
 int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
 {
-       return __qcom_scm_pas_mem_setup(peripheral, addr, size);
+       int ret;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = __qcom_scm_pas_mem_setup(peripheral, addr, size);
+       qcom_scm_clk_disable();
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
 
@@ -226,7 +249,16 @@ EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
  */
 int qcom_scm_pas_auth_and_reset(u32 peripheral)
 {
-       return __qcom_scm_pas_auth_and_reset(peripheral);
+       int ret;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = __qcom_scm_pas_auth_and_reset(peripheral);
+       qcom_scm_clk_disable();
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
 
@@ -238,7 +270,16 @@ EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
  */
 int qcom_scm_pas_shutdown(u32 peripheral)
 {
-       return __qcom_scm_pas_shutdown(peripheral);
+       int ret;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = __qcom_scm_pas_shutdown(peripheral);
+       qcom_scm_clk_disable();
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_shutdown);
 
@@ -351,6 +392,21 @@ static int __init qcom_scm_init(void)
        return __qcom_scm_init();
 }
 
+static int qcom_scm_reset_assert(struct reset_controller_dev *rcdev, unsigned long idx)
+{
+       return __qcom_scm_pas_mss_reset(1);
+}
+
+static int qcom_scm_reset_deassert(struct reset_controller_dev *rcdev, unsigned long idx)
+{
+       return __qcom_scm_pas_mss_reset(0);
+}
+
+static struct reset_control_ops scm_reset_ops = {
+       .assert = qcom_scm_reset_assert,
+       .deassert = qcom_scm_reset_deassert,
+};
+
 static int qcom_scm_probe(struct platform_device *pdev)
 {
        struct qcom_scm *scm;
@@ -365,35 +421,45 @@ static int qcom_scm_probe(struct platform_device *pdev)
        if (!scm)
                return -ENOMEM;
 
+       scm->dev = &pdev->dev;
+
        scm->core_clk = devm_clk_get(&pdev->dev, "core");
        if (IS_ERR(scm->core_clk)) {
-               if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to acquire core clk\n");
+               if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_err(&pdev->dev, "failed to acquire core clk\n");
                scm->core_clk = NULL;
        }
 
        scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
        if (IS_ERR(scm->iface_clk)) {
-               if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to acquire iface clk\n");
+               if (PTR_ERR(scm->iface_clk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_err(&pdev->dev, "failed to acquire iface clk\n");
                scm->iface_clk = NULL;
        }
 
        scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
        if (IS_ERR(scm->bus_clk)) {
-               if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to acquire bus clk\n");
+               if (PTR_ERR(scm->bus_clk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
 
+               dev_err(&pdev->dev, "failed to acquire bus clk\n");
                scm->bus_clk = NULL;
        }
 
-       if (scm->core_clk) {
+       scm->reset.ops = &scm_reset_ops;
+       scm->reset.nr_resets = 1;
+       scm->reset.of_node = pdev->dev.of_node;
+       reset_controller_register(&scm->reset);
+
        /* vote for max clk rate for highest performance */
-               rate = clk_round_rate(scm->core_clk, INT_MAX);
-               ret = clk_set_rate(scm->core_clk, rate);
-               if (ret)
-                       return ret;
-       }
+       rate = clk_round_rate(scm->core_clk, INT_MAX);
+       ret = clk_set_rate(scm->core_clk, rate);
+       if (ret)
+               return ret;
 
        __scm = scm;
 
index 93b94c9ad34f05eb6e41067f5bf12fe10925c9af..e1d6a42ba466e6b38f28b1cb753941513a1d33e6 100644 (file)
@@ -42,11 +42,13 @@ extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
 #define QCOM_SCM_PAS_AUTH_AND_RESET_CMD        0x5
 #define QCOM_SCM_PAS_SHUTDOWN_CMD      0x6
 #define QCOM_SCM_PAS_IS_SUPPORTED_CMD  0x7
+#define QCOM_SCM_PAS_MSS_RESET         0xa
 extern bool __qcom_scm_pas_supported(u32 peripheral);
-extern int  __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size);
+extern int  __qcom_scm_pas_init_image(u32 peripheral, dma_addr_t metadata_phys);
 extern int  __qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size);
 extern int  __qcom_scm_pas_auth_and_reset(u32 peripheral);
 extern int  __qcom_scm_pas_shutdown(u32 peripheral);
+extern int  __qcom_scm_pas_mss_reset(bool reset);
 
 /* common error codes */
 #define QCOM_SCM_ENOMEM                -5
@@ -111,7 +113,6 @@ extern int __qcom_scm_iommu_secure_unmap(u32 id, u32 ctx_id, u64 va,
 extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
 extern int __qcom_scm_get_feat_version(u32 feat);
 extern int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
-extern int __qcom_scm_restart_proc(u32 proc_id, int restart, u32 *resp);
 
 extern int __qcom_scm_set_video_state(u32 state, u32 spare);
 extern int __qcom_scm_mem_protect_video_var(u32 start, u32 size,
index caf36519f410b838e3c1c1ae93ca4318d23f2a5c..b18bea08ff253398db70846445dca4ee3ea0eafc 100644 (file)
@@ -337,21 +337,6 @@ config GPIO_PXA
        help
          Say yes here to support the PXA GPIO device
 
-config GPIO_QCOM_SMSM
-       bool "Qualcomm Shared Memory State Machine"
-       depends on QCOM_SMEM
-       help
-         Say yes here to support the Qualcomm Shared Memory State Machine.
-         The state machine is represented by bits in shared memory and is
-         exposed to the system as GPIOs.
-
-config GPIO_QCOM_SMP2P
-       bool "Qualcomm Shared Memory Point to Point support"
-       depends on QCOM_SMEM
-       help
-         Say yes here to support the Qualcomm Shared Memory Point to Point
-         protocol, exposed to the system as GPIOs.
-
 config GPIO_RCAR
        tristate "Renesas R-Car GPIO"
        depends on ARCH_SHMOBILE || COMPILE_TEST
index 6c9d22e86b315fcafc06be41ba967a01edae0d54..986dbd838ceaceb03c42ffc15a704bf5f180b09d 100644 (file)
@@ -76,8 +76,6 @@ obj-$(CONFIG_GPIO_PCF857X)    += gpio-pcf857x.o
 obj-$(CONFIG_GPIO_PCH)         += gpio-pch.o
 obj-$(CONFIG_GPIO_PL061)       += gpio-pl061.o
 obj-$(CONFIG_GPIO_PXA)         += gpio-pxa.o
-obj-$(CONFIG_GPIO_QCOM_SMSM)   += gpio-qcom-smsm.o
-obj-$(CONFIG_GPIO_QCOM_SMP2P)  += gpio-qcom-smp2p.o
 obj-$(CONFIG_GPIO_RC5T583)     += gpio-rc5t583.o
 obj-$(CONFIG_GPIO_RDC321X)     += gpio-rdc321x.o
 obj-$(CONFIG_GPIO_RCAR)                += gpio-rcar.o
diff --git a/drivers/gpio/gpio-qcom-smp2p.c b/drivers/gpio/gpio-qcom-smp2p.c
deleted file mode 100644 (file)
index 164f39a..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (c) 2015, Sony Mobile Communications AB.
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/memblock.h>
-#include <linux/slab.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/regmap.h>
-#include <linux/list.h>
-#include <linux/gpio.h>
-#include <linux/mfd/syscon.h>
-
-#include <linux/delay.h>
-
-#include <linux/soc/qcom/smem.h>
-
-/*
- * The Shared Memory Point to Point (SMP2P) protocol facilitates communication
- * of a single 32-bit value between two processors.  Each value has a single
- * writer (the local side) and a single reader (the remote side). Values are
- * uniquely identified in the system by the directed edge (local processor ID
- * to remote processor ID) and a string identifier.
- *
- * Each processor is responsible for creating the outgoing SMEM items and each
- * item is writable by the local processor and readable by the remote
- * processor.  By using two separate SMEM items that are single-reader and
- * single-writer, SMP2P does not require any remote locking mechanisms.
- *
- * The driver uses the Linux GPIO and interrupt framework to expose a virtual
- * GPIO for each outbound entry and a virtual interrupt controller for each
- * inbound entry.
- */
-
-#define SMP2P_MAX_ENTRY 16
-#define SMP2P_MAX_ENTRY_NAME 16
-
-#define SMP2P_FEATURE_SSR_ACK 0x1
-
-#define SMP2P_MAGIC 0x504d5324
-
-/**
- * struct smp2p_smem_item - in memory communication structure
- * @magic:             magic number
- * @version:           version - must be 1
- * @features:          features flag - currently unused
- * @local_pid:         processor id of sending end
- * @remote_pid:                processor id of receiving end
- * @total_entries:     number of entries - always SMP2P_MAX_ENTRY
- * @valid_entries:     number of allocated entries
- * @flags:
- * @entries:           individual communication entries
- *     @name:          name of the entry
- *     @value:         content of the entry
- */
-struct smp2p_smem_item {
-       u32 magic;
-       u8 version;
-       unsigned features:24;
-       u16 local_pid;
-       u16 remote_pid;
-       u16 total_entries;
-       u16 valid_entries;
-       u32 flags;
-
-       struct {
-               u8 name[SMP2P_MAX_ENTRY_NAME];
-               u32 value;
-       } entries[SMP2P_MAX_ENTRY];
-} __packed;
-
-/**
- * struct smp2p_entry - driver context matching one entry
- * @node:      list entry to keep track of allocated entries
- * @smp2p:     reference to the device driver context
- * @name:      name of the entry, to match against smp2p_smem_item
- * @value:     pointer to smp2p_smem_item entry value
- * @last_value:        last handled value
- * @domain:    irq_domain for inbound entries
- * @irq_enabled:bitmap to track enabled irq bits
- * @irq_rising:        bitmap to mark irq bits for rising detection
- * @irq_falling:bitmap to mark irq bits for falling detection
- * @chip:      gpio_chip for outbound entries
- */
-struct smp2p_entry {
-       struct list_head node;
-       struct qcom_smp2p *smp2p;
-
-       const char *name;
-       u32 *value;
-       u32 last_value;
-
-       struct irq_domain *domain;
-       DECLARE_BITMAP(irq_enabled, 32);
-       DECLARE_BITMAP(irq_rising, 32);
-       DECLARE_BITMAP(irq_falling, 32);
-
-       struct gpio_chip chip;
-};
-
-#define SMP2P_INBOUND  0
-#define SMP2P_OUTBOUND 1
-
-/**
- * struct qcom_smp2p - device driver context
- * @dev:       device driver handle
- * @in:                pointer to the inbound smem item
- * @smem_items:        ids of the two smem items
- * @valid_entries: already scanned inbound entries
- * @local_pid: processor id of the inbound edge
- * @remote_pid:        processor id of the outbound edge
- * @ipc_regmap:        regmap for the outbound ipc
- * @ipc_offset:        offset within the regmap
- * @ipc_bit:   bit in regmap@offset to kick to signal remote processor
- * @inbound:   list of inbound entries
- * @outbound:  list of outbound entries
- */
-struct qcom_smp2p {
-       struct device *dev;
-
-       struct smp2p_smem_item *in;
-       struct smp2p_smem_item *out;
-
-       unsigned smem_items[SMP2P_OUTBOUND + 1];
-
-       unsigned valid_entries;
-
-       unsigned local_pid;
-       unsigned remote_pid;
-
-       struct regmap *ipc_regmap;
-       int ipc_offset;
-       int ipc_bit;
-
-       struct list_head inbound;
-       struct list_head outbound;
-};
-
-static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
-{
-       /* Make sure any updated data is written before the kick */
-       wmb();
-       regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit));
-}
-
-static irqreturn_t qcom_smp2p_intr(int irq, void *data)
-{
-       struct smp2p_smem_item *in;
-       struct smp2p_entry *entry;
-       struct qcom_smp2p *smp2p = data;
-       unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND];
-       unsigned pid = smp2p->remote_pid;
-       size_t size;
-       int irq_pin;
-       u32 status;
-       u32 val;
-       int i;
-       u8 tmp_name[SMP2P_MAX_ENTRY_NAME];
-
-       in = smp2p->in;
-
-       /* Acquire smem item, if not already found */
-       if (!in) {
-               in = qcom_smem_get(pid, smem_id, &size);
-               if (IS_ERR(in)) {
-                       dev_err(smp2p->dev,
-                                       "Unable to acquire remote smp2p item\n");
-                       return IRQ_HANDLED;
-               }
-
-               smp2p->in = in;
-       }
-
-       /* Match newly created entries */
-       for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
-               list_for_each_entry(entry, &smp2p->inbound, node) {
-                       memcpy_fromio(tmp_name, in->entries[i].name,
-                                       SMP2P_MAX_ENTRY_NAME);
-                       if (!strcmp(tmp_name, entry->name)) {
-                               entry->value = &in->entries[i].value;
-                               break;
-                       }
-               }
-       }
-       smp2p->valid_entries = i;
-
-       /* Fire interrupts based on any value changes */
-       list_for_each_entry(entry, &smp2p->inbound, node) {
-               /* Ignore entries not yet allocated by the remote side */
-               if (!entry->value)
-                       continue;
-
-               val = *entry->value;
-
-               status = val ^ entry->last_value;
-               entry->last_value = val;
-
-               /* No changes of this entry? */
-               if (!status)
-                       continue;
-
-               for_each_set_bit(i, entry->irq_enabled, 32) {
-                       if (!(status & BIT(i)))
-                               continue;
-
-                       if (val & BIT(i)) {
-                               if (test_bit(i, entry->irq_rising)) {
-                                       irq_pin = irq_find_mapping(entry->domain, i);
-                                       handle_nested_irq(irq_pin);
-                               }
-                       } else {
-                               if (test_bit(i, entry->irq_falling)) {
-                                       irq_pin = irq_find_mapping(entry->domain, i);
-                                       handle_nested_irq(irq_pin);
-                               }
-                       }
-
-               }
-       }
-
-       return IRQ_HANDLED;
-}
-
-static void smp2p_mask_irq(struct irq_data *irqd)
-{
-       struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
-       irq_hw_number_t irq = irqd_to_hwirq(irqd);
-
-       clear_bit(irq, entry->irq_enabled);
-}
-
-static void smp2p_unmask_irq(struct irq_data *irqd)
-{
-       struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
-       irq_hw_number_t irq = irqd_to_hwirq(irqd);
-
-       set_bit(irq, entry->irq_enabled);
-}
-
-static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type)
-{
-       struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
-       irq_hw_number_t irq = irqd_to_hwirq(irqd);
-
-       if (!(type & IRQ_TYPE_EDGE_BOTH))
-               return -EINVAL;
-
-       if (type & IRQ_TYPE_EDGE_RISING)
-               set_bit(irq, entry->irq_rising);
-       else
-               clear_bit(irq, entry->irq_rising);
-
-       if (type & IRQ_TYPE_EDGE_FALLING)
-               set_bit(irq, entry->irq_falling);
-       else
-               clear_bit(irq, entry->irq_falling);
-
-       return 0;
-}
-
-static struct irq_chip smp2p_irq_chip = {
-       .name           = "smp2p",
-       .irq_mask       = smp2p_mask_irq,
-       .irq_unmask     = smp2p_unmask_irq,
-       .irq_set_type   = smp2p_set_irq_type,
-};
-
-static int smp2p_irq_map(struct irq_domain *d,
-                        unsigned int irq,
-                        irq_hw_number_t hw)
-{
-       struct smp2p_entry *entry = d->host_data;
-
-       irq_set_chip_and_handler(irq, &smp2p_irq_chip, handle_level_irq);
-       irq_set_chip_data(irq, entry);
-       irq_set_nested_thread(irq, 1);
-
-       irq_set_noprobe(irq);
-
-       return 0;
-}
-
-static const struct irq_domain_ops smp2p_irq_ops = {
-       .map = smp2p_irq_map,
-       .xlate = irq_domain_xlate_twocell,
-};
-
-static int smp2p_gpio_direction_output(struct gpio_chip *chip,
-                                      unsigned offset,
-                                      int value)
-{
-       struct smp2p_entry *entry = container_of(chip, struct smp2p_entry, chip);
-
-       if (value)
-               *entry->value |= BIT(offset);
-       else
-               *entry->value &= ~BIT(offset);
-
-       qcom_smp2p_kick(entry->smp2p);
-
-       return 0;
-}
-
-static void smp2p_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       smp2p_gpio_direction_output(chip, offset, value);
-}
-
-static int qcom_smp2p_inbound_entry(struct qcom_smp2p *smp2p,
-                                   struct smp2p_entry *entry,
-                                   struct device_node *node)
-{
-       entry->domain = irq_domain_add_linear(node, 32, &smp2p_irq_ops, entry);
-       if (!entry->domain) {
-               dev_err(smp2p->dev, "failed to add irq_domain\n");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p,
-                                    struct smp2p_entry *entry,
-                                    struct device_node *node)
-{
-       struct smp2p_smem_item *out = smp2p->out;
-       struct gpio_chip *chip;
-       int ret;
-
-       /* Allocate an entry from the smem item */
-       memcpy_toio(out->entries[out->valid_entries].name, entry->name, SMP2P_MAX_ENTRY_NAME);
-       out->valid_entries++;
-
-       /* Make the logical entry reference the physical value */
-       entry->value = &out->entries[out->valid_entries].value;
-
-       chip = &entry->chip;
-       chip->base = -1;
-       chip->ngpio = 32;
-       chip->label = entry->name;
-       chip->dev = smp2p->dev;
-       chip->owner = THIS_MODULE;
-       chip->of_node = node;
-
-       chip->set = smp2p_gpio_set;
-       chip->direction_output = smp2p_gpio_direction_output;
-
-       ret = gpiochip_add(chip);
-       if (ret)
-               dev_err(smp2p->dev, "failed register gpiochip\n");
-
-       return 0;
-}
-
-static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
-{
-       struct smp2p_smem_item *out;
-       unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND];
-       unsigned pid = smp2p->remote_pid;
-       int ret;
-
-       ret = qcom_smem_alloc(pid, smem_id, sizeof(*out));
-       if (ret < 0 && ret != -EEXIST) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(smp2p->dev,
-                               "unable to allocate local smp2p item\n");
-               return ret;
-       }
-
-       out = qcom_smem_get(pid, smem_id, NULL);
-       if (IS_ERR(out)) {
-               dev_err(smp2p->dev, "Unable to acquire local smp2p item\n");
-               return PTR_ERR(out);
-       }
-
-       memset_io(out, 0, sizeof(*out));
-       out->magic = SMP2P_MAGIC;
-       out->local_pid = smp2p->local_pid;
-       out->remote_pid = smp2p->remote_pid;
-       out->total_entries = SMP2P_MAX_ENTRY;
-       out->valid_entries = 0;
-
-       /*
-        * Make sure the rest of the header is written before we validate the
-        * item by writing a valid version number.
-        */
-       wmb();
-       out->version = 1;
-
-       qcom_smp2p_kick(smp2p);
-
-       smp2p->out = out;
-
-       return 0;
-}
-
-static int smp2p_parse_ipc(struct qcom_smp2p *smp2p)
-{
-       struct device_node *syscon;
-       struct device *dev = smp2p->dev;
-       const char *key;
-       int ret;
-
-       syscon = of_parse_phandle(dev->of_node, "qcom,ipc", 0);
-       if (!syscon) {
-               dev_err(dev, "no qcom,ipc node\n");
-               return -ENODEV;
-       }
-
-       smp2p->ipc_regmap = syscon_node_to_regmap(syscon);
-       if (IS_ERR(smp2p->ipc_regmap))
-               return PTR_ERR(smp2p->ipc_regmap);
-
-       key = "qcom,ipc";
-       ret = of_property_read_u32_index(dev->of_node, key, 1, &smp2p->ipc_offset);
-       if (ret < 0) {
-               dev_err(dev, "no offset in %s\n", key);
-               return -EINVAL;
-       }
-
-       ret = of_property_read_u32_index(dev->of_node, key, 2, &smp2p->ipc_bit);
-       if (ret < 0) {
-               dev_err(dev, "no bit in %s\n", key);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int qcom_smp2p_probe(struct platform_device *pdev)
-{
-       struct smp2p_entry *entry;
-       struct device_node *node;
-       struct qcom_smp2p *smp2p;
-       const char *key;
-       int irq;
-       int ret;
-
-       smp2p = devm_kzalloc(&pdev->dev, sizeof(*smp2p), GFP_KERNEL);
-       if (!smp2p)
-               return -ENOMEM;
-
-       smp2p->dev = &pdev->dev;
-       INIT_LIST_HEAD(&smp2p->inbound);
-       INIT_LIST_HEAD(&smp2p->outbound);
-
-       platform_set_drvdata(pdev, smp2p);
-
-       ret = smp2p_parse_ipc(smp2p);
-       if (ret)
-               return ret;
-
-       key = "qcom,smem";
-       ret = of_property_read_u32_array(pdev->dev.of_node, key,
-                                        smp2p->smem_items, 2);
-       if (ret)
-               return ret;
-
-       key = "qcom,local-pid";
-       ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->local_pid);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to read %s\n", key);
-               return -EINVAL;
-       }
-
-       key = "qcom,remote-pid";
-       ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->remote_pid);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to read %s\n", key);
-               return -EINVAL;
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "unable to acquire smp2p interrupt\n");
-               return irq;
-       }
-
-       ret = qcom_smp2p_alloc_outbound_item(smp2p);
-       if (ret < 0)
-               return ret;
-
-       for_each_available_child_of_node(pdev->dev.of_node, node) {
-               entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL);
-               if (!entry) {
-                       ret = -ENOMEM;
-                       goto unwind_interfaces;
-               }
-
-               entry->smp2p = smp2p;
-
-               ret = of_property_read_string(node, "qcom,entry-name", &entry->name);
-               if (ret < 0)
-                       goto unwind_interfaces;
-
-               if (of_property_read_bool(node, "qcom,inbound")) {
-                       ret = qcom_smp2p_inbound_entry(smp2p, entry, node);
-                       if (ret < 0)
-                               goto unwind_interfaces;
-
-                       list_add(&entry->node, &smp2p->inbound);
-               } else if (of_property_read_bool(node, "qcom,outbound")) {
-                       ret = qcom_smp2p_outbound_entry(smp2p, entry, node);
-                       if (ret < 0)
-                               goto unwind_interfaces;
-
-                       list_add(&entry->node, &smp2p->outbound);
-               } else {
-                       dev_err(&pdev->dev, "neither inbound nor outbound\n");
-                       ret = -EINVAL;
-                       goto unwind_interfaces;
-               }
-       }
-
-       /* Kick the outgoing edge after allocating entries */
-       qcom_smp2p_kick(smp2p);
-
-       ret = devm_request_threaded_irq(&pdev->dev, irq,
-                                       NULL, qcom_smp2p_intr,
-                                       IRQF_ONESHOT,
-                                       "smp2p", (void *)smp2p);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to request interrupt\n");
-               goto unwind_interfaces;
-       }
-
-
-       return 0;
-
-unwind_interfaces:
-       list_for_each_entry(entry, &smp2p->inbound, node)
-               irq_domain_remove(entry->domain);
-
-       list_for_each_entry(entry, &smp2p->outbound, node)
-               gpiochip_remove(&entry->chip);
-
-       smp2p->out->valid_entries = 0;
-
-       return ret;
-}
-
-static int qcom_smp2p_remove(struct platform_device *pdev)
-{
-       struct qcom_smp2p *smp2p = platform_get_drvdata(pdev);
-       struct smp2p_entry *entry;
-
-       list_for_each_entry(entry, &smp2p->inbound, node)
-               irq_domain_remove(entry->domain);
-
-       list_for_each_entry(entry, &smp2p->outbound, node)
-               gpiochip_remove(&entry->chip);
-
-       smp2p->out->valid_entries = 0;
-
-       return 0;
-}
-
-static const struct of_device_id qcom_smp2p_of_match[] = {
-       { .compatible = "qcom,smp2p" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match);
-
-static struct platform_driver qcom_smp2p_driver = {
-       .probe = qcom_smp2p_probe,
-       .remove = qcom_smp2p_remove,
-       .driver  = {
-               .name  = "qcom_smp2p",
-               .of_match_table = qcom_smp2p_of_match,
-       },
-};
-module_platform_driver(qcom_smp2p_driver);
-
-MODULE_DESCRIPTION("Qualcomm Shared Memory Point to Point driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-qcom-smsm.c b/drivers/gpio/gpio-qcom-smsm.c
deleted file mode 100644 (file)
index c3e5103..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (c) 2014, Sony Mobile Communications AB.
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/memblock.h>
-#include <linux/slab.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/hwspinlock.h>
-#include <linux/regmap.h>
-#include <linux/gpio.h>
-#include <linux/mfd/syscon.h>
-
-#include <linux/delay.h>
-
-#include <linux/soc/qcom/smem.h>
-
-#define SMSM_APPS_STATE 0
-#define SMEM_SMSM_SHARED_STATE 85
-
-#define SMSM_MAX_STATES 8
-
-struct qcom_smsm_state {
-       unsigned state_id;
-       struct gpio_chip chip;
-
-       int irq;
-
-       struct regmap *ipc_regmap;
-       int ipc_bit;
-       int ipc_offset;
-};
-
-struct qcom_smsm {
-       struct device *dev;
-
-       u32 *shared_state;
-       size_t shared_state_size;
-
-       struct qcom_smsm_state states[SMSM_MAX_STATES];
-};
-
-#if 0
-int qcom_smsm_change_state(struct qcom_smsm *smsm, u32 clear_mask, u32 set_mask)
-{
-       u32 state;
-
-       dev_dbg(smsm->dev, "SMSM_APPS_STATE clear 0x%x set 0x%x\n", clear_mask, set_mask);
-       print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
-
-       state = readl(&smsm->shared_state[SMSM_APPS_STATE]);
-       state &= ~clear_mask;
-       state |= set_mask;
-       writel(state, &smsm->shared_state[SMSM_APPS_STATE]);
-
-       print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
-
-       // qcom_smem_signal(-1, smsm->smem, smsm->signal_offset, smsm->signal_bit);
-
-       return 0;
-}
-EXPORT_SYMBOL(qcom_smsm_change_state);
-#endif
-
-static struct qcom_smsm_state *to_smsm_state(struct gpio_chip *chip)
-{
-       return container_of(chip, struct qcom_smsm_state, chip);
-}
-
-static struct qcom_smsm *to_smsm(struct qcom_smsm_state *state)
-{
-       return container_of(state, struct qcom_smsm, states[state->state_id]);
-}
-
-static int smsm_gpio_direction_input(struct gpio_chip *chip,
-                                    unsigned offset)
-{
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-
-       if (state->state_id == SMSM_APPS_STATE)
-               return -EINVAL;
-       return 0;
-}
-
-static int smsm_gpio_direction_output(struct gpio_chip *chip,
-                                     unsigned offset,
-                                     int value)
-{
-       struct qcom_smsm_state *ipc_state;
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-       struct qcom_smsm *smsm = to_smsm(state);
-       unsigned word;
-       unsigned bit;
-       u32 val;
-       int i;
-
-       /* Only SMSM_APPS_STATE supports writing */
-       if (state->state_id != SMSM_APPS_STATE)
-               return -EINVAL;
-
-       offset += state->state_id * 32;
-
-       word = ALIGN(offset / 32, 4);
-       bit = offset % 32;
-
-       val = readl(smsm->shared_state + word);
-       if (value)
-               val |= BIT(bit);
-       else
-               val &= ~BIT(bit);
-       writel(val, smsm->shared_state + word);
-
-       /* XXX: send out interrupts */
-       for (i = 0; i < SMSM_MAX_STATES; i++) {
-               ipc_state = &smsm->states[i];
-               if (!ipc_state->ipc_regmap)
-                       continue;
-
-               regmap_write(ipc_state->ipc_regmap, ipc_state->ipc_offset, BIT(ipc_state->ipc_bit));
-       }
-
-       dev_err(smsm->dev, "set %d %d\n", offset, value);
-
-       return 0;
-}
-
-static int smsm_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-       struct qcom_smsm *smsm = to_smsm(state);
-       unsigned word;
-       unsigned bit;
-       u32 val;
-
-       offset += state->state_id * 32;
-
-       word = ALIGN(offset / 32, 4);
-       bit = offset % 32;
-
-       val = readl(smsm->shared_state + word);
-
-       return !!(val & BIT(bit));
-}
-
-static void smsm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       smsm_gpio_direction_output(chip, offset, value);
-}
-
-static int smsm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       return -EINVAL;
-}
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/seq_file.h>
-
-static void smsm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-       struct qcom_smsm *smsm = to_smsm(state);
-       unsigned i;
-       u32 val;
-
-       val = readl(smsm->shared_state + state->state_id * 4);
-
-       for (i = 0; i < 32; i++) {
-               if (val & BIT(i))
-                       seq_puts(s, "1");
-               else
-                       seq_puts(s, "0");
-
-               if (i == 7 || i == 15 || i == 23)
-                       seq_puts(s, " ");
-       }
-       seq_puts(s, "\n");
-}
-
-#else
-#define smsm_gpio_dbg_show NULL
-#endif
-
-static struct gpio_chip smsm_gpio_template = {
-       .direction_input = smsm_gpio_direction_input,
-       .direction_output = smsm_gpio_direction_output,
-       .get = smsm_gpio_get,
-       .set = smsm_gpio_set,
-       .to_irq = smsm_gpio_to_irq,
-       .dbg_show = smsm_gpio_dbg_show,
-       .owner = THIS_MODULE,
-};
-
-static int qcom_smsm_probe(struct platform_device *pdev)
-{
-       struct qcom_smsm_state *state;
-       struct device_node *syscon_np;
-       struct device_node *node;
-       struct qcom_smsm *smsm;
-       char *key;
-       u32 sid;
-       int ret;
-
-       smsm = devm_kzalloc(&pdev->dev, sizeof(*smsm), GFP_KERNEL);
-       if (!smsm)
-               return -ENOMEM;
-       smsm->dev = &pdev->dev;
-
-       ret = qcom_smem_alloc(-1, SMEM_SMSM_SHARED_STATE, 8 * sizeof(uint32_t));
-       if (ret < 0 && ret != -EEXIST) {
-               dev_err(&pdev->dev, "unable to allocate shared state entry\n");
-               return ret;
-       }
-
-       smsm->shared_state = qcom_smem_get(-1, SMEM_SMSM_SHARED_STATE,
-                           &smsm->shared_state_size);
-       if (IS_ERR(smsm->shared_state)) {
-               dev_err(&pdev->dev, "Unable to acquire shared state entry\n");
-               return PTR_ERR(smsm->shared_state);
-       }
-
-       dev_err(smsm->dev, "SMEM_SMSM_SHARED_STATE: %d, %zu\n", ret, smsm->shared_state_size);
-       print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
-
-       for_each_child_of_node(pdev->dev.of_node, node) {
-               key = "reg";
-               ret = of_property_read_u32(node, key, &sid);
-               if (ret || sid >= SMSM_MAX_STATES) {
-                       dev_err(&pdev->dev, "smsm state missing %s\n", key);
-                       return -EINVAL;
-               }
-               state = &smsm->states[sid];
-               state->state_id = sid;
-
-               state->chip = smsm_gpio_template;
-               state->chip.base = -1;
-               state->chip.dev = &pdev->dev;
-               state->chip.of_node = node;
-               state->chip.label = node->name;
-               state->chip.ngpio = 8 * sizeof(u32);
-               ret = gpiochip_add(&state->chip);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed register gpiochip\n");
-                       // goto wooha;
-               }
-
-               /* The remaining properties are only for non-apps state */
-               if (sid == SMSM_APPS_STATE)
-                       continue;
-
-               state->irq = irq_of_parse_and_map(node, 0);
-               if (state->irq < 0 && state->irq != -EINVAL) {
-                       dev_err(&pdev->dev, "failed to parse smsm interrupt\n");
-                       return -EINVAL;
-               }
-
-               syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
-               if (!syscon_np) {
-                       dev_err(&pdev->dev, "no qcom,ipc node\n");
-                       return -ENODEV;
-               }
-
-               state->ipc_regmap = syscon_node_to_regmap(syscon_np);
-               if (IS_ERR(state->ipc_regmap))
-                       return PTR_ERR(state->ipc_regmap);
-
-               key = "qcom,ipc";
-               ret = of_property_read_u32_index(node, key, 1, &state->ipc_offset);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "no offset in %s\n", key);
-                       return -EINVAL;
-               }
-
-               ret = of_property_read_u32_index(node, key, 2, &state->ipc_bit);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "no bit in %s\n", key);
-                       return -EINVAL;
-               }
-
-       }
-
-       return 0;
-}
-
-static const struct of_device_id qcom_smsm_of_match[] = {
-       { .compatible = "qcom,smsm" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, qcom_smsm_of_match);
-
-static struct platform_driver qcom_smsm_driver = {
-       .probe          = qcom_smsm_probe,
-       .driver  = {
-               .name  = "qcom_smsm",
-               .owner = THIS_MODULE,
-               .of_match_table = qcom_smsm_of_match,
-       },
-};
-
-static int __init qcom_smsm_init(void)
-{
-       return platform_driver_register(&qcom_smsm_driver);
-}
-arch_initcall(qcom_smsm_init);
-
-static void __exit qcom_smsm_exit(void)
-{
-       platform_driver_unregister(&qcom_smsm_driver);
-}
-module_exit(qcom_smsm_exit)
-
-MODULE_DESCRIPTION("Qualcomm Shared Memory Signaling Mechanism");
-MODULE_LICENSE("GPLv2");
index ab46e6a743e0145b330c0a041cc4ef843e21d032..be522ac6cc81167f24a2f42966d3f69f4d97b0b5 100644 (file)
@@ -17,8 +17,9 @@
  */
 
 #include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+
 #include <sound/hdmi-codec.h>
-#include <sound/msm_hdmi_audio.h>
 #include "hdmi.h"
 
 void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
@@ -417,7 +418,114 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char
 }
 #endif
 
-static void msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev);
+/*
+ * HDMI audio codec callbacks
+ */
+static int msm_hdmi_audio_hw_params(struct device *dev,
+                                   struct hdmi_codec_daifmt *daifmt,
+                                   struct hdmi_codec_params *params)
+{
+       struct hdmi *hdmi = dev_get_drvdata(dev);
+       unsigned int chan;
+       unsigned int channel_allocation = 0;
+       unsigned int rate;
+       unsigned int level_shift  = 0; /* 0dB */
+       bool down_mix = false;
+
+       dev_dbg(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate,
+                params->sample_width, params->cea.channels);
+
+       switch (params->cea.channels) {
+       case 2:
+               /* FR and FL speakers */
+               channel_allocation  = 0;
+               chan = MSM_HDMI_AUDIO_CHANNEL_2;
+               break;
+       case 4:
+               /* FC, LFE, FR and FL speakers */
+               channel_allocation  = 0x3;
+               chan = MSM_HDMI_AUDIO_CHANNEL_4;
+               break;
+       case 6:
+               /* RR, RL, FC, LFE, FR and FL speakers */
+               channel_allocation  = 0x0B;
+               chan = MSM_HDMI_AUDIO_CHANNEL_6;
+               break;
+       case 8:
+               /* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */
+               channel_allocation  = 0x1F;
+               chan = MSM_HDMI_AUDIO_CHANNEL_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params->sample_rate) {
+       case 32000:
+               rate = HDMI_SAMPLE_RATE_32KHZ;
+               break;
+       case 44100:
+               rate = HDMI_SAMPLE_RATE_44_1KHZ;
+               break;
+       case 48000:
+               rate = HDMI_SAMPLE_RATE_48KHZ;
+               break;
+       case 88200:
+               rate = HDMI_SAMPLE_RATE_88_2KHZ;
+               break;
+       case 96000:
+               rate = HDMI_SAMPLE_RATE_96KHZ;
+               break;
+       case 176400:
+               rate = HDMI_SAMPLE_RATE_176_4KHZ;
+               break;
+       case 192000:
+               rate = HDMI_SAMPLE_RATE_192KHZ;
+               break;
+       default:
+               dev_err(dev, "rate[%d] not supported!\n",
+                       params->sample_rate);
+               return -EINVAL;
+       }
+
+       hdmi_audio_set_sample_rate(hdmi, rate);
+       hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation,
+                             level_shift, down_mix);
+
+       return 0;
+}
+
+static void msm_hdmi_audio_shutdown(struct device *dev)
+{
+       struct hdmi *hdmi = dev_get_drvdata(dev);
+
+       hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
+}
+
+static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
+       .hw_params = msm_hdmi_audio_hw_params,
+       .audio_shutdown = msm_hdmi_audio_shutdown,
+};
+
+static struct hdmi_codec_pdata codec_data = {
+       .ops = &msm_hdmi_audio_codec_ops,
+       .max_i2s_channels = 8,
+       .i2s = 1,
+};
+
+static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev)
+{
+       hdmi->audio_pdev = platform_device_register_data(dev,
+                                                        HDMI_CODEC_DRV_NAME,
+                                                        PLATFORM_DEVID_AUTO,
+                                                        &codec_data,
+                                                        sizeof(codec_data));
+       if (IS_ERR(hdmi->audio_pdev))
+               return PTR_ERR(hdmi->audio_pdev);
+
+       return 0;
+}
+
 static int hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        struct drm_device *drm = dev_get_drvdata(master);
@@ -427,6 +535,7 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
 #ifdef CONFIG_OF
        struct device_node *of_node = dev->of_node;
        const struct of_device_id *match;
+       int err;
 
        match = of_match_node(dt_match, of_node);
        if (match && match->data) {
@@ -501,7 +610,12 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
        if (IS_ERR(hdmi))
                return PTR_ERR(hdmi);
        priv->hdmi = hdmi;
-       msm_hdmi_register_audio_driver(hdmi, dev);
+
+       err = msm_hdmi_register_audio_driver(hdmi, dev);
+       if (err) {
+               DRM_ERROR("Failed to attach an audio codec %d\n", err);
+               hdmi->audio_pdev = NULL;
+       }
 
        return 0;
 }
@@ -512,9 +626,10 @@ static void hdmi_unbind(struct device *dev, struct device *master,
        struct drm_device *drm = dev_get_drvdata(master);
        struct msm_drm_private *priv = drm->dev_private;
        if (priv->hdmi) {
-               DRM_INFO("%s driver unbound to HDMI\n", HDMI_CODEC_DRV_NAME);
-               platform_device_unregister(priv->hdmi->audio_pdev);
                hdmi_destroy(priv->hdmi);
+               if (priv->hdmi->audio_pdev)
+                       platform_device_unregister(priv->hdmi->audio_pdev);
+
                priv->hdmi = NULL;
        }
 }
@@ -523,124 +638,6 @@ static const struct component_ops hdmi_ops = {
                .bind   = hdmi_bind,
                .unbind = hdmi_unbind,
 };
-/*
- * HDMI audio codec callbacks
- */
-
-static int msm_hdmi_audio_hw_params(struct device *dev,
-                                   struct hdmi_codec_daifmt *daifmt,
-                                   struct hdmi_codec_params *params)
-{
-       struct hdmi *hdmi = dev_get_drvdata(dev);
-       unsigned int chan;// = params->cea.channels;
-       unsigned int channel_allocation = 0;
-       unsigned int rate;//
-       unsigned int level_shift  = 0; /* 0dB */
-       bool down_mix = false;
-       dev_dbg(dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
-               params->sample_rate, params->sample_width, chan);
-
-       switch (params->cea.channels) {
-       case 2:
-               channel_allocation  = 0;
-               chan = MSM_HDMI_AUDIO_CHANNEL_2;
-               break;
-       case 4:
-               channel_allocation  = 0;
-               chan = MSM_HDMI_AUDIO_CHANNEL_4;
-               break;
-       case 6:
-               channel_allocation  = 0x0B;
-               chan = MSM_HDMI_AUDIO_CHANNEL_6;
-               break;
-       case 8:
-               channel_allocation  = 0x1F;
-               chan = MSM_HDMI_AUDIO_CHANNEL_8;
-               break;
-       default:
-               //dev_err(hdmi->dev, "channel[%d] not supported!\n", chan);
-               return -EINVAL;
-       }
-
-       switch (params->sample_rate) {
-       case 32000:
-               rate = HDMI_SAMPLE_RATE_32KHZ;
-       case 44100:
-               rate = HDMI_SAMPLE_RATE_48KHZ;
-       case 48000:
-               rate = HDMI_SAMPLE_RATE_48KHZ;
-       case 88200:
-               rate = HDMI_SAMPLE_RATE_88_2KHZ;
-       case 96000:
-               rate = HDMI_SAMPLE_RATE_96KHZ;
-       case 176400:
-               rate = HDMI_SAMPLE_RATE_176_4KHZ;
-       case 192000:
-               rate = HDMI_SAMPLE_RATE_192KHZ;
-               break;
-       default:
-               dev_err(dev, "rate[%d] not supported!\n",
-                       params->sample_rate);
-               return -EINVAL;
-       }
-               rate = HDMI_SAMPLE_RATE_48KHZ;
-               channel_allocation  = 0;
-
-       //FIXME..
-       hdmi_audio_set_sample_rate(hdmi, rate);
-
-       hdmi_audio_info_setup(hdmi, 1, chan,
-                       channel_allocation, level_shift, down_mix);
-
-
-
-       return 0;
-}
-
-static int msm_hdmi_audio_startup(struct device *dev,
-                                 void (*abort_cb)(struct device *dev))
-{
-       struct hdmi *hdmi = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "%s\n", __func__);
-
-       //msm_hdmi_audio_enable(hdmi);
-
-       return 0;
-}
-
-static void msm_hdmi_audio_shutdown(struct device *dev)
-{
-       struct hdmi *hdmi = dev_get_drvdata(dev);
-
-       dev_dbg(dev, "%s\n", __func__);
-
-       hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0);
-}
-
-static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = {
-       .hw_params = msm_hdmi_audio_hw_params,
-       .audio_startup = msm_hdmi_audio_startup,
-       .audio_shutdown = msm_hdmi_audio_shutdown,
-};
-
-static void msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev)
-{
-       struct hdmi_codec_pdata codec_data = {
-               .ops = &msm_hdmi_audio_codec_ops,
-               .max_i2s_channels = 2,
-               .i2s = 1,
-       };
-       //struct platform_device *pdev;
-
-       hdmi->audio_pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
-                                            PLATFORM_DEVID_AUTO, &codec_data,
-                                            sizeof(codec_data));
-       if (IS_ERR(hdmi->audio_pdev))
-               return;
-
-       DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
-}
 
 static int hdmi_dev_probe(struct platform_device *pdev)
 {
index 7eb16bee51913a76574b52501d1e4002836c7682..c70bd1585e8a1fd2692e7a9071b546783bcbf222 100644 (file)
@@ -155,6 +155,19 @@ struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi);
 /*
  * audio:
  */
+/* Supported HDMI Audio channels and rates */
+#define        MSM_HDMI_AUDIO_CHANNEL_2        0
+#define        MSM_HDMI_AUDIO_CHANNEL_4        1
+#define        MSM_HDMI_AUDIO_CHANNEL_6        2
+#define        MSM_HDMI_AUDIO_CHANNEL_8        3
+
+#define        HDMI_SAMPLE_RATE_32KHZ          0
+#define        HDMI_SAMPLE_RATE_44_1KHZ        1
+#define        HDMI_SAMPLE_RATE_48KHZ          2
+#define        HDMI_SAMPLE_RATE_88_2KHZ        3
+#define        HDMI_SAMPLE_RATE_96KHZ          4
+#define        HDMI_SAMPLE_RATE_176_4KHZ       5
+#define        HDMI_SAMPLE_RATE_192KHZ         6
 
 int hdmi_audio_update(struct hdmi *hdmi);
 int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
index 1c2caffc97e400b650b96a3e554fb5fe25d312a8..b4a8aa4490eed8ced3aaf167d4172331abcd5d4f 100644 (file)
@@ -105,6 +105,12 @@ static const struct mdp_format formats[] = {
                        MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4,
                        MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+       FMT(XBGR8888, 8, 8, 8, 8,  2, 0, 1, 3,  false,   true,  4,  4,
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+       FMT(RGBX8888, 8, 8, 8, 8,  3, 1, 0, 2,  false,   true,  4,  4,
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
+       FMT(BGRX8888, 8, 8, 8, 8,  3, 2, 0, 1,  false,   true,  4,  4,
+                       MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(RGB888,   0, 8, 8, 8,  1, 0, 2, 0,  false,  true,  3,  3,
                        MDP_PLANE_INTERLEAVED, CHROMA_FULL, false),
        FMT(BGR888,   0, 8, 8, 8,  2, 0, 1, 0,  false,  true,  3,  3,
index edb71cb9e5f7361b68f52ddae00df515e68e3dd4..68184c7f80895ac87df6d5e31397640cc6724414 100644 (file)
 
 #define CORE_HC_MODE           0x78
 #define HC_MODE_EN             0x1
+
 #define CORE_POWER             0x0
 #define CORE_SW_RST            BIT(7)
 
+#define CORE_PWRCTL_STATUS     0xdc
+#define CORE_PWRCTL_MASK       0xe0
+#define CORE_PWRCTL_CLEAR      0xe4
+#define CORE_PWRCTL_CTL                0xe8
+
+#define CORE_PWRCTL_BUS_OFF    BIT(0)
+#define CORE_PWRCTL_BUS_ON     BIT(1)
+#define CORE_PWRCTL_IO_LOW     BIT(2)
+#define CORE_PWRCTL_IO_HIGH    BIT(3)
+#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
+#define CORE_PWRCTL_IO_SUCCESS BIT(2)
+#define REQ_BUS_OFF            BIT(0)
+#define REQ_BUS_ON             BIT(1)
+#define REQ_IO_LOW             BIT(2)
+#define REQ_IO_HIGH            BIT(3)
+
+#define INT_MASK               0xf
 #define MAX_PHASES             16
 #define CORE_DLL_LOCK          BIT(7)
 #define CORE_DLL_EN            BIT(16)
 struct sdhci_msm_host {
        struct platform_device *pdev;
        void __iomem *core_mem; /* MSM SDCC mapped address */
+       int pwr_irq;            /* power irq */
        struct clk *clk;        /* main SD/MMC bus clock */
        struct clk *pclk;       /* SDHC peripheral bus clock */
        struct clk *bus_clk;    /* SDHC bus voter clock */
        struct mmc_host *mmc;
-       struct sdhci_pltfm_data sdhci_msm_pdata;
 };
 
 /* Platform specific tuning */
@@ -411,6 +429,39 @@ retry:
        return rc;
 }
 
+static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       u32 irq_status, irq_ack = 0;
+
+       irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+       irq_status &= INT_MASK;
+
+       writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
+
+       if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
+               irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+       if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
+               irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+
+       /*
+        * The driver has to acknowledge the interrupt, switch voltages and
+        * report back if it succeded or not to this register. The voltage
+        * switches are handled by the sdhci core, so just report success.
+        */
+       writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+}
+
+static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
+{
+       struct sdhci_host *host = (struct sdhci_host *)data;
+
+       sdhci_msm_voltage_switch(host);
+
+       return IRQ_HANDLED;
+}
+
 static const struct of_device_id sdhci_msm_dt_match[] = {
        { .compatible = "qcom,sdhci-msm-v4" },
        {},
@@ -418,12 +469,20 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
 
 MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 
-static struct sdhci_ops sdhci_msm_ops = {
+static const struct sdhci_ops sdhci_msm_ops = {
        .platform_execute_tuning = sdhci_msm_execute_tuning,
        .reset = sdhci_reset,
        .set_clock = sdhci_set_clock,
        .set_bus_width = sdhci_set_bus_width,
        .set_uhs_signaling = sdhci_set_uhs_signaling,
+       .voltage_switch = sdhci_msm_voltage_switch,
+};
+
+static const struct sdhci_pltfm_data sdhci_msm_pdata = {
+       .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                 SDHCI_QUIRK_SINGLE_POWER_WRITE |
+                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       .ops = &sdhci_msm_ops,
 };
 
 static int sdhci_msm_probe(struct platform_device *pdev)
@@ -437,17 +496,12 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        u32 core_version, caps;
        u8 core_major;
 
-       msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
-       if (!msm_host)
-               return -ENOMEM;
-
-       msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
-       host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
+       host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
        if (IS_ERR(host))
                return PTR_ERR(host);
 
        pltfm_host = sdhci_priv(host);
-       pltfm_host->priv = msm_host;
+       msm_host = sdhci_pltfm_priv(pltfm_host);
        msm_host->mmc = host->mmc;
        msm_host->pdev = pdev;
 
@@ -522,10 +576,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        /* Set HC_MODE_EN bit in HC_MODE register */
        writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
 
-       host->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
-       host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-       host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
-
        host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
        dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
                host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
@@ -549,6 +599,22 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                               CORE_VENDOR_SPEC_CAPABILITIES0);
        }
 
+       /* Setup IRQ for handling power/voltage tasks with PMIC */
+       msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+       if (msm_host->pwr_irq < 0) {
+               dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n",
+                       msm_host->pwr_irq);
+               goto clk_disable;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
+                                       sdhci_msm_pwr_irq, IRQF_ONESHOT,
+                                       dev_name(&pdev->dev), host);
+       if (ret) {
+               dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
+               goto clk_disable;
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto clk_disable;
@@ -571,16 +637,16 @@ static int sdhci_msm_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_msm_host *msm_host = pltfm_host->priv;
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
        int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
                    0xffffffff);
 
        sdhci_remove_host(host, dead);
-       sdhci_pltfm_free(pdev);
        clk_disable_unprepare(msm_host->clk);
        clk_disable_unprepare(msm_host->pclk);
        if (!IS_ERR(msm_host->bus_clk))
                clk_disable_unprepare(msm_host->bus_clk);
+       sdhci_pltfm_free(pdev);
        return 0;
 }
 
index 591ebaea826564bf339f82b8152394dca022b5e8..394fe5b77c904b92fcd494e86eaad7863a49fe72 100644 (file)
@@ -1,6 +1,6 @@
 config WCN36XX
        tristate "Qualcomm Atheros WCN3660/3680 support"
-       depends on MAC80211 && HAS_DMA
+       depends on MAC80211 && HAS_DMA && QCOM_SMD
        ---help---
          This module adds support for wireless adapters based on
          Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
index 9f6370f0cabc199234128a9693f586d0202beeaf..50c43b4382bacd91c9ff8380a1af0eaaafea5ba1 100644 (file)
@@ -1,10 +1,7 @@
-obj-$(CONFIG_WCN36XX) := wcn36xx.o wcn36xx-platform.o
+obj-$(CONFIG_WCN36XX) := wcn36xx.o
 wcn36xx-y +=   main.o \
                dxe.o \
                txrx.o \
                smd.o \
                pmc.o \
                debug.o
-
-wcn36xx-platform-y     += wcn36xx-msm.o\
-       wcnss_core.o
index af0e515f634da99f002c07c859a9822b5818a34f..87dfdaf9044cdf8b41aba6b8345e9d2f9dd325a6 100644 (file)
@@ -23,6 +23,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/interrupt.h>
+#include <linux/soc/qcom/smem_state.h>
 #include "wcn36xx.h"
 #include "txrx.h"
 
@@ -35,26 +36,27 @@ void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low)
        return ch->head_blk_ctl->bd_cpu_addr;
 }
 
+static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
+{
+       wcn36xx_dbg(WCN36XX_DBG_DXE,
+                   "wcn36xx_ccu_write_register: addr=%x, data=%x\n",
+                   addr, data);
+
+       writel(data, wcn->ccu_base + addr);
+}
+
 static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
 {
        wcn36xx_dbg(WCN36XX_DBG_DXE,
                    "wcn36xx_dxe_write_register: addr=%x, data=%x\n",
                    addr, data);
 
-       writel(data, wcn->mmio + addr);
+       writel(data, wcn->dxe_base + addr);
 }
 
-#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data)                \
-do {                                                                    \
-       if (wcn->chip_version != WCN36XX_CHIP_3660)                      \
-               wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \
-       else                                                             \
-               wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \
-} while (0)                                                             \
-
 static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
 {
-       *data = readl(wcn->mmio + addr);
+       *data = readl(wcn->dxe_base + addr);
 
        wcn36xx_dbg(WCN36XX_DBG_DXE,
                    "wcn36xx_dxe_read_register: addr=%x, data=%x\n",
@@ -150,9 +152,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
                goto out_err;
 
        /* Initialize SMSM state  Clear TX Enable RING EMPTY STATE */
-       ret = wcn->ctrl_ops->smsm_change_state(
-               WCN36XX_SMSM_WLAN_TX_ENABLE,
-               WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+       ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
+                                         WCN36XX_SMSM_WLAN_TX_ENABLE |
+                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
+                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+       if (ret)
+               goto out_err;
 
        return 0;
 
@@ -677,9 +682,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
         * notify chip about new frame through SMSM bus.
         */
        if (is_low &&  vif_priv->pw_state == WCN36XX_BMPS) {
-               wcn->ctrl_ops->smsm_change_state(
-                                 0,
-                                 WCN36XX_SMSM_WLAN_TX_ENABLE);
+               qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
+                                           WCN36XX_SMSM_WLAN_TX_ENABLE,
+                                           WCN36XX_SMSM_WLAN_TX_ENABLE);
        } else {
                /* indicate End Of Packet and generate interrupt on descriptor
                 * done.
@@ -701,9 +706,13 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
        reg_data = WCN36XX_DXE_REG_RESET;
        wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
 
-       /* Setting interrupt path */
-       reg_data = WCN36XX_DXE_CCU_INT;
-       wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
+       /* Select channels for rx avail and xfer done interrupts... */
+       reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 |
+                   WCN36XX_DXE_INT_CH0_MASK | WCN36XX_DXE_INT_CH4_MASK;
+       if (wcn->is_pronto)
+               wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_PRONTO, reg_data);
+       else
+               wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_RIVA, reg_data);
 
        /***************************************/
        /* Init descriptors for TX LOW channel */
index 3eca4f9594f2a3a3c638996fd13daae66e473283..c012e807753b763112a1be05b046b71f2d51087f 100644 (file)
@@ -28,11 +28,10 @@ H2H_TEST_RX_TX = DMA2
 */
 
 /* DXE registers */
-#define WCN36XX_DXE_MEM_REG                    0x202000
+#define WCN36XX_DXE_MEM_REG                    0
 
-#define WCN36XX_DXE_CCU_INT                    0xA0011
-#define WCN36XX_DXE_REG_CCU_INT_3660           0x200b10
-#define WCN36XX_DXE_REG_CCU_INT_3680           0x2050dc
+#define WCN36XX_CCU_DXE_INT_SELECT_RIVA                0x310
+#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO      0x10dc
 
 /* TODO This must calculated properly but not hardcoded */
 #define WCN36XX_DXE_CTRL_TX_L                  0x328a44
index dbf1769a969920875e198436214eff8906c0a59d..4f87ef1e1eb866808ecc0b071b28d7bd4bbaeff1 100644 (file)
@@ -51,7 +51,7 @@
 #define WCN36XX_HAL_STA_INVALID_IDX 0xFF
 #define WCN36XX_HAL_BSS_INVALID_IDX 0xFF
 
-/* Default Beacon template size. */
+/* Default Beacon template size */
 #define BEACON_TEMPLATE_SIZE 0x180
 
 /* Minimum PVM size that the FW expects. See comment in smd.c for details. */
@@ -350,8 +350,6 @@ enum wcn36xx_hal_host_msg_type {
 
        WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
 
-       WCN36XX_HAL_PRINT_REG_INFO_IND = 259,
-
        WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE
 };
 
@@ -2889,11 +2887,13 @@ struct update_beacon_rsp_msg {
 struct wcn36xx_hal_send_beacon_req_msg {
        struct wcn36xx_hal_msg_header header;
 
-       /* length of the template + sizeof(beacon_length) */
-       u32 template_length;
+       /* length of the template + 6. Only qcom knows why */
+       u32 beacon_length6;
 
-       /* Beacon data. */
+       /* length of the template. */
        u32 beacon_length;
+
+       /* Beacon data. */
        u8 beacon[BEACON_TEMPLATE_SIZE - sizeof(u32)];
 
        u8 bssid[ETH_ALEN];
@@ -4123,7 +4123,7 @@ struct wcn36xx_hal_update_scan_params_req {
 
 /* Update scan params - sent from host to PNO to be used during PNO
  * scanningx */
-struct update_scan_params_req_ex {
+struct wcn36xx_hal_update_scan_params_req_ex {
 
        struct wcn36xx_hal_msg_header header;
 
@@ -4151,7 +4151,7 @@ struct update_scan_params_req_ex {
 
        /* Cb State */
        enum phy_chan_bond_state state;
-};
+} __packed;
 
 /* Update scan params - sent from host to PNO to be used during PNO
  * scanningx */
index cc4903cdc666b0cf16553d9dc9764dd7de5c0854..2d9402e718fc6aafd4bda5787e5ad2cded519e50 100644 (file)
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/smem_state.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
 #include "wcn36xx.h"
 
 unsigned int wcn36xx_dbg_mask;
@@ -26,14 +32,14 @@ module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644);
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 
 #define CHAN2G(_freq, _idx) { \
-       .band = IEEE80211_BAND_2GHZ, \
+       .band = NL80211_BAND_2GHZ, \
        .center_freq = (_freq), \
        .hw_value = (_idx), \
        .max_power = 25, \
 }
 
 #define CHAN5G(_freq, _idx) { \
-       .band = IEEE80211_BAND_5GHZ, \
+       .band = NL80211_BAND_5GHZ, \
        .center_freq = (_freq), \
        .hw_value = (_idx), \
        .max_power = 25, \
@@ -313,8 +319,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
                        wcn36xx_feat_caps_info(wcn);
        }
 
-       wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
-
        /* DMA channel initialization */
        ret = wcn36xx_dxe_init(wcn);
        if (ret) {
@@ -381,8 +385,6 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
        return 0;
 }
 
-#define WCN36XX_SUPPORTED_FILTERS (FIF_ALLMULTI)
-
 static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
                                     unsigned int changed,
                                     unsigned int *total, u64 multicast)
@@ -394,7 +396,7 @@ static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
 
-       *total &= WCN36XX_SUPPORTED_FILTERS;
+       *total &= FIF_ALLMULTI;
 
        fp = (void *)(unsigned long)multicast;
        list_for_each_entry(tmp, &wcn->vif_list, list) {
@@ -566,27 +568,61 @@ out:
        return ret;
 }
 
-static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,
-                                 struct ieee80211_vif *vif,
-                                 const u8 *mac_addr)
+static void wcn36xx_hw_scan_worker(struct work_struct *work)
 {
-       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx *wcn = container_of(work, struct wcn36xx, scan_work);
+       struct cfg80211_scan_request *req = wcn->scan_req;
+       u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX];
+       int i;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 scan %d channels worker\n", req->n_channels);
+
+       for (i = 0; i < req->n_channels; i++)
+               channels[i] = req->channels[i]->hw_value;
+
+       wcn36xx_smd_update_scan_params(wcn, channels, req->n_channels);
 
        wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
-       wcn36xx_smd_start_scan(wcn);
+       for (i = 0; i < req->n_channels; i++) {
+               wcn->scan_freq = req->channels[i]->center_freq;
+               wcn->scan_band = req->channels[i]->band;
+
+               wcn36xx_smd_start_scan(wcn, req->channels[i]->hw_value);
+               msleep(30);
+               wcn36xx_smd_end_scan(wcn, req->channels[i]->hw_value);
+
+               wcn->scan_freq = 0;
+       }
+       wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+
+       ieee80211_scan_completed(wcn->hw, false);
+
+       mutex_lock(&wcn->scan_lock);
+       wcn->scan_req = NULL;
+       mutex_unlock(&wcn->scan_lock);
 }
 
-static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
-                                    struct ieee80211_vif *vif)
+static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif,
+                          struct ieee80211_scan_request *hw_req)
 {
        struct wcn36xx *wcn = hw->priv;
 
-       wcn36xx_smd_end_scan(wcn);
-       wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+       mutex_lock(&wcn->scan_lock);
+       if (wcn->scan_req) {
+               mutex_unlock(&wcn->scan_lock);
+               return -EBUSY;
+       }
+       wcn->scan_req = &hw_req->req;
+       mutex_unlock(&wcn->scan_lock);
+
+       schedule_work(&wcn->scan_work);
+
+       return 0;
 }
 
 static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
-                                        enum ieee80211_band band)
+                                        enum nl80211_band band)
 {
        int i, size;
        u16 *rates_table;
@@ -599,7 +635,7 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
 
        size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);
        rates_table = sta_priv->supported_rates.dsss_rates;
-       if (band == IEEE80211_BAND_2GHZ) {
+       if (band == NL80211_BAND_2GHZ) {
                for (i = 0; i < size; i++) {
                        if (rates & 0x01) {
                                rates_table[i] = wcn_2ghz_rates[i].hw_value;
@@ -993,8 +1029,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
        .configure_filter       = wcn36xx_configure_filter,
        .tx                     = wcn36xx_tx,
        .set_key                = wcn36xx_set_key,
-       .sw_scan_start          = wcn36xx_sw_scan_start,
-       .sw_scan_complete       = wcn36xx_sw_scan_complete,
+       .hw_scan                = wcn36xx_hw_scan,
        .bss_info_changed       = wcn36xx_bss_info_changed,
        .set_rts_threshold      = wcn36xx_set_rts_threshold,
        .sta_add                = wcn36xx_sta_add,
@@ -1019,18 +1054,18 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
        ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
        ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
        ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
-
-       /* 3620 powersaving currently unstable */
-       if (wcn->chip_version == WCN36XX_CHIP_3620)
-               __clear_bit(IEEE80211_HW_SUPPORTS_PS, wcn->hw->flags);
+       ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS);
 
        wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_ADHOC) |
                BIT(NL80211_IFTYPE_MESH_POINT);
 
-       wcn->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wcn_band_2ghz;
-       wcn->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wcn_band_5ghz;
+       wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz;
+       wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz;
+
+       wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS;
+       wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN;
 
        wcn->hw->wiphy->cipher_suites = cipher_suites;
        wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -1059,10 +1094,13 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
 static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
                                          struct platform_device *pdev)
 {
+       struct device_node *mmio_node;
        struct resource *res;
+       int index;
+       int ret;
+
        /* Set TX IRQ */
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          "wcnss_wlantx_irq");
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx");
        if (!res) {
                wcn36xx_err("failed to get tx_irq\n");
                return -ENOENT;
@@ -1070,38 +1108,77 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
        wcn->tx_irq = res->start;
 
        /* Set RX IRQ */
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          "wcnss_wlanrx_irq");
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx");
        if (!res) {
                wcn36xx_err("failed to get rx_irq\n");
                return -ENOENT;
        }
        wcn->rx_irq = res->start;
 
-       /* Map the memory */
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                "wcnss_mmio");
-       if (!res) {
-               wcn36xx_err("failed to get mmio\n");
+       /* Acquire SMSM tx enable handle */
+       wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev,
+                       "tx-enable", &wcn->tx_enable_state_bit);
+       if (IS_ERR(wcn->tx_enable_state)) {
+               wcn36xx_err("failed to get tx-enable state\n");
                return -ENOENT;
        }
-       wcn->mmio = ioremap(res->start, resource_size(res));
-       if (!wcn->mmio) {
-               wcn36xx_err("failed to map io memory\n");
-               return -ENOMEM;
+
+       /* Acquire SMSM tx rings empty handle */
+       wcn->tx_rings_empty_state = qcom_smem_state_get(&pdev->dev,
+                       "tx-rings-empty", &wcn->tx_rings_empty_state_bit);
+       if (IS_ERR(wcn->tx_rings_empty_state)) {
+               wcn36xx_err("failed to get tx-rings-empty state\n");
+               return -ENOENT;
+       }
+
+       mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
+       if (!mmio_node) {
+               wcn36xx_err("failed to acquire qcom,mmio reference\n");
+               return -EINVAL;
+       }
+
+       wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");
+
+       /* Map the CCU memory */
+       index = of_property_match_string(mmio_node, "reg-names", "ccu");
+       wcn->ccu_base = of_iomap(mmio_node, index);
+       if (!wcn->ccu_base) {
+               wcn36xx_err("failed to map ccu memory\n");
+               ret = -ENOMEM;
+               goto put_mmio_node;
+       }
+
+       /* Map the DXE memory */
+       index = of_property_match_string(mmio_node, "reg-names", "dxe");
+       wcn->dxe_base = of_iomap(mmio_node, index);
+       if (!wcn->dxe_base) {
+               wcn36xx_err("failed to map dxe memory\n");
+               ret = -ENOMEM;
+               goto unmap_ccu;
        }
+
+       of_node_put(mmio_node);
        return 0;
+
+unmap_ccu:
+       iounmap(wcn->ccu_base);
+put_mmio_node:
+       of_node_put(mmio_node);
+       return ret;
 }
 
 static int wcn36xx_probe(struct platform_device *pdev)
 {
        struct ieee80211_hw *hw;
        struct wcn36xx *wcn;
+       void *wcnss;
        int ret;
-       u8 addr[ETH_ALEN];
+       const u8 *addr;
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
 
+       wcnss = dev_get_drvdata(pdev->dev.parent);
+
        hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
        if (!hw) {
                wcn36xx_err("failed to alloc hw\n");
@@ -1112,25 +1189,26 @@ static int wcn36xx_probe(struct platform_device *pdev)
        wcn = hw->priv;
        wcn->hw = hw;
        wcn->dev = &pdev->dev;
-       wcn->dev->dma_mask = kzalloc(sizeof(*wcn->dev->dma_mask), GFP_KERNEL);
-       if (!wcn->dev->dma_mask) {
-               ret = -ENOMEM;
-               goto dma_mask_err;
-       }
-       dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));
-       wcn->wcn36xx_data = pdev->dev.platform_data;
-       wcn->ctrl_ops = &wcn->wcn36xx_data->ctrl_ops;
-       wcn->wcn36xx_data->wcn = wcn;
-       if (!wcn->ctrl_ops->get_chip_type) {
-               dev_err(&pdev->dev, "Missing ops->get_chip_type\n");
-               ret = -EINVAL;
+       mutex_init(&wcn->hal_mutex);
+       mutex_init(&wcn->scan_lock);
+
+       INIT_WORK(&wcn->scan_work, wcn36xx_hw_scan_worker);
+
+       wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process);
+       if (IS_ERR(wcn->smd_channel)) {
+               wcn36xx_err("failed to open WLAN_CTRL channel\n");
+               ret = PTR_ERR(wcn->smd_channel);
                goto out_wq;
        }
-       wcn->chip_version = wcn->ctrl_ops->get_chip_type(wcn);
 
-       mutex_init(&wcn->hal_mutex);
+       qcom_smd_set_drvdata(wcn->smd_channel, hw);
 
-       if (!wcn->ctrl_ops->get_hw_mac(wcn, addr)) {
+       addr = of_get_property(pdev->dev.of_node, "local-mac-address", &ret);
+       if (addr && ret != ETH_ALEN) {
+               wcn36xx_err("invalid local-mac-address\n");
+               ret = -EINVAL;
+               goto out_wq;
+       } else if (addr) {
                wcn36xx_info("mac address: %pM\n", addr);
                SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
        }
@@ -1147,14 +1225,14 @@ static int wcn36xx_probe(struct platform_device *pdev)
        return 0;
 
 out_unmap:
-       iounmap(wcn->mmio);
+       iounmap(wcn->ccu_base);
+       iounmap(wcn->dxe_base);
 out_wq:
-       kfree(wcn->dev->dma_mask);
-dma_mask_err:
        ieee80211_free_hw(hw);
 out_err:
        return ret;
 }
+
 static int wcn36xx_remove(struct platform_device *pdev)
 {
        struct ieee80211_hw *hw = platform_get_drvdata(pdev);
@@ -1165,41 +1243,33 @@ static int wcn36xx_remove(struct platform_device *pdev)
        mutex_destroy(&wcn->hal_mutex);
 
        ieee80211_unregister_hw(hw);
-       iounmap(wcn->mmio);
+
+       qcom_smem_state_put(wcn->tx_enable_state);
+       qcom_smem_state_put(wcn->tx_rings_empty_state);
+
+       iounmap(wcn->dxe_base);
+       iounmap(wcn->ccu_base);
        ieee80211_free_hw(hw);
 
        return 0;
 }
-static const struct platform_device_id wcn36xx_platform_id_table[] = {
-       {
-               .name = "wcn36xx",
-               .driver_data = 0
-       },
+
+static const struct of_device_id wcn36xx_of_match[] = {
+       { .compatible = "qcom,wcnss-wlan" },
        {}
 };
-MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
+MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
 
 static struct platform_driver wcn36xx_driver = {
        .probe      = wcn36xx_probe,
        .remove     = wcn36xx_remove,
        .driver         = {
                .name   = "wcn36xx",
+               .of_match_table = wcn36xx_of_match,
        },
-       .id_table    = wcn36xx_platform_id_table,
 };
 
-static int __init wcn36xx_init(void)
-{
-       platform_driver_register(&wcn36xx_driver);
-       return 0;
-}
-module_init(wcn36xx_init);
-
-static void __exit wcn36xx_exit(void)
-{
-       platform_driver_unregister(&wcn36xx_driver);
-}
-module_exit(wcn36xx_exit);
+module_platform_driver(wcn36xx_driver);
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
index 61754967e2effc5429515ffc35ca25ba4f5cde01..87a62eb6228cab3352e79f166e5824e5f478426e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/etherdevice.h>
 #include <linux/firmware.h>
 #include <linux/bitops.h>
+#include <linux/soc/qcom/smd.h>
 #include "smd.h"
 
 struct wcn36xx_cfg_val {
@@ -104,11 +105,11 @@ static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn,
                struct ieee80211_sta *sta,
                struct wcn36xx_hal_config_bss_params *bss_params)
 {
-       if (IEEE80211_BAND_5GHZ == WCN36XX_BAND(wcn))
+       if (NL80211_BAND_5GHZ == WCN36XX_BAND(wcn))
                bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE;
        else if (sta && sta->ht_cap.ht_supported)
                bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE;
-       else if (sta && (sta->supp_rates[IEEE80211_BAND_2GHZ] & 0x7f))
+       else if (sta && (sta->supp_rates[NL80211_BAND_2GHZ] & 0x7f))
                bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE;
        else
                bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE;
@@ -253,7 +254,7 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
 
        init_completion(&wcn->hal_rsp_compl);
        start = jiffies;
-       ret = wcn->ctrl_ops->tx(wcn, wcn->hal_buf, len);
+       ret = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
        if (ret) {
                wcn36xx_err("HAL TX failed\n");
                goto out;
@@ -521,7 +522,7 @@ out:
        return ret;
 }
 
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel)
 {
        struct wcn36xx_hal_start_scan_req_msg msg_body;
        int ret = 0;
@@ -529,7 +530,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);
 
-       msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+       msg_body.scan_channel = scan_channel;
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -551,7 +552,7 @@ out:
        return ret;
 }
 
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel)
 {
        struct wcn36xx_hal_end_scan_req_msg msg_body;
        int ret = 0;
@@ -559,7 +560,7 @@ int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);
 
-       msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+       msg_body.scan_channel = scan_channel;
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -674,22 +675,25 @@ static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len)
        return 0;
 }
 
-int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn)
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn,
+                                  u8 *channels, size_t channel_count)
 {
-       struct wcn36xx_hal_update_scan_params_req msg_body;
+       struct wcn36xx_hal_update_scan_params_req_ex msg_body;
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);
 
-       msg_body.dot11d_enabled = 0;
-       msg_body.dot11d_resolved = 0;
-       msg_body.channel_count = 26;
+       msg_body.dot11d_enabled = false;
+       msg_body.dot11d_resolved = true;
+
+       msg_body.channel_count = channel_count;
+       memcpy(msg_body.channels, channels, channel_count);
        msg_body.active_min_ch_time = 60;
        msg_body.active_max_ch_time = 120;
        msg_body.passive_min_ch_time = 60;
        msg_body.passive_max_ch_time = 110;
-       msg_body.state = 0;
+       msg_body.state = PHY_SINGLE_CHANNEL_CENTERED;
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -1388,7 +1392,6 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
 {
        struct wcn36xx_hal_send_beacon_req_msg msg_body;
        int ret = 0, pad, pvm_len;
-       u32 beacon_length;
 
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ);
@@ -1400,16 +1403,16 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
        if (vif->type == NL80211_IFTYPE_MESH_POINT)
                pad = 0;
 
-       beacon_length = skb_beacon->len + pad;
-       msg_body.template_length = beacon_length + sizeof(beacon_length);
+       msg_body.beacon_length = skb_beacon->len + pad;
+       /* TODO need to find out why + 6 is needed */
+       msg_body.beacon_length6 = msg_body.beacon_length + 6;
 
-       if (msg_body.template_length > BEACON_TEMPLATE_SIZE) {
+       if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) {
                wcn36xx_err("Beacon is to big: beacon size=%d\n",
-                             msg_body.template_length);
+                             msg_body.beacon_length);
                ret = -ENOMEM;
                goto out;
        }
-       msg_body.beacon_length = beacon_length;
        memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len);
        memcpy(msg_body.bssid, vif->addr, ETH_ALEN);
 
@@ -2178,13 +2181,18 @@ out:
        return ret;
 }
 
-static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+                           const void *buf, size_t len)
 {
-       struct wcn36xx_hal_msg_header *msg_header = buf;
+       struct wcn36xx_hal_msg_header msg_header;
+       struct ieee80211_hw *hw = qcom_smd_get_drvdata(channel);
+       struct wcn36xx *wcn = hw->priv;
        struct wcn36xx_hal_ind_msg *msg_ind;
        wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
 
-       switch (msg_header->msg_type) {
+       memcpy_fromio(&msg_header, buf, sizeof(struct wcn36xx_hal_msg_header));
+
+       switch (msg_header.msg_type) {
        case WCN36XX_HAL_START_RSP:
        case WCN36XX_HAL_CONFIG_STA_RSP:
        case WCN36XX_HAL_CONFIG_BSS_RSP:
@@ -2220,44 +2228,42 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
        case WCN36XX_HAL_CH_SWITCH_RSP:
        case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
        case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
-               memcpy(wcn->hal_buf, buf, len);
+               memcpy_fromio(wcn->hal_buf, buf, len);
                wcn->hal_rsp_len = len;
                complete(&wcn->hal_rsp_compl);
                break;
 
-       case WCN36XX_HAL_DEL_BA_IND:
-       case WCN36XX_HAL_PRINT_REG_INFO_IND:
        case WCN36XX_HAL_COEX_IND:
        case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
        case WCN36XX_HAL_OTA_TX_COMPL_IND:
        case WCN36XX_HAL_MISSED_BEACON_IND:
        case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
-               msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
-               if (!msg_ind)
-                       goto nomem;
-               msg_ind->msg_len = len;
-               msg_ind->msg = kmemdup(buf, len, GFP_KERNEL);
-               if (!msg_ind->msg) {
-                       kfree(msg_ind);
-nomem:
+               msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
+               if (!msg_ind) {
                        /*
                         * FIXME: Do something smarter then just
                         * printing an error.
                         */
                        wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
-                                   msg_header->msg_type);
+                                   msg_header.msg_type);
                        break;
                }
-               mutex_lock(&wcn->hal_ind_mutex);
+
+               msg_ind->msg_len = len;
+               memcpy_fromio(msg_ind->msg, buf, len);
+
+               spin_lock(&wcn->hal_ind_lock);
                list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
                queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
-               mutex_unlock(&wcn->hal_ind_mutex);
+               spin_unlock(&wcn->hal_ind_lock);
                wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
                break;
        default:
                wcn36xx_err("SMD_EVENT (%d) not supported\n",
-                             msg_header->msg_type);
+                             msg_header.msg_type);
        }
+
+       return 0;
 }
 static void wcn36xx_ind_smd_work(struct work_struct *work)
 {
@@ -2265,8 +2271,9 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
                container_of(work, struct wcn36xx, hal_ind_work);
        struct wcn36xx_hal_msg_header *msg_header;
        struct wcn36xx_hal_ind_msg *hal_ind_msg;
+       unsigned long flags;
 
-       mutex_lock(&wcn->hal_ind_mutex);
+       spin_lock_irqsave(&wcn->hal_ind_lock, flags);
 
        hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
                                       struct wcn36xx_hal_ind_msg,
@@ -2275,8 +2282,6 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
        msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
 
        switch (msg_header->msg_type) {
-       case WCN36XX_HAL_DEL_BA_IND:
-       case WCN36XX_HAL_PRINT_REG_INFO_IND:
        case WCN36XX_HAL_COEX_IND:
        case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
                break;
@@ -2300,9 +2305,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
                              msg_header->msg_type);
        }
        list_del(wcn->hal_ind_queue.next);
-       kfree(hal_ind_msg->msg);
+       spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
        kfree(hal_ind_msg);
-       mutex_unlock(&wcn->hal_ind_mutex);
 }
 int wcn36xx_smd_open(struct wcn36xx *wcn)
 {
@@ -2315,25 +2319,15 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
        }
        INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);
        INIT_LIST_HEAD(&wcn->hal_ind_queue);
-       mutex_init(&wcn->hal_ind_mutex);
-
-       ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
-       if (ret) {
-               wcn36xx_err("failed to open control channel\n");
-               goto free_wq;
-       }
+       spin_lock_init(&wcn->hal_ind_lock);
 
-       return ret;
+       return 0;
 
-free_wq:
-       destroy_workqueue(wcn->hal_ind_wq);
 out:
        return ret;
 }
 
 void wcn36xx_smd_close(struct wcn36xx *wcn)
 {
-       wcn->ctrl_ops->close(wcn);
        destroy_workqueue(wcn->hal_ind_wq);
-       mutex_destroy(&wcn->hal_ind_mutex);
 }
index d93e3fd73831c98b67ddf32c1cf436d32a34d20e..8892ccd67b144903ae25cde3287e79f951e5a8c6 100644 (file)
@@ -46,11 +46,12 @@ struct wcn36xx_fw_msg_status_rsp {
 
 struct wcn36xx_hal_ind_msg {
        struct list_head list;
-       u8 *msg;
        size_t msg_len;
+       u8 msg[];
 };
 
 struct wcn36xx;
+struct qcom_smd_channel;
 
 int wcn36xx_smd_open(struct wcn36xx *wcn);
 void wcn36xx_smd_close(struct wcn36xx *wcn);
@@ -59,11 +60,11 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn);
 int wcn36xx_smd_start(struct wcn36xx *wcn);
 int wcn36xx_smd_stop(struct wcn36xx *wcn);
 int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode);
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel);
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel);
 int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
                            enum wcn36xx_hal_sys_mode mode);
-int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn);
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
 int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
 int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
 int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
@@ -127,6 +128,10 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
 
 int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+                           const void *buf, size_t len);
+
 int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
                            struct ieee80211_vif *vif,
                            struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
index 37f13410e6339c38a656be6a67aacd54418e1194..8c387a0a3c091c474e8f7dd948dc31b9060c0813 100644 (file)
@@ -45,9 +45,20 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
        skb_put(skb, bd->pdu.mpdu_header_off + bd->pdu.mpdu_len);
        skb_pull(skb, bd->pdu.mpdu_header_off);
 
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = __le16_to_cpu(hdr->frame_control);
+       sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
+
+       /* When scanning associate beacons to this */
+       if (ieee80211_is_beacon(hdr->frame_control) && wcn->scan_freq) {
+               status.freq = wcn->scan_freq;
+               status.band = wcn->scan_band;
+       } else {
+               status.freq = WCN36XX_CENTER_FREQ(wcn);
+               status.band = WCN36XX_BAND(wcn);
+       }
+
        status.mactime = 10;
-       status.freq = WCN36XX_CENTER_FREQ(wcn);
-       status.band = WCN36XX_BAND(wcn);
        status.signal = -get_rssi0(bd);
        status.antenna = 1;
        status.rate_idx = 1;
@@ -57,14 +68,10 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
                       RX_FLAG_MMIC_STRIPPED |
                       RX_FLAG_DECRYPTED;
 
-       wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag);
+       wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%llx\n", status.flag);
 
        memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
 
-       hdr = (struct ieee80211_hdr *) skb->data;
-       fc = __le16_to_cpu(hdr->frame_control);
-       sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
-
        if (ieee80211_is_beacon(hdr->frame_control)) {
                wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n",
                            skb, skb->len, fc, sn);
@@ -221,7 +228,7 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
 
        /* default rate for unicast */
        if (ieee80211_is_mgmt(hdr->frame_control))
-               bd->bd_rate = (WCN36XX_BAND(wcn) == IEEE80211_BAND_5GHZ) ?
+               bd->bd_rate = (WCN36XX_BAND(wcn) == NL80211_BAND_5GHZ) ?
                        WCN36XX_BD_RATE_CTRL :
                        WCN36XX_BD_RATE_MGMT;
        else if (ieee80211_is_ctl(hdr->frame_control))
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
deleted file mode 100644 (file)
index 647f623..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
- * Copyright (c) 2013 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/completion.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/remoteproc.h>
-#include <linux/soc/qcom/smd.h>
-#include "wcn36xx.h"
-#include "wcnss_core.h"
-
-#define MAC_ADDR_0 "wlan/macaddr0"
-
-struct smd_packet_item {
-       struct list_head list;
-       void *buf;
-       size_t count;
-};
-
-static int wcn36xx_msm_smsm_change_state(u32 clear_mask, u32 set_mask)
-{
-       return 0;
-}
-
-static int wcn36xx_msm_get_hw_mac(struct wcn36xx *wcn, u8 *addr)
-{
-       const struct firmware *addr_file = NULL;
-       int status;
-       u8 tmp[18];
-       static const u8 qcom_oui[3] = {0x00, 0x0A, 0xF5};
-       static const char *files = {MAC_ADDR_0};
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
-       status = request_firmware(&addr_file, files, &pdata->core->dev);
-
-       if (status < 0) {
-               /* Assign a random mac with Qualcomm oui */
-               dev_err(&pdata->core->dev, "Failed (%d) to read macaddress"
-                       "file %s, using a random address instead", status, files);
-               memcpy(addr, qcom_oui, 3);
-               get_random_bytes(addr + 3, 3);
-       } else {
-               memset(tmp, 0, sizeof(tmp));
-               memcpy(tmp, addr_file->data, sizeof(tmp) - 1);
-               sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
-                      &addr[0],
-                      &addr[1],
-                      &addr[2],
-                      &addr[3],
-                      &addr[4],
-                      &addr[5]);
-
-               release_firmware(addr_file);
-       }
-
-       return 0;
-}
-
-static int wcn36xx_msm_smd_send_and_wait(struct wcn36xx *wcn, char *buf, size_t len)
-{
-       int ret = 0;
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
-       mutex_lock(&pdata->wlan_ctrl_lock);
-       ret = qcom_smd_send(pdata->wlan_ctrl_channel, buf, len);
-       if (ret) {
-               dev_err(wcn->dev, "wlan ctrl channel tx failed\n");
-       }
-       mutex_unlock(&pdata->wlan_ctrl_lock);
-
-       return ret;
-}
-
-static int wcn36xx_msm_smd_open(struct wcn36xx *wcn, void *rsp_cb)
-{
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
-       pdata->cb = rsp_cb;
-       return 0;
-}
-
-static void wcn36xx_msm_smd_close(struct wcn36xx *wcn)
-{
-       return;
-}
-
-static int wcn36xx_msm_get_chip_type(struct wcn36xx *wcn)
-{
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-       return pdata->chip_type;
-}
-
-static struct wcn36xx_platform_data wcn36xx_data = {
-       .ctrl_ops = {
-               .open = wcn36xx_msm_smd_open,
-               .close = wcn36xx_msm_smd_close,
-               .tx = wcn36xx_msm_smd_send_and_wait,
-               .get_hw_mac = wcn36xx_msm_get_hw_mac,
-               .smsm_change_state = wcn36xx_msm_smsm_change_state,
-               .get_chip_type = wcn36xx_msm_get_chip_type,
-       },
-};
-
-static void wlan_ctrl_smd_process(struct work_struct *worker)
-{
-       unsigned long flags;
-       struct wcn36xx_platform_data *pdata =
-               container_of(worker,
-                       struct wcn36xx_platform_data, packet_process_work);
-
-       spin_lock_irqsave(&pdata->packet_lock, flags);
-       while (!list_empty(&pdata->packet_list)) {
-               struct smd_packet_item *packet;
-
-               packet = list_first_entry(&pdata->packet_list,
-                               struct smd_packet_item, list);
-               list_del(&packet->list);
-               spin_unlock_irqrestore(&pdata->packet_lock, flags);
-               pdata->cb(pdata->wcn, packet->buf, packet->count);
-               kfree(packet->buf);
-               spin_lock_irqsave(&pdata->packet_lock, flags);
-       }
-       spin_unlock_irqrestore(&pdata->packet_lock, flags);
-}
-
-static int qcom_smd_wlan_ctrl_probe(struct qcom_smd_device *sdev)
-{
-       pr_info("%s: enter\n", __func__);
-        mutex_init(&wcn36xx_data.wlan_ctrl_lock);
-        init_completion(&wcn36xx_data.wlan_ctrl_ack);
-
-       wcn36xx_data.sdev = sdev;
-       spin_lock_init(&wcn36xx_data.packet_lock);
-       INIT_LIST_HEAD(&wcn36xx_data.packet_list);
-       INIT_WORK(&wcn36xx_data.packet_process_work, wlan_ctrl_smd_process);
-
-        dev_set_drvdata(&sdev->dev, &wcn36xx_data);
-       wcn36xx_data.wlan_ctrl_channel = sdev->channel;
-
-       of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev);
-
-        return 0;
-}
-
-static void qcom_smd_wlan_ctrl_remove(struct qcom_smd_device *sdev)
-{
-        of_platform_depopulate(&sdev->dev);
-}
-
-static int qcom_smd_wlan_ctrl_callback(struct qcom_smd_device *qsdev,
-                                 const void *data,
-                                 size_t count)
-{
-       unsigned long flags;
-       struct smd_packet_item *packet = NULL;
-       struct wcn36xx_platform_data *pdata = dev_get_drvdata(&qsdev->dev);
-       void *buf = kzalloc(count + sizeof(struct smd_packet_item),
-                               GFP_ATOMIC);
-       if (!buf) {
-               dev_err(&pdata->core->dev, "can't allocate buffer\n");
-               return -ENOMEM;
-       }
-
-       memcpy_fromio(buf, data, count);
-       packet = buf + count;
-       packet->buf = buf;
-       packet->count = count;
-
-       spin_lock_irqsave(&pdata->packet_lock, flags);
-       list_add_tail(&packet->list, &pdata->packet_list);
-       spin_unlock_irqrestore(&pdata->packet_lock, flags);
-       schedule_work(&pdata->packet_process_work);
-
-       /* buf will be freed in workqueue */
-
-       return 0;
-}
-
-static const struct qcom_smd_id qcom_smd_wlan_ctrl_match[] = {
-       { .name = "WLAN_CTRL" },
-       {}
-};
-
-static struct qcom_smd_driver qcom_smd_wlan_ctrl_driver = {
-       .probe = qcom_smd_wlan_ctrl_probe,
-       .remove = qcom_smd_wlan_ctrl_remove,
-       .callback = qcom_smd_wlan_ctrl_callback,
-       .smd_match_table = qcom_smd_wlan_ctrl_match,
-       .driver  = {
-               .name  = "qcom_smd_wlan_ctrl",
-               .owner = THIS_MODULE,
-       },
-};
-
-static const struct of_device_id wcn36xx_msm_match_table[] = {
-       { .compatible = "qcom,wcn3660", .data = (void *)WCN36XX_CHIP_3660 },
-       { .compatible = "qcom,wcn3680", .data = (void *)WCN36XX_CHIP_3680 },
-       { .compatible = "qcom,wcn3620", .data = (void *)WCN36XX_CHIP_3620 },
-       { }
-};
-MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table);
-
-static int wcn36xx_msm_probe(struct platform_device *pdev)
-{
-       int ret;
-       const struct of_device_id *of_id;
-       struct resource *r;
-       struct resource res[3];
-       static const char const *rnames[] = {
-               "wcnss_mmio", "wcnss_wlantx_irq", "wcnss_wlanrx_irq" };
-       static const int rtype[] = {
-               IORESOURCE_MEM, IORESOURCE_IRQ, IORESOURCE_IRQ };
-       struct device_node *dn;
-       int n;
-
-       wcnss_core_prepare(pdev);
-
-       dn = of_parse_phandle(pdev->dev.of_node, "rproc", 0);
-       if (!dn) {
-               dev_err(&pdev->dev, "No rproc specified in DT\n");
-       } else {
-               struct rproc *rproc= rproc_get_by_phandle(dn->phandle);
-               if (rproc)
-                       rproc_boot(rproc);
-               else {
-                       dev_err(&pdev->dev, "No rproc registered\n");
-               }
-       }
-
-       qcom_smd_driver_register(&qcom_smd_wlan_ctrl_driver);
-       wcnss_core_init();
-
-       of_id = of_match_node(wcn36xx_msm_match_table, pdev->dev.of_node);
-       if (!of_id)
-               return -EINVAL;
-
-       wcn36xx_data.chip_type = (enum wcn36xx_chip_type)of_id->data;
-
-       wcn36xx_data.core = platform_device_alloc("wcn36xx", -1);
-
-       for (n = 0; n < ARRAY_SIZE(rnames); n++) {
-               r = platform_get_resource_byname(pdev, rtype[n], rnames[n]);
-               if (!r) {
-                       dev_err(&wcn36xx_data.core->dev,
-                               "Missing resource %s'\n", rnames[n]);
-                       ret = -ENOMEM;
-                       return ret;
-               }
-               res[n] = *r;
-       }
-
-       platform_device_add_resources(wcn36xx_data.core, res, n);
-       wcn36xx_data.core->dev.platform_data = &wcn36xx_data;
-
-       platform_device_add(wcn36xx_data.core);
-
-       dev_info(&pdev->dev, "%s initialized\n", __func__);
-
-       return 0;
-}
-
-static int wcn36xx_msm_remove(struct platform_device *pdev)
-{
-       platform_device_del(wcn36xx_data.core);
-       platform_device_put(wcn36xx_data.core);
-       return 0;
-}
-
-static struct platform_driver wcn36xx_msm_driver = {
-       .probe          = wcn36xx_msm_probe,
-       .remove         = wcn36xx_msm_remove,
-       .driver         = {
-               .name   = "wcn36xx-msm",
-               .owner  = THIS_MODULE,
-               .of_match_table = wcn36xx_msm_match_table,
-       },
-};
-
-static int __init wcn36xx_msm_init(void)
-{
-       return platform_driver_register(&wcn36xx_msm_driver);
-}
-module_init(wcn36xx_msm_init);
-
-static void __exit wcn36xx_msm_exit(void)
-{
-       platform_driver_unregister(&wcn36xx_msm_driver);
-}
-module_exit(wcn36xx_msm_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
-MODULE_FIRMWARE(MAC_ADDR_0);
-
index b17d284a69c9850758464a5d1569d69384aac994..35a6590c3ee51db0c5f9f2e3e1aa927e1b0531c8 100644 (file)
@@ -35,6 +35,9 @@
 /* How many frames until we start a-mpdu TX session */
 #define WCN36XX_AMPDU_START_THRESH     20
 
+#define WCN36XX_MAX_SCAN_SSIDS         9
+#define WCN36XX_MAX_SCAN_IE_LEN                500
+
 extern unsigned int wcn36xx_dbg_mask;
 
 enum wcn36xx_debug_mask {
@@ -103,49 +106,6 @@ struct nv_data {
        u8      table;
 };
 
-enum wcn36xx_chip_type {
-       WCN36XX_CHIP_UNKNOWN,
-       WCN36XX_CHIP_3660,
-       WCN36XX_CHIP_3680,
-       WCN36XX_CHIP_3620,
-};
-
-/* Interface for platform control path
- *
- * @open: hook must be called when wcn36xx wants to open control channel.
- * @tx: sends a buffer.
- */
-struct wcn36xx_platform_ctrl_ops {
-       int (*open)(struct wcn36xx *wcn, void *rsp_cb);
-       void (*close)(struct wcn36xx *wcn);
-       int (*tx)(struct wcn36xx *wcn, char *buf, size_t len);
-       int (*get_hw_mac)(struct wcn36xx *wcn, u8 *addr);
-       int (*get_chip_type)(struct wcn36xx *wcn);
-       int (*smsm_change_state)(u32 clear_mask, u32 set_mask);
-};
-
-struct wcn36xx_platform_data {
-       enum wcn36xx_chip_type chip_type;
-
-       struct platform_device *core;
-
-       struct qcom_smd_device *sdev;
-        struct qcom_smd_channel *wlan_ctrl_channel;
-        struct completion wlan_ctrl_ack;
-        struct mutex wlan_ctrl_lock;
-
-       struct pinctrl *pinctrl;
-
-       struct wcn36xx *wcn;
-
-       void (*cb)(struct wcn36xx *wcn, void *buf, size_t len);
-       struct wcn36xx_platform_ctrl_ops ctrl_ops;
-
-       struct work_struct packet_process_work;
-       spinlock_t packet_lock;
-       struct list_head packet_list;
-};
-
 /**
  * struct wcn36xx_vif - holds VIF related fields
  *
@@ -223,7 +183,7 @@ struct wcn36xx {
        u8                      fw_minor;
        u8                      fw_major;
        u32                     fw_feat_caps[WCN36XX_HAL_CAPS_SIZE];
-       enum wcn36xx_chip_type  chip_version;
+       bool                    is_pronto;
 
        /* extra byte for the NULL termination */
        u8                      crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
@@ -232,10 +192,16 @@ struct wcn36xx {
        /* IRQs */
        int                     tx_irq;
        int                     rx_irq;
-       void __iomem            *mmio;
+       void __iomem            *ccu_base;
+       void __iomem            *dxe_base;
+
+       struct qcom_smd_channel *smd_channel;
+
+       struct qcom_smem_state  *tx_enable_state;
+       unsigned                tx_enable_state_bit;
+       struct qcom_smem_state  *tx_rings_empty_state;
+       unsigned                tx_rings_empty_state_bit;
 
-       struct wcn36xx_platform_data *wcn36xx_data;
-       struct wcn36xx_platform_ctrl_ops *ctrl_ops;
        /*
         * smd_buf must be protected with smd_mutex to garantee
         * that all messages are sent one after another
@@ -246,9 +212,15 @@ struct wcn36xx {
        struct completion       hal_rsp_compl;
        struct workqueue_struct *hal_ind_wq;
        struct work_struct      hal_ind_work;
-       struct mutex            hal_ind_mutex;
+       spinlock_t              hal_ind_lock;
        struct list_head        hal_ind_queue;
 
+       struct work_struct      scan_work;
+       struct cfg80211_scan_request *scan_req;
+       int                     scan_freq;
+       int                     scan_band;
+       struct mutex            scan_lock;
+
        /* DXE channels */
        struct wcn36xx_dxe_ch   dxe_tx_l_ch;    /* TX low */
        struct wcn36xx_dxe_ch   dxe_tx_h_ch;    /* TX high */
diff --git a/drivers/net/wireless/ath/wcn36xx/wcnss_core.c b/drivers/net/wireless/ath/wcn36xx/wcnss_core.c
deleted file mode 100644 (file)
index e7d389e..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-#include <linux/completion.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/soc/qcom/smd.h>
-#include "wcn36xx.h"
-#include "wcnss_core.h"
-
-#define        WCNSS_CTRL_TIMEOUT      (msecs_to_jiffies(500))
-
-static int wcnss_core_config(struct platform_device *pdev, void __iomem *base)
-{
-       int ret = 0;
-       u32 value, iris_read_v = INVALID_IRIS_REG;
-       int clk_48m = 0;
-
-       value = readl_relaxed(base + SPARE_OFFSET);
-       value |= WCNSS_FW_DOWNLOAD_ENABLE;
-       writel_relaxed(value, base + SPARE_OFFSET);
-
-       writel_relaxed(0, base + PMU_OFFSET);
-       value = readl_relaxed(base + PMU_OFFSET);
-       value |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-               WCNSS_PMU_CFG_IRIS_XO_EN;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       iris_read_v = readl_relaxed(base + IRIS_REG_OFFSET);
-       pr_info("iris_read_v: 0x%x\n", iris_read_v);
-
-       iris_read_v &= 0xffff;
-       iris_read_v |= 0x04;
-       writel_relaxed(iris_read_v, base + IRIS_REG_OFFSET);
-
-       value = readl_relaxed(base + PMU_OFFSET);
-       value |= WCNSS_PMU_CFG_IRIS_XO_READ;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       while (readl_relaxed(base + PMU_OFFSET) &
-                       WCNSS_PMU_CFG_IRIS_XO_READ_STS)
-               cpu_relax();
-
-       iris_read_v = readl_relaxed(base + 0x1134);
-       pr_info("wcnss: IRIS Reg: 0x%08x\n", iris_read_v);
-       clk_48m = (iris_read_v >> 30) ? 0 : 1;
-       value &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
-
-       /* XO_MODE[b2:b1]. Clear implies 19.2MHz */
-       value &= ~WCNSS_PMU_CFG_IRIS_XO_MODE;
-
-       if (clk_48m)
-               value |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
-
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       /* Reset IRIS */
-       value |= WCNSS_PMU_CFG_IRIS_RESET;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       while (readl_relaxed(base + PMU_OFFSET) &
-                       WCNSS_PMU_CFG_IRIS_RESET_STS)
-               cpu_relax();
-
-       /* reset IRIS reset bit */
-       value &= ~WCNSS_PMU_CFG_IRIS_RESET;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       /* start IRIS XO configuration */
-       value |= WCNSS_PMU_CFG_IRIS_XO_CFG;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       /* Wait for XO configuration to finish */
-       while (readl_relaxed(base + PMU_OFFSET) &
-                       WCNSS_PMU_CFG_IRIS_XO_CFG_STS)
-               cpu_relax();
-
-       /* Stop IRIS XO configuration */
-       value &= ~(WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-                       WCNSS_PMU_CFG_IRIS_XO_CFG);
-       writel_relaxed(value, base + PMU_OFFSET);
-
-        msleep(200);
-
-       return ret;
-}
-
-int wcnss_core_prepare(struct platform_device *pdev)
-{
-       int ret = 0;
-       struct resource *res;
-       void __iomem *wcnss_base;
-
-       res = platform_get_resource_byname(pdev,
-                        IORESOURCE_MEM, "pronto_phy_base");
-       if (!res) {
-               ret = -EIO;
-               dev_err(&pdev->dev, "resource pronto_phy_base failed\n");
-               return ret;
-       }
-
-       wcnss_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(wcnss_base)) {
-               dev_err(&pdev->dev, "pronto_phy_base map failed\n");
-               return PTR_ERR(wcnss_base);
-       }
-
-       ret = wcnss_core_config(pdev, wcnss_base);
-       return ret;
-}
-
-struct wcnss_platform_data {
-        struct qcom_smd_channel        *channel;
-        struct completion      ack;
-        struct mutex           lock;
-
-       struct work_struct      rx_work;
-       struct work_struct      download_work;
-
-       struct qcom_smd_device  *sdev;
-};
-
-static struct completion fw_ready_compl;
-#define        NV_FILE_NAME    "wlan/prima/WCNSS_qcom_wlan_nv.bin"
-static void wcn36xx_nv_download_work(struct work_struct *worker)
-{
-       int ret = 0, i;
-       const struct firmware *nv = NULL;
-       struct wcnss_platform_data *wcnss_data =
-               container_of(worker, struct wcnss_platform_data, download_work);
-       struct device *dev = &wcnss_data->sdev->dev;
-
-       struct nvbin_dnld_req_msg *msg;
-       const void *nv_blob_start;
-       char *pkt = NULL;
-       int nv_blob_size = 0, fragments;
-
-       ret = request_firmware(&nv, NV_FILE_NAME, dev);
-       if (ret || !nv || !nv->data || !nv->size) {
-               dev_err(dev, "request firmware for %s (ret = %d)\n",
-                       NV_FILE_NAME, ret);
-               return;
-       }
-
-       nv_blob_start = nv->data + 4;
-       nv_blob_size = nv->size -4;
-
-       fragments = (nv_blob_size + NV_FRAGMENT_SIZE - 1)/NV_FRAGMENT_SIZE;
-
-       pkt = kzalloc(sizeof(struct nvbin_dnld_req_msg) + NV_FRAGMENT_SIZE,
-                       GFP_KERNEL);
-       if (!pkt) {
-               dev_err(dev, "allocation packet for nv download failed\n");
-               release_firmware(nv);
-       }
-
-       msg = (struct nvbin_dnld_req_msg *)pkt;
-       msg->hdr.msg_type = WCNSS_NV_DOWNLOAD_REQ;
-       msg->dnld_req_params.msg_flags = 0;
-
-       i = 0;
-       do {
-               int pkt_len = 0;
-
-               msg->dnld_req_params.frag_number = i;
-               if (nv_blob_size > NV_FRAGMENT_SIZE) {
-                       msg->dnld_req_params.msg_flags &=
-                               ~LAST_FRAGMENT;
-                       pkt_len = NV_FRAGMENT_SIZE;
-               } else {
-                       pkt_len = nv_blob_size;
-                       msg->dnld_req_params.msg_flags |=
-                               LAST_FRAGMENT | CAN_RECEIVE_CALDATA;
-               }
-
-               msg->dnld_req_params.nvbin_buffer_size = pkt_len;
-               msg->hdr.msg_len =
-                       sizeof(struct nvbin_dnld_req_msg) + pkt_len;
-
-               memcpy(pkt + sizeof(struct nvbin_dnld_req_msg),
-                       nv_blob_start + i * NV_FRAGMENT_SIZE, pkt_len);
-
-               ret = qcom_smd_send(wcnss_data->channel, pkt, msg->hdr.msg_len);
-               if (ret) {
-                       dev_err(dev, "nv download failed\n");
-                       goto out;
-               }
-
-               i++;
-               nv_blob_size -= NV_FRAGMENT_SIZE;
-               msleep(100);
-       } while (nv_blob_size > 0);
-
-out:
-       kfree(pkt);
-       release_firmware(nv);
-       return;
-}
-
-static int qcom_smd_wcnss_ctrl_callback(struct qcom_smd_device *qsdev,
-                                 const void *data,
-                                 size_t count)
-{
-       struct wcnss_platform_data *wcnss_data = dev_get_drvdata(&qsdev->dev);
-       struct smd_msg_hdr phdr;
-       const unsigned char *tmp = data;
-
-       memcpy_fromio(&phdr, data, sizeof(struct smd_msg_hdr));
-
-       switch (phdr.msg_type) {
-       /* CBC COMPLETE means firmware ready for go */
-        case WCNSS_CBC_COMPLETE_IND:
-                complete(&fw_ready_compl);
-                pr_info("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n");
-                break;
-
-       case WCNSS_NV_DOWNLOAD_RSP:
-               pr_info("fw_status: %d\n", tmp[sizeof(struct smd_msg_hdr)]);
-               break;
-       }
-
-       complete(&wcnss_data->ack);
-       return 0;
-}
-
-static int qcom_smd_wcnss_ctrl_probe(struct qcom_smd_device *sdev)
-{
-       struct wcnss_platform_data *wcnss_data;
-
-        wcnss_data = devm_kzalloc(&sdev->dev, sizeof(*wcnss_data), GFP_KERNEL);
-        if (!wcnss_data)
-                return -ENOMEM;
-
-        mutex_init(&wcnss_data->lock);
-        init_completion(&wcnss_data->ack);
-
-       wcnss_data->sdev = sdev;
-
-        dev_set_drvdata(&sdev->dev, wcnss_data);
-       wcnss_data->channel = sdev->channel;
-
-       INIT_WORK(&wcnss_data->download_work, wcn36xx_nv_download_work);
-
-       of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev);
-
-       /* We are ready for download here */
-       schedule_work(&wcnss_data->download_work);
-        return 0;
-}
-
-static void qcom_smd_wcnss_ctrl_remove(struct qcom_smd_device *sdev)
-{
-        of_platform_depopulate(&sdev->dev);
-}
-
-static const struct qcom_smd_id qcom_smd_wcnss_ctrl_match[] = {
-       { .name = "WCNSS_CTRL" },
-       {}
-};
-
-static struct qcom_smd_driver qcom_smd_wcnss_ctrl_driver = {
-       .probe = qcom_smd_wcnss_ctrl_probe,
-       .remove = qcom_smd_wcnss_ctrl_remove,
-       .callback = qcom_smd_wcnss_ctrl_callback,
-       .smd_match_table = qcom_smd_wcnss_ctrl_match,
-       .driver  = {
-               .name  = "qcom_smd_wcnss_ctrl",
-               .owner = THIS_MODULE,
-       },
-};
-
-void wcnss_core_init(void)
-{
-       int ret = 0;
-
-       init_completion(&fw_ready_compl);
-       qcom_smd_driver_register(&qcom_smd_wcnss_ctrl_driver);
-
-       ret = wait_for_completion_interruptible_timeout(
-               &fw_ready_compl, msecs_to_jiffies(FW_READY_TIMEOUT));
-       if (ret <= 0) {
-                pr_err("timeout waiting for wcnss firmware ready indicator\n");
-               return;
-        }
-
-       return;
-}
-
-void wcnss_core_deinit(void)
-{
-       qcom_smd_driver_unregister(&qcom_smd_wcnss_ctrl_driver);
-}
diff --git a/drivers/net/wireless/ath/wcn36xx/wcnss_core.h b/drivers/net/wireless/ath/wcn36xx/wcnss_core.h
deleted file mode 100644 (file)
index 49524c8..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef        _WCNSS_CORE_H_
-#define        _WCNSS_CORE_H_
-
-#define        PMU_OFFSET      0x1004
-#define        SPARE_OFFSET    0x1088
-#define IRIS_REG_OFFSET 0x1134
-
-#define INVALID_IRIS_REG        0xbaadbaad
-
-#define WCNSS_PMU_CFG_IRIS_XO_CFG          BIT(3)
-#define WCNSS_PMU_CFG_IRIS_XO_EN           BIT(4)
-#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
-#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
-
-#define WCNSS_PMU_CFG_IRIS_RESET           BIT(7)
-#define WCNSS_PMU_CFG_IRIS_RESET_STS       BIT(8) /* 1: in progress, 0: done */
-#define WCNSS_PMU_CFG_IRIS_XO_READ         BIT(9)
-#define WCNSS_PMU_CFG_IRIS_XO_READ_STS     BIT(10)
-#define        WCNSS_FW_DOWNLOAD_ENABLE           BIT(25)
-
-#define WCNSS_PMU_CFG_IRIS_XO_MODE         0x6
-#define WCNSS_PMU_CFG_IRIS_XO_MODE_48      (3 << 1)
-
-#define        NV_DOWNLOAD_TIMEOUT     500
-#define        NV_FRAGMENT_SIZE        3072
-#define MAX_CALIBRATED_DATA_SIZE  (64*1024)
-#define LAST_FRAGMENT        (1 << 0)
-#define MESSAGE_TO_FOLLOW    (1 << 1)
-#define CAN_RECEIVE_CALDATA  (1 << 15)
-#define WCNSS_RESP_SUCCESS   1
-#define WCNSS_RESP_FAIL      0
-
-
-#define        WCNSS_NV_DOWNLOAD_REQ   0x01000002
-#define        WCNSS_NV_DOWNLOAD_RSP   0x01000003
-#define WCNSS_CBC_COMPLETE_IND  0x0100000C
-
-/*time out 10s for the firmware status ready indicator */
-#define FW_READY_TIMEOUT        (10000)
-
-
-struct smd_msg_hdr {
-       unsigned int msg_type;
-       unsigned int msg_len;
-};
-
-struct nvbin_dnld_req_params {
-       /* Fragment sequence number of the NV bin Image. NV Bin Image
-        * might not fit into one message due to size limitation of
-        * the SMD channel FIFO so entire NV blob is chopped into
-        * multiple fragments starting with seqeunce number 0. The
-        * last fragment is indicated by marking is_last_fragment field
-        * to 1. At receiving side, NV blobs would be concatenated
-        * together without any padding bytes in between.
-        */
-       unsigned short frag_number;
-
-       /* bit 0: When set to 1 it indicates that no more fragments will
-        * be sent.
-        * bit 1: When set, a new message will be followed by this message
-        * bit 2- bit 14:  Reserved
-        * bit 15: when set, it indicates that the sender is capable of
-        * receiving Calibrated data.
-        */
-       unsigned short msg_flags;
-
-       /* NV Image size (number of bytes) */
-       unsigned int nvbin_buffer_size;
-
-       /* Following the 'nvbin_buffer_size', there should be
-        * nvbin_buffer_size bytes of NV bin Image i.e.
-        * uint8[nvbin_buffer_size].
-        */
-};
-
-struct nvbin_dnld_req_msg {
-       /* Note: The length specified in nvbin_dnld_req_msg messages
-        * should be hdr.msg_len = sizeof(nvbin_dnld_req_msg) +
-        * nvbin_buffer_size.
-        */
-       struct smd_msg_hdr hdr;
-       struct nvbin_dnld_req_params dnld_req_params;
-};
-
-struct wcnss_version {
-       struct smd_msg_hdr hdr;
-       unsigned char  major;
-       unsigned char  minor;
-       unsigned char  version;
-       unsigned char  revision;
-};
-
-
-int wcnss_core_prepare(struct platform_device *pdev);
-void wcnss_core_init(void);
-void wcnss_core_deinit(void);
-
-#endif
-
index e310300beaead5ef3384db13b67aa6f6aa8baecc..9faef1de185655447ca8ed9df91ea23c00b1c005 100644 (file)
@@ -192,6 +192,18 @@ static const struct regulator_ops rpm_smps_ldo_ops = {
        .enable = rpm_reg_enable,
        .disable = rpm_reg_disable,
        .is_enabled = rpm_reg_is_enabled,
+       .list_voltage = regulator_list_voltage_linear_range,
+
+       .get_voltage = rpm_reg_get_voltage,
+       .set_voltage = rpm_reg_set_voltage,
+
+       .set_load = rpm_reg_set_load,
+};
+
+static const struct regulator_ops rpm_smps_ldo_ops_fixed = {
+       .enable = rpm_reg_enable,
+       .disable = rpm_reg_disable,
+       .is_enabled = rpm_reg_is_enabled,
 
        .get_voltage = rpm_reg_get_voltage,
        .set_voltage = rpm_reg_set_voltage,
@@ -299,7 +311,7 @@ static const struct regulator_desc pm8941_nldo = {
 static const struct regulator_desc pm8941_lnldo = {
        .fixed_uV = 1740000,
        .n_voltages = 1,
-       .ops = &rpm_smps_ldo_ops,
+       .ops = &rpm_smps_ldo_ops_fixed,
 };
 
 static const struct regulator_desc pm8941_switch = {
index 54d5b637d14caf6aa7e2ef6512631e5ad06bcad1..ff61075a97557fc15b99800c1fad00d2637682ea 100644 (file)
@@ -81,6 +81,7 @@ config QCOM_Q6V5_PIL
        tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
        depends on OF && ARCH_QCOM
        select REMOTEPROC
+       select QCOM_MDT_LOADER
        help
          Say y here to support the Qualcomm Peripherial Image Loader for the
          Hexagon V5 based remote processors.
@@ -93,4 +94,16 @@ config QCOM_TZ_PIL
          Say y here to support the TrustZone based Qualcomm Peripherial Image
          Loader.
 
+config QCOM_MDT_LOADER
+       tristate
+
+config QCOM_WCNSS_PIL
+       tristate "Qualcomm WCNSS Peripheral Image Loader"
+       depends on OF && ARCH_QCOM
+       select REMOTEPROC
+       select QCOM_MDT_LOADER
+       select QCOM_SCM
+       help
+         Peripherial Image Loader for the WCNSS block.
+
 endmenu
index 4351f2e462adddae74ddaff149d896e091dc39bd..1ce1b0a269aba02d82bab1129a8b1ec846ba308f 100644 (file)
@@ -13,3 +13,6 @@ obj-$(CONFIG_WKUP_M3_RPROC)           += wkup_m3_rproc.o
 obj-$(CONFIG_DA8XX_REMOTEPROC)         += da8xx_remoteproc.o
 obj-$(CONFIG_QCOM_Q6V5_PIL)            += qcom_q6v5_pil.o
 obj-$(CONFIG_QCOM_TZ_PIL)              += qcom_tz_pil.o
+obj-$(CONFIG_QCOM_MDT_LOADER)          += qcom_mdt_loader.o
+obj-$(CONFIG_QCOM_WCNSS_PIL)           += qcom_wcnss.o qcom_wcnss_iris.o
+obj-$(CONFIG_QCOM_Q6V5_PIL)            += qcom_q6v5_pil.o
diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c
new file mode 100644 (file)
index 0000000..4efeda9
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2015 Sony Mobile Communications Inc
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 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/elf.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/qcom_scm.h>
+#include <linux/remoteproc.h>
+#include <linux/slab.h>
+
+#include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
+
+/**
+ * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc
+ * @rproc:     remoteproc handle
+ * @fw:                firmware header
+ * @tablesz:   outgoing size of the table
+ *
+ * Returns a dummy table.
+ */
+struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc,
+                                              const struct firmware *fw,
+                                              int *tablesz)
+{
+       static struct resource_table table = { .ver = 1, };
+
+       *tablesz = sizeof(table);
+       return &table;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table);
+
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t max_addr = 0;
+       bool relocate = false;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
+                       relocate = true;
+
+               if (phdr->p_paddr < min_addr)
+                       min_addr = phdr->p_paddr;
+
+               if (phdr->p_paddr + phdr->p_memsz > max_addr)
+                       max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
+       }
+
+       if (fw_addr)
+               *fw_addr = min_addr;
+       if (fw_size)
+               *fw_size = max_addr - min_addr;
+       if (fw_relocate)
+               *fw_relocate = relocate;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_parse);
+
+/**
+ * qcom_mdt_load() - load the firmware which header is defined in fw
+ * @rproc:     rproc handle
+ * @pas_id:    PAS identifier to load this firmware into
+ * @fw:                frimware object for the header
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+int qcom_mdt_load(struct rproc *rproc,
+                 const struct firmware *fw,
+                 const char *firmware)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       unsigned fw_name_len;
+       char *fw_name;
+       void *ptr;
+       int ret;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       fw_name_len = strlen(firmware);
+       if (fw_name_len <= 4)
+               return -EINVAL;
+
+       fw_name = kstrdup(firmware, GFP_KERNEL);
+       if (!fw_name)
+               return -ENOMEM;
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               ptr = rproc_da_to_va(rproc, phdr->p_paddr, phdr->p_memsz);
+               if (!ptr) {
+                       dev_err(&rproc->dev, "segment outside memory range\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (phdr->p_filesz) {
+                       sprintf(fw_name + fw_name_len - 3, "b%02d", i);
+                       ret = request_firmware(&fw, fw_name, &rproc->dev);
+                       if (ret) {
+                               dev_err(&rproc->dev, "failed to load %s\n", fw_name);
+                               break;
+                       }
+
+                       memcpy(ptr, fw->data, fw->size);
+
+                       release_firmware(fw);
+               }
+
+               if (phdr->p_memsz > phdr->p_filesz)
+                       memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+       }
+
+       kfree(fw_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_load);
diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/drivers/remoteproc/qcom_mdt_loader.h
new file mode 100644 (file)
index 0000000..c5d7122
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __QCOM_MDT_LOADER_H__
+#define __QCOM_MDT_LOADER_H__
+
+#define QCOM_MDT_TYPE_MASK     (7 << 24)
+#define QCOM_MDT_TYPE_HASH     (2 << 24)
+#define QCOM_MDT_RELOCATABLE   BIT(27)
+
+struct resource_table * qcom_mdt_find_rsc_table(struct rproc *rproc, const struct firmware *fw, int *tablesz);
+int qcom_mdt_load(struct rproc *rproc, const struct firmware *fw, const char *fw_name);
+
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate);
+
+#endif
index ec4333ed791eb63c1a7202aa5a74a125eeca1c1f..5d3372feb095eda82f208b9e2b361eae2034a88b 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Qualcomm Peripheral Image Loader
  *
+ * Copyright (C) 2016 Linaro Ltd.
  * Copyright (C) 2014 Sony Mobile Communications AB
  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * GNU General Public License for more details.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/firmware.h>
-#include <linux/remoteproc.h>
+#include <linux/io.h>
 #include <linux/interrupt.h>
-#include <linux/memblock.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
 #include <linux/of_address.h>
-#include <linux/elf.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
-#include <linux/soc/qcom/smem.h>
+#include <linux/remoteproc.h>
 #include <linux/reset.h>
-#include <linux/qcom_scm.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
 
 #include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
 
 #include <linux/qcom_scm.h>
 
-#define SCM_SVC_PIL                    0x2
+#define MBA_FIRMWARE_NAME              "mba.mbn"
+#define MPSS_FIRMWARE_NAME             "modem.mdt"
 
-struct mdt_hdr {
-       struct elf32_hdr hdr;
-       struct elf32_phdr phdr[];
-};
+#define MPSS_CRASH_REASON_SMEM         421
+
+/* RMB Status Register Values */
+#define RMB_PBL_SUCCESS                        0x1
+
+#define RMB_MBA_XPU_UNLOCKED           0x1
+#define RMB_MBA_XPU_UNLOCKED_SCRIBBLED 0x2
+#define RMB_MBA_META_DATA_AUTH_SUCCESS 0x3
+#define RMB_MBA_AUTH_COMPLETE          0x4
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE_REG              0x00
+#define RMB_PBL_STATUS_REG             0x04
+#define RMB_MBA_COMMAND_REG            0x08
+#define RMB_MBA_STATUS_REG             0x0C
+#define RMB_PMI_META_DATA_REG          0x10
+#define RMB_PMI_CODE_START_REG         0x14
+#define RMB_PMI_CODE_LENGTH_REG                0x18
+
+#define RMB_CMD_META_DATA_READY                0x1
+#define RMB_CMD_LOAD_READY             0x2
+
+/* QDSP6SS Register Offsets */
+#define QDSP6SS_RESET_REG              0x014
+#define QDSP6SS_GFMUX_CTL_REG          0x020
+#define QDSP6SS_PWR_CTL_REG            0x030
+
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ_REG                        0x0
+#define AXI_HALTACK_REG                        0x4
+#define AXI_IDLE_REG                   0x8
+
+#define HALT_ACK_TIMEOUT_MS            100
 
-struct qproc {
+/* QDSP6SS_RESET */
+#define Q6SS_STOP_CORE                 BIT(0)
+#define Q6SS_CORE_ARES                 BIT(1)
+#define Q6SS_BUS_ARES_ENABLE           BIT(2)
+
+/* QDSP6SS_GFMUX_CTL */
+#define Q6SS_CLK_ENABLE                        BIT(1)
+
+/* QDSP6SS_PWR_CTL */
+#define Q6SS_L2DATA_SLP_NRET_N_0       BIT(0)
+#define Q6SS_L2DATA_SLP_NRET_N_1       BIT(1)
+#define Q6SS_L2DATA_SLP_NRET_N_2       BIT(2)
+#define Q6SS_L2TAG_SLP_NRET_N          BIT(16)
+#define Q6SS_ETB_SLP_NRET_N            BIT(17)
+#define Q6SS_L2DATA_STBY_N             BIT(18)
+#define Q6SS_SLP_RET_N                 BIT(19)
+#define Q6SS_CLAMP_IO                  BIT(20)
+#define QDSS_BHS_ON                    BIT(21)
+#define QDSS_LDO_BYP                   BIT(22)
+
+struct q6v5 {
        struct device *dev;
        struct rproc *rproc;
 
        void __iomem *reg_base;
-       void __iomem *halt_base;
-       void __iomem *halt_q6;
-       void __iomem *halt_modem;
-       void __iomem *halt_nc;
        void __iomem *rmb_base;
-       void __iomem *restart_sec_base;
 
-       struct reset_control *mss_restart;
+       struct regmap *halt_map;
+       u32 halt_q6;
+       u32 halt_modem;
+       u32 halt_nc;
 
-       int wdog_irq;
-       int fatal_irq;
-       int ready_irq;
-       int handover_irq;
-       int stop_ack_irq;
+       struct reset_control *mss_restart;
 
-       struct gpio_desc *stop_gpio;
+       struct qcom_smem_state *state;
+       unsigned stop_bit;
 
-       struct regulator *vdd;
-       struct regulator *cx;
-       struct regulator *mx;
-       struct regulator *pll;
+       struct regulator_bulk_data supply[4];
 
        struct clk *ahb_clk;
        struct clk *axi_clk;
        struct clk *rom_clk;
 
        struct completion start_done;
+       struct completion stop_done;
+       bool running;
 
-       void                    *mba_va;
-       dma_addr_t              mba_da;
-       size_t                  mba_size;
-       struct dma_attrs        mba_attrs;
+       phys_addr_t mba_phys;
+       void *mba_region;
+       size_t mba_size;
 
-       phys_addr_t reloc_phys;
-       size_t reloc_size;
+       phys_addr_t mpss_phys;
+       phys_addr_t mpss_reloc;
+       void *mpss_region;
+       size_t mpss_size;
 };
 
-#define VDD_MSS_UV     1000000
-#define VDD_MSS_UV_MAX 1150000
-#define VDD_MSS_UA     100000
-
-/* Q6 Register Offsets */
-#define QDSP6SS_RST_EVB                 0x010
-
-/* AXI Halting Registers */
-#define MSS_Q6_HALT_BASE                0x180
-#define MSS_MODEM_HALT_BASE             0x200
-#define MSS_NC_HALT_BASE                0x280
-
-/* RMB Status Register Values */
-#define STATUS_PBL_SUCCESS              0x1
-#define STATUS_XPU_UNLOCKED             0x1
-#define STATUS_XPU_UNLOCKED_SCRIBBLED   0x2
-
-/* PBL/MBA interface registers */
-#define RMB_MBA_IMAGE                   0x00
-#define RMB_PBL_STATUS                  0x04
-#define RMB_MBA_COMMAND                 0x08
-#define RMB_MBA_STATUS                  0x0C
-#define RMB_PMI_META_DATA               0x10
-#define RMB_PMI_CODE_START              0x14
-#define RMB_PMI_CODE_LENGTH             0x18
-
-#define POLL_INTERVAL_US                50
-
-#define CMD_META_DATA_READY             0x1
-#define CMD_LOAD_READY                  0x2
+enum {
+       Q6V5_SUPPLY_CX,
+       Q6V5_SUPPLY_MX,
+       Q6V5_SUPPLY_MSS,
+       Q6V5_SUPPLY_PLL,
+};
 
-#define STATUS_META_DATA_AUTH_SUCCESS   0x3
-#define STATUS_AUTH_COMPLETE            0x4
+static int q6v5_regulator_init(struct q6v5 *qproc)
+{
+       int ret;
 
-/* External BHS */
-#define EXTERNAL_BHS_ON                 BIT(0)
-#define EXTERNAL_BHS_STATUS             BIT(4)
-#define BHS_TIMEOUT_US                  50
+       qproc->supply[Q6V5_SUPPLY_CX].supply = "cx";
+       qproc->supply[Q6V5_SUPPLY_MX].supply = "mx";
+       qproc->supply[Q6V5_SUPPLY_MSS].supply = "mss";
+       qproc->supply[Q6V5_SUPPLY_PLL].supply = "pll";
 
-#define MSS_RESTART_ID                  0xA
+       ret = devm_regulator_bulk_get(qproc->dev,
+                                     ARRAY_SIZE(qproc->supply), qproc->supply);
+       if (ret < 0) {
+               dev_err(qproc->dev, "failed to get supplies\n");
+               return ret;
+       }
 
-/* QDSP6SS Register Offsets */
-#define QDSP6SS_RESET                   0x014
-#define QDSP6SS_GFMUX_CTL               0x020
-#define QDSP6SS_PWR_CTL                 0x030
-#define QDSP6SS_STRAP_ACC               0x110
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_CX].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_PLL].consumer, 10000);
 
-/* AXI Halt Register Offsets */
-#define AXI_HALTREQ                     0x0
-#define AXI_HALTACK                     0x4
-#define AXI_IDLE                        0x8
+       return 0;
+}
 
-#define HALT_ACK_TIMEOUT_US             100000
+static int q6v5_regulator_enable(struct q6v5 *qproc)
+{
+       int ret;
 
-/* QDSP6SS_RESET */
-#define Q6SS_STOP_CORE                  BIT(0)
-#define Q6SS_CORE_ARES                  BIT(1)
-#define Q6SS_BUS_ARES_ENA               BIT(2)
+       /* TODO: Q6V5_SUPPLY_CX is supposed to be set to super-turbo here */
+       ret = regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MX].consumer,
+                                   1050000, INT_MAX);
+       if (ret)
+               return ret;
 
-/* QDSP6SS_GFMUX_CTL */
-#define Q6SS_CLK_ENA                    BIT(1)
-#define Q6SS_CLK_SRC_SEL_C              BIT(3)
-#define Q6SS_CLK_SRC_SEL_FIELD          0xC
-#define Q6SS_CLK_SRC_SWITCH_CLK_OVR     BIT(8)
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MSS].consumer,
+                             1000000, 1150000);
 
-/* QDSP6SS_PWR_CTL */
-#define Q6SS_L2DATA_SLP_NRET_N_0        BIT(0)
-#define Q6SS_L2DATA_SLP_NRET_N_1        BIT(1)
-#define Q6SS_L2DATA_SLP_NRET_N_2        BIT(2)
-#define Q6SS_L2TAG_SLP_NRET_N           BIT(16)
-#define Q6SS_ETB_SLP_NRET_N             BIT(17)
-#define Q6SS_L2DATA_STBY_N              BIT(18)
-#define Q6SS_SLP_RET_N                  BIT(19)
-#define Q6SS_CLAMP_IO                   BIT(20)
-#define QDSS_BHS_ON                     BIT(21)
-#define QDSS_LDO_BYP                    BIT(22)
-
-/* QDSP6v55 parameters */
-#define QDSP6v55_LDO_ON                 BIT(26)
-#define QDSP6v55_LDO_BYP                BIT(25)
-#define QDSP6v55_BHS_ON                 BIT(24)
-#define QDSP6v55_CLAMP_WL               BIT(21)
-#define L1IU_SLP_NRET_N                 BIT(15)
-#define L1DU_SLP_NRET_N                 BIT(14)
-#define L2PLRU_SLP_NRET_N               BIT(13)
-
-#define HALT_CHECK_MAX_LOOPS            (200)
-#define QDSP6SS_XO_CBCR                 (0x0038)
-
-#define QDSP6SS_ACC_OVERRIDE_VAL        0x20
-
-#define segment_is_hash(flag) (((flag) & (0x7 << 24)) == (0x2 << 24))
-static int segment_is_loadable(const struct elf32_phdr *p)
-{
-       return (p->p_type == PT_LOAD) &&
-              !segment_is_hash(p->p_flags) &&
-              p->p_memsz;
+       return regulator_bulk_enable(ARRAY_SIZE(qproc->supply), qproc->supply);
 }
 
-static bool segment_is_relocatable(const struct elf32_phdr *p)
+static void q6v5_regulator_disable(struct q6v5 *qproc)
 {
-       return !!(p->p_flags & BIT(27));
+       regulator_bulk_disable(ARRAY_SIZE(qproc->supply), qproc->supply);
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_CX].consumer, 0, INT_MAX);
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MX].consumer, 0, INT_MAX);
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 0, 1150000);
 }
 
-static int qproc_sanity_check(struct rproc *rproc,
-                                 const struct firmware *fw)
+static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
 {
-       if (!fw) {
-               dev_err(&rproc->dev, "failed to load %s\n", rproc->name);
-               return -EINVAL;
-       }
+       struct q6v5 *qproc = rproc->priv;
 
-       /* XXX: ??? */
+       memcpy(qproc->mba_region, fw->data, fw->size);
 
        return 0;
 }
 
-static struct resource_table * qproc_find_rsc_table(struct rproc *rproc,
-                                                   const struct firmware *fw,
-                                                   int *tablesz)
+static const struct rproc_fw_ops q6v5_fw_ops = {
+       .find_rsc_table = qcom_mdt_find_rsc_table,
+       .load = q6v5_load,
+};
+
+static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms)
 {
-       static struct resource_table table = { .ver = 1, };
+       unsigned long timeout;
+       s32 val;
 
-       *tablesz = sizeof(table);
-       return &table;
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_PBL_STATUS_REG);
+               if (val)
+                       break;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+       }
+
+       return val;
 }
 
-static int qproc_load(struct rproc *rproc, const struct firmware *fw)
+static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms)
 {
-       struct qproc *qproc = rproc->priv;
-       DEFINE_DMA_ATTRS(attrs);
-       dma_addr_t phys;
-       dma_addr_t end;
-       void *ptr;
 
-       dma_set_mask(qproc->dev, DMA_BIT_MASK(32));
-       dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &attrs);
+       unsigned long timeout;
+       s32 val;
 
-       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, &attrs);
-       if (!ptr) {
-               dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
-               return -ENOMEM;
-       }
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
+               if (val < 0)
+                       break;
 
-       end = phys + fw->size;
-       dev_info(qproc->dev, "loading MBA from %pa to %pa\n", &phys, &end);
+               if (!status && val)
+                       break;
+               else if (status && val == status)
+                       break;
 
-       memcpy(ptr, fw->data, fw->size);
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
 
-       qproc->mba_va = ptr;
-       qproc->mba_da = phys;
-       qproc->mba_size = fw->size;
-       qproc->mba_attrs = attrs;
+               msleep(1);
+       }
 
-       return 0;
+       return val;
 }
 
-static const struct rproc_fw_ops qproc_fw_ops = {
-       .find_rsc_table = qproc_find_rsc_table,
-       .load = qproc_load,
-       .sanity_check = qproc_sanity_check,
-};
-
-static void q6v5proc_reset(struct qproc *qproc)
+static void q6v5proc_reset(struct q6v5 *qproc)
 {
        u32 val;
 
        /* Assert resets, stop core */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_RESET);
-       val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA | Q6SS_STOP_CORE);
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_RESET);
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
 
        /* Enable power block headswitch, and wait for it to stabilize */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL);
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= QDSS_BHS_ON | QDSS_LDO_BYP;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        mb();
        udelay(1);
 
@@ -270,604 +265,214 @@ static void q6v5proc_reset(struct qproc *qproc)
         * Turn on memories. L2 banks should be done individually
         * to minimize inrush current.
         */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL);
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N |
                Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_L2DATA_SLP_NRET_N_2;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_L2DATA_SLP_NRET_N_1;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_L2DATA_SLP_NRET_N_0;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
 
        /* Remove IO clamp */
        val &= ~Q6SS_CLAMP_IO;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
 
        /* Bring core out of reset */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_RESET);
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
        val &= ~Q6SS_CORE_ARES;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_RESET);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
 
        /* Turn on core clock */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_GFMUX_CTL);
-       val |= Q6SS_CLK_ENA;
-
-#if 0
-       /* Need a different clock source for v5.2.0 */
-       if (qproc->qdsp6v5_2_0) {
-               val &= ~Q6SS_CLK_SRC_SEL_FIELD;
-               val |= Q6SS_CLK_SRC_SEL_C;
-       }
-
-#endif
-       /* force clock on during source switch */
-//     if (qproc->qdsp6v56)
-               val |= Q6SS_CLK_SRC_SWITCH_CLK_OVR;
-
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_GFMUX_CTL);
+       val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+       val |= Q6SS_CLK_ENABLE;
+       writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
 
        /* Start core execution */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_RESET);
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
        val &= ~Q6SS_STOP_CORE;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_RESET);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
 }
 
-static void q6v5proc_halt_axi_port(struct qproc *qproc, void __iomem *halt)
+static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
+                                  struct regmap *halt_map,
+                                  u32 offset)
 {
        unsigned long timeout;
+       unsigned int val;
+       int ret;
 
-       if (readl_relaxed(halt + AXI_IDLE))
+       /* Check if we're already idle */
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (!ret && val)
                return;
 
-        /* Assert halt request */
-        writel_relaxed(1, halt + AXI_HALTREQ);
+       /* Assert halt request */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
 
-        /* Wait for halt */
-       timeout = jiffies + 10 * HZ;
+       /* Wait for halt */
+       timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
        for (;;) {
-               if (readl(halt + AXI_HALTACK) || time_after(jiffies, timeout))
+               ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
+               if (ret || val || time_after(jiffies, timeout))
                        break;
 
                msleep(1);
        }
 
-       if (!readl_relaxed(halt + AXI_IDLE))
-               dev_err(qproc->dev, "port %pa failed halt\n", &halt);
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (ret || !val)
+               dev_err(qproc->dev, "port failed halt\n");
 
-        /* Clear halt request (port will remain halted until reset) */
-        writel_relaxed(0, halt + AXI_HALTREQ);
+       /* Clear halt request (port will remain halted until reset) */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
 }
 
-static int qproc_mba_load_mdt(struct qproc *qproc, const struct firmware *fw)
+static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
 {
        DEFINE_DMA_ATTRS(attrs);
-       unsigned long timeout;
        dma_addr_t phys;
-       dma_addr_t end;
        void *ptr;
        int ret;
-       s32 val;
 
-       dma_set_mask(qproc->dev, DMA_BIT_MASK(32));
        dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &attrs);
-
        ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, &attrs);
        if (!ptr) {
-               dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
+               dev_err(qproc->dev, "failed to allocate mdt buffer\n");
                return -ENOMEM;
        }
 
-       end = phys + fw->size;
-       dev_info(qproc->dev, "loading mdt header from %pa to %pa\n", &phys, &end);
-
        memcpy(ptr, fw->data, fw->size);
 
-       writel_relaxed(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH);
+       writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG);
+       writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
 
-       writel_relaxed(phys, qproc->rmb_base + RMB_PMI_META_DATA);
-       writel(CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND);
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MBA header authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MBA returned error %d for MDT header\n", ret);
 
-       timeout = jiffies + HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val == STATUS_META_DATA_AUTH_SUCCESS || val < 0)
-                       break;
-
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
-               dev_err(qproc->dev, "MBA authentication of headers timed out\n");
-               ret = -ETIMEDOUT;
-               goto out;
-       } else if (val < 0) {
-               dev_err(qproc->dev, "MBA returned error %d for headers\n", val);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       dev_err(qproc->dev, "mdt authenticated\n");
-
-       ret = 0;
-out:
        dma_free_attrs(qproc->dev, fw->size, ptr, phys, &attrs);
 
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 
-
-static int
-old_qproc_load_segments(struct qproc *qproc, const struct firmware *fw)
+static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
 {
-       struct device *dev = qproc->dev;
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
        struct elf32_hdr *ehdr;
-       struct elf32_phdr *phdr;
-       int i, ret = 0;
-       const u8 *elf_data = fw->data;
-       const struct firmware *seg_fw;
-       char fw_name[20];
-
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-
-
-
-       /* go through the available ELF segments */
-       for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-               u32 da = phdr->p_paddr;
-               u32 memsz = phdr->p_memsz;
-               u32 filesz = phdr->p_filesz;
-               void *ptr;
-
-               if (!segment_is_loadable(phdr))
-                       continue;
-               /*
-               if (phdr->p_type != PT_LOAD)
-                       continue;
-
-               if (segment_is_hash(phdr->p_flags))
-                       continue;
-
-               if (filesz == 0)
-                       continue;
-*/
-               //dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-               pr_emerg("phdr(%d): type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-                                       i, phdr->p_type, da, memsz, filesz);
-
-               if (filesz > memsz) {
-                       dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
-                                                       filesz, memsz);
-                       ret = -EINVAL;
-                       break;
-               }
-
-               ptr = ioremap(da, memsz);
-               if (!ptr) {
-                       dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               if (filesz) {
-                       snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
-                       ret = request_firmware(&seg_fw, fw_name, qproc->dev);
-                       if (ret) {
-                               iounmap(ptr);
-                               break;
-                       }
-
-                       memcpy(ptr, seg_fw->data, filesz);
-
-                       release_firmware(seg_fw);
-               }
-
-               if (memsz > filesz)
-                       memset(ptr + filesz, 0, memsz - filesz);
-
-
-
-               wmb();
-               iounmap(ptr);
-       }
-
-       return ret;
-}
-
-static int qproc_verify_segment(struct qproc *qproc, phys_addr_t paddr, size_t size)
-{
-       s32 status;
-       u32 img_length;
-
-       img_length = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %x\n", img_length);
-
-       msleep(1);
-       img_length = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %x\n", img_length);
-
-
-       if (img_length == 0) {
-               writel_relaxed(paddr, qproc->rmb_base + RMB_PMI_CODE_START);
-               writel(CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND);
-       }
-       img_length += size;
-       writel(img_length, qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-
-       img_length = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %x\n", img_length);
-       
-       status = readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS);
-
-
-       if (status < 0) {
-               dev_err(qproc->dev, "MBA returned error %d\n", status);
-       }
-
-       printk("DEBUG:pil: status... %08x\n", readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS));
-
-       return 0;
-}
-
-static int qproc_load_segment(struct qproc *rproc, const char *fw_name,
-                               const struct elf32_phdr *phdr, phys_addr_t paddr)
-{
-       const struct firmware *fw;
-       void *ptr;
-       int ret = 0;
-
-       ptr = ioremap_nocache(paddr, phdr->p_memsz);
-       if (!ptr) {
-               dev_err(rproc->dev, "failed to ioremap segment area (%pa+0x%x)\n", &paddr, phdr->p_memsz);
-               return -EBUSY;
-       }
-
-       if (phdr->p_filesz) {
-               ret = request_firmware(&fw, fw_name, rproc->dev);
-               if (ret) {
-                       dev_err(rproc->dev, "failed to load %s\n", fw_name);
-                       goto out;
-               }
-
-               memcpy_toio(ptr, fw->data, fw->size);
+       phys_addr_t boot_addr;
+       phys_addr_t fw_addr;
+       bool relocate;
+       size_t size;
+       u32 val;
+       int ret;
+       int i;
 
-               release_firmware(fw);
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               return ret;
        }
 
-       if (phdr->p_memsz > phdr->p_filesz)
-               memset_io(ptr + phdr->p_filesz, 0,
-                         phdr->p_memsz - phdr->p_filesz);
-
-       printk("DEBUG:pil: verifing %s size: %x\n",fw_name, phdr->p_memsz);
-       qproc_verify_segment(rproc, paddr, phdr->p_memsz);
-
-out:
-       iounmap(ptr);
-       return ret;
-}
-
-static int
-qproc_load_segments(struct qproc *qproc, const struct firmware *fw)
-{
-       struct device *dev = qproc->dev;
-       struct elf32_hdr *ehdr;
-       struct elf32_phdr *phdr;
-       int i, ret = 0;
-       const u8 *elf_data = fw->data;
-       const struct firmware *seg_fw;
-       char fw_name[20];
-
-       const struct mdt_hdr *mdt;
-       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
-       phys_addr_t max_addr = 0;
-       size_t align = 0;
-       bool relocatable = false;
-       phys_addr_t paddr;
-
-
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-
-
-       mdt = (struct mdt_hdr *)fw->data;
-       ehdr = &mdt->hdr;
-
-       for (i = 0; i < ehdr->e_phnum; i++) {
-               phdr = &mdt->phdr[i];
-
-               if (!segment_is_loadable(phdr))
-                       continue;
-
-               if (phdr->p_paddr < min_addr) {
-                       min_addr = phdr->p_paddr;
-
-                       if (segment_is_relocatable(phdr)) {
-                               align = phdr->p_align;
-                               relocatable = true;
-                       }
-               }
-
-               if (phdr->p_paddr + phdr->p_memsz > max_addr)
-                       max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
-       }
+       if (relocate)
+               boot_addr = qproc->mpss_phys;
+       else
+               boot_addr = fw_addr;
 
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-       /* go through the available ELF segments */
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
        for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-               u32 da = phdr->p_paddr;
-               u32 paddr = phdr->p_paddr;
-               u32 memsz = phdr->p_memsz;
-               u32 filesz = phdr->p_filesz;
-               void *ptr;
+               phdr = &phdrs[i];
 
-               if (!segment_is_loadable(phdr))
-                       continue;
-               /*
                if (phdr->p_type != PT_LOAD)
                        continue;
 
-               if (segment_is_hash(phdr->p_flags))
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
                        continue;
 
-               if (filesz == 0)
+               if (!phdr->p_memsz)
                        continue;
-*/
-               //dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-               pr_emerg("phdr(%d): type %d paddr 0x%x memsz 0x%x filesz 0x%x\n",
-                                       i, phdr->p_type, paddr, memsz, filesz);
-
-               if (filesz > memsz) {
-                       dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
-                                                       filesz, memsz);
-                       ret = -EINVAL;
-                       break;
-               }
 
-               paddr = relocatable ?
-                               (phdr->p_paddr - min_addr + qproc->reloc_phys) :
-                               phdr->p_paddr;
-
-               pr_emerg("Relocated-phdr(%d): type %d paddr 0x%x memsz 0x%x filesz 0x%x\n",
-                                       i, phdr->p_type, paddr, memsz, filesz);
-//             if (filesz) {
-                       snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
-                       ret = qproc_load_segment(qproc, fw_name, phdr, paddr);
-//             }
-#if 0
-
-               ptr = ioremap(da, memsz);
-               if (!ptr) {
-                       dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
-                       ret = -ENOMEM;
-                       break;
+               size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+               if (!size) {
+                       writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
+                       writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
                }
 
-               if (filesz) {
-                       snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
-                       ret = request_firmware(&seg_fw, fw_name, qproc->dev);
-                       if (ret) {
-                               iounmap(ptr);
-                               break;
-                       }
-
-                       memcpy(ptr, seg_fw->data, filesz);
-
-                       release_firmware(seg_fw);
-               }
-
-               if (memsz > filesz)
-                       memset(ptr + filesz, 0, memsz - filesz);
-
-
-
-               wmb();
-               iounmap(ptr);
-#endif
+               size += phdr->p_memsz;
+               writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
        }
 
-       return ret;
+       val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
+       return val < 0 ? val : 0;
 }
 
-static int qproc_verify_segments(struct qproc *qproc, const struct firmware *fw)
+static int q6v5_mpss_load(struct q6v5 *qproc)
 {
-       struct elf32_hdr *ehdr;
-       struct elf32_phdr *phdr;
-       const u8 *elf_data = fw->data;
-       unsigned long timeout;
-       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
-       u32 size = 0;
-       s32 val;
+       const struct firmware *fw;
+       phys_addr_t fw_addr;
+       bool relocate;
        int ret;
-       int i;
-       u32 v;
-
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-
-       v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
-
-       msleep(1);
-
-
-#if 1
-       for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-               phys_addr_t da = phdr->p_paddr;
-               u32 memsz = phdr->p_memsz;
-
-
-               if (!segment_is_loadable(phdr))
-                       continue;
-               /*
-               if (phdr->p_type != PT_LOAD)
-                       continue;
-*/
-               dev_err(qproc->dev, "0x%x %d %d\n", phdr->p_paddr, segment_is_hash(phdr->p_flags), !!(phdr->p_flags & BIT(27)));
-
-               /*
-               if (segment_is_hash(phdr->p_flags))
-                       continue;
-
-               if (memsz == 0)
-                       continue;
-               */
-               if (da < min_addr)
-                       min_addr = da;
-
-               size += memsz;
-       }
-
-       dev_err(qproc->dev, "verify: %pa:%pa\n", &min_addr, &size);
-       v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
-#if 0
-if (v == 0) {
-       writel_relaxed(min_addr, qproc->rmb_base + RMB_PMI_CODE_START);
-       writel(CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND);
-}
-       writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-#endif
-#endif
-
-       v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
-       
-       printk("DEBUG:pil: status... %08x\n", readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS));
 
-       timeout = jiffies + 10 * HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val == STATUS_AUTH_COMPLETE || val < 0)
-                       break;
-
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
-               dev_err(qproc->dev, "MBA authentication of headers timed out\n");
-               ret = -ETIMEDOUT;
-               goto out;
-       } else if (val < 0) {
-               dev_err(qproc->dev, "MBA returned error %d for segments\n", val);
-               ret = -EINVAL;
-               goto out;
+       ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev);
+       if (ret < 0) {
+               dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n");
+               return ret;
        }
 
-       ret = 0;
-out:
-       return ret;
-
-
-}
-
-static int qproc_msa_mba_auth(struct qproc *qproc)
-{
-       unsigned long timeout;
-       s32 val;
-       int ret;
-       int i;
-       u32 v;
-
-       timeout = jiffies + 10 * HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val == STATUS_AUTH_COMPLETE || val < 0)
-                       break;
-
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
-               dev_err(qproc->dev, "MBA authentication of headers timed out\n");
-               ret = -ETIMEDOUT;
-//             goto out;
-       } else if (val < 0) {
-               dev_err(qproc->dev, "MBA returned error %d for segments\n", val);
-               ret = -EINVAL;
-//             goto out;
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               goto release_firmware;
        }
-       printk("DEBUG:pil: status auth... %08x\n", readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS));
-
-       return 0;
-}
 
-static int qproc_load_modem(struct qproc *qproc)
-{
-       const struct firmware *fw;
-       int ret;
+       if (relocate)
+               qproc->mpss_reloc = fw_addr;
 
-       ret = request_firmware(&fw, "modem.mdt", qproc->dev);
-       if (ret < 0) {
-               dev_err(qproc->dev, "unable to load modem.mdt\n");
-               return ret;
-       }
+       /* Initialize the RMB validator */
+       writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
 
-       dev_err(qproc->dev, "Loading mba\n");
-       ret = qproc_mba_load_mdt(qproc, fw);
+       ret = q6v5_mpss_init_image(qproc, fw);
        if (ret)
-               goto out;
+               goto release_firmware;
 
-       dev_err(qproc->dev, "Loading segments\n");
-       ret = qproc_load_segments(qproc, fw);
+       ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME);
        if (ret)
-               goto out;
+               goto release_firmware;
 
-       ret = qproc_msa_mba_auth(qproc);
-//     dev_err(qproc->dev, "Verifying segments\n");
-//     ret = qproc_verify_segments(qproc, fw);
-//     if (ret)
-//             goto out;
-       return 0;
-out:
-       release_firmware(fw);
+       ret = q6v5_mpss_validate(qproc, fw);
+       if (ret)
+               goto release_firmware;
 
-       return ret;
-}
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MBA authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MBA returned error %d\n", ret);
 
-static int pil_mss_restart_reg(struct qproc *qproc, int mss_restart)
-{
-       int ret = 0;
-       unsigned int resp;
-       ret = qcom_scm_restart_proc(MSS_RESTART_ID, mss_restart, &resp);
-       if (ret || resp)
-               pr_err("Secure MSS restart failed\n");
+release_firmware:
+       release_firmware(fw);
 
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 
-static int qproc_start(struct rproc *rproc)
+static int q6v5_start(struct rproc *rproc)
 {
-       struct qproc *qproc = (struct qproc *)rproc->priv;
-       unsigned long timeout;
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
        int ret;
-       u32 val;
-
-       printk("DEBUG::: pill................... %s \n", __func__);
-//     ret = regulator_enable(qproc->vdd);
-//     if (ret) {
-//             dev_err(qproc->dev, "failed to enable mss vdd\n");
-//             return ret;
-//     }
 
-       ret = regulator_enable(qproc->pll);
+       ret = q6v5_regulator_enable(qproc);
        if (ret) {
-               dev_err(qproc->dev, "failed to enable mss vdd pll\n");
+               dev_err(qproc->dev, "failed to enable supplies\n");
                return ret;
        }
 
-
-       ret = pil_mss_restart_reg(qproc, 0);
-       //FIXME
-       //ret = reset_control_deassert(qproc->mss_restart);
+       ret = reset_control_deassert(qproc->mss_restart);
        if (ret) {
                dev_err(qproc->dev, "failed to deassert mss restart\n");
                goto disable_vdd;
@@ -885,61 +490,54 @@ static int qproc_start(struct rproc *rproc)
        if (ret)
                goto disable_axi_clk;
 
-       writel_relaxed(qproc->mba_da, qproc->rmb_base + RMB_MBA_IMAGE);
-
-       /* Ensure order of data/entry point and the following reset release */
-       wmb();
+       writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
 
        q6v5proc_reset(qproc);
 
-       timeout = jiffies + HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_PBL_STATUS);
-               if (val || time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
+       ret = q6v5_rmb_pbl_wait(qproc, 1000);
+       if (ret == -ETIMEDOUT) {
                dev_err(qproc->dev, "PBL boot timed out\n");
-               ret = -ETIMEDOUT;
                goto halt_axi_ports;
-       } else if (val != STATUS_PBL_SUCCESS) {
-               dev_err(qproc->dev, "PBL returned unexpected status %d\n", val);
+       } else if (ret != RMB_PBL_SUCCESS) {
+               dev_err(qproc->dev, "PBL returned unexpected status %d\n", ret);
                ret = -EINVAL;
                goto halt_axi_ports;
        }
 
-       timeout = jiffies + HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val || time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
+       ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
+       if (ret == -ETIMEDOUT) {
                dev_err(qproc->dev, "MBA boot timed out\n");
-               ret = -ETIMEDOUT;
                goto halt_axi_ports;
-       } else if (val != STATUS_XPU_UNLOCKED && val != STATUS_XPU_UNLOCKED_SCRIBBLED) {
-               dev_err(qproc->dev, "MBA returned unexpected status %d\n", val);
+       } else if (ret != RMB_MBA_XPU_UNLOCKED && ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
+               dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
                ret = -EINVAL;
                goto halt_axi_ports;
        }
 
-       dev_info(qproc->dev, "MBA boot done\n");
+       dev_info(qproc->dev, "MBA booted, loading mpss\n");
 
-       ret = qproc_load_modem(qproc);
+       ret = q6v5_mpss_load(qproc);
        if (ret)
                goto halt_axi_ports;
 
+       ret = wait_for_completion_timeout(&qproc->start_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0) {
+               dev_err(qproc->dev, "start timed out\n");
+               ret = -ETIMEDOUT;
+               goto halt_axi_ports;
+       }
+
+       qproc->running = true;
+
+       /* All done, release the handover resources */
+
        return 0;
 
 halt_axi_ports:
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_Q6_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_MODEM_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_NC_HALT_BASE);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
 disable_axi_clk:
        clk_disable_unprepare(qproc->axi_clk);
 disable_ahb_clk:
@@ -947,215 +545,199 @@ disable_ahb_clk:
 assert_reset:
        reset_control_assert(qproc->mss_restart);
 disable_vdd:
-//     regulator_disable(qproc->vdd);
+       q6v5_regulator_disable(qproc);
 
-       dma_free_attrs(qproc->dev, qproc->mba_size, qproc->mba_va, qproc->mba_da, &qproc->mba_attrs);
        return ret;
 }
 
-static int qproc_stop(struct rproc *rproc)
+static int q6v5_stop(struct rproc *rproc)
 {
-       struct qproc *qproc = (struct qproc *)rproc->priv;
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+       int ret;
+
+       qproc->running = false;
+
+       qcom_smem_state_update_bits(qproc->state,
+                                   BIT(qproc->stop_bit), BIT(qproc->stop_bit));
+
+       ret = wait_for_completion_timeout(&qproc->stop_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0)
+               dev_err(qproc->dev, "timed out on wait\n");
 
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_Q6_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_MODEM_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_NC_HALT_BASE);
+       qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit), 0);
+
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
 
        reset_control_assert(qproc->mss_restart);
        clk_disable_unprepare(qproc->axi_clk);
        clk_disable_unprepare(qproc->ahb_clk);
-//     regulator_disable(qproc->vdd);
-
-       dma_free_attrs(qproc->dev, qproc->mba_size, qproc->mba_va, qproc->mba_da, &qproc->mba_attrs);
+       q6v5_regulator_disable(qproc);
 
        return 0;
 }
 
-static const struct rproc_ops qproc_ops = {
-       .start = qproc_start,
-       .stop = qproc_stop,
-};
-
-static irqreturn_t qproc_wdog_interrupt(int irq, void *dev)
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
 {
-       struct qproc *qproc = dev;
+       struct q6v5 *qproc = rproc->priv;
+       int offset;
 
-       dev_err(qproc->dev, "                                                            WATCHDOG\n");
+       offset = da - qproc->mpss_reloc;
+       if (offset < 0 || offset + len > qproc->mpss_size)
+               return NULL;
 
-       rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
-       return IRQ_HANDLED;
+       return qproc->mpss_region + offset;
 }
 
-static irqreturn_t qproc_fatal_interrupt(int irq, void *dev)
-{
-       struct qproc *qproc = dev;
-
-       dev_err(qproc->dev, "                                                            FATAL\n");
+static const struct rproc_ops q6v5_ops = {
+       .start = q6v5_start,
+       .stop = q6v5_stop,
+       .da_to_va = q6v5_da_to_va,
+};
 
-       rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
+static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
 
-       return IRQ_HANDLED;
-}
+       /* Sometimes the stop triggers a watchdog rather than a stop-ack */
+       if (!qproc->running) {
+               complete(&qproc->stop_done);
+               return IRQ_HANDLED;
+       }
 
-static irqreturn_t qproc_ready_interrupt(int irq, void *dev)
-{
-       struct qproc *qproc = dev;
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "watchdog received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "watchdog without message\n");
 
-       dev_err(qproc->dev, "                                                            READY\n");
+       rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
 
-       complete(&qproc->start_done);
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
 
        return IRQ_HANDLED;
 }
 
-static irqreturn_t qproc_handover_interrupt(int irq, void *dev)
+static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
 {
-       struct qproc *qproc = dev;
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
 
-       dev_err(qproc->dev, "                                                            HANDOVER\n");
-
-       return IRQ_HANDLED;
-}
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "fatal error received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "fatal error without message\n");
 
-static irqreturn_t qproc_stop_ack_interrupt(int irq, void *dev)
-{
-       struct qproc *qproc = dev;
+       rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
 
-       dev_err(qproc->dev, "                                                            STOP-ACK\n");
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
 
        return IRQ_HANDLED;
 }
 
-static ssize_t qproc_boot_store(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t size)
+static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
 {
-       struct qproc *qproc = dev_get_drvdata(dev);
-       int ret;
+       struct q6v5 *qproc = dev;
 
-       ret = rproc_boot(qproc->rproc);
-       return ret ? : size;
+       complete(&qproc->start_done);
+       return IRQ_HANDLED;
 }
 
-static ssize_t qproc_shutdown_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t size)
+static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev)
 {
-       struct qproc *qproc = dev_get_drvdata(dev);
+       struct q6v5 *qproc = dev;
 
-       rproc_shutdown(qproc->rproc);
-       return size;
+       complete(&qproc->stop_done);
+       return IRQ_HANDLED;
 }
 
-static const struct device_attribute qproc_attrs[] = {
-       __ATTR(boot, S_IWUSR, 0, qproc_boot_store),
-       __ATTR(shutdown, S_IWUSR, 0, qproc_shutdown_store),
-};
-
-static int qproc_init_mem(struct qproc *qproc, struct platform_device *pdev)
+static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
 {
+       struct device_node *halt_np;
        struct resource *res;
+       int ret;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
        qproc->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(qproc->reg_base))
+       if (IS_ERR(qproc->reg_base)) {
+               dev_err(qproc->dev, "failed to get qdsp6_base\n");
                return PTR_ERR(qproc->reg_base);
+       }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
-       qproc->halt_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(qproc->halt_base)) {
-#if 0
-               //return PTR_ERR(qproc->halt_base);
-
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_q6");
-               qproc->halt_q6 = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(qproc->halt_q6))
-                       return PTR_ERR(qproc->halt_q6);
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
+       qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(qproc->rmb_base)) {
+               dev_err(qproc->dev, "failed to get rmb_base\n");
+               return PTR_ERR(qproc->rmb_base);
+       }
 
+       halt_np = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0);
+       if (!halt_np) {
+               dev_err(&pdev->dev, "no qcom,halt-regs node\n");
+               return -ENODEV;
+       }
 
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_modem");
-               qproc->halt_modem = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(qproc->halt_modem))
-                       return PTR_ERR(qproc->halt_modem);
+       qproc->halt_map = syscon_node_to_regmap(halt_np);
+       if (IS_ERR(qproc->halt_map))
+               return PTR_ERR(qproc->halt_map);
 
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_nc");
-               qproc->halt_nc = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(qproc->halt_nc))
-                       return PTR_ERR(qproc->halt_nc);
-#endif
+       ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
+                                        1, &qproc->halt_q6);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no q6 halt offset\n");
+               return -EINVAL;
+       }
 
+       ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
+                                        2, &qproc->halt_modem);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no modem halt offset\n");
+               return -EINVAL;
        }
-//Only required if self auth is set???
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
-       qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(qproc->rmb_base))
-               return PTR_ERR(qproc->rmb_base);
 
-//     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg_sec");
-//     qproc->restart_sec_base = devm_ioremap_resource(&pdev->dev, res);
-//     if (IS_ERR(qproc->restart_sec_base))
-//             return PTR_ERR(qproc->restart_sec_base);
+       ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
+                                        3, &qproc->halt_nc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no nc halt offset\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
 
-static int qproc_init_clocks(struct qproc *qproc)
+static int q6v5_init_clocks(struct q6v5 *qproc)
 {
        qproc->ahb_clk = devm_clk_get(qproc->dev, "iface");
-       if (IS_ERR(qproc->ahb_clk))
+       if (IS_ERR(qproc->ahb_clk)) {
+               dev_err(qproc->dev, "failed to get iface clock\n");
                return PTR_ERR(qproc->ahb_clk);
+       }
 
        qproc->axi_clk = devm_clk_get(qproc->dev, "bus");
-       if (IS_ERR(qproc->axi_clk))
+       if (IS_ERR(qproc->axi_clk)) {
+               dev_err(qproc->dev, "failed to get bus clock\n");
                return PTR_ERR(qproc->axi_clk);
+       }
 
        qproc->rom_clk = devm_clk_get(qproc->dev, "mem");
-       if (IS_ERR(qproc->rom_clk))
+       if (IS_ERR(qproc->rom_clk)) {
+               dev_err(qproc->dev, "failed to get mem clock\n");
                return PTR_ERR(qproc->rom_clk);
+       }
 
        return 0;
 }
 
-static int qproc_init_regulators(struct qproc *qproc)
-{
-       int ret;
-       u32 uV;
-
-       printk("DEBUG:pil: starting vdd\n");
-//     qproc->vdd = devm_regulator_get_optional(qproc->dev, "qcom,vdd");
-//     if (IS_ERR(qproc->vdd))
-//             return PTR_ERR(qproc->vdd);
-
-//     regulator_set_voltage(qproc->vdd, VDD_MSS_UV, VDD_MSS_UV_MAX);
-//     regulator_set_load(qproc->vdd, VDD_MSS_UA);
-
-       printk("DEBUG:pil: done vdd\n");
-//     qproc->cx = devm_regulator_get(qproc->dev, "qcom,cx");
-//     if (IS_ERR(qproc->cx))
-//             return PTR_ERR(qproc->cx);
-
-       qproc->mx = devm_regulator_get(qproc->dev, "qcom,mx");
-       if (IS_ERR(qproc->mx))
-               return PTR_ERR(qproc->mx);
-
-       ret = of_property_read_u32(qproc->dev->of_node, "qcom,mx-uV", &uV);
-       if (!ret)
-               regulator_set_voltage(qproc->mx, uV, uV);
-
-       qproc->pll = devm_regulator_get(qproc->dev, "qcom,pll");
-       if (IS_ERR(qproc->pll))
-               return PTR_ERR(qproc->pll);
-
-       ret = of_property_read_u32(qproc->dev->of_node, "qcom,pll-uV", &uV);
-       if (!ret)
-               regulator_set_voltage(qproc->pll, uV, uV);
-
-       return 0;
-}
-
-static int qproc_init_reset(struct qproc *qproc)
+static int q6v5_init_reset(struct q6v5 *qproc)
 {
-       //FIXME 
        qproc->mss_restart = devm_reset_control_get(qproc->dev, NULL);
        if (IS_ERR(qproc->mss_restart)) {
                dev_err(qproc->dev, "failed to acquire mss restart\n");
@@ -1165,7 +747,7 @@ static int qproc_init_reset(struct qproc *qproc)
        return 0;
 }
 
-static int qproc_request_irq(struct qproc *qproc,
+static int q6v5_request_irq(struct q6v5 *qproc,
                             struct platform_device *pdev,
                             const char *name,
                             irq_handler_t thread_fn)
@@ -1181,150 +763,153 @@ static int qproc_request_irq(struct qproc *qproc,
        ret = devm_request_threaded_irq(&pdev->dev, ret,
                                        NULL, thread_fn,
                                        IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                       "qproc", qproc);
+                                       "q6v5", qproc);
        if (ret)
                dev_err(&pdev->dev, "request %s IRQ failed\n", name);
        return ret;
 }
 
-static int qproc_probe(struct platform_device *pdev)
+static int q6v5_alloc_memory_region(struct q6v5 *qproc)
+{
+       struct device_node *child;
+       struct device_node *node;
+       struct resource r;
+       int ret;
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mba");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mba region\n");
+               return ret;
+       }
+
+       qproc->mba_phys = r.start;
+       qproc->mba_size = resource_size(&r);
+       qproc->mba_region = devm_ioremap_wc(qproc->dev, qproc->mba_phys, qproc->mba_size);
+       if (!qproc->mba_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mba_size);
+               return -EBUSY;
+       }
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mpss");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mpss region\n");
+               return ret;
+       }
+
+       qproc->mpss_phys = qproc->mpss_reloc = r.start;
+       qproc->mpss_size = resource_size(&r);
+       qproc->mpss_region = devm_ioremap_wc(qproc->dev, qproc->mpss_phys, qproc->mpss_size);
+       if (!qproc->mpss_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mpss_size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int q6v5_probe(struct platform_device *pdev)
 {
-       struct qproc *qproc;
+       struct q6v5 *qproc;
        struct rproc *rproc;
        int ret;
-       int i;
-       struct device_node *np;
-       struct resource r;
 
-       rproc = rproc_alloc(&pdev->dev, pdev->name, &qproc_ops,
-                           "mba.mbn", sizeof(*qproc));
-       if (!rproc)
+       rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
+                           MBA_FIRMWARE_NAME, sizeof(*qproc));
+       if (!rproc) {
+               dev_err(&pdev->dev, "failed to allocate rproc\n");
                return -ENOMEM;
+       }
 
-       rproc->fw_ops = &qproc_fw_ops;
+       rproc->fw_ops = &q6v5_fw_ops;
 
-       qproc = (struct qproc *)rproc->priv;
+       qproc = (struct q6v5 *)rproc->priv;
        qproc->dev = &pdev->dev;
        qproc->rproc = rproc;
        platform_set_drvdata(pdev, qproc);
 
        init_completion(&qproc->start_done);
+       init_completion(&qproc->stop_done);
 
-       ret = qproc_init_mem(qproc, pdev);
+       ret = q6v5_init_mem(qproc, pdev);
        if (ret)
                goto free_rproc;
 
-       ret = qproc_init_clocks(qproc);
+       ret = q6v5_alloc_memory_region(qproc);
        if (ret)
                goto free_rproc;
 
-       ret = qproc_init_regulators(qproc);
+       ret = q6v5_init_clocks(qproc);
        if (ret)
                goto free_rproc;
 
-       //FIXME need to convert this to a proper reset... 
-//     ret = qproc_init_reset(qproc);
-//     if (ret)
-//             goto free_rproc;
+       ret = q6v5_regulator_init(qproc);
+       if (ret)
+               goto free_rproc;
 
-       ret = qproc_request_irq(qproc, pdev, "wdog", qproc_wdog_interrupt);
-       if (ret < 0)
+       ret = q6v5_init_reset(qproc);
+       if (ret)
                goto free_rproc;
-       qproc->wdog_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "fatal", qproc_fatal_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->fatal_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "ready", qproc_ready_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->ready_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "handover", qproc_handover_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->handover_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "stop-ack", qproc_stop_ack_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->stop_ack_irq = ret;
-
-       qproc->stop_gpio = devm_gpiod_get(&pdev->dev, "qcom,stop", GPIOD_OUT_LOW);
-       if (IS_ERR(qproc->stop_gpio)) {
-               dev_err(&pdev->dev, "failed to acquire stop gpio\n");
-               return PTR_ERR(qproc->stop_gpio);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(qproc_attrs); i++) {
-               ret = device_create_file(&pdev->dev, &qproc_attrs[i]);
-               if (ret) {
-                       dev_err(&pdev->dev, "unable to create sysfs file\n");
-                       goto remove_device_files;
-               }
-       }
-
-       np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
-       if (!np) {
-               dev_err(&pdev->dev, "No memory region specified\n");
-       } else {
-
-               ret = of_address_to_resource(np, 0, &r);
-               of_node_put(np);
-               if (ret)
-                       return ret;
-
-               qproc->reloc_phys = r.start;
-               qproc->reloc_size = resource_size(&r);
-
-               dev_info(&pdev->dev, "Found relocation area %lu@%pad\n",
-                               qproc->reloc_size, &qproc->reloc_phys);
-       }
 
+       qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit);
+       if (IS_ERR(qproc->state))
+               goto free_rproc;
 
        ret = rproc_add(rproc);
        if (ret)
-               goto remove_device_files;
+               goto free_rproc;
 
        return 0;
 
-remove_device_files:
-       for (i--; i >= 0; i--)
-               device_remove_file(&pdev->dev, &qproc_attrs[i]);
-
 free_rproc:
        rproc_put(rproc);
 
        return ret;
 }
 
-static int qproc_remove(struct platform_device *pdev)
+static int q6v5_remove(struct platform_device *pdev)
 {
-       struct qproc *qproc = platform_get_drvdata(pdev);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(qproc_attrs); i++)
-               device_remove_file(&pdev->dev, &qproc_attrs[i]);
+       struct q6v5 *qproc = platform_get_drvdata(pdev);
 
+       rproc_del(qproc->rproc);
        rproc_put(qproc->rproc);
 
        return 0;
 }
 
-static const struct of_device_id qproc_of_match[] = {
+static const struct of_device_id q6v5_of_match[] = {
        { .compatible = "qcom,q6v5-pil", },
        { },
 };
 
-static struct platform_driver qproc_driver = {
-       .probe = qproc_probe,
-       .remove = qproc_remove,
+static struct platform_driver q6v5_driver = {
+       .probe = q6v5_probe,
+       .remove = q6v5_remove,
        .driver = {
                .name = "qcom-q6v5-pil",
-               .of_match_table = qproc_of_match,
+               .of_match_table = q6v5_of_match,
        },
 };
 
-module_platform_driver(qproc_driver);
+module_platform_driver(q6v5_driver);
index ae361fc26dd10ca3530e91f2aea9fcf04a1bdd33..6de08442f57f7089a63b544d4379374239183020 100644 (file)
@@ -276,8 +276,7 @@ static int qproc_load(struct rproc *rproc, const struct firmware *fw)
                        max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
        }
 
-       ret = qcom_scm_pas_init_image(qproc->dev,
-                               qproc->pas_id, fw->data, fw->size);
+       ret = qcom_scm_pas_init_image(qproc->pas_id, fw->data, fw->size);
        if (ret) {
                dev_err(qproc->dev, "Invalid firmware metadata\n");
                return -EINVAL;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
new file mode 100644 (file)
index 0000000..648afdb
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/qcom_scm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/remoteproc.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+
+#include "qcom_mdt_loader.h"
+#include "remoteproc_internal.h"
+#include "qcom_wcnss.h"
+
+#define WCNSS_CRASH_REASON_SMEM                422
+#define WCNSS_FIRMWARE_NAME            "wcnss.mdt"
+#define WCNSS_PAS_ID                   6
+
+#define WCNSS_SPARE_NVBIN_DLND         BIT(25)
+
+#define WCNSS_PMU_IRIS_XO_CFG          BIT(3)
+#define WCNSS_PMU_IRIS_XO_EN           BIT(4)
+#define WCNSS_PMU_GC_BUS_MUX_SEL_TOP   BIT(5)
+#define WCNSS_PMU_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
+
+#define WCNSS_PMU_IRIS_RESET           BIT(7)
+#define WCNSS_PMU_IRIS_RESET_STS       BIT(8) /* 1: in progress, 0: done */
+#define WCNSS_PMU_IRIS_XO_READ         BIT(9)
+#define WCNSS_PMU_IRIS_XO_READ_STS     BIT(10)
+
+#define WCNSS_PMU_XO_MODE_MASK         GENMASK(2, 1)
+#define WCNSS_PMU_XO_MODE_19p2         0
+#define WCNSS_PMU_XO_MODE_48           3
+
+static const struct rproc_ops wcnss_ops;
+
+struct wcnss_data {
+       size_t pmu_offset;
+       size_t spare_offset;
+
+       const struct wcnss_vreg_info *vregs;
+       size_t num_vregs;
+};
+
+struct qcom_wcnss {
+       struct device *dev;
+       struct rproc *rproc;
+
+       void __iomem *pmu_cfg;
+       void __iomem *spare_out;
+
+       bool use_48mhz_xo;
+
+       int wdog_irq;
+       int fatal_irq;
+       int ready_irq;
+       int handover_irq;
+       int stop_ack_irq;
+
+       struct qcom_smem_state *state;
+       unsigned stop_bit;
+
+       struct mutex iris_lock;
+       struct qcom_iris *iris;
+
+       struct regulator_bulk_data *vregs;
+       size_t num_vregs;
+
+       struct completion start_done;
+       struct completion stop_done;
+
+       phys_addr_t mem_phys;
+       phys_addr_t mem_reloc;
+       void *mem_region;
+       size_t mem_size;
+};
+
+static const struct wcnss_data riva_data = {
+       .pmu_offset = 0x28,
+       .spare_offset = 0xb4,
+
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddmx",  1050000, 1150000, 0 },
+               { "vddcx",  1050000, 1150000, 0 },
+               { "vddpx",  1800000, 1800000, 0 },
+       },
+       .num_vregs = 3,
+};
+
+static const struct wcnss_data pronto_v1_data = {
+       .pmu_offset = 0x1004,
+       .spare_offset = 0x1088,
+
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddmx", 950000, 1150000, 0 },
+               { "vddcx", .super_turbo = true},
+               { "vddpx", 1800000, 1800000, 0 },
+       },
+       .num_vregs = 3,
+};
+
+static const struct wcnss_data pronto_v2_data = {
+       .pmu_offset = 0x1004,
+       .spare_offset = 0x1088,
+
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddmx", 1287500, 1287500, 0 },
+               { "vddcx", .super_turbo = true },
+               { "vddpx", 1800000, 1800000, 0 },
+       },
+       .num_vregs = 3,
+};
+
+void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss,
+                           struct qcom_iris *iris,
+                           bool use_48mhz_xo)
+{
+       mutex_lock(&wcnss->iris_lock);
+
+       wcnss->iris = iris;
+       wcnss->use_48mhz_xo = use_48mhz_xo;
+
+       mutex_unlock(&wcnss->iris_lock);
+}
+
+static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       phys_addr_t fw_addr;
+       size_t fw_size;
+       bool relocate;
+       int ret;
+
+       ret = qcom_scm_pas_init_image(WCNSS_PAS_ID, fw->data, fw->size);
+       if (ret) {
+               dev_err(&rproc->dev, "invalid firmware metadata\n");
+               return -EINVAL;
+       }
+
+       ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate);
+       if (ret) {
+               dev_err(&rproc->dev, "failed to parse mdt header\n");
+               return ret;
+       }
+
+       if (relocate) {
+               wcnss->mem_reloc = fw_addr;
+
+               ret = qcom_scm_pas_mem_setup(WCNSS_PAS_ID, wcnss->mem_phys, fw_size);
+               if (ret) {
+                       dev_err(&rproc->dev, "unable to setup memory for image\n");
+                       return -EINVAL;
+               }
+       }
+
+       return qcom_mdt_load(rproc, fw, rproc->firmware);
+}
+
+static const struct rproc_fw_ops wcnss_fw_ops = {
+       .find_rsc_table = qcom_mdt_find_rsc_table,
+       .load = wcnss_load,
+};
+
+static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
+{
+       u32 val;
+
+       /* Indicate NV download capability */
+       val = readl(wcnss->spare_out);
+       val |= WCNSS_SPARE_NVBIN_DLND;
+       writel(val, wcnss->spare_out);
+}
+
+static void wcnss_configure_iris(struct qcom_wcnss *wcnss)
+{
+       u32 val;
+
+       /* Clear PMU cfg register */
+       writel(0, wcnss->pmu_cfg);
+
+       val = WCNSS_PMU_GC_BUS_MUX_SEL_TOP | WCNSS_PMU_IRIS_XO_EN;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Clear XO_MODE */
+       val &= ~WCNSS_PMU_XO_MODE_MASK;
+       if (wcnss->use_48mhz_xo)
+               val |= WCNSS_PMU_XO_MODE_48 << 1;
+       else
+               val |= WCNSS_PMU_XO_MODE_19p2 << 1;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Reset IRIS */
+       val |= WCNSS_PMU_IRIS_RESET;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Wait for PMU.iris_reg_reset_sts */
+       while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_RESET_STS)
+               cpu_relax();
+
+       /* Clear IRIS reset */
+       val &= ~WCNSS_PMU_IRIS_RESET;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Start IRIS XO configuration */
+       val |= WCNSS_PMU_IRIS_XO_CFG;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Wait for XO configuration to finish */
+       while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_XO_CFG_STS)
+               cpu_relax();
+
+       /* Stop IRIS XO configuration */
+       val &= ~WCNSS_PMU_GC_BUS_MUX_SEL_TOP;
+       val &= ~WCNSS_PMU_IRIS_XO_CFG;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Add some delay for XO to settle */
+       msleep(20);
+}
+
+static int wcnss_start(struct rproc *rproc)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       int ret;
+
+       mutex_lock(&wcnss->iris_lock);
+       if (!wcnss->iris) {
+               dev_err(wcnss->dev, "no iris registered\n");
+               ret = -EINVAL;
+               goto release_iris_lock;
+       }
+
+       ret = regulator_bulk_enable(wcnss->num_vregs, wcnss->vregs);
+       if (ret)
+               goto release_iris_lock;
+
+       ret = qcom_iris_enable(wcnss->iris);
+       if (ret)
+               goto disable_regulators;
+
+       wcnss_indicate_nv_download(wcnss);
+       wcnss_configure_iris(wcnss);
+
+       ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
+       if (ret) {
+               dev_err(wcnss->dev,
+                       "failed to authenticate image and release reset\n");
+               goto disable_iris;
+       }
+
+       ret = wait_for_completion_timeout(&wcnss->start_done,
+                                         msecs_to_jiffies(5000));
+       if (wcnss->ready_irq > 0 && ret == 0) {
+               /* We have a ready_irq, but it didn't fire in time. */
+               dev_err(wcnss->dev, "start timed out\n");
+               qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+               ret = -ETIMEDOUT;
+               goto disable_iris;
+       }
+
+       ret = 0;
+
+disable_iris:
+       qcom_iris_disable(wcnss->iris);
+disable_regulators:
+       regulator_bulk_disable(wcnss->num_vregs, wcnss->vregs);
+release_iris_lock:
+       mutex_unlock(&wcnss->iris_lock);
+
+       return ret;
+}
+
+static int wcnss_stop(struct rproc *rproc)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       int ret;
+
+       if (wcnss->state) {
+               qcom_smem_state_update_bits(wcnss->state,
+                                           BIT(wcnss->stop_bit),
+                                           BIT(wcnss->stop_bit));
+
+               ret = wait_for_completion_timeout(&wcnss->stop_done,
+                                                 msecs_to_jiffies(5000));
+               if (ret == 0)
+                       dev_err(wcnss->dev, "timed out on wait\n");
+
+               qcom_smem_state_update_bits(wcnss->state,
+                                           BIT(wcnss->stop_bit),
+                                           0);
+       }
+
+       ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+       if (ret)
+               dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
+
+       return ret;
+}
+
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       int offset;
+
+       offset = da - wcnss->mem_reloc;
+       if (offset < 0 || offset + len > wcnss->mem_size)
+               return NULL;
+
+       return wcnss->mem_region + offset;
+}
+
+static const struct rproc_ops wcnss_ops = {
+       .start = wcnss_start,
+       .stop = wcnss_stop,
+       .da_to_va = wcnss_da_to_va,
+};
+
+static irqreturn_t wcnss_wdog_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+
+       rproc_report_crash(wcnss->rproc, RPROC_WATCHDOG);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+       size_t len;
+       char *msg;
+
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, WCNSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(wcnss->dev, "fatal error received: %s\n", msg);
+
+       rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR);
+
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_ready_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+
+       complete(&wcnss->start_done);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_handover_interrupt(int irq, void *dev)
+{
+       /*
+        * XXX: At this point we're supposed to release the resources that we
+        * have been holding on behalf of the WCNSS. Unfortunately this
+        * interrupt comes way before the other side seems to be done.
+        *
+        * So we're currently relying on the ready interrupt firing later then
+        * this and we just disable the resources at the end of wcnss_start().
+        */
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+
+       complete(&wcnss->stop_done);
+       return IRQ_HANDLED;
+}
+
+static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
+                                const struct wcnss_vreg_info *info,
+                                int num_vregs)
+{
+       struct regulator_bulk_data *bulk;
+       int ret;
+       int i;
+
+       bulk = devm_kcalloc(wcnss->dev,
+                           num_vregs, sizeof(struct regulator_bulk_data),
+                           GFP_KERNEL);
+       if (!bulk)
+               return -ENOMEM;
+
+       for (i = 0; i < num_vregs; i++)
+               bulk[i].supply = info[i].name;
+
+       ret = devm_regulator_bulk_get(wcnss->dev, num_vregs, bulk);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < num_vregs; i++) {
+               if (info[i].max_voltage)
+                       regulator_set_voltage(bulk[i].consumer,
+                                             info[i].min_voltage,
+                                             info[i].max_voltage);
+
+               if (info[i].load_uA)
+                       regulator_set_load(bulk[i].consumer, info[i].load_uA);
+       }
+
+       wcnss->vregs = bulk;
+       wcnss->num_vregs = num_vregs;
+
+       return 0;
+}
+
+static int wcnss_request_irq(struct qcom_wcnss *wcnss,
+                            struct platform_device *pdev,
+                            const char *name,
+                            bool optional,
+                            irq_handler_t thread_fn)
+{
+       int ret;
+
+       ret = platform_get_irq_byname(pdev, name);
+       if (ret < 0 && optional) {
+               dev_dbg(&pdev->dev, "no %s IRQ defined, ignoring\n", name);
+               return 0;
+       } else if (ret < 0) {
+               dev_err(&pdev->dev, "no %s IRQ defined\n", name);
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, ret,
+                                       NULL, thread_fn,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       "wcnss", wcnss);
+       if (ret)
+               dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+       return ret;
+}
+
+static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
+{
+       struct device_node *node;
+       struct resource r;
+       int ret;
+
+       node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0);
+       if (!node) {
+               dev_err(wcnss->dev, "no memory-region specified\n");
+               return -EINVAL;
+       }
+
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret)
+               return ret;
+
+       wcnss->mem_phys = wcnss->mem_reloc = r.start;
+       wcnss->mem_size = resource_size(&r);
+       wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
+       if (!wcnss->mem_region) {
+               dev_err(wcnss->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, wcnss->mem_size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int wcnss_probe(struct platform_device *pdev)
+{
+       const struct wcnss_data *data;
+       struct qcom_wcnss *wcnss;
+       struct resource *res;
+       struct rproc *rproc;
+       void __iomem *mmio;
+       int ret;
+
+       data = of_device_get_match_data(&pdev->dev);
+
+       if (!qcom_scm_is_available())
+               return -EPROBE_DEFER;
+
+       if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
+               dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
+               return -ENXIO;
+       }
+
+       rproc = rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops,
+                           WCNSS_FIRMWARE_NAME, sizeof(*wcnss));
+       if (!rproc) {
+               dev_err(&pdev->dev, "unable to allocate remoteproc\n");
+               return -ENOMEM;
+       }
+
+       rproc->fw_ops = &wcnss_fw_ops;
+
+       wcnss = (struct qcom_wcnss *)rproc->priv;
+       wcnss->dev = &pdev->dev;
+       wcnss->rproc = rproc;
+       platform_set_drvdata(pdev, wcnss);
+
+       init_completion(&wcnss->start_done);
+       init_completion(&wcnss->stop_done);
+
+       mutex_init(&wcnss->iris_lock);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu");
+       mmio = devm_ioremap_resource(&pdev->dev, res);
+       if (!mmio) {
+               ret = -ENOMEM;
+               goto free_rproc;
+       };
+
+       ret = wcnss_alloc_memory_region(wcnss);
+       if (ret)
+               goto free_rproc;
+
+       wcnss->pmu_cfg = mmio + data->pmu_offset;
+       wcnss->spare_out = mmio + data->spare_offset;
+
+       ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs);
+       if (ret)
+               goto free_rproc;
+
+       ret = wcnss_request_irq(wcnss, pdev, "wdog", false, wcnss_wdog_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->wdog_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "fatal", false, wcnss_fatal_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->fatal_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "ready", true, wcnss_ready_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->ready_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "handover", true, wcnss_handover_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->handover_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "stop-ack", true, wcnss_stop_ack_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->stop_ack_irq = ret;
+
+       if (wcnss->stop_ack_irq) {
+               wcnss->state = qcom_smem_state_get(&pdev->dev, "stop",
+                                                  &wcnss->stop_bit);
+               if (IS_ERR(wcnss->state)) {
+                       ret = PTR_ERR(wcnss->state);
+                       goto free_rproc;
+               }
+       }
+
+       ret = rproc_add(rproc);
+       if (ret)
+               goto free_rproc;
+
+       return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+free_rproc:
+       rproc_put(rproc);
+
+       return ret;
+}
+
+static int wcnss_remove(struct platform_device *pdev)
+{
+       struct qcom_wcnss *wcnss = platform_get_drvdata(pdev);
+
+       of_platform_depopulate(&pdev->dev);
+
+       qcom_smem_state_put(wcnss->state);
+       rproc_del(wcnss->rproc);
+       rproc_put(wcnss->rproc);
+
+       return 0;
+}
+
+static const struct of_device_id wcnss_of_match[] = {
+       { .compatible = "qcom,riva-pil", &riva_data },
+       { .compatible = "qcom,pronto-v1-pil", &pronto_v1_data },
+       { .compatible = "qcom,pronto-v2-pil", &pronto_v2_data },
+       { },
+};
+
+static struct platform_driver wcnss_driver = {
+       .probe = wcnss_probe,
+       .remove = wcnss_remove,
+       .driver = {
+               .name = "qcom-wcnss-pil",
+               .of_match_table = wcnss_of_match,
+       },
+};
+
+module_platform_driver(wcnss_driver);
diff --git a/drivers/remoteproc/qcom_wcnss.h b/drivers/remoteproc/qcom_wcnss.h
new file mode 100644 (file)
index 0000000..9dc4a9f
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __QCOM_WNCSS_H__
+#define __QCOM_WNCSS_H__
+
+struct qcom_iris;
+struct qcom_wcnss;
+
+struct wcnss_vreg_info {
+       const char * const name;
+       int min_voltage;
+       int max_voltage;
+
+       int load_uA;
+
+       bool super_turbo;
+};
+
+int qcom_iris_enable(struct qcom_iris *iris);
+void qcom_iris_disable(struct qcom_iris *iris);
+
+void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss, struct qcom_iris *iris, bool use_48mhz_xo);
+
+#endif
diff --git a/drivers/remoteproc/qcom_wcnss_iris.c b/drivers/remoteproc/qcom_wcnss_iris.c
new file mode 100644 (file)
index 0000000..62a3758
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/qcom_scm.h>
+#include <linux/regulator/consumer.h>
+
+#include "qcom_wcnss.h"
+
+struct qcom_iris {
+       struct device *dev;
+
+       struct clk *xo_clk;
+
+       struct regulator_bulk_data *vregs;
+       size_t num_vregs;
+};
+
+struct iris_data {
+       const struct wcnss_vreg_info *vregs;
+       size_t num_vregs;
+
+       bool use_48mhz_xo;
+};
+
+static const struct iris_data wcn3620_data = {
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddxo",  1800000, 1800000, 10000 },
+               { "vddrfa", 1300000, 1300000, 100000 },
+               { "vddpa",  3300000, 3300000, 515000 },
+               { "vdddig", 1800000, 1800000, 10000 },
+       },
+       .num_vregs = 4,
+       .use_48mhz_xo = false,
+};
+
+static const struct iris_data wcn3660_data = {
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddxo",  1800000, 1800000, 10000 },
+               { "vddrfa", 1300000, 1300000, 100000 },
+               { "vddpa",  2900000, 3000000, 515000 },
+               { "vdddig", 1200000, 1225000, 10000 },
+       },
+       .num_vregs = 4,
+       .use_48mhz_xo = true,
+};
+
+static const struct iris_data wcn3680_data = {
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddxo",  1800000, 1800000, 10000 },
+               { "vddrfa", 1300000, 1300000, 100000 },
+               { "vddpa",  3300000, 3300000, 515000 },
+               { "vdddig", 1800000, 1800000, 10000 },
+       },
+       .num_vregs = 4,
+       .use_48mhz_xo = true,
+};
+
+int qcom_iris_enable(struct qcom_iris *iris)
+{
+       int ret;
+
+       ret = regulator_bulk_enable(iris->num_vregs, iris->vregs);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(iris->xo_clk);
+       if (ret) {
+               dev_err(iris->dev, "failed to enable xo clk\n");
+               goto disable_regulators;
+       }
+
+       return 0;
+
+disable_regulators:
+       regulator_bulk_disable(iris->num_vregs, iris->vregs);
+
+       return ret;
+}
+
+void qcom_iris_disable(struct qcom_iris *iris)
+{
+       clk_disable_unprepare(iris->xo_clk);
+       regulator_bulk_disable(iris->num_vregs, iris->vregs);
+}
+
+static int qcom_iris_probe(struct platform_device *pdev)
+{
+       const struct iris_data *data;
+       struct qcom_wcnss *wcnss;
+       struct qcom_iris *iris;
+       int ret;
+       int i;
+
+       iris = devm_kzalloc(&pdev->dev, sizeof(struct qcom_iris), GFP_KERNEL);
+       if (!iris)
+               return -ENOMEM;
+
+       data = of_device_get_match_data(&pdev->dev);
+       wcnss = dev_get_drvdata(pdev->dev.parent);
+
+       iris->xo_clk = devm_clk_get(&pdev->dev, "xo");
+       if (IS_ERR(iris->xo_clk)) {
+               if (PTR_ERR(iris->xo_clk) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to acquire xo clk\n");
+               return PTR_ERR(iris->xo_clk);
+       }
+
+       iris->num_vregs = data->num_vregs;
+       iris->vregs = devm_kcalloc(&pdev->dev,
+                                  iris->num_vregs,
+                                  sizeof(struct regulator_bulk_data),
+                                  GFP_KERNEL);
+       if (!iris->vregs)
+               return -ENOMEM;
+
+       for (i = 0; i < iris->num_vregs; i++)
+               iris->vregs[i].supply = data->vregs[i].name;
+
+       ret = devm_regulator_bulk_get(&pdev->dev, iris->num_vregs, iris->vregs);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to get regulators\n");
+               return ret;
+       }
+
+       for (i = 0; i < iris->num_vregs; i++) {
+               if (data->vregs[i].max_voltage)
+                       regulator_set_voltage(iris->vregs[i].consumer,
+                                             data->vregs[i].min_voltage,
+                                             data->vregs[i].max_voltage);
+
+               if (data->vregs[i].load_uA)
+                       regulator_set_load(iris->vregs[i].consumer,
+                                          data->vregs[i].load_uA);
+       }
+
+       qcom_wcnss_assign_iris(wcnss, iris, data->use_48mhz_xo);
+
+       return 0;
+}
+
+static int qcom_iris_remove(struct platform_device *pdev)
+{
+       struct qcom_wcnss *wcnss = dev_get_drvdata(pdev->dev.parent);
+
+       qcom_wcnss_assign_iris(wcnss, NULL, false);
+
+       return 0;
+}
+
+static const struct of_device_id iris_of_match[] = {
+       { .compatible = "qcom,wcn3620", .data = &wcn3620_data },
+       { .compatible = "qcom,wcn3660", .data = &wcn3660_data },
+       { .compatible = "qcom,wcn3680", .data = &wcn3680_data },
+       {}
+};
+
+static struct platform_driver wcnss_driver = {
+       .probe = qcom_iris_probe,
+       .remove = qcom_iris_remove,
+       .driver = {
+               .name = "qcom-iris",
+               .of_match_table = iris_of_match,
+       },
+};
+
+module_platform_driver(wcnss_driver);
index 916af5096f57b93b7f7e148d28716329b31c7be6..9ef9f47b28e2e6354c2183a073f4a6cdc25b4ce6 100644 (file)
@@ -88,8 +88,42 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
        return simple_read_from_buffer(userbuf, count, ppos, buf, i);
 }
 
+static ssize_t rproc_state_write(struct file *filp, const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct rproc *rproc = filp->private_data;
+       char buf[10];
+       int ret;
+
+       if (count > sizeof(buf) || count <= 0)
+               return -EINVAL;
+
+       ret = copy_from_user(buf, userbuf, count);
+       if (ret)
+               return -EFAULT;
+
+       if (buf[count - 1] == '\n')
+               buf[count - 1] = '\0';
+
+       if (!strncmp(buf, "start", count)) {
+               ret = rproc_boot(rproc);
+               if (ret) {
+                       dev_err(&rproc->dev, "Boot failed: %d\n", ret);
+                       return ret;
+               }
+       } else if (!strncmp(buf, "stop", count)) {
+               rproc_shutdown(rproc);
+       } else {
+               dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
+               return -EINVAL;
+       }
+
+       return count;
+}
+
 static const struct file_operations rproc_state_ops = {
        .read = rproc_state_read,
+       .write = rproc_state_write,
        .open = simple_open,
        .llseek = generic_file_llseek,
 };
index 9f244d633f3b7d474794e9ead629908ec8a0d1b9..35fa84660dee638936921656a428e23d52c9274c 100644 (file)
@@ -83,6 +83,15 @@ config QCOM_WCNSS_CTRL
 config MSM_BUS_SCALING
        bool "Bus scaling driver"
        default n
+
+config QTI_LNX_GPS_PROXY
+       tristate "User mode QTI_LNX_GPS_PROXY device driver support"
+       help
+         This supports user mode QTI_LNX_GPS_PROXY
+
+         Note that this application programming interface is EXPERIMENTAL
+         and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
+
        help
                This option enables bus scaling on MSM devices.  Bus scaling
                allows devices to request the clocks be set to rates sufficient
@@ -108,8 +117,3 @@ config BUS_TOPOLOGY_ADHOC
                directionality of connections by explicitly listing device connections
                thus avoiding illegal routes.
 
-config QCOM_IPCRTR_STUB
-       tristate "Qualcomm IPCRTR stub driver"
-       depends on QCOM_SMD
-       help
-         Stub driver to bring the IPCRTR channel up.
index 49e0f7c3aeda0348b00978692e9bacd112b05da6..56da0a585cfd5d6c39c609d3f2bbf11f4a17ba61 100644 (file)
@@ -12,4 +12,4 @@ obj-$(CONFIG_MFD_QCOM_SMD_RPM) += rpm_log.o
 
 obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
 obj-$(CONFIG_BUS_TOPOLOGY_ADHOC) += msm_bus/
-obj-$(CONFIG_QCOM_IPCRTR_STUB) += ipcrtr_stub.o
+obj-$(CONFIG_QTI_LNX_GPS_PROXY) += gps_proxy.o
diff --git a/drivers/soc/qcom/gps_proxy.c b/drivers/soc/qcom/gps_proxy.c
new file mode 100644 (file)
index 0000000..6812962
--- /dev/null
@@ -0,0 +1,304 @@
+/* Copyright (c) 2016, 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/fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <asm/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <uapi/linux/gps_proxy.h>
+
+/* Module information */
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL v2");
+
+#define LOC_SERVICE_SVC_ID     0x00000010
+#define LOC_SERVICE_V1                 2
+#define LOC_SERVICE_INS_ID     0
+
+#define DRIVER_VERSION                 "v1.0"
+#define DRIVER_DESC            "GPS TTY driver"
+#define MODULE_NAME            "gps_proxy"
+#define TTY_DRIVER_NAME        "gps_serial"
+#define TTY_DEV_NAME           "ttyGPS"
+#define MAX_TTY_BUFFER_SZ      0x10000
+#define GPS_TTY_MAJOR          100     /* experimental range */
+#define DEVICE_NAME            "gps_proxy_ch"
+#define CLASS_NAME             "gps_proxy_class"
+
+static struct tty_driver *gps_proxy_tty_driver;
+static struct tty_port gps_proxy_tty_port;
+static bool g_port_open = false;
+static struct semaphore g_port_sem;
+static int gps_proxy_ch_driver_major = 0;
+static struct class* gps_proxy_ch_class = 0;
+static struct device* gps_proxy_ch_dev = 0;
+
+static void serial_port_shutdown(struct tty_port *tport)
+{
+}
+
+static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)
+{
+       return 0;
+}
+
+static struct tty_port_operations serial_port_ops = {
+       .activate = serial_port_activate,
+       .shutdown = serial_port_shutdown
+};
+
+static int gps_proxy_open(struct tty_struct *tty, struct file *file)
+{
+       int rc; 
+       rc = tty_port_open(&gps_proxy_tty_port, tty, file);
+       g_port_open = true;
+       up(&g_port_sem);
+       return rc;
+}
+
+static void gps_proxy_close(struct tty_struct *tty, struct file *file)
+{
+       tty_port_close(tty->port, tty, file);
+       g_port_open = false;
+       down(&g_port_sem);
+}
+
+static void gps_proxy_tty_hangup(struct tty_struct *tty)
+{
+       tty_port_hangup(tty->port);
+}
+
+static int gps_proxy_write(struct tty_struct *tty, 
+                     const unsigned char *buffer, int count)
+{
+       return count;
+}
+
+static int gps_proxy_write_room(struct tty_struct *tty) 
+{
+       return MAX_TTY_BUFFER_SZ;
+}
+
+static int gps_proxy_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+
+static int gps_proxy_tiocmget(struct tty_struct *tty)
+{
+       return 0;
+}
+
+static int gps_proxy_tiocmset(struct tty_struct *tty,
+                         unsigned int set, unsigned int clear)
+{
+       return 0;
+}
+
+static int gps_proxy_ioctl(struct tty_struct *tty,
+                      unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static struct tty_operations serial_ops = {
+       .open = gps_proxy_open,
+       .close = gps_proxy_close,
+       .hangup = gps_proxy_tty_hangup,
+       .write = gps_proxy_write,
+       .write_room = gps_proxy_write_room,
+       .chars_in_buffer = gps_proxy_tty_chars_in_buffer,
+       .tiocmget = gps_proxy_tiocmget,
+       .tiocmset = gps_proxy_tiocmset,
+       .ioctl = gps_proxy_ioctl,
+};
+
+int gps_proxy_ch_driver_open(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+int gps_proxy_ch_driver_close(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+long gps_proxy_chdev_ioctl(struct file *filp, unsigned int opt, unsigned long arg)
+{
+       int rc = 0;
+       struct gps_proxy_data buff;
+       switch (opt)
+       {
+               case QGPS_REGISTER_HANDLE:
+                       /* DOWN is necessary to make client wait till port is open */
+                       down(&g_port_sem);
+                       /* UP to semaphore is necessary here for close or
+                       next register handle (for parity) */
+                       up(&g_port_sem);
+                       rc = 0;
+                       break;
+               case QGPS_SEND_NMEA:
+                       pr_debug(KERN_INFO "Received string: %s\n", 
+                               ((struct gps_proxy_data*)arg)->nmea_string);
+                       rc = access_ok(struct gps_proxy_data, (struct gps_proxy_data*)arg,
+                                       sizeof(struct gps_proxy_data));
+                       if (!rc) {
+                               pr_err(KERN_ERR "Invalid argument was received\n");
+                               return rc;
+                       }
+                       rc = copy_from_user((void*)&buff, (void*)arg, sizeof(buff));
+                       if (rc) {
+                               pr_err(KERN_ERR "Number of bytes that \
+                                                couldn't be copied: %d", rc);
+                               return -EFAULT;
+                       }
+                       if (buff.nmea_length < QMI_LOC_NMEA_STRING_MAX_LENGTH_V02 + 1) {
+                               pr_debug(KERN_INFO "Received string: %s\n",
+                                       buff.nmea_string);
+                               rc = tty_insert_flip_string(&gps_proxy_tty_port, 
+                                               buff.nmea_string,
+                                               strnlen(buff.nmea_string,
+                                               QMI_LOC_NMEA_STRING_MAX_LENGTH_V02) + 1);
+                               if (rc < 0) {
+                                       pr_err(KERN_ERR "Error flipping string");
+                                       return rc;
+                               }
+                               tty_flip_buffer_push(&gps_proxy_tty_port);
+                       }
+                       else {
+                               pr_err(KERN_ERR "Illegal message size");
+                               rc = -EFAULT;
+                       }
+                       break;
+               case QGPS_IS_ACTIVE:
+                       if (g_port_open)
+                               rc = 0;
+                       else
+                               rc = -EFAULT;
+                       break;
+               default:
+                       rc = -EFAULT;
+                       break;
+       }
+       return rc;
+}
+
+struct file_operations gps_proxy_ch_driver_ops = {
+       open: gps_proxy_ch_driver_open,
+       unlocked_ioctl: gps_proxy_chdev_ioctl,
+       release: gps_proxy_ch_driver_close
+};
+
+static int __init gps_proxy_init(void)
+{
+       int rc;
+       struct device *ttydev;
+
+       sema_init(&g_port_sem,0);
+
+       gps_proxy_ch_driver_major = register_chrdev(0, "gps_proxy_ch_dev",
+                                                       &gps_proxy_ch_driver_ops);
+       if (gps_proxy_ch_driver_major < 0) {
+               pr_err(KERN_ERR "Failed to register char device\n");
+               return -EFAULT;
+       }
+       else {
+               pr_debug(KERN_INFO "char device registered with major %d\n",
+                       gps_proxy_ch_driver_major);
+       }
+
+       /* Register the device class */
+       gps_proxy_ch_class = class_create(THIS_MODULE, CLASS_NAME);
+       if (IS_ERR(gps_proxy_ch_class)){
+               unregister_chrdev(gps_proxy_ch_driver_major, DEVICE_NAME);
+               pr_debug(KERN_ALERT "Failed to register device class\n");
+               return -EFAULT;
+       }
+       pr_debug(KERN_INFO "EBBChar: device class registered correctly\n");
+
+       /* Register the device driver */
+       gps_proxy_ch_dev = device_create(gps_proxy_ch_class, NULL,
+                               MKDEV(gps_proxy_ch_driver_major, 0), NULL, DEVICE_NAME);
+       if (IS_ERR(gps_proxy_ch_dev)){
+               class_destroy(gps_proxy_ch_class);
+               unregister_chrdev(gps_proxy_ch_driver_major, DEVICE_NAME);
+               pr_debug(KERN_ALERT "Failed to create the device\n");
+               return -EFAULT;
+       }
+
+       /* allocate the tty driver */
+       gps_proxy_tty_driver = alloc_tty_driver(1);
+       if (!gps_proxy_tty_driver)
+               return -ENOMEM;
+
+       tty_port_init(&gps_proxy_tty_port);
+       gps_proxy_tty_port.ops = &serial_port_ops;
+
+       /* initialize the tty driver */
+       gps_proxy_tty_driver->driver_name = TTY_DRIVER_NAME;
+       gps_proxy_tty_driver->name = TTY_DEV_NAME;
+       gps_proxy_tty_driver->major = GPS_TTY_MAJOR;
+       gps_proxy_tty_driver->minor_start = 0;
+       gps_proxy_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       gps_proxy_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gps_proxy_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       gps_proxy_tty_driver->init_termios = tty_std_termios;
+
+       tty_set_operations(gps_proxy_tty_driver, &serial_ops);
+       /* register the tty driver */
+       rc = tty_register_driver(gps_proxy_tty_driver);
+       if (rc) {
+               pr_err("Failed to register gps_proxy tty driver\n");
+               put_tty_driver(gps_proxy_tty_driver);
+               return rc;
+       }
+
+       ttydev = tty_port_register_device(&gps_proxy_tty_port, gps_proxy_tty_driver, 0, 0);
+       if (IS_ERR(ttydev)) {
+               rc = PTR_ERR(ttydev);
+               pr_err("Failed to register gps_proxy tty proxy\n");
+               return rc;
+       }
+
+       pr_debug(KERN_INFO DRIVER_DESC " \n" DRIVER_VERSION);
+       return rc;
+}
+
+static void __exit gps_proxy_exit(void)
+{
+       tty_unregister_device(gps_proxy_tty_driver, 0);
+       tty_unregister_driver(gps_proxy_tty_driver);
+       unregister_chrdev(gps_proxy_ch_driver_major, "gps_proxy_ch_dev");
+       device_destroy(gps_proxy_ch_class, MKDEV(gps_proxy_ch_driver_major, 0));
+       class_unregister(gps_proxy_ch_class);
+       class_destroy(gps_proxy_ch_class);
+}
+
+late_initcall(gps_proxy_init);
+module_exit(gps_proxy_exit);
diff --git a/drivers/soc/qcom/ipcrtr_stub.c b/drivers/soc/qcom/ipcrtr_stub.c
deleted file mode 100644 (file)
index 6f8d724..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014, Sony Mobile Communications AB.
- *
- * 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/module.h>
-#include <linux/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <linux/soc/qcom/smd.h>
-
-static int ipcrtr_stub_callback(struct qcom_smd_device *qsdev,
-                               const void *data,
-                                size_t count)
-{
-       print_hex_dump(KERN_DEBUG, "IPCRTR <<<: ", DUMP_PREFIX_OFFSET, 16, 1, data, count, true);
-
-       return 0;
-}
-
-static int ipcrtr_stub_probe(struct qcom_smd_device *sdev)
-{
-       dev_err(&sdev->dev, "ipcrtr initialized\n");
-
-       return 0;
-}
-
-static const struct of_device_id ipcrtr_stub_of_match[] = {
-       { .compatible = "qcom,ipcrtr" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, ipcrtr_stub_of_match);
-
-static struct qcom_smd_driver ipcrtr_stub_driver = {
-       .probe = ipcrtr_stub_probe,
-       .callback = ipcrtr_stub_callback,
-       .driver  = {
-               .name  = "ipcrtr_stub",
-               .owner = THIS_MODULE,
-               .of_match_table = ipcrtr_stub_of_match,
-       },
-};
-
-module_qcom_smd_driver(ipcrtr_stub_driver);
-
-MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
-MODULE_DESCRIPTION("Qualcomm IPCRTR stub driver");
-MODULE_LICENSE("GPLv2");
-
index af3152c733998935bbda347def7b204ecff2772a..abb32001ff3a82dd444b2d0ec156235fdd58eeac 100644 (file)
@@ -33,6 +33,7 @@
  */
 struct qcom_smd_rpm {
        struct qcom_smd_channel *rpm_channel;
+       struct device *dev;
 
        struct completion ack;
        struct mutex lock;
@@ -149,14 +150,14 @@ out:
 }
 EXPORT_SYMBOL(qcom_rpm_smd_write);
 
-static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
+static int qcom_smd_rpm_callback(struct qcom_smd_channel *channel,
                                 const void *data,
                                 size_t count)
 {
        const struct qcom_rpm_header *hdr = data;
        size_t hdr_length = le32_to_cpu(hdr->length);
        const struct qcom_rpm_message *msg;
-       struct qcom_smd_rpm *rpm = dev_get_drvdata(&qsdev->dev);
+       struct qcom_smd_rpm *rpm = qcom_smd_get_drvdata(channel);
        const u8 *buf = data + sizeof(struct qcom_rpm_header);
        const u8 *end = buf + hdr_length;
        char msgbuf[32];
@@ -165,7 +166,7 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
 
        if (le32_to_cpu(hdr->service_type) != RPM_SERVICE_TYPE_REQUEST ||
            hdr_length < sizeof(struct qcom_rpm_message)) {
-               dev_err(&qsdev->dev, "invalid request\n");
+               dev_err(rpm->dev, "invalid request\n");
                return 0;
        }
 
@@ -206,7 +207,9 @@ static int qcom_smd_rpm_probe(struct qcom_smd_device *sdev)
        mutex_init(&rpm->lock);
        init_completion(&rpm->ack);
 
+       rpm->dev = &sdev->dev;
        rpm->rpm_channel = sdev->channel;
+       qcom_smd_set_drvdata(sdev->channel, rpm);
 
        dev_set_drvdata(&sdev->dev, rpm);
 
index 1ef645a785404bf5d1829816b7ac03dd66865c2b..0b08b9dc8005840932243352655930f8992e1c5c 100644 (file)
@@ -123,7 +123,7 @@ struct qcom_smd_edge {
        int ipc_bit;
 
        struct list_head channels;
-       rwlock_t channels_lock;
+       spinlock_t channels_lock;
 
        DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE);
 
@@ -135,6 +135,70 @@ struct qcom_smd_edge {
        struct work_struct state_work;
 };
 
+/*
+ * SMD channel states.
+ */
+enum smd_channel_state {
+       SMD_CHANNEL_CLOSED,
+       SMD_CHANNEL_OPENING,
+       SMD_CHANNEL_OPENED,
+       SMD_CHANNEL_FLUSHING,
+       SMD_CHANNEL_CLOSING,
+       SMD_CHANNEL_RESET,
+       SMD_CHANNEL_RESET_OPENING
+};
+
+/**
+ * struct qcom_smd_channel - smd channel struct
+ * @edge:              qcom_smd_edge this channel is living on
+ * @qsdev:             reference to a associated smd client device
+ * @name:              name of the channel
+ * @state:             local state of the channel
+ * @remote_state:      remote state of the channel
+ * @info:              byte aligned outgoing/incoming channel info
+ * @info_word:         word aligned outgoing/incoming channel info
+ * @tx_lock:           lock to make writes to the channel mutually exclusive
+ * @fblockread_event:  wakeup event tied to tx fBLOCKREADINTR
+ * @tx_fifo:           pointer to the outgoing ring buffer
+ * @rx_fifo:           pointer to the incoming ring buffer
+ * @fifo_size:         size of each ring buffer
+ * @bounce_buffer:     bounce buffer for reading wrapped packets
+ * @cb:                        callback function registered for this channel
+ * @recv_lock:         guard for rx info modifications and cb pointer
+ * @pkt_size:          size of the currently handled packet
+ * @list:              lite entry for @channels in qcom_smd_edge
+ */
+struct qcom_smd_channel {
+       struct qcom_smd_edge *edge;
+
+       struct qcom_smd_device *qsdev;
+
+       char *name;
+       enum smd_channel_state state;
+       enum smd_channel_state remote_state;
+
+       struct smd_channel_info_pair *info;
+       struct smd_channel_info_word_pair *info_word;
+
+       struct mutex tx_lock;
+       wait_queue_head_t fblockread_event;
+
+       void *tx_fifo;
+       void *rx_fifo;
+       int fifo_size;
+
+       void *bounce_buffer;
+       qcom_smd_cb_t cb;
+
+       spinlock_t recv_lock;
+
+       int pkt_size;
+
+       void *drvdata;
+
+       struct list_head list;
+       struct list_head dev_list;
+};
 
 /**
  * struct qcom_smd - smd struct
@@ -453,7 +517,6 @@ static void qcom_smd_channel_advance(struct qcom_smd_channel *channel,
  */
 static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
 {
-       struct qcom_smd_device *qsdev = channel->qsdev;
        unsigned tail;
        size_t len;
        void *ptr;
@@ -473,7 +536,7 @@ static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
                len = channel->pkt_size;
        }
 
-       ret = channel->cb(qsdev, ptr, len);
+       ret = channel->cb(channel, ptr, len);
        if (ret < 0)
                return ret;
 
@@ -557,18 +620,19 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
        struct qcom_smd_edge *edge = data;
        struct qcom_smd_channel *channel;
        unsigned available;
-       bool kick_worker = false;
+       bool kick_scanner = false;
+       bool kick_state = false;
 
        /*
         * Handle state changes or data on each of the channels on this edge
         */
-       read_lock(&edge->channels_lock);
+       spin_lock(&edge->channels_lock);
        list_for_each_entry(channel, &edge->channels, list) {
                spin_lock(&channel->recv_lock);
-               kick_worker |= qcom_smd_channel_intr(channel);
+               kick_state |= qcom_smd_channel_intr(channel);
                spin_unlock(&channel->recv_lock);
        }
-       read_unlock(&edge->channels_lock);
+       spin_unlock(&edge->channels_lock);
 
        /*
         * Creating a new channel requires allocating an smem entry, so we only
@@ -578,11 +642,13 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
        available = qcom_smem_get_free_space(edge->remote_pid);
        if (available != edge->smem_available) {
                edge->smem_available = available;
-               kick_worker = true;
+               kick_scanner = true;
        }
 
-       if (kick_worker)
+       if (kick_scanner)
                schedule_work(&edge->scan_work);
+       if (kick_state)
+               schedule_work(&edge->state_work);
 
        return IRQ_HANDLED;
 }
@@ -667,7 +733,7 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
 {
        __le32 hdr[5] = { cpu_to_le32(len), };
        int tlen = sizeof(hdr) + len;
-       int ret, length;
+       int ret;
 
        /* Word aligned channels only accept word size aligned data */
        if (channel->info_word && len % 4)
@@ -677,13 +743,10 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
        if (tlen >= channel->fifo_size)
                return -EINVAL;
 
-       length = qcom_smd_get_tx_avail(channel);
-
        ret = mutex_lock_interruptible(&channel->tx_lock);
        if (ret)
                return ret;
 
-       length = qcom_smd_get_tx_avail(channel);
        while (qcom_smd_get_tx_avail(channel) < tlen) {
                if (channel->state != SMD_CHANNEL_OPENED) {
                        ret = -EPIPE;
@@ -703,7 +766,6 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
 
        SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
 
-       length = qcom_smd_get_tx_avail(channel);
        qcom_smd_write_fifo(channel, hdr, sizeof(hdr));
        qcom_smd_write_fifo(channel, data, len);
 
@@ -975,6 +1037,18 @@ int qcom_smd_driver_register(struct qcom_smd_driver *qsdrv)
 }
 EXPORT_SYMBOL(qcom_smd_driver_register);
 
+void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
+{
+       return channel->drvdata;
+}
+EXPORT_SYMBOL(qcom_smd_get_drvdata);
+
+void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
+{
+       channel->drvdata = data;
+}
+EXPORT_SYMBOL(qcom_smd_set_drvdata);
+
 /**
  * qcom_smd_driver_unregister - unregister a smd driver
  * @qsdrv:     qcom_smd_driver struct
@@ -990,9 +1064,10 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
 {
        struct qcom_smd_channel *channel;
        struct qcom_smd_channel *ret = NULL;
+       unsigned long flags;
        unsigned state;
 
-       read_lock(&edge->channels_lock);
+       spin_lock_irqsave(&edge->channels_lock, flags);
        list_for_each_entry(channel, &edge->channels, list) {
                if (strcmp(channel->name, name))
                        continue;
@@ -1005,7 +1080,7 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
                ret = channel;
                break;
        }
-       read_unlock(&edge->channels_lock);
+       spin_unlock_irqrestore(&edge->channels_lock, flags);
 
        return ret;
 }
@@ -1019,12 +1094,13 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
  * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't
  * ready.
  */
-struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev,
+struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
                                               const char *name,
                                               qcom_smd_cb_t cb)
 {
        struct qcom_smd_channel *channel;
-       struct qcom_smd_edge *edge = sdev->channel->edge;
+       struct qcom_smd_device *sdev = parent->qsdev;
+       struct qcom_smd_edge *edge = parent->edge;
        int ret;
 
        /* Wait up to HZ for the channel to appear */
@@ -1116,7 +1192,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
        /* The channel consist of a rx and tx fifo of equal size */
        fifo_size /= 2;
 
-       dev_err(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
+       dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
                          name, info_size, fifo_size);
 
        channel->tx_fifo = fifo_base;
@@ -1185,9 +1261,9 @@ static void qcom_channel_scan_worker(struct work_struct *work)
                        if (IS_ERR(channel))
                                continue;
 
-                       write_lock_irqsave(&edge->channels_lock, flags);
+                       spin_lock_irqsave(&edge->channels_lock, flags);
                        list_add(&channel->list, &edge->channels);
-                       write_unlock_irqrestore(&edge->channels_lock, flags);
+                       spin_unlock_irqrestore(&edge->channels_lock, flags);
 
                        dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name);
                        set_bit(i, edge->allocated[tbl]);
@@ -1214,12 +1290,13 @@ static void qcom_channel_state_worker(struct work_struct *work)
                                                  struct qcom_smd_edge,
                                                  state_work);
        unsigned remote_state;
+       unsigned long flags;
 
        /*
         * Register a device for any closed channel where the remote processor
         * is showing interest in opening the channel.
         */
-       read_lock(&edge->channels_lock);
+       spin_lock_irqsave(&edge->channels_lock, flags);
        list_for_each_entry(channel, &edge->channels, list) {
                if (channel->state != SMD_CHANNEL_CLOSED)
                        continue;
@@ -1229,9 +1306,9 @@ static void qcom_channel_state_worker(struct work_struct *work)
                    remote_state != SMD_CHANNEL_OPENED)
                        continue;
 
-               read_unlock(&edge->channels_lock);
+               spin_unlock_irqrestore(&edge->channels_lock, flags);
                qcom_smd_create_device(channel);
-               read_lock(&edge->channels_lock);
+               spin_lock_irqsave(&edge->channels_lock, flags);
        }
 
        /*
@@ -1248,11 +1325,11 @@ static void qcom_channel_state_worker(struct work_struct *work)
                    remote_state == SMD_CHANNEL_OPENED)
                        continue;
 
-               read_unlock(&edge->channels_lock);
+               spin_unlock_irqrestore(&edge->channels_lock, flags);
                qcom_smd_destroy_device(channel);
-               read_lock(&edge->channels_lock);
+               spin_lock_irqsave(&edge->channels_lock, flags);
        }
-       read_unlock(&edge->channels_lock);
+       spin_unlock_irqrestore(&edge->channels_lock, flags);
 }
 
 /*
@@ -1268,7 +1345,7 @@ static int qcom_smd_parse_edge(struct device *dev,
        int ret;
 
        INIT_LIST_HEAD(&edge->channels);
-       rwlock_init(&edge->channels_lock);
+       spin_lock_init(&edge->channels_lock);
 
        INIT_WORK(&edge->scan_work, qcom_channel_scan_worker);
        INIT_WORK(&edge->state_work, qcom_channel_state_worker);
index 5290bb02c5476a4582d89a7c3d197df218152a46..8b9bfe912f8635a79cfe096c20ac234340ab2686 100644 (file)
@@ -690,8 +690,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
 
        smem->regions[i].aux_base = (u32)r.start;
        smem->regions[i].size = resource_size(&r);
-       smem->regions[i].virt_base = devm_ioremap_nocache(dev, r.start,
-                                                         resource_size(&r));
+       smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
        if (!smem->regions[i].virt_base)
                return -ENOMEM;
 
index 7a986f881d5c860df19614c4ca781bce69d2d296..00538a1a961774730387c885d1b9512952757d04 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2016, Linaro Ltd.
  * Copyright (c) 2015, Sony Mobile Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/soc/qcom/smd.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
 
 #define WCNSS_REQUEST_TIMEOUT  (5 * HZ)
+#define WCNSS_CBC_TIMEOUT      (10 * HZ)
+
+#define WCNSS_ACK_DONE_BOOTING 1
+#define WCNSS_ACK_COLD_BOOTING 2
 
 #define NV_FRAGMENT_SIZE       3072
 #define NVBIN_FILE             "wlan/prima/WCNSS_qcom_wlan_nv.bin"
  * @dev:       device handle
  * @channel:   SMD channel handle
  * @ack:       completion for outstanding requests
+ * @cbc:       completion for cbc complete indication
  * @ack_status:        status of the outstanding request
- * @download_nv_work: worker for uploading nv binary
+ * @probe_work: worker for uploading nv binary
  */
 struct wcnss_ctrl {
        struct device *dev;
        struct qcom_smd_channel *channel;
 
        struct completion ack;
+       struct completion cbc;
        int ack_status;
 
-       struct work_struct download_nv_work;
+       struct work_struct probe_work;
 };
 
 /* message types */
@@ -48,6 +59,11 @@ enum {
        WCNSS_UPLOAD_CAL_RESP,
        WCNSS_DOWNLOAD_CAL_REQ,
        WCNSS_DOWNLOAD_CAL_RESP,
+       WCNSS_VBAT_LEVEL_IND,
+       WCNSS_BUILD_VERSION_REQ,
+       WCNSS_BUILD_VERSION_RESP,
+       WCNSS_PM_CONFIG_REQ,
+       WCNSS_CBC_COMPLETE_IND,
 };
 
 /**
@@ -100,17 +116,17 @@ struct wcnss_download_nv_resp {
 
 /**
  * wcnss_ctrl_smd_callback() - handler from SMD responses
- * @qsdev:     smd device handle
+ * @channel:   smd channel handle
  * @data:      pointer to the incoming data packet
  * @count:     size of the incoming data packet
  *
  * Handles any incoming packets from the remote WCNSS_CTRL service.
  */
-static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
+static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel,
                                   const void *data,
                                   size_t count)
 {
-       struct wcnss_ctrl *wcnss = dev_get_drvdata(&qsdev->dev);
+       struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(channel);
        const struct wcnss_download_nv_resp *nvresp;
        const struct wcnss_version_resp *version;
        const struct wcnss_msg_hdr *hdr = data;
@@ -128,7 +144,7 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
                         version->major, version->minor,
                         version->version, version->revision);
 
-               schedule_work(&wcnss->download_nv_work);
+               complete(&wcnss->ack);
                break;
        case WCNSS_DOWNLOAD_NV_RESP:
                if (count != sizeof(*nvresp)) {
@@ -141,6 +157,10 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
                wcnss->ack_status = nvresp->status;
                complete(&wcnss->ack);
                break;
+       case WCNSS_CBC_COMPLETE_IND:
+               dev_dbg(wcnss->dev, "cold boot complete\n");
+               complete(&wcnss->cbc);
+               break;
        default:
                dev_info(wcnss->dev, "unknown message type %d\n", hdr->type);
                break;
@@ -156,20 +176,32 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
 static int wcnss_request_version(struct wcnss_ctrl *wcnss)
 {
        struct wcnss_msg_hdr msg;
+       int ret;
 
        msg.type = WCNSS_VERSION_REQ;
        msg.len = sizeof(msg);
+       ret = qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
+       if (ret < 0)
+               return ret;
+
+       ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_CBC_TIMEOUT);
+       if (!ret) {
+               dev_err(wcnss->dev, "timeout waiting for version response\n");
+               return -ETIMEDOUT;
+       }
 
-       return qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
+       return 0;
 }
 
 /**
  * wcnss_download_nv() - send nv binary to WCNSS
- * @work:      work struct to acquire wcnss context
+ * @wcnss:     wcnss_ctrl state handle
+ * @expect_cbc:        indicator to caller that an cbc event is expected
+ *
+ * Returns 0 on success. Negative errno on failure.
  */
-static void wcnss_download_nv(struct work_struct *work)
+static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
 {
-       struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work);
        struct wcnss_download_nv_req *req;
        const struct firmware *fw;
        const void *data;
@@ -178,10 +210,10 @@ static void wcnss_download_nv(struct work_struct *work)
 
        req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL);
        if (!req)
-               return;
+               return -ENOMEM;
 
        ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev);
-       if (ret) {
+       if (ret < 0) {
                dev_err(wcnss->dev, "Failed to load nv file %s: %d\n",
                        NVBIN_FILE, ret);
                goto free_req;
@@ -207,7 +239,7 @@ static void wcnss_download_nv(struct work_struct *work)
                memcpy(req->fragment, data, req->frag_size);
 
                ret = qcom_smd_send(wcnss->channel, req, req->hdr.len);
-               if (ret) {
+               if (ret < 0) {
                        dev_err(wcnss->dev, "failed to send smd packet\n");
                        goto release_fw;
                }
@@ -220,16 +252,63 @@ static void wcnss_download_nv(struct work_struct *work)
        } while (left > 0);
 
        ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT);
-       if (!ret)
+       if (!ret) {
                dev_err(wcnss->dev, "timeout waiting for nv upload ack\n");
-       else if (wcnss->ack_status != 1)
-               dev_err(wcnss->dev, "nv upload response failed err: %d\n",
-                       wcnss->ack_status);
+               ret = -ETIMEDOUT;
+       } else {
+               *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING;
+               ret = 0;
+       }
 
 release_fw:
        release_firmware(fw);
 free_req:
        kfree(req);
+
+       return ret;
+}
+
+int wcnss_ctrl_done_loading_nv;
+EXPORT_SYMBOL(wcnss_ctrl_done_loading_nv);
+
+/**
+ * qcom_wcnss_open_channel() - open additional SMD channel to WCNSS
+ * @wcnss:     wcnss handle, retrieved from drvdata
+ * @name:      SMD channel name
+ * @cb:                callback to handle incoming data on the channel
+ */
+struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb)
+{
+       struct wcnss_ctrl *_wcnss = wcnss;
+
+       return qcom_smd_open_channel(_wcnss->channel, name, cb);
+}
+EXPORT_SYMBOL(qcom_wcnss_open_channel);
+
+static void wcnss_async_probe(struct work_struct *work)
+{
+       struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, probe_work);
+       bool expect_cbc;
+       int ret;
+
+       ret = wcnss_request_version(wcnss);
+       if (ret < 0)
+               return;
+
+       ret = wcnss_download_nv(wcnss, &expect_cbc);
+       if (ret < 0)
+               return;
+
+       /* Wait for pending cold boot completion if indicated by the nv downloader */
+       if (expect_cbc) {
+               ret = wait_for_completion_timeout(&wcnss->cbc, WCNSS_REQUEST_TIMEOUT);
+               if (!ret)
+                       dev_err(wcnss->dev, "expected cold boot completion\n");
+       }
+
+       wcnss_ctrl_done_loading_nv = 1;
+
+       of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev);
 }
 
 static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
@@ -244,25 +323,40 @@ static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
        wcnss->channel = sdev->channel;
 
        init_completion(&wcnss->ack);
-       INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv);
+       init_completion(&wcnss->cbc);
+       INIT_WORK(&wcnss->probe_work, wcnss_async_probe);
 
+       qcom_smd_set_drvdata(sdev->channel, wcnss);
        dev_set_drvdata(&sdev->dev, wcnss);
 
-       return wcnss_request_version(wcnss);
+       qcom_smd_set_drvdata(sdev->channel, wcnss);
+
+       schedule_work(&wcnss->probe_work);
+
+       return 0;
+}
+
+static void wcnss_ctrl_remove(struct qcom_smd_device *sdev)
+{
+       struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(sdev->channel);
+
+       cancel_work_sync(&wcnss->probe_work);
+       of_platform_depopulate(&sdev->dev);
 }
 
-static const struct qcom_smd_id wcnss_ctrl_smd_match[] = {
-       { .name = "WCNSS_CTRL" },
+static const struct of_device_id wcnss_ctrl_of_match[] = {
+       { .compatible = "qcom,wcnss", },
        {}
 };
 
 static struct qcom_smd_driver wcnss_ctrl_driver = {
        .probe = wcnss_ctrl_probe,
+       .remove = wcnss_ctrl_remove,
        .callback = wcnss_ctrl_smd_callback,
-       .smd_match_table = wcnss_ctrl_smd_match,
        .driver  = {
                .name  = "qcom_wcnss_ctrl",
                .owner = THIS_MODULE,
+               .of_match_table = wcnss_ctrl_of_match,
        },
 };
 
index 810a7fae347988a7d9dc1101586234b8ef8efc77..68f95acf7971c280da93389cd68a65f50846aa20 100644 (file)
@@ -142,6 +142,7 @@ struct spi_qup {
 
        struct spi_transfer     *xfer;
        struct completion       done;
+       struct completion       dma_tx_done;
        int                     error;
        int                     w_size; /* bytes per SPI word */
        int                     n_words;
@@ -276,16 +277,16 @@ static void spi_qup_fifo_write(struct spi_qup *controller,
 
 static void spi_qup_dma_done(void *data)
 {
-       struct spi_qup *qup = data;
+       struct completion *done = data;
 
-       complete(&qup->done);
+       complete(done);
 }
 
 static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
                           enum dma_transfer_direction dir,
-                          dma_async_tx_callback callback)
+                          dma_async_tx_callback callback,
+                          void *data)
 {
-       struct spi_qup *qup = spi_master_get_devdata(master);
        unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
        struct dma_async_tx_descriptor *desc;
        struct scatterlist *sgl;
@@ -308,7 +309,7 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
                return -EINVAL;
 
        desc->callback = callback;
-       desc->callback_param = qup;
+       desc->callback_param = data;
 
        cookie = dmaengine_submit(desc);
 
@@ -324,18 +325,29 @@ static void spi_qup_dma_terminate(struct spi_master *master,
                dmaengine_terminate_all(master->dma_rx);
 }
 
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+unsigned long timeout)
 {
+       struct spi_qup *qup = spi_master_get_devdata(master);
        dma_async_tx_callback rx_done = NULL, tx_done = NULL;
        int ret;
 
+       /* before issuing the descriptors, set the QUP to run */
+       ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+       if (ret) {
+               dev_warn(qup->dev, "cannot set RUN state\n");
+               return ret;
+       }
+
        if (xfer->rx_buf)
                rx_done = spi_qup_dma_done;
-       else if (xfer->tx_buf)
+
+       if (xfer->tx_buf)
                tx_done = spi_qup_dma_done;
 
        if (xfer->rx_buf) {
-               ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
+               ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done,
+                                     &qup->done);
                if (ret)
                        return ret;
 
@@ -343,17 +355,25 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
        }
 
        if (xfer->tx_buf) {
-               ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
+               ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done,
+                                     &qup->dma_tx_done);
                if (ret)
                        return ret;
 
                dma_async_issue_pending(master->dma_tx);
        }
 
-       return 0;
+       if (xfer->rx_buf && !wait_for_completion_timeout(&qup->done, timeout))
+               return -ETIMEDOUT;
+
+       if (xfer->tx_buf && !wait_for_completion_timeout(&qup->dma_tx_done, timeout))
+               ret = -ETIMEDOUT;
+
+       return ret;
 }
 
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+                         unsigned long timeout)
 {
        struct spi_qup *qup = spi_master_get_devdata(master);
        int ret;
@@ -372,6 +392,15 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
 
        spi_qup_fifo_write(qup, xfer);
 
+       ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+       if (ret) {
+               dev_warn(qup->dev, "cannot set RUN state\n");
+               return ret;
+       }
+
+       if (!wait_for_completion_timeout(&qup->done, timeout))
+               return -ETIMEDOUT;
+
        return 0;
 }
 
@@ -420,7 +449,6 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
                        dev_warn(controller->dev, "CLK_OVER_RUN\n");
                if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
                        dev_warn(controller->dev, "CLK_UNDER_RUN\n");
-
                error = -EIO;
        }
 
@@ -437,7 +465,8 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
        controller->xfer = xfer;
        spin_unlock_irqrestore(&controller->lock, flags);
 
-       if (controller->rx_bytes == xfer->len || error)
+       if ((controller->rx_bytes == xfer->len &&
+               (opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) ||  error)
                complete(&controller->done);
 
        return IRQ_HANDLED;
@@ -625,6 +654,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
        timeout = 100 * msecs_to_jiffies(timeout);
 
        reinit_completion(&controller->done);
+       reinit_completion(&controller->dma_tx_done);
 
        spin_lock_irqsave(&controller->lock, flags);
        controller->xfer     = xfer;
@@ -634,21 +664,13 @@ static int spi_qup_transfer_one(struct spi_master *master,
        spin_unlock_irqrestore(&controller->lock, flags);
 
        if (controller->use_dma)
-               ret = spi_qup_do_dma(master, xfer);
+               ret = spi_qup_do_dma(master, xfer, timeout);
        else
-               ret = spi_qup_do_pio(master, xfer);
+               ret = spi_qup_do_pio(master, xfer, timeout);
 
        if (ret)
                goto exit;
 
-       if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-               dev_warn(controller->dev, "cannot set EXECUTE state\n");
-               goto exit;
-       }
-
-       if (!wait_for_completion_timeout(&controller->done, timeout))
-               ret = -ETIMEDOUT;
-
 exit:
        spi_qup_set_state(controller, QUP_STATE_RESET);
        spin_lock_irqsave(&controller->lock, flags);
@@ -672,15 +694,23 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
 
        qup->use_dma = 0;
 
-       if (xfer->rx_buf && (xfer->len % qup->in_blk_sz ||
-           IS_ERR_OR_NULL(master->dma_rx) ||
-           !IS_ALIGNED((size_t)xfer->rx_buf, dma_align)))
-               return false;
+       if (xfer->rx_buf) {
+               if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
+                   IS_ERR_OR_NULL(master->dma_rx))
+                       return false;
 
-       if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
-           IS_ERR_OR_NULL(master->dma_tx) ||
-           !IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
-               return false;
+               if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
+                       return false;
+       }
+
+       if (xfer->tx_buf) {
+               if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
+                   IS_ERR_OR_NULL(master->dma_tx))
+                       return false;
+
+               if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
+                       return false;
+       }
 
        mode = spi_qup_get_mode(master, xfer);
        if (mode == QUP_IO_M_MODE_FIFO)
@@ -848,6 +878,7 @@ static int spi_qup_probe(struct platform_device *pdev)
 
        spin_lock_init(&controller->lock);
        init_completion(&controller->done);
+       init_completion(&controller->dma_tx_done);
 
        iomode = readl_relaxed(base + QUP_IO_M_MODES);
 
index dcde955475dc9b11029c614d0d137d582d04e77c..e1de4944e0ce5f8eae8ada1020086294c9a13fea 100644 (file)
@@ -726,7 +726,7 @@ static void msm_handle_tx(struct uart_port *port)
                return;
        }
 
-       pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+       pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
        dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
 
        dma_min = 1;    /* Always DMA */
index 81ae6c956eb815229b3e1531dbcf678a4e582463..5924cdb7133621f0e4a4427c1208b8cc6fbc0d80 100644 (file)
 #ifndef _DT_BINDINGS_CLK_MSM_RPMCC_H
 #define _DT_BINDINGS_CLK_MSM_RPMCC_H
 
-/* msm8916 */
-#define RPM_XO_CLK_SRC                         0
-#define RPM_XO_A_CLK_SRC                       1
-#define RPM_PCNOC_CLK                          2
-#define RPM_PCNOC_A_CLK                                3
-#define RPM_SNOC_CLK                           4
-#define RPM_SNOC_A_CLK                         5
-#define RPM_BIMC_CLK                           6
-#define RPM_BIMC_A_CLK                         7
-#define RPM_QDSS_CLK                           8
-#define RPM_QDSS_A_CLK                         9
-#define RPM_BB_CLK1                            10
-#define RPM_BB_CLK1_A                          11
-#define RPM_BB_CLK2                            12
-#define RPM_BB_CLK2_A                          13
-#define RPM_RF_CLK1                            14
-#define RPM_RF_CLK1_A                          15
-#define RPM_RF_CLK2                            16
-#define RPM_RF_CLK2_A                          17
-#define RPM_BB_CLK1_PIN                                18
-#define RPM_BB_CLK1_A_PIN                      19
-#define RPM_BB_CLK2_PIN                                20
-#define RPM_BB_CLK2_A_PIN                      21
-#define RPM_RF_CLK1_PIN                                22
-#define RPM_RF_CLK1_A_PIN                      23
-#define RPM_RF_CLK2_PIN                                24
-#define RPM_RF_CLK2_A_PIN                      25
-
-/* msm8974 */
-#define RPM_CXO_CLK_SRC                                0
-#define RPM_CXO_A_CLK_SRC                      1
-#define RPM_PNOC_CLK                           2
-#define RPM_PNOC_A_CLK                         3
-#define RPM_SNOC_CLK                           4
-#define RPM_SNOC_A_CLK                         5
-#define RPM_BIMC_CLK                           6
-#define RPM_BIMC_A_CLK                         7
+/* apq8064 */
+#define RPM_PXO_CLK                            0
+#define RPM_PXO_A_CLK                          1
+#define RPM_CXO_CLK                            2
+#define RPM_CXO_A_CLK                          3
+#define RPM_APPS_FABRIC_CLK                    4
+#define RPM_APPS_FABRIC_A_CLK                  5
+#define RPM_CFPB_CLK                           6
+#define RPM_CFPB_A_CLK                         7
 #define RPM_QDSS_CLK                           8
 #define RPM_QDSS_A_CLK                         9
-#define RPM_CXO_D0                             10
-#define RPM_CXO_D0_A                           11
-#define RPM_CXO_D1                             12
-#define RPM_CXO_D1_A                           13
-#define RPM_CXO_A0                             14
-#define RPM_CXO_A0_A                           15
-#define RPM_CXO_A1                             16
-#define RPM_CXO_A1_A                           17
-#define RPM_CXO_A2                             18
-#define RPM_CXO_A2_A                           19
-#define RPM_CXO_D0_PIN                         20
-#define RPM_CXO_D0_A_PIN                       21
-#define RPM_CXO_A2_PIN                         22
-#define RPM_CXO_A2_A_PIN                       23
-#define RPM_CXO_A1_PIN                         24
-#define RPM_CXO_A1_A_PIN                       25
-#define RPM_DIFF_CLK                           26
-#define RPM_DIFF_A_CLK                         27
-#define RPM_CNOC_CLK                           28
-#define RPM_CNOC_A_CLK                         29
-#define RPM_MMSSNOC_AHB_CLK                    30
-#define RPM_MMSSNOC_AHB_A_CLK                  31
-#define RPM_OCMEMGX_CLK                                32
-#define RPM_OCMEMGX_A_CLK                      33
-#define RPM_GFX3D_CLK_SRC                      34
-#define RPM_GFX3D_A_CLK_SRC                    35
-#define RPM_DIV_CLK1                           36
-#define RPM_DIV_A_CLK1                         37
-#define RPM_DIV_CLK2                           38
-#define RPM_DIV_A_CLK2                         39
-#define RPM_CXO_D1_PIN                         40
-#define RPM_CXO_D1_A_PIN                       41
-#define RPM_CXO_A0_PIN                         42
-#define RPM_CXO_A0_A_PIN                       43
+#define RPM_DAYTONA_FABRIC_CLK                 10
+#define RPM_DAYTONA_FABRIC_A_CLK               11
+#define RPM_EBI1_CLK                           12
+#define RPM_EBI1_A_CLK                         13
+#define RPM_MM_FABRIC_CLK                      14
+#define RPM_MM_FABRIC_A_CLK                    15
+#define RPM_MMFPB_CLK                          16
+#define RPM_MMFPB_A_CLK                                17
+#define RPM_SYS_FABRIC_CLK                     18
+#define RPM_SYS_FABRIC_A_CLK                   19
+#define RPM_SFPB_CLK                           20
+#define RPM_SFPB_A_CLK                         21
 
-/* apq8084 */
-#define RPM_XO_CLK_SRC                         0
-#define RPM_XO_A_CLK_SRC                       1
-#define RPM_PNOC_CLK                           2
-#define RPM_PNOC_A_CLK                         3
-#define RPM_SNOC_CLK                           4
-#define RPM_SNOC_A_CLK                         5
-#define RPM_BIMC_CLK                           6
-#define RPM_BIMC_A_CLK                         7
-#define RPM_QDSS_CLK                           8
-#define RPM_QDSS_A_CLK                         9
-#define RPM_BB_CLK1                            10
-#define RPM_BB_CLK1_A                          11
-#define RPM_BB_CLK2                            12
-#define RPM_BB_CLK2_A                          13
-#define RPM_RF_CLK1                            14
-#define RPM_RF_CLK1_A                          15
-#define RPM_RF_CLK2                            16
-#define RPM_RF_CLK2_A                          17
-#define RPM_BB_CLK1_PIN                                18
-#define RPM_BB_CLK1_A_PIN                      19
-#define RPM_BB_CLK2_PIN                                20
-#define RPM_BB_CLK2_A_PIN                      21
-#define RPM_RF_CLK1_PIN                                22
-#define RPM_RF_CLK1_A_PIN                      23
-#define RPM_RF_CLK2_PIN                                24
-#define RPM_RF_CLK2_A_PIN                      25
-#define RPM_DIFF_CLK1                          26
-#define RPM_DIFF_CLK1_A                                27
-#define RPM_CNOC_CLK                           28
-#define RPM_CNOC_A_CLK                         29
-#define RPM_MMSSNOC_AHB_CLK                    30
-#define RPM_MMSSNOC_AHB_A_CLK                  31
-#define RPM_OCMEMGX_CLK                                32
-#define RPM_OCMEMGX_A_CLK                      33
-#define RPM_GFX3D_CLK_SRC                      34
-#define RPM_GFX3D_A_CLK_SRC                    35
-#define RPM_DIV_CLK1                           36
-#define RPM_DIV_CLK1_A                         37
-#define RPM_DIV_CLK2                           38
-#define RPM_DIV_CLK2_A                         39
-#define RPM_DIV_CLK3                           40
-#define RPM_DIV_CLK3_A                         41
-#define RPM_RF_CLK3_PIN                                44
-#define RPM_RF_CLK3_A_PIN                      45
-#define RPM_RF_CLK3                            46
-#define RPM_RF_CLK3_A                          47
+/* msm8916 */
+#define RPM_SMD_XO_CLK_SRC                             0
+#define RPM_SMD_XO_A_CLK_SRC                   1
+#define RPM_SMD_PCNOC_CLK                              2
+#define RPM_SMD_PCNOC_A_CLK                            3
+#define RPM_SMD_SNOC_CLK                               4
+#define RPM_SMD_SNOC_A_CLK                             5
+#define RPM_SMD_BIMC_CLK                               6
+#define RPM_SMD_BIMC_A_CLK                             7
+#define RPM_SMD_QDSS_CLK                               8
+#define RPM_SMD_QDSS_A_CLK                             9
+#define RPM_SMD_BB_CLK1                                10
+#define RPM_SMD_BB_CLK1_A                              11
+#define RPM_SMD_BB_CLK2                                12
+#define RPM_SMD_BB_CLK2_A                              13
+#define RPM_SMD_RF_CLK1                                14
+#define RPM_SMD_RF_CLK1_A                              15
+#define RPM_SMD_RF_CLK2                                16
+#define RPM_SMD_RF_CLK2_A                              17
+#define RPM_SMD_BB_CLK1_PIN                            18
+#define RPM_SMD_BB_CLK1_A_PIN                  19
+#define RPM_SMD_BB_CLK2_PIN                            20
+#define RPM_SMD_BB_CLK2_A_PIN                  21
+#define RPM_SMD_RF_CLK1_PIN                            22
+#define RPM_SMD_RF_CLK1_A_PIN                  23
+#define RPM_SMD_RF_CLK2_PIN                            24
+#define RPM_SMD_RF_CLK2_A_PIN                  25
 
 #endif
diff --git a/include/dt-bindings/sound/msm8916-wcd.h b/include/dt-bindings/sound/msm8916-wcd.h
new file mode 100644 (file)
index 0000000..718db3c
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __DT_MSM8916_WCD_H
+#define __DT_MSM8916_WCD_H
+
+#define MSM8916_WCD_PLAYBACK_DAI       0
+#define MSM8916_WCD_CAPTURE_DAI                1
+
+#endif /* __DT_MSM8916_WCD_H */
index 0b9f01b489cb2d70c53a3d4471918bc4efb0daf2..93819720e2a4bb1f677ed10d033ed553bbbc838c 100644 (file)
@@ -32,8 +32,7 @@ extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
                u32 *resp);
 
 extern bool qcom_scm_pas_supported(u32 peripheral);
-extern int qcom_scm_restart_proc(u32 pid, int restart, u32 *resp);
-extern int qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size);
+extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size);
 extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size);
 extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
 extern int qcom_scm_pas_shutdown(u32 peripheral);
index 49764d94ef4f74349737f6e5406f427a92e2b3d1..cbb0f06c41b21866385882d85e6954d70b77b1a4 100644 (file)
@@ -5,74 +5,8 @@
 #include <linux/mod_devicetable.h>
 
 struct qcom_smd;
+struct qcom_smd_channel;
 struct qcom_smd_lookup;
-struct qcom_smd_device;
-
-typedef int (*qcom_smd_cb_t)(struct qcom_smd_device *, const void *, size_t);
-
-/*
- * SMD channel states.
- */
-enum smd_channel_state {
-       SMD_CHANNEL_CLOSED,
-       SMD_CHANNEL_OPENING,
-       SMD_CHANNEL_OPENED,
-       SMD_CHANNEL_FLUSHING,
-       SMD_CHANNEL_CLOSING,
-       SMD_CHANNEL_RESET,
-       SMD_CHANNEL_RESET_OPENING
-};
-
-/**
- * struct qcom_smd_channel - smd channel struct
- * @edge:              qcom_smd_edge this channel is living on
- * @qsdev:             reference to a associated smd client device
- * @name:              name of the channel
- * @state:             local state of the channel
- * @remote_state:      remote state of the channel
- * @info:              byte aligned outgoing/incoming channel info
- * @info_word:         word aligned outgoing/incoming channel info
- * @tx_lock:           lock to make writes to the channel mutually exclusive
- * @fblockread_event:  wakeup event tied to tx fBLOCKREADINTR
- * @tx_fifo:           pointer to the outgoing ring buffer
- * @rx_fifo:           pointer to the incoming ring buffer
- * @fifo_size:         size of each ring buffer
- * @bounce_buffer:     bounce buffer for reading wrapped packets
- * @cb:                        callback function registered for this channel
- * @recv_lock:         guard for rx info modifications and cb pointer
- * @pkt_size:          size of the currently handled packet
- * @list:              lite entry for @channels in qcom_smd_edge
- */
-
-struct qcom_smd_channel {
-       struct qcom_smd_edge *edge;
-
-       struct qcom_smd_device *qsdev;
-
-       char *name;
-       enum smd_channel_state state;
-       enum smd_channel_state remote_state;
-
-       struct smd_channel_info_pair *info;
-       struct smd_channel_info_word_pair *info_word;
-
-       struct mutex tx_lock;
-       wait_queue_head_t fblockread_event;
-
-       void *tx_fifo;
-       void *rx_fifo;
-       int fifo_size;
-
-       void *bounce_buffer;
-       qcom_smd_cb_t cb;
-
-       spinlock_t recv_lock;
-
-       int pkt_size;
-
-       struct list_head list;
-       struct list_head dev_list;
-};
 
 /**
  * struct qcom_smd_id - struct used for matching a smd device
@@ -92,6 +26,8 @@ struct qcom_smd_device {
        struct qcom_smd_channel *channel;
 };
 
+typedef int (*qcom_smd_cb_t)(struct qcom_smd_channel *, const void *, size_t);
+
 /**
  * struct qcom_smd_driver - smd driver struct
  * @driver:    underlying device driver
@@ -111,17 +47,68 @@ struct qcom_smd_driver {
        qcom_smd_cb_t callback;
 };
 
+#if IS_ENABLED(CONFIG_QCOM_SMD)
+
 int qcom_smd_driver_register(struct qcom_smd_driver *drv);
 void qcom_smd_driver_unregister(struct qcom_smd_driver *drv);
 
+struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
+                                              const char *name,
+                                              qcom_smd_cb_t cb);
+void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel);
+void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data);
+int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
+
+
+#else
+
+static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv)
+{
+       return -ENXIO;
+}
+
+static inline void qcom_smd_driver_unregister(struct qcom_smd_driver *drv)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+}
+
+static inline struct qcom_smd_channel *
+qcom_smd_open_channel(struct qcom_smd_channel *channel,
+                     const char *name,
+                     qcom_smd_cb_t cb)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+       return NULL;
+}
+
+void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+       return NULL;
+}
+
+void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+}
+
+static inline int qcom_smd_send(struct qcom_smd_channel *channel,
+                               const void *data, int len)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+       return -ENXIO;
+}
+
+#endif
+
 #define module_qcom_smd_driver(__smd_driver) \
        module_driver(__smd_driver, qcom_smd_driver_register, \
                      qcom_smd_driver_unregister)
 
-int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
-
-struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev,
-                                              const char *name,
-                                              qcom_smd_cb_t cb);
 
 #endif
diff --git a/include/linux/soc/qcom/wcnss_ctrl.h b/include/linux/soc/qcom/wcnss_ctrl.h
new file mode 100644 (file)
index 0000000..a37bc55
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __WCNSS_CTRL_H__
+#define __WCNSS_CTRL_H__
+
+#include <linux/soc/qcom/smd.h>
+
+struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb);
+
+#endif
index 5bf59c8493b763c6dc11ccce18da9c0ac6c0da46..dbd81e7f21fd058d65e1049e37af1c942d306c3f 100644 (file)
@@ -200,7 +200,10 @@ struct ucred {
 #define AF_ALG         38      /* Algorithm sockets            */
 #define AF_NFC         39      /* NFC sockets                  */
 #define AF_VSOCK       40      /* vSockets                     */
-#define AF_MAX         41      /* For now.. */
+#define AF_KCM         41      /* Kernel Connection Multiplexor*/
+#define AF_QIPCRTR     42      /* Qualcomm IPC Router          */
+
+#define AF_MAX         43      /* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC      AF_UNSPEC
@@ -246,6 +249,8 @@ struct ucred {
 #define PF_ALG         AF_ALG
 #define PF_NFC         AF_NFC
 #define PF_VSOCK       AF_VSOCK
+#define PF_KCM         AF_KCM
+#define PF_QIPCRTR     AF_QIPCRTR
 #define PF_MAX         AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -322,6 +327,7 @@ struct ucred {
 #define SOL_CAIF       278
 #define SOL_ALG                279
 #define SOL_NFC                280
+#define SOL_KCM                281
 
 /* IPX options */
 #define IPX_TYPE       1
diff --git a/include/net/kcm.h b/include/net/kcm.h
new file mode 100644 (file)
index 0000000..1bcae39
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Kernel Connection Multiplexor
+ *
+ * Copyright (c) 2016 Tom Herbert <tom@herbertland.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef __NET_KCM_H_
+#define __NET_KCM_H_
+
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <uapi/linux/kcm.h>
+
+extern unsigned int kcm_net_id;
+
+struct kcm_tx_msg {
+       unsigned int sent;
+       unsigned int fragidx;
+       unsigned int frag_offset;
+       unsigned int msg_flags;
+       struct sk_buff *frag_skb;
+       struct sk_buff *last_skb;
+};
+
+struct kcm_rx_msg {
+       int full_len;
+       int accum_len;
+       int offset;
+};
+
+/* Socket structure for KCM client sockets */
+struct kcm_sock {
+       struct sock sk;
+       struct kcm_mux *mux;
+       struct list_head kcm_sock_list;
+       int index;
+       u32 done : 1;
+       struct work_struct done_work;
+
+       /* Transmit */
+       struct kcm_psock *tx_psock;
+       struct work_struct tx_work;
+       struct list_head wait_psock_list;
+       struct sk_buff *seq_skb;
+
+       /* Don't use bit fields here, these are set under different locks */
+       bool tx_wait;
+       bool tx_wait_more;
+
+       /* Receive */
+       struct kcm_psock *rx_psock;
+       struct list_head wait_rx_list; /* KCMs waiting for receiving */
+       bool rx_wait;
+       u32 rx_disabled : 1;
+};
+
+struct bpf_prog;
+
+/* Structure for an attached lower socket */
+struct kcm_psock {
+       struct sock *sk;
+       struct kcm_mux *mux;
+       int index;
+
+       u32 tx_stopped : 1;
+       u32 rx_stopped : 1;
+       u32 done : 1;
+       u32 unattaching : 1;
+
+       void (*save_state_change)(struct sock *sk);
+       void (*save_data_ready)(struct sock *sk);
+       void (*save_write_space)(struct sock *sk);
+
+       struct list_head psock_list;
+
+       /* Receive */
+       struct sk_buff *rx_skb_head;
+       struct sk_buff **rx_skb_nextp;
+       struct sk_buff *ready_rx_msg;
+       struct list_head psock_ready_list;
+       struct work_struct rx_work;
+       struct delayed_work rx_delayed_work;
+       struct bpf_prog *bpf_prog;
+       struct kcm_sock *rx_kcm;
+
+       /* Transmit */
+       struct kcm_sock *tx_kcm;
+       struct list_head psock_avail_list;
+};
+
+/* Per net MUX list */
+struct kcm_net {
+       struct mutex mutex;
+       struct list_head mux_list;
+       int count;
+};
+
+/* Structure for a MUX */
+struct kcm_mux {
+       struct list_head kcm_mux_list;
+       struct rcu_head rcu;
+       struct kcm_net *knet;
+
+       struct list_head kcm_socks;     /* All KCM sockets on MUX */
+       int kcm_socks_cnt;              /* Total KCM socket count for MUX */
+       struct list_head psocks;        /* List of all psocks on MUX */
+       int psocks_cnt;         /* Total attached sockets */
+
+       /* Receive */
+       spinlock_t rx_lock ____cacheline_aligned_in_smp;
+       struct list_head kcm_rx_waiters; /* KCMs waiting for receiving */
+       struct list_head psocks_ready;  /* List of psocks with a msg ready */
+       struct sk_buff_head rx_hold_queue;
+
+       /* Transmit */
+       spinlock_t  lock ____cacheline_aligned_in_smp;  /* TX and mux locking */
+       struct list_head psocks_avail;  /* List of available psocks */
+       struct list_head kcm_tx_waiters; /* KCMs waiting for a TX psock */
+};
+
+#endif /* __NET_KCM_H_ */
index 760bc4d5a2cfe87aadd2e96a98292855cf2eb050..323237e5bf368bbe855cf18c617f4b52d711652a 100644 (file)
@@ -2157,7 +2157,7 @@ static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev
  * @hw: the &struct ieee80211_hw to set the MAC address for
  * @addr: the address to set
  */
-static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
+static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, const u8 *addr)
 {
        memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
 }
index fb955e69a78ea29f79bd4382b492bca009cd6fe7..fecde5b4d97865fee59a29ac7477f9ceebf530e5 100644 (file)
        .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
        .private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \
                                            xmin, xmax, xsign_bit, xinvert) }
+#define SOC_SINGLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
+{      .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+                 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .tlv.p  = (tlv_array), \
+       .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+       .put = snd_soc_put_volsw, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+       {.reg = xreg, .rreg = xreg,  \
+        .min = xmin, .max = xmax, .platform_max = xmax, \
+       .sign_bit = 7,} }
 #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
 {      .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
diff --git a/include/uapi/linux/gps_proxy.h b/include/uapi/linux/gps_proxy.h
new file mode 100644 (file)
index 0000000..5ac7f6b
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (c) 2016, 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 __GPS_PROXY_H__
+#define __GPS_PROXY_H__
+
+#define QMI_LOC_NMEA_STRING_MAX_LENGTH_V02 201
+
+enum QGPS_TTY_IOCTL_CMDS {
+       QGPS_REGISTER_HANDLE_IOC = 0,
+       QGPS_SEND_NMEA_IOC,
+       QGPS_IS_ACTIVE_IOC,
+};
+
+#define QGPS_IOC_MAGIC                 'q'
+#define QGPS_REGISTER_HANDLE   _IO(QGPS_IOC_MAGIC, QGPS_REGISTER_HANDLE_IOC)
+#define QGPS_SEND_NMEA                 _IO(QGPS_IOC_MAGIC, QGPS_SEND_NMEA_IOC)
+#define QGPS_IS_ACTIVE                 _IO(QGPS_IOC_MAGIC, QGPS_IS_ACTIVE_IOC)
+
+struct gps_proxy_data {
+       size_t nmea_length;
+       char nmea_string[QMI_LOC_NMEA_STRING_MAX_LENGTH_V02];
+};
+
+#endif /* __GPS_PROXY_H__ */
diff --git a/include/uapi/linux/kcm.h b/include/uapi/linux/kcm.h
new file mode 100644 (file)
index 0000000..a5a5309
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Kernel Connection Multiplexor
+ *
+ * Copyright (c) 2016 Tom Herbert <tom@herbertland.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * User API to clone KCM sockets and attach transport socket to a KCM
+ * multiplexor.
+ */
+
+#ifndef KCM_KERNEL_H
+#define KCM_KERNEL_H
+
+struct kcm_attach {
+       int fd;
+       int bpf_fd;
+};
+
+struct kcm_unattach {
+       int fd;
+};
+
+struct kcm_clone {
+       int fd;
+};
+
+#define SIOCKCMATTACH  (SIOCPROTOPRIVATE + 0)
+#define SIOCKCMUNATTACH        (SIOCPROTOPRIVATE + 1)
+#define SIOCKCMCLONE   (SIOCPROTOPRIVATE + 2)
+
+#define KCMPROTO_CONNECTED     0
+
+/* Socket options */
+#define KCM_RECV_DISABLE       1
+
+#endif
+
diff --git a/include/uapi/linux/qrtr.h b/include/uapi/linux/qrtr.h
new file mode 100644 (file)
index 0000000..66c0748
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _LINUX_QRTR_H
+#define _LINUX_QRTR_H
+
+#include <linux/socket.h>
+
+struct sockaddr_qrtr {
+       __kernel_sa_family_t sq_family;
+       __u32 sq_node;
+       __u32 sq_port;
+};
+
+#endif /* _LINUX_QRTR_H */
diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config
new file mode 100644 (file)
index 0000000..451a71b
--- /dev/null
@@ -0,0 +1,13 @@
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_KASAN=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
index 032e3fef8994d903ece36be5b3a56a492358df3c..e4112b36deb8defb3ea7ea1c52a022fdfa38bd7a 100644 (file)
@@ -111,7 +111,6 @@ CONFIG_USB_SERIAL_QT2=m
 
 # USB gadget
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_VBUS_DRAW=500
 CONFIG_USB_CONFIGFS=m
 CONFIG_USB_ZERO=m
@@ -210,7 +209,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_PRINTK_TIME=y
 CONFIG_STACKTRACE=y
 CONFIG_MMC_BLOCK_MINORS=32
-CONFIG_PROVE_LOCKING=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_SND_USB=y
 CONFIG_SND_USB_AUDIO=y
index 127da94ae25eb73e8ffd45e7e7dbc9e07d937033..1c9fda1c602d5bc3a628d1f3ce7d69b34fca07dd 100644 (file)
@@ -233,6 +233,7 @@ source "net/mpls/Kconfig"
 source "net/hsr/Kconfig"
 source "net/switchdev/Kconfig"
 source "net/l3mdev/Kconfig"
+source "net/qrtr/Kconfig"
 
 config RPS
        bool
@@ -351,6 +352,7 @@ source "net/can/Kconfig"
 source "net/irda/Kconfig"
 source "net/bluetooth/Kconfig"
 source "net/rxrpc/Kconfig"
+source "net/kcm/Kconfig"
 
 config FIB_RULES
        bool
index a5d04098dfce8693c46785f6c0dfa90bd23f4187..bdd14553a774f9e6ffe14adb772bfe9a20ce9bd3 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_IRDA)            += irda/
 obj-$(CONFIG_BT)               += bluetooth/
 obj-$(CONFIG_SUNRPC)           += sunrpc/
 obj-$(CONFIG_AF_RXRPC)         += rxrpc/
+obj-$(CONFIG_AF_KCM)           += kcm/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_L2TP)             += l2tp/
 obj-$(CONFIG_DECNET)           += decnet/
@@ -77,3 +78,4 @@ endif
 ifneq ($(CONFIG_NET_L3_MASTER_DEV),)
 obj-y                          += l3mdev/
 endif
+obj-$(CONFIG_QRTR)             += qrtr/
diff --git a/net/kcm/Kconfig b/net/kcm/Kconfig
new file mode 100644 (file)
index 0000000..5db94d9
--- /dev/null
@@ -0,0 +1,10 @@
+
+config AF_KCM
+       tristate "KCM sockets"
+       depends on INET
+       select BPF_SYSCALL
+       ---help---
+         KCM (Kernel Connection Multiplexor) sockets provide a method
+         for multiplexing messages of a message based application
+         protocol over kernel connectons (e.g. TCP connections).
+
diff --git a/net/kcm/Makefile b/net/kcm/Makefile
new file mode 100644 (file)
index 0000000..cb525f7
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_AF_KCM) += kcm.o
+
+kcm-y := kcmsock.o
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
new file mode 100644 (file)
index 0000000..30ef69a
--- /dev/null
@@ -0,0 +1,2016 @@
+#include <linux/bpf.h>
+#include <linux/errno.h>
+#include <linux/errqueue.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/rculist.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <net/kcm.h>
+#include <net/netns/generic.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <uapi/linux/kcm.h>
+
+unsigned int kcm_net_id;
+
+static struct kmem_cache *kcm_psockp __read_mostly;
+static struct kmem_cache *kcm_muxp __read_mostly;
+static struct workqueue_struct *kcm_wq;
+
+static inline struct kcm_sock *kcm_sk(const struct sock *sk)
+{
+       return (struct kcm_sock *)sk;
+}
+
+static inline struct kcm_tx_msg *kcm_tx_msg(struct sk_buff *skb)
+{
+       return (struct kcm_tx_msg *)skb->cb;
+}
+
+static inline struct kcm_rx_msg *kcm_rx_msg(struct sk_buff *skb)
+{
+       return (struct kcm_rx_msg *)((void *)skb->cb +
+                                    offsetof(struct qdisc_skb_cb, data));
+}
+
+static void report_csk_error(struct sock *csk, int err)
+{
+       csk->sk_err = EPIPE;
+       csk->sk_error_report(csk);
+}
+
+/* Callback lock held */
+static void kcm_abort_rx_psock(struct kcm_psock *psock, int err,
+                              struct sk_buff *skb)
+{
+       struct sock *csk = psock->sk;
+
+       /* Unrecoverable error in receive */
+
+       if (psock->rx_stopped)
+               return;
+
+       psock->rx_stopped = 1;
+
+       /* Report an error on the lower socket */
+       report_csk_error(csk, err);
+}
+
+static void kcm_abort_tx_psock(struct kcm_psock *psock, int err,
+                              bool wakeup_kcm)
+{
+       struct sock *csk = psock->sk;
+       struct kcm_mux *mux = psock->mux;
+
+       /* Unrecoverable error in transmit */
+
+       spin_lock_bh(&mux->lock);
+
+       if (psock->tx_stopped) {
+               spin_unlock_bh(&mux->lock);
+               return;
+       }
+
+       psock->tx_stopped = 1;
+
+       if (!psock->tx_kcm) {
+               /* Take off psocks_avail list */
+               list_del(&psock->psock_avail_list);
+       } else if (wakeup_kcm) {
+               /* In this case psock is being aborted while outside of
+                * write_msgs and psock is reserved. Schedule tx_work
+                * to handle the failure there. Need to commit tx_stopped
+                * before queuing work.
+                */
+               smp_mb();
+
+               queue_work(kcm_wq, &psock->tx_kcm->tx_work);
+       }
+
+       spin_unlock_bh(&mux->lock);
+
+       /* Report error on lower socket */
+       report_csk_error(csk, err);
+}
+
+static int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+
+/* KCM is ready to receive messages on its queue-- either the KCM is new or
+ * has become unblocked after being blocked on full socket buffer. Queue any
+ * pending ready messages on a psock. RX mux lock held.
+ */
+static void kcm_rcv_ready(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+       struct kcm_psock *psock;
+       struct sk_buff *skb;
+
+       if (unlikely(kcm->rx_wait || kcm->rx_psock || kcm->rx_disabled))
+               return;
+
+       while (unlikely((skb = __skb_dequeue(&mux->rx_hold_queue)))) {
+               if (kcm_queue_rcv_skb(&kcm->sk, skb)) {
+                       /* Assuming buffer limit has been reached */
+                       skb_queue_head(&mux->rx_hold_queue, skb);
+                       WARN_ON(!sk_rmem_alloc_get(&kcm->sk));
+                       return;
+               }
+       }
+
+       while (!list_empty(&mux->psocks_ready)) {
+               psock = list_first_entry(&mux->psocks_ready, struct kcm_psock,
+                                        psock_ready_list);
+
+               if (kcm_queue_rcv_skb(&kcm->sk, psock->ready_rx_msg)) {
+                       /* Assuming buffer limit has been reached */
+                       WARN_ON(!sk_rmem_alloc_get(&kcm->sk));
+                       return;
+               }
+
+               /* Consumed the ready message on the psock. Schedule rx_work to
+                * get more messages.
+                */
+               list_del(&psock->psock_ready_list);
+               psock->ready_rx_msg = NULL;
+
+               /* Commit clearing of ready_rx_msg for queuing work */
+               smp_mb();
+
+               queue_work(kcm_wq, &psock->rx_work);
+       }
+
+       /* Buffer limit is okay now, add to ready list */
+       list_add_tail(&kcm->wait_rx_list,
+                     &kcm->mux->kcm_rx_waiters);
+       kcm->rx_wait = true;
+}
+
+static void kcm_rfree(struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       struct kcm_sock *kcm = kcm_sk(sk);
+       struct kcm_mux *mux = kcm->mux;
+       unsigned int len = skb->truesize;
+
+       sk_mem_uncharge(sk, len);
+       atomic_sub(len, &sk->sk_rmem_alloc);
+
+       /* For reading rx_wait and rx_psock without holding lock */
+       smp_mb__after_atomic();
+
+       if (!kcm->rx_wait && !kcm->rx_psock &&
+           sk_rmem_alloc_get(sk) < sk->sk_rcvlowat) {
+               spin_lock_bh(&mux->rx_lock);
+               kcm_rcv_ready(kcm);
+               spin_unlock_bh(&mux->rx_lock);
+       }
+}
+
+static int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       struct sk_buff_head *list = &sk->sk_receive_queue;
+
+       if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
+               return -ENOMEM;
+
+       if (!sk_rmem_schedule(sk, skb, skb->truesize))
+               return -ENOBUFS;
+
+       skb->dev = NULL;
+
+       skb_orphan(skb);
+       skb->sk = sk;
+       skb->destructor = kcm_rfree;
+       atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+       sk_mem_charge(sk, skb->truesize);
+
+       skb_queue_tail(list, skb);
+
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk->sk_data_ready(sk);
+
+       return 0;
+}
+
+/* Requeue received messages for a kcm socket to other kcm sockets. This is
+ * called with a kcm socket is receive disabled.
+ * RX mux lock held.
+ */
+static void requeue_rx_msgs(struct kcm_mux *mux, struct sk_buff_head *head)
+{
+       struct sk_buff *skb;
+       struct kcm_sock *kcm;
+
+       while ((skb = __skb_dequeue(head))) {
+               /* Reset destructor to avoid calling kcm_rcv_ready */
+               skb->destructor = sock_rfree;
+               skb_orphan(skb);
+try_again:
+               if (list_empty(&mux->kcm_rx_waiters)) {
+                       skb_queue_tail(&mux->rx_hold_queue, skb);
+                       continue;
+               }
+
+               kcm = list_first_entry(&mux->kcm_rx_waiters,
+                                      struct kcm_sock, wait_rx_list);
+
+               if (kcm_queue_rcv_skb(&kcm->sk, skb)) {
+                       /* Should mean socket buffer full */
+                       list_del(&kcm->wait_rx_list);
+                       kcm->rx_wait = false;
+
+                       /* Commit rx_wait to read in kcm_free */
+                       smp_wmb();
+
+                       goto try_again;
+               }
+       }
+}
+
+/* Lower sock lock held */
+static struct kcm_sock *reserve_rx_kcm(struct kcm_psock *psock,
+                                      struct sk_buff *head)
+{
+       struct kcm_mux *mux = psock->mux;
+       struct kcm_sock *kcm;
+
+       WARN_ON(psock->ready_rx_msg);
+
+       if (psock->rx_kcm)
+               return psock->rx_kcm;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       if (psock->rx_kcm) {
+               spin_unlock_bh(&mux->rx_lock);
+               return psock->rx_kcm;
+       }
+
+       if (list_empty(&mux->kcm_rx_waiters)) {
+               psock->ready_rx_msg = head;
+               list_add_tail(&psock->psock_ready_list,
+                             &mux->psocks_ready);
+               spin_unlock_bh(&mux->rx_lock);
+               return NULL;
+       }
+
+       kcm = list_first_entry(&mux->kcm_rx_waiters,
+                              struct kcm_sock, wait_rx_list);
+       list_del(&kcm->wait_rx_list);
+       kcm->rx_wait = false;
+
+       psock->rx_kcm = kcm;
+       kcm->rx_psock = psock;
+
+       spin_unlock_bh(&mux->rx_lock);
+
+       return kcm;
+}
+
+static void kcm_done(struct kcm_sock *kcm);
+
+static void kcm_done_work(struct work_struct *w)
+{
+       kcm_done(container_of(w, struct kcm_sock, done_work));
+}
+
+/* Lower sock held */
+static void unreserve_rx_kcm(struct kcm_psock *psock,
+                            bool rcv_ready)
+{
+       struct kcm_sock *kcm = psock->rx_kcm;
+       struct kcm_mux *mux = psock->mux;
+
+       if (!kcm)
+               return;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       psock->rx_kcm = NULL;
+       kcm->rx_psock = NULL;
+
+       /* Commit kcm->rx_psock before sk_rmem_alloc_get to sync with
+        * kcm_rfree
+        */
+       smp_mb();
+
+       if (unlikely(kcm->done)) {
+               spin_unlock_bh(&mux->rx_lock);
+
+               /* Need to run kcm_done in a task since we need to qcquire
+                * callback locks which may already be held here.
+                */
+               INIT_WORK(&kcm->done_work, kcm_done_work);
+               schedule_work(&kcm->done_work);
+               return;
+       }
+
+       if (unlikely(kcm->rx_disabled)) {
+               requeue_rx_msgs(mux, &kcm->sk.sk_receive_queue);
+       } else if (rcv_ready || unlikely(!sk_rmem_alloc_get(&kcm->sk))) {
+               /* Check for degenerative race with rx_wait that all
+                * data was dequeued (accounted for in kcm_rfree).
+                */
+               kcm_rcv_ready(kcm);
+       }
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+/* Macro to invoke filter function. */
+#define KCM_RUN_FILTER(prog, ctx) \
+       (*prog->bpf_func)(ctx, prog->insnsi)
+
+/* Lower socket lock held */
+static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
+                       unsigned int orig_offset, size_t orig_len)
+{
+       struct kcm_psock *psock = (struct kcm_psock *)desc->arg.data;
+       struct kcm_rx_msg *rxm;
+       struct kcm_sock *kcm;
+       struct sk_buff *head, *skb;
+       size_t eaten = 0, cand_len;
+       ssize_t extra;
+       int err;
+       bool cloned_orig = false;
+
+       if (psock->ready_rx_msg)
+               return 0;
+
+       head = psock->rx_skb_head;
+       if (head) {
+               /* Message already in progress */
+
+               if (unlikely(orig_offset)) {
+                       /* Getting data with a non-zero offset when a message is
+                        * in progress is not expected. If it does happen, we
+                        * need to clone and pull since we can't deal with
+                        * offsets in the skbs for a message expect in the head.
+                        */
+                       orig_skb = skb_clone(orig_skb, GFP_ATOMIC);
+                       if (!orig_skb) {
+                               desc->error = -ENOMEM;
+                               return 0;
+                       }
+                       if (!pskb_pull(orig_skb, orig_offset)) {
+                               kfree_skb(orig_skb);
+                               desc->error = -ENOMEM;
+                               return 0;
+                       }
+                       cloned_orig = true;
+                       orig_offset = 0;
+               }
+
+               if (!psock->rx_skb_nextp) {
+                       /* We are going to append to the frags_list of head.
+                        * Need to unshare the frag_list.
+                        */
+                       err = skb_unclone(head, GFP_ATOMIC);
+                       if (err) {
+                               desc->error = err;
+                               return 0;
+                       }
+
+                       if (unlikely(skb_shinfo(head)->frag_list)) {
+                               /* We can't append to an sk_buff that already
+                                * has a frag_list. We create a new head, point
+                                * the frag_list of that to the old head, and
+                                * then are able to use the old head->next for
+                                * appending to the message.
+                                */
+                               if (WARN_ON(head->next)) {
+                                       desc->error = -EINVAL;
+                                       return 0;
+                               }
+
+                               skb = alloc_skb(0, GFP_ATOMIC);
+                               if (!skb) {
+                                       desc->error = -ENOMEM;
+                                       return 0;
+                               }
+                               skb->len = head->len;
+                               skb->data_len = head->len;
+                               skb->truesize = head->truesize;
+                               *kcm_rx_msg(skb) = *kcm_rx_msg(head);
+                               psock->rx_skb_nextp = &head->next;
+                               skb_shinfo(skb)->frag_list = head;
+                               psock->rx_skb_head = skb;
+                               head = skb;
+                       } else {
+                               psock->rx_skb_nextp =
+                                   &skb_shinfo(head)->frag_list;
+                       }
+               }
+       }
+
+       while (eaten < orig_len) {
+               /* Always clone since we will consume something */
+               skb = skb_clone(orig_skb, GFP_ATOMIC);
+               if (!skb) {
+                       desc->error = -ENOMEM;
+                       break;
+               }
+
+               cand_len = orig_len - eaten;
+
+               head = psock->rx_skb_head;
+               if (!head) {
+                       head = skb;
+                       psock->rx_skb_head = head;
+                       /* Will set rx_skb_nextp on next packet if needed */
+                       psock->rx_skb_nextp = NULL;
+                       rxm = kcm_rx_msg(head);
+                       memset(rxm, 0, sizeof(*rxm));
+                       rxm->offset = orig_offset + eaten;
+               } else {
+                       /* Unclone since we may be appending to an skb that we
+                        * already share a frag_list with.
+                        */
+                       err = skb_unclone(skb, GFP_ATOMIC);
+                       if (err) {
+                               desc->error = err;
+                               break;
+                       }
+
+                       rxm = kcm_rx_msg(head);
+                       *psock->rx_skb_nextp = skb;
+                       psock->rx_skb_nextp = &skb->next;
+                       head->data_len += skb->len;
+                       head->len += skb->len;
+                       head->truesize += skb->truesize;
+               }
+
+               if (!rxm->full_len) {
+                       ssize_t len;
+
+                       len = KCM_RUN_FILTER(psock->bpf_prog, head);
+
+                       if (!len) {
+                               /* Need more header to determine length */
+                               rxm->accum_len += cand_len;
+                               eaten += cand_len;
+                               WARN_ON(eaten != orig_len);
+                               break;
+                       } else if (len <= (ssize_t)head->len -
+                                         skb->len - rxm->offset) {
+                               /* Length must be into new skb (and also
+                                * greater than zero)
+                                */
+                               desc->error = -EPROTO;
+                               psock->rx_skb_head = NULL;
+                               kcm_abort_rx_psock(psock, EPROTO, head);
+                               break;
+                       }
+
+                       rxm->full_len = len;
+               }
+
+               extra = (ssize_t)(rxm->accum_len + cand_len) - rxm->full_len;
+
+               if (extra < 0) {
+                       /* Message not complete yet. */
+                       rxm->accum_len += cand_len;
+                       eaten += cand_len;
+                       WARN_ON(eaten != orig_len);
+                       break;
+               }
+
+               /* Positive extra indicates ore bytes than needed for the
+                * message
+                */
+
+               WARN_ON(extra > cand_len);
+
+               eaten += (cand_len - extra);
+
+               /* Hurray, we have a new message! */
+               psock->rx_skb_head = NULL;
+
+try_queue:
+               kcm = reserve_rx_kcm(psock, head);
+               if (!kcm) {
+                       /* Unable to reserve a KCM, message is held in psock. */
+                       break;
+               }
+
+               if (kcm_queue_rcv_skb(&kcm->sk, head)) {
+                       /* Should mean socket buffer full */
+                       unreserve_rx_kcm(psock, false);
+                       goto try_queue;
+               }
+       }
+
+       if (cloned_orig)
+               kfree_skb(orig_skb);
+
+       return eaten;
+}
+
+/* Called with lock held on lower socket */
+static int psock_tcp_read_sock(struct kcm_psock *psock)
+{
+       read_descriptor_t desc;
+
+       desc.arg.data = psock;
+       desc.error = 0;
+       desc.count = 1; /* give more than one skb per call */
+
+       /* sk should be locked here, so okay to do tcp_read_sock */
+       tcp_read_sock(psock->sk, &desc, kcm_tcp_recv);
+
+       unreserve_rx_kcm(psock, true);
+
+       return desc.error;
+}
+
+/* Lower sock lock held */
+static void psock_tcp_data_ready(struct sock *sk)
+{
+       struct kcm_psock *psock;
+
+       read_lock_bh(&sk->sk_callback_lock);
+
+       psock = (struct kcm_psock *)sk->sk_user_data;
+       if (unlikely(!psock || psock->rx_stopped))
+               goto out;
+
+       if (psock->ready_rx_msg)
+               goto out;
+
+       if (psock_tcp_read_sock(psock) == -ENOMEM)
+               queue_delayed_work(kcm_wq, &psock->rx_delayed_work, 0);
+
+out:
+       read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void do_psock_rx_work(struct kcm_psock *psock)
+{
+       read_descriptor_t rd_desc;
+       struct sock *csk = psock->sk;
+
+       /* We need the read lock to synchronize with psock_tcp_data_ready. We
+        * need the socket lock for calling tcp_read_sock.
+        */
+       lock_sock(csk);
+       read_lock_bh(&csk->sk_callback_lock);
+
+       if (unlikely(csk->sk_user_data != psock))
+               goto out;
+
+       if (unlikely(psock->rx_stopped))
+               goto out;
+
+       if (psock->ready_rx_msg)
+               goto out;
+
+       rd_desc.arg.data = psock;
+
+       if (psock_tcp_read_sock(psock) == -ENOMEM)
+               queue_delayed_work(kcm_wq, &psock->rx_delayed_work, 0);
+
+out:
+       read_unlock_bh(&csk->sk_callback_lock);
+       release_sock(csk);
+}
+
+static void psock_rx_work(struct work_struct *w)
+{
+       do_psock_rx_work(container_of(w, struct kcm_psock, rx_work));
+}
+
+static void psock_rx_delayed_work(struct work_struct *w)
+{
+       do_psock_rx_work(container_of(w, struct kcm_psock,
+                                     rx_delayed_work.work));
+}
+
+static void psock_tcp_state_change(struct sock *sk)
+{
+       /* TCP only does a POLLIN for a half close. Do a POLLHUP here
+        * since application will normally not poll with POLLIN
+        * on the TCP sockets.
+        */
+
+       report_csk_error(sk, EPIPE);
+}
+
+static void psock_tcp_write_space(struct sock *sk)
+{
+       struct kcm_psock *psock;
+       struct kcm_mux *mux;
+       struct kcm_sock *kcm;
+
+       read_lock_bh(&sk->sk_callback_lock);
+
+       psock = (struct kcm_psock *)sk->sk_user_data;
+       if (unlikely(!psock))
+               goto out;
+
+       mux = psock->mux;
+
+       spin_lock_bh(&mux->lock);
+
+       /* Check if the socket is reserved so someone is waiting for sending. */
+       kcm = psock->tx_kcm;
+       if (kcm)
+               queue_work(kcm_wq, &kcm->tx_work);
+
+       spin_unlock_bh(&mux->lock);
+out:
+       read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void unreserve_psock(struct kcm_sock *kcm);
+
+/* kcm sock is locked. */
+static struct kcm_psock *reserve_psock(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+       struct kcm_psock *psock;
+
+       psock = kcm->tx_psock;
+
+       smp_rmb(); /* Must read tx_psock before tx_wait */
+
+       if (psock) {
+               WARN_ON(kcm->tx_wait);
+               if (unlikely(psock->tx_stopped))
+                       unreserve_psock(kcm);
+               else
+                       return kcm->tx_psock;
+       }
+
+       spin_lock_bh(&mux->lock);
+
+       /* Check again under lock to see if psock was reserved for this
+        * psock via psock_unreserve.
+        */
+       psock = kcm->tx_psock;
+       if (unlikely(psock)) {
+               WARN_ON(kcm->tx_wait);
+               spin_unlock_bh(&mux->lock);
+               return kcm->tx_psock;
+       }
+
+       if (!list_empty(&mux->psocks_avail)) {
+               psock = list_first_entry(&mux->psocks_avail,
+                                        struct kcm_psock,
+                                        psock_avail_list);
+               list_del(&psock->psock_avail_list);
+               if (kcm->tx_wait) {
+                       list_del(&kcm->wait_psock_list);
+                       kcm->tx_wait = false;
+               }
+               kcm->tx_psock = psock;
+               psock->tx_kcm = kcm;
+       } else if (!kcm->tx_wait) {
+               list_add_tail(&kcm->wait_psock_list,
+                             &mux->kcm_tx_waiters);
+               kcm->tx_wait = true;
+       }
+
+       spin_unlock_bh(&mux->lock);
+
+       return psock;
+}
+
+/* mux lock held */
+static void psock_now_avail(struct kcm_psock *psock)
+{
+       struct kcm_mux *mux = psock->mux;
+       struct kcm_sock *kcm;
+
+       if (list_empty(&mux->kcm_tx_waiters)) {
+               list_add_tail(&psock->psock_avail_list,
+                             &mux->psocks_avail);
+       } else {
+               kcm = list_first_entry(&mux->kcm_tx_waiters,
+                                      struct kcm_sock,
+                                      wait_psock_list);
+               list_del(&kcm->wait_psock_list);
+               kcm->tx_wait = false;
+               psock->tx_kcm = kcm;
+
+               /* Commit before changing tx_psock since that is read in
+                * reserve_psock before queuing work.
+                */
+               smp_mb();
+
+               kcm->tx_psock = psock;
+               queue_work(kcm_wq, &kcm->tx_work);
+       }
+}
+
+/* kcm sock is locked. */
+static void unreserve_psock(struct kcm_sock *kcm)
+{
+       struct kcm_psock *psock;
+       struct kcm_mux *mux = kcm->mux;
+
+       spin_lock_bh(&mux->lock);
+
+       psock = kcm->tx_psock;
+
+       if (WARN_ON(!psock)) {
+               spin_unlock_bh(&mux->lock);
+               return;
+       }
+
+       smp_rmb(); /* Read tx_psock before tx_wait */
+
+       WARN_ON(kcm->tx_wait);
+
+       kcm->tx_psock = NULL;
+       psock->tx_kcm = NULL;
+
+       if (unlikely(psock->tx_stopped)) {
+               if (psock->done) {
+                       /* Deferred free */
+                       list_del(&psock->psock_list);
+                       mux->psocks_cnt--;
+                       sock_put(psock->sk);
+                       fput(psock->sk->sk_socket->file);
+                       kmem_cache_free(kcm_psockp, psock);
+               }
+
+               /* Don't put back on available list */
+
+               spin_unlock_bh(&mux->lock);
+
+               return;
+       }
+
+       psock_now_avail(psock);
+
+       spin_unlock_bh(&mux->lock);
+}
+
+/* Write any messages ready on the kcm socket.  Called with kcm sock lock
+ * held.  Return bytes actually sent or error.
+ */
+static int kcm_write_msgs(struct kcm_sock *kcm)
+{
+       struct sock *sk = &kcm->sk;
+       struct kcm_psock *psock;
+       struct sk_buff *skb, *head;
+       struct kcm_tx_msg *txm;
+       unsigned short fragidx, frag_offset;
+       unsigned int sent, total_sent = 0;
+       int ret = 0;
+
+       kcm->tx_wait_more = false;
+       psock = kcm->tx_psock;
+       if (unlikely(psock && psock->tx_stopped)) {
+               /* A reserved psock was aborted asynchronously. Unreserve
+                * it and we'll retry the message.
+                */
+               unreserve_psock(kcm);
+               if (skb_queue_empty(&sk->sk_write_queue))
+                       return 0;
+
+               kcm_tx_msg(skb_peek(&sk->sk_write_queue))->sent = 0;
+
+       } else if (skb_queue_empty(&sk->sk_write_queue)) {
+               return 0;
+       }
+
+       head = skb_peek(&sk->sk_write_queue);
+       txm = kcm_tx_msg(head);
+
+       if (txm->sent) {
+               /* Send of first skbuff in queue already in progress */
+               if (WARN_ON(!psock)) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               sent = txm->sent;
+               frag_offset = txm->frag_offset;
+               fragidx = txm->fragidx;
+               skb = txm->frag_skb;
+
+               goto do_frag;
+       }
+
+try_again:
+       psock = reserve_psock(kcm);
+       if (!psock)
+               goto out;
+
+       do {
+               skb = head;
+               txm = kcm_tx_msg(head);
+               sent = 0;
+
+do_frag_list:
+               if (WARN_ON(!skb_shinfo(skb)->nr_frags)) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags;
+                    fragidx++) {
+                       skb_frag_t *frag;
+
+                       frag_offset = 0;
+do_frag:
+                       frag = &skb_shinfo(skb)->frags[fragidx];
+                       if (WARN_ON(!frag->size)) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       ret = kernel_sendpage(psock->sk->sk_socket,
+                                             frag->page.p,
+                                             frag->page_offset + frag_offset,
+                                             frag->size - frag_offset,
+                                             MSG_DONTWAIT);
+                       if (ret <= 0) {
+                               if (ret == -EAGAIN) {
+                                       /* Save state to try again when there's
+                                        * write space on the socket
+                                        */
+                                       txm->sent = sent;
+                                       txm->frag_offset = frag_offset;
+                                       txm->fragidx = fragidx;
+                                       txm->frag_skb = skb;
+
+                                       ret = 0;
+                                       goto out;
+                               }
+
+                               /* Hard failure in sending message, abort this
+                                * psock since it has lost framing
+                                * synchonization and retry sending the
+                                * message from the beginning.
+                                */
+                               kcm_abort_tx_psock(psock, ret ? -ret : EPIPE,
+                                                  true);
+                               unreserve_psock(kcm);
+
+                               txm->sent = 0;
+                               ret = 0;
+
+                               goto try_again;
+                       }
+
+                       sent += ret;
+                       frag_offset += ret;
+                       if (frag_offset < frag->size) {
+                               /* Not finished with this frag */
+                               goto do_frag;
+                       }
+               }
+
+               if (skb == head) {
+                       if (skb_has_frag_list(skb)) {
+                               skb = skb_shinfo(skb)->frag_list;
+                               goto do_frag_list;
+                       }
+               } else if (skb->next) {
+                       skb = skb->next;
+                       goto do_frag_list;
+               }
+
+               /* Successfully sent the whole packet, account for it. */
+               skb_dequeue(&sk->sk_write_queue);
+               kfree_skb(head);
+               sk->sk_wmem_queued -= sent;
+               total_sent += sent;
+       } while ((head = skb_peek(&sk->sk_write_queue)));
+out:
+       if (!head) {
+               /* Done with all queued messages. */
+               WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
+               unreserve_psock(kcm);
+       }
+
+       /* Check if write space is available */
+       sk->sk_write_space(sk);
+
+       return total_sent ? : ret;
+}
+
+static void kcm_tx_work(struct work_struct *w)
+{
+       struct kcm_sock *kcm = container_of(w, struct kcm_sock, tx_work);
+       struct sock *sk = &kcm->sk;
+       int err;
+
+       lock_sock(sk);
+
+       /* Primarily for SOCK_DGRAM sockets, also handle asynchronous tx
+        * aborts
+        */
+       err = kcm_write_msgs(kcm);
+       if (err < 0) {
+               /* Hard failure in write, report error on KCM socket */
+               pr_warn("KCM: Hard failure on kcm_write_msgs %d\n", err);
+               report_csk_error(&kcm->sk, -err);
+               goto out;
+       }
+
+       /* Primarily for SOCK_SEQPACKET sockets */
+       if (likely(sk->sk_socket) &&
+           test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
+               clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+               sk->sk_write_space(sk);
+       }
+
+out:
+       release_sock(sk);
+}
+
+static void kcm_push(struct kcm_sock *kcm)
+{
+       if (kcm->tx_wait_more)
+               kcm_write_msgs(kcm);
+}
+
+static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+{
+       struct sock *sk = sock->sk;
+       struct kcm_sock *kcm = kcm_sk(sk);
+       struct sk_buff *skb = NULL, *head = NULL;
+       size_t copy, copied = 0;
+       long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
+       int eor = (sock->type == SOCK_DGRAM) ?
+                 !(msg->msg_flags & MSG_MORE) : !!(msg->msg_flags & MSG_EOR);
+       int err = -EPIPE;
+
+       lock_sock(sk);
+
+       /* Per tcp_sendmsg this should be in poll */
+       sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
+
+       if (sk->sk_err)
+               goto out_error;
+
+       if (kcm->seq_skb) {
+               /* Previously opened message */
+               head = kcm->seq_skb;
+               skb = kcm_tx_msg(head)->last_skb;
+               goto start;
+       }
+
+       /* Call the sk_stream functions to manage the sndbuf mem. */
+       if (!sk_stream_memory_free(sk)) {
+               kcm_push(kcm);
+               set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+               err = sk_stream_wait_memory(sk, &timeo);
+               if (err)
+                       goto out_error;
+       }
+
+       /* New message, alloc head skb */
+       head = alloc_skb(0, sk->sk_allocation);
+       while (!head) {
+               kcm_push(kcm);
+               err = sk_stream_wait_memory(sk, &timeo);
+               if (err)
+                       goto out_error;
+
+               head = alloc_skb(0, sk->sk_allocation);
+       }
+
+       skb = head;
+
+       /* Set ip_summed to CHECKSUM_UNNECESSARY to avoid calling
+        * csum_and_copy_from_iter from skb_do_copy_data_nocache.
+        */
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+start:
+       while (msg_data_left(msg)) {
+               bool merge = true;
+               int i = skb_shinfo(skb)->nr_frags;
+               struct page_frag *pfrag = sk_page_frag(sk);
+
+               if (!sk_page_frag_refill(sk, pfrag))
+                       goto wait_for_memory;
+
+               if (!skb_can_coalesce(skb, i, pfrag->page,
+                                     pfrag->offset)) {
+                       if (i == MAX_SKB_FRAGS) {
+                               struct sk_buff *tskb;
+
+                               tskb = alloc_skb(0, sk->sk_allocation);
+                               if (!tskb)
+                                       goto wait_for_memory;
+
+                               if (head == skb)
+                                       skb_shinfo(head)->frag_list = tskb;
+                               else
+                                       skb->next = tskb;
+
+                               skb = tskb;
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               continue;
+                       }
+                       merge = false;
+               }
+
+               copy = min_t(int, msg_data_left(msg),
+                            pfrag->size - pfrag->offset);
+
+               if (!sk_wmem_schedule(sk, copy))
+                       goto wait_for_memory;
+
+               err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
+                                              pfrag->page,
+                                              pfrag->offset,
+                                              copy);
+               if (err)
+                       goto out_error;
+
+               /* Update the skb. */
+               if (merge) {
+                       skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
+               } else {
+                       skb_fill_page_desc(skb, i, pfrag->page,
+                                          pfrag->offset, copy);
+                       get_page(pfrag->page);
+               }
+
+               pfrag->offset += copy;
+               copied += copy;
+               if (head != skb) {
+                       head->len += copy;
+                       head->data_len += copy;
+               }
+
+               continue;
+
+wait_for_memory:
+               kcm_push(kcm);
+               err = sk_stream_wait_memory(sk, &timeo);
+               if (err)
+                       goto out_error;
+       }
+
+       if (eor) {
+               bool not_busy = skb_queue_empty(&sk->sk_write_queue);
+
+               /* Message complete, queue it on send buffer */
+               __skb_queue_tail(&sk->sk_write_queue, head);
+               kcm->seq_skb = NULL;
+
+               if (msg->msg_flags & MSG_BATCH) {
+                       kcm->tx_wait_more = true;
+               } else if (kcm->tx_wait_more || not_busy) {
+                       err = kcm_write_msgs(kcm);
+                       if (err < 0) {
+                               /* We got a hard error in write_msgs but have
+                                * already queued this message. Report an error
+                                * in the socket, but don't affect return value
+                                * from sendmsg
+                                */
+                               pr_warn("KCM: Hard failure on kcm_write_msgs\n");
+                               report_csk_error(&kcm->sk, -err);
+                       }
+               }
+       } else {
+               /* Message not complete, save state */
+partial_message:
+               kcm->seq_skb = head;
+               kcm_tx_msg(head)->last_skb = skb;
+       }
+
+       release_sock(sk);
+       return copied;
+
+out_error:
+       kcm_push(kcm);
+
+       if (copied && sock->type == SOCK_SEQPACKET) {
+               /* Wrote some bytes before encountering an
+                * error, return partial success.
+                */
+               goto partial_message;
+       }
+
+       if (head != kcm->seq_skb)
+               kfree_skb(head);
+
+       err = sk_stream_error(sk, msg->msg_flags, err);
+
+       /* make sure we wake any epoll edge trigger waiter */
+       if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
+               sk->sk_write_space(sk);
+
+       release_sock(sk);
+       return err;
+}
+
+static struct sk_buff *kcm_wait_data(struct sock *sk, int flags,
+                                    long timeo, int *err)
+{
+       struct sk_buff *skb;
+
+       while (!(skb = skb_peek(&sk->sk_receive_queue))) {
+               if (sk->sk_err) {
+                       *err = sock_error(sk);
+                       return NULL;
+               }
+
+               if (sock_flag(sk, SOCK_DONE))
+                       return NULL;
+
+               if ((flags & MSG_DONTWAIT) || !timeo) {
+                       *err = -EAGAIN;
+                       return NULL;
+               }
+
+               sk_wait_data(sk, &timeo, NULL);
+
+               /* Handle signals */
+               if (signal_pending(current)) {
+                       *err = sock_intr_errno(timeo);
+                       return NULL;
+               }
+       }
+
+       return skb;
+}
+
+static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
+                      size_t len, int flags)
+{
+       struct sock *sk = sock->sk;
+       int err = 0;
+       long timeo;
+       struct kcm_rx_msg *rxm;
+       int copied = 0;
+       struct sk_buff *skb;
+
+       timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
+       lock_sock(sk);
+
+       skb = kcm_wait_data(sk, flags, timeo, &err);
+       if (!skb)
+               goto out;
+
+       /* Okay, have a message on the receive queue */
+
+       rxm = kcm_rx_msg(skb);
+
+       if (len > rxm->full_len)
+               len = rxm->full_len;
+
+       err = skb_copy_datagram_msg(skb, rxm->offset, msg, len);
+       if (err < 0)
+               goto out;
+
+       copied = len;
+       if (likely(!(flags & MSG_PEEK))) {
+               if (copied < rxm->full_len) {
+                       if (sock->type == SOCK_DGRAM) {
+                               /* Truncated message */
+                               msg->msg_flags |= MSG_TRUNC;
+                               goto msg_finished;
+                       }
+                       rxm->offset += copied;
+                       rxm->full_len -= copied;
+               } else {
+msg_finished:
+                       /* Finished with message */
+                       msg->msg_flags |= MSG_EOR;
+                       skb_unlink(skb, &sk->sk_receive_queue);
+                       kfree_skb(skb);
+               }
+       }
+
+out:
+       release_sock(sk);
+
+       return copied ? : err;
+}
+
+/* kcm sock lock held */
+static void kcm_recv_disable(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+
+       if (kcm->rx_disabled)
+               return;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       kcm->rx_disabled = 1;
+
+       /* If a psock is reserved we'll do cleanup in unreserve */
+       if (!kcm->rx_psock) {
+               if (kcm->rx_wait) {
+                       list_del(&kcm->wait_rx_list);
+                       kcm->rx_wait = false;
+               }
+
+               requeue_rx_msgs(mux, &kcm->sk.sk_receive_queue);
+       }
+
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+/* kcm sock lock held */
+static void kcm_recv_enable(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+
+       if (!kcm->rx_disabled)
+               return;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       kcm->rx_disabled = 0;
+       kcm_rcv_ready(kcm);
+
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+static int kcm_setsockopt(struct socket *sock, int level, int optname,
+                         char __user *optval, unsigned int optlen)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       int val, valbool;
+       int err = 0;
+
+       if (level != SOL_KCM)
+               return -ENOPROTOOPT;
+
+       if (optlen < sizeof(int))
+               return -EINVAL;
+
+       if (get_user(val, (int __user *)optval))
+               return -EINVAL;
+
+       valbool = val ? 1 : 0;
+
+       switch (optname) {
+       case KCM_RECV_DISABLE:
+               lock_sock(&kcm->sk);
+               if (valbool)
+                       kcm_recv_disable(kcm);
+               else
+                       kcm_recv_enable(kcm);
+               release_sock(&kcm->sk);
+               break;
+       default:
+               err = -ENOPROTOOPT;
+       }
+
+       return err;
+}
+
+static int kcm_getsockopt(struct socket *sock, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       int val, len;
+
+       if (level != SOL_KCM)
+               return -ENOPROTOOPT;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       len = min_t(unsigned int, len, sizeof(int));
+       if (len < 0)
+               return -EINVAL;
+
+       switch (optname) {
+       case KCM_RECV_DISABLE:
+               val = kcm->rx_disabled;
+               break;
+       default:
+               return -ENOPROTOOPT;
+       }
+
+       if (put_user(len, optlen))
+               return -EFAULT;
+       if (copy_to_user(optval, &val, len))
+               return -EFAULT;
+       return 0;
+}
+
+static void init_kcm_sock(struct kcm_sock *kcm, struct kcm_mux *mux)
+{
+       struct kcm_sock *tkcm;
+       struct list_head *head;
+       int index = 0;
+
+       /* For SOCK_SEQPACKET sock type, datagram_poll checks the sk_state, so
+        * we set sk_state, otherwise epoll_wait always returns right away with
+        * POLLHUP
+        */
+       kcm->sk.sk_state = TCP_ESTABLISHED;
+
+       /* Add to mux's kcm sockets list */
+       kcm->mux = mux;
+       spin_lock_bh(&mux->lock);
+
+       head = &mux->kcm_socks;
+       list_for_each_entry(tkcm, &mux->kcm_socks, kcm_sock_list) {
+               if (tkcm->index != index)
+                       break;
+               head = &tkcm->kcm_sock_list;
+               index++;
+       }
+
+       list_add(&kcm->kcm_sock_list, head);
+       kcm->index = index;
+
+       mux->kcm_socks_cnt++;
+       spin_unlock_bh(&mux->lock);
+
+       INIT_WORK(&kcm->tx_work, kcm_tx_work);
+
+       spin_lock_bh(&mux->rx_lock);
+       kcm_rcv_ready(kcm);
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+static int kcm_attach(struct socket *sock, struct socket *csock,
+                     struct bpf_prog *prog)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       struct kcm_mux *mux = kcm->mux;
+       struct sock *csk;
+       struct kcm_psock *psock = NULL, *tpsock;
+       struct list_head *head;
+       int index = 0;
+
+       if (csock->ops->family != PF_INET &&
+           csock->ops->family != PF_INET6)
+               return -EINVAL;
+
+       csk = csock->sk;
+       if (!csk)
+               return -EINVAL;
+
+       /* Only support TCP for now */
+       if (csk->sk_protocol != IPPROTO_TCP)
+               return -EINVAL;
+
+       psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
+       if (!psock)
+               return -ENOMEM;
+
+       psock->mux = mux;
+       psock->sk = csk;
+       psock->bpf_prog = prog;
+       INIT_WORK(&psock->rx_work, psock_rx_work);
+       INIT_DELAYED_WORK(&psock->rx_delayed_work, psock_rx_delayed_work);
+
+       sock_hold(csk);
+
+       write_lock_bh(&csk->sk_callback_lock);
+       psock->save_data_ready = csk->sk_data_ready;
+       psock->save_write_space = csk->sk_write_space;
+       psock->save_state_change = csk->sk_state_change;
+       csk->sk_user_data = psock;
+       csk->sk_data_ready = psock_tcp_data_ready;
+       csk->sk_write_space = psock_tcp_write_space;
+       csk->sk_state_change = psock_tcp_state_change;
+       write_unlock_bh(&csk->sk_callback_lock);
+
+       /* Finished initialization, now add the psock to the MUX. */
+       spin_lock_bh(&mux->lock);
+       head = &mux->psocks;
+       list_for_each_entry(tpsock, &mux->psocks, psock_list) {
+               if (tpsock->index != index)
+                       break;
+               head = &tpsock->psock_list;
+               index++;
+       }
+
+       list_add(&psock->psock_list, head);
+       psock->index = index;
+
+       mux->psocks_cnt++;
+       psock_now_avail(psock);
+       spin_unlock_bh(&mux->lock);
+
+       /* Schedule RX work in case there are already bytes queued */
+       queue_work(kcm_wq, &psock->rx_work);
+
+       return 0;
+}
+
+static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info)
+{
+       struct socket *csock;
+       struct bpf_prog *prog;
+       int err;
+
+       csock = sockfd_lookup(info->fd, &err);
+       if (!csock)
+               return -ENOENT;
+
+       prog = bpf_prog_get(info->bpf_fd);
+       if (IS_ERR(prog)) {
+               err = PTR_ERR(prog);
+               goto out;
+       }
+
+       if (prog->type != BPF_PROG_TYPE_SOCKET_FILTER) {
+               bpf_prog_put(prog);
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = kcm_attach(sock, csock, prog);
+       if (err) {
+               bpf_prog_put(prog);
+               goto out;
+       }
+
+       /* Keep reference on file also */
+
+       return 0;
+out:
+       fput(csock->file);
+       return err;
+}
+
+static void kcm_unattach(struct kcm_psock *psock)
+{
+       struct sock *csk = psock->sk;
+       struct kcm_mux *mux = psock->mux;
+
+       /* Stop getting callbacks from TCP socket. After this there should
+        * be no way to reserve a kcm for this psock.
+        */
+       write_lock_bh(&csk->sk_callback_lock);
+       csk->sk_user_data = NULL;
+       csk->sk_data_ready = psock->save_data_ready;
+       csk->sk_write_space = psock->save_write_space;
+       csk->sk_state_change = psock->save_state_change;
+       psock->rx_stopped = 1;
+
+       if (WARN_ON(psock->rx_kcm)) {
+               write_unlock_bh(&csk->sk_callback_lock);
+               return;
+       }
+
+       spin_lock_bh(&mux->rx_lock);
+
+       /* Stop receiver activities. After this point psock should not be
+        * able to get onto ready list either through callbacks or work.
+        */
+       if (psock->ready_rx_msg) {
+               list_del(&psock->psock_ready_list);
+               kfree_skb(psock->ready_rx_msg);
+               psock->ready_rx_msg = NULL;
+       }
+
+       spin_unlock_bh(&mux->rx_lock);
+
+       write_unlock_bh(&csk->sk_callback_lock);
+
+       cancel_work_sync(&psock->rx_work);
+       cancel_delayed_work_sync(&psock->rx_delayed_work);
+
+       bpf_prog_put(psock->bpf_prog);
+
+       kfree_skb(psock->rx_skb_head);
+       psock->rx_skb_head = NULL;
+
+       spin_lock_bh(&mux->lock);
+
+       if (psock->tx_kcm) {
+               /* psock was reserved.  Just mark it finished and we will clean
+                * up in the kcm paths, we need kcm lock which can not be
+                * acquired here.
+                */
+               spin_unlock_bh(&mux->lock);
+
+               /* We are unattaching a socket that is reserved. Abort the
+                * socket since we may be out of sync in sending on it. We need
+                * to do this without the mux lock.
+                */
+               kcm_abort_tx_psock(psock, EPIPE, false);
+
+               spin_lock_bh(&mux->lock);
+               if (!psock->tx_kcm) {
+                       /* psock now unreserved in window mux was unlocked */
+                       goto no_reserved;
+               }
+               psock->done = 1;
+
+               /* Commit done before queuing work to process it */
+               smp_mb();
+
+               /* Queue tx work to make sure psock->done is handled */
+               queue_work(kcm_wq, &psock->tx_kcm->tx_work);
+               spin_unlock_bh(&mux->lock);
+       } else {
+no_reserved:
+               if (!psock->tx_stopped)
+                       list_del(&psock->psock_avail_list);
+               list_del(&psock->psock_list);
+               mux->psocks_cnt--;
+               spin_unlock_bh(&mux->lock);
+
+               sock_put(csk);
+               fput(csk->sk_socket->file);
+               kmem_cache_free(kcm_psockp, psock);
+       }
+}
+
+static int kcm_unattach_ioctl(struct socket *sock, struct kcm_unattach *info)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       struct kcm_mux *mux = kcm->mux;
+       struct kcm_psock *psock;
+       struct socket *csock;
+       struct sock *csk;
+       int err;
+
+       csock = sockfd_lookup(info->fd, &err);
+       if (!csock)
+               return -ENOENT;
+
+       csk = csock->sk;
+       if (!csk) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = -ENOENT;
+
+       spin_lock_bh(&mux->lock);
+
+       list_for_each_entry(psock, &mux->psocks, psock_list) {
+               if (psock->sk != csk)
+                       continue;
+
+               /* Found the matching psock */
+
+               if (psock->unattaching || WARN_ON(psock->done)) {
+                       err = -EALREADY;
+                       break;
+               }
+
+               psock->unattaching = 1;
+
+               spin_unlock_bh(&mux->lock);
+
+               kcm_unattach(psock);
+
+               err = 0;
+               goto out;
+       }
+
+       spin_unlock_bh(&mux->lock);
+
+out:
+       fput(csock->file);
+       return err;
+}
+
+static struct proto kcm_proto = {
+       .name   = "KCM",
+       .owner  = THIS_MODULE,
+       .obj_size = sizeof(struct kcm_sock),
+};
+
+/* Clone a kcm socket. */
+static int kcm_clone(struct socket *osock, struct kcm_clone *info,
+                    struct socket **newsockp)
+{
+       struct socket *newsock;
+       struct sock *newsk;
+       struct file *newfile;
+       int err, newfd;
+
+       err = -ENFILE;
+       newsock = sock_alloc();
+       if (!newsock)
+               goto out;
+
+       newsock->type = osock->type;
+       newsock->ops = osock->ops;
+
+       __module_get(newsock->ops->owner);
+
+       newfd = get_unused_fd_flags(0);
+       if (unlikely(newfd < 0)) {
+               err = newfd;
+               goto out_fd_fail;
+       }
+
+       newfile = sock_alloc_file(newsock, 0, osock->sk->sk_prot_creator->name);
+       if (unlikely(IS_ERR(newfile))) {
+               err = PTR_ERR(newfile);
+               goto out_sock_alloc_fail;
+       }
+
+       newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL,
+                        &kcm_proto, true);
+       if (!newsk) {
+               err = -ENOMEM;
+               goto out_sk_alloc_fail;
+       }
+
+       sock_init_data(newsock, newsk);
+       init_kcm_sock(kcm_sk(newsk), kcm_sk(osock->sk)->mux);
+
+       fd_install(newfd, newfile);
+       *newsockp = newsock;
+       info->fd = newfd;
+
+       return 0;
+
+out_sk_alloc_fail:
+       fput(newfile);
+out_sock_alloc_fail:
+       put_unused_fd(newfd);
+out_fd_fail:
+       sock_release(newsock);
+out:
+       return err;
+}
+
+static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       int err;
+
+       switch (cmd) {
+       case SIOCKCMATTACH: {
+               struct kcm_attach info;
+
+               if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+                       err = -EFAULT;
+
+               err = kcm_attach_ioctl(sock, &info);
+
+               break;
+       }
+       case SIOCKCMUNATTACH: {
+               struct kcm_unattach info;
+
+               if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+                       err = -EFAULT;
+
+               err = kcm_unattach_ioctl(sock, &info);
+
+               break;
+       }
+       case SIOCKCMCLONE: {
+               struct kcm_clone info;
+               struct socket *newsock = NULL;
+
+               if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+                       err = -EFAULT;
+
+               err = kcm_clone(sock, &info, &newsock);
+
+               if (!err) {
+                       if (copy_to_user((void __user *)arg, &info,
+                                        sizeof(info))) {
+                               err = -EFAULT;
+                               sock_release(newsock);
+                       }
+               }
+
+               break;
+       }
+       default:
+               err = -ENOIOCTLCMD;
+               break;
+       }
+
+       return err;
+}
+
+static void free_mux(struct rcu_head *rcu)
+{
+       struct kcm_mux *mux = container_of(rcu,
+           struct kcm_mux, rcu);
+
+       kmem_cache_free(kcm_muxp, mux);
+}
+
+static void release_mux(struct kcm_mux *mux)
+{
+       struct kcm_net *knet = mux->knet;
+       struct kcm_psock *psock, *tmp_psock;
+
+       /* Release psocks */
+       list_for_each_entry_safe(psock, tmp_psock,
+                                &mux->psocks, psock_list) {
+               if (!WARN_ON(psock->unattaching))
+                       kcm_unattach(psock);
+       }
+
+       if (WARN_ON(mux->psocks_cnt))
+               return;
+
+       __skb_queue_purge(&mux->rx_hold_queue);
+
+       mutex_lock(&knet->mutex);
+       list_del_rcu(&mux->kcm_mux_list);
+       knet->count--;
+       mutex_unlock(&knet->mutex);
+
+       call_rcu(&mux->rcu, free_mux);
+}
+
+static void kcm_done(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+       struct sock *sk = &kcm->sk;
+       int socks_cnt;
+
+       spin_lock_bh(&mux->rx_lock);
+       if (kcm->rx_psock) {
+               /* Cleanup in unreserve_rx_kcm */
+               WARN_ON(kcm->done);
+               kcm->rx_disabled = 1;
+               kcm->done = 1;
+               spin_unlock_bh(&mux->rx_lock);
+               return;
+       }
+
+       if (kcm->rx_wait) {
+               list_del(&kcm->wait_rx_list);
+               kcm->rx_wait = false;
+       }
+       /* Move any pending receive messages to other kcm sockets */
+       requeue_rx_msgs(mux, &sk->sk_receive_queue);
+
+       spin_unlock_bh(&mux->rx_lock);
+
+       if (WARN_ON(sk_rmem_alloc_get(sk)))
+               return;
+
+       /* Detach from MUX */
+       spin_lock_bh(&mux->lock);
+
+       list_del(&kcm->kcm_sock_list);
+       mux->kcm_socks_cnt--;
+       socks_cnt = mux->kcm_socks_cnt;
+
+       spin_unlock_bh(&mux->lock);
+
+       if (!socks_cnt) {
+               /* We are done with the mux now. */
+               release_mux(mux);
+       }
+
+       WARN_ON(kcm->rx_wait);
+
+       sock_put(&kcm->sk);
+}
+
+/* Called by kcm_release to close a KCM socket.
+ * If this is the last KCM socket on the MUX, destroy the MUX.
+ */
+static int kcm_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct kcm_sock *kcm;
+       struct kcm_mux *mux;
+       struct kcm_psock *psock;
+
+       if (!sk)
+               return 0;
+
+       kcm = kcm_sk(sk);
+       mux = kcm->mux;
+
+       sock_orphan(sk);
+       kfree_skb(kcm->seq_skb);
+
+       lock_sock(sk);
+       /* Purge queue under lock to avoid race condition with tx_work trying
+        * to act when queue is nonempty. If tx_work runs after this point
+        * it will just return.
+        */
+       __skb_queue_purge(&sk->sk_write_queue);
+       release_sock(sk);
+
+       spin_lock_bh(&mux->lock);
+       if (kcm->tx_wait) {
+               /* Take of tx_wait list, after this point there should be no way
+                * that a psock will be assigned to this kcm.
+                */
+               list_del(&kcm->wait_psock_list);
+               kcm->tx_wait = false;
+       }
+       spin_unlock_bh(&mux->lock);
+
+       /* Cancel work. After this point there should be no outside references
+        * to the kcm socket.
+        */
+       cancel_work_sync(&kcm->tx_work);
+
+       lock_sock(sk);
+       psock = kcm->tx_psock;
+       if (psock) {
+               /* A psock was reserved, so we need to kill it since it
+                * may already have some bytes queued from a message. We
+                * need to do this after removing kcm from tx_wait list.
+                */
+               kcm_abort_tx_psock(psock, EPIPE, false);
+               unreserve_psock(kcm);
+       }
+       release_sock(sk);
+
+       WARN_ON(kcm->tx_wait);
+       WARN_ON(kcm->tx_psock);
+
+       sock->sk = NULL;
+
+       kcm_done(kcm);
+
+       return 0;
+}
+
+static const struct proto_ops kcm_ops = {
+       .family =       PF_KCM,
+       .owner =        THIS_MODULE,
+       .release =      kcm_release,
+       .bind =         sock_no_bind,
+       .connect =      sock_no_connect,
+       .socketpair =   sock_no_socketpair,
+       .accept =       sock_no_accept,
+       .getname =      sock_no_getname,
+       .poll =         datagram_poll,
+       .ioctl =        kcm_ioctl,
+       .listen =       sock_no_listen,
+       .shutdown =     sock_no_shutdown,
+       .setsockopt =   kcm_setsockopt,
+       .getsockopt =   kcm_getsockopt,
+       .sendmsg =      kcm_sendmsg,
+       .recvmsg =      kcm_recvmsg,
+       .mmap =         sock_no_mmap,
+       .sendpage =     sock_no_sendpage,
+};
+
+/* Create proto operation for kcm sockets */
+static int kcm_create(struct net *net, struct socket *sock,
+                     int protocol, int kern)
+{
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+       struct sock *sk;
+       struct kcm_mux *mux;
+
+       switch (sock->type) {
+       case SOCK_DGRAM:
+       case SOCK_SEQPACKET:
+               sock->ops = &kcm_ops;
+               break;
+       default:
+               return -ESOCKTNOSUPPORT;
+       }
+
+       if (protocol != KCMPROTO_CONNECTED)
+               return -EPROTONOSUPPORT;
+
+       sk = sk_alloc(net, PF_KCM, GFP_KERNEL, &kcm_proto, kern);
+       if (!sk)
+               return -ENOMEM;
+
+       /* Allocate a kcm mux, shared between KCM sockets */
+       mux = kmem_cache_zalloc(kcm_muxp, GFP_KERNEL);
+       if (!mux) {
+               sk_free(sk);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&mux->lock);
+       spin_lock_init(&mux->rx_lock);
+       INIT_LIST_HEAD(&mux->kcm_socks);
+       INIT_LIST_HEAD(&mux->kcm_rx_waiters);
+       INIT_LIST_HEAD(&mux->kcm_tx_waiters);
+
+       INIT_LIST_HEAD(&mux->psocks);
+       INIT_LIST_HEAD(&mux->psocks_ready);
+       INIT_LIST_HEAD(&mux->psocks_avail);
+
+       mux->knet = knet;
+
+       /* Add new MUX to list */
+       mutex_lock(&knet->mutex);
+       list_add_rcu(&mux->kcm_mux_list, &knet->mux_list);
+       knet->count++;
+       mutex_unlock(&knet->mutex);
+
+       skb_queue_head_init(&mux->rx_hold_queue);
+
+       /* Init KCM socket */
+       sock_init_data(sock, sk);
+       init_kcm_sock(kcm_sk(sk), mux);
+
+       return 0;
+}
+
+static struct net_proto_family kcm_family_ops = {
+       .family = PF_KCM,
+       .create = kcm_create,
+       .owner  = THIS_MODULE,
+};
+
+static __net_init int kcm_init_net(struct net *net)
+{
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+
+       INIT_LIST_HEAD_RCU(&knet->mux_list);
+       mutex_init(&knet->mutex);
+
+       return 0;
+}
+
+static __net_exit void kcm_exit_net(struct net *net)
+{
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+
+       /* All KCM sockets should be closed at this point, which should mean
+        * that all multiplexors and psocks have been destroyed.
+        */
+       WARN_ON(!list_empty(&knet->mux_list));
+}
+
+static struct pernet_operations kcm_net_ops = {
+       .init = kcm_init_net,
+       .exit = kcm_exit_net,
+       .id   = &kcm_net_id,
+       .size = sizeof(struct kcm_net),
+};
+
+static int __init kcm_init(void)
+{
+       int err = -ENOMEM;
+
+       kcm_muxp = kmem_cache_create("kcm_mux_cache",
+                                    sizeof(struct kcm_mux), 0,
+                                    SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+       if (!kcm_muxp)
+               goto fail;
+
+       kcm_psockp = kmem_cache_create("kcm_psock_cache",
+                                      sizeof(struct kcm_psock), 0,
+                                       SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+       if (!kcm_psockp)
+               goto fail;
+
+       kcm_wq = create_singlethread_workqueue("kkcmd");
+       if (!kcm_wq)
+               goto fail;
+
+       err = proto_register(&kcm_proto, 1);
+       if (err)
+               goto fail;
+
+       err = sock_register(&kcm_family_ops);
+       if (err)
+               goto sock_register_fail;
+
+       err = register_pernet_device(&kcm_net_ops);
+       if (err)
+               goto net_ops_fail;
+
+       return 0;
+
+net_ops_fail:
+       sock_unregister(PF_KCM);
+
+sock_register_fail:
+       proto_unregister(&kcm_proto);
+
+fail:
+       kmem_cache_destroy(kcm_muxp);
+       kmem_cache_destroy(kcm_psockp);
+
+       if (kcm_wq)
+               destroy_workqueue(kcm_wq);
+
+       return err;
+}
+
+static void __exit kcm_exit(void)
+{
+       unregister_pernet_device(&kcm_net_ops);
+       sock_unregister(PF_KCM);
+       proto_unregister(&kcm_proto);
+       destroy_workqueue(kcm_wq);
+
+       kmem_cache_destroy(kcm_muxp);
+       kmem_cache_destroy(kcm_psockp);
+}
+
+module_init(kcm_init);
+module_exit(kcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_KCM);
+
diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig
new file mode 100644 (file)
index 0000000..b83c680
--- /dev/null
@@ -0,0 +1,24 @@
+# Qualcomm IPC Router configuration
+#
+
+config QRTR
+       tristate "Qualcomm IPC Router support"
+       depends on ARCH_QCOM || COMPILE_TEST
+       ---help---
+         Say Y if you intend to use Qualcomm IPC router protocol.  The
+         protocol is used to communicate with services provided by other
+         hardware blocks in the system.
+
+         In order to do service lookups, a userspace daemon is required to
+         maintain a service listing.
+
+if QRTR
+
+config QRTR_SMD
+       tristate "SMD IPC Router channels"
+       depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n)
+       ---help---
+         Say Y here to support SMD based ipcrouter channels.  SMD is the
+         most common transport for IPC Router.
+
+endif # QRTR
diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile
new file mode 100644 (file)
index 0000000..ab09e40
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_QRTR) := qrtr.o
+
+obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o
+qrtr-smd-y     := smd.o
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
new file mode 100644 (file)
index 0000000..c985ecb
--- /dev/null
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ * 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/module.h>
+#include <linux/netlink.h>
+#include <linux/qrtr.h>
+#include <linux/termios.h>     /* For TIOCINQ/OUTQ */
+
+#include <net/sock.h>
+
+#include "qrtr.h"
+
+#define QRTR_PROTO_VER 1
+
+/* auto-bind range */
+#define QRTR_MIN_EPH_SOCKET 0x4000
+#define QRTR_MAX_EPH_SOCKET 0x7fff
+
+enum qrtr_pkt_type {
+       QRTR_TYPE_DATA          = 1,
+       QRTR_TYPE_HELLO         = 2,
+       QRTR_TYPE_BYE           = 3,
+       QRTR_TYPE_NEW_SERVER    = 4,
+       QRTR_TYPE_DEL_SERVER    = 5,
+       QRTR_TYPE_DEL_CLIENT    = 6,
+       QRTR_TYPE_RESUME_TX     = 7,
+       QRTR_TYPE_EXIT          = 8,
+       QRTR_TYPE_PING          = 9,
+};
+
+/**
+ * struct qrtr_hdr - (I|R)PCrouter packet header
+ * @version: protocol version
+ * @type: packet type; one of QRTR_TYPE_*
+ * @src_node_id: source node
+ * @src_port_id: source port
+ * @confirm_rx: boolean; whether a resume-tx packet should be send in reply
+ * @size: length of packet, excluding this header
+ * @dst_node_id: destination node
+ * @dst_port_id: destination port
+ */
+struct qrtr_hdr {
+       __le32 version;
+       __le32 type;
+       __le32 src_node_id;
+       __le32 src_port_id;
+       __le32 confirm_rx;
+       __le32 size;
+       __le32 dst_node_id;
+       __le32 dst_port_id;
+} __packed;
+
+#define QRTR_HDR_SIZE sizeof(struct qrtr_hdr)
+#define QRTR_NODE_BCAST ((unsigned int)-1)
+#define QRTR_PORT_CTRL ((unsigned int)-2)
+
+struct qrtr_sock {
+       /* WARNING: sk must be the first member */
+       struct sock sk;
+       struct sockaddr_qrtr us;
+       struct sockaddr_qrtr peer;
+};
+
+static inline struct qrtr_sock *qrtr_sk(struct sock *sk)
+{
+       BUILD_BUG_ON(offsetof(struct qrtr_sock, sk) != 0);
+       return container_of(sk, struct qrtr_sock, sk);
+}
+
+static unsigned int qrtr_local_nid = -1;
+
+/* for node ids */
+static RADIX_TREE(qrtr_nodes, GFP_KERNEL);
+/* broadcast list */
+static LIST_HEAD(qrtr_all_nodes);
+/* lock for qrtr_nodes, qrtr_all_nodes and node reference */
+static DEFINE_MUTEX(qrtr_node_lock);
+
+/* local port allocation management */
+static DEFINE_IDR(qrtr_ports);
+static DEFINE_MUTEX(qrtr_port_lock);
+
+/**
+ * struct qrtr_node - endpoint node
+ * @ep_lock: lock for endpoint management and callbacks
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+ * @rx_queue: receive queue
+ * @work: scheduled work struct for recv work
+ * @item: list item for broadcast list
+ */
+struct qrtr_node {
+       struct mutex ep_lock;
+       struct qrtr_endpoint *ep;
+       struct kref ref;
+       unsigned int nid;
+
+       struct sk_buff_head rx_queue;
+       struct work_struct work;
+       struct list_head item;
+};
+
+/* Release node resources and free the node.
+ *
+ * Do not call directly, use qrtr_node_release.  To be used with
+ * kref_put_mutex.  As such, the node mutex is expected to be locked on call.
+ */
+static void __qrtr_node_release(struct kref *kref)
+{
+       struct qrtr_node *node = container_of(kref, struct qrtr_node, ref);
+
+       if (node->nid != QRTR_EP_NID_AUTO)
+               radix_tree_delete(&qrtr_nodes, node->nid);
+
+       list_del(&node->item);
+       mutex_unlock(&qrtr_node_lock);
+
+       skb_queue_purge(&node->rx_queue);
+       kfree(node);
+}
+
+/* Increment reference to node. */
+static struct qrtr_node *qrtr_node_acquire(struct qrtr_node *node)
+{
+       if (node)
+               kref_get(&node->ref);
+       return node;
+}
+
+/* Decrement reference to node and release as necessary. */
+static void qrtr_node_release(struct qrtr_node *node)
+{
+       if (!node)
+               return;
+       kref_put_mutex(&node->ref, __qrtr_node_release, &qrtr_node_lock);
+}
+
+/* Pass an outgoing packet socket buffer to the endpoint driver. */
+static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb)
+{
+       int rc = -ENODEV;
+
+       mutex_lock(&node->ep_lock);
+       if (node->ep)
+               rc = node->ep->xmit(node->ep, skb);
+       else
+               kfree_skb(skb);
+       mutex_unlock(&node->ep_lock);
+
+       return rc;
+}
+
+/* Lookup node by id.
+ *
+ * callers must release with qrtr_node_release()
+ */
+static struct qrtr_node *qrtr_node_lookup(unsigned int nid)
+{
+       struct qrtr_node *node;
+
+       mutex_lock(&qrtr_node_lock);
+       node = radix_tree_lookup(&qrtr_nodes, nid);
+       node = qrtr_node_acquire(node);
+       mutex_unlock(&qrtr_node_lock);
+
+       return node;
+}
+
+/* Assign node id to node.
+ *
+ * This is mostly useful for automatic node id assignment, based on
+ * the source id in the incoming packet.
+ */
+static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid)
+{
+       if (node->nid != QRTR_EP_NID_AUTO || nid == QRTR_EP_NID_AUTO)
+               return;
+
+       mutex_lock(&qrtr_node_lock);
+       radix_tree_insert(&qrtr_nodes, nid, node);
+       node->nid = nid;
+       mutex_unlock(&qrtr_node_lock);
+}
+
+/**
+ * qrtr_endpoint_post() - post incoming data
+ * @ep: endpoint handle
+ * @data: data pointer
+ * @len: size of data in bytes
+ *
+ * Return: 0 on success; negative error code on failure
+ */
+int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
+{
+       struct qrtr_node *node = ep->node;
+       const struct qrtr_hdr *phdr = data;
+       struct sk_buff *skb;
+       unsigned int psize;
+       unsigned int size;
+       unsigned int type;
+       unsigned int ver;
+       unsigned int dst;
+
+       if (len < QRTR_HDR_SIZE || len & 3)
+               return -EINVAL;
+
+       ver = le32_to_cpu(phdr->version);
+       size = le32_to_cpu(phdr->size);
+       type = le32_to_cpu(phdr->type);
+       dst = le32_to_cpu(phdr->dst_port_id);
+
+       psize = (size + 3) & ~3;
+
+       if (ver != QRTR_PROTO_VER)
+               return -EINVAL;
+
+       if (len != psize + QRTR_HDR_SIZE)
+               return -EINVAL;
+
+       if (dst != QRTR_PORT_CTRL && type != QRTR_TYPE_DATA)
+               return -EINVAL;
+
+       skb = netdev_alloc_skb(NULL, len);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_reset_transport_header(skb);
+       memcpy(skb_put(skb, len), data, len);
+
+       skb_queue_tail(&node->rx_queue, skb);
+       schedule_work(&node->work);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
+
+/* Allocate and construct a resume-tx packet. */
+static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
+                                           u32 dst_node, u32 port)
+{
+       const int pkt_len = 20;
+       struct qrtr_hdr *hdr;
+       struct sk_buff *skb;
+       u32 *buf;
+
+       skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL);
+       if (!skb)
+               return NULL;
+       skb_reset_transport_header(skb);
+
+       hdr = (struct qrtr_hdr *)skb_put(skb, QRTR_HDR_SIZE);
+       hdr->version = cpu_to_le32(QRTR_PROTO_VER);
+       hdr->type = cpu_to_le32(QRTR_TYPE_RESUME_TX);
+       hdr->src_node_id = cpu_to_le32(src_node);
+       hdr->src_port_id = cpu_to_le32(QRTR_PORT_CTRL);
+       hdr->confirm_rx = cpu_to_le32(0);
+       hdr->size = cpu_to_le32(pkt_len);
+       hdr->dst_node_id = cpu_to_le32(dst_node);
+       hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
+
+       buf = (u32 *)skb_put(skb, pkt_len);
+       memset(buf, 0, pkt_len);
+       buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX);
+       buf[1] = cpu_to_le32(src_node);
+       buf[2] = cpu_to_le32(port);
+
+       return skb;
+}
+
+static struct qrtr_sock *qrtr_port_lookup(int port);
+static void qrtr_port_put(struct qrtr_sock *ipc);
+
+/* Handle and route a received packet.
+ *
+ * This will auto-reply with resume-tx packet as necessary.
+ */
+static void qrtr_node_rx_work(struct work_struct *work)
+{
+       struct qrtr_node *node = container_of(work, struct qrtr_node, work);
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&node->rx_queue)) != NULL) {
+               const struct qrtr_hdr *phdr;
+               u32 dst_node, dst_port;
+               struct qrtr_sock *ipc;
+               u32 src_node;
+               int confirm;
+
+               phdr = (const struct qrtr_hdr *)skb_transport_header(skb);
+               src_node = le32_to_cpu(phdr->src_node_id);
+               dst_node = le32_to_cpu(phdr->dst_node_id);
+               dst_port = le32_to_cpu(phdr->dst_port_id);
+               confirm = !!phdr->confirm_rx;
+
+               qrtr_node_assign(node, src_node);
+
+               ipc = qrtr_port_lookup(dst_port);
+               if (!ipc) {
+                       kfree_skb(skb);
+               } else {
+                       if (sock_queue_rcv_skb(&ipc->sk, skb))
+                               kfree_skb(skb);
+
+                       qrtr_port_put(ipc);
+               }
+
+               if (confirm) {
+                       skb = qrtr_alloc_resume_tx(dst_node, node->nid, dst_port);
+                       if (!skb)
+                               break;
+                       if (qrtr_node_enqueue(node, skb))
+                               break;
+               }
+       }
+}
+
+/**
+ * qrtr_endpoint_register() - register a new endpoint
+ * @ep: endpoint to register
+ * @nid: desired node id; may be QRTR_EP_NID_AUTO for auto-assignment
+ * Return: 0 on success; negative error code on failure
+ *
+ * The specified endpoint must have the xmit function pointer set on call.
+ */
+int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+{
+       struct qrtr_node *node;
+
+       if (!ep || !ep->xmit)
+               return -EINVAL;
+
+       node = kzalloc(sizeof(*node), GFP_KERNEL);
+       if (!node)
+               return -ENOMEM;
+
+       INIT_WORK(&node->work, qrtr_node_rx_work);
+       kref_init(&node->ref);
+       mutex_init(&node->ep_lock);
+       skb_queue_head_init(&node->rx_queue);
+       node->nid = QRTR_EP_NID_AUTO;
+       node->ep = ep;
+
+       qrtr_node_assign(node, nid);
+
+       mutex_lock(&qrtr_node_lock);
+       list_add(&node->item, &qrtr_all_nodes);
+       mutex_unlock(&qrtr_node_lock);
+       ep->node = node;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qrtr_endpoint_register);
+
+/**
+ * qrtr_endpoint_unregister - unregister endpoint
+ * @ep: endpoint to unregister
+ */
+void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+{
+       struct qrtr_node *node = ep->node;
+
+       mutex_lock(&node->ep_lock);
+       node->ep = NULL;
+       mutex_unlock(&node->ep_lock);
+
+       qrtr_node_release(node);
+       ep->node = NULL;
+}
+EXPORT_SYMBOL_GPL(qrtr_endpoint_unregister);
+
+/* Lookup socket by port.
+ *
+ * Callers must release with qrtr_port_put()
+ */
+static struct qrtr_sock *qrtr_port_lookup(int port)
+{
+       struct qrtr_sock *ipc;
+
+       if (port == QRTR_PORT_CTRL)
+               port = 0;
+
+       mutex_lock(&qrtr_port_lock);
+       ipc = idr_find(&qrtr_ports, port);
+       if (ipc)
+               sock_hold(&ipc->sk);
+       mutex_unlock(&qrtr_port_lock);
+
+       return ipc;
+}
+
+/* Release acquired socket. */
+static void qrtr_port_put(struct qrtr_sock *ipc)
+{
+       sock_put(&ipc->sk);
+}
+
+/* Remove port assignment. */
+static void qrtr_port_remove(struct qrtr_sock *ipc)
+{
+       int port = ipc->us.sq_port;
+
+       if (port == QRTR_PORT_CTRL)
+               port = 0;
+
+       __sock_put(&ipc->sk);
+
+       mutex_lock(&qrtr_port_lock);
+       idr_remove(&qrtr_ports, port);
+       mutex_unlock(&qrtr_port_lock);
+}
+
+/* Assign port number to socket.
+ *
+ * Specify port in the integer pointed to by port, and it will be adjusted
+ * on return as necesssary.
+ *
+ * Port may be:
+ *   0: Assign ephemeral port in [QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET]
+ *   <QRTR_MIN_EPH_SOCKET: Specified; requires CAP_NET_ADMIN
+ *   >QRTR_MIN_EPH_SOCKET: Specified; available to all
+ */
+static int qrtr_port_assign(struct qrtr_sock *ipc, int *port)
+{
+       int rc;
+
+       mutex_lock(&qrtr_port_lock);
+       if (!*port) {
+               rc = idr_alloc(&qrtr_ports, ipc,
+                              QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET + 1,
+                              GFP_ATOMIC);
+               if (rc >= 0)
+                       *port = rc;
+       } else if (*port < QRTR_MIN_EPH_SOCKET && !capable(CAP_NET_ADMIN)) {
+               rc = -EACCES;
+       } else if (*port == QRTR_PORT_CTRL) {
+               rc = idr_alloc(&qrtr_ports, ipc, 0, 1, GFP_ATOMIC);
+       } else {
+               rc = idr_alloc(&qrtr_ports, ipc, *port, *port + 1, GFP_ATOMIC);
+               if (rc >= 0)
+                       *port = rc;
+       }
+       mutex_unlock(&qrtr_port_lock);
+
+       if (rc == -ENOSPC)
+               return -EADDRINUSE;
+       else if (rc < 0)
+               return rc;
+
+       sock_hold(&ipc->sk);
+
+       return 0;
+}
+
+/* Bind socket to address.
+ *
+ * Socket should be locked upon call.
+ */
+static int __qrtr_bind(struct socket *sock,
+                      const struct sockaddr_qrtr *addr, int zapped)
+{
+       struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+       struct sock *sk = sock->sk;
+       int port;
+       int rc;
+
+       /* rebinding ok */
+       if (!zapped && addr->sq_port == ipc->us.sq_port)
+               return 0;
+
+       port = addr->sq_port;
+       rc = qrtr_port_assign(ipc, &port);
+       if (rc)
+               return rc;
+
+       /* unbind previous, if any */
+       if (!zapped)
+               qrtr_port_remove(ipc);
+       ipc->us.sq_port = port;
+
+       sock_reset_flag(sk, SOCK_ZAPPED);
+
+       return 0;
+}
+
+/* Auto bind to an ephemeral port. */
+static int qrtr_autobind(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_qrtr addr;
+
+       if (!sock_flag(sk, SOCK_ZAPPED))
+               return 0;
+
+       addr.sq_family = AF_QIPCRTR;
+       addr.sq_node = qrtr_local_nid;
+       addr.sq_port = 0;
+
+       return __qrtr_bind(sock, &addr, 1);
+}
+
+/* Bind socket to specified sockaddr. */
+static int qrtr_bind(struct socket *sock, struct sockaddr *saddr, int len)
+{
+       DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr);
+       struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+       struct sock *sk = sock->sk;
+       int rc;
+
+       if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR)
+               return -EINVAL;
+
+       if (addr->sq_node != ipc->us.sq_node)
+               return -EINVAL;
+
+       lock_sock(sk);
+       rc = __qrtr_bind(sock, addr, sock_flag(sk, SOCK_ZAPPED));
+       release_sock(sk);
+
+       return rc;
+}
+
+/* Queue packet to local peer socket. */
+static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb)
+{
+       const struct qrtr_hdr *phdr;
+       struct qrtr_sock *ipc;
+
+       phdr = (const struct qrtr_hdr *)skb_transport_header(skb);
+
+       ipc = qrtr_port_lookup(le32_to_cpu(phdr->dst_port_id));
+       if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */
+               kfree_skb(skb);
+               return -ENODEV;
+       }
+
+       if (sock_queue_rcv_skb(&ipc->sk, skb)) {
+               qrtr_port_put(ipc);
+               kfree_skb(skb);
+               return -ENOSPC;
+       }
+
+       qrtr_port_put(ipc);
+
+       return 0;
+}
+
+/* Queue packet for broadcast. */
+static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb)
+{
+       struct sk_buff *skbn;
+
+       mutex_lock(&qrtr_node_lock);
+       list_for_each_entry(node, &qrtr_all_nodes, item) {
+               skbn = skb_clone(skb, GFP_KERNEL);
+               if (!skbn)
+                       break;
+               skb_set_owner_w(skbn, skb->sk);
+               qrtr_node_enqueue(node, skbn);
+       }
+       mutex_unlock(&qrtr_node_lock);
+
+       qrtr_local_enqueue(node, skb);
+
+       return 0;
+}
+
+static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+{
+       DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
+       int (*enqueue_fn)(struct qrtr_node *, struct sk_buff *);
+       struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+       struct sock *sk = sock->sk;
+       struct qrtr_node *node;
+       struct qrtr_hdr *hdr;
+       struct sk_buff *skb;
+       size_t plen;
+       int rc;
+
+       if (msg->msg_flags & ~(MSG_DONTWAIT))
+               return -EINVAL;
+
+       if (len > 65535)
+               return -EMSGSIZE;
+
+       lock_sock(sk);
+
+       if (addr) {
+               if (msg->msg_namelen < sizeof(*addr)) {
+                       release_sock(sk);
+                       return -EINVAL;
+               }
+
+               if (addr->sq_family != AF_QIPCRTR) {
+                       release_sock(sk);
+                       return -EINVAL;
+               }
+
+               rc = qrtr_autobind(sock);
+               if (rc) {
+                       release_sock(sk);
+                       return rc;
+               }
+       } else if (sk->sk_state == TCP_ESTABLISHED) {
+               addr = &ipc->peer;
+       } else {
+               release_sock(sk);
+               return -ENOTCONN;
+       }
+
+       node = NULL;
+       if (addr->sq_node == QRTR_NODE_BCAST) {
+               enqueue_fn = qrtr_bcast_enqueue;
+       } else if (addr->sq_node == ipc->us.sq_node) {
+               enqueue_fn = qrtr_local_enqueue;
+       } else {
+               enqueue_fn = qrtr_node_enqueue;
+               node = qrtr_node_lookup(addr->sq_node);
+               if (!node) {
+                       release_sock(sk);
+                       return -ECONNRESET;
+               }
+       }
+
+       plen = (len + 3) & ~3;
+       skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_SIZE,
+                                 msg->msg_flags & MSG_DONTWAIT, &rc);
+       if (!skb)
+               goto out_node;
+
+       skb_reset_transport_header(skb);
+       skb_put(skb, len + QRTR_HDR_SIZE);
+
+       hdr = (struct qrtr_hdr *)skb_transport_header(skb);
+       hdr->version = cpu_to_le32(QRTR_PROTO_VER);
+       hdr->src_node_id = cpu_to_le32(ipc->us.sq_node);
+       hdr->src_port_id = cpu_to_le32(ipc->us.sq_port);
+       hdr->confirm_rx = cpu_to_le32(0);
+       hdr->size = cpu_to_le32(len);
+       hdr->dst_node_id = cpu_to_le32(addr->sq_node);
+       hdr->dst_port_id = cpu_to_le32(addr->sq_port);
+
+       rc = skb_copy_datagram_from_iter(skb, QRTR_HDR_SIZE,
+                                        &msg->msg_iter, len);
+       if (rc) {
+               kfree_skb(skb);
+               goto out_node;
+       }
+
+       if (plen != len) {
+               skb_pad(skb, plen - len);
+               skb_put(skb, plen - len);
+       }
+
+       if (ipc->us.sq_port == QRTR_PORT_CTRL) {
+               if (len < 4) {
+                       rc = -EINVAL;
+                       kfree_skb(skb);
+                       goto out_node;
+               }
+
+               /* control messages already require the type as 'command' */
+               skb_copy_bits(skb, QRTR_HDR_SIZE, &hdr->type, 4);
+       } else {
+               hdr->type = cpu_to_le32(QRTR_TYPE_DATA);
+       }
+
+       rc = enqueue_fn(node, skb);
+       if (rc >= 0)
+               rc = len;
+
+out_node:
+       qrtr_node_release(node);
+       release_sock(sk);
+
+       return rc;
+}
+
+static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg,
+                       size_t size, int flags)
+{
+       DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
+       const struct qrtr_hdr *phdr;
+       struct sock *sk = sock->sk;
+       struct sk_buff *skb;
+       int copied, rc;
+
+       lock_sock(sk);
+
+       if (sock_flag(sk, SOCK_ZAPPED)) {
+               release_sock(sk);
+               return -EADDRNOTAVAIL;
+       }
+
+       skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+                               flags & MSG_DONTWAIT, &rc);
+       if (!skb) {
+               release_sock(sk);
+               return rc;
+       }
+
+       phdr = (const struct qrtr_hdr *)skb_transport_header(skb);
+       copied = le32_to_cpu(phdr->size);
+       if (copied > size) {
+               copied = size;
+               msg->msg_flags |= MSG_TRUNC;
+       }
+
+       rc = skb_copy_datagram_msg(skb, QRTR_HDR_SIZE, msg, copied);
+       if (rc < 0)
+               goto out;
+       rc = copied;
+
+       if (addr) {
+               addr->sq_family = AF_QIPCRTR;
+               addr->sq_node = le32_to_cpu(phdr->src_node_id);
+               addr->sq_port = le32_to_cpu(phdr->src_port_id);
+               msg->msg_namelen = sizeof(*addr);
+       }
+
+out:
+       skb_free_datagram(sk, skb);
+       release_sock(sk);
+
+       return rc;
+}
+
+static int qrtr_connect(struct socket *sock, struct sockaddr *saddr,
+                       int len, int flags)
+{
+       DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr);
+       struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+       struct sock *sk = sock->sk;
+       int rc;
+
+       if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR)
+               return -EINVAL;
+
+       lock_sock(sk);
+
+       sk->sk_state = TCP_CLOSE;
+       sock->state = SS_UNCONNECTED;
+
+       rc = qrtr_autobind(sock);
+       if (rc) {
+               release_sock(sk);
+               return rc;
+       }
+
+       ipc->peer = *addr;
+       sock->state = SS_CONNECTED;
+       sk->sk_state = TCP_ESTABLISHED;
+
+       release_sock(sk);
+
+       return 0;
+}
+
+static int qrtr_getname(struct socket *sock, struct sockaddr *saddr,
+                       int *len, int peer)
+{
+       struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+       struct sockaddr_qrtr qaddr;
+       struct sock *sk = sock->sk;
+
+       lock_sock(sk);
+       if (peer) {
+               if (sk->sk_state != TCP_ESTABLISHED) {
+                       release_sock(sk);
+                       return -ENOTCONN;
+               }
+
+               qaddr = ipc->peer;
+       } else {
+               qaddr = ipc->us;
+       }
+       release_sock(sk);
+
+       *len = sizeof(qaddr);
+       qaddr.sq_family = AF_QIPCRTR;
+
+       memcpy(saddr, &qaddr, sizeof(qaddr));
+
+       return 0;
+}
+
+static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+       struct sock *sk = sock->sk;
+       struct sockaddr_qrtr *sq;
+       struct sk_buff *skb;
+       struct ifreq ifr;
+       long len = 0;
+       int rc = 0;
+
+       lock_sock(sk);
+
+       switch (cmd) {
+       case TIOCOUTQ:
+               len = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
+               if (len < 0)
+                       len = 0;
+               rc = put_user(len, (int __user *)argp);
+               break;
+       case TIOCINQ:
+               skb = skb_peek(&sk->sk_receive_queue);
+               if (skb)
+                       len = skb->len - QRTR_HDR_SIZE;
+               rc = put_user(len, (int __user *)argp);
+               break;
+       case SIOCGIFADDR:
+               if (copy_from_user(&ifr, argp, sizeof(ifr))) {
+                       rc = -EFAULT;
+                       break;
+               }
+
+               sq = (struct sockaddr_qrtr *)&ifr.ifr_addr;
+               *sq = ipc->us;
+               if (copy_to_user(argp, &ifr, sizeof(ifr))) {
+                       rc = -EFAULT;
+                       break;
+               }
+               break;
+       case SIOCGSTAMP:
+               rc = sock_get_timestamp(sk, argp);
+               break;
+       case SIOCADDRT:
+       case SIOCDELRT:
+       case SIOCSIFADDR:
+       case SIOCGIFDSTADDR:
+       case SIOCSIFDSTADDR:
+       case SIOCGIFBRDADDR:
+       case SIOCSIFBRDADDR:
+       case SIOCGIFNETMASK:
+       case SIOCSIFNETMASK:
+               rc = -EINVAL;
+               break;
+       default:
+               rc = -ENOIOCTLCMD;
+               break;
+       }
+
+       release_sock(sk);
+
+       return rc;
+}
+
+static int qrtr_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct qrtr_sock *ipc;
+
+       if (!sk)
+               return 0;
+
+       lock_sock(sk);
+
+       ipc = qrtr_sk(sk);
+       sk->sk_shutdown = SHUTDOWN_MASK;
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk->sk_state_change(sk);
+
+       sock_set_flag(sk, SOCK_DEAD);
+       sock->sk = NULL;
+
+       if (!sock_flag(sk, SOCK_ZAPPED))
+               qrtr_port_remove(ipc);
+
+       skb_queue_purge(&sk->sk_receive_queue);
+
+       release_sock(sk);
+       sock_put(sk);
+
+       return 0;
+}
+
+static const struct proto_ops qrtr_proto_ops = {
+       .owner          = THIS_MODULE,
+       .family         = AF_QIPCRTR,
+       .bind           = qrtr_bind,
+       .connect        = qrtr_connect,
+       .socketpair     = sock_no_socketpair,
+       .accept         = sock_no_accept,
+       .listen         = sock_no_listen,
+       .sendmsg        = qrtr_sendmsg,
+       .recvmsg        = qrtr_recvmsg,
+       .getname        = qrtr_getname,
+       .ioctl          = qrtr_ioctl,
+       .poll           = datagram_poll,
+       .shutdown       = sock_no_shutdown,
+       .setsockopt     = sock_no_setsockopt,
+       .getsockopt     = sock_no_getsockopt,
+       .release        = qrtr_release,
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage,
+};
+
+static struct proto qrtr_proto = {
+       .name           = "QIPCRTR",
+       .owner          = THIS_MODULE,
+       .obj_size       = sizeof(struct qrtr_sock),
+};
+
+static int qrtr_create(struct net *net, struct socket *sock,
+                      int protocol, int kern)
+{
+       struct qrtr_sock *ipc;
+       struct sock *sk;
+
+       if (sock->type != SOCK_DGRAM)
+               return -EPROTOTYPE;
+
+       sk = sk_alloc(net, AF_QIPCRTR, GFP_KERNEL, &qrtr_proto, kern);
+       if (!sk)
+               return -ENOMEM;
+
+       sock_set_flag(sk, SOCK_ZAPPED);
+
+       sock_init_data(sock, sk);
+       sock->ops = &qrtr_proto_ops;
+
+       ipc = qrtr_sk(sk);
+       ipc->us.sq_family = AF_QIPCRTR;
+       ipc->us.sq_node = qrtr_local_nid;
+       ipc->us.sq_port = 0;
+
+       return 0;
+}
+
+static const struct nla_policy qrtr_policy[IFA_MAX + 1] = {
+       [IFA_LOCAL] = { .type = NLA_U32 },
+};
+
+static int qrtr_addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       struct nlattr *tb[IFA_MAX + 1];
+       struct ifaddrmsg *ifm;
+       int rc;
+
+       if (!netlink_capable(skb, CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (!netlink_capable(skb, CAP_SYS_ADMIN))
+               return -EPERM;
+
+       ASSERT_RTNL();
+
+       rc = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, qrtr_policy);
+       if (rc < 0)
+               return rc;
+
+       ifm = nlmsg_data(nlh);
+       if (!tb[IFA_LOCAL])
+               return -EINVAL;
+
+       qrtr_local_nid = nla_get_u32(tb[IFA_LOCAL]);
+       return 0;
+}
+
+static const struct net_proto_family qrtr_family = {
+       .owner  = THIS_MODULE,
+       .family = AF_QIPCRTR,
+       .create = qrtr_create,
+};
+
+static int __init qrtr_proto_init(void)
+{
+       int rc;
+
+       rc = proto_register(&qrtr_proto, 1);
+       if (rc)
+               return rc;
+
+       rc = sock_register(&qrtr_family);
+       if (rc) {
+               proto_unregister(&qrtr_proto);
+               return rc;
+       }
+
+       rtnl_register(PF_QIPCRTR, RTM_NEWADDR, qrtr_addr_doit, NULL, NULL);
+
+       return 0;
+}
+module_init(qrtr_proto_init);
+
+static void __exit qrtr_proto_fini(void)
+{
+       rtnl_unregister(PF_QIPCRTR, RTM_NEWADDR);
+       sock_unregister(qrtr_family.family);
+       proto_unregister(&qrtr_proto);
+}
+module_exit(qrtr_proto_fini);
+
+MODULE_DESCRIPTION("Qualcomm IPC-router driver");
+MODULE_LICENSE("GPL v2");
diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
new file mode 100644 (file)
index 0000000..2b84871
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __QRTR_H_
+#define __QRTR_H_
+
+#include <linux/types.h>
+
+struct sk_buff;
+
+/* endpoint node id auto assignment */
+#define QRTR_EP_NID_AUTO (-1)
+
+/**
+ * struct qrtr_endpoint - endpoint handle
+ * @xmit: Callback for outgoing packets
+ *
+ * The socket buffer passed to the xmit function becomes owned by the endpoint
+ * driver.  As such, when the driver is done with the buffer, it should
+ * call kfree_skb() on failure, or consume_skb() on success.
+ */
+struct qrtr_endpoint {
+       int (*xmit)(struct qrtr_endpoint *ep, struct sk_buff *skb);
+       /* private: not for endpoint use */
+       struct qrtr_node *node;
+};
+
+int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid);
+
+void qrtr_endpoint_unregister(struct qrtr_endpoint *ep);
+
+int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len);
+
+#endif
diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c
new file mode 100644 (file)
index 0000000..0d11132
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ * 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/module.h>
+#include <linux/skbuff.h>
+#include <linux/soc/qcom/smd.h>
+
+#include "qrtr.h"
+
+struct qrtr_smd_dev {
+       struct qrtr_endpoint ep;
+       struct qcom_smd_channel *channel;
+       struct device *dev;
+};
+
+/* from smd to qrtr */
+static int qcom_smd_qrtr_callback(struct qcom_smd_channel *channel,
+                                 const void *data, size_t len)
+{
+       struct qrtr_smd_dev *qdev = qcom_smd_get_drvdata(channel);
+       int rc;
+
+       if (!qdev)
+               return -EAGAIN;
+
+       rc = qrtr_endpoint_post(&qdev->ep, data, len);
+       if (rc == -EINVAL) {
+               dev_err(qdev->dev, "invalid ipcrouter packet\n");
+               /* return 0 to let smd drop the packet */
+               rc = 0;
+       }
+
+       return rc;
+}
+
+/* from qrtr to smd */
+static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
+{
+       struct qrtr_smd_dev *qdev = container_of(ep, struct qrtr_smd_dev, ep);
+       int rc;
+
+       rc = skb_linearize(skb);
+       if (rc)
+               goto out;
+
+       rc = qcom_smd_send(qdev->channel, skb->data, skb->len);
+
+out:
+       if (rc)
+               kfree_skb(skb);
+       else
+               consume_skb(skb);
+       return rc;
+}
+
+static int qcom_smd_qrtr_probe(struct qcom_smd_device *sdev)
+{
+       struct qrtr_smd_dev *qdev;
+       int rc;
+
+       qdev = devm_kzalloc(&sdev->dev, sizeof(*qdev), GFP_KERNEL);
+       if (!qdev)
+               return -ENOMEM;
+
+       qdev->channel = sdev->channel;
+       qdev->dev = &sdev->dev;
+       qdev->ep.xmit = qcom_smd_qrtr_send;
+
+       rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
+       if (rc)
+               return rc;
+
+       qcom_smd_set_drvdata(sdev->channel, qdev);
+       dev_set_drvdata(&sdev->dev, qdev);
+
+       dev_dbg(&sdev->dev, "Qualcomm SMD QRTR driver probed\n");
+
+       return 0;
+}
+
+static void qcom_smd_qrtr_remove(struct qcom_smd_device *sdev)
+{
+       struct qrtr_smd_dev *qdev = dev_get_drvdata(&sdev->dev);
+
+       qrtr_endpoint_unregister(&qdev->ep);
+
+       dev_set_drvdata(&sdev->dev, NULL);
+}
+
+static const struct qcom_smd_id qcom_smd_qrtr_smd_match[] = {
+       { "IPCRTR" },
+       {}
+};
+
+static struct qcom_smd_driver qcom_smd_qrtr_driver = {
+       .probe = qcom_smd_qrtr_probe,
+       .remove = qcom_smd_qrtr_remove,
+       .callback = qcom_smd_qrtr_callback,
+       .smd_match_table = qcom_smd_qrtr_smd_match,
+       .driver = {
+               .name = "qcom_smd_qrtr",
+               .owner = THIS_MODULE,
+       },
+};
+
+module_qcom_smd_driver(qcom_smd_qrtr_driver);
+
+MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver");
+MODULE_LICENSE("GPL v2");
index c20d2d3d9464143fe5eeb8670ffce055ed6feaf5..258080c36643383753585d0a6f1f32cfb5ae1b11 100644 (file)
@@ -501,7 +501,7 @@ config SND_SOC_MAX98925
 config SND_SOC_MAX9850
        tristate
 
-config SND_SOC_MSM8x16_WCD
+config SND_SOC_MSM8916_WCD
        tristate "Qualcomm MSM8x16 WCD"
        depends on SPMI && MFD_SYSCON
 
index afb8af97fd932ed30ff59d56db116ce370083228..27aebb926ad5ade10046e1f79b0443f1607c7362 100644 (file)
@@ -74,9 +74,9 @@ snd-soc-max98925-objs := max98925.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
+snd-soc-msm8916-objs := msm8916-wcd.o
 snd-soc-nau8825-objs := nau8825.o
 snd-soc-hdmi-codec-objs := hdmi-codec.o
-snd-soc-msm8x16-objs := msm8x16-wcd.o msm8x16-wcd-tables.o
 snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
@@ -270,9 +270,9 @@ obj-$(CONFIG_SND_SOC_MAX98925)      += snd-soc-max98925.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_MSM8916_WCD) +=snd-soc-msm8916.o
 obj-$(CONFIG_SND_SOC_NAU8825)   += snd-soc-nau8825.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC)       += snd-soc-hdmi-codec.o
-obj-$(CONFIG_SND_SOC_MSM8x16_WCD) +=snd-soc-msm8x16.o
 obj-$(CONFIG_SND_SOC_PCM1681)  += snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
diff --git a/sound/soc/codecs/msm8916-wcd-registers.h b/sound/soc/codecs/msm8916-wcd-registers.h
new file mode 100644 (file)
index 0000000..8896603
--- /dev/null
@@ -0,0 +1,710 @@
+ /* Copyright (c) 2016, 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 MSM8916_WCD_REGISTERS_H
+#define MSM8916_WCD_REGISTERS_H
+
+#define CDC_D_REVISION1                        (0x000)
+#define CDC_D_REVISION1_POR                            (0x00)
+#define CDC_D_REVISION2                        (0x001)
+#define CDC_D_REVISION2_POR                            (0x00)
+#define CDC_D_PERPH_TYPE                       (0x004)
+#define CDC_D_PERPH_TYPE_POR                           (0x23)
+#define CDC_D_PERPH_SUBTYPE                    (0x005)
+#define CDC_D_PERPH_SUBTYPE_POR                        (0x01)
+#define CDC_D_INT_RT_STS                       (0x010)
+#define CDC_D_INT_RT_STS_POR                           (0x00)
+#define CDC_D_INT_SET_TYPE                     (0x011)
+#define CDC_D_INT_SET_TYPE_POR                         (0xFF)
+#define CDC_D_INT_POLARITY_HIGH                        (0x012)
+#define CDC_D_INT_POLARITY_HIGH_POR                    (0xFF)
+#define CDC_D_INT_POLARITY_LOW                 (0x013)
+#define CDC_D_INT_POLARITY_LOW_POR                     (0x00)
+#define CDC_D_INT_LATCHED_CLR                  (0x014)
+#define CDC_D_INT_LATCHED_CLR_POR                      (0x00)
+#define CDC_D_INT_EN_SET                       (0x015)
+#define CDC_D_INT_EN_SET_POR                           (0x00)
+#define CDC_D_INT_EN_CLR                       (0x016)
+#define CDC_D_INT_EN_CLR_POR                           (0x00)
+#define CDC_D_INT_LATCHED_STS                  (0x018)
+#define CDC_D_INT_LATCHED_STS_POR                      (0x00)
+#define CDC_D_INT_PENDING_STS                  (0x019)
+#define CDC_D_INT_PENDING_STS_POR                      (0x00)
+#define CDC_D_INT_MID_SEL                      (0x01A)
+#define CDC_D_INT_MID_SEL_POR                          (0x00)
+#define CDC_D_INT_PRIORITY                     (0x01B)
+#define CDC_D_INT_PRIORITY_POR                         (0x00)
+#define CDC_D_GPIO_MODE                        (0x040)
+#define CDC_D_GPIO_MODE_POR                            (0x00)
+#define CDC_D_PIN_CTL_OE                       (0x041)
+#define CDC_D_PIN_CTL_OE_POR                           (0x01)
+#define CDC_D_PIN_CTL_DATA                     (0x042)
+#define CDC_D_PIN_CTL_DATA_POR                         (0x00)
+#define CDC_D_PIN_STATUS                       (0x043)
+#define CDC_D_PIN_STATUS_POR                           (0x00)
+#define CDC_D_HDRIVE_CTL                       (0x044)
+#define CDC_D_HDRIVE_CTL_POR                           (0x00)
+#define CDC_D_CDC_RST_CTL                      (0x046)
+#define RST_CTL_DIG_SW_RST_N_MASK              BIT(7)
+#define RST_CTL_DIG_SW_RST_N_RESET             0
+#define RST_CTL_DIG_SW_RST_N_REMOVE_RESET      BIT(7)
+
+#define CDC_D_CDC_RST_CTL_POR                          (0x00)
+#define CDC_D_CDC_TOP_CLK_CTL                  (0x048)
+#define TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK       (BIT(2) | BIT(3))
+#define TOP_CLK_CTL_A_MCLK_EN_ENABLE           BIT(2)
+#define TOP_CLK_CTL_A_MCLK2_EN_ENABLE          BIT(3)
+
+#define CDC_D_CDC_TOP_CLK_CTL_POR                      (0x00)
+#define CDC_D_CDC_ANA_CLK_CTL                  (0x049)
+#define ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK       BIT(0)
+#define ANA_CLK_CTL_EAR_HPHR_CLK_EN    BIT(0)
+#define ANA_CLK_CTL_EAR_HPHL_CLK_EN    BIT(1)
+#define ANA_CLK_CTL_SPKR_CLK_EN_MASK   BIT(4)
+#define ANA_CLK_CTL_SPKR_CLK_EN        BIT(4)
+#define ANA_CLK_CTL_TXA_CLK25_EN       BIT(5)
+
+#define CDC_D_CDC_ANA_CLK_CTL_POR                      (0x00)
+#define CDC_D_CDC_DIG_CLK_CTL                  (0x04A)
+#define DIG_CLK_CTL_RXD1_CLK_EN        BIT(0)
+#define DIG_CLK_CTL_RXD2_CLK_EN        BIT(1)
+#define DIG_CLK_CTL_RXD3_CLK_EN        BIT(3)
+#define DIG_CLK_CTL_TXD_CLK_EN BIT(4)
+#define DIG_CLK_CTL_NCP_CLK_EN_MASK    BIT(6)
+#define DIG_CLK_CTL_NCP_CLK_EN BIT(6)
+#define DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK        BIT(7)
+#define DIG_CLK_CTL_RXD_PDM_CLK_EN     BIT(7)
+
+#define CDC_D_CDC_DIG_CLK_CTL_POR                      (0x00)
+#define CDC_D_CDC_CONN_TX1_CTL                 (0x050)
+#define CONN_TX1_SERIAL_TX1_MUX                        GENMASK(1, 0)
+#define CONN_TX1_SERIAL_TX1_ADC_1              0x0
+#define CONN_TX1_SERIAL_TX1_RX_PDM_LB          0x1
+#define CONN_TX1_SERIAL_TX1_ZERO               0x2
+
+#define CDC_D_CDC_CONN_TX1_CTL_POR                     (0x02)
+#define CDC_D_CDC_CONN_TX2_CTL                 (0x051)
+#define CONN_TX2_SERIAL_TX2_MUX                        GENMASK(1, 0)
+#define CONN_TX2_SERIAL_TX2_ADC_2              0x0
+#define CONN_TX2_SERIAL_TX2_RX_PDM_LB          0x1
+#define CONN_TX2_SERIAL_TX2_ZERO               0x2
+#define CDC_D_CDC_CONN_TX2_CTL_POR                     (0x02)
+#define CDC_D_CDC_CONN_HPHR_DAC_CTL                    (0x052)
+#define CDC_D_CDC_CONN_HPHR_DAC_CTL_POR                (0x00)
+#define CDC_D_CDC_CONN_RX1_CTL                 (0x053)
+#define CDC_D_CDC_CONN_RX1_CTL_POR                     (0x00)
+#define CDC_D_CDC_CONN_RX2_CTL                 (0x054)
+#define CDC_D_CDC_CONN_RX2_CTL_POR                     (0x00)
+#define CDC_D_CDC_CONN_RX3_CTL                 (0x055)
+#define CDC_D_CDC_CONN_RX3_CTL_POR                     (0x00)
+#define CDC_D_CDC_CONN_RX_LB_CTL                       (0x056)
+#define CDC_D_CDC_CONN_RX_LB_CTL_POR                   (0x00)
+#define CDC_D_CDC_RX_CTL1                      (0x058)
+#define CDC_D_CDC_RX_CTL1_POR                          (0x7C)
+#define CDC_D_CDC_RX_CTL2                      (0x059)
+#define CDC_D_CDC_RX_CTL2_POR                          (0x7C)
+#define CDC_D_CDC_RX_CTL3                      (0x05A)
+#define CDC_D_CDC_RX_CTL3_POR                          (0x7C)
+#define CDC_D_DEM_BYPASS_DATA0                 (0x05B)
+#define CDC_D_DEM_BYPASS_DATA0_POR                     (0x00)
+#define CDC_D_DEM_BYPASS_DATA1                 (0x05C)
+#define CDC_D_DEM_BYPASS_DATA1_POR                     (0x00)
+#define CDC_D_DEM_BYPASS_DATA2                 (0x05D)
+#define CDC_D_DEM_BYPASS_DATA2_POR                     (0x00)
+#define CDC_D_DEM_BYPASS_DATA3                 (0x05E)
+#define CDC_D_DEM_BYPASS_DATA3_POR                     (0x00)
+#define CDC_D_DIG_DEBUG_CTL                    (0x068)
+#define CDC_D_DIG_DEBUG_CTL_POR                        (0x00)
+#define CDC_D_DIG_DEBUG_EN                     (0x069)
+#define CDC_D_DIG_DEBUG_EN_POR                         (0x00)
+#define CDC_D_SPARE_0                          (0x070)
+#define CDC_D_SPARE_0_POR                              (0x00)
+#define CDC_D_SPARE_1                          (0x071)
+#define CDC_D_SPARE_1_POR                              (0x00)
+#define CDC_D_SPARE_2                          (0x072)
+#define CDC_D_SPARE_2_POR                              (0x00)
+#define CDC_D_SEC_ACCESS                       (0x0D0)
+#define CDC_D_SEC_ACCESS_POR                           (0x00)
+#define CDC_D_PERPH_RESET_CTL1                 (0x0D8)
+#define CDC_D_PERPH_RESET_CTL1_POR                     (0x00)
+#define CDC_D_PERPH_RESET_CTL2                 (0x0D9)
+#define CDC_D_PERPH_RESET_CTL2_POR                     (0x01)
+#define CDC_D_PERPH_RESET_CTL3                 (0x0DA)
+#define CDC_D_PERPH_RESET_CTL3_POR                     (0x05)
+#define CDC_D_PERPH_RESET_CTL4                 (0x0DB)
+#define CDC_D_PERPH_RESET_CTL4_POR                     (0x00)
+#define CDC_D_INT_TEST1                                (0x0E0)
+#define CDC_D_INT_TEST1_POR                            (0x00)
+#define CDC_D_INT_TEST_VAL                     (0x0E1)
+#define CDC_D_INT_TEST_VAL_POR                         (0x00)
+#define CDC_D_TRIM_NUM                         (0x0F0)
+#define CDC_D_TRIM_NUM_POR                             (0x00)
+#define CDC_D_TRIM_CTRL                                (0x0F1)
+#define CDC_D_TRIM_CTRL_POR                            (0x00)
+
+#define CDC_A_REVISION1                        (0x100)
+#define CDC_A_REVISION1_POR                            (0x00)
+#define CDC_A_REVISION2                        (0x101)
+#define CDC_A_REVISION2_POR                            (0x00)
+#define CDC_A_REVISION3                        (0x102)
+#define CDC_A_REVISION3_POR                            (0x00)
+#define CDC_A_REVISION4                        (0x103)
+#define CDC_A_REVISION4_POR                            (0x00)
+#define CDC_A_PERPH_TYPE                       (0x104)
+#define CDC_A_PERPH_TYPE_POR                   (0x23)
+#define CDC_A_PERPH_SUBTYPE            (0x105)
+#define CDC_A_PERPH_SUBTYPE_POR                        (0x09)
+#define CDC_A_INT_RT_STS                       (0x110)
+#define CDC_A_INT_RT_STS_POR                   (0x00)
+#define CDC_A_INT_SET_TYPE             (0x111)
+#define CDC_A_INT_SET_TYPE_POR                 (0x3F)
+#define CDC_A_INT_POLARITY_HIGH                (0x112)
+#define CDC_A_INT_POLARITY_HIGH_POR            (0x3F)
+#define CDC_A_INT_POLARITY_LOW         (0x113)
+#define CDC_A_INT_POLARITY_LOW_POR             (0x00)
+#define CDC_A_INT_LATCHED_CLR          (0x114)
+#define CDC_A_INT_LATCHED_CLR_POR              (0x00)
+#define CDC_A_INT_EN_SET                       (0x115)
+#define CDC_A_INT_EN_SET_POR                   (0x00)
+#define CDC_A_INT_EN_CLR                       (0x116)
+#define CDC_A_INT_EN_CLR_POR                   (0x00)
+#define CDC_A_INT_LATCHED_STS          (0x118)
+#define CDC_A_INT_LATCHED_STS_POR              (0x00)
+#define CDC_A_INT_PENDING_STS          (0x119)
+#define CDC_A_INT_PENDING_STS_POR              (0x00)
+#define CDC_A_INT_MID_SEL              (0x11A)
+#define CDC_A_INT_MID_SEL_POR                  (0x00)
+#define CDC_A_INT_PRIORITY             (0x11B)
+#define CDC_A_INT_PRIORITY_POR                 (0x00)
+
+#define CDC_A_MICB_1_EN                        (0x140)
+#define MICB_1_EN_MICB_ENABLE  BIT(7)
+#define MICB_1_EN_BYP_CAP_MASK BIT(6)
+#define MICB_1_EN_NO_EXT_BYP_CAP       BIT(6)
+#define MICB_1_EN_EXT_BYP_CAP  0
+#define MICB_1_EN_PULL_DOWN_EN_MASK    BIT(5)
+#define MICB_1_EN_PULL_DOWN_EN_ENABLE  BIT(5)
+#define MICB_1_EN_OPA_STG2_TAIL_CURR_MASK GENMASK(3, 1)
+#define MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA    BIT(2)
+#define MICB_1_EN_TX3_GND_SEL_MASK     BIT(0)
+#define MICB_1_EN_TX3_GND_SEL_TX_GND   0
+#define CDC_A_MICB_1_EN_POR                    (0x00)
+
+#define CDC_A_MICB_1_VAL                       (0x141)
+#define MICB_1_VAL_MICB_OUT_VAL_MASK           GENMASK(7, 3)
+#define MICB_1_VAL_MICB_OUT_VAL_V2P70V         ((0x16)  << 3)
+#define CDC_A_MICB_1_VAL_POR                   (0x20)
+#define CDC_A_MICB_1_CTL                       (0x142)
+
+#define MICB_1_CTL_CFILT_REF_SEL_MASK          BIT(1)
+#define MICB_1_CTL_CFILT_REF_SEL_HPF_REF       BIT(1)
+#define MICB_1_CTL_EXT_PRECHARG_EN_MASK                BIT(5)
+#define MICB_1_CTL_EXT_PRECHARG_EN_ENABLE      BIT(5)
+#define MICB_1_CTL_INT_PRECHARG_BYP_MASK       BIT(6)
+#define MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL    BIT(6)
+
+#define CDC_A_MICB_1_CTL_POR                   (0x00)
+#define CDC_A_MICB_1_INT_RBIAS                 (0x143)
+
+#define MICB_1_INT_TX1_INT_RBIAS_EN_MASK       BIT(7)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE     BIT(7)
+#define MICB_1_INT_TX1_INT_RBIAS_EN_DISABLE    0
+
+#define MICB_1_INT_TX1_INT_PULLUP_EN_MASK      BIT(6)
+#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(6)
+#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_GND       0
+
+#define MICB_1_INT_TX2_INT_RBIAS_EN_MASK       BIT(4)
+#define MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE     BIT(4)
+#define MICB_1_INT_TX2_INT_RBIAS_EN_DISABLE    0
+#define MICB_1_INT_TX2_INT_PULLUP_EN_MASK      BIT(3)
+#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(3)
+#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_GND       0
+
+#define MICB_1_INT_TX3_INT_RBIAS_EN_MASK       BIT(1)
+#define MICB_1_INT_TX3_INT_RBIAS_EN_ENABLE     BIT(1)
+#define MICB_1_INT_TX3_INT_RBIAS_EN_DISABLE    0
+#define MICB_1_INT_TX3_INT_PULLUP_EN_MASK      BIT(0)
+#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(0)
+#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND       0
+
+#define CDC_A_MICB_1_INT_RBIAS_POR             (0x49)
+#define CDC_A_MICB_2_EN                        (0x144)
+#define CDC_A_MICB_2_EN_POR                    (0x20)
+#define CDC_A_TX_1_2_ATEST_CTL_2                       (0x145)
+#define CDC_A_TX_1_2_ATEST_CTL_2_POR           (0x00)
+#define CDC_A_MASTER_BIAS_CTL                  (0x146)
+#define MASTER_BIAS_CTL_MASTER_BIAS_EN_MASK    BIT(5)
+#define MASTER_BIAS_CTL_MASTER_BIAS_EN_ENABLE  BIT(5)
+#define MASTER_BIAS_CTL_V2L_BUFFER_EN_MASK     BIT(4)
+#define MASTER_BIAS_CTL_V2L_BUFFER_EN_ENABLE   BIT(4)
+#define CDC_A_MASTER_BIAS_CTL_POR              (0x00)
+#define CDC_A_MBHC_DET_CTL_1           (0x147)
+#define CDC_A_MBHC_DET_CTL_1_POR               (0x35)
+#define CDC_A_MBHC_DET_CTL_2           (0x150)
+#define CDC_A_MBHC_DET_CTL_2_POR               (0x08)
+#define CDC_A_MBHC_FSM_CTL             (0x151)
+#define CDC_A_MBHC_FSM_CTL_POR                 (0x00)
+#define CDC_A_MBHC_DBNC_TIMER          (0x152)
+#define CDC_A_MBHC_DBNC_TIMER_POR              (0x98)
+#define CDC_A_MBHC_BTN0_ZDETL_CTL      (0x153)
+#define CDC_A_MBHC_BTN0_ZDETL_CTL_POR          (0x00)
+#define CDC_A_MBHC_BTN1_ZDETM_CTL      (0x154)
+#define CDC_A_MBHC_BTN1_ZDETM_CTL_POR          (0x20)
+#define CDC_A_MBHC_BTN2_ZDETH_CTL      (0x155)
+#define CDC_A_MBHC_BTN2_ZDETH_CTL_POR          (0x40)
+#define CDC_A_MBHC_BTN3_CTL            (0x156)
+#define CDC_A_MBHC_BTN3_CTL_POR                        (0x61)
+#define CDC_A_MBHC_BTN4_CTL            (0x157)
+#define CDC_A_MBHC_BTN4_CTL_POR                        (0x80)
+#define CDC_A_MBHC_BTN_RESULT          (0x158)
+#define CDC_A_MBHC_BTN_RESULT_POR              (0x00)
+#define CDC_A_MBHC_ZDET_ELECT_RESULT   (0x159)
+#define CDC_A_MBHC_ZDET_ELECT_RESULT_POR       (0x00)
+#define CDC_A_TX_1_EN                  (0x160)
+#define CDC_A_TX_1_EN_POR                      (0x03)
+#define CDC_A_TX_2_EN                  (0x161)
+#define CDC_A_TX_2_EN_POR                      (0x03)
+#define CDC_A_TX_1_2_TEST_CTL_1                (0x162)
+#define CDC_A_TX_1_2_TEST_CTL_1_POR            (0xBF)
+#define CDC_A_TX_1_2_TEST_CTL_2                (0x163)
+#define CDC_A_TX_1_2_TEST_CTL_2_POR            (0x8C)
+#define CDC_A_TX_1_2_ATEST_CTL         (0x164)
+#define CDC_A_TX_1_2_ATEST_CTL_POR             (0x00)
+#define CDC_A_TX_1_2_OPAMP_BIAS                (0x165)
+#define CDC_A_TX_1_2_OPAMP_BIAS_POR            (0x6B)
+#define CDC_A_TX_1_2_TXFE_CLKDIV               (0x166)
+#define CDC_A_TX_1_2_TXFE_CLKDIV_POR           (0x51)
+#define CDC_A_TX_3_EN                  (0x167)
+#define CDC_A_TX_3_EN_POR                      (0x02)
+#define CDC_A_NCP_EN                   (0x180)
+#define CDC_A_NCP_EN_POR                       (0x26)
+#define CDC_A_NCP_CLK                  (0x181)
+#define CDC_A_NCP_CLK_POR                      (0x23)
+#define CDC_A_NCP_DEGLITCH             (0x182)
+#define CDC_A_NCP_DEGLITCH_POR                 (0x5B)
+#define CDC_A_NCP_FBCTRL                       (0x183)
+#define CDC_A_NCP_FBCTRL_FB_CLK_INV_MASK       BIT(5)
+#define CDC_A_NCP_FBCTRL_FB_CLK_INV            BIT(5)
+#define CDC_A_NCP_FBCTRL_POR                   (0x08)
+#define CDC_A_NCP_BIAS                 (0x184)
+#define CDC_A_NCP_BIAS_POR                     (0x29)
+#define CDC_A_NCP_VCTRL                        (0x185)
+#define CDC_A_NCP_VCTRL_POR                    (0x24)
+#define CDC_A_NCP_TEST                 (0x186)
+#define CDC_A_NCP_TEST_POR                     (0x00)
+#define CDC_A_NCP_CLIM_ADDR            (0x187)
+#define CDC_A_NCP_CLIM_ADDR_POR                        (0xD5)
+#define CDC_A_RX_CLOCK_DIVIDER         (0x190)
+#define CDC_A_RX_CLOCK_DIVIDER_POR             (0xE8)
+#define CDC_A_RX_COM_OCP_CTL           (0x191)
+#define CDC_A_RX_COM_OCP_CTL_POR               (0xCF)
+#define CDC_A_RX_COM_OCP_COUNT         (0x192)
+#define CDC_A_RX_COM_OCP_COUNT_POR             (0x6E)
+#define CDC_A_RX_COM_BIAS_DAC          (0x193)
+#define RX_COM_BIAS_DAC_RX_BIAS_EN_MASK                BIT(7)
+#define RX_COM_BIAS_DAC_RX_BIAS_EN_ENABLE      BIT(7)
+#define RX_COM_BIAS_DAC_DAC_REF_EN_MASK                BIT(0)
+#define RX_COM_BIAS_DAC_DAC_REF_EN_ENABLE      BIT(0)
+
+#define CDC_A_RX_COM_BIAS_DAC_POR              (0x10)
+#define CDC_A_RX_HPH_BIAS_PA           (0x194)
+#define CDC_A_RX_HPH_BIAS_PA_POR               (0x5A)
+#define CDC_A_RX_HPH_BIAS_LDO_OCP      (0x195)
+#define CDC_A_RX_HPH_BIAS_LDO_OCP_POR          (0x69)
+#define CDC_A_RX_HPH_BIAS_CNP          (0x196)
+#define CDC_A_RX_HPH_BIAS_CNP_POR              (0x29)
+#define CDC_A_RX_HPH_CNP_EN            (0x197)
+#define CDC_A_RX_HPH_CNP_EN_POR                        (0x80)
+#define CDC_A_RX_HPH_CNP_WG_CTL                (0x198)
+#define CDC_A_RX_HPH_CNP_WG_CTL_POR            (0xDA)
+#define CDC_A_RX_HPH_CNP_WG_TIME               (0x199)
+#define CDC_A_RX_HPH_CNP_WG_TIME_POR           (0x16)
+#define CDC_A_RX_HPH_L_TEST            (0x19A)
+#define CDC_A_RX_HPH_L_TEST_POR                        (0x00)
+#define CDC_A_RX_HPH_L_PA_DAC_CTL      (0x19B)
+#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK    BIT(1)
+#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET   BIT(1)
+#define CDC_A_RX_HPH_L_PA_DAC_CTL_POR          (0x20)
+#define CDC_A_RX_HPH_R_TEST            (0x19C)
+#define CDC_A_RX_HPH_R_TEST_POR                        (0x00)
+#define CDC_A_RX_HPH_R_PA_DAC_CTL      (0x19D)
+#define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1)
+#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1)
+
+#define CDC_A_RX_HPH_R_PA_DAC_CTL_POR          (0x20)
+#define CDC_A_RX_EAR_CTL                       (0x19E)
+#define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK                BIT(0)
+#define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE      BIT(0)
+
+#define CDC_A_RX_EAR_CTL_POR                   (0x12)
+#define CDC_A_RX_ATEST                 (0x19F)
+#define CDC_A_RX_ATEST_POR                     (0x00)
+#define CDC_A_RX_HPH_STATUS            (0x1A0)
+#define CDC_A_RX_HPH_STATUS_POR                        (0x0C)
+#define CDC_A_RX_EAR_STATUS            (0x1A1)
+#define CDC_A_RX_EAR_STATUS_POR                        (0x00)
+#define CDC_A_SPKR_DAC_CTL             (0x1B0)
+#define SPKR_DAC_CTL_DAC_RESET_MASK            BIT(4)
+#define SPKR_DAC_CTL_DAC_RESET_NORMAL          0
+
+#define CDC_A_SPKR_DAC_CTL_POR                 (0x83)
+#define CDC_A_SPKR_DRV_CLIP_DET                (0x1B1)
+#define CDC_A_SPKR_DRV_CLIP_DET_POR            (0x91)
+#define CDC_A_SPKR_DRV_CTL             (0x1B2)
+#define SPKR_DRV_CTL_DEF_MASK          0xEF
+#define SPKR_DRV_CLASSD_PA_EN_MASK             BIT(7)
+#define SPKR_DRV_CLASSD_PA_EN_ENABLE           BIT(7)
+#define SPKR_DRV_CAL_EN                                BIT(6)
+#define SPKR_DRV_SETTLE_EN                     BIT(5)
+#define SPKR_DRV_FW_EN                         BIT(3)
+#define SPKR_DRV_BOOST_SET                     BIT(2)
+#define SPKR_DRV_CMFB_SET                      BIT(1)
+#define SPKR_DRV_GAIN_SET                      BIT(0)
+#define SPKR_DRV_CTL_DEF_VAL (SPKR_DRV_CLASSD_PA_EN_ENABLE | \
+               SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \
+               SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \
+               SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET)
+#define CDC_A_SPKR_DRV_CTL_POR                 (0x29)
+#define CDC_A_SPKR_ANA_BIAS_SET                (0x1B3)
+#define CDC_A_SPKR_ANA_BIAS_SET_POR            (0x4D)
+#define CDC_A_SPKR_OCP_CTL             (0x1B4)
+#define CDC_A_SPKR_OCP_CTL_POR                 (0xE1)
+#define CDC_A_SPKR_PWRSTG_CTL          (0x1B5)
+#define SPKR_PWRSTG_CTL_DAC_EN_MASK    BIT(0)
+#define SPKR_PWRSTG_CTL_DAC_EN_ENABLE  BIT(0)
+#define SPKR_PWRSTG_CTL_HBRDGE_EN      BIT(6)
+#define SPKR_PWRSTG_CTL_CLAMP_EN       BIT(5)
+#define SPKR_PWRSTG_CTL_DEADTIME_T20NS 0
+#define SPKR_PWRSTG_CTL_DEADTIME_T15NS BIT(3)
+#define SPKR_PWRSTG_CTL_DEADTIME_T10NS BIT(4)
+#define SPKR_PWRSTG_CTL_DEADTIME_T05NS (BIT(3) | BIT(4))
+#define SPKR_PWRSTG_CTL_MASK           0xE0
+#define SPKR_PWRSTG_CTL_DEFAULTS       0xE0
+
+#define CDC_A_SPKR_PWRSTG_CTL_POR              (0x1E)
+#define CDC_A_SPKR_DRV_MISC            (0x1B6)
+#define CDC_A_SPKR_DRV_MISC_POR                        (0xCB)
+#define CDC_A_SPKR_DRV_DBG             (0x1B7)
+#define CDC_A_SPKR_DRV_DBG_POR                 (0x00)
+#define CDC_A_CURRENT_LIMIT            (0x1C0)
+#define CDC_A_CURRENT_LIMIT_POR                        (0x02)
+#define CDC_A_OUTPUT_VOLTAGE           (0x1C1)
+#define CDC_A_OUTPUT_VOLTAGE_POR               (0x14)
+#define CDC_A_BYPASS_MODE              (0x1C2)
+#define CDC_A_BYPASS_MODE_POR                  (0x00)
+#define CDC_A_BOOST_EN_CTL             (0x1C3)
+#define CDC_A_BOOST_EN_CTL_POR                 (0x1F)
+#define CDC_A_SLOPE_COMP_IP_ZERO               (0x1C4)
+#define CDC_A_SLOPE_COMP_IP_ZERO_POR           (0x8C)
+#define CDC_A_RDSON_MAX_DUTY_CYCLE     (0x1C5)
+#define CDC_A_RDSON_MAX_DUTY_CYCLE_POR         (0xC0)
+#define CDC_A_BOOST_TEST1_1            (0x1C6)
+#define CDC_A_BOOST_TEST1_1_POR                        (0x00)
+#define CDC_A_BOOST_TEST_2             (0x1C7)
+#define CDC_A_BOOST_TEST_2_POR                 (0x00)
+#define CDC_A_SPKR_SAR_STATUS          (0x1C8)
+#define CDC_A_SPKR_SAR_STATUS_POR              (0x00)
+#define CDC_A_SPKR_DRV_STATUS          (0x1C9)
+#define CDC_A_SPKR_DRV_STATUS_POR              (0x00)
+#define CDC_A_PBUS_ADD_CSR             (0x1CE)
+#define CDC_A_PBUS_ADD_CSR_POR                 (0x00)
+#define CDC_A_PBUS_ADD_SEL             (0x1CF)
+#define CDC_A_PBUS_ADD_SEL_POR                 (0x00)
+#define CDC_A_SEC_ACCESS                       (0x1D0)
+#define CDC_A_SEC_ACCESS_POR                   (0x00)
+#define CDC_A_PERPH_RESET_CTL1         (0x1D8)
+#define CDC_A_PERPH_RESET_CTL1_POR             (0x00)
+#define CDC_A_PERPH_RESET_CTL2         (0x1D9)
+#define CDC_A_PERPH_RESET_CTL2_POR             (0x01)
+#define CDC_A_PERPH_RESET_CTL3         (0x1DA)
+#define CDC_A_PERPH_RESET_CTL3_POR             (0x05)
+#define CDC_A_PERPH_RESET_CTL4         (0x1DB)
+#define CDC_A_PERPH_RESET_CTL4_POR             (0x00)
+#define CDC_A_INT_TEST1                        (0x1E0)
+#define CDC_A_INT_TEST1_POR                    (0x00)
+#define CDC_A_INT_TEST_VAL             (0x1E1)
+#define CDC_A_INT_TEST_VAL_POR                 (0x00)
+#define CDC_A_TRIM_NUM                 (0x1F0)
+#define CDC_A_TRIM_NUM_POR                     (0x04)
+#define CDC_A_TRIM_CTRL1                       (0x1F1)
+#define CDC_A_TRIM_CTRL1_POR                   (0x00)
+#define CDC_A_TRIM_CTRL2                       (0x1F2)
+#define CDC_A_TRIM_CTRL2_POR                   (0x00)
+#define CDC_A_TRIM_CTRL3                       (0x1F3)
+#define CDC_A_TRIM_CTRL3_POR                   (0x00)
+#define CDC_A_TRIM_CTRL4                       (0x1F4)
+#define CDC_A_TRIM_CTRL4_POR                   (0x00)
+
+/* Digital part */
+#define LPASS_CDC_CLK_RX_RESET_CTL                     (0x200)
+#define LPASS_CDC_CLK_RX_RESET_CTL_POR                         (0x00)
+#define LPASS_CDC_CLK_TX_RESET_B1_CTL                  (0x204)
+#define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK             BIT(0)
+#define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK             BIT(1)
+#define LPASS_CDC_CLK_TX_RESET_B1_CTL_POR                      (0x00)
+#define LPASS_CDC_CLK_DMIC_B1_CTL                      (0x208)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK                 GENMASK(3, 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2                 (0x0 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3                 (0x1 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4                 (0x2 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6                 (0x3 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16                        (0x4 << 1)
+#define DMIC_B1_CTL_DMIC0_CLK_EN_MASK                  BIT(0)
+#define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE                        BIT(0)
+
+#define LPASS_CDC_CLK_DMIC_B1_CTL_POR                          (0x00)
+#define LPASS_CDC_CLK_RX_I2S_CTL                       (0x20C)
+#define RX_I2S_CTL_RX_I2S_MODE_MASK                    BIT(5)
+#define RX_I2S_CTL_RX_I2S_MODE_16                      BIT(5)
+#define RX_I2S_CTL_RX_I2S_MODE_32                      0
+#define RX_I2S_CTL_RX_I2S_FS_RATE_MASK                 GENMASK(2, 0)
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ              0x0
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ             0x1
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ             0x2
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ             0x3
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ             0x4
+#define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ            0x5
+#define LPASS_CDC_CLK_RX_I2S_CTL_POR                           (0x13)
+#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL                        (0x214)
+#define LPASS_CDC_CLK_TX_I2S_CTL_POR                           (0x13)
+#define LPASS_CDC_CLK_TX_I2S_CTL                       (0x210)
+#define TX_I2S_CTL_TX_I2S_MODE_MASK                    BIT(5)
+#define TX_I2S_CTL_TX_I2S_MODE_16                      BIT(5)
+#define TX_I2S_CTL_TX_I2S_MODE_32                      0
+#define TX_I2S_CTL_TX_I2S_FS_RATE_MASK                 GENMASK(2, 0)
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ              0x0
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ             0x1
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ             0x2
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ             0x3
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ             0x4
+#define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ            0x5
+
+#define LPASS_CDC_CLK_TX_I2S_CTL_POR                           (0x13)
+#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL                        (0x214)
+#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL_POR                    (0x00)
+#define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL                 (0x218)
+#define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL_POR                     (0x00)
+#define LPASS_CDC_CLK_OTHR_CTL                 (0x21C)
+#define LPASS_CDC_CLK_OTHR_CTL_POR                             (0x04)
+#define LPASS_CDC_CLK_RX_B1_CTL                        (0x220)
+#define LPASS_CDC_CLK_RX_B1_CTL_POR                            (0x00)
+#define LPASS_CDC_CLK_MCLK_CTL                 (0x224)
+#define MCLK_CTL_MCLK_EN_MASK                  BIT(0)
+#define MCLK_CTL_MCLK_EN_ENABLE                        BIT(0)
+#define MCLK_CTL_MCLK_EN_DISABLE               0
+#define LPASS_CDC_CLK_MCLK_CTL_POR                             (0x00)
+#define LPASS_CDC_CLK_PDM_CTL                  (0x228)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK      BIT(0)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_EN           BIT(0)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK BIT(1)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB   BIT(1)
+#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK  0
+
+#define LPASS_CDC_CLK_PDM_CTL_POR                              (0x00)
+#define LPASS_CDC_CLK_SD_CTL                   (0x22C)
+#define LPASS_CDC_CLK_SD_CTL_POR                               (0x00)
+#define LPASS_CDC_RX1_B1_CTL                   (0x240)
+#define LPASS_CDC_RX1_B1_CTL_POR                               (0x00)
+#define LPASS_CDC_RX2_B1_CTL                   (0x260)
+#define LPASS_CDC_RX2_B1_CTL_POR                               (0x00)
+#define LPASS_CDC_RX3_B1_CTL                   (0x280)
+#define LPASS_CDC_RX3_B1_CTL_POR                               (0x00)
+#define LPASS_CDC_RX1_B2_CTL                   (0x244)
+#define LPASS_CDC_RX1_B2_CTL_POR                               (0x00)
+#define LPASS_CDC_RX2_B2_CTL                   (0x264)
+#define LPASS_CDC_RX2_B2_CTL_POR                               (0x00)
+#define LPASS_CDC_RX3_B2_CTL                   (0x284)
+#define LPASS_CDC_RX3_B2_CTL_POR                               (0x00)
+#define LPASS_CDC_RX1_B3_CTL                   (0x248)
+#define LPASS_CDC_RX1_B3_CTL_POR                               (0x00)
+#define LPASS_CDC_RX2_B3_CTL                   (0x268)
+#define LPASS_CDC_RX2_B3_CTL_POR                               (0x00)
+#define LPASS_CDC_RX3_B3_CTL                   (0x288)
+#define LPASS_CDC_RX3_B3_CTL_POR                               (0x00)
+#define LPASS_CDC_RX1_B4_CTL                   (0x24C)
+#define LPASS_CDC_RX1_B4_CTL_POR                               (0x00)
+#define LPASS_CDC_RX2_B4_CTL                   (0x26C)
+#define LPASS_CDC_RX2_B4_CTL_POR                               (0x00)
+#define LPASS_CDC_RX3_B4_CTL                   (0x28C)
+#define LPASS_CDC_RX3_B4_CTL_POR                               (0x00)
+#define LPASS_CDC_RX1_B5_CTL                   (0x250)
+#define LPASS_CDC_RX1_B5_CTL_POR                               (0x68)
+#define LPASS_CDC_RX2_B5_CTL                   (0x270)
+#define LPASS_CDC_RX2_B5_CTL_POR                               (0x68)
+#define LPASS_CDC_RX3_B5_CTL                   (0x290)
+#define LPASS_CDC_RX3_B5_CTL_POR                               (0x68)
+#define LPASS_CDC_RX1_B6_CTL                   (0x254)
+#define RXn_B6_CTL_MUTE_MASK                   BIT(0)
+#define RXn_B6_CTL_MUTE_ENABLE                 BIT(0)
+#define RXn_B6_CTL_MUTE_DISABLE                        0
+#define LPASS_CDC_RX1_B6_CTL_POR                               (0x00)
+#define LPASS_CDC_RX2_B6_CTL                   (0x274)
+#define LPASS_CDC_RX2_B6_CTL_POR                               (0x00)
+#define LPASS_CDC_RX3_B6_CTL                   (0x294)
+#define LPASS_CDC_RX3_B6_CTL_POR                               (0x00)
+#define LPASS_CDC_RX1_VOL_CTL_B1_CTL                   (0x258)
+#define LPASS_CDC_RX1_VOL_CTL_B1_CTL_POR                       (0x00)
+#define LPASS_CDC_RX2_VOL_CTL_B1_CTL                   (0x278)
+#define LPASS_CDC_RX2_VOL_CTL_B1_CTL_POR                       (0x00)
+#define LPASS_CDC_RX3_VOL_CTL_B1_CTL                   (0x298)
+#define LPASS_CDC_RX3_VOL_CTL_B1_CTL_POR                       (0x00)
+#define LPASS_CDC_RX1_VOL_CTL_B2_CTL                   (0x25C)
+#define LPASS_CDC_RX1_VOL_CTL_B2_CTL_POR                       (0x00)
+#define LPASS_CDC_RX2_VOL_CTL_B2_CTL                   (0x27C)
+#define LPASS_CDC_RX2_VOL_CTL_B2_CTL_POR                       (0x00)
+#define LPASS_CDC_RX3_VOL_CTL_B2_CTL                   (0x29C)
+#define LPASS_CDC_RX3_VOL_CTL_B2_CTL_POR                       (0x00)
+#define LPASS_CDC_TOP_GAIN_UPDATE                      (0x2A0)
+#define LPASS_CDC_TOP_GAIN_UPDATE_POR                          (0x00)
+#define LPASS_CDC_TOP_CTL                              (0x2A4)
+#define TOP_CTL_DIG_MCLK_FREQ_MASK                     BIT(0)
+#define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ              0
+#define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ                 BIT(0)
+
+#define LPASS_CDC_TOP_CTL_POR                                  (0x01)
+#define LPASS_CDC_DEBUG_DESER1_CTL                     (0x2E0)
+#define LPASS_CDC_DEBUG_DESER1_CTL_POR                         (0x00)
+#define LPASS_CDC_DEBUG_DESER2_CTL                     (0x2E4)
+#define LPASS_CDC_DEBUG_DESER2_CTL_POR                         (0x00)
+#define LPASS_CDC_DEBUG_B1_CTL_CFG                     (0x2E8)
+#define LPASS_CDC_DEBUG_B1_CTL_CFG_POR                         (0x00)
+#define LPASS_CDC_DEBUG_B2_CTL_CFG                     (0x2EC)
+#define LPASS_CDC_DEBUG_B2_CTL_CFG_POR                         (0x00)
+#define LPASS_CDC_DEBUG_B3_CTL_CFG                     (0x2F0)
+#define LPASS_CDC_DEBUG_B3_CTL_CFG_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B1_CTL                     (0x300)
+#define LPASS_CDC_IIR1_GAIN_B1_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B1_CTL                     (0x340)
+#define LPASS_CDC_IIR2_GAIN_B1_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B2_CTL                     (0x304)
+#define LPASS_CDC_IIR1_GAIN_B2_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B2_CTL                     (0x344)
+#define LPASS_CDC_IIR2_GAIN_B2_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B3_CTL                     (0x308)
+#define LPASS_CDC_IIR1_GAIN_B3_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B3_CTL                     (0x348)
+#define LPASS_CDC_IIR2_GAIN_B3_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B4_CTL                     (0x30C)
+#define LPASS_CDC_IIR1_GAIN_B4_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B4_CTL                     (0x34C)
+#define LPASS_CDC_IIR2_GAIN_B4_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B5_CTL                     (0x310)
+#define LPASS_CDC_IIR1_GAIN_B5_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B5_CTL                     (0x350)
+#define LPASS_CDC_IIR2_GAIN_B5_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B6_CTL                     (0x314)
+#define LPASS_CDC_IIR1_GAIN_B6_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B6_CTL                     (0x354)
+#define LPASS_CDC_IIR2_GAIN_B6_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B7_CTL                     (0x318)
+#define LPASS_CDC_IIR1_GAIN_B7_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B7_CTL                     (0x358)
+#define LPASS_CDC_IIR2_GAIN_B7_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_GAIN_B8_CTL                     (0x31C)
+#define LPASS_CDC_IIR1_GAIN_B8_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_GAIN_B8_CTL                     (0x35C)
+#define LPASS_CDC_IIR2_GAIN_B8_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_CTL                     (0x320)
+#define LPASS_CDC_IIR1_CTL_POR                         (0x40)
+#define LPASS_CDC_IIR2_CTL                     (0x360)
+#define LPASS_CDC_IIR2_CTL_POR                         (0x40)
+#define LPASS_CDC_IIR1_GAIN_TIMER_CTL                  (0x324)
+#define LPASS_CDC_IIR1_GAIN_TIMER_CTL_POR                      (0x00)
+#define LPASS_CDC_IIR2_GAIN_TIMER_CTL                  (0x364)
+#define LPASS_CDC_IIR2_GAIN_TIMER_CTL_POR                      (0x00)
+#define LPASS_CDC_IIR1_COEF_B1_CTL                     (0x328)
+#define LPASS_CDC_IIR1_COEF_B1_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_COEF_B1_CTL                     (0x368)
+#define LPASS_CDC_IIR2_COEF_B1_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR1_COEF_B2_CTL                     (0x32C)
+#define LPASS_CDC_IIR1_COEF_B2_CTL_POR                         (0x00)
+#define LPASS_CDC_IIR2_COEF_B2_CTL                     (0x36C)
+#define LPASS_CDC_IIR2_COEF_B2_CTL_POR                         (0x00)
+#define LPASS_CDC_CONN_RX1_B1_CTL                      (0x380)
+#define LPASS_CDC_CONN_RX1_B1_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_RX1_B2_CTL                      (0x384)
+#define LPASS_CDC_CONN_RX1_B2_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_RX1_B3_CTL                      (0x388)
+#define LPASS_CDC_CONN_RX1_B3_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_RX2_B1_CTL                      (0x38C)
+#define LPASS_CDC_CONN_RX2_B1_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_RX2_B2_CTL                      (0x390)
+#define LPASS_CDC_CONN_RX2_B2_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_RX2_B3_CTL                      (0x394)
+#define LPASS_CDC_CONN_RX2_B3_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_RX3_B1_CTL                      (0x398)
+#define LPASS_CDC_CONN_RX3_B1_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_RX3_B2_CTL                      (0x39C)
+#define LPASS_CDC_CONN_RX3_B2_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_TX_B1_CTL                       (0x3A0)
+#define LPASS_CDC_CONN_TX_B1_CTL_POR                           (0x00)
+#define LPASS_CDC_CONN_EQ1_B1_CTL                      (0x3A8)
+#define LPASS_CDC_CONN_EQ1_B1_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_EQ1_B2_CTL                      (0x3AC)
+#define LPASS_CDC_CONN_EQ1_B2_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_EQ1_B3_CTL                      (0x3B0)
+#define LPASS_CDC_CONN_EQ1_B3_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_EQ1_B4_CTL                      (0x3B4)
+#define LPASS_CDC_CONN_EQ1_B4_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_EQ2_B1_CTL                      (0x3B8)
+#define LPASS_CDC_CONN_EQ2_B1_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_EQ2_B2_CTL                      (0x3BC)
+#define LPASS_CDC_CONN_EQ2_B2_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_EQ2_B3_CTL                      (0x3C0)
+#define LPASS_CDC_CONN_EQ2_B3_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_EQ2_B4_CTL                      (0x3C4)
+#define LPASS_CDC_CONN_EQ2_B4_CTL_POR                          (0x00)
+#define LPASS_CDC_CONN_TX_I2S_SD1_CTL                  (0x3C8)
+#define LPASS_CDC_CONN_TX_I2S_SD1_CTL_POR                      (0x00)
+#define LPASS_CDC_TX1_VOL_CTL_TIMER                    (0x480)
+#define LPASS_CDC_TX1_VOL_CTL_TIMER_POR                        (0x00)
+#define LPASS_CDC_TX2_VOL_CTL_TIMER                    (0x4A0)
+#define LPASS_CDC_TX2_VOL_CTL_TIMER_POR                        (0x00)
+#define LPASS_CDC_TX1_VOL_CTL_GAIN                     (0x484)
+#define LPASS_CDC_TX1_VOL_CTL_GAIN_POR                         (0x00)
+#define LPASS_CDC_TX2_VOL_CTL_GAIN                     (0x4A4)
+#define LPASS_CDC_TX2_VOL_CTL_GAIN_POR                         (0x00)
+#define LPASS_CDC_TX1_VOL_CTL_CFG                      (0x488)
+#define TX_VOL_CTL_CFG_MUTE_EN_MASK                    BIT(0)
+#define TX_VOL_CTL_CFG_MUTE_EN_ENABLE                  BIT(0)
+
+#define LPASS_CDC_TX1_VOL_CTL_CFG_POR                          (0x00)
+#define LPASS_CDC_TX2_VOL_CTL_CFG                      (0x4A8)
+#define LPASS_CDC_TX2_VOL_CTL_CFG_POR                          (0x00)
+#define LPASS_CDC_TX1_MUX_CTL                  (0x48C)
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK                   GENMASK(5, 4)
+#define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT                  4
+#define TX_MUX_CTL_CUT_OFF_FREQ_CF_NEG_3DB_4HZ         (0x0 << 4)
+#define TX_MUX_CTL_CUT_OFF_FREQ_CF_NEG_3DB_75HZ                (0x1 << 4)
+#define TX_MUX_CTL_CUT_OFF_FREQ_CF_NEG_3DB_150HZ       (0x2 << 4)
+#define TX_MUX_CTL_HPF_BP_SEL_MASK                     BIT(3)
+#define TX_MUX_CTL_HPF_BP_SEL_BYPASS                   BIT(3)
+#define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS                        0
+
+#define LPASS_CDC_TX1_MUX_CTL_POR                              (0x00)
+#define LPASS_CDC_TX2_MUX_CTL                  (0x4AC)
+#define LPASS_CDC_TX2_MUX_CTL_POR                              (0x00)
+#define LPASS_CDC_TX1_CLK_FS_CTL                       (0x490)
+#define LPASS_CDC_TX1_CLK_FS_CTL_POR                           (0x03)
+#define LPASS_CDC_TX2_CLK_FS_CTL                       (0x4B0)
+#define LPASS_CDC_TX2_CLK_FS_CTL_POR                           (0x03)
+#define LPASS_CDC_TX1_DMIC_CTL                 (0x494)
+#define LPASS_CDC_TX1_DMIC_CTL_POR                             (0x00)
+#define LPASS_CDC_TX2_DMIC_CTL                 (0x4B4)
+#define TXN_DMIC_CTL_CLK_SEL_MASK              GENMASK(2, 0)
+#define TXN_DMIC_CTL_CLK_SEL_DIV2              0x0
+#define TXN_DMIC_CTL_CLK_SEL_DIV3              0x1
+#define TXN_DMIC_CTL_CLK_SEL_DIV4              0x2
+#define TXN_DMIC_CTL_CLK_SEL_DIV6              0x3
+#define TXN_DMIC_CTL_CLK_SEL_DIV16             0x4
+#define LPASS_CDC_TX2_DMIC_CTL_POR                             (0x00)
+#endif
diff --git a/sound/soc/codecs/msm8916-wcd.c b/sound/soc/codecs/msm8916-wcd.c
new file mode 100644 (file)
index 0000000..fb4d0ad
--- /dev/null
@@ -0,0 +1,1582 @@
+/* Copyright (c) 2016, 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/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+
+#include "msm8916-wcd-registers.h"
+#include "msm8916-wcd.h"
+#include "dt-bindings/sound/msm8916-wcd.h"
+
+#define MSM8916_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define MSM8916_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+               SNDRV_PCM_FMTBIT_S24_LE)
+
+/* Internal status on mute_mask to track mute on different sinks */
+#define MUTE_MASK_HPHL_PA_DISABLE              BIT(1)
+#define MUTE_MASK_HPHR_PA_DISABLE              BIT(2)
+#define MUTE_MASK_EAR_PA_DISABLE               BIT(3)
+#define MUTE_MASK_SPKR_PA_DISABLE              BIT(4)
+
+struct msm8916_wcd_chip {
+       struct regmap *analog_map;
+       struct regmap *digital_map;
+       unsigned int analog_offset;
+       u16 pmic_rev;
+       u16 codec_version;
+
+       struct clk *mclk;
+       struct regulator *vddio;
+       struct regulator *vdd_tx_rx;
+
+       u32 mute_mask;
+       u32 rx_bias_count;
+       bool micbias1_cap_mode;
+       bool micbias2_cap_mode;
+       int dmic_clk_cnt;
+};
+
+static unsigned long rx_gain_reg[] = {
+       LPASS_CDC_RX1_VOL_CTL_B2_CTL,
+       LPASS_CDC_RX2_VOL_CTL_B2_CTL,
+       LPASS_CDC_RX3_VOL_CTL_B2_CTL,
+};
+
+static unsigned long tx_gain_reg[] = {
+       LPASS_CDC_TX1_VOL_CTL_GAIN,
+       LPASS_CDC_TX2_VOL_CTL_GAIN,
+};
+
+static const char *const rx_mix1_text[] = {
+       "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
+};
+
+static const char *const dec_mux_text[] = {
+       "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
+};
+static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" };
+static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" };
+static const char *const rdac2_mux_text[] = { "ZERO", "RX2", "RX1" };
+static const char *const hph_text[] = { "ZERO", "Switch", };
+
+/* RX1 MIX1 */
+static const struct soc_enum rx_mix1_inp_enum[] = {
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text),
+};
+
+/* RX1 MIX2 */
+static const struct soc_enum rx_mix2_inp1_chain_enum =
+SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
+
+/* RX2 MIX1 */
+static const struct soc_enum rx2_mix1_inp_enum[] = {
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text),
+};
+
+/* RX2 MIX2 */
+static const struct soc_enum rx2_mix2_inp1_chain_enum =
+SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
+
+/* RX3 MIX1 */
+static const struct soc_enum rx3_mix1_inp_enum[] = {
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text),
+       SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text),
+};
+
+/* DEC */
+static const struct soc_enum dec1_mux_enum =
+SOC_ENUM_SINGLE(LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+SOC_ENUM_SINGLE(LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text);
+
+/* RDAC2 MUX */
+static const struct soc_enum rdac2_mux_enum =
+SOC_ENUM_SINGLE(CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 3, rdac2_mux_text);
+
+/* ADC2 MUX */
+static const struct soc_enum adc2_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
+static const struct soc_enum hph_enum =
+SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(hph_text), hph_text);
+
+static const struct snd_kcontrol_new spkr_switch[] = {
+       SOC_DAPM_SINGLE("Switch", CDC_A_SPKR_DAC_CTL, 7, 1, 0)
+};
+
+static const struct snd_kcontrol_new dec1_mux =
+SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new rdac2_mux =
+SOC_DAPM_ENUM("RDAC2 MUX Mux", rdac2_mux_enum);
+
+static const struct snd_kcontrol_new tx_adc2_mux =
+SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]);
+
+static const struct snd_kcontrol_new rx_mix1_inp3_mux =
+SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]);
+
+static const struct snd_kcontrol_new rx2_mix1_inp3_mux =
+SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]);
+
+static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
+SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]);
+
+static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum);
+
+static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum);
+
+/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */
+static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0);
+
+/* Analog Gain control 0 dB to +24 dB in 6 dB steps */
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 600, 0);
+
+static const struct snd_kcontrol_new msm8916_wcd_snd_controls[] = {
+       SOC_SINGLE_TLV("ADC1 Volume", CDC_A_TX_1_EN, 3, 8, 0, analog_gain),
+       SOC_SINGLE_TLV("ADC2 Volume", CDC_A_TX_2_EN, 3, 8, 0, analog_gain),
+       SOC_SINGLE_TLV("ADC3 Volume", CDC_A_TX_3_EN, 3, 8, 0, analog_gain),
+       SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL,
+                         -128, 127, digital_gain),
+       SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL,
+                         -128, 127, digital_gain),
+       SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL,
+                         -128, 127, digital_gain),
+};
+
+static int msm8916_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
+                            unsigned int val)
+{
+       int ret = -EINVAL;
+       struct msm8916_wcd_chip *chip = dev_get_drvdata(codec->dev);
+       u8 *cache = codec->reg_cache;
+
+       if (!msm8916_wcd_reg_readonly[reg])
+               cache[reg] = val;
+
+       if (MSM8916_WCD_IS_TOMBAK_REG(reg)) {
+               /* codec registers inside pmic core */
+               ret = regmap_write(chip->analog_map,
+                                  chip->analog_offset + reg, val);
+       } else if (MSM8916_WCD_IS_DIGITAL_REG(reg)) {
+               /* codec registers in the cpu core */
+               u32 v = val & MSM8916_WCD_REG_VAL_MASK;
+               u16 offset = MSM8916_WCD_DIGITAL_REG(reg);
+
+               ret = regmap_write(chip->digital_map, offset, v);
+       }
+
+       return ret;
+}
+
+static unsigned int msm8916_wcd_read(struct snd_soc_codec *codec,
+                                    unsigned int reg)
+{
+       int ret = -EINVAL;
+       u32 val = 0;
+       struct msm8916_wcd_chip *chip = dev_get_drvdata(codec->dev);
+       u8 *cache = codec->reg_cache;
+
+       if (!msm8916_wcd_reg_readonly[reg])
+               return cache[reg];
+
+       if (MSM8916_WCD_IS_TOMBAK_REG(reg)) {
+               ret = regmap_read(chip->analog_map,
+                                 chip->analog_offset + reg, &val);
+       } else if (MSM8916_WCD_IS_DIGITAL_REG(reg)) {
+               u32 v;
+               u16 offset = MSM8916_WCD_DIGITAL_REG(reg);
+
+               ret = regmap_read(chip->digital_map, offset, &v);
+               val = (u8) v;
+       }
+
+       return val;
+}
+
+static void msm8916_wcd_configure_cap(struct snd_soc_codec *codec,
+                                     bool micbias1, bool micbias2)
+{
+       struct msm8916_wcd_chip *wcd = snd_soc_codec_get_drvdata(codec);
+
+       if (micbias1 && micbias2) {
+               if ((wcd->micbias1_cap_mode == MICB_1_EN_EXT_BYP_CAP) ||
+                   (wcd->micbias2_cap_mode == MICB_1_EN_EXT_BYP_CAP))
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                           MICB_1_EN_BYP_CAP_MASK,
+                                           MICB_1_EN_EXT_BYP_CAP);
+               else
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                           MICB_1_EN_BYP_CAP_MASK,
+                                           MICB_1_EN_NO_EXT_BYP_CAP);
+       } else if (micbias2) {
+               snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                   MICB_1_EN_BYP_CAP_MASK,
+                                   wcd->micbias2_cap_mode);
+       } else if (micbias1) {
+               snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                   MICB_1_EN_BYP_CAP_MASK,
+                                   wcd->micbias1_cap_mode);
+       } else {
+               snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                   MICB_1_EN_BYP_CAP_MASK, 0);
+       }
+}
+
+static int msm8916_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
+                                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, CDC_A_NCP_FBCTRL,
+                                   CDC_A_NCP_FBCTRL_FB_CLK_INV_MASK,
+                                   CDC_A_NCP_FBCTRL_FB_CLK_INV);
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
+               if (w->shift == 5)
+                       snd_soc_update_bits(codec, LPASS_CDC_RX1_B6_CTL,
+                                           RXn_B6_CTL_MUTE_MASK, 0);
+               else if (w->shift == 4)
+                       snd_soc_update_bits(codec, LPASS_CDC_RX2_B6_CTL,
+                                           RXn_B6_CTL_MUTE_MASK, 0);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               if (w->shift == 5) {
+                       snd_soc_update_bits(codec, LPASS_CDC_RX1_B6_CTL,
+                                           RXn_B6_CTL_MUTE_MASK,
+                                           RXn_B6_CTL_MUTE_ENABLE);
+                       msm8916_wcd->mute_mask |= MUTE_MASK_HPHL_PA_DISABLE;
+               } else if (w->shift == 4) {
+                       snd_soc_update_bits(codec, LPASS_CDC_RX2_B6_CTL,
+                                           RXn_B6_CTL_MUTE_MASK,
+                                           RXn_B6_CTL_MUTE_ENABLE);
+                       msm8916_wcd->mute_mask |= MUTE_MASK_HPHR_PA_DISABLE;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_NCP_CLK_EN,
+                                   DIG_CLK_CTL_NCP_CLK_EN);
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w,
+                                     struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, CDC_A_RX_HPH_L_PA_DAC_CTL,
+                                   RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK,
+                                   RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET);
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD1_CLK_EN,
+                                   DIG_CLK_CTL_RXD1_CLK_EN);
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_EAR_HPHL_CLK_EN,
+                                   ANA_CLK_CTL_EAR_HPHL_CLK_EN);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, CDC_A_RX_HPH_L_PA_DAC_CTL,
+                                   RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_EAR_HPHL_CLK_EN, 0);
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD1_CLK_EN, 0);
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
+                                          struct snd_kcontrol *kcontrol,
+                                          int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_SPKR_CLK_EN_MASK,
+                                   ANA_CLK_CTL_SPKR_CLK_EN);
+               snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+                                   SPKR_PWRSTG_CTL_DAC_EN_MASK,
+                                   SPKR_PWRSTG_CTL_DAC_EN_ENABLE);
+               snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+                                   SPKR_PWRSTG_CTL_MASK,
+                                   SPKR_PWRSTG_CTL_DEFAULTS);
+               if (!TOMBAK_IS_1_0(msm8916_wcd->pmic_rev))
+                       snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL,
+                                           RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK,
+                                           RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, CDC_A_SPKR_DRV_CTL,
+                                   SPKR_DRV_CTL_DEF_MASK,
+                                   SPKR_DRV_CTL_DEF_VAL);
+
+               snd_soc_update_bits(codec, LPASS_CDC_RX3_B6_CTL,
+                                   RXn_B6_CTL_MUTE_MASK,
+                                   RXn_B6_CTL_MUTE_DISABLE);
+               snd_soc_update_bits(codec, w->reg,
+                                   SPKR_DRV_CLASSD_PA_EN_MASK,
+                                   SPKR_DRV_CLASSD_PA_EN_ENABLE);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+                                   SPKR_PWRSTG_CTL_MASK, 0);
+               snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL,
+                                   SPKR_PWRSTG_CTL_DAC_EN_MASK, 0);
+
+               snd_soc_update_bits(codec, CDC_A_SPKR_DAC_CTL,
+                                   SPKR_DAC_CTL_DAC_RESET_MASK,
+                                   SPKR_DAC_CTL_DAC_RESET_NORMAL);
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_SPKR_CLK_EN, 0);
+               if (!TOMBAK_IS_1_0(msm8916_wcd->pmic_rev))
+                       snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL,
+                                           RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, 0);
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
+                                           struct snd_kcontrol *kcontrol,
+                                           int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK,
+                                   DIG_CLK_CTL_RXD_PDM_CLK_EN);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (msm8916_wcd->rx_bias_count == 0)
+                       snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                           DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_rx_chain(struct snd_soc_dapm_widget *w,
+                                            struct snd_kcontrol *kcontrol,
+                                            int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD_PDM_CLK_EN,
+                                   DIG_CLK_CTL_RXD_PDM_CLK_EN);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD_PDM_CLK_EN, 0);
+               snd_soc_update_bits(codec, w->reg, 1 << w->shift, 0x00);
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+                                               struct snd_kcontrol *kcontrol,
+                                               int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK |
+                                   DIG_CLK_CTL_NCP_CLK_EN_MASK,
+                                   DIG_CLK_CTL_RXD_PDM_CLK_EN |
+                                   DIG_CLK_CTL_NCP_CLK_EN);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_NCP_CLK_EN_MASK, 0);
+               if (msm8916_wcd->rx_bias_count == 0)
+                       snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                           DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK, 0);
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+                                           struct snd_kcontrol *kcontrol,
+                                           int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               msm8916_wcd->rx_bias_count++;
+               if (msm8916_wcd->rx_bias_count == 1) {
+                       snd_soc_update_bits(codec, CDC_A_RX_COM_BIAS_DAC,
+                                           RX_COM_BIAS_DAC_RX_BIAS_EN_MASK |
+                                           RX_COM_BIAS_DAC_DAC_REF_EN_MASK,
+                                           RX_COM_BIAS_DAC_RX_BIAS_EN_ENABLE |
+                                           RX_COM_BIAS_DAC_DAC_REF_EN_ENABLE);
+               }
+
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               msm8916_wcd->rx_bias_count--;
+               if (msm8916_wcd->rx_bias_count == 0) {
+                       snd_soc_update_bits(codec, CDC_A_RX_COM_BIAS_DAC,
+                                           RX_COM_BIAS_DAC_RX_BIAS_EN_MASK |
+                                           RX_COM_BIAS_DAC_DAC_REF_EN_MASK, 0);
+
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static void msm8916_wcd_micbias2_enable(struct snd_soc_codec *codec, bool on)
+{
+       if (on) {
+               snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                                   MICB_1_CTL_EXT_PRECHARG_EN_MASK |
+                                   MICB_1_CTL_INT_PRECHARG_BYP_MASK,
+                                   MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL
+                                   | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE);
+               snd_soc_write(codec, CDC_A_MICB_1_VAL,
+                             MICB_1_VAL_MICB_OUT_VAL_V2P70V);
+               /*
+                * Special headset needs MICBIAS as 2.7V so wait for
+                * 50 msec for the MICBIAS to reach 2.7 volts.
+                */
+               msleep(50);
+               snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                                   MICB_1_CTL_EXT_PRECHARG_EN_MASK |
+                                   MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0);
+       }
+}
+
+static int msm8916_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+                                           struct snd_kcontrol *kcontrol,
+                                           int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       char *internal1_text = "Internal1";
+       char *internal2_text = "Internal2";
+       char *internal3_text = "Internal3";
+       char *external2_text = "External2";
+       char *external_text = "External";
+       bool micbias2;
+
+       micbias2 = (snd_soc_read(codec, CDC_A_MICB_2_EN) & 0x80);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (strnstr(w->name, internal1_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX1_INT_RBIAS_EN_MASK,
+                                           MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE);
+               } else if (strnstr(w->name, internal2_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX2_INT_RBIAS_EN_MASK,
+                                           MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE);
+                       snd_soc_update_bits(codec, w->reg,
+                                           MICB_1_EN_BYP_CAP_MASK |
+                                           MICB_1_EN_PULL_DOWN_EN_MASK, 0);
+               } else if (strnstr(w->name, internal3_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX3_INT_RBIAS_EN_MASK,
+                                           MICB_1_INT_TX3_INT_RBIAS_EN_ENABLE);
+               }
+               if (!strnstr(w->name, external_text, 30))
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_EN,
+                                           MICB_1_EN_OPA_STG2_TAIL_CURR_MASK |
+                                           MICB_1_EN_TX3_GND_SEL_MASK,
+                                           MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA);
+               if (w->reg == CDC_A_MICB_1_EN)
+                       msm8916_wcd_configure_cap(codec, true, micbias2);
+
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               if (strnstr(w->name, internal1_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX1_INT_PULLUP_EN_MASK,
+                                           MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_MICBIAS);
+               } else if (strnstr(w->name, internal2_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX2_INT_PULLUP_EN_MASK,
+                                           MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_MICBIAS);
+                       msm8916_wcd_micbias2_enable(codec, true);
+                       msm8916_wcd_configure_cap(codec, false, true);
+               } else if (strnstr(w->name, internal3_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX3_INT_PULLUP_EN_MASK,
+                                           MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_MICBIAS);
+               } else if (strnstr(w->name, external2_text, 30)) {
+                       msm8916_wcd_micbias2_enable(codec, true);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (strnstr(w->name, internal1_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX1_INT_RBIAS_EN_MASK,
+                                           MICB_1_INT_TX1_INT_RBIAS_EN_DISABLE);
+               } else if (strnstr(w->name, internal2_text, 30)) {
+                       msm8916_wcd_micbias2_enable(codec, false);
+               } else if (strnstr(w->name, internal3_text, 30)) {
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS,
+                                           MICB_1_INT_TX3_INT_RBIAS_EN_MASK,
+                                           MICB_1_INT_TX3_INT_RBIAS_EN_DISABLE);
+               } else if (strnstr(w->name, external2_text, 30)) {
+                       msm8916_wcd_micbias2_enable(codec, false);
+                       break;
+               }
+               if (w->reg == CDC_A_MICB_1_EN)
+                       msm8916_wcd_configure_cap(codec, false, micbias2);
+               break;
+       }
+
+       return 0;
+}
+
+static void msm8916_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
+                                              int enable)
+{
+       if (enable) {
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_TXA_CLK25_EN,
+                                   ANA_CLK_CTL_TXA_CLK25_EN);
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_TXD_CLK_EN,
+                                   DIG_CLK_CTL_TXD_CLK_EN);
+       } else {
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_TXD_CLK_EN, 0);
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_TXA_CLK25_EN, 0);
+       }
+}
+
+static int msm8916_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       u16 adc_reg = CDC_A_TX_1_2_TEST_CTL_2;
+       u8 init_bit_shift;
+
+       if (w->reg == CDC_A_TX_1_EN)
+               init_bit_shift = 5;
+       else
+               init_bit_shift = 4;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               msm8916_wcd_codec_enable_adc_block(codec, 1);
+               if (w->reg == CDC_A_TX_2_EN)
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                                           MICB_1_CTL_CFILT_REF_SEL_MASK,
+                                           MICB_1_CTL_CFILT_REF_SEL_HPF_REF);
+               /*
+                * Add delay of 10 ms to give sufficient time for the voltage
+                * to shoot up and settle so that the txfe init does not
+                * happen when the input voltage is changing too much.
+                */
+               usleep_range(10000, 10010);
+               snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+                                   1 << init_bit_shift);
+               if (w->reg == CDC_A_TX_1_EN)
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL,
+                                           CONN_TX1_SERIAL_TX1_MUX,
+                                           CONN_TX1_SERIAL_TX1_ADC_1);
+               else if ((w->reg == CDC_A_TX_2_EN) || (w->reg == CDC_A_TX_3_EN))
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
+                                           CONN_TX2_SERIAL_TX2_MUX,
+                                           CONN_TX2_SERIAL_TX2_ADC_2);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               /*
+                * Add delay of 12 ms before deasserting the init
+                * to reduce the tx pop
+                */
+               usleep_range(12000, 12010);
+               snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               msm8916_wcd_codec_enable_adc_block(codec, 0);
+               if (w->reg == CDC_A_TX_2_EN)
+                       snd_soc_update_bits(codec, CDC_A_MICB_1_CTL,
+                                           MICB_1_CTL_CFILT_REF_SEL_MASK, 0);
+               if (w->reg == CDC_A_TX_1_EN)
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL,
+                                           CONN_TX1_SERIAL_TX1_MUX,
+                                           CONN_TX1_SERIAL_TX1_ZERO);
+               else if ((w->reg == CDC_A_TX_2_EN) || (w->reg == CDC_A_TX_3_EN))
+                       snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL,
+                                           CONN_TX2_SERIAL_TX2_MUX,
+                                           CONN_TX2_SERIAL_TX2_ZERO);
+
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
+                                     struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec,
+                                   CDC_A_RX_HPH_R_PA_DAC_CTL,
+                                   RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK,
+                                   RX_HPH_R_PA_DAC_CTL_DATA_RESET);
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD2_CLK_EN,
+                                   DIG_CLK_CTL_RXD2_CLK_EN);
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK,
+                                   ANA_CLK_CTL_EAR_HPHR_CLK_EN);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, CDC_A_RX_HPH_R_PA_DAC_CTL,
+                                   RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, CDC_D_CDC_ANA_CLK_CTL,
+                                   ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK, 0);
+               snd_soc_update_bits(codec, CDC_D_CDC_DIG_CLK_CTL,
+                                   DIG_CLK_CTL_RXD2_CLK_EN, 0);
+               break;
+       }
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+                                                struct snd_kcontrol *kcontrol,
+                                                int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               /* apply the digital gain after the interpolator is enabled */
+               snd_soc_write(codec, rx_gain_reg[w->shift],
+                             snd_soc_read(codec, rx_gain_reg[w->shift]));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, LPASS_CDC_CLK_RX_RESET_CTL,
+                                   1 << w->shift, 1 << w->shift);
+               snd_soc_update_bits(codec, LPASS_CDC_CLK_RX_RESET_CTL,
+                                   1 << w->shift, 0x0);
+               /* disable the mute enabled during the PMD of this device */
+               if (msm8916_wcd->mute_mask & MUTE_MASK_HPHL_PA_DISABLE) {
+                       snd_soc_update_bits(codec,
+                                           LPASS_CDC_RX1_B6_CTL,
+                                           RXn_B6_CTL_MUTE_MASK,
+                                           RXn_B6_CTL_MUTE_DISABLE);
+                       msm8916_wcd->mute_mask &= ~(MUTE_MASK_HPHL_PA_DISABLE);
+               }
+               if (msm8916_wcd->mute_mask & MUTE_MASK_HPHR_PA_DISABLE) {
+                       snd_soc_update_bits(codec, LPASS_CDC_RX2_B6_CTL,
+                                           RXn_B6_CTL_MUTE_MASK,
+                                           RXn_B6_CTL_MUTE_DISABLE);
+
+                       msm8916_wcd->mute_mask &= ~(MUTE_MASK_HPHR_PA_DISABLE);
+               }
+               if (msm8916_wcd->mute_mask & MUTE_MASK_SPKR_PA_DISABLE) {
+                       snd_soc_update_bits(codec, LPASS_CDC_RX3_B6_CTL,
+                                           RXn_B6_CTL_MUTE_MASK,
+                                           RXn_B6_CTL_MUTE_DISABLE);
+
+                       msm8916_wcd->mute_mask &= ~(MUTE_MASK_SPKR_PA_DISABLE);
+               }
+       }
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       unsigned int decimator;
+       char *dec_name = NULL;
+       char *widget_name = NULL;
+       char *temp;
+       int ret = 0;
+       u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+       u8 dec_hpf_cut_of_freq;
+       char *dec_num;
+
+       widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+       if (!widget_name)
+               return -ENOMEM;
+       temp = widget_name;
+
+       dec_name = strsep(&widget_name, " ");
+       widget_name = temp;
+       if (!dec_name) {
+               dev_err(codec->dev, "Invalid decimator = %s\n", w->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       dec_num = strpbrk(dec_name, "12");
+       if (dec_num == NULL) {
+               dev_err(codec->dev, "Invalid Decimator\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = kstrtouint(dec_num, 10, &decimator);
+       if (ret < 0) {
+               dev_err(codec->dev, "Invalid decimator = %s\n", dec_name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL;
+       tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1);
+       tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Enableable TX digital mute */
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK,
+                                   TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
+               dec_hpf_cut_of_freq =
+                   snd_soc_read(codec,
+                                tx_mux_ctl_reg) & TX_MUX_CTL_CUT_OFF_FREQ_MASK;
+               dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT;
+               if (dec_hpf_cut_of_freq !=
+                   TX_MUX_CTL_CUT_OFF_FREQ_CF_NEG_3DB_150HZ) {
+                       /* set cut of freq to CF_MIN_3DB_150HZ (0x1) */
+                       snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                           TX_MUX_CTL_CUT_OFF_FREQ_MASK,
+                                           TX_MUX_CTL_CUT_OFF_FREQ_CF_NEG_3DB_150HZ);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               /* enable HPF */
+               snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                   TX_MUX_CTL_HPF_BP_SEL_MASK,
+                                   TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS);
+               /* apply the digital gain after the decimator is enabled */
+               snd_soc_write(codec, tx_gain_reg[w->shift],
+                             snd_soc_read(codec, tx_gain_reg[w->shift]));
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK,
+                                   TX_VOL_CTL_CFG_MUTE_EN_ENABLE);
+               snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                   TX_MUX_CTL_HPF_BP_SEL_MASK,
+                                   TX_MUX_CTL_HPF_BP_SEL_BYPASS);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+                                   1 << w->shift);
+               snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+               snd_soc_update_bits(codec, tx_mux_ctl_reg,
+                                   TX_MUX_CTL_HPF_BP_SEL_MASK,
+                                   TX_MUX_CTL_HPF_BP_SEL_BYPASS);
+               snd_soc_update_bits(codec, tx_vol_ctl_reg,
+                                   TX_VOL_CTL_CFG_MUTE_EN_MASK, 0);
+               break;
+       }
+
+out:
+       kfree(widget_name);
+       return ret;
+}
+
+static int msm8916_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+                                        struct snd_kcontrol *kcontrol,
+                                        int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+       u16 dmic_clk_reg = LPASS_CDC_CLK_DMIC_B1_CTL;
+       unsigned int dmic;
+       int ret;
+       char *dec_num = strpbrk(w->name, "12");
+
+       if (dec_num == NULL) {
+               dev_err(codec->dev, "Invalid DMIC\n");
+               return -EINVAL;
+       }
+
+       ret = kstrtouint(dec_num, 10, &dmic);
+       if (ret < 0) {
+               dev_err(codec->dev, "Invalid DMIC line on the codec\n");
+               return -EINVAL;
+       }
+       if (dmic > 2) {
+               dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (++msm8916_wcd->dmic_clk_cnt == 1) {
+                       snd_soc_update_bits(codec, dmic_clk_reg,
+                                           DMIC_B1_CTL_DMIC0_CLK_SEL_MASK,
+                                           DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3);
+                       snd_soc_update_bits(codec, dmic_clk_reg,
+                                           DMIC_B1_CTL_DMIC0_CLK_EN_MASK,
+                                           DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE);
+               }
+               if (dmic == 1)
+                       snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL,
+                                           TXN_DMIC_CTL_CLK_SEL_MASK,
+                                           TXN_DMIC_CTL_CLK_SEL_DIV3);
+               if (dmic == 2)
+                       snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL,
+                                           TXN_DMIC_CTL_CLK_SEL_MASK,
+                                           TXN_DMIC_CTL_CLK_SEL_DIV3);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (--msm8916_wcd->dmic_clk_cnt == 0)
+                       snd_soc_update_bits(codec, dmic_clk_reg,
+                                           DMIC_B1_CTL_DMIC0_CLK_EN_MASK, 0);
+               break;
+       }
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget msm8916_wcd_dapm_widgets[] = {
+       /*RX stuff */
+       SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+       SND_SOC_DAPM_PGA_E("HPHL PA", CDC_A_RX_HPH_CNP_EN,
+                          5, 0, NULL, 0,
+                          msm8916_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+                          SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux),
+       SND_SOC_DAPM_MIXER_E("HPHL DAC",
+                            CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
+                            0, msm8916_wcd_hphl_dac_event,
+                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("HPHR PA", CDC_A_RX_HPH_CNP_EN,
+                          4, 0, NULL, 0,
+                          msm8916_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
+                          SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux),
+       SND_SOC_DAPM_MIXER_E("HPHR DAC",
+                            CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
+                            0, msm8916_wcd_hphr_dac_event,
+                            SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
+                          spkr_switch, ARRAY_SIZE(spkr_switch)),
+
+       /* Speaker */
+       SND_SOC_DAPM_OUTPUT("SPK_OUT"),
+       SND_SOC_DAPM_PGA_E("SPK PA", CDC_A_SPKR_DRV_CTL,
+                          6, 0, NULL, 0, msm8916_wcd_codec_enable_spk_pa,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER_E("RX1 MIX2", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+                            0, msm8916_wcd_codec_enable_interpolator,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX2 MIX2", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+                            0, msm8916_wcd_codec_enable_interpolator,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX3 MIX1", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+                            0, msm8916_wcd_codec_enable_interpolator,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("RX1 CLK", CDC_D_CDC_DIG_CLK_CTL, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RX2 CLK", CDC_D_CDC_DIG_CLK_CTL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("RX3 CLK", CDC_D_CDC_DIG_CLK_CTL,
+                           2, 0, msm8916_wcd_codec_enable_dig_clk,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX1 CHAIN", LPASS_CDC_RX1_B6_CTL, 0, 0,
+                            NULL, 0, msm8916_wcd_codec_enable_rx_chain,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX2 CHAIN", LPASS_CDC_RX2_B6_CTL, 0, 0,
+                            NULL, 0, msm8916_wcd_codec_enable_rx_chain,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX3 CHAIN", LPASS_CDC_RX3_B6_CTL, 0, 0,
+                            NULL, 0, msm8916_wcd_codec_enable_rx_chain,
+                            SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx_mix1_inp1_mux),
+       SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+                        &rx_mix1_inp2_mux),
+       SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+                        &rx_mix1_inp3_mux),
+       SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx2_mix1_inp1_mux),
+       SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+                        &rx2_mix1_inp2_mux),
+       SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+                        &rx2_mix1_inp3_mux),
+       SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+                        &rx3_mix1_inp1_mux),
+       SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+                        &rx3_mix1_inp2_mux),
+       SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+                        &rx3_mix1_inp3_mux),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micbias", 0, 0),
+       SND_SOC_DAPM_SUPPLY("CP", CDC_A_NCP_EN, 0, 0,
+                           msm8916_wcd_codec_enable_charge_pump,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+                           msm8916_wcd_codec_enable_rx_bias,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("SPK_RX_BIAS", SND_SOC_NOPM, 0, 0,
+                           msm8916_wcd_codec_enable_rx_bias,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* TX */
+       SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL,
+                             2, 0, NULL, 0),
+       SND_SOC_DAPM_INPUT("AMIC1"),
+       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal1", CDC_A_MICB_1_EN, 7, 0,
+                           msm8916_wcd_codec_enable_micbias,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal2", CDC_A_MICB_2_EN, 7, 0,
+                           msm8916_wcd_codec_enable_micbias,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal3", CDC_A_MICB_1_EN, 7, 0,
+                           msm8916_wcd_codec_enable_micbias,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                           SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0,
+                          msm8916_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, CDC_A_TX_2_EN, 7, 0,
+                          msm8916_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, CDC_A_TX_3_EN, 7, 0,
+                          msm8916_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+                          SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux),
+       SND_SOC_DAPM_SUPPLY("MIC BIAS External", CDC_A_MICB_1_EN, 7, 0,
+                           msm8916_wcd_codec_enable_micbias,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0,
+                           msm8916_wcd_codec_enable_micbias,
+                           SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_INPUT("AMIC3"),
+       SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+                          &dec1_mux, msm8916_wcd_codec_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+                          &dec2_mux, msm8916_wcd_codec_enable_dec,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
+       SND_SOC_DAPM_INPUT("AMIC2"),
+       SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Digital Mic Inputs */
+       SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+                          msm8916_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+                          SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+                          msm8916_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+                          SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL,
+                           4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0,
+                           NULL, 0),
+};
+
+static int msm8916_wcd_codec_parse_dt(struct platform_device *pdev,
+                                     struct msm8916_wcd_chip *chip)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       int ret;
+       struct regulator_bulk_data regs[2];
+       const char *ext1_cap = "qcom,micbias1-ext-cap";
+       const char *ext2_cap = "qcom,micbias2-ext-cap";
+       u32 res[2];
+
+       ret = of_property_read_u32_array(np, "reg", res, 2);
+       if (ret < 0)
+               return ret;
+
+       if (of_property_read_bool(pdev->dev.of_node, ext1_cap))
+               chip->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP;
+       else
+               chip->micbias1_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+
+       if (of_property_read_bool(pdev->dev.of_node, ext2_cap))
+               chip->micbias2_cap_mode = MICB_1_EN_EXT_BYP_CAP;
+       else
+               chip->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP;
+
+       chip->analog_offset = res[0];
+       chip->digital_map = syscon_regmap_lookup_by_phandle(np,
+                                                           "qcom,lpass-codec-core");
+       if (IS_ERR(chip->digital_map))
+               return PTR_ERR(chip->digital_map);
+
+       chip->mclk = devm_clk_get(dev, "mclk");
+       if (IS_ERR(chip->mclk)) {
+               dev_err(dev, "failed to get mclk\n");
+               return PTR_ERR(chip->mclk);
+       }
+
+       regs[0].supply = "vddio";
+       regs[1].supply = "vdd-tx-rx";
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(regs), regs);
+       if (ret) {
+               dev_err(dev, "Failed to get regulator supplies %d\n", ret);
+               return ret;
+       }
+       chip->vddio = regs[0].consumer;
+       chip->vdd_tx_rx = regs[1].consumer;
+
+       return 0;
+}
+
+static int msm8916_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
+                                               int enable)
+{
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+       unsigned long mclk_rate;
+
+       if (enable) {
+               snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL,
+                                   MCLK_CTL_MCLK_EN_MASK,
+                                   MCLK_CTL_MCLK_EN_ENABLE);
+               snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL,
+                                   LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK |
+                                   LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK,
+                                   LPASS_CDC_CLK_PDM_CTL_PDM_EN |
+                                   LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB);
+               snd_soc_update_bits(codec, CDC_A_MASTER_BIAS_CTL,
+                                   MASTER_BIAS_CTL_MASTER_BIAS_EN_MASK |
+                                   MASTER_BIAS_CTL_V2L_BUFFER_EN_MASK,
+                                   MASTER_BIAS_CTL_MASTER_BIAS_EN_ENABLE |
+                                   MASTER_BIAS_CTL_V2L_BUFFER_EN_ENABLE);
+               snd_soc_update_bits(codec, CDC_D_CDC_RST_CTL,
+                                   RST_CTL_DIG_SW_RST_N_MASK,
+                                   RST_CTL_DIG_SW_RST_N_REMOVE_RESET);
+
+               snd_soc_update_bits(codec, CDC_D_CDC_TOP_CLK_CTL,
+                                   TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK,
+                                   TOP_CLK_CTL_A_MCLK_EN_ENABLE |
+                                   TOP_CLK_CTL_A_MCLK2_EN_ENABLE);
+
+               mclk_rate = clk_get_rate(msm8916_wcd->mclk);
+
+               if (mclk_rate == 12288000)
+                       snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL,
+                                           TOP_CTL_DIG_MCLK_FREQ_MASK,
+                                           TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ);
+
+               else if (mclk_rate == 9600000)
+                       snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL,
+                                           TOP_CTL_DIG_MCLK_FREQ_MASK,
+                                           TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ);
+       } else {
+               snd_soc_update_bits(codec, CDC_D_CDC_TOP_CLK_CTL,
+                                   TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK, 0);
+               snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL,
+                                   LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK |
+                                   LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0);
+
+       }
+       return 0;
+}
+
+static const struct msm8916_wcd_reg_mask_val wcd_reg_defaults[] = {
+       MSM8916_WCD_REG_VAL(CDC_A_SPKR_DAC_CTL, 0x03),
+       MSM8916_WCD_REG_VAL(CDC_A_CURRENT_LIMIT, 0x82),
+       MSM8916_WCD_REG_VAL(CDC_A_SPKR_OCP_CTL, 0xE1),
+};
+
+static const struct msm8916_wcd_reg_mask_val wcd_reg_defaults_2_0[] = {
+       MSM8916_WCD_REG_VAL(CDC_D_SEC_ACCESS, 0xA5),
+       MSM8916_WCD_REG_VAL(CDC_D_PERPH_RESET_CTL3, 0x0F),
+       MSM8916_WCD_REG_VAL(CDC_A_TX_1_2_OPAMP_BIAS, 0x4F),
+       MSM8916_WCD_REG_VAL(CDC_A_NCP_FBCTRL, 0x28),
+       MSM8916_WCD_REG_VAL(CDC_A_SPKR_DRV_CTL, 0x69),
+       MSM8916_WCD_REG_VAL(CDC_A_SPKR_DRV_DBG, 0x01),
+       MSM8916_WCD_REG_VAL(CDC_A_BOOST_EN_CTL, 0x5F),
+       MSM8916_WCD_REG_VAL(CDC_A_SLOPE_COMP_IP_ZERO, 0x88),
+       MSM8916_WCD_REG_VAL(CDC_A_SEC_ACCESS, 0xA5),
+       MSM8916_WCD_REG_VAL(CDC_A_PERPH_RESET_CTL3, 0x0F),
+       MSM8916_WCD_REG_VAL(CDC_A_CURRENT_LIMIT, 0x82),
+       MSM8916_WCD_REG_VAL(CDC_A_SPKR_DAC_CTL, 0x03),
+       MSM8916_WCD_REG_VAL(CDC_A_SPKR_OCP_CTL, 0xE1),
+};
+
+static const struct msm8916_wcd_reg_mask_val msm8916_wcd_reg_init_val[] = {
+       /**
+        * Initialize current threshold to 350MA
+        * number of wait and run cycles to 4096
+        */
+       {CDC_A_RX_COM_OCP_CTL, 0xFF, 0xD1},
+       {CDC_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+};
+
+static int msm8916_wcd_device_up(struct snd_soc_codec *codec)
+{
+       struct msm8916_wcd_chip *msm8916_wcd = snd_soc_codec_get_drvdata(codec);
+       u32 reg;
+
+       snd_soc_write(codec, CDC_D_PERPH_RESET_CTL4, 0x01);
+       snd_soc_write(codec, CDC_A_PERPH_RESET_CTL4, 0x01);
+
+       for (reg = 0; reg < ARRAY_SIZE(msm8916_wcd_reg_init_val); reg++)
+               snd_soc_update_bits(codec,
+                                   msm8916_wcd_reg_init_val[reg].reg,
+                                   msm8916_wcd_reg_init_val[reg].mask,
+                                   msm8916_wcd_reg_init_val[reg].val);
+
+       if (TOMBAK_IS_1_0(msm8916_wcd->pmic_rev)) {
+               for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults); reg++)
+                       snd_soc_write(codec, wcd_reg_defaults[reg].reg,
+                                     wcd_reg_defaults[reg].val);
+       } else {
+               for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++)
+                       snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg,
+                                     wcd_reg_defaults_2_0[reg].val);
+       }
+
+       return 0;
+}
+
+static int msm8916_wcd_codec_probe(struct snd_soc_codec *codec)
+{
+       struct msm8916_wcd_chip *chip = dev_get_drvdata(codec->dev);
+       int err;
+
+       err = regulator_enable(chip->vddio);
+       if (err < 0) {
+               dev_err(codec->dev, "failed to enable VDDIO regulator\n");
+               return err;
+       }
+
+       err = regulator_enable(chip->vdd_tx_rx);
+       if (err < 0) {
+               dev_err(codec->dev, "failed to enable VDD_TX_RX regulator\n");
+               return err;
+       }
+
+       snd_soc_codec_set_drvdata(codec, chip);
+       chip->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1);
+       chip->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE);
+       dev_info(codec->dev, "PMIC REV: %d\t CODEC Version: %d\n",
+                chip->pmic_rev, chip->codec_version);
+
+       msm8916_wcd_device_up(codec);
+       /* Set initial cap mode */
+       msm8916_wcd_configure_cap(codec, false, false);
+
+       return 0;
+}
+
+static int msm8916_wcd_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       u8 tx_fs_rate;
+
+       switch (params_rate(params)) {
+       case 8000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ;
+               break;
+       case 16000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ;
+               break;
+       case 32000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ;
+               break;
+       case 48000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ;
+               break;
+       case 96000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ;
+               break;
+       case 192000:
+               tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ;
+               break;
+       default:
+               dev_err(dai->codec->dev, "Invalid sampling rate %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_CAPTURE:
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+                                   TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate);
+               break;
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+                                   TX_I2S_CTL_TX_I2S_MODE_MASK,
+                                   TX_I2S_CTL_TX_I2S_MODE_16);
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+                                   RX_I2S_CTL_RX_I2S_MODE_MASK,
+                                   RX_I2S_CTL_RX_I2S_MODE_16);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL,
+                                   TX_I2S_CTL_TX_I2S_MODE_MASK,
+                                   TX_I2S_CTL_TX_I2S_MODE_32);
+               snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL,
+                                   RX_I2S_CTL_RX_I2S_MODE_MASK,
+                                   RX_I2S_CTL_RX_I2S_MODE_32);
+               break;
+       default:
+               dev_err(dai->dev, "%s: wrong format selected\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"RX_I2S_CLK", NULL, "CDC_CONN"},
+       {"I2S RX1", NULL, "RX_I2S_CLK"},
+       {"I2S RX2", NULL, "RX_I2S_CLK"},
+       {"I2S RX3", NULL, "RX_I2S_CLK"},
+
+       {"I2S TX1", NULL, "TX_I2S_CLK"},
+       {"I2S TX2", NULL, "TX_I2S_CLK"},
+
+       {"I2S TX1", NULL, "DEC1 MUX"},
+       {"I2S TX2", NULL, "DEC2 MUX"},
+
+       /* RDAC Connections */
+       {"HPHR DAC", NULL, "RDAC2 MUX"},
+       {"RDAC2 MUX", "RX1", "RX1 CHAIN"},
+       {"RDAC2 MUX", "RX2", "RX2 CHAIN"},
+
+       /* Headset (RX MIX1 and RX MIX2) */
+       {"HEADPHONE", NULL, "HPHL PA"},
+       {"HEADPHONE", NULL, "HPHR PA"},
+
+       {"HPHL PA", NULL, "HPHL"},
+       {"HPHR PA", NULL, "HPHR"},
+       {"HPHL", "Switch", "HPHL DAC"},
+       {"HPHR", "Switch", "HPHR DAC"},
+       {"HPHL PA", NULL, "CP"},
+       {"HPHL PA", NULL, "RX_BIAS"},
+       {"HPHR PA", NULL, "CP"},
+       {"HPHR PA", NULL, "RX_BIAS"},
+       {"HPHL DAC", NULL, "RX1 CHAIN"},
+
+       {"SPK_OUT", NULL, "SPK PA"},
+       {"SPK PA", NULL, "SPK_RX_BIAS"},
+       {"SPK PA", NULL, "SPK DAC"},
+       {"SPK DAC", "Switch", "RX3 CHAIN"},
+
+       {"RX1 CHAIN", NULL, "RX1 CLK"},
+       {"RX2 CHAIN", NULL, "RX2 CLK"},
+       {"RX3 CHAIN", NULL, "RX3 CLK"},
+       {"RX1 CHAIN", NULL, "RX1 MIX2"},
+       {"RX2 CHAIN", NULL, "RX2 MIX2"},
+       {"RX3 CHAIN", NULL, "RX3 MIX1"},
+
+       {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+       {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+       {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+       {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+       {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+       {"RX2 MIX1", NULL, "RX2 MIX1 INP3"},
+       {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+       {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+       {"RX3 MIX1", NULL, "RX3 MIX1 INP3"},
+       {"RX1 MIX2", NULL, "RX1 MIX1"},
+       {"RX2 MIX2", NULL, "RX2 MIX1"},
+
+       {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
+       {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
+       {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
+       {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
+       {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
+       {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
+       {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
+       {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
+       {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
+
+       {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
+       {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
+       {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
+       {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
+       {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
+       {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
+       {"RX2 MIX1 INP3", "RX1", "I2S RX1"},
+       {"RX2 MIX1 INP3", "RX2", "I2S RX2"},
+       {"RX2 MIX1 INP3", "RX3", "I2S RX3"},
+
+       {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
+       {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
+       {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
+       {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
+       {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
+       {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
+       {"RX3 MIX1 INP3", "RX1", "I2S RX1"},
+       {"RX3 MIX1 INP3", "RX2", "I2S RX2"},
+       {"RX3 MIX1 INP3", "RX3", "I2S RX3"},
+
+       /* Decimator Inputs */
+       {"DEC1 MUX", "DMIC1", "DMIC1"},
+       {"DEC1 MUX", "DMIC2", "DMIC2"},
+       {"DEC1 MUX", "ADC1", "ADC1"},
+       {"DEC1 MUX", "ADC2", "ADC2"},
+       {"DEC1 MUX", "ADC3", "ADC3"},
+       {"DEC1 MUX", NULL, "CDC_CONN"},
+
+       {"DEC2 MUX", "DMIC1", "DMIC1"},
+       {"DEC2 MUX", "DMIC2", "DMIC2"},
+       {"DEC2 MUX", "ADC1", "ADC1"},
+       {"DEC2 MUX", "ADC2", "ADC2"},
+       {"DEC2 MUX", "ADC3", "ADC3"},
+       {"DEC2 MUX", NULL, "CDC_CONN"},
+
+       /* ADC Connections */
+       {"ADC2", NULL, "ADC2 MUX"},
+       {"ADC3", NULL, "ADC2 MUX"},
+       {"ADC2 MUX", "INP2", "ADC2_INP2"},
+       {"ADC2 MUX", "INP3", "ADC2_INP3"},
+
+       {"ADC1", NULL, "AMIC1"},
+       {"ADC2_INP2", NULL, "AMIC2"},
+       {"ADC2_INP3", NULL, "AMIC3"},
+
+       {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
+       {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
+       {"MIC BIAS External", NULL, "INT_LDO_H"},
+       {"MIC BIAS External2", NULL, "INT_LDO_H"},
+       {"MIC BIAS Internal1", NULL, "vdd-micbias"},
+       {"MIC BIAS Internal2", NULL, "vdd-micbias"},
+       {"MIC BIAS External", NULL, "vdd-micbias"},
+       {"MIC BIAS External2", NULL, "vdd-micbias"},
+};
+
+static int msm8916_wcd_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       msm8916_wcd_codec_enable_clock_block(dai->codec, 1);
+       return 0;
+}
+
+static void msm8916_wcd_shutdown(struct snd_pcm_substream *substream,
+                                struct snd_soc_dai *dai)
+{
+       msm8916_wcd_codec_enable_clock_block(dai->codec, 0);
+}
+
+static struct snd_soc_dai_ops msm8916_wcd_dai_ops = {
+       .startup = msm8916_wcd_startup,
+       .shutdown = msm8916_wcd_shutdown,
+       .hw_params = msm8916_wcd_hw_params,
+};
+
+static struct snd_soc_dai_driver msm8916_wcd_codec_dai[] = {
+       [0] = {
+              .name = "msm8916_wcd_i2s_rx1",
+              .id = MSM8916_WCD_PLAYBACK_DAI,
+              .playback = {
+                           .stream_name = "AIF1 Playback",
+                           .rates = MSM8916_WCD_RATES,
+                           .formats = MSM8916_WCD_FORMATS,
+                           .rate_max = 192000,
+                           .rate_min = 8000,
+                           .channels_min = 1,
+                           .channels_max = 3,
+                           },
+              .ops = &msm8916_wcd_dai_ops,
+              },
+       [1] = {
+              .name = "msm8916_wcd_i2s_tx1",
+              .id = MSM8916_WCD_CAPTURE_DAI,
+              .capture = {
+                          .stream_name = "AIF1 Capture",
+                          .rates = MSM8916_WCD_RATES,
+                          .formats = MSM8916_WCD_FORMATS,
+                          .rate_max = 192000,
+                          .rate_min = 8000,
+                          .channels_min = 1,
+                          .channels_max = 4,
+                          },
+              .ops = &msm8916_wcd_dai_ops,
+              },
+};
+
+static struct snd_soc_codec_driver msm8916_wcd_codec = {
+       .probe = msm8916_wcd_codec_probe,
+       .read = msm8916_wcd_read,
+       .write = msm8916_wcd_write,
+       .reg_cache_size = MSM8916_WCD_NUM_REGISTERS,
+       .reg_cache_default = msm8916_wcd_reset_reg_defaults,
+       .reg_word_size = 1,
+       .controls = msm8916_wcd_snd_controls,
+       .num_controls = ARRAY_SIZE(msm8916_wcd_snd_controls),
+       .dapm_widgets = msm8916_wcd_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(msm8916_wcd_dapm_widgets),
+       .dapm_routes = audio_map,
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static int msm8916_wcd_probe(struct platform_device *pdev)
+{
+       struct msm8916_wcd_chip *chip;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->analog_map = dev_get_regmap(dev->parent, NULL);
+       if (!chip->analog_map)
+               return -ENXIO;
+
+       ret = msm8916_wcd_codec_parse_dt(pdev, chip);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+
+       ret = clk_prepare_enable(chip->mclk);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable mclk %d\n", ret);
+               return ret;
+       }
+
+       dev_set_drvdata(dev, chip);
+
+       return snd_soc_register_codec(dev, &msm8916_wcd_codec,
+                                     msm8916_wcd_codec_dai,
+                                     ARRAY_SIZE(msm8916_wcd_codec_dai));
+}
+
+static int msm8916_wcd_remove(struct platform_device *pdev)
+{
+       struct msm8916_wcd_chip *chip = dev_get_drvdata(&pdev->dev);
+
+       clk_disable_unprepare(chip->mclk);
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static const struct of_device_id msm8916_wcd_match_table[] = {
+       {.compatible = "qcom,msm8916-wcd-codec"},
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, msm8916_wcd_match_table);
+
+static struct platform_driver msm8916_wcd_driver = {
+       .driver = {
+                  .name = "msm8916-wcd-codec",
+                  .of_match_table = msm8916_wcd_match_table,
+                  },
+       .probe = msm8916_wcd_probe,
+       .remove = msm8916_wcd_remove,
+};
+
+module_platform_driver(msm8916_wcd_driver);
+
+MODULE_ALIAS("platform:spmi-wcd-codec");
+MODULE_DESCRIPTION("SPMI PMIC WCD codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm8916-wcd.h b/sound/soc/codecs/msm8916-wcd.h
new file mode 100644 (file)
index 0000000..f8e0d49
--- /dev/null
@@ -0,0 +1,308 @@
+/* Copyright (c) 2016, 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 MSM8916_WCD_H
+#define MSM8916_WCD_H
+
+#include "msm8916-wcd-registers.h"
+
+#define MSM8916_WCD_NUM_REGISTERS      0x6FF
+#define MSM8916_WCD_MAX_REGISTER       (MSM8916_WCD_NUM_REGISTERS-1)
+#define MSM8916_WCD_REG_VAL(reg, val)          {reg, 0, val}
+#define MSM8916_WCD_REG_VAL_MASK       0xFF
+#define MSM8916_WCD_DIGITAL_REG(reg) ((reg ^ 0x0200) & 0x0FFF)
+#define MSM8916_WCD_IS_DIGITAL_REG(reg) \
+       (((reg >= 0x200) && (reg <= 0x4FF)) ? 1 : 0)
+#define MSM8916_WCD_IS_TOMBAK_REG(reg) \
+       (((reg >= 0x000) && (reg <= 0x1FF)) ? 1 : 0)
+#define TOMBAK_VERSION_1_0     0
+#define TOMBAK_IS_1_0(ver) ((ver == TOMBAK_VERSION_1_0) ? 1 : 0)
+
+struct msm8916_wcd_reg_mask_val {
+       u16 reg;
+       u8 mask;
+       u8 val;
+};
+
+const u8 msm8916_wcd_reg_readonly[MSM8916_WCD_NUM_REGISTERS] = {
+       [CDC_D_REVISION1] = 1,
+       [CDC_D_REVISION2] = 1,
+       [CDC_D_PERPH_TYPE] = 1,
+       [CDC_D_PERPH_SUBTYPE] = 1,
+       [CDC_D_INT_RT_STS] = 1,
+       [CDC_D_INT_SET_TYPE] = 1,
+       [CDC_D_INT_POLARITY_HIGH] = 1,
+       [CDC_D_INT_POLARITY_LOW] = 1,
+       [CDC_D_INT_LATCHED_STS] = 1,
+       [CDC_D_INT_PENDING_STS] = 1,
+       [CDC_D_PIN_STATUS] = 1,
+       [CDC_A_REVISION1] = 1,
+       [CDC_A_REVISION2] = 1,
+       [CDC_A_REVISION3] = 1,
+       [CDC_A_REVISION4] = 1,
+       [CDC_A_PERPH_TYPE] = 1,
+       [CDC_A_PERPH_SUBTYPE] = 1,
+       [CDC_A_INT_RT_STS] = 1,
+       [CDC_A_INT_SET_TYPE] = 1,
+       [CDC_A_INT_POLARITY_HIGH] = 1,
+       [CDC_A_INT_POLARITY_LOW] = 1,
+       [CDC_A_INT_LATCHED_STS] = 1,
+       [CDC_A_INT_PENDING_STS] = 1,
+       [CDC_A_MBHC_BTN_RESULT] = 1,
+       [CDC_A_MBHC_ZDET_ELECT_RESULT] = 1,
+       [CDC_A_RX_HPH_STATUS] = 1,
+       [CDC_A_RX_EAR_STATUS] = 1,
+       [CDC_A_SPKR_SAR_STATUS] = 1,
+       [CDC_A_SPKR_DRV_STATUS] = 1,
+       [LPASS_CDC_RX1_B1_CTL] = 1,
+       [LPASS_CDC_RX2_B1_CTL] = 1,
+       [LPASS_CDC_RX3_B1_CTL] = 1,
+       [LPASS_CDC_RX1_B6_CTL] = 1,
+       [LPASS_CDC_RX2_B6_CTL] = 1,
+       [LPASS_CDC_RX3_B6_CTL] = 1,
+       [LPASS_CDC_TX1_VOL_CTL_CFG] = 1,
+       [LPASS_CDC_TX2_VOL_CTL_CFG] = 1,
+       [LPASS_CDC_IIR1_COEF_B1_CTL] = 1,
+       [LPASS_CDC_IIR2_COEF_B1_CTL] = 1,
+       [LPASS_CDC_CLK_MCLK_CTL] = 1,
+       [LPASS_CDC_CLK_PDM_CTL] = 1,
+};
+
+#define MSM8916_REG_POR(reg)   [reg] = reg##_POR
+
+u8 msm8916_wcd_reset_reg_defaults[MSM8916_WCD_NUM_REGISTERS] = {
+       MSM8916_REG_POR(CDC_D_REVISION1),
+       MSM8916_REG_POR(CDC_D_REVISION2),
+       MSM8916_REG_POR(CDC_D_PERPH_TYPE),
+       MSM8916_REG_POR(CDC_D_PERPH_SUBTYPE),
+       MSM8916_REG_POR(CDC_D_INT_RT_STS),
+       MSM8916_REG_POR(CDC_D_INT_SET_TYPE),
+       MSM8916_REG_POR(CDC_D_INT_POLARITY_HIGH),
+       MSM8916_REG_POR(CDC_D_INT_POLARITY_LOW),
+       MSM8916_REG_POR(CDC_D_INT_LATCHED_CLR),
+       MSM8916_REG_POR(CDC_D_INT_EN_SET),
+       MSM8916_REG_POR(CDC_D_INT_EN_CLR),
+       MSM8916_REG_POR(CDC_D_INT_LATCHED_STS),
+       MSM8916_REG_POR(CDC_D_INT_PENDING_STS),
+       MSM8916_REG_POR(CDC_D_INT_MID_SEL),
+       MSM8916_REG_POR(CDC_D_INT_PRIORITY),
+       MSM8916_REG_POR(CDC_D_GPIO_MODE),
+       MSM8916_REG_POR(CDC_D_PIN_CTL_OE),
+       MSM8916_REG_POR(CDC_D_PIN_CTL_DATA),
+       MSM8916_REG_POR(CDC_D_PIN_STATUS),
+       MSM8916_REG_POR(CDC_D_HDRIVE_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_RST_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_TOP_CLK_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_ANA_CLK_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_DIG_CLK_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_CONN_TX1_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_CONN_TX2_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_CONN_HPHR_DAC_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_CONN_RX1_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_CONN_RX2_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_CONN_RX3_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_CONN_RX_LB_CTL),
+       MSM8916_REG_POR(CDC_D_CDC_RX_CTL1),
+       MSM8916_REG_POR(CDC_D_CDC_RX_CTL2),
+       MSM8916_REG_POR(CDC_D_CDC_RX_CTL3),
+       MSM8916_REG_POR(CDC_D_DEM_BYPASS_DATA0),
+       MSM8916_REG_POR(CDC_D_DEM_BYPASS_DATA1),
+       MSM8916_REG_POR(CDC_D_DEM_BYPASS_DATA2),
+       MSM8916_REG_POR(CDC_D_DEM_BYPASS_DATA3),
+       MSM8916_REG_POR(CDC_D_SPARE_0),
+       MSM8916_REG_POR(CDC_D_SPARE_1),
+       MSM8916_REG_POR(CDC_D_SPARE_2),
+       MSM8916_REG_POR(CDC_A_REVISION1),
+       MSM8916_REG_POR(CDC_A_REVISION2),
+       MSM8916_REG_POR(CDC_A_REVISION3),
+       MSM8916_REG_POR(CDC_A_REVISION4),
+       MSM8916_REG_POR(CDC_A_PERPH_TYPE),
+       MSM8916_REG_POR(CDC_A_PERPH_SUBTYPE),
+       MSM8916_REG_POR(CDC_A_INT_RT_STS),
+       MSM8916_REG_POR(CDC_A_INT_SET_TYPE),
+       MSM8916_REG_POR(CDC_A_INT_POLARITY_HIGH),
+       MSM8916_REG_POR(CDC_A_INT_POLARITY_LOW),
+       MSM8916_REG_POR(CDC_A_INT_LATCHED_CLR),
+       MSM8916_REG_POR(CDC_A_INT_EN_SET),
+       MSM8916_REG_POR(CDC_A_INT_EN_CLR),
+       MSM8916_REG_POR(CDC_A_INT_LATCHED_STS),
+       MSM8916_REG_POR(CDC_A_INT_PENDING_STS),
+       MSM8916_REG_POR(CDC_A_INT_MID_SEL),
+       MSM8916_REG_POR(CDC_A_INT_PRIORITY),
+       MSM8916_REG_POR(CDC_A_MICB_1_EN),
+       MSM8916_REG_POR(CDC_A_MICB_1_VAL),
+       MSM8916_REG_POR(CDC_A_MICB_1_CTL),
+       MSM8916_REG_POR(CDC_A_MICB_1_INT_RBIAS),
+       MSM8916_REG_POR(CDC_A_MICB_2_EN),
+       MSM8916_REG_POR(CDC_A_MBHC_DET_CTL_1),
+       MSM8916_REG_POR(CDC_A_MBHC_DET_CTL_2),
+       MSM8916_REG_POR(CDC_A_MBHC_FSM_CTL),
+       MSM8916_REG_POR(CDC_A_MBHC_DBNC_TIMER),
+       MSM8916_REG_POR(CDC_A_MBHC_BTN0_ZDETL_CTL),
+       MSM8916_REG_POR(CDC_A_MBHC_BTN1_ZDETM_CTL),
+       MSM8916_REG_POR(CDC_A_MBHC_BTN2_ZDETH_CTL),
+       MSM8916_REG_POR(CDC_A_MBHC_BTN3_CTL),
+       MSM8916_REG_POR(CDC_A_MBHC_BTN4_CTL),
+       MSM8916_REG_POR(CDC_A_MBHC_BTN_RESULT),
+       MSM8916_REG_POR(CDC_A_MBHC_ZDET_ELECT_RESULT),
+       MSM8916_REG_POR(CDC_A_TX_1_EN),
+       MSM8916_REG_POR(CDC_A_TX_2_EN),
+       MSM8916_REG_POR(CDC_A_TX_1_2_TEST_CTL_1),
+       MSM8916_REG_POR(CDC_A_TX_1_2_TEST_CTL_2),
+       MSM8916_REG_POR(CDC_A_TX_1_2_ATEST_CTL),
+       MSM8916_REG_POR(CDC_A_TX_1_2_OPAMP_BIAS),
+       MSM8916_REG_POR(CDC_A_TX_1_2_TXFE_CLKDIV),
+       MSM8916_REG_POR(CDC_A_TX_3_EN),
+       MSM8916_REG_POR(CDC_A_NCP_EN),
+       MSM8916_REG_POR(CDC_A_NCP_CLK),
+       MSM8916_REG_POR(CDC_A_NCP_DEGLITCH),
+       MSM8916_REG_POR(CDC_A_NCP_FBCTRL),
+       MSM8916_REG_POR(CDC_A_NCP_BIAS),
+       MSM8916_REG_POR(CDC_A_NCP_VCTRL),
+       MSM8916_REG_POR(CDC_A_NCP_TEST),
+       MSM8916_REG_POR(CDC_A_RX_CLOCK_DIVIDER),
+       MSM8916_REG_POR(CDC_A_RX_COM_OCP_CTL),
+       MSM8916_REG_POR(CDC_A_RX_COM_OCP_COUNT),
+       MSM8916_REG_POR(CDC_A_RX_COM_BIAS_DAC),
+       MSM8916_REG_POR(CDC_A_RX_HPH_BIAS_PA),
+       MSM8916_REG_POR(CDC_A_RX_HPH_BIAS_LDO_OCP),
+       MSM8916_REG_POR(CDC_A_RX_HPH_BIAS_CNP),
+       MSM8916_REG_POR(CDC_A_RX_HPH_CNP_EN),
+       MSM8916_REG_POR(CDC_A_RX_HPH_CNP_WG_CTL),
+       MSM8916_REG_POR(CDC_A_RX_HPH_CNP_WG_TIME),
+       MSM8916_REG_POR(CDC_A_RX_HPH_L_TEST),
+       MSM8916_REG_POR(CDC_A_RX_HPH_L_PA_DAC_CTL),
+       MSM8916_REG_POR(CDC_A_RX_HPH_R_TEST),
+       MSM8916_REG_POR(CDC_A_RX_HPH_R_PA_DAC_CTL),
+       MSM8916_REG_POR(CDC_A_RX_EAR_CTL),
+       MSM8916_REG_POR(CDC_A_RX_ATEST),
+       MSM8916_REG_POR(CDC_A_RX_HPH_STATUS),
+       MSM8916_REG_POR(CDC_A_RX_EAR_STATUS),
+       MSM8916_REG_POR(CDC_A_SPKR_DAC_CTL),
+       MSM8916_REG_POR(CDC_A_SPKR_DRV_CLIP_DET),
+       MSM8916_REG_POR(CDC_A_SPKR_DRV_CTL),
+       MSM8916_REG_POR(CDC_A_SPKR_ANA_BIAS_SET),
+       MSM8916_REG_POR(CDC_A_SPKR_OCP_CTL),
+       MSM8916_REG_POR(CDC_A_SPKR_PWRSTG_CTL),
+       MSM8916_REG_POR(CDC_A_SPKR_DRV_MISC),
+       MSM8916_REG_POR(CDC_A_SPKR_DRV_DBG),
+       MSM8916_REG_POR(CDC_A_CURRENT_LIMIT),
+       MSM8916_REG_POR(CDC_A_OUTPUT_VOLTAGE),
+       MSM8916_REG_POR(CDC_A_BYPASS_MODE),
+       MSM8916_REG_POR(CDC_A_BOOST_EN_CTL),
+       MSM8916_REG_POR(CDC_A_SLOPE_COMP_IP_ZERO),
+       MSM8916_REG_POR(CDC_A_RDSON_MAX_DUTY_CYCLE),
+       MSM8916_REG_POR(CDC_A_BOOST_TEST1_1),
+       MSM8916_REG_POR(CDC_A_BOOST_TEST_2),
+       MSM8916_REG_POR(CDC_A_SPKR_SAR_STATUS),
+       MSM8916_REG_POR(CDC_A_SPKR_DRV_STATUS),
+       MSM8916_REG_POR(CDC_A_PBUS_ADD_CSR),
+       MSM8916_REG_POR(CDC_A_PBUS_ADD_SEL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_RX_RESET_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_TX_RESET_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_DMIC_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_RX_I2S_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_TX_I2S_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_OTHR_RESET_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_TX_CLK_EN_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_OTHR_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_RX_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_MCLK_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_PDM_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CLK_SD_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_B4_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_B4_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_B4_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_B5_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_B5_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_B5_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_B6_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_B6_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_B6_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_VOL_CTL_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_VOL_CTL_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_VOL_CTL_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX1_VOL_CTL_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX2_VOL_CTL_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_RX3_VOL_CTL_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_TOP_GAIN_UPDATE),
+       MSM8916_REG_POR(LPASS_CDC_TOP_CTL),
+       MSM8916_REG_POR(LPASS_CDC_DEBUG_DESER1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_DEBUG_DESER2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_DEBUG_B1_CTL_CFG),
+       MSM8916_REG_POR(LPASS_CDC_DEBUG_B2_CTL_CFG),
+       MSM8916_REG_POR(LPASS_CDC_DEBUG_B3_CTL_CFG),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B4_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B4_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B5_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B5_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B6_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B6_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B7_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B7_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_B8_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_B8_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_GAIN_TIMER_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_GAIN_TIMER_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_COEF_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_COEF_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR1_COEF_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_IIR2_COEF_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX1_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX1_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX1_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX2_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX2_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX2_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX3_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_RX3_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_TX_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ1_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ1_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ1_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ1_B4_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ2_B1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ2_B2_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ2_B3_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_EQ2_B4_CTL),
+       MSM8916_REG_POR(LPASS_CDC_CONN_TX_I2S_SD1_CTL),
+       MSM8916_REG_POR(LPASS_CDC_TX1_VOL_CTL_TIMER),
+       MSM8916_REG_POR(LPASS_CDC_TX2_VOL_CTL_TIMER),
+       MSM8916_REG_POR(LPASS_CDC_TX1_VOL_CTL_GAIN),
+       MSM8916_REG_POR(LPASS_CDC_TX2_VOL_CTL_GAIN),
+       MSM8916_REG_POR(LPASS_CDC_TX1_VOL_CTL_CFG),
+       MSM8916_REG_POR(LPASS_CDC_TX2_VOL_CTL_CFG),
+       MSM8916_REG_POR(LPASS_CDC_TX1_MUX_CTL),
+       MSM8916_REG_POR(LPASS_CDC_TX2_MUX_CTL),
+       MSM8916_REG_POR(LPASS_CDC_TX1_CLK_FS_CTL),
+       MSM8916_REG_POR(LPASS_CDC_TX2_CLK_FS_CTL),
+       MSM8916_REG_POR(LPASS_CDC_TX1_DMIC_CTL),
+       MSM8916_REG_POR(LPASS_CDC_TX2_DMIC_CTL),
+};
+
+#endif /* MSM8916_WCD_H */
diff --git a/sound/soc/codecs/msm8x16-wcd-tables.c b/sound/soc/codecs/msm8x16-wcd-tables.c
deleted file mode 100644 (file)
index c6b1fd6..0000000
+++ /dev/null
@@ -1,742 +0,0 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include "msm8x16_wcd_registers.h"
-#include "msm8x16-wcd.h"
-
-const u8 msm8x16_wcd_reg_readable[MSM8X16_WCD_CACHE_SIZE] = {
-               [MSM8X16_WCD_A_DIGITAL_REVISION1] = 1,
-               [MSM8X16_WCD_A_DIGITAL_REVISION2] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PERPH_TYPE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_RT_STS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_SET_TYPE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_POLARITY_HIGH] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_POLARITY_LOW] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_EN_SET] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_EN_CLR] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_LATCHED_STS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_PENDING_STS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_MID_SEL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_PRIORITY] = 1,
-               [MSM8X16_WCD_A_DIGITAL_GPIO_MODE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PIN_CTL_OE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PIN_CTL_DATA] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PIN_STATUS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_HDRIVE_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RST_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_TOP_CLK_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX1_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX2_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_HPHR_DAC_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX1_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX2_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX3_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX_LB_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL1] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL2] = 1,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL3] = 1,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA0] = 1,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA1] = 1,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA2] = 1,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA3] = 1,
-               [MSM8X16_WCD_A_DIGITAL_DIG_DEBUG_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_SPARE_0] = 1,
-               [MSM8X16_WCD_A_DIGITAL_SPARE_1] = 1,
-               [MSM8X16_WCD_A_DIGITAL_SPARE_2] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION1] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION2] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION3] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION4] = 1,
-               [MSM8X16_WCD_A_ANALOG_PERPH_TYPE] = 1,
-               [MSM8X16_WCD_A_ANALOG_PERPH_SUBTYPE] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_RT_STS] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_SET_TYPE] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_POLARITY_HIGH] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_POLARITY_LOW] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_EN_SET] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_EN_CLR] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_LATCHED_STS] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_PENDING_STS] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_MID_SEL] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_PRIORITY] = 1,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_EN] = 1,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_VAL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS] = 1,
-               [MSM8X16_WCD_A_ANALOG_MICB_2_EN] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_DBNC_TIMER] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN0_ZDETL_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN1_ZDETM_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN2_ZDETH_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN3_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN4_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN_RESULT] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_1_EN] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_2_EN] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_1] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_2] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_OPAMP_BIAS] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_TXFE_CLKDIV] = 1,
-               [MSM8X16_WCD_A_ANALOG_TX_3_EN] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_EN] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_CLK] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_DEGLITCH] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_FBCTRL] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_BIAS] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_VCTRL] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_TEST] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_CLOCK_DIVIDER] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_COM_OCP_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_COM_OCP_COUNT] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_PA] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_LDO_OCP] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_CNP] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_L_TEST] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_R_TEST] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_EAR_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_ATEST] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_EAR_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_CLIP_DET] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_ANA_BIAS_SET] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_OCP_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_MISC] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_DBG] = 1,
-               [MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT] = 1,
-               [MSM8X16_WCD_A_ANALOG_OUTPUT_VOLTAGE] = 1,
-               [MSM8X16_WCD_A_ANALOG_BYPASS_MODE] = 1,
-               [MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_SLOPE_COMP_IP_ZERO] = 1,
-               [MSM8X16_WCD_A_ANALOG_RDSON_MAX_DUTY_CYCLE] = 1,
-               [MSM8X16_WCD_A_ANALOG_BOOST_TEST1_1] = 1,
-               [MSM8X16_WCD_A_ANALOG_BOOST_TEST_2] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_SAR_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_PBUS_ADD_CSR] = 1,
-               [MSM8X16_WCD_A_ANALOG_PBUS_ADD_SEL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_DMIC_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_OTHR_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_MCLK_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_PDM_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_SD_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B4_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B4_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B4_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B5_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B5_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B5_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE] = 1,
-               [MSM8X16_WCD_A_CDC_TOP_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_DEBUG_B1_CTL_CFG] = 1,
-               [MSM8X16_WCD_A_CDC_DEBUG_B2_CTL_CFG] = 1,
-               [MSM8X16_WCD_A_CDC_DEBUG_B3_CTL_CFG] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B4_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B4_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B5_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B5_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B7_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B7_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B8_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B8_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_TIMER_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_COEF_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_COEF_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_COEF_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_COEF_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX1_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX1_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX2_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX2_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_RX3_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_TX_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B4_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B2_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B3_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B4_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CONN_TX_I2S_SD1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TX1_VOL_CTL_TIMER] = 1,
-               [MSM8X16_WCD_A_CDC_TX2_VOL_CTL_TIMER] = 1,
-               [MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN] = 1,
-               [MSM8X16_WCD_A_CDC_TX2_VOL_CTL_GAIN] = 1,
-               [MSM8X16_WCD_A_CDC_TX1_VOL_CTL_CFG] = 1,
-               [MSM8X16_WCD_A_CDC_TX2_VOL_CTL_CFG] = 1,
-               [MSM8X16_WCD_A_CDC_TX1_MUX_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TX2_MUX_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TX1_CLK_FS_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TX2_CLK_FS_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TX1_DMIC_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TX2_DMIC_CTL] = 1,
-               [MSM8X16_WCD_A_ANALOG_MASTER_BIAS_CTL] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_LATCHED_CLR] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_LATCHED_CLR] = 1,
-               [MSM8X16_WCD_A_ANALOG_NCP_CLIM_ADDR] = 1,
-               [MSM8X16_WCD_A_DIGITAL_SEC_ACCESS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL3] = 1,
-               [MSM8X16_WCD_A_ANALOG_SEC_ACCESS] = 1,
-};
-
-const u8 msm8x16_wcd_reg_readonly[MSM8X16_WCD_CACHE_SIZE] = {
-               [MSM8X16_WCD_A_DIGITAL_REVISION1] = 1,
-               [MSM8X16_WCD_A_DIGITAL_REVISION2] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PERPH_TYPE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_RT_STS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_SET_TYPE] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_POLARITY_HIGH] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_POLARITY_LOW] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_LATCHED_STS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_INT_PENDING_STS] = 1,
-               [MSM8X16_WCD_A_DIGITAL_PIN_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION1] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION2] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION3] = 1,
-               [MSM8X16_WCD_A_ANALOG_REVISION4] = 1,
-               [MSM8X16_WCD_A_ANALOG_PERPH_TYPE] = 1,
-               [MSM8X16_WCD_A_ANALOG_PERPH_SUBTYPE] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_RT_STS] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_SET_TYPE] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_POLARITY_HIGH] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_POLARITY_LOW] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_LATCHED_STS] = 1,
-               [MSM8X16_WCD_A_ANALOG_INT_PENDING_STS] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN_RESULT] = 1,
-               [MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_RX_EAR_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_SAR_STATUS] = 1,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_STATUS] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX1_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX2_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_RX3_B6_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_TX1_VOL_CTL_CFG] = 1,
-               [MSM8X16_WCD_A_CDC_TX2_VOL_CTL_CFG] = 1,
-               [MSM8X16_WCD_A_CDC_IIR1_COEF_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_IIR2_COEF_B1_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_MCLK_CTL] = 1,
-               [MSM8X16_WCD_A_CDC_CLK_PDM_CTL] = 1,
-};
-
-u8 msm8x16_wcd_reset_reg_defaults[MSM8X16_WCD_CACHE_SIZE] = {
-               [MSM8X16_WCD_A_DIGITAL_REVISION1] =
-                       MSM8X16_WCD_A_DIGITAL_REVISION1__POR,
-               [MSM8X16_WCD_A_DIGITAL_REVISION2] =
-                       MSM8X16_WCD_A_DIGITAL_REVISION2__POR,
-               [MSM8X16_WCD_A_DIGITAL_PERPH_TYPE] =
-                       MSM8X16_WCD_A_DIGITAL_PERPH_TYPE__POR,
-               [MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE] =
-                       MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_RT_STS] =
-                       MSM8X16_WCD_A_DIGITAL_INT_RT_STS__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_SET_TYPE] =
-                       MSM8X16_WCD_A_DIGITAL_INT_SET_TYPE__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_POLARITY_HIGH] =
-                       MSM8X16_WCD_A_DIGITAL_INT_POLARITY_HIGH__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_POLARITY_LOW] =
-                       MSM8X16_WCD_A_DIGITAL_INT_POLARITY_LOW__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_LATCHED_CLR] =
-                       MSM8X16_WCD_A_DIGITAL_INT_LATCHED_CLR__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_EN_SET] =
-                       MSM8X16_WCD_A_DIGITAL_INT_EN_SET__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_EN_CLR] =
-                       MSM8X16_WCD_A_DIGITAL_INT_EN_CLR__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_LATCHED_STS] =
-                       MSM8X16_WCD_A_DIGITAL_INT_LATCHED_STS__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_PENDING_STS] =
-                       MSM8X16_WCD_A_DIGITAL_INT_PENDING_STS__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_MID_SEL] =
-                       MSM8X16_WCD_A_DIGITAL_INT_MID_SEL__POR,
-               [MSM8X16_WCD_A_DIGITAL_INT_PRIORITY] =
-                       MSM8X16_WCD_A_DIGITAL_INT_PRIORITY__POR,
-               [MSM8X16_WCD_A_DIGITAL_GPIO_MODE] =
-                       MSM8X16_WCD_A_DIGITAL_GPIO_MODE__POR,
-               [MSM8X16_WCD_A_DIGITAL_PIN_CTL_OE] =
-                       MSM8X16_WCD_A_DIGITAL_PIN_CTL_OE__POR,
-               [MSM8X16_WCD_A_DIGITAL_PIN_CTL_DATA] =
-                       MSM8X16_WCD_A_DIGITAL_PIN_CTL_DATA__POR,
-               [MSM8X16_WCD_A_DIGITAL_PIN_STATUS] =
-                       MSM8X16_WCD_A_DIGITAL_PIN_STATUS__POR,
-               [MSM8X16_WCD_A_DIGITAL_HDRIVE_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_HDRIVE_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RST_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_RST_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_TOP_CLK_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_TOP_CLK_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX1_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX1_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX2_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX2_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_HPHR_DAC_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_CONN_HPHR_DAC_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX1_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX1_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX2_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX2_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX3_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX3_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX_LB_CTL] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX_LB_CTL__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL1] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL1__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL2] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL2__POR,
-               [MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL3] =
-                       MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL3__POR,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA0] =
-                       MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA0__POR,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA1] =
-                       MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA1__POR,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA2] =
-                       MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA2__POR,
-               [MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA3] =
-                       MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA3__POR,
-               [MSM8X16_WCD_A_DIGITAL_SPARE_0] =
-                       MSM8X16_WCD_A_DIGITAL_SPARE_0__POR,
-               [MSM8X16_WCD_A_DIGITAL_SPARE_1] =
-                       MSM8X16_WCD_A_DIGITAL_SPARE_1__POR,
-               [MSM8X16_WCD_A_DIGITAL_SPARE_2] =
-                       MSM8X16_WCD_A_DIGITAL_SPARE_2__POR,
-               [MSM8X16_WCD_A_ANALOG_REVISION1] =
-                       MSM8X16_WCD_A_ANALOG_REVISION1__POR,
-               [MSM8X16_WCD_A_ANALOG_REVISION2] =
-                       MSM8X16_WCD_A_ANALOG_REVISION2__POR,
-               [MSM8X16_WCD_A_ANALOG_REVISION3] =
-                       MSM8X16_WCD_A_ANALOG_REVISION3__POR,
-               [MSM8X16_WCD_A_ANALOG_REVISION4] =
-                       MSM8X16_WCD_A_ANALOG_REVISION4__POR,
-               [MSM8X16_WCD_A_ANALOG_PERPH_TYPE] =
-                       MSM8X16_WCD_A_ANALOG_PERPH_TYPE__POR,
-               [MSM8X16_WCD_A_ANALOG_PERPH_SUBTYPE] =
-                       MSM8X16_WCD_A_ANALOG_PERPH_SUBTYPE__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_RT_STS] =
-                       MSM8X16_WCD_A_ANALOG_INT_RT_STS__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_SET_TYPE] =
-                       MSM8X16_WCD_A_ANALOG_INT_SET_TYPE__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_POLARITY_HIGH] =
-                       MSM8X16_WCD_A_ANALOG_INT_POLARITY_HIGH__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_POLARITY_LOW] =
-                       MSM8X16_WCD_A_ANALOG_INT_POLARITY_LOW__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_LATCHED_CLR] =
-                       MSM8X16_WCD_A_ANALOG_INT_LATCHED_CLR__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_EN_SET] =
-                       MSM8X16_WCD_A_ANALOG_INT_EN_SET__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_EN_CLR] =
-                       MSM8X16_WCD_A_ANALOG_INT_EN_CLR__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_LATCHED_STS] =
-                       MSM8X16_WCD_A_ANALOG_INT_LATCHED_STS__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_PENDING_STS] =
-                       MSM8X16_WCD_A_ANALOG_INT_PENDING_STS__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_MID_SEL] =
-                       MSM8X16_WCD_A_ANALOG_INT_MID_SEL__POR,
-               [MSM8X16_WCD_A_ANALOG_INT_PRIORITY] =
-                       MSM8X16_WCD_A_ANALOG_INT_PRIORITY__POR,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_EN] =
-                       MSM8X16_WCD_A_ANALOG_MICB_1_EN__POR,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_VAL] =
-                       MSM8X16_WCD_A_ANALOG_MICB_1_VAL__POR,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_CTL] =
-                       MSM8X16_WCD_A_ANALOG_MICB_1_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS] =
-                       MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS__POR,
-               [MSM8X16_WCD_A_ANALOG_MICB_2_EN] =
-                       MSM8X16_WCD_A_ANALOG_MICB_2_EN__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_DBNC_TIMER] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_DBNC_TIMER__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN0_ZDETL_CTL] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_BTN0_ZDETL_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN1_ZDETM_CTL] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_BTN1_ZDETM_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN2_ZDETH_CTL] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_BTN2_ZDETH_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN3_CTL] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_BTN3_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN4_CTL] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_BTN4_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_BTN_RESULT] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_BTN_RESULT__POR,
-               [MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT] =
-                       MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_1_EN] =
-                       MSM8X16_WCD_A_ANALOG_TX_1_EN__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_2_EN] =
-                       MSM8X16_WCD_A_ANALOG_TX_2_EN__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_1] =
-                       MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_1__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_2] =
-                       MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_2__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL] =
-                       MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_OPAMP_BIAS] =
-                       MSM8X16_WCD_A_ANALOG_TX_1_2_OPAMP_BIAS__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_1_2_TXFE_CLKDIV] =
-                       MSM8X16_WCD_A_ANALOG_TX_1_2_TXFE_CLKDIV__POR,
-               [MSM8X16_WCD_A_ANALOG_TX_3_EN] =
-                       MSM8X16_WCD_A_ANALOG_TX_3_EN__POR,
-               [MSM8X16_WCD_A_ANALOG_NCP_EN] =
-                       MSM8X16_WCD_A_ANALOG_NCP_EN__POR,
-               [MSM8X16_WCD_A_ANALOG_NCP_CLK] =
-                       MSM8X16_WCD_A_ANALOG_NCP_CLK__POR,
-               [MSM8X16_WCD_A_ANALOG_NCP_DEGLITCH] =
-                       MSM8X16_WCD_A_ANALOG_NCP_DEGLITCH__POR,
-               [MSM8X16_WCD_A_ANALOG_NCP_FBCTRL] =
-                       MSM8X16_WCD_A_ANALOG_NCP_FBCTRL__POR,
-               [MSM8X16_WCD_A_ANALOG_NCP_BIAS] =
-                       MSM8X16_WCD_A_ANALOG_NCP_BIAS__POR,
-               [MSM8X16_WCD_A_ANALOG_NCP_VCTRL] =
-                       MSM8X16_WCD_A_ANALOG_NCP_VCTRL__POR,
-               [MSM8X16_WCD_A_ANALOG_NCP_TEST] =
-                       MSM8X16_WCD_A_ANALOG_NCP_TEST__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_CLOCK_DIVIDER] =
-                       MSM8X16_WCD_A_ANALOG_RX_CLOCK_DIVIDER__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_COM_OCP_CTL] =
-                       MSM8X16_WCD_A_ANALOG_RX_COM_OCP_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_COM_OCP_COUNT] =
-                       MSM8X16_WCD_A_ANALOG_RX_COM_OCP_COUNT__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC] =
-                       MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_PA] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_PA__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_LDO_OCP] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_LDO_OCP__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_CNP] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_CNP__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_CTL] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_L_TEST] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_L_TEST__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_R_TEST] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_R_TEST__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_EAR_CTL] =
-                       MSM8X16_WCD_A_ANALOG_RX_EAR_CTL___POR,
-               [MSM8X16_WCD_A_ANALOG_RX_ATEST] =
-                       MSM8X16_WCD_A_ANALOG_RX_ATEST__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_HPH_STATUS] =
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_STATUS__POR,
-               [MSM8X16_WCD_A_ANALOG_RX_EAR_STATUS] =
-                       MSM8X16_WCD_A_ANALOG_RX_EAR_STATUS__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_CLIP_DET] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_DRV_CLIP_DET__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_ANA_BIAS_SET] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_ANA_BIAS_SET__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_OCP_CTL] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_OCP_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_MISC] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_DRV_MISC__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_DBG] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_DRV_DBG__POR,
-               [MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT] =
-                       MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT__POR,
-               [MSM8X16_WCD_A_ANALOG_OUTPUT_VOLTAGE] =
-                       MSM8X16_WCD_A_ANALOG_OUTPUT_VOLTAGE__POR,
-               [MSM8X16_WCD_A_ANALOG_BYPASS_MODE] =
-                       MSM8X16_WCD_A_ANALOG_BYPASS_MODE__POR,
-               [MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL] =
-                       MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL__POR,
-               [MSM8X16_WCD_A_ANALOG_SLOPE_COMP_IP_ZERO] =
-                       MSM8X16_WCD_A_ANALOG_SLOPE_COMP_IP_ZERO__POR,
-               [MSM8X16_WCD_A_ANALOG_RDSON_MAX_DUTY_CYCLE] =
-                       MSM8X16_WCD_A_ANALOG_RDSON_MAX_DUTY_CYCLE__POR,
-               [MSM8X16_WCD_A_ANALOG_BOOST_TEST1_1] =
-                       MSM8X16_WCD_A_ANALOG_BOOST_TEST1_1__POR,
-               [MSM8X16_WCD_A_ANALOG_BOOST_TEST_2] =
-                       MSM8X16_WCD_A_ANALOG_BOOST_TEST_2__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_SAR_STATUS] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_SAR_STATUS__POR,
-               [MSM8X16_WCD_A_ANALOG_SPKR_DRV_STATUS] =
-                       MSM8X16_WCD_A_ANALOG_SPKR_DRV_STATUS__POR,
-               [MSM8X16_WCD_A_ANALOG_PBUS_ADD_CSR] =
-                       MSM8X16_WCD_A_ANALOG_PBUS_ADD_CSR__POR,
-               [MSM8X16_WCD_A_ANALOG_PBUS_ADD_SEL] =
-                       MSM8X16_WCD_A_ANALOG_PBUS_ADD_SEL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_TX_RESET_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_TX_RESET_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_DMIC_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_DMIC_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_OTHR_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_OTHR_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_MCLK_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_MCLK_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_PDM_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_PDM_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CLK_SD_CTL] =
-                       MSM8X16_WCD_A_CDC_CLK_SD_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_B4_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_B4_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_B4_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_B4_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_B4_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_B4_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_B5_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_B5_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_B5_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_B5_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_B5_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_B5_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_B6_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_B6_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_B6_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_B6_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_B6_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_B6_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE] =
-                       MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE__POR,
-               [MSM8X16_WCD_A_CDC_TOP_CTL] =
-                       MSM8X16_WCD_A_CDC_TOP_CTL__POR,
-               [MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL] =
-                       MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL] =
-                       MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_DEBUG_B1_CTL_CFG] =
-                       MSM8X16_WCD_A_CDC_DEBUG_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_DEBUG_B2_CTL_CFG] =
-                       MSM8X16_WCD_A_CDC_DEBUG_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_DEBUG_B3_CTL_CFG] =
-                       MSM8X16_WCD_A_CDC_DEBUG_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B4_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B4_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B4_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B4_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B5_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B5_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B5_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B5_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B6_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B6_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B6_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B6_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B7_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B7_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B7_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B7_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_B8_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_B8_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_B8_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_B8_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_GAIN_TIMER_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_GAIN_TIMER_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_GAIN_TIMER_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_COEF_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_COEF_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_COEF_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_COEF_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR1_COEF_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR1_COEF_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_IIR2_COEF_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_IIR2_COEF_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX1_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX1_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX1_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX1_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX2_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX2_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX2_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX2_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_RX3_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_RX3_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_TX_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_TX_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ1_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ1_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ1_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ1_B4_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ1_B4_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B1_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ2_B1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B2_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ2_B2_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B3_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ2_B3_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_EQ2_B4_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_EQ2_B4_CTL__POR,
-               [MSM8X16_WCD_A_CDC_CONN_TX_I2S_SD1_CTL] =
-                       MSM8X16_WCD_A_CDC_CONN_TX_I2S_SD1_CTL__POR,
-               [MSM8X16_WCD_A_CDC_TX1_VOL_CTL_TIMER] =
-                       MSM8X16_WCD_A_CDC_TX1_VOL_CTL_TIMER__POR,
-               [MSM8X16_WCD_A_CDC_TX2_VOL_CTL_TIMER] =
-                       MSM8X16_WCD_A_CDC_TX2_VOL_CTL_TIMER__POR,
-               [MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN] =
-                       MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN__POR,
-               [MSM8X16_WCD_A_CDC_TX2_VOL_CTL_GAIN] =
-                       MSM8X16_WCD_A_CDC_TX2_VOL_CTL_GAIN__POR,
-               [MSM8X16_WCD_A_CDC_TX1_VOL_CTL_CFG] =
-                       MSM8X16_WCD_A_CDC_TX1_VOL_CTL_CFG__POR,
-               [MSM8X16_WCD_A_CDC_TX2_VOL_CTL_CFG] =
-                       MSM8X16_WCD_A_CDC_TX2_VOL_CTL_CFG__POR,
-               [MSM8X16_WCD_A_CDC_TX1_MUX_CTL] =
-                       MSM8X16_WCD_A_CDC_TX1_MUX_CTL__POR,
-               [MSM8X16_WCD_A_CDC_TX2_MUX_CTL] =
-                       MSM8X16_WCD_A_CDC_TX2_MUX_CTL__POR,
-               [MSM8X16_WCD_A_CDC_TX1_CLK_FS_CTL] =
-                       MSM8X16_WCD_A_CDC_TX1_CLK_FS_CTL__POR,
-               [MSM8X16_WCD_A_CDC_TX2_CLK_FS_CTL] =
-                       MSM8X16_WCD_A_CDC_TX2_CLK_FS_CTL__POR,
-               [MSM8X16_WCD_A_CDC_TX1_DMIC_CTL] =
-                       MSM8X16_WCD_A_CDC_TX1_DMIC_CTL__POR,
-               [MSM8X16_WCD_A_CDC_TX2_DMIC_CTL] =
-                       MSM8X16_WCD_A_CDC_TX2_DMIC_CTL__POR,
-};
diff --git a/sound/soc/codecs/msm8x16-wcd.c b/sound/soc/codecs/msm8x16-wcd.c
deleted file mode 100644 (file)
index 77a13cf..0000000
+++ /dev/null
@@ -1,2271 +0,0 @@
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/regulator/consumer.h>
-#include <linux/types.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/tlv.h>
-
-#include "msm8x16-wcd.h"
-#include "msm8x16_wcd_registers.h"
-
-#define MSM8X16_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
-                       SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
-#define MSM8X16_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-               SNDRV_PCM_FMTBIT_S24_LE)
-
-#define TOMBAK_VERSION_1_0     0
-#define TOMBAK_IS_1_0(ver) \
-       ((ver == TOMBAK_VERSION_1_0) ? 1 : 0)
-
-#define HPHL_PA_DISABLE (0x01 << 1)
-#define HPHR_PA_DISABLE (0x01 << 2)
-#define EAR_PA_DISABLE (0x01 << 3)
-#define SPKR_PA_DISABLE (0x01 << 4)
-
-#define MICBIAS_DEFAULT_VAL 1800000
-#define MICBIAS_MIN_VAL 1600000
-#define MICBIAS_STEP_SIZE 50000
-
-#define DEFAULT_BOOST_VOLTAGE 5000
-#define MIN_BOOST_VOLTAGE 4000
-#define MAX_BOOST_VOLTAGE 5550
-#define BOOST_VOLTAGE_STEP 50
-
-#define VOLTAGE_CONVERTER(value, min_value, step_size)\
-       ((value - min_value)/step_size);
-
-enum {
-       AIF1_PB = 0,
-       AIF1_CAP,
-       NUM_CODEC_DAIS,
-};
-
-static unsigned long rx_digital_gain_reg[] = {
-       MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
-       MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
-       MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
-};
-
-static unsigned long tx_digital_gain_reg[] = {
-       MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN,
-       MSM8X16_WCD_A_CDC_TX2_VOL_CTL_GAIN,
-};
-
-struct wcd_chip {
-       struct regmap   *analog_map;
-       struct regmap   *digital_map;
-       unsigned int    analog_base;
-       u16 pmic_rev;
-       u16 codec_version;
-       bool spk_boost_set;
-       u32 mute_mask;
-       u32 rx_bias_count;
-       bool ear_pa_boost_set;
-       bool lb_mode;
-       struct clk *mclk;
-
-       struct regulator *vddio;
-       struct regulator *vdd_pa;
-       struct regulator *vdd_px;
-       struct regulator *vdd_cp;
-       struct regulator *vdd_mic_bias;
-};
-
-static int msm8x16_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
-{
-       return msm8x16_wcd_reg_readonly[reg];
-}
-
-static int msm8x16_wcd_readable(struct snd_soc_codec *ssc, unsigned int reg)
-{
-       return msm8x16_wcd_reg_readable[reg];
-}
-
-static int __msm8x16_wcd_reg_write(struct snd_soc_codec *codec,
-                       unsigned short reg, u8 val)
-{
-       int ret = -EINVAL;
-       struct wcd_chip *chip = dev_get_drvdata(codec->dev);
-
-       if (MSM8X16_WCD_IS_TOMBAK_REG(reg)) {
-               ret = regmap_write(chip->analog_map,
-                                  chip->analog_base + reg, val);
-       } else if (MSM8X16_WCD_IS_DIGITAL_REG(reg)) {
-               u32 temp = val & 0x000000FF;
-               u16 offset = (reg ^ 0x0200) & 0x0FFF;
-
-               ret = regmap_write(chip->digital_map, offset, temp);
-       }
-
-       return ret;
-}
-
-static int msm8x16_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
-                            unsigned int value)
-{
-       if (reg == SND_SOC_NOPM)
-               return 0;
-
-       BUG_ON(reg > MSM8X16_WCD_MAX_REGISTER);
-       if (!msm8x16_wcd_volatile(codec, reg))
-               msm8x16_wcd_reset_reg_defaults[reg] = value;
-
-       return __msm8x16_wcd_reg_write(codec, reg, (u8)value);
-}
-
-static int __msm8x16_wcd_reg_read(struct snd_soc_codec *codec,
-                               unsigned short reg)
-{
-       int ret = -EINVAL;
-       u32 temp = 0;
-       struct wcd_chip *chip = dev_get_drvdata(codec->dev);
-
-       if (MSM8X16_WCD_IS_TOMBAK_REG(reg)) {
-               ret = regmap_read(chip->analog_map,
-                                 chip->analog_base + reg, &temp);
-       } else if (MSM8X16_WCD_IS_DIGITAL_REG(reg)) {
-               u32 val;
-               u16 offset = (reg ^ 0x0200) & 0x0FFF;
-
-               ret = regmap_read(chip->digital_map, offset, &val);
-               temp = (u8)val;
-       }
-
-       if (ret < 0) {
-               dev_err(codec->dev,
-                               "%s: codec read failed for reg 0x%x\n",
-                               __func__, reg);
-               return ret;
-       }
-
-       dev_dbg(codec->dev, "Read 0x%02x from 0x%x\n", temp, reg);
-
-       return temp;
-}
-
-static unsigned int msm8x16_wcd_read(struct snd_soc_codec *codec,
-                               unsigned int reg)
-{
-       unsigned int val;
-
-       if (reg == SND_SOC_NOPM)
-               return 0;
-
-       BUG_ON(reg > MSM8X16_WCD_MAX_REGISTER);
-
-       if (!msm8x16_wcd_volatile(codec, reg) &&
-           msm8x16_wcd_readable(codec, reg) &&
-               reg < codec->driver->reg_cache_size) {
-               return msm8x16_wcd_reset_reg_defaults[reg];
-       }
-
-       val = __msm8x16_wcd_reg_read(codec, reg);
-
-       return val;
-}
-
-static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults[] = {
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 0x03),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT, 0x82),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_SPKR_OCP_CTL, 0xE1),
-};
-
-static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults_2_0[] = {
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL3, 0x0F),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_TX_1_2_OPAMP_BIAS, 0x4B),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_NCP_FBCTRL, 0x28),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL, 0x69),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_SPKR_DRV_DBG, 0x01),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL, 0x5F),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_SLOPE_COMP_IP_ZERO, 0x88),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL3, 0x0F),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT, 0x82),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 0x03),
-       MSM8X16_WCD_REG_VAL(MSM8X16_WCD_A_ANALOG_SPKR_OCP_CTL, 0xE1),
-};
-
-static int msm8x16_wcd_bringup(struct snd_soc_codec *codec)
-{
-       snd_soc_write(codec, MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL4, 0x01);
-       snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL4, 0x01);
-       return 0;
-}
-
-static const struct msm8x16_wcd_reg_mask_val
-       msm8x16_wcd_codec_reg_init_val[] = {
-
-       /* Initialize current threshold to 350MA
-        * number of wait and run cycles to 4096
-        */
-       {MSM8X16_WCD_A_ANALOG_RX_COM_OCP_CTL, 0xFF, 0xD1},
-       {MSM8X16_WCD_A_ANALOG_RX_COM_OCP_COUNT, 0xFF, 0xFF},
-};
-
-static void msm8x16_wcd_codec_init_reg(struct snd_soc_codec *codec)
-{
-       u32 i;
-
-       for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_codec_reg_init_val); i++)
-               snd_soc_update_bits(codec,
-                                   msm8x16_wcd_codec_reg_init_val[i].reg,
-                                   msm8x16_wcd_codec_reg_init_val[i].mask,
-                                   msm8x16_wcd_codec_reg_init_val[i].val);
-}
-
-static void msm8x16_wcd_update_reg_defaults(struct snd_soc_codec *codec)
-{
-       u32 i;
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       if (TOMBAK_IS_1_0(msm8x16_wcd->pmic_rev)) {
-               for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults); i++)
-                       snd_soc_write(codec, msm8x16_wcd_reg_defaults[i].reg,
-                                       msm8x16_wcd_reg_defaults[i].val);
-       } else {
-               for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults_2_0); i++)
-                       snd_soc_write(codec,
-                               msm8x16_wcd_reg_defaults_2_0[i].reg,
-                               msm8x16_wcd_reg_defaults_2_0[i].val);
-       }
-}
-
-static int msm8x16_wcd_device_up(struct snd_soc_codec *codec)
-{
-       u32 reg;
-
-       dev_dbg(codec->dev, "%s: device up!\n", __func__);
-       msm8x16_wcd_bringup(codec);
-
-       for (reg = 0; reg < ARRAY_SIZE(msm8x16_wcd_reset_reg_defaults); reg++)
-               if (msm8x16_wcd_reg_readable[reg])
-                       msm8x16_wcd_write(codec,
-                               reg, msm8x16_wcd_reset_reg_defaults[reg]);
-
-       /* delay is required to make sure sound card state updated */
-       usleep_range(5000, 5100);
-
-       msm8x16_wcd_codec_init_reg(codec);
-       msm8x16_wcd_update_reg_defaults(codec);
-
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
-                                               int enable)
-{
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-       unsigned long mclk_rate;
-
-       if (enable) {
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_CLK_PDM_CTL, 0x03, 0x03);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
-
-               mclk_rate = clk_get_rate(msm8x16_wcd->mclk);
-
-               if (mclk_rate == 12288000)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_TOP_CTL, 0x01, 0x00);
-               else if (mclk_rate == 9600000)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_TOP_CTL, 0x01, 0x01);
-       } else {
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
-               snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_CLK_PDM_CTL, 0x03, 0x00);
-
-       }
-       return 0;
-}
-
-#define MICBIAS_EXT_BYP_CAP 0x00
-#define MICBIAS_NO_EXT_BYP_CAP 0x01
-
-static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec,
-               bool micbias1, bool micbias2)
-{
-
-//     struct msm8916_asoc_mach_data *pdata = NULL;
-//FIXME should come from DT
-       int micbias1_cap_mode = MICBIAS_EXT_BYP_CAP, micbias2_cap_mode = MICBIAS_NO_EXT_BYP_CAP;
-
-       //pdata = snd_soc_card_get_drvdata(codec->card);
-
-       pr_debug("\n %s: micbias1 %x micbias2 = %d\n", __func__, micbias1,
-                       micbias2);
-       if (micbias1 && micbias2) {
-               if ((micbias1_cap_mode
-                    == MICBIAS_EXT_BYP_CAP) ||
-                   (micbias2_cap_mode
-                    == MICBIAS_EXT_BYP_CAP))
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_MICB_1_EN,
-                               0x40, (MICBIAS_EXT_BYP_CAP << 6));
-               else
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_MICB_1_EN,
-                               0x40, (MICBIAS_NO_EXT_BYP_CAP << 6));
-       } else if (micbias2) {
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN,
-                               0x40, (micbias2_cap_mode << 6));
-       } else if (micbias1) {
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN,
-                               0x40, (micbias1_cap_mode << 6));
-       } else {
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_EN,
-                               0x40, 0x00);
-       }
-}
-
-static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
-{
-       struct wcd_chip *chip = dev_get_drvdata(codec->dev);
-       int err;
-
-       snd_soc_codec_set_drvdata(codec, chip);
-
-       regulator_set_voltage(chip->vddio, 1800000, 1800000);
-       err = regulator_enable(chip->vddio);
-       if (err < 0) {
-               dev_err(codec->dev, "failed to enable VDD regulator\n");
-               return err;
-       }
-       regulator_set_voltage(chip->vdd_pa, 1800000, 2200000);
-       err = regulator_enable(chip->vdd_pa);
-       if (err < 0) {
-               dev_err(codec->dev, "failed to enable VDD regulator\n");
-               return err;
-       }
-
-       regulator_set_voltage(chip->vdd_mic_bias, 3075000, 3075000);
-       err = regulator_enable(chip->vdd_mic_bias);
-       if (err < 0) {
-               dev_err(codec->dev, "failed to enable micbias regulator\n");
-               return err;
-       }
-
-       chip->pmic_rev = snd_soc_read(codec, MSM8X16_WCD_A_DIGITAL_REVISION1);
-       dev_info(codec->dev, "%s :PMIC REV: %d", __func__,
-                                       chip->pmic_rev);
-
-       chip->codec_version = snd_soc_read(codec,
-                       MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE);
-       dev_info(codec->dev, "%s :CODEC Version: %d", __func__,
-                               chip->codec_version);
-
-       msm8x16_wcd_device_up(codec);
-
-       /* Set initial cap mode */
-       msm8x16_wcd_configure_cap(codec, false, false);
-
-       msm8x16_wcd_codec_enable_clock_block(codec, 1);
-
-       return 0;
-}
-
-static int msm8x16_wcd_startup(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       dev_dbg(dai->codec->dev, "%s(): substream = %s  stream = %d\n",
-               __func__,
-               substream->name, substream->stream);
-       return 0;
-}
-
-static void msm8x16_wcd_shutdown(struct snd_pcm_substream *substream,
-               struct snd_soc_dai *dai)
-{
-       dev_dbg(dai->codec->dev,
-               "%s(): substream = %s  stream = %d\n", __func__,
-               substream->name, substream->stream);
-}
-
-static int msm8x16_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
-       u8 rx_fs_rate_reg_val, u32 sample_rate)
-{
-       return 0;
-}
-
-static int msm8x16_wcd_set_decimator_rate(struct snd_soc_dai *dai,
-       u8 tx_fs_rate_reg_val, u32 sample_rate)
-{
-
-       return 0;
-}
-
-static int msm8x16_wcd_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params,
-                           struct snd_soc_dai *dai)
-{
-       u8 tx_fs_rate, rx_fs_rate;
-       int ret;
-
-       dev_err(dai->codec->dev,
-               "%s: dai_name = %s DAI-ID %x rate %d num_ch %d format %d\n",
-               __func__, dai->name, dai->id, params_rate(params),
-               params_channels(params), params_format(params));
-
-       switch (params_rate(params)) {
-       case 8000:
-               tx_fs_rate = 0x00;
-               rx_fs_rate = 0x00;
-               break;
-       case 16000:
-               tx_fs_rate = 0x01;
-               rx_fs_rate = 0x20;
-               break;
-       case 32000:
-               tx_fs_rate = 0x02;
-               rx_fs_rate = 0x40;
-               break;
-       case 48000:
-               tx_fs_rate = 0x03;
-               rx_fs_rate = 0x60;
-               break;
-       case 96000:
-               tx_fs_rate = 0x04;
-               rx_fs_rate = 0x80;
-               break;
-       case 192000:
-               tx_fs_rate = 0x05;
-               rx_fs_rate = 0xA0;
-               break;
-       default:
-               dev_err(dai->codec->dev,
-                       "%s: Invalid sampling rate %d\n", __func__,
-                       params_rate(params));
-               return -EINVAL;
-       }
-
-       switch (substream->stream) {
-       case SNDRV_PCM_STREAM_CAPTURE:
-               snd_soc_update_bits(dai->codec,
-                               MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL, 0x07, tx_fs_rate);
-               ret = msm8x16_wcd_set_decimator_rate(dai, tx_fs_rate,
-                                              params_rate(params));
-               if (ret < 0) {
-                       dev_err(dai->codec->dev,
-                               "%s: set decimator rate failed %d\n", __func__,
-                               ret);
-                       return ret;
-               }
-               break;
-       case SNDRV_PCM_STREAM_PLAYBACK:
-               ret = msm8x16_wcd_set_interpolator_rate(dai, rx_fs_rate,
-                                                 params_rate(params));
-               if (ret < 0) {
-                       dev_err(dai->codec->dev,
-                               "%s: set decimator rate failed %d\n", __func__,
-                               ret);
-                       return ret;
-               }
-               break;
-       default:
-               dev_err(dai->codec->dev,
-                       "%s: Invalid stream type %d\n", __func__,
-                       substream->stream);
-               return -EINVAL;
-       }
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               snd_soc_update_bits(dai->codec,
-                               MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x20);
-               snd_soc_update_bits(dai->codec,
-                               MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x20);
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               snd_soc_update_bits(dai->codec,
-                               MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x00);
-               snd_soc_update_bits(dai->codec,
-                               MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x00);
-               break;
-       default:
-               dev_err(dai->dev, "%s: wrong format selected\n",
-                               __func__);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int msm8x16_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
-               int clk_id, unsigned int freq, int dir)
-{
-       dev_dbg(dai->codec->dev, "%s\n", __func__);
-       return 0;
-}
-
-static int msm8x16_wcd_set_channel_map(struct snd_soc_dai *dai,
-                               unsigned int tx_num, unsigned int *tx_slot,
-                               unsigned int rx_num, unsigned int *rx_slot)
-
-{
-       dev_dbg(dai->codec->dev, "%s\n", __func__);
-       return 0;
-}
-
-static int msm8x16_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-       dev_dbg(dai->codec->dev, "%s\n", __func__);
-
-       return 0;
-}
-
-static struct snd_soc_dai_ops msm8x16_wcd_dai_ops = {
-       .startup = msm8x16_wcd_startup,
-       .shutdown = msm8x16_wcd_shutdown,
-       .hw_params = msm8x16_wcd_hw_params,
-       .set_sysclk = msm8x16_wcd_set_dai_sysclk,
-       .set_fmt = msm8x16_wcd_set_dai_fmt,
-       .set_channel_map = msm8x16_wcd_set_channel_map,
-};
-
-static struct snd_soc_dai_driver msm8x16_wcd_codec_dai[] = {
-       [0] = {
-               .name = "msm8x16_wcd_i2s_rx1",
-               .id = AIF1_PB,
-               .playback = {
-                       .stream_name = "AIF1 Playback",
-                       .rates = MSM8X16_WCD_RATES,
-                       .formats = MSM8X16_WCD_FORMATS,
-                       .rate_max = 192000,
-                       .rate_min = 8000,
-                       .channels_min = 1,
-                       .channels_max = 3,
-               },
-               .ops = &msm8x16_wcd_dai_ops,
-       },
-       [1] = {
-               .name = "msm8x16_wcd_i2s_tx1",
-               .id = AIF1_CAP,
-               .capture = {
-                       .stream_name = "AIF1 Capture",
-                       .rates = MSM8X16_WCD_RATES,
-                       .formats = MSM8X16_WCD_FORMATS,
-                       .rate_max = 192000,
-                       .rate_min = 8000,
-                       .channels_min = 1,
-                       .channels_max = 4,
-               },
-               .ops = &msm8x16_wcd_dai_ops,
-       },
-};
-
-static int msm8x16_wcd_codec_remove(struct snd_soc_codec *codec)
-{
-       /* TODO */
-       return 0;
-};
-
-static int msm8x16_wcd_spk_boost_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct wcd_chip *msm8x16_wcd = dev_get_drvdata(codec->dev);
-
-       if (msm8x16_wcd->spk_boost_set == false) {
-               ucontrol->value.integer.value[0] = 0;
-       } else if (msm8x16_wcd->spk_boost_set == true) {
-               ucontrol->value.integer.value[0] = 1;
-       } else  {
-               dev_err(codec->dev, "%s: ERROR: Unsupported Speaker Boost = %d\n",
-                       __func__, msm8x16_wcd->spk_boost_set);
-               return -EINVAL;
-       }
-
-       dev_dbg(codec->dev, "%s: msm8x16_wcd->spk_boost_set = %d\n", __func__,
-                       msm8x16_wcd->spk_boost_set);
-       return 0;
-}
-
-static int msm8x16_wcd_spk_boost_set(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (ucontrol->value.integer.value[0]) {
-       case 0:
-               msm8x16_wcd->spk_boost_set = false;
-               break;
-       case 1:
-               msm8x16_wcd->spk_boost_set = true;
-               break;
-       default:
-               return -EINVAL;
-       }
-       dev_dbg(codec->dev, "%s: msm8x16_wcd->spk_boost_set = %d\n",
-               __func__, msm8x16_wcd->spk_boost_set);
-       return 0;
-}
-
-static const char * const hph_text[] = {
-       "ZERO", "Switch",
-};
-
-static const struct soc_enum hph_enum =
-       SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(hph_text), hph_text);
-
-static const struct snd_kcontrol_new hphl_mux[] = {
-       SOC_DAPM_ENUM("HPHL", hph_enum)
-};
-
-static const struct snd_kcontrol_new hphr_mux[] = {
-       SOC_DAPM_ENUM("HPHR", hph_enum)
-};
-
-static const struct snd_kcontrol_new spkr_switch[] = {
-       SOC_DAPM_SINGLE("Switch",
-               MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 7, 1, 0)
-};
-
-static void msm8x16_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
-                                        int enable)
-{
-       //struct msm8x16_wcd_priv *wcd8x16 = snd_soc_codec_get_drvdata(codec);
-
-       dev_dbg(codec->dev, "%s %d\n", __func__, enable);
-
-       if (enable) {
-               //wcd8x16->adc_count++;
-               snd_soc_update_bits(codec,
-                                   MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL,
-                                   0x20, 0x20);
-               snd_soc_update_bits(codec,
-                                   MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                   0x10, 0x10);
-       } else {
-               //wcd8x16->adc_count--;
-               //if (!wcd8x16->adc_count) {
-                       snd_soc_update_bits(codec,
-                                   MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                   0x10, 0x00);
-                       snd_soc_update_bits(codec,
-                                   MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL,
-                                           0x20, 0x0);
-               //}
-       }
-}
-
-static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
-static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
-
-static const char * const rx_mix1_text[] = {
-       "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
-};
-
-static const char * const rx_mix2_text[] = {
-       "ZERO", "IIR1", "IIR2"
-};
-
-static const char * const dec_mux_text[] = {
-       "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2"
-};
-
-static const char * const adc2_mux_text[] = {
-       "ZERO", "INP2", "INP3"
-};
-
-static const char * const rdac2_mux_text[] = {
-       "ZERO", "RX2", "RX1"
-};
-
-static const char * const iir_inp1_text[] = {
-       "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
-};
-
-static const char * const iir1_inp1_text[] = {
-       "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
-};
-
-static const struct soc_enum adc2_enum =
-       SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
-
-/* RX1 MIX1 */
-static const struct soc_enum rx_mix1_inp1_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL,
-               0, 6, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp2_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL,
-               3, 6, rx_mix1_text);
-
-static const struct soc_enum rx_mix1_inp3_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX1_B2_CTL,
-               0, 6, rx_mix1_text);
-/* RX1 MIX2 */
-static const struct soc_enum rx_mix2_inp1_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX1_B3_CTL,
-               0, 3, rx_mix2_text);
-
-/* RX2 MIX1 */
-static const struct soc_enum rx2_mix1_inp1_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL,
-               0, 6, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp2_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL,
-               3, 6, rx_mix1_text);
-
-static const struct soc_enum rx2_mix1_inp3_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL,
-               0, 6, rx_mix1_text);
-
-/* RX2 MIX2 */
-static const struct soc_enum rx2_mix2_inp1_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX2_B3_CTL,
-               0, 3, rx_mix2_text);
-
-/* RX3 MIX1 */
-static const struct soc_enum rx3_mix1_inp1_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL,
-               0, 6, rx_mix1_text);
-
-static const struct soc_enum rx3_mix1_inp2_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL,
-               3, 6, rx_mix1_text);
-
-/* DEC */
-static const struct soc_enum dec1_mux_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_TX_B1_CTL,
-               0, 6, dec_mux_text);
-
-static const struct soc_enum dec2_mux_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_TX_B1_CTL,
-               3, 6, dec_mux_text);
-
-static const struct soc_enum rdac2_mux_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_DIGITAL_CDC_CONN_HPHR_DAC_CTL,
-               0, 3, rdac2_mux_text);
-
-static const struct soc_enum iir1_inp1_mux_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_EQ1_B1_CTL,
-               0, 6, iir_inp1_text);
-
-static const struct soc_enum iir2_inp1_mux_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_EQ2_B1_CTL,
-               0, 6, iir_inp1_text);
-static const struct snd_kcontrol_new iir2_inp1_mux =
-       SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
-
-static const struct soc_enum rx3_mix1_inp3_chain_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL,
-               0, 6, rx_mix1_text);
-static const struct snd_kcontrol_new rx_mix1_inp1_mux =
-       SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new dec1_mux =
-       SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
-
-static const struct snd_kcontrol_new dec2_mux =
-       SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
-
-static const struct snd_kcontrol_new rdac2_mux =
-       SOC_DAPM_ENUM("RDAC2 MUX Mux", rdac2_mux_enum);
-
-static const struct snd_kcontrol_new iir1_inp1_mux =
-       SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp2_mux =
-       SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx_mix1_inp3_mux =
-       SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
-       SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
-       SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix1_inp3_mux =
-       SOC_DAPM_ENUM("RX2 MIX1 INP3 Mux", rx2_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
-       SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
-       SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
-
-static const struct snd_kcontrol_new rx3_mix1_inp3_mux =
-       SOC_DAPM_ENUM("RX3 MIX1 INP3 Mux", rx3_mix1_inp3_chain_enum);
-
-static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
-       SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
-       SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
-
-static const struct snd_kcontrol_new tx_adc2_mux =
-       SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
-
-static const char * const msm8x16_wcd_loopback_mode_ctrl_text[] = {
-               "DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_loopback_mode_ctl_enum[] = {
-               SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_loopback_mode_ctrl_text),
-};
-
-static int msm8x16_wcd_codec_enable_on_demand_supply(
-               struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-       int ret = 0;
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               ret = regulator_enable(msm8x16_wcd->vdd_mic_bias);
-               if (ret)
-               dev_err(codec->dev, "%s: Failed to enable vdd micbias\n",
-                       __func__);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               ret = regulator_disable(msm8x16_wcd->vdd_mic_bias);
-               if (ret)
-                       dev_err(codec->dev, "%s: Failed to disable vdd-micbias\n",
-                               __func__);
-               break;
-       default:
-               break;
-       }
-
-       return ret;
-}
-
-static const char * const msm8x16_wcd_ear_pa_boost_ctrl_text[] = {
-               "DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_ear_pa_boost_ctl_enum[] = {
-               SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ear_pa_boost_ctrl_text),
-};
-
-static const char * const msm8x16_wcd_ear_pa_gain_text[] = {
-               "POS_6_DB", "POS_1P5_DB"};
-static const struct soc_enum msm8x16_wcd_ear_pa_gain_enum[] = {
-               SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ear_pa_gain_text),
-};
-
-static const char * const msm8x16_wcd_spk_boost_ctrl_text[] = {
-               "DISABLE", "ENABLE"};
-static const struct soc_enum msm8x16_wcd_spk_boost_ctl_enum[] = {
-               SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_spk_boost_ctrl_text),
-};
-
-/*cut of frequency for high pass filter*/
-static const char * const cf_text[] = {
-       "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
-};
-
-static const struct soc_enum cf_dec1_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_dec2_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
-
-static const struct soc_enum cf_rxmix1_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
-
-static const struct soc_enum cf_rxmix2_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
-
-static const struct soc_enum cf_rxmix3_enum =
-       SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
-
-static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = {
-
-       SOC_ENUM_EXT("Speaker Boost", msm8x16_wcd_spk_boost_ctl_enum[0],
-               msm8x16_wcd_spk_boost_get, msm8x16_wcd_spk_boost_set),
-
-       SOC_SINGLE_TLV("ADC1 Volume", MSM8X16_WCD_A_ANALOG_TX_1_EN, 3,
-                                       8, 0, analog_gain),
-       SOC_SINGLE_TLV("ADC2 Volume", MSM8X16_WCD_A_ANALOG_TX_2_EN, 3,
-                                       8, 0, analog_gain),
-       SOC_SINGLE_TLV("ADC3 Volume", MSM8X16_WCD_A_ANALOG_TX_3_EN, 3,
-                                       8, 0, analog_gain),
-
-       SOC_SINGLE_SX_TLV("RX1 Digital Volume",
-                         MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX2 Digital Volume",
-                         MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
-                       0,  -84, 40, digital_gain),
-       SOC_SINGLE_SX_TLV("RX3 Digital Volume",
-                         MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
-                       0,  -84, 40, digital_gain),
-
-       SOC_SINGLE("RX1 HPF Switch",
-               MSM8X16_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
-       SOC_SINGLE("RX2 HPF Switch",
-               MSM8X16_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
-       SOC_SINGLE("RX3 HPF Switch",
-               MSM8X16_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
-
-       SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
-       SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
-       SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
-};
-
-static const struct snd_kcontrol_new ear_pa_switch[] = {
-       SOC_DAPM_SINGLE("Switch",
-               MSM8X16_WCD_A_ANALOG_RX_EAR_CTL, 5, 1, 0)
-};
-
-static int msm8x16_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               dev_dbg(codec->dev,
-                       "%s: Sleeping 20ms after select EAR PA\n",
-                       __func__);
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_EAR_CTL,
-                           0x80, 0x80);
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               dev_dbg(codec->dev,
-                       "%s: Sleeping 20ms after enabling EAR PA\n",
-                       __func__);
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_EAR_CTL,
-                           0x40, 0x40);
-               usleep_range(7000, 7100);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_RX1_B6_CTL, 0x01, 0x00);
-               break;
-       case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_RX1_B6_CTL, 0x01, 0x01);
-               msleep(20);
-               msm8x16_wcd->mute_mask |= EAR_PA_DISABLE;
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               dev_dbg(codec->dev,
-                       "%s: Sleeping 7ms after disabling EAR PA\n",
-                       __func__);
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_EAR_CTL,
-                           0x40, 0x00);
-               usleep_range(7000, 7100);
-               /*
-                * Reset pa select bit from ear to hph after ear pa
-                * is disabled to reduce ear turn off pop
-                */
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_EAR_CTL,
-                           0x80, 0x00);
-               break;
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       //struct snd_soc_codec *codec = w->codec;
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       u16 adc_reg;
-       u8 init_bit_shift;
-
-       dev_dbg(codec->dev, "%s %d\n", __func__, event);
-
-       adc_reg = MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_2;
-
-       if (w->reg == MSM8X16_WCD_A_ANALOG_TX_1_EN)
-               init_bit_shift = 5;
-       else if ((w->reg == MSM8X16_WCD_A_ANALOG_TX_2_EN) ||
-                (w->reg == MSM8X16_WCD_A_ANALOG_TX_3_EN))
-               init_bit_shift = 4;
-       else {
-               dev_err(codec->dev, "%s: Error, invalid adc register\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               msm8x16_wcd_codec_enable_adc_block(codec, 1);
-               if (w->reg == MSM8X16_WCD_A_ANALOG_TX_2_EN)
-                       snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_MICB_1_CTL, 0x02, 0x02);
-               /*
-                * Add delay of 10 ms to give sufficient time for the voltage
-                * to shoot up and settle so that the txfe init does not
-                * happen when the input voltage is changing too much.
-                */
-               usleep_range(10000, 10010);
-               snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
-                               1 << init_bit_shift);
-               if (w->reg == MSM8X16_WCD_A_ANALOG_TX_1_EN)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX1_CTL,
-                               0x03, 0x00);
-               else if ((w->reg == MSM8X16_WCD_A_ANALOG_TX_2_EN) ||
-                       (w->reg == MSM8X16_WCD_A_ANALOG_TX_3_EN))
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX2_CTL,
-                               0x03, 0x00);
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               /*
-                * Add delay of 12 ms before deasserting the init
-                * to reduce the tx pop
-                */
-       usleep_range(12000, 12010);
-               snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               msm8x16_wcd_codec_enable_adc_block(codec, 0);
-               if (w->reg == MSM8X16_WCD_A_ANALOG_TX_2_EN)
-                       snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_MICB_1_CTL, 0x02, 0x00);
-               if (w->reg == MSM8X16_WCD_A_ANALOG_TX_1_EN)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX1_CTL,
-                               0x03, 0x02);
-               else if ((w->reg == MSM8X16_WCD_A_ANALOG_TX_2_EN) ||
-                       (w->reg == MSM8X16_WCD_A_ANALOG_TX_3_EN))
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX2_CTL,
-                               0x03, 0x02);
-
-               break;
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
-                                    struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x01);
-               if (!msm8x16_wcd->spk_boost_set)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 0x10, 0x10);
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0xE0);
-               if (!TOMBAK_IS_1_0(msm8x16_wcd->pmic_rev))
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_RX_EAR_CTL, 0x01, 0x01);
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               if (msm8x16_wcd->spk_boost_set)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL, 0xEF, 0xEF);
-               else
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_RX3_B6_CTL, 0x01, 0x00);
-               snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
-               break;
-       case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_RX3_B6_CTL, 0x01, 0x01);
-               msleep(20);
-               msm8x16_wcd->mute_mask |= SPKR_PA_DISABLE;
-               snd_soc_update_bits(codec, w->reg, 0x80, 0x00);
-               if (msm8x16_wcd->spk_boost_set)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL, 0xEF, 0x00);
-               else
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL, 0x10, 0x00);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0x00);
-               if (!TOMBAK_IS_1_0(msm8x16_wcd->pmic_rev))
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_RX_EAR_CTL, 0x01, 0x00);
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x00);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00);
-               break;
-       }
-       return 0;
-}
-
-static void msm8x16_wcd_micbias_2_enable(struct snd_soc_codec *codec, bool on)
-{
-       if (on) {
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_CTL,
-                                       0x60, 0x60);
-               snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_1_VAL,
-                                       0xC0);
-               /*
-                * Special headset needs MICBIAS as 2.7V so wait for
-                * 50 msec for the MICBIAS to reach 2.7 volts.
-                */
-               msleep(50);
-               snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MICB_1_CTL,
-                               0x60, 0x00);
-       }
-}
-
-static s32 g_dmic_clk_cnt;
-static int msm8x16_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       u8  dmic_clk_en;
-       u16 dmic_clk_reg;
-       s32 *dmic_clk_cnt;
-       unsigned int dmic;
-       int ret;
-       char *dec_num = strpbrk(w->name, "12");
-
-       if (dec_num == NULL) {
-               dev_err(codec->dev, "%s: Invalid DMIC\n", __func__);
-               return -EINVAL;
-       }
-
-       ret = kstrtouint(dec_num, 10, &dmic);
-       if (ret < 0) {
-               dev_err(codec->dev,
-                       "%s: Invalid DMIC line on the codec\n", __func__);
-               return -EINVAL;
-       }
-
-       switch (dmic) {
-       case 1:
-       case 2:
-               dmic_clk_en = 0x01;
-               dmic_clk_cnt = &g_dmic_clk_cnt;
-               dmic_clk_reg = MSM8X16_WCD_A_CDC_CLK_DMIC_B1_CTL;
-               dev_dbg(codec->dev,
-                       "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
-                       __func__, event,  dmic, *dmic_clk_cnt);
-               break;
-       default:
-               dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
-               return -EINVAL;
-       }
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               (*dmic_clk_cnt)++;
-               if (*dmic_clk_cnt == 1) {
-                       snd_soc_update_bits(codec, dmic_clk_reg,
-                                       0x0E, 0x02);
-                       snd_soc_update_bits(codec, dmic_clk_reg,
-                                       dmic_clk_en, dmic_clk_en);
-               }
-               if (dmic == 1)
-                       snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_TX1_DMIC_CTL, 0x07, 0x01);
-               if (dmic == 2)
-                       snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_TX2_DMIC_CTL, 0x07, 0x01);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               (*dmic_clk_cnt)--;
-               if (*dmic_clk_cnt  == 0)
-                       snd_soc_update_bits(codec, dmic_clk_reg,
-                                       dmic_clk_en, 0);
-               break;
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-       u16 micb_int_reg;
-       char *internal1_text = "Internal1";
-       char *internal2_text = "Internal2";
-       char *internal3_text = "Internal3";
-       char *external2_text = "External2";
-       char *external_text = "External";
-       bool micbias2;
-
-       switch (w->reg) {
-       case MSM8X16_WCD_A_ANALOG_MICB_1_EN:
-       case MSM8X16_WCD_A_ANALOG_MICB_2_EN:
-               micb_int_reg = MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS;
-               break;
-       default:
-               dev_err(codec->dev,
-                       "%s: Error, invalid micbias register 0x%x\n",
-                       __func__, w->reg);
-               return -EINVAL;
-       }
-
-       micbias2 = (snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN) & 0x80);
-       
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               if (strnstr(w->name, internal1_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
-               } else if (strnstr(w->name, internal2_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
-                       snd_soc_update_bits(codec, w->reg, 0x60, 0x00);
-               } else if (strnstr(w->name, internal3_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
-               }
-               if (!strnstr(w->name, external_text, 30))
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_MICB_1_EN, 0x05, 0x04);
-               if (w->reg == MSM8X16_WCD_A_ANALOG_MICB_1_EN)
-                       msm8x16_wcd_configure_cap(codec, true, micbias2);
-
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               usleep_range(20000, 20100);
-               if (strnstr(w->name, internal1_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0x40, 0x40);
-               } else if (strnstr(w->name, internal2_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0x08, 0x08);
-                       msm8x16_wcd_micbias_2_enable(codec, true);
-
-                       msm8x16_wcd_configure_cap(codec, false, true);
-                       regmap_write(msm8x16_wcd->analog_map, 0xf144, 0x95);
-               } else if (strnstr(w->name, internal3_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0x01, 0x01);
-               }  else if (strnstr(w->name, external2_text, 30)) {
-                       msm8x16_wcd_micbias_2_enable(codec, true);
-               }
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               if (strnstr(w->name, internal1_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0xC0, 0x40);
-               } else if (strnstr(w->name, internal2_text, 30)) {
-                       msm8x16_wcd_micbias_2_enable(codec, false);
-               } else if (strnstr(w->name, internal3_text, 30)) {
-                       snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
-               } else if (strnstr(w->name, external2_text, 30)) {
-                       /*
-                        * send micbias turn off event to mbhc driver and then
-                        * break, as no need to set MICB_1_EN register.
-                        */
-                       msm8x16_wcd_micbias_2_enable(codec, false);
-                       break;
-               }
-               if (w->reg == MSM8X16_WCD_A_ANALOG_MICB_1_EN)
-                       msm8x16_wcd_configure_cap(codec, false, micbias2);
-               break;
-       }
-
-       return 0;
-}
-
-#define  TX_MUX_CTL_CUT_OFF_FREQ_MASK  0x30
-#define  CF_MIN_3DB_4HZ                        0x0
-#define  CF_MIN_3DB_75HZ               0x1
-#define  CF_MIN_3DB_150HZ              0x2
-
-static int msm8x16_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       unsigned int decimator;
-       char *dec_name = NULL;
-       char *widget_name = NULL;
-       char *temp;
-       int ret = 0;
-       u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
-       u8 dec_hpf_cut_of_freq;
-       int offset;
-       char *dec_num;
-       dev_dbg(codec->dev, "%s %d\n", __func__, event);
-
-       widget_name = kstrndup(w->name, 15, GFP_KERNEL);
-       if (!widget_name)
-               return -ENOMEM;
-       temp = widget_name;
-
-       dec_name = strsep(&widget_name, " ");
-       widget_name = temp;
-       if (!dec_name) {
-               dev_err(codec->dev,
-                       "%s: Invalid decimator = %s\n", __func__, w->name);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       dec_num = strpbrk(dec_name, "12");
-       if (dec_num == NULL) {
-               dev_err(codec->dev, "%s: Invalid Decimator\n", __func__);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = kstrtouint(dec_num, 10, &decimator);
-       if (ret < 0) {
-               dev_err(codec->dev,
-                       "%s: Invalid decimator = %s\n", __func__, dec_name);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       dev_err(codec->dev,
-               "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
-               w->name, dec_name, decimator);
-
-       if (w->reg == MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
-               dec_reset_reg = MSM8X16_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
-               offset = 0;
-       } else {
-               dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       tx_vol_ctl_reg = MSM8X16_WCD_A_CDC_TX1_VOL_CTL_CFG +
-                        32 * (decimator - 1);
-       tx_mux_ctl_reg = MSM8X16_WCD_A_CDC_TX1_MUX_CTL +
-                         32 * (decimator - 1);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               /* Enableable TX digital mute */
-               snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
-               dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
-               dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
-               if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
-
-                       /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
-                       snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
-                                           CF_MIN_3DB_150HZ << 4);
-               }
-               snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_TX_1_2_TXFE_CLKDIV,
-                               0xFF, 0x42);
-
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               /* enable HPF */
-               snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
-               /* apply the digital gain after the decimator is enabled*/
-               if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
-                       snd_soc_write(codec,
-                                 tx_digital_gain_reg[w->shift + offset],
-                                 snd_soc_read(codec,
-                                 tx_digital_gain_reg[w->shift + offset])
-                                 );
-               snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
-               break;
-       case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
-               msleep(20);
-               snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
-                       1 << w->shift);
-               snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
-               snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
-               snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
-               break;
-       }
-
-out:
-       kfree(widget_name);
-       return ret;
-}
-
-static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
-                                                struct snd_kcontrol *kcontrol,
-                                                int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               /* apply the digital gain after the interpolator is enabled*/
-               if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
-                       snd_soc_write(codec,
-                                 rx_digital_gain_reg[w->shift],
-                                 snd_soc_read(codec,
-                                 rx_digital_gain_reg[w->shift])
-                                 );
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL,
-                       1 << w->shift, 1 << w->shift);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL,
-                       1 << w->shift, 0x0);
-               /*
-                * disable the mute enabled during the PMD of this device
-                */
-               if (msm8x16_wcd->mute_mask & HPHL_PA_DISABLE) {
-                       pr_debug("disabling HPHL mute\n");
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX1_B6_CTL, 0x01, 0x00);
-                       msm8x16_wcd->mute_mask &= ~(HPHL_PA_DISABLE);
-               }
-               if (msm8x16_wcd->mute_mask & HPHR_PA_DISABLE) {
-                       pr_debug("disabling HPHR mute\n");
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX2_B6_CTL, 0x01, 0x00);
-                       msm8x16_wcd->mute_mask &= ~(HPHR_PA_DISABLE);
-               }
-               if (msm8x16_wcd->mute_mask & SPKR_PA_DISABLE) {
-                       pr_debug("disabling SPKR mute\n");
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX3_B6_CTL, 0x01, 0x00);
-                       msm8x16_wcd->mute_mask &= ~(SPKR_PA_DISABLE);
-               }
-               if (msm8x16_wcd->mute_mask & EAR_PA_DISABLE) {
-                       pr_debug("disabling EAR mute\n");
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX1_B6_CTL, 0x01, 0x00);
-                       msm8x16_wcd->mute_mask &= ~(EAR_PA_DISABLE);
-               }
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_dig_clk(struct snd_soc_dapm_widget *w,
-                                    struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               if (w->shift == 2)
-                       snd_soc_update_bits(codec, w->reg, 0x80, 0x80);
-               if (msm8x16_wcd->spk_boost_set) {
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_SEC_ACCESS,
-                                       0xA5, 0xA5);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL3,
-                                       0x0F, 0x0F);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT,
-                                       0x82, 0x82);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                       0x20, 0x20);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL,
-                                       0xDF, 0xDF);
-                       usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT,
-                                       0x83, 0x83);
-               } else if (msm8x16_wcd->ear_pa_boost_set) {
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_SEC_ACCESS,
-                                       0xA5, 0xA5);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL3,
-                                       0x07, 0x07);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BYPASS_MODE,
-                                       0x40, 0x40);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BYPASS_MODE,
-                                       0x80, 0x80);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BYPASS_MODE,
-                                       0x02, 0x02);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL,
-                                       0xDF, 0xDF);
-               } else {
-                       snd_soc_update_bits(codec, w->reg, 1<<w->shift,
-                                       1<<w->shift);
-               }
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               if (msm8x16_wcd->spk_boost_set) {
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL,
-                                       0xDF, 0x5F);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                       0x20, 0x00);
-               } else if (msm8x16_wcd->ear_pa_boost_set) {
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL,
-                                       0x80, 0x00);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BYPASS_MODE,
-                                       0x80, 0x00);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BYPASS_MODE,
-                                       0x02, 0x00);
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_BYPASS_MODE,
-                                       0x40, 0x00);
-               } else {
-                       snd_soc_update_bits(codec, w->reg, 1<<w->shift, 0x00);
-               }
-               break;
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_rx_chain(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                               0x80, 0x80);
-               dev_dbg(codec->dev,
-                       "%s: PMU:Sleeping 20ms after disabling mute\n",
-                       __func__);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                               0x80, 0x00);
-               dev_dbg(codec->dev,
-                       "%s: PMD:Sleeping 20ms after disabling mute\n",
-                       __func__);
-               snd_soc_update_bits(codec, w->reg,
-                           1 << w->shift, 0x00);
-               msleep(20);
-               break;
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               msm8x16_wcd->rx_bias_count++;
-               if (msm8x16_wcd->rx_bias_count == 1)
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC,
-                                       0x81, 0x81);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               msm8x16_wcd->rx_bias_count--;
-               if (msm8x16_wcd->rx_bias_count == 0)
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC,
-                                       0x81, 0x00);
-               break;
-       }
-       dev_dbg(codec->dev, "%s rx_bias_count = %d\n",
-                       __func__, msm8x16_wcd->rx_bias_count);
-       return 0;
-}
-
-static int msm8x16_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               if (!(strcmp(w->name, "EAR CP")))
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                       0x80, 0x80);
-               else
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                       0xC0, 0xC0);
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               if (!(strcmp(w->name, "EAR CP")))
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                       0x80, 0x00);
-               else {
-                       snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                       0x40, 0x00);
-                       if (msm8x16_wcd->rx_bias_count == 0)
-                               snd_soc_update_bits(codec,
-                                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-                                       0x80, 0x00);
-                       dev_dbg(codec->dev, "%s: rx_bias_count = %d\n",
-                                       __func__, msm8x16_wcd->rx_bias_count);
-               }
-               break;
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02);
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x00);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
-               break;
-       }
-       return 0;
-}
-
-static int msm8x16_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
-                             struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-       struct wcd_chip *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               if (w->shift == 5) {
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_RX_HPH_L_TEST, 0x04, 0x04);
-               } else if (w->shift == 4) {
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_RX_HPH_R_TEST, 0x04, 0x04);
-               }
-               snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_NCP_FBCTRL, 0x20, 0x20);
-               break;
-
-       case SND_SOC_DAPM_POST_PMU:
-               usleep_range(4000, 4100);
-               if (w->shift == 5)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX1_B6_CTL, 0x01, 0x00);
-               else if (w->shift == 4)
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX2_B6_CTL, 0x01, 0x00);
-               usleep_range(10000, 10100);
-               break;
-
-       case SND_SOC_DAPM_PRE_PMD:
-               if (w->shift == 5) {
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX1_B6_CTL, 0x01, 0x01);
-                       msleep(20);
-                       msm8x16_wcd->mute_mask |= HPHL_PA_DISABLE;
-               } else if (w->shift == 4) {
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_CDC_RX2_B6_CTL, 0x01, 0x01);
-                       msleep(20);
-                       msm8x16_wcd->mute_mask |= HPHR_PA_DISABLE;
-               }
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               if (w->shift == 5) {
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_RX_HPH_L_TEST, 0x04, 0x00);
-
-               } else if (w->shift == 4) {
-                       snd_soc_update_bits(codec,
-                               MSM8X16_WCD_A_ANALOG_RX_HPH_R_TEST, 0x04, 0x00);
-               }
-               usleep_range(4000, 4100);
-
-               usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x40, 0x40);
-               dev_dbg(codec->dev,
-                       "%s: sleep 10 ms after %s PA disable.\n", __func__,
-                       w->name);
-               usleep_range(10000, 10100);
-               break;
-       }
-       return 0;
-}
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       {"RX_I2S_CLK", NULL, "CDC_CONN"},
-       {"I2S RX1", NULL, "RX_I2S_CLK"},
-       {"I2S RX2", NULL, "RX_I2S_CLK"},
-       {"I2S RX3", NULL, "RX_I2S_CLK"},
-
-       {"I2S TX1", NULL, "TX_I2S_CLK"},
-       {"I2S TX2", NULL, "TX_I2S_CLK"},
-
-       {"I2S TX1", NULL, "DEC1 MUX"},
-       {"I2S TX2", NULL, "DEC2 MUX"},
-
-       /* RDAC Connections */
-       {"HPHR DAC", NULL, "RDAC2 MUX"},
-       {"RDAC2 MUX", "RX1", "RX1 CHAIN"},
-       {"RDAC2 MUX", "RX2", "RX2 CHAIN"},
-
-       /* Earpiece (RX MIX1) */
-       {"EAR", NULL, "EAR_S"},
-       {"EAR_S", "Switch", "EAR PA"},
-       {"EAR PA", NULL, "RX_BIAS"},
-       {"EAR PA", NULL, "HPHL DAC"},
-       {"EAR PA", NULL, "HPHR DAC"},
-       {"EAR PA", NULL, "EAR CP"},
-
-       /* Headset (RX MIX1 and RX MIX2) */
-       {"HEADPHONE", NULL, "HPHL PA"},
-       {"HEADPHONE", NULL, "HPHR PA"},
-
-       {"HPHL PA", NULL, "HPHL"},
-       {"HPHR PA", NULL, "HPHR"},
-       {"HPHL", "Switch", "HPHL DAC"},
-       {"HPHR", "Switch", "HPHR DAC"},
-       {"HPHL PA", NULL, "CP"},
-       {"HPHL PA", NULL, "RX_BIAS"},
-       {"HPHR PA", NULL, "CP"},
-       {"HPHR PA", NULL, "RX_BIAS"},
-       {"HPHL DAC", NULL, "RX1 CHAIN"},
-
-       {"SPK_OUT", NULL, "SPK PA"},
-       {"SPK PA", NULL, "SPK_RX_BIAS"},
-       {"SPK PA", NULL, "SPK DAC"},
-       {"SPK DAC", "Switch", "RX3 CHAIN"},
-       {"SPK DAC", NULL, "VDD_SPKDRV"},
-
-       {"RX1 CHAIN", NULL, "RX1 CLK"},
-       {"RX2 CHAIN", NULL, "RX2 CLK"},
-       {"RX3 CHAIN", NULL, "RX3 CLK"},
-       {"RX1 CHAIN", NULL, "RX1 MIX2"},
-       {"RX2 CHAIN", NULL, "RX2 MIX2"},
-       {"RX3 CHAIN", NULL, "RX3 MIX1"},
-
-       {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
-       {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
-       {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
-       {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
-       {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
-       {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
-       {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
-       {"RX1 MIX2", NULL, "RX1 MIX1"},
-       {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
-       {"RX2 MIX2", NULL, "RX2 MIX1"},
-       {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
-
-       {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
-       {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
-       {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
-       {"RX1 MIX1 INP1", "IIR1", "IIR1"},
-       {"RX1 MIX1 INP1", "IIR2", "IIR2"},
-       {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
-       {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
-       {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
-       {"RX1 MIX1 INP2", "IIR1", "IIR1"},
-       {"RX1 MIX1 INP2", "IIR2", "IIR2"},
-       {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
-       {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
-       {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
-
-       {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
-       {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
-       {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
-       {"RX2 MIX1 INP1", "IIR1", "IIR1"},
-       {"RX2 MIX1 INP1", "IIR2", "IIR2"},
-       {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
-       {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
-       {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
-       {"RX2 MIX1 INP2", "IIR1", "IIR1"},
-       {"RX2 MIX1 INP2", "IIR2", "IIR2"},
-
-       {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
-       {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
-       {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
-       {"RX3 MIX1 INP1", "IIR1", "IIR1"},
-       {"RX3 MIX1 INP1", "IIR2", "IIR2"},
-       {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
-       {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
-       {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
-       {"RX3 MIX1 INP2", "IIR1", "IIR1"},
-       {"RX3 MIX1 INP2", "IIR2", "IIR2"},
-
-       {"RX1 MIX2 INP1", "IIR1", "IIR1"},
-       {"RX2 MIX2 INP1", "IIR1", "IIR1"},
-       {"RX1 MIX2 INP1", "IIR2", "IIR2"},
-       {"RX2 MIX2 INP1", "IIR2", "IIR2"},
-
-       /* Decimator Inputs */
-       {"DEC1 MUX", "DMIC1", "DMIC1"},
-       {"DEC1 MUX", "DMIC2", "DMIC2"},
-       {"DEC1 MUX", "ADC1", "ADC1"},
-       {"DEC1 MUX", "ADC2", "ADC2"},
-       {"DEC1 MUX", "ADC3", "ADC3"},
-       {"DEC1 MUX", NULL, "CDC_CONN"},
-
-       {"DEC2 MUX", "DMIC1", "DMIC1"},
-       {"DEC2 MUX", "DMIC2", "DMIC2"},
-       {"DEC2 MUX", "ADC1", "ADC1"},
-       {"DEC2 MUX", "ADC2", "ADC2"},
-       {"DEC2 MUX", "ADC3", "ADC3"},
-       {"DEC2 MUX", NULL, "CDC_CONN"},
-
-       /* ADC Connections */
-       {"ADC2", NULL, "ADC2 MUX"},
-       {"ADC3", NULL, "ADC2 MUX"},
-       {"ADC2 MUX", "INP2", "ADC2_INP2"},
-       {"ADC2 MUX", "INP3", "ADC2_INP3"},
-
-       {"ADC1", NULL, "AMIC1"},
-       {"ADC2_INP2", NULL, "AMIC2"},
-       {"ADC2_INP3", NULL, "AMIC3"},
-
-       /* TODO: Fix this */
-       {"IIR1", NULL, "IIR1 INP1 MUX"},
-       {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
-       {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
-       {"IIR2", NULL, "IIR2 INP1 MUX"},
-       {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
-       {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
-       {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
-       {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
-       {"MIC BIAS External", NULL, "INT_LDO_H"},
-       {"MIC BIAS External2", NULL, "INT_LDO_H"},
-       {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
-       {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
-       {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
-       {"MIC BIAS External2", NULL, "MICBIAS_REGULATOR"},
-};
-
-static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
-       struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01);
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x00);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00);
-               snd_soc_update_bits(codec,
-                       MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00);
-               break;
-       }
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = {
-       /*RX stuff */
-       SND_SOC_DAPM_OUTPUT("EAR"),
-
-       SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM,
-                       0, 0, NULL, 0, msm8x16_wcd_codec_enable_ear_pa,
-                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-                       SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MIXER("EAR_S", SND_SOC_NOPM, 0, 0,
-               ear_pa_switch, ARRAY_SIZE(ear_pa_switch)),
-
-       SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
-       SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
-       SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
-
-       SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
-
-       SND_SOC_DAPM_OUTPUT("HEADPHONE"),
-       SND_SOC_DAPM_PGA_E("HPHL PA", MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN,
-               5, 0, NULL, 0,
-               msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
-               SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, hphl_mux),
-
-       SND_SOC_DAPM_MIXER_E("HPHL DAC",
-               MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
-               0, msm8x16_wcd_hphl_dac_event,
-               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_PGA_E("HPHR PA", MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN,
-               4, 0, NULL, 0,
-               msm8x16_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
-               SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, hphr_mux),
-
-       SND_SOC_DAPM_MIXER_E("HPHR DAC",
-               MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
-               0, msm8x16_wcd_hphr_dac_event,
-               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
-               spkr_switch, ARRAY_SIZE(spkr_switch)),
-
-       /* Speaker */
-       SND_SOC_DAPM_OUTPUT("SPK_OUT"),
-
-       SND_SOC_DAPM_PGA_E("SPK PA", MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL,
-                       6, 0, NULL, 0, msm8x16_wcd_codec_enable_spk_pa,
-                       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-                       SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MIXER_E("RX1 MIX1",
-                       MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL, 0,
-                       msm8x16_wcd_codec_enable_interpolator,
-               SND_SOC_DAPM_PRE_REG|
-                       SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD|
-                       SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MIXER_E("RX2 MIX1",
-                       MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL, 0,
-                       msm8x16_wcd_codec_enable_interpolator,
-               SND_SOC_DAPM_PRE_REG|
-                       SND_SOC_DAPM_POST_PMU |
-                       SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MIXER_E("RX1 MIX2",
-               MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
-               0, msm8x16_wcd_codec_enable_interpolator,
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MIXER_E("RX2 MIX2",
-               MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
-               0, msm8x16_wcd_codec_enable_interpolator,
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MIXER_E("RX3 MIX1",
-               MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
-               0, msm8x16_wcd_codec_enable_interpolator,
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-               0, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-               1, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL,
-               2, 0, msm8x16_wcd_codec_enable_dig_clk, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MIXER_E("RX1 CHAIN", MSM8X16_WCD_A_CDC_RX1_B6_CTL, 0, 0,
-               NULL, 0,
-               msm8x16_wcd_codec_enable_rx_chain,
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MIXER_E("RX2 CHAIN", MSM8X16_WCD_A_CDC_RX2_B6_CTL, 0, 0,
-               NULL, 0,
-               msm8x16_wcd_codec_enable_rx_chain,
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_MIXER_E("RX3 CHAIN", MSM8X16_WCD_A_CDC_RX3_B6_CTL, 0, 0,
-               NULL, 0,
-               msm8x16_wcd_codec_enable_rx_chain,
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-               &rx_mix1_inp1_mux),
-       SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-               &rx_mix1_inp2_mux),
-       SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-               &rx_mix1_inp3_mux),
-
-       SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-               &rx2_mix1_inp1_mux),
-       SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-               &rx2_mix1_inp2_mux),
-       SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-               &rx2_mix1_inp3_mux),
-
-       SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
-               &rx3_mix1_inp1_mux),
-       SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
-               &rx3_mix1_inp2_mux),
-       SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
-               &rx3_mix1_inp3_mux),
-
-       SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-               &rx1_mix2_inp1_mux),
-       SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
-               &rx2_mix2_inp1_mux),
-
-       SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
-               ON_DEMAND_MICBIAS, 0,
-               msm8x16_wcd_codec_enable_on_demand_supply,
-               SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_SUPPLY("CP", MSM8X16_WCD_A_ANALOG_NCP_EN, 0, 0,
-               msm8x16_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_SUPPLY("EAR CP", MSM8X16_WCD_A_ANALOG_NCP_EN, 4, 0,
-               msm8x16_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM,
-               0, 0, msm8x16_wcd_codec_enable_rx_bias,
-               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_SUPPLY("SPK_RX_BIAS", SND_SOC_NOPM, 0, 0,
-               msm8x16_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-       /* TX */
-
-       SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, MSM8X16_WCD_A_CDC_CLK_OTHR_CTL,
-               2, 0, NULL, 0),
-
-       SND_SOC_DAPM_INPUT("AMIC1"),
-       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal1",
-               MSM8X16_WCD_A_ANALOG_MICB_1_EN, 7, 0,
-               msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal2",
-               MSM8X16_WCD_A_ANALOG_MICB_2_EN, 7, 0,
-               msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_SUPPLY("MIC BIAS Internal3",
-               MSM8X16_WCD_A_ANALOG_MICB_1_EN, 7, 0,
-               msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X16_WCD_A_ANALOG_TX_1_EN, 7, 0,
-               msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_ADC_E("ADC2_INP2",
-               NULL, MSM8X16_WCD_A_ANALOG_TX_2_EN, 7, 0,
-               msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_ADC_E("ADC2_INP3",
-               NULL, MSM8X16_WCD_A_ANALOG_TX_3_EN, 7, 0,
-               msm8x16_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-       SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
-               &tx_adc2_mux),
-
-       SND_SOC_DAPM_SUPPLY("MIC BIAS External",
-               MSM8X16_WCD_A_ANALOG_MICB_1_EN, 7, 0,
-               msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_SUPPLY("MIC BIAS External2",
-               MSM8X16_WCD_A_ANALOG_MICB_2_EN, 7, 0,
-               msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-
-       SND_SOC_DAPM_INPUT("AMIC3"),
-
-       SND_SOC_DAPM_MUX_E("DEC1 MUX",
-               MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
-               &dec1_mux, msm8x16_wcd_codec_enable_dec,
-               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MUX_E("DEC2 MUX",
-               MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
-               &dec2_mux, msm8x16_wcd_codec_enable_dec,
-               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux),
-
-       SND_SOC_DAPM_INPUT("AMIC2"),
-
-       SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
-               0, 0),
-       SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
-               0, 0),
-       SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
-               0, 0),
-
-
-       /* Digital Mic Inputs */
-       SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
-               msm8x16_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-       SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
-               msm8x16_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
-               SND_SOC_DAPM_POST_PMD),
-
-       /* Sidetone */
-       SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
-       SND_SOC_DAPM_PGA("IIR1",
-               MSM8X16_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
-
-       SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
-       SND_SOC_DAPM_PGA("IIR2",
-               MSM8X16_WCD_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
-
-       SND_SOC_DAPM_SUPPLY("RX_I2S_CLK",
-               MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL,       4, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("TX_I2S_CLK",
-               MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL, 4, 0,
-               NULL, 0),
-};
-
-static struct snd_soc_codec_driver msm8x16_wcd_codec = {
-       .probe  = msm8x16_wcd_codec_probe,
-       .remove = msm8x16_wcd_codec_remove,
-       .read = msm8x16_wcd_read,
-       .write = msm8x16_wcd_write,
-       .reg_cache_size = MSM8X16_WCD_CACHE_SIZE,
-       .reg_cache_default = msm8x16_wcd_reset_reg_defaults,
-       .reg_word_size = 1,
-       .controls = msm8x16_wcd_snd_controls,
-       .num_controls = ARRAY_SIZE(msm8x16_wcd_snd_controls),
-       .dapm_widgets = msm8x16_wcd_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(msm8x16_wcd_dapm_widgets),
-       .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map),
-};
-
-static int msm8x16_wcd_codec_parse_dt(struct platform_device *pdev,
-                                     struct wcd_chip *chip)
-{
-       struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
-       int ret;
-       u32 res[2];
-
-       ret = of_property_read_u32_array(np, "reg", res, 2);
-       if (ret < 0)
-               return ret;
-
-       chip->analog_base = res[0];
-
-       chip->digital_map = syscon_regmap_lookup_by_phandle(np, "digital");
-       if (IS_ERR(chip->digital_map))
-               return PTR_ERR(chip->digital_map);
-
-       chip->vddio = devm_regulator_get(dev, "vddio");
-       if (IS_ERR(chip->vddio)) {
-               dev_err(dev, "Failed to get vdd supply\n");
-               return PTR_ERR(chip->vddio);
-       }
-
-       chip->vdd_pa = devm_regulator_get(dev, "vdd-pa");
-       if (IS_ERR(chip->vdd_pa)) {
-               dev_err(dev, "Failed to get vdd supply\n");
-               return PTR_ERR(chip->vdd_pa);
-       }
-
-       chip->vdd_mic_bias = devm_regulator_get(dev, "vdd-mic-bias");
-       if (IS_ERR(chip->vdd_mic_bias)) {
-               dev_err(dev, "Failed to get vdd micbias supply\n");
-               return PTR_ERR(chip->vdd_mic_bias);
-       }
-
-       chip->mclk = devm_clk_get(dev, "mclk");
-
-       return 0;
-}
-
-static int wcd_probe(struct platform_device *pdev)
-{
-       struct wcd_chip *chip;
-       struct device *dev = &pdev->dev;
-       int ret;
-
-       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
-       if (!chip)
-               return -ENOMEM;
-
-       chip->analog_map = dev_get_regmap(dev->parent, NULL);
-       if (!chip->analog_map)
-               return -ENXIO;
-
-       ret = msm8x16_wcd_codec_parse_dt(pdev, chip);
-       if (IS_ERR_VALUE(ret))
-               return ret;
-
-       clk_set_rate(chip->mclk, 9600000);
-       clk_prepare_enable(chip->mclk);
-
-       dev_set_drvdata(dev, chip);
-
-       return snd_soc_register_codec(dev, &msm8x16_wcd_codec,
-                                     msm8x16_wcd_codec_dai,
-                                     ARRAY_SIZE(msm8x16_wcd_codec_dai));
-}
-
-static int wcd_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_codec(&pdev->dev);
-
-       return 0;
-}
-
-static const struct of_device_id wcd_match_table[] = {
-       { .compatible = "qcom,apq8016-wcd-codec" },
-       { .compatible = "qcom,msm8x16-wcd-codec" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, wcd_match_table);
-
-static struct platform_driver wcd_driver = {
-       .driver = {
-               .name = "msm8x16-wcd-codec",
-               .of_match_table = wcd_match_table,
-       },
-       .probe  = wcd_probe,
-       .remove = wcd_remove,
-};
-module_platform_driver(wcd_driver);
-
-MODULE_ALIAS("platform:spmi-wcd-codec");
-MODULE_DESCRIPTION("SPMI PMIC WCD codec driver");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/msm8x16-wcd.h b/sound/soc/codecs/msm8x16-wcd.h
deleted file mode 100644 (file)
index ad4c9d0..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef MSM8X16_WCD_H
-#define MSM8X16_WCD_H
-
-#include <linux/types.h>
-
-#define MSM8X16_WCD_NUM_REGISTERS      0x6FF
-#define MSM8X16_WCD_MAX_REGISTER       (MSM8X16_WCD_NUM_REGISTERS-1)
-#define MSM8X16_WCD_CACHE_SIZE         MSM8X16_WCD_NUM_REGISTERS
-#define MSM8X16_WCD_NUM_IRQ_REGS       2
-#define MAX_REGULATOR                          7
-#define MSM8X16_WCD_REG_VAL(reg, val)          {reg, 0, val}
-#define MSM8X16_TOMBAK_LPASS_AUDIO_CORE_DIG_CODEC_CLK_SEL      0xFE03B004
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CMD_RCGR                 0x0181C09C
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CFG_RCGR                 0x0181C0A0
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_M                                0x0181C0A4
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_N                                0x0181C0A8
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_D                                0x0181C0AC
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_CBCR                     0x0181C0B0
-#define MSM8X16_TOMBAK_LPASS_DIGCODEC_AHB_CBCR                 0x0181C0B4
-
-#define MSM8X16_CODEC_NAME "msm8x16_wcd_codec"
-
-#define MSM8X16_WCD_IS_DIGITAL_REG(reg) \
-       (((reg >= 0x200) && (reg <= 0x4FF)) ? 1 : 0)
-#define MSM8X16_WCD_IS_TOMBAK_REG(reg) \
-       (((reg >= 0x000) && (reg <= 0x1FF)) ? 1 : 0)
-/*
- * MCLK activity indicators during suspend and resume call
- */
-#define MCLK_SUS_DIS   1
-#define MCLK_SUS_RSC   2
-#define MCLK_SUS_NO_ACT        3
-
-#define NUM_DECIMATORS 2
-
-extern const u8 msm8x16_wcd_reg_readable[MSM8X16_WCD_CACHE_SIZE];
-extern const u8 msm8x16_wcd_reg_readonly[MSM8X16_WCD_CACHE_SIZE];
-extern u8 msm8x16_wcd_reset_reg_defaults[MSM8X16_WCD_CACHE_SIZE];
-
-enum msm8x16_wcd_pid_current {
-       MSM8X16_WCD_PID_MIC_2P5_UA,
-       MSM8X16_WCD_PID_MIC_5_UA,
-       MSM8X16_WCD_PID_MIC_10_UA,
-       MSM8X16_WCD_PID_MIC_20_UA,
-};
-
-struct msm8x16_wcd_reg_mask_val {
-       u16     reg;
-       u8      mask;
-       u8      val;
-};
-
-enum msm8x16_wcd_mbhc_analog_pwr_cfg {
-       MSM8X16_WCD_ANALOG_PWR_COLLAPSED = 0,
-       MSM8X16_WCD_ANALOG_PWR_ON,
-       MSM8X16_WCD_NUM_ANALOG_PWR_CONFIGS,
-};
-
-/* Number of input and output I2S port */
-enum {
-       MSM8X16_WCD_RX1 = 0,
-       MSM8X16_WCD_RX2,
-       MSM8X16_WCD_RX3,
-       MSM8X16_WCD_RX_MAX,
-};
-
-enum {
-       MSM8X16_WCD_TX1 = 0,
-       MSM8X16_WCD_TX2,
-       MSM8X16_WCD_TX3,
-       MSM8X16_WCD_TX4,
-       MSM8X16_WCD_TX_MAX,
-};
-
-enum {
-       /* INTR_REG 0 - Digital Periph */
-       MSM8X16_WCD_IRQ_SPKR_CNP = 0,
-       MSM8X16_WCD_IRQ_SPKR_CLIP,
-       MSM8X16_WCD_IRQ_SPKR_OCP,
-       MSM8X16_WCD_IRQ_MBHC_INSREM_DET1,
-       MSM8X16_WCD_IRQ_MBHC_RELEASE,
-       MSM8X16_WCD_IRQ_MBHC_PRESS,
-       MSM8X16_WCD_IRQ_MBHC_INSREM_DET,
-       MSM8X16_WCD_IRQ_MBHC_HS_DET,
-       /* INTR_REG 1 - Analog Periph */
-       MSM8X16_WCD_IRQ_EAR_OCP,
-       MSM8X16_WCD_IRQ_HPHR_OCP,
-       MSM8X16_WCD_IRQ_HPHL_OCP,
-       MSM8X16_WCD_IRQ_EAR_CNP,
-       MSM8X16_WCD_IRQ_HPHR_CNP,
-       MSM8X16_WCD_IRQ_HPHL_CNP,
-       MSM8X16_WCD_NUM_IRQS,
-};
-
-enum wcd_notify_event {
-       WCD_EVENT_INVALID,
-       /* events for micbias ON and OFF */
-       WCD_EVENT_PRE_MICBIAS_2_OFF,
-       WCD_EVENT_POST_MICBIAS_2_OFF,
-       WCD_EVENT_PRE_MICBIAS_2_ON,
-       WCD_EVENT_POST_MICBIAS_2_ON,
-       /* events for PA ON and OFF */
-       WCD_EVENT_PRE_HPHL_PA_ON,
-       WCD_EVENT_POST_HPHL_PA_OFF,
-       WCD_EVENT_PRE_HPHR_PA_ON,
-       WCD_EVENT_POST_HPHR_PA_OFF,
-       WCD_EVENT_LAST,
-};
-
-enum {
-       ON_DEMAND_MICBIAS = 0,
-       ON_DEMAND_SUPPLIES_MAX,
-};
-
-/*
- * The delay list is per codec HW specification.
- * Please add delay in the list in the future instead
- * of magic number
- */
-enum {
-       CODEC_DELAY_1_MS = 1000,
-       CODEC_DELAY_1_1_MS  = 1100,
-};
-#if 0
-struct msm8x16_wcd_regulator {
-       const char *name;
-       int min_uv;
-       int max_uv;
-       int optimum_ua;
-       bool ondemand;
-       struct regulator *regulator;
-};
-
-struct msm8916_asoc_mach_data {
-       int codec_type;
-       int ext_pa;
-       int us_euro_gpio;
-       int mclk_freq;
-       int lb_mode;
-       atomic_t mclk_rsc_ref;
-       atomic_t mclk_enabled;
-       struct mutex cdc_mclk_mutex;
-       struct delayed_work disable_mclk_work;
-       struct afe_digital_clk_cfg digital_cdc_clk;
-};
-
-struct msm8x16_wcd_pdata {
-       int irq;
-       int irq_base;
-       int num_irqs;
-       int reset_gpio;
-       void *msm8x16_wcd_ahb_base_vaddr;
-       struct wcd9xxx_micbias_setting micbias;
-       struct msm8x16_wcd_regulator regulator[MAX_REGULATOR];
-       u32 mclk_rate;
-};
-
-enum msm8x16_wcd_micbias_num {
-       MSM8X16_WCD_MICBIAS1 = 0,
-};
-
-struct msm8x16_wcd {
-       struct device *dev;
-       struct mutex io_lock;
-       u8 version;
-
-       int reset_gpio;
-       int (*read_dev)(struct snd_soc_codec *codec,
-                       unsigned short reg);
-       int (*write_dev)(struct snd_soc_codec *codec,
-                        unsigned short reg, u8 val);
-
-       u32 num_of_supplies;
-       struct regulator_bulk_data *supplies;
-
-       u8 idbyte[4];
-
-       int num_irqs;
-       u32 mclk_rate;
-       char __iomem *dig_base;
-};
-
-struct on_demand_supply {
-       struct regulator *supply;
-       atomic_t ref;
-};
-
-struct msm8x16_wcd_priv {
-       struct snd_soc_codec *codec;
-       u16 pmic_rev;
-       u32 adc_count;
-       u32 rx_bias_count;
-       s32 dmic_1_2_clk_cnt;
-       u32 mute_mask;
-       bool mclk_enabled;
-       bool clock_active;
-       bool config_mode_active;
-       bool spk_boost_set;
-       bool ear_pa_boost_set;
-       bool dec_active[NUM_DECIMATORS];
-       struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
-       /* mbhc module */
-       struct wcd_mbhc mbhc;
-       struct blocking_notifier_head notifier;
-
-};
-
-extern int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
-                            bool dapm);
-
-extern int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec,
-                   struct wcd_mbhc_config *mbhc_cfg);
-
-extern void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec);
-
-extern int msm8x16_register_notifier(struct snd_soc_codec *codec,
-                                    struct notifier_block *nblock);
-
-extern int msm8x16_unregister_notifier(struct snd_soc_codec *codec,
-                                    struct notifier_block *nblock);
-#endif
-#endif
-
diff --git a/sound/soc/codecs/msm8x16_wcd_registers.h b/sound/soc/codecs/msm8x16_wcd_registers.h
deleted file mode 100644 (file)
index 03d92c8..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
- /* Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-#ifndef MSM8X16_WCD_REGISTERS_H
-#define MSM8X16_WCD_REGISTERS_H
-
-#define MSM8X16_WCD_A_DIGITAL_REVISION1                        (0x000)
-#define MSM8X16_WCD_A_DIGITAL_REVISION1__POR                           (0x00)
-#define MSM8X16_WCD_A_DIGITAL_REVISION2                        (0x001)
-#define MSM8X16_WCD_A_DIGITAL_REVISION2__POR                           (0x00)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_TYPE                       (0x004)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_TYPE__POR                          (0x23)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE                    (0x005)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_SUBTYPE__POR                       (0x01)
-#define MSM8X16_WCD_A_DIGITAL_INT_RT_STS                       (0x010)
-#define MSM8X16_WCD_A_DIGITAL_INT_RT_STS__POR                          (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_SET_TYPE                     (0x011)
-#define MSM8X16_WCD_A_DIGITAL_INT_SET_TYPE__POR                                (0xFF)
-#define MSM8X16_WCD_A_DIGITAL_INT_POLARITY_HIGH                        (0x012)
-#define MSM8X16_WCD_A_DIGITAL_INT_POLARITY_HIGH__POR                   (0xFF)
-#define MSM8X16_WCD_A_DIGITAL_INT_POLARITY_LOW                 (0x013)
-#define MSM8X16_WCD_A_DIGITAL_INT_POLARITY_LOW__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_LATCHED_CLR                  (0x014)
-#define MSM8X16_WCD_A_DIGITAL_INT_LATCHED_CLR__POR                     (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_EN_SET                       (0x015)
-#define MSM8X16_WCD_A_DIGITAL_INT_EN_SET__POR                          (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_EN_CLR                       (0x016)
-#define MSM8X16_WCD_A_DIGITAL_INT_EN_CLR__POR                          (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_LATCHED_STS                  (0x018)
-#define MSM8X16_WCD_A_DIGITAL_INT_LATCHED_STS__POR                     (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_PENDING_STS                  (0x019)
-#define MSM8X16_WCD_A_DIGITAL_INT_PENDING_STS__POR                     (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_MID_SEL                      (0x01A)
-#define MSM8X16_WCD_A_DIGITAL_INT_MID_SEL__POR                         (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_PRIORITY                     (0x01B)
-#define MSM8X16_WCD_A_DIGITAL_INT_PRIORITY__POR                                (0x00)
-#define MSM8X16_WCD_A_DIGITAL_GPIO_MODE                        (0x040)
-#define MSM8X16_WCD_A_DIGITAL_GPIO_MODE__POR                           (0x00)
-#define MSM8X16_WCD_A_DIGITAL_PIN_CTL_OE                       (0x041)
-#define MSM8X16_WCD_A_DIGITAL_PIN_CTL_OE__POR                          (0x01)
-#define MSM8X16_WCD_A_DIGITAL_PIN_CTL_DATA                     (0x042)
-#define MSM8X16_WCD_A_DIGITAL_PIN_CTL_DATA__POR                                (0x00)
-#define MSM8X16_WCD_A_DIGITAL_PIN_STATUS                       (0x043)
-#define MSM8X16_WCD_A_DIGITAL_PIN_STATUS__POR                          (0x00)
-#define MSM8X16_WCD_A_DIGITAL_HDRIVE_CTL                       (0x044)
-#define MSM8X16_WCD_A_DIGITAL_HDRIVE_CTL__POR                          (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RST_CTL                      (0x046)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RST_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_TOP_CLK_CTL                  (0x048)
-#define MSM8X16_WCD_A_DIGITAL_CDC_TOP_CLK_CTL__POR                     (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL                  (0x049)
-#define MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL__POR                     (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL                  (0x04A)
-#define MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL__POR                     (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX1_CTL                 (0x050)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX1_CTL__POR                    (0x02)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX2_CTL                 (0x051)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_TX2_CTL__POR                    (0x02)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_HPHR_DAC_CTL                    (0x052)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_HPHR_DAC_CTL__POR               (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX1_CTL                 (0x053)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX1_CTL__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX2_CTL                 (0x054)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX2_CTL__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX3_CTL                 (0x055)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX3_CTL__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX_LB_CTL                       (0x056)
-#define MSM8X16_WCD_A_DIGITAL_CDC_CONN_RX_LB_CTL__POR                  (0x00)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL1                      (0x058)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL1__POR                         (0x7C)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL2                      (0x059)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL2__POR                         (0x7C)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL3                      (0x05A)
-#define MSM8X16_WCD_A_DIGITAL_CDC_RX_CTL3__POR                         (0x7C)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA0                 (0x05B)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA0__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA1                 (0x05C)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA1__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA2                 (0x05D)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA2__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA3                 (0x05E)
-#define MSM8X16_WCD_A_DIGITAL_DEM_BYPASS_DATA3__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_DIG_DEBUG_CTL                    (0x068)
-#define MSM8X16_WCD_A_DIGITAL_DIG_DEBUG_CTL__POR                       (0x00)
-#define MSM8X16_WCD_A_DIGITAL_DIG_DEBUG_EN                     (0x069)
-#define MSM8X16_WCD_A_DIGITAL_DIG_DEBUG_EN__POR                                (0x00)
-#define MSM8X16_WCD_A_DIGITAL_SPARE_0                          (0x070)
-#define MSM8X16_WCD_A_DIGITAL_SPARE_0__POR                             (0x00)
-#define MSM8X16_WCD_A_DIGITAL_SPARE_1                          (0x071)
-#define MSM8X16_WCD_A_DIGITAL_SPARE_1__POR                             (0x00)
-#define MSM8X16_WCD_A_DIGITAL_SPARE_2                          (0x072)
-#define MSM8X16_WCD_A_DIGITAL_SPARE_2__POR                             (0x00)
-#define MSM8X16_WCD_A_DIGITAL_SEC_ACCESS                       (0x0D0)
-#define MSM8X16_WCD_A_DIGITAL_SEC_ACCESS__POR                          (0x00)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL1                 (0x0D8)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL1__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL2                 (0x0D9)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL2__POR                    (0x01)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL3                 (0x0DA)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL3__POR                    (0x05)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL4                 (0x0DB)
-#define MSM8X16_WCD_A_DIGITAL_PERPH_RESET_CTL4__POR                    (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_TEST1                                (0x0E0)
-#define MSM8X16_WCD_A_DIGITAL_INT_TEST1__POR                           (0x00)
-#define MSM8X16_WCD_A_DIGITAL_INT_TEST_VAL                     (0x0E1)
-#define MSM8X16_WCD_A_DIGITAL_INT_TEST_VAL__POR                                (0x00)
-#define MSM8X16_WCD_A_DIGITAL_TRIM_NUM                         (0x0F0)
-#define MSM8X16_WCD_A_DIGITAL_TRIM_NUM__POR                            (0x00)
-#define MSM8X16_WCD_A_DIGITAL_TRIM_CTRL                                (0x0F1)
-#define MSM8X16_WCD_A_DIGITAL_TRIM_CTRL__POR                           (0x00)
-
-#define MSM8X16_WCD_A_ANALOG_REVISION1                 (0x100)
-#define MSM8X16_WCD_A_ANALOG_REVISION1__POR                            (0x00)
-#define MSM8X16_WCD_A_ANALOG_REVISION2                 (0x101)
-#define MSM8X16_WCD_A_ANALOG_REVISION2__POR                            (0x00)
-#define MSM8X16_WCD_A_ANALOG_REVISION3                 (0x102)
-#define MSM8X16_WCD_A_ANALOG_REVISION3__POR                            (0x00)
-#define MSM8X16_WCD_A_ANALOG_REVISION4                 (0x103)
-#define MSM8X16_WCD_A_ANALOG_REVISION4__POR                            (0x00)
-#define MSM8X16_WCD_A_ANALOG_PERPH_TYPE                        (0x104)
-#define MSM8X16_WCD_A_ANALOG_PERPH_TYPE__POR                   (0x23)
-#define MSM8X16_WCD_A_ANALOG_PERPH_SUBTYPE             (0x105)
-#define MSM8X16_WCD_A_ANALOG_PERPH_SUBTYPE__POR                        (0x09)
-#define MSM8X16_WCD_A_ANALOG_INT_RT_STS                        (0x110)
-#define MSM8X16_WCD_A_ANALOG_INT_RT_STS__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_SET_TYPE              (0x111)
-#define MSM8X16_WCD_A_ANALOG_INT_SET_TYPE__POR                 (0x3F)
-#define MSM8X16_WCD_A_ANALOG_INT_POLARITY_HIGH         (0x112)
-#define MSM8X16_WCD_A_ANALOG_INT_POLARITY_HIGH__POR            (0x3F)
-#define MSM8X16_WCD_A_ANALOG_INT_POLARITY_LOW          (0x113)
-#define MSM8X16_WCD_A_ANALOG_INT_POLARITY_LOW__POR             (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_LATCHED_CLR           (0x114)
-#define MSM8X16_WCD_A_ANALOG_INT_LATCHED_CLR__POR              (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_EN_SET                        (0x115)
-#define MSM8X16_WCD_A_ANALOG_INT_EN_SET__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_EN_CLR                        (0x116)
-#define MSM8X16_WCD_A_ANALOG_INT_EN_CLR__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_LATCHED_STS           (0x118)
-#define MSM8X16_WCD_A_ANALOG_INT_LATCHED_STS__POR              (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_PENDING_STS           (0x119)
-#define MSM8X16_WCD_A_ANALOG_INT_PENDING_STS__POR              (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_MID_SEL               (0x11A)
-#define MSM8X16_WCD_A_ANALOG_INT_MID_SEL__POR                  (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_PRIORITY              (0x11B)
-#define MSM8X16_WCD_A_ANALOG_INT_PRIORITY__POR                 (0x00)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_EN                 (0x140)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_EN__POR                    (0x00)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_VAL                        (0x141)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_VAL__POR                   (0x20)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_CTL                        (0x142)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_CTL__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS                  (0x143)
-#define MSM8X16_WCD_A_ANALOG_MICB_1_INT_RBIAS__POR             (0x49)
-#define MSM8X16_WCD_A_ANALOG_MICB_2_EN                 (0x144)
-#define MSM8X16_WCD_A_ANALOG_MICB_2_EN__POR                    (0x20)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL_2                        (0x145)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL_2__POR           (0x00)
-#define MSM8X16_WCD_A_ANALOG_MASTER_BIAS_CTL                   (0x146)
-#define MSM8X16_WCD_A_ANALOG_MASTER_BIAS_CTL__POR              (0x00)
-#define MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1            (0x147)
-#define MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1__POR               (0x35)
-#define MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2            (0x150)
-#define MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2__POR               (0x08)
-#define MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL              (0x151)
-#define MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL__POR                 (0x00)
-#define MSM8X16_WCD_A_ANALOG_MBHC_DBNC_TIMER           (0x152)
-#define MSM8X16_WCD_A_ANALOG_MBHC_DBNC_TIMER__POR              (0x98)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN0_ZDETL_CTL       (0x153)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN0_ZDETL_CTL__POR          (0x00)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN1_ZDETM_CTL       (0x154)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN1_ZDETM_CTL__POR          (0x20)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN2_ZDETH_CTL       (0x155)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN2_ZDETH_CTL__POR          (0x40)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN3_CTL             (0x156)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN3_CTL__POR                        (0x61)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN4_CTL             (0x157)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN4_CTL__POR                        (0x80)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN_RESULT           (0x158)
-#define MSM8X16_WCD_A_ANALOG_MBHC_BTN_RESULT__POR              (0x00)
-#define MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT    (0x159)
-#define MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT__POR       (0x00)
-#define MSM8X16_WCD_A_ANALOG_TX_1_EN                   (0x160)
-#define MSM8X16_WCD_A_ANALOG_TX_1_EN__POR                      (0x03)
-#define MSM8X16_WCD_A_ANALOG_TX_2_EN                   (0x161)
-#define MSM8X16_WCD_A_ANALOG_TX_2_EN__POR                      (0x03)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_1         (0x162)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_1__POR            (0xBF)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_2         (0x163)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_TEST_CTL_2__POR            (0x8C)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL          (0x164)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_ATEST_CTL__POR             (0x00)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_OPAMP_BIAS         (0x165)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_OPAMP_BIAS__POR            (0x6B)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_TXFE_CLKDIV                (0x166)
-#define MSM8X16_WCD_A_ANALOG_TX_1_2_TXFE_CLKDIV__POR           (0x51)
-#define MSM8X16_WCD_A_ANALOG_TX_3_EN                   (0x167)
-#define MSM8X16_WCD_A_ANALOG_TX_3_EN__POR                      (0x02)
-#define MSM8X16_WCD_A_ANALOG_NCP_EN                    (0x180)
-#define MSM8X16_WCD_A_ANALOG_NCP_EN__POR                       (0x26)
-#define MSM8X16_WCD_A_ANALOG_NCP_CLK                   (0x181)
-#define MSM8X16_WCD_A_ANALOG_NCP_CLK__POR                      (0x23)
-#define MSM8X16_WCD_A_ANALOG_NCP_DEGLITCH              (0x182)
-#define MSM8X16_WCD_A_ANALOG_NCP_DEGLITCH__POR                 (0x5B)
-#define MSM8X16_WCD_A_ANALOG_NCP_FBCTRL                        (0x183)
-#define MSM8X16_WCD_A_ANALOG_NCP_FBCTRL__POR                   (0x08)
-#define MSM8X16_WCD_A_ANALOG_NCP_BIAS                  (0x184)
-#define MSM8X16_WCD_A_ANALOG_NCP_BIAS__POR                     (0x29)
-#define MSM8X16_WCD_A_ANALOG_NCP_VCTRL                 (0x185)
-#define MSM8X16_WCD_A_ANALOG_NCP_VCTRL__POR                    (0x24)
-#define MSM8X16_WCD_A_ANALOG_NCP_TEST                  (0x186)
-#define MSM8X16_WCD_A_ANALOG_NCP_TEST__POR                     (0x00)
-#define MSM8X16_WCD_A_ANALOG_NCP_CLIM_ADDR             (0x187)
-#define MSM8X16_WCD_A_ANALOG_NCP_CLIM_ADDR__POR                        (0xD5)
-#define MSM8X16_WCD_A_ANALOG_RX_CLOCK_DIVIDER          (0x190)
-#define MSM8X16_WCD_A_ANALOG_RX_CLOCK_DIVIDER__POR             (0xE8)
-#define MSM8X16_WCD_A_ANALOG_RX_COM_OCP_CTL            (0x191)
-#define MSM8X16_WCD_A_ANALOG_RX_COM_OCP_CTL__POR               (0xCF)
-#define MSM8X16_WCD_A_ANALOG_RX_COM_OCP_COUNT          (0x192)
-#define MSM8X16_WCD_A_ANALOG_RX_COM_OCP_COUNT__POR             (0x6E)
-#define MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC           (0x193)
-#define MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC__POR              (0x10)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_PA            (0x194)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_PA__POR               (0x5A)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_LDO_OCP       (0x195)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_LDO_OCP__POR          (0x69)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_CNP           (0x196)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_BIAS_CNP__POR              (0x29)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN             (0x197)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN__POR                        (0x80)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_CTL         (0x198)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_CTL__POR            (0xDA)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME                (0x199)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_WG_TIME__POR           (0x16)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_L_TEST             (0x19A)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_L_TEST__POR                        (0x00)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL       (0x19B)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL__POR          (0x20)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_R_TEST             (0x19C)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_R_TEST__POR                        (0x00)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL       (0x19D)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL__POR          (0x20)
-#define MSM8X16_WCD_A_ANALOG_RX_EAR_CTL                        (0x19E)
-#define MSM8X16_WCD_A_ANALOG_RX_EAR_CTL___POR                  (0x12)
-#define MSM8X16_WCD_A_ANALOG_RX_ATEST                  (0x19F)
-#define MSM8X16_WCD_A_ANALOG_RX_ATEST__POR                     (0x00)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_STATUS             (0x1A0)
-#define MSM8X16_WCD_A_ANALOG_RX_HPH_STATUS__POR                        (0x0C)
-#define MSM8X16_WCD_A_ANALOG_RX_EAR_STATUS             (0x1A1)
-#define MSM8X16_WCD_A_ANALOG_RX_EAR_STATUS__POR                        (0x00)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL              (0x1B0)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DAC_CTL__POR                 (0x83)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_CLIP_DET         (0x1B1)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_CLIP_DET__POR            (0x91)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL              (0x1B2)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_CTL__POR                 (0x29)
-#define MSM8X16_WCD_A_ANALOG_SPKR_ANA_BIAS_SET         (0x1B3)
-#define MSM8X16_WCD_A_ANALOG_SPKR_ANA_BIAS_SET__POR            (0x4D)
-#define MSM8X16_WCD_A_ANALOG_SPKR_OCP_CTL              (0x1B4)
-#define MSM8X16_WCD_A_ANALOG_SPKR_OCP_CTL__POR                 (0xE1)
-#define MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL           (0x1B5)
-#define MSM8X16_WCD_A_ANALOG_SPKR_PWRSTG_CTL__POR              (0x1E)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_MISC             (0x1B6)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_MISC__POR                        (0xCB)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_DBG              (0x1B7)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_DBG__POR                 (0x00)
-#define MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT             (0x1C0)
-#define MSM8X16_WCD_A_ANALOG_CURRENT_LIMIT__POR                        (0x02)
-#define MSM8X16_WCD_A_ANALOG_OUTPUT_VOLTAGE            (0x1C1)
-#define MSM8X16_WCD_A_ANALOG_OUTPUT_VOLTAGE__POR               (0x14)
-#define MSM8X16_WCD_A_ANALOG_BYPASS_MODE               (0x1C2)
-#define MSM8X16_WCD_A_ANALOG_BYPASS_MODE__POR                  (0x00)
-#define MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL              (0x1C3)
-#define MSM8X16_WCD_A_ANALOG_BOOST_EN_CTL__POR                 (0x1F)
-#define MSM8X16_WCD_A_ANALOG_SLOPE_COMP_IP_ZERO                (0x1C4)
-#define MSM8X16_WCD_A_ANALOG_SLOPE_COMP_IP_ZERO__POR           (0x8C)
-#define MSM8X16_WCD_A_ANALOG_RDSON_MAX_DUTY_CYCLE      (0x1C5)
-#define MSM8X16_WCD_A_ANALOG_RDSON_MAX_DUTY_CYCLE__POR         (0xC0)
-#define MSM8X16_WCD_A_ANALOG_BOOST_TEST1_1             (0x1C6)
-#define MSM8X16_WCD_A_ANALOG_BOOST_TEST1_1__POR                        (0x00)
-#define MSM8X16_WCD_A_ANALOG_BOOST_TEST_2              (0x1C7)
-#define MSM8X16_WCD_A_ANALOG_BOOST_TEST_2__POR                 (0x00)
-#define MSM8X16_WCD_A_ANALOG_SPKR_SAR_STATUS           (0x1C8)
-#define MSM8X16_WCD_A_ANALOG_SPKR_SAR_STATUS__POR              (0x00)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_STATUS           (0x1C9)
-#define MSM8X16_WCD_A_ANALOG_SPKR_DRV_STATUS__POR              (0x00)
-#define MSM8X16_WCD_A_ANALOG_PBUS_ADD_CSR              (0x1CE)
-#define MSM8X16_WCD_A_ANALOG_PBUS_ADD_CSR__POR                 (0x00)
-#define MSM8X16_WCD_A_ANALOG_PBUS_ADD_SEL              (0x1CF)
-#define MSM8X16_WCD_A_ANALOG_PBUS_ADD_SEL__POR                 (0x00)
-#define MSM8X16_WCD_A_ANALOG_SEC_ACCESS                        (0x1D0)
-#define MSM8X16_WCD_A_ANALOG_SEC_ACCESS__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL1          (0x1D8)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL1__POR             (0x00)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL2          (0x1D9)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL2__POR             (0x01)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL3          (0x1DA)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL3__POR             (0x05)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL4          (0x1DB)
-#define MSM8X16_WCD_A_ANALOG_PERPH_RESET_CTL4__POR             (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_TEST1                 (0x1E0)
-#define MSM8X16_WCD_A_ANALOG_INT_TEST1__POR                    (0x00)
-#define MSM8X16_WCD_A_ANALOG_INT_TEST_VAL              (0x1E1)
-#define MSM8X16_WCD_A_ANALOG_INT_TEST_VAL__POR                 (0x00)
-#define MSM8X16_WCD_A_ANALOG_TRIM_NUM                  (0x1F0)
-#define MSM8X16_WCD_A_ANALOG_TRIM_NUM__POR                     (0x04)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL1                        (0x1F1)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL1__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL2                        (0x1F2)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL2__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL3                        (0x1F3)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL3__POR                   (0x00)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL4                        (0x1F4)
-#define MSM8X16_WCD_A_ANALOG_TRIM_CTRL4__POR                   (0x00)
-
-/* Digital part */
-#define MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL                     (0x200)
-#define MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_TX_RESET_B1_CTL                  (0x204)
-#define MSM8X16_WCD_A_CDC_CLK_TX_RESET_B1_CTL__POR                     (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_DMIC_B1_CTL                      (0x208)
-#define MSM8X16_WCD_A_CDC_CLK_DMIC_B1_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL                       (0x20C)
-#define MSM8X16_WCD_A_CDC_CLK_RX_I2S_CTL__POR                          (0x13)
-#define MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL                       (0x210)
-#define MSM8X16_WCD_A_CDC_CLK_TX_I2S_CTL__POR                          (0x13)
-#define MSM8X16_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL                        (0x214)
-#define MSM8X16_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL__POR                   (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL                 (0x218)
-#define MSM8X16_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR                    (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_OTHR_CTL                 (0x21C)
-#define MSM8X16_WCD_A_CDC_CLK_OTHR_CTL__POR                            (0x04)
-#define MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL                        (0x220)
-#define MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL__POR                           (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_MCLK_CTL                 (0x224)
-#define MSM8X16_WCD_A_CDC_CLK_MCLK_CTL__POR                            (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_PDM_CTL                  (0x228)
-#define MSM8X16_WCD_A_CDC_CLK_PDM_CTL__POR                             (0x00)
-#define MSM8X16_WCD_A_CDC_CLK_SD_CTL                   (0x22C)
-#define MSM8X16_WCD_A_CDC_CLK_SD_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX1_B1_CTL                   (0x240)
-#define MSM8X16_WCD_A_CDC_RX1_B1_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX2_B1_CTL                   (0x260)
-#define MSM8X16_WCD_A_CDC_RX2_B1_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX3_B1_CTL                   (0x280)
-#define MSM8X16_WCD_A_CDC_RX3_B1_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX1_B2_CTL                   (0x244)
-#define MSM8X16_WCD_A_CDC_RX1_B2_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX2_B2_CTL                   (0x264)
-#define MSM8X16_WCD_A_CDC_RX2_B2_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX3_B2_CTL                   (0x284)
-#define MSM8X16_WCD_A_CDC_RX3_B2_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX1_B3_CTL                   (0x248)
-#define MSM8X16_WCD_A_CDC_RX1_B3_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX2_B3_CTL                   (0x268)
-#define MSM8X16_WCD_A_CDC_RX2_B3_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX3_B3_CTL                   (0x288)
-#define MSM8X16_WCD_A_CDC_RX3_B3_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX1_B4_CTL                   (0x24C)
-#define MSM8X16_WCD_A_CDC_RX1_B4_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX2_B4_CTL                   (0x26C)
-#define MSM8X16_WCD_A_CDC_RX2_B4_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX3_B4_CTL                   (0x28C)
-#define MSM8X16_WCD_A_CDC_RX3_B4_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX1_B5_CTL                   (0x250)
-#define MSM8X16_WCD_A_CDC_RX1_B5_CTL__POR                              (0x68)
-#define MSM8X16_WCD_A_CDC_RX2_B5_CTL                   (0x270)
-#define MSM8X16_WCD_A_CDC_RX2_B5_CTL__POR                              (0x68)
-#define MSM8X16_WCD_A_CDC_RX3_B5_CTL                   (0x290)
-#define MSM8X16_WCD_A_CDC_RX3_B5_CTL__POR                              (0x68)
-#define MSM8X16_WCD_A_CDC_RX1_B6_CTL                   (0x254)
-#define MSM8X16_WCD_A_CDC_RX1_B6_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX2_B6_CTL                   (0x274)
-#define MSM8X16_WCD_A_CDC_RX2_B6_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX3_B6_CTL                   (0x294)
-#define MSM8X16_WCD_A_CDC_RX3_B6_CTL__POR                              (0x00)
-#define MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B1_CTL                   (0x258)
-#define MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B1_CTL__POR                      (0x00)
-#define MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B1_CTL                   (0x278)
-#define MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B1_CTL__POR                      (0x00)
-#define MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B1_CTL                   (0x298)
-#define MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B1_CTL__POR                      (0x00)
-#define MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL                   (0x25C)
-#define MSM8X16_WCD_A_CDC_RX1_VOL_CTL_B2_CTL__POR                      (0x00)
-#define MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL                   (0x27C)
-#define MSM8X16_WCD_A_CDC_RX2_VOL_CTL_B2_CTL__POR                      (0x00)
-#define MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B2_CTL                   (0x29C)
-#define MSM8X16_WCD_A_CDC_RX3_VOL_CTL_B2_CTL__POR                      (0x00)
-#define MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE                      (0x2A0)
-#define MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_TOP_CTL                              (0x2A4)
-#define MSM8X16_WCD_A_CDC_TOP_CTL__POR                                 (0x01)
-#define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL                     (0x2E0)
-#define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL                     (0x2E4)
-#define MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_DEBUG_B1_CTL_CFG                     (0x2E8)
-#define MSM8X16_WCD_A_CDC_DEBUG_B1_CTL__POR                            (0x00)
-#define MSM8X16_WCD_A_CDC_DEBUG_B2_CTL_CFG                     (0x2EC)
-#define MSM8X16_WCD_A_CDC_DEBUG_B2_CTL__POR                            (0x00)
-#define MSM8X16_WCD_A_CDC_DEBUG_B3_CTL_CFG                     (0x2F0)
-#define MSM8X16_WCD_A_CDC_DEBUG_B3_CTL__POR                            (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B1_CTL                     (0x300)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B1_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B1_CTL                     (0x340)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B1_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B2_CTL                     (0x304)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B2_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B2_CTL                     (0x344)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B2_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B3_CTL                     (0x308)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B3_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B3_CTL                     (0x348)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B3_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B4_CTL                     (0x30C)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B4_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B4_CTL                     (0x34C)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B4_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B5_CTL                     (0x310)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B5_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B5_CTL                     (0x350)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B5_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B6_CTL                     (0x314)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B6_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B6_CTL                     (0x354)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B6_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B7_CTL                     (0x318)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B7_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B7_CTL                     (0x358)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B7_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B8_CTL                     (0x31C)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_B8_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B8_CTL                     (0x35C)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_B8_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_CTL                     (0x320)
-#define MSM8X16_WCD_A_CDC_IIR1_CTL__POR                                (0x40)
-#define MSM8X16_WCD_A_CDC_IIR2_CTL                     (0x360)
-#define MSM8X16_WCD_A_CDC_IIR2_CTL__POR                                (0x40)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_TIMER_CTL                  (0x324)
-#define MSM8X16_WCD_A_CDC_IIR1_GAIN_TIMER_CTL__POR                     (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_TIMER_CTL                  (0x364)
-#define MSM8X16_WCD_A_CDC_IIR2_GAIN_TIMER_CTL__POR                     (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_COEF_B1_CTL                     (0x328)
-#define MSM8X16_WCD_A_CDC_IIR1_COEF_B1_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_COEF_B1_CTL                     (0x368)
-#define MSM8X16_WCD_A_CDC_IIR2_COEF_B1_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR1_COEF_B2_CTL                     (0x32C)
-#define MSM8X16_WCD_A_CDC_IIR1_COEF_B2_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_IIR2_COEF_B2_CTL                     (0x36C)
-#define MSM8X16_WCD_A_CDC_IIR2_COEF_B2_CTL__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL                      (0x380)
-#define MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX1_B2_CTL                      (0x384)
-#define MSM8X16_WCD_A_CDC_CONN_RX1_B2_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX1_B3_CTL                      (0x388)
-#define MSM8X16_WCD_A_CDC_CONN_RX1_B3_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL                      (0x38C)
-#define MSM8X16_WCD_A_CDC_CONN_RX2_B1_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX2_B2_CTL                      (0x390)
-#define MSM8X16_WCD_A_CDC_CONN_RX2_B2_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX2_B3_CTL                      (0x394)
-#define MSM8X16_WCD_A_CDC_CONN_RX2_B3_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL                      (0x398)
-#define MSM8X16_WCD_A_CDC_CONN_RX3_B1_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_RX3_B2_CTL                      (0x39C)
-#define MSM8X16_WCD_A_CDC_CONN_RX3_B2_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_TX_B1_CTL                       (0x3A0)
-#define MSM8X16_WCD_A_CDC_CONN_TX_B1_CTL__POR                          (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B1_CTL                      (0x3A8)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B1_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B2_CTL                      (0x3AC)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B2_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B3_CTL                      (0x3B0)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B3_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B4_CTL                      (0x3B4)
-#define MSM8X16_WCD_A_CDC_CONN_EQ1_B4_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B1_CTL                      (0x3B8)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B1_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B2_CTL                      (0x3BC)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B2_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B3_CTL                      (0x3C0)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B3_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B4_CTL                      (0x3C4)
-#define MSM8X16_WCD_A_CDC_CONN_EQ2_B4_CTL__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_CONN_TX_I2S_SD1_CTL                  (0x3C8)
-#define MSM8X16_WCD_A_CDC_CONN_TX_I2S_SD1_CTL__POR                     (0x00)
-#define MSM8X16_WCD_A_CDC_TX1_VOL_CTL_TIMER                    (0x480)
-#define MSM8X16_WCD_A_CDC_TX1_VOL_CTL_TIMER__POR                       (0x00)
-#define MSM8X16_WCD_A_CDC_TX2_VOL_CTL_TIMER                    (0x4A0)
-#define MSM8X16_WCD_A_CDC_TX2_VOL_CTL_TIMER__POR                       (0x00)
-#define MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN                     (0x484)
-#define MSM8X16_WCD_A_CDC_TX1_VOL_CTL_GAIN__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_TX2_VOL_CTL_GAIN                     (0x4A4)
-#define MSM8X16_WCD_A_CDC_TX2_VOL_CTL_GAIN__POR                                (0x00)
-#define MSM8X16_WCD_A_CDC_TX1_VOL_CTL_CFG                      (0x488)
-#define MSM8X16_WCD_A_CDC_TX1_VOL_CTL_CFG__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_TX2_VOL_CTL_CFG                      (0x4A8)
-#define MSM8X16_WCD_A_CDC_TX2_VOL_CTL_CFG__POR                         (0x00)
-#define MSM8X16_WCD_A_CDC_TX1_MUX_CTL                  (0x48C)
-#define MSM8X16_WCD_A_CDC_TX1_MUX_CTL__POR                             (0x00)
-#define MSM8X16_WCD_A_CDC_TX2_MUX_CTL                  (0x4AC)
-#define MSM8X16_WCD_A_CDC_TX2_MUX_CTL__POR                             (0x00)
-#define MSM8X16_WCD_A_CDC_TX1_CLK_FS_CTL                       (0x490)
-#define MSM8X16_WCD_A_CDC_TX1_CLK_FS_CTL__POR                          (0x03)
-#define MSM8X16_WCD_A_CDC_TX2_CLK_FS_CTL                       (0x4B0)
-#define MSM8X16_WCD_A_CDC_TX2_CLK_FS_CTL__POR                          (0x03)
-#define MSM8X16_WCD_A_CDC_TX1_DMIC_CTL                 (0x494)
-#define MSM8X16_WCD_A_CDC_TX1_DMIC_CTL__POR                            (0x00)
-#define MSM8X16_WCD_A_CDC_TX2_DMIC_CTL                 (0x4B4)
-#define MSM8X16_WCD_A_CDC_TX2_DMIC_CTL__POR                            (0x00)
-#endif
index cca94c69554f73a6789bf335ef11ee5b456b83ff..db115ce34541ffaa40032f7286d47405769975db 100644 (file)
@@ -64,25 +64,11 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
                        return NULL;
                }
                pr_info("apr_tal:Wakeup done\n");
-               apr_svc_ch[dl][dest][svc].dest_state = 0;
-       }
-
-       rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
-               (apr_svc_ch[dl][dest][svc].ch->state == SMD_CHANNEL_OPENED), 5 * HZ);
-       if (rc == 0) {
-               pr_err("apr_tal:TIMEOUT for OPEN event\n");
-               apr_tal_close(&apr_svc_ch[dl][dest][svc]);
-               return NULL;
-       }
-       if (!apr_svc_ch[dl][dest][svc].dest_state) {
-               apr_svc_ch[dl][dest][svc].dest_state = 1;
-               pr_info("apr_tal:Waiting for apr svc init\n");
-               msleep(200);
-               pr_info("apr_tal:apr svc init done\n");
        }
        apr_svc_ch[dl][dest][svc].func = func;
        apr_svc_ch[dl][dest][svc].priv = priv;
 
+       pr_info("apr_tal:apr svc init done\n");
 
        return &apr_svc_ch[dl][dest][svc];
 }
@@ -99,13 +85,13 @@ int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
 }
 
 
-static int qcom_smd_q6_callback(struct qcom_smd_device *sdev,
+static int qcom_smd_q6_callback(struct qcom_smd_channel *channel,
                                 const void *data,
                                 size_t count)
 {
-       struct apr_svc_ch_dev *apr_ch = dev_get_drvdata(&sdev->dev);
+       struct apr_svc_ch_dev *apr_ch = qcom_smd_get_drvdata(channel);
 
-       memcpy_fromio(apr_ch->data, data, count);
+       memcpy(apr_ch->data, data, count);
 
        if (apr_ch->func)
                apr_ch->func(apr_ch->data, count, apr_ch->priv);
@@ -115,22 +101,25 @@ static int qcom_smd_q6_callback(struct qcom_smd_device *sdev,
 
 static int qcom_smd_q6_probe(struct qcom_smd_device *sdev)
 {
-       int dest = APR_DEST_QDSP6;
-       int clnt = APR_CLIENT_AUDIO;
-
-       apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO].ch = sdev->channel;
+       struct apr_svc_ch_dev *apr = &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO];
 
        pr_info("apr_tal:Q6 Is Up\n");
-       apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
-       wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
 
-       dev_set_drvdata(&sdev->dev, &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO]);
+       qcom_smd_set_drvdata(sdev->channel, apr);
+
+       apr->ch = sdev->channel;
+       apr->dest_state = 1;
+       wake_up(&apr->dest);
 
        return 0;
 }
 
 static void qcom_smd_q6_remove(struct qcom_smd_device *sdev)
 {
+       struct apr_svc_ch_dev *apr = &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO];
+
+       apr->ch = NULL;
+       apr->dest_state = 0;
 }