diff options
119 files changed, 16943 insertions, 2991 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt new file mode 100644 index 000000000000..1c7c2c5ea99f --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt @@ -0,0 +1,53 @@ +FocalTech touch controller + +The focaltech controller is connected to host processor +via i2c. The controller generates interrupts when the +user touches the panel. The host controller is expected +to read the touch coordinates over i2c and pass the coordinates +to the rest of the system. + +Required properties: + + - compatible : should be "focaltech,5x06". + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - vdd-supply : Power supply needed to power up the device. + - vcc_i2c-supply : Power source required to power up i2c bus. + - focaltech,family-id : family identification of the controller. + - focaltech,irq-gpio : irq gpio which is to provide interrupts to host, + same as "interrupts" node. It will also + contain active low or active high information. + - focaltech,reset-gpio : reset gpio to control the reset of chip. + - focaltech,display-coords : display coordinates in pixels. It is a four + tuple consisting of min x, min y, max x and + max y values. + +Optional properties: + + - focaltech,panel-coords : panel coordinates for the chip in pixels. + It is a four tuple consisting of min x, + min y, max x and max y values. + - focaltech,i2c-pull-up : to specify pull up is required. + - focaltech,no-force-update : to specify force update is allowed. + - focaltech,button-map : button map of key codes. The number + of key codes depend on panel. + +Example: + i2c@f9924000 { + ft5x06_ts@38 { + compatible = "focaltech,5x06"; + reg = <0x38>; + interrupt-parent = <&msmgpio>; + interrupts = <61 0x2>; + vdd-supply = <&pm8941_l22>; + vcc_i2c-supply = <&pm8941_s3>; + focaltech,reset-gpio = <&msmgpio 60 0x00>; + focaltech,irq-gpio = <&msmgpio 61 0x00>; + focaltech,panel-coords = <0 0 480 800>; + focaltech,display-coords = <0 0 480 800>; + focaltech,button-map= <158 102 139 217>; + focaltech,family-id = <0x0a>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/msg21xx-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/msg21xx-ts.txt new file mode 100644 index 000000000000..26f01ca8577f --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/msg21xx-ts.txt @@ -0,0 +1,60 @@ +Mstar touch controller + +The mstar controller is connected to host processor +via i2c. The controller generates interrupts when the +user touches the panel. The host controller is expected +to read the touch coordinates over i2c and pass the coordinates +to the rest of the system. + +Required properties: + + - compatible : should be "mstar,msg21xx". + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - vdd-supply : Power supply needed to power up the device. + - vcc_i2c-supply : Power source required to power up i2c bus. + - mstar,irq-gpio : irq gpio which is to provide interrupts to host, + same as "interrupts" node. It will also + contain active low or active high information. + - mstar,reset-gpio : reset gpio to control the reset of chip. + - mstar,display-coords : display coords in pixels. It is a four + tuple consisting of min x, min y, max x and + max y values. + - pinctrl-names : This should be defined if a target uses pinctrl framework. + See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt. + Specify the names of the configs that pinctrl can install in driver. + Following are the pinctrl configs that can be installed: + "pmx_ts_active" : Active configuration of pins, this should specify active + config defined in pin groups of interrupt and reset gpio. + "pmx_ts_suspend" : Disabled configuration of pins, this should specify sleep + config defined in pin groups of interrupt and reset gpio. + "pmx_ts_release" : Release configuration of pins, this should specify + release config defined in pin groups of interrupt and reset gpio. + +Optional properties: + + - mstar,button-map : button map of key codes. It is a three tuple consisting of key codes. + - mstar,panel-coords : panel coords for the chip in pixels. + It is a four tuple consisting of min x, + min y, max x and max y values. + +Example: + i2c@78b9000 { /* BLSP1 QUP5 */ + mstar@26 { + compatible = "mstar,msg21xx"; + reg = <0x26>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2008>; + mstar,irq-gpio = <&msm_gpio 13 0x00000001>; + mstar,reset-gpio = <&msm_gpio 12 0x0>; + vdd-supply = <&pm8916_l17>; + vcc_i2c-supply = <&pm8916_l6>; + mstar,display-coords = <0 0 480 854>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + mstar,button-map= <172 139 158>; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 526c51836402..20e5c5be37ce 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -50,6 +50,12 @@ Optional properties: to enable. - qcom,reset-aon-logic: If present, the GPU DEMET cells need to be reset while enabling the GX GDSC. + - resets: reset specifier pair consisting of phandle for the reset controller + and reset lines used by this controller. These can be + supplied only if we support qcom,skip-logic-collapse. + - reset-names: reset signal name strings sorted in the same order as the resets + property. These can be supplied only if we support + qcom,skip-logic-collapse. Example: gdsc_oxili_gx: qcom,gdsc@fd8c4024 { diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 7fa51e394f5c..c8f8d38c2a5e 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -725,6 +725,11 @@ Optional Properties: Example: + msm_dig_codec: qcom,msm-int-codec { + compatible = "qcom,msm_int_core_codec"; + qcom,dig-cdc-base-addr = <0xc0f0000>; + }; + sound { compatible = "qcom,msm8x16-audio-codec"; qcom,model = "msm8x16-snd-card"; diff --git a/Documentation/devicetree/bindings/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt index e37e7c2bea3c..c0a7a240b922 100644 --- a/Documentation/devicetree/bindings/sound/wcd_codec.txt +++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt @@ -383,7 +383,9 @@ i2c@f9925000 { Tombak audio CODEC in SPMI mode - - compatible = "qcom,msm8x16_wcd_codec"; + - compatible = "qcom,msm-codec-core", + - compatible = "qcom,pmic-codec-digital" + - compatible = "qcom,pmic-codec-analog" - reg: represents the slave base address provided to the peripheral. - interrupt-parent : The parent interrupt controller. - interrupts: List of interrupts in given SPMI peripheral. @@ -435,8 +437,19 @@ Optional properties: core register writes. Example: + +msm_dig_codec: qcom,msm-int-codec { + compatible = "qcom,msm_int_core_codec"; + qcom,dig-cdc-base-addr = <0xc0f0000>; +}; + +msm8x16_wcd_codec@f100 { + compatible = "qcom,msm_int_pmic_analog_codec"; + reg = <0xf100 0x100>; +}; + msm8x16_wcd_codec@f000{ - compatible = "qcom,msm8x16_wcd_codec"; + compatible = "qcom,msm_int_pmic_digital_codec"; reg = <0xf000 0x100>; interrupt-parent = <&spmi_bus>; interrupts = <0x1 0xf0 0x0>, diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index 2b2bfe428c79..c5e5f1851fc2 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -50,6 +50,7 @@ Optional properties : - qcom,disable-dev-mode-pm: If present, it disables PM runtime functionality for device mode. - qcom,disable-host-mode-pm: If present, it disables XHCI PM runtime functionality when USB host mode is used. +- qcom,core-clk-rate: If present, indicates clock frequency to be set for USB master clock. - extcon: phandles to external connector devices. First phandle should point to external connector, which provide "USB" cable events, the second should point to external connector device, which provide "USB-HOST" diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 4097b7cd6454..aca2dd3e4ccb 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -146,6 +146,7 @@ mosaixtech Mosaix Technologies, Inc. moxa Moxa mpl MPL AG msi Micro-Star International Co. Ltd. +mstar MStar Semiconductor, Inc. mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.) mundoreader Mundo Reader S.L. murata Murata Manufacturing Co., Ltd. diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-1080p-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-1080p-video.dtsi new file mode 100644 index 000000000000..cecd8d3cf2a0 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-1080p-video.dtsi @@ -0,0 +1,66 @@ +/* Copyright (c) 2013-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. + */ + +&mdss_mdp { + dsi_jdi_1080_vid: qcom,mdss_dsi_jdi_1080p_video { + qcom,mdss-dsi-panel-name = "jdi 1080p video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <96>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 53 2C + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 78 00 02 29 00 + 05 01 00 00 78 00 02 11 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 02 00 02 28 00 + 05 01 00 00 79 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = + [e7 36 24 00 66 6a 2a 3a 2d 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1b>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <61>; + qcom,mdss-pan-physical-height-dimension = <110>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-impl-defs-cobalt.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-impl-defs-cobalt.dtsi new file mode 100644 index 000000000000..feb74b5480f1 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-impl-defs-cobalt.dtsi @@ -0,0 +1,564 @@ +/* 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. + */ + + +&kgsl_smmu { + attach-impl-defs = <0x6000 0x3270>, + <0x6060 0x1055>, + <0x6470 0x110011>, + <0x6478 0x0>, + <0x647c 0x1000100>, + <0x6480 0x81108110>, + <0x6484 0x81108110>, + <0x6488 0x3e003e0>, + <0x648c 0x3e003e0>, + <0x6490 0x80008010>, + <0x6494 0x8020>, + <0x649c 0x6>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x604>, + <0x6928 0x11000>, + <0x6930 0x800>, + <0x6b64 0x1a5551>, + <0x6b68 0x2aaa2f82>; +}; + +&lpass_q6_smmu { + attach-impl-defs = <0x6000 0x3270>, + <0x6060 0x1055>, + <0x6070 0xe0>, + <0x6074 0xe0>, + <0x6078 0xe0>, + <0x607c 0xe0>, + <0x60f0 0xc0>, + <0x60f4 0xc8>, + <0x60f8 0xd0>, + <0x60fc 0xd8>, + <0x6170 0x0>, + <0x6174 0x30>, + <0x6178 0x60>, + <0x617c 0x90>, + <0x6270 0x0>, + <0x6274 0x2>, + <0x6278 0x4>, + <0x627c 0x6>, + <0x62f0 0x8>, + <0x62f4 0xe>, + <0x62f8 0x14>, + <0x62fc 0x1a>, + <0x6370 0x20>, + <0x6374 0x40>, + <0x6378 0x60>, + <0x637c 0x80>, + <0x67a0 0x0>, + <0x67a4 0x0>, + <0x67a8 0x20>, + <0x67b0 0x0>, + <0x67b4 0x8>, + <0x67b8 0xc8>, + <0x67d0 0x4>, + <0x67dc 0x8>, + <0x67e0 0x8>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x202>, + <0x6928 0x10a00>, + <0x6930 0x500>, + <0x6b64 0x121151>, + <0x6b68 0x8a840080>, + <0x6c00 0x0>, + <0x6c04 0x0>, + <0x6c08 0x0>, + <0x6c0c 0x0>, + <0x6c10 0x1>, + <0x6c14 0x1>, + <0x6c18 0x1>, + <0x6c1c 0x1>, + <0x6c20 0x2>, + <0x6c24 0x2>, + <0x6c28 0x2>, + <0x6c2c 0x2>, + <0x6c30 0x3>, + <0x6c34 0x3>, + <0x6c38 0x3>, + <0x6c3c 0x3>; +}; + +&mmss_smmu { + attach-impl-defs = <0x6000 0x3270>, + <0x6060 0x1055>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x204>, + <0x6928 0x11002>, + <0x6930 0x800>, + <0x6960 0xffffffff>, + <0x6964 0xffffffff>, + <0x6968 0xffffffff>, + <0x696c 0xffffffff>, + <0x6b48 0x330330>, + <0x6b4c 0x81>, + <0x6b50 0x3333>, + <0x6b54 0x3333>, + <0x6b64 0x1a5555>, + <0x6b68 0x9aaa892a>, + <0x6b70 0x10100002>, + <0x6b74 0x10100002>, + <0x6b78 0x10100002>, + <0x6b80 0x20042004>, + <0x6b84 0x20042004>; +}; + +&anoc1_smmu { + attach-impl-defs = <0x6000 0x3270>, + <0x6060 0x1055>, + <0x6070 0x19>, + <0x6074 0x39>, + <0x6078 0x41>, + <0x607c 0x59>, + <0x6080 0x95>, + <0x6084 0x98>, + <0x6088 0xc0>, + <0x608c 0xc0>, + <0x60f0 0x0>, + <0x60f4 0x2>, + <0x60f8 0x5>, + <0x60fc 0x8>, + <0x6100 0x16>, + <0x6104 0x17>, + <0x6108 0x19>, + <0x610c 0x19>, + <0x6170 0x0>, + <0x6174 0x0>, + <0x6178 0x0>, + <0x617c 0x0>, + <0x6180 0x0>, + <0x6184 0x0>, + <0x6188 0x0>, + <0x618c 0x0>, + <0x6270 0x0>, + <0x6274 0xd>, + <0x6278 0xe>, + <0x627c 0x12>, + <0x6280 0x16>, + <0x6284 0x16>, + <0x6288 0x18>, + <0x628c 0x18>, + <0x62f0 0x18>, + <0x62f4 0x1b>, + <0x62f8 0x1c>, + <0x62fc 0x24>, + <0x6300 0x28>, + <0x6304 0x2b>, + <0x6308 0x31>, + <0x630c 0x31>, + <0x6370 0x31>, + <0x6374 0x34>, + <0x6378 0x35>, + <0x637c 0x47>, + <0x6380 0x4f>, + <0x6384 0x54>, + <0x6388 0x60>, + <0x638c 0x60>, + <0x67a0 0x0>, + <0x67a4 0xa7>, + <0x67a8 0xc0>, + <0x67b0 0x0>, + <0x67b4 0x18>, + <0x67b8 0x7c>, + <0x67d0 0x0>, + <0x67dc 0x4>, + <0x67e0 0x8>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6b64 0x121151>, + <0x6b68 0xbb804080>, + <0x6c00 0x0>, + <0x6c04 0x0>, + <0x6c08 0x0>, + <0x6c0c 0x0>, + <0x6c10 0x0>, + <0x6c14 0x0>, + <0x6c18 0x0>, + <0x6c1c 0x0>, + <0x6c20 0x0>, + <0x6c24 0x0>, + <0x6c28 0x0>, + <0x6c2c 0x0>, + <0x6c30 0x0>, + <0x6c34 0x0>, + <0x6c38 0x0>, + <0x6c3c 0x0>, + <0x6c40 0x0>, + <0x6c44 0x0>, + <0x6c48 0x0>, + <0x6c4c 0x0>, + <0x6c50 0x0>, + <0x6c54 0x0>, + <0x6c58 0x0>, + <0x6c5c 0x0>, + <0x6c60 0x0>, + <0x6c64 0x0>, + <0x6c68 0x0>, + <0x6c6c 0x0>, + <0x6c70 0x0>, + <0x6c74 0x0>, + <0x6c78 0x0>, + <0x6c7c 0x0>, + <0x6c80 0x0>, + <0x6c84 0x1>, + <0x6c88 0x0>, + <0x6c8c 0x0>, + <0x6c90 0x4>, + <0x6c94 0x3>, + <0x6c98 0x2>, + <0x6c9c 0x0>, + <0x6ca0 0x5>, + <0x6ca4 0x5>, + <0x6ca8 0x0>, + <0x6cac 0x0>, + <0x6cb0 0x0>, + <0x6cb4 0x0>, + <0x6cb8 0x0>, + <0x6cbc 0x0>, + <0x6cc0 0x0>, + <0x6cc4 0x0>, + <0x6cc8 0x0>, + <0x6ccc 0x0>, + <0x6cd0 0x0>, + <0x6cd4 0x0>, + <0x6cd8 0x0>, + <0x6cdc 0x0>, + <0x6ce0 0x0>, + <0x6ce4 0x0>, + <0x6ce8 0x0>, + <0x6cec 0x0>, + <0x6cf0 0x0>, + <0x6cf4 0x0>, + <0x6cf8 0x0>, + <0x6cfc 0x0>, + <0x6d00 0x0>, + <0x6d04 0x0>, + <0x6d08 0x0>, + <0x6d0c 0x0>, + <0x6d10 0x0>, + <0x6d14 0x0>, + <0x6d18 0x0>, + <0x6d1c 0x0>, + <0x6d20 0x0>, + <0x6d24 0x0>, + <0x6d28 0x0>, + <0x6d2c 0x0>, + <0x6d30 0x0>, + <0x6d34 0x0>, + <0x6d38 0x0>, + <0x6d3c 0x0>, + <0x6d40 0x0>, + <0x6d44 0x0>, + <0x6d48 0x0>, + <0x6d4c 0x0>, + <0x6d50 0x0>, + <0x6d54 0x0>, + <0x6d58 0x0>, + <0x6d5c 0x0>, + <0x6d60 0x0>, + <0x6d64 0x0>, + <0x6d68 0x0>, + <0x6d6c 0x0>, + <0x6d70 0x0>, + <0x6d74 0x0>, + <0x6d78 0x0>, + <0x6d7c 0x0>, + <0x6d80 0x0>, + <0x6d84 0x0>, + <0x6d88 0x0>, + <0x6d8c 0x0>, + <0x6d90 0x0>, + <0x6d94 0x0>, + <0x6d98 0x0>, + <0x6d9c 0x0>, + <0x6da0 0x0>, + <0x6da4 0x0>, + <0x6da8 0x0>, + <0x6dac 0x0>, + <0x6db0 0x0>, + <0x6db4 0x0>, + <0x6db8 0x0>, + <0x6dbc 0x0>, + <0x6dc0 0x0>, + <0x6dc4 0x0>, + <0x6dc8 0x0>, + <0x6dcc 0x0>, + <0x6dd0 0x0>, + <0x6dd4 0x0>, + <0x6dd8 0x0>, + <0x6ddc 0x0>, + <0x6de0 0x0>, + <0x6de4 0x0>, + <0x6de8 0x0>, + <0x6dec 0x0>, + <0x6df0 0x0>, + <0x6df4 0x0>, + <0x6df8 0x0>, + <0x6dfc 0x0>; +}; + +&anoc2_smmu { + attach-impl-defs = <0x6000 0x3270>, + <0x6060 0x1055>, + <0x6070 0x12>, + <0x6074 0x26>, + <0x6078 0x3a>, + <0x607c 0x3c>, + <0x6080 0x3f>, + <0x6084 0x67>, + <0x6088 0x6c>, + <0x608c 0x74>, + <0x6090 0x7c>, + <0x6094 0x80>, + <0x6098 0xa0>, + <0x609c 0xa0>, + <0x60a0 0xa0>, + <0x60a4 0xa0>, + <0x60a8 0xa0>, + <0x60ac 0xa0>, + <0x60f0 0x0>, + <0x60f4 0x1>, + <0x60f8 0x3>, + <0x60fc 0x4>, + <0x6100 0x5>, + <0x6104 0x7>, + <0x6108 0x8>, + <0x610c 0x10>, + <0x6110 0x10>, + <0x6114 0x10>, + <0x6118 0x12>, + <0x611c 0x12>, + <0x6120 0x12>, + <0x6124 0x12>, + <0x6128 0x12>, + <0x612c 0x12>, + <0x6170 0x0>, + <0x6174 0x0>, + <0x6178 0x0>, + <0x617c 0x0>, + <0x6180 0x0>, + <0x6184 0x0>, + <0x6188 0x0>, + <0x618c 0x0>, + <0x6190 0x0>, + <0x6194 0x0>, + <0x6198 0x0>, + <0x619c 0x0>, + <0x61a0 0x0>, + <0x61a4 0x0>, + <0x61a8 0x0>, + <0x61ac 0x0>, + <0x6270 0x0>, + <0x6274 0x1>, + <0x6278 0x2>, + <0x627c 0x4>, + <0x6280 0x4>, + <0x6284 0x6>, + <0x6288 0x6>, + <0x628c 0x18>, + <0x6290 0x1a>, + <0x6294 0x1a>, + <0x6298 0x1e>, + <0x629c 0x1e>, + <0x62a0 0x1e>, + <0x62a4 0x1e>, + <0x62a8 0x1e>, + <0x62ac 0x1e>, + <0x62f0 0x1e>, + <0x62f4 0x24>, + <0x62f8 0x2a>, + <0x62fc 0x2c>, + <0x6300 0x2d>, + <0x6304 0x33>, + <0x6308 0x34>, + <0x630c 0x3a>, + <0x6310 0x3c>, + <0x6314 0x44>, + <0x6318 0x48>, + <0x631c 0x48>, + <0x6320 0x48>, + <0x6324 0x48>, + <0x6328 0x48>, + <0x632c 0x48>, + <0x6370 0x48>, + <0x6374 0x4d>, + <0x6378 0x52>, + <0x637c 0x56>, + <0x6380 0x59>, + <0x6384 0x63>, + <0x6388 0x68>, + <0x638c 0x70>, + <0x6390 0x78>, + <0x6394 0x88>, + <0x6398 0x90>, + <0x639c 0x90>, + <0x63a0 0x90>, + <0x63a4 0x90>, + <0x63a8 0x90>, + <0x63ac 0x90>, + <0x67a0 0x0>, + <0x67a4 0x8e>, + <0x67a8 0xa0>, + <0x67b0 0x0>, + <0x67b4 0x1e>, + <0x67b8 0xc6>, + <0x67d0 0x0>, + <0x67dc 0x4>, + <0x67e0 0x8>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6b48 0x330331>, + <0x6b4c 0x81>, + <0x6b50 0x1313>, + <0x6b64 0x121155>, + <0x6b68 0xea880920>, + <0x6b70 0x10100101>, + <0x6b74 0xc0c0000>, + <0x6b78 0xc0c0000>, + <0x6b80 0x20012001>, + <0x6b84 0x20012001>, + <0x6c00 0x5>, + <0x6c04 0x0>, + <0x6c08 0x5>, + <0x6c0c 0x0>, + <0x6c10 0x5>, + <0x6c14 0x0>, + <0x6c18 0x5>, + <0x6c1c 0x0>, + <0x6c20 0x5>, + <0x6c24 0x0>, + <0x6c28 0x0>, + <0x6c2c 0x0>, + <0x6c30 0x0>, + <0x6c34 0x0>, + <0x6c38 0x0>, + <0x6c3c 0x0>, + <0x6c40 0x0>, + <0x6c44 0x0>, + <0x6c48 0x0>, + <0x6c4c 0x0>, + <0x6c50 0x0>, + <0x6c54 0x0>, + <0x6c58 0x0>, + <0x6c5c 0x0>, + <0x6c60 0x0>, + <0x6c64 0x0>, + <0x6c68 0x0>, + <0x6c6c 0x0>, + <0x6c70 0x0>, + <0x6c74 0x0>, + <0x6c78 0x0>, + <0x6c7c 0x0>, + <0x6c80 0x0>, + <0x6c84 0x0>, + <0x6c88 0x0>, + <0x6c8c 0x0>, + <0x6c90 0x0>, + <0x6c94 0x0>, + <0x6c98 0x0>, + <0x6c9c 0x0>, + <0x6ca0 0x0>, + <0x6ca4 0x0>, + <0x6ca8 0x0>, + <0x6cac 0x0>, + <0x6cb0 0x0>, + <0x6cb4 0x0>, + <0x6cb8 0x0>, + <0x6cbc 0x0>, + <0x6cc0 0x0>, + <0x6cc4 0x0>, + <0x6cc8 0x0>, + <0x6ccc 0x0>, + <0x6cd0 0x0>, + <0x6cd4 0x0>, + <0x6cd8 0x0>, + <0x6cdc 0x0>, + <0x6ce0 0x0>, + <0x6ce4 0x0>, + <0x6ce8 0x0>, + <0x6cec 0x0>, + <0x6cf0 0x0>, + <0x6cf4 0x0>, + <0x6cf8 0x0>, + <0x6cfc 0x0>, + <0x6d00 0x8>, + <0x6d04 0x0>, + <0x6d08 0x8>, + <0x6d0c 0x0>, + <0x6d10 0x7>, + <0x6d14 0x0>, + <0x6d18 0x3>, + <0x6d1c 0x2>, + <0x6d20 0x4>, + <0x6d24 0x0>, + <0x6d28 0x4>, + <0x6d2c 0x0>, + <0x6d30 0x6>, + <0x6d34 0x0>, + <0x6d38 0x9>, + <0x6d3c 0x0>, + <0x6d40 0x0>, + <0x6d44 0x1>, + <0x6d48 0x4>, + <0x6d4c 0x0>, + <0x6d50 0x4>, + <0x6d54 0x0>, + <0x6d58 0x0>, + <0x6d5c 0x0>, + <0x6d60 0x0>, + <0x6d64 0x0>, + <0x6d68 0x0>, + <0x6d6c 0x0>, + <0x6d70 0x0>, + <0x6d74 0x0>, + <0x6d78 0x0>, + <0x6d7c 0x0>, + <0x6d80 0x0>, + <0x6d84 0x0>, + <0x6d88 0x0>, + <0x6d8c 0x0>, + <0x6d90 0x0>, + <0x6d94 0x0>, + <0x6d98 0x0>, + <0x6d9c 0x0>, + <0x6da0 0x0>, + <0x6da4 0x0>, + <0x6da8 0x0>, + <0x6dac 0x0>, + <0x6db0 0x0>, + <0x6db4 0x0>, + <0x6db8 0x0>, + <0x6dbc 0x0>, + <0x6dc0 0x0>, + <0x6dc4 0x0>, + <0x6dc8 0x0>, + <0x6dcc 0x0>, + <0x6dd0 0x0>, + <0x6dd4 0x0>, + <0x6dd8 0x0>, + <0x6ddc 0x0>, + <0x6de0 0x0>, + <0x6de4 0x0>, + <0x6de8 0x0>, + <0x6dec 0x0>, + <0x6df0 0x0>, + <0x6df4 0x0>, + <0x6df8 0x0>, + <0x6dfc 0x0>; +}; diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index c724ce5a8ad9..714bdf48da6c 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -147,6 +147,9 @@ dpdm-supply = <&qusb_phy0>; + qcom,thermal-mitigation + = <3000000 1500000 1000000 500000>; + qcom,chgr@1000 { reg = <0x1000 0x100>; interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 596a713a9ad0..deccd14d5d85 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -781,6 +781,7 @@ reg-names = "cc_base"; vdd_dig-supply = <&pm8994_s1_corner>; #clock-cells = <1>; + #reset-cells = <1>; }; clock_mmss: qcom,mmsscc@8c0000 { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi index aeb9b1c0207f..ed29dd9e1508 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi @@ -92,22 +92,27 @@ qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active - &cam_sensor_rear_active>; + &cam_sensor_rear_active + &cam_actuator_vaf_active>; pinctrl-1 = <&cam_sensor_mclk0_suspend - &cam_sensor_rear_suspend>; + &cam_sensor_rear_suspend + &cam_actuator_vaf_suspend>; gpios = <&tlmm 13 0>, <&tlmm 30 0>, <&pmcobalt_gpios 20 0>, - <&tlmm 29 0>; + <&tlmm 29 0>, + <&tlmm 27 0>; qcom,gpio-reset = <1>; qcom,gpio-vdig = <2>; qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-vaf = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", "CAM_VDIG", - "CAM_VANA"; + "CAM_VANA", + "CAM_VAF"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi index 3887999e9bab..485bc560eef5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi @@ -92,22 +92,27 @@ qcom,gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active - &cam_sensor_rear_active>; + &cam_sensor_rear_active + &cam_actuator_vaf_active>; pinctrl-1 = <&cam_sensor_mclk0_suspend - &cam_sensor_rear_suspend>; + &cam_sensor_rear_suspend + &cam_actuator_vaf_suspend>; gpios = <&tlmm 13 0>, <&tlmm 30 0>, <&pmcobalt_gpios 20 0>, - <&tlmm 29 0>; + <&tlmm 29 0>, + <&tlmm 27 0>; qcom,gpio-reset = <1>; qcom,gpio-vdig = <2>; qcom,gpio-vana = <3>; - qcom,gpio-req-tbl-num = <0 1 2 3>; - qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-vaf = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; qcom,gpio-req-tbl-label = "CAMIF_MCLK0", "CAM_RESET0", "CAM_VDIG", - "CAM_VANA"; + "CAM_VANA", + "CAM_VAF"; qcom,sensor-position = <0>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi index a3911ea7a89d..b11c68ae543e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi @@ -48,7 +48,7 @@ "csi_src_clk", "csi_clk", "cphy_csid_clk", "csiphy_timer_src_clk", "csiphy_timer_clk", "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk"; - qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 269333333 0 + qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0 0 256000000 0>; status = "ok"; }; @@ -80,7 +80,7 @@ "csi_src_clk", "csi_clk", "cphy_csid_clk", "csiphy_timer_src_clk", "csiphy_timer_clk", "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk"; - qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 269333333 0 + qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0 0 256000000 0>; status = "ok"; }; @@ -112,7 +112,7 @@ "csi_src_clk", "csi_clk", "cphy_csid_clk", "csiphy_timer_src_clk", "csiphy_timer_clk", "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk"; - qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 269333333 0 + qcom,clock-rates = <0 0 0 0 0 0 256000000 0 0 200000000 0 0 256000000 0>; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi index a8b047a0e0b3..d1a8ae03cde2 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi @@ -173,7 +173,7 @@ synaptics,avdd-current = <20000>; pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; pinctrl-0 = <&ts_active>; - pinctrl-1 = <&ts_suspend>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; synaptics,display-coords = <0 0 1439 2559>; synaptics,panel-coords = <0 0 1439 2559>; synaptics,reset-gpio = <&tlmm 89 0x00>; @@ -316,6 +316,21 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +&dsi_sharp_1080_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_jdi_1080_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,5v-boost-gpio = <&tlmm 51 0>; +}; + &mdss_hdmi_tx { pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", "hdmi_active", "hdmi_sleep"; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi index fc6c4d2eadd7..43d6e3b84cec 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi @@ -22,6 +22,8 @@ #include "dsi-panel-sharp-dsc-4k-cmd.dtsi" #include "dsi-panel-jdi-dualmipi-video.dtsi" #include "dsi-panel-jdi-dualmipi-cmd.dtsi" +#include "dsi-panel-sharp-1080p-cmd.dtsi" +#include "dsi-panel-jdi-1080p-video.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -135,3 +137,15 @@ qcom,mdss-dsi-t-clk-post = <0x06>; qcom,mdss-dsi-t-clk-pre = <0x22>; }; + +&dsi_sharp_1080_cmd { + qcom,mdss-dsi-panel-timings = [00 17 04 05 09 09 05 06 04 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x06>; + qcom,mdss-dsi-t-clk-pre = <0x21>; +}; + +&dsi_jdi_1080_vid { + qcom,mdss-dsi-panel-timings = [00 1b 05 06 0a 0c 05 07 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x27>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi index a99ce727c195..7f1f2c10f6c4 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi @@ -44,7 +44,8 @@ /* VBIF QoS remapper settings*/ qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>; - qcom,vbif-settings = <0x00ac 0x00000040>; + qcom,vbif-settings = <0x00ac 0x00000040>, + <0x00d0 0x00001010>; /* v1 only */ qcom,mdss-has-panic-ctrl; qcom,mdss-per-pipe-panic-luts = <0x000f>, @@ -57,9 +58,8 @@ qcom,max-bandwidth-high-kbps = <6700000>; qcom,max-bandwidth-per-pipe-kbps = <2400000>; qcom,max-clk-rate = <412500000>; - /* OT settings and bw for v1, revisit for v2 */ - qcom,mdss-default-ot-rd-limit = <16>; - qcom,mdss-default-ot-wr-limit = <16>; + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; qcom,mdss-dram-channels = <2>; qcom,mdss-pipe-vig-off = <0x00005000 0x00007000 diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi index aaf9aed30e7f..ba25d2f07736 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi @@ -174,7 +174,7 @@ synaptics,avdd-current = <20000>; pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; pinctrl-0 = <&ts_active>; - pinctrl-1 = <&ts_suspend>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; synaptics,display-coords = <0 0 1439 2559>; synaptics,panel-coords = <0 0 1439 2559>; synaptics,reset-gpio = <&tlmm 89 0x00>; @@ -341,6 +341,21 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +&dsi_sharp_1080_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_jdi_1080_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,5v-boost-gpio = <&tlmm 51 0>; +}; + &i2c_7 { status = "okay"; qcom,smb138x@8 { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi index 4cbd17f80cb8..24e23d00d697 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi @@ -1543,18 +1543,31 @@ }; }; - ts_suspend: ts_suspend { + ts_reset_suspend: ts_reset_suspend { mux { - pins = "gpio89", "gpio125"; + pins = "gpio89"; function = "gpio"; }; config { - pins = "gpio89", "gpio125"; + pins = "gpio89"; drive-strength = <2>; bias-pull-down; }; }; + + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <2>; + bias-disable; + }; + }; }; sdc2_clk_on: sdc2_clk_on { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi index b5d3a85f9b15..6103f4c2b304 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi @@ -292,103 +292,404 @@ qcom,ipc-bit-offset = <1>; qcom,gic-parent = <&intc>; - qcom,gic-map = <2 216>, /* tsens_upper_lower_int */ - <79 379>, /* qusb2phy_dmse_hv_prim */ - <80 384>, /* qusb2phy_dmse_hv_sec */ - <52 275>, /* qmp_usb3_lfps_rxterm_irq */ - <87 358>, /* ee0_krait_hlos_spmi_periph_irq */ - <49 212>, /* usb30_power_event_irq */ - <0xff 19>, /* arch_timer */ - <0xff 39>, /* arch_mem_timer */ - <0xff 483>, /* smp2p */ - <0xff 190>, /* smp2p */ - <0xff 210>, /* smp2p */ - <0xff 146>, /* msm_serial0 */ - <0xff 195>, /* ngd_slim_irq */ - <0xff 75>, /* ARM64 */ - <0xff 76>, /* ARM64 */ - <0xff 73>, /* ARM64 */ - <0xff 74>, /* ARM64 */ - <0xff 67>, /* OSM */ - <0xff 68>, /* OSM */ - <0xff 365>, /* ipa */ - <0xff 464>, /* gsi */ - <0xff 54>, /* gladiator-error */ - <0xff 481>, /* qcom,smd-modem */ - <0xff 188>, /* qcom,smd-adsp */ - <0xff 208>, /* qcom,smd-dsps */ - <0xff 484>, /* qcom,glink-smem-native-xprt-modem */ - <0xff 189>, /* qcom,glink-smem-native-xprt-adsp */ - <0xff 211>, /* qcom,glink-smem-native-xprt-dsps */ - <0xff 200>, /* qcom,glink-smem-native-xprt-rpm */ - <0xff 380>, /* qcom,glink-mailbox-xprt-spss */ - <0xff 157>, /* mmc0 */ - <0xff 253>, /* c0a4900.sdhci */ - <0xff 297>, /* ufshcd */ - <0xff 194>, /* adsp */ - <0xff 480>, /* modem */ - <0xff 490>, /* tsens_interrupt */ - <0xff 477>, /* tsens_critical_interrupt */ - <0xff 462>, /* tsens_critical_interrupt */ - <0xff 38>, /* lmh-interrupt */ - <0xff 422>, /* slpi */ - <0xff 35>, /* apps_wdog_bark */ - <0xff 22>, /* arm-pmu */ - <0xff 317>, /* cpr3 */ - <0xff 203>, /* 7781b8.qcom,mpm */ - <0xff 261>, /* arm-smmu */ - <0xff 263>, /* arm-smmu */ - <0xff 405>, /* arm-smmu-context-fault */ - <0xff 258>, /* arm-smmu-context-fault */ - <0xff 425>, /* arm-smmu-context-fault */ - <0xff 426>, /* arm-smmu-context-fault */ - <0xff 427>, /* arm-smmu-context-fault */ - <0xff 428>, /* arm-smmu-context-fault */ - <0xff 429>, /* arm-smmu-context-fault */ - <0xff 430>, /* arm-smmu-context-fault */ - <0xff 431>, /* arm-smmu-context-fault */ - <0xff 295>, /* arm-smmu-context-fault */ - <0xff 298>, /* arm-smmu-context-fault */ - <0xff 299>, /* arm-smmu-context-fault */ - <0xff 300>, /* arm-smmu-context-fault */ - <0xff 276>, /* arm-smmu-context-fault */ - <0xff 277>, /* arm-smmu-context-fault */ - <0xff 361>, /* arm-smmu-context-fault */ - <0xff 362>, /* arm-smmu-"ontext-fault */ - <0xff 110>, /* csiphy */ - <0xff 111>, /* csiphy */ - <0xff 112>, /* csiphy */ - <0xff 328>, /* csid */ - <0xff 329>, /* csid */ - <0xff 330>, /* csid */ - <0xff 331>, /* csid */ - <0xff 326>, /* */ - <0xff 341>, /* ispif */ - <0xff 346>, /* vfe */ - <0xff 347>, /* vfe */ - <0xff 327>, /* cci */ - <0xff 319>, /* msm_vidc */ - <0xff 332>, /* kgsl-3d0 */ - <0xff 115>, /* MDSS */ - <0xff 131>, /* i2c-msm-v2-irq */ - <0xff 163>, /* dwc3 */ - <0xff 240>, /* tlmm */ - <0xff 310>, /* pcie20_global_int */ - <0xff 323>, /* lpass_slimbus1_core_ee1_irq */ - <0xff 437>, /* pcie20_0_int_msi_dev0 */ - <0xff 196>, /* lpass_aud_slimbus_bam_ee1_irq */ - <0xff 215>, /* o_bimc_intr */ - <0xff 280>, /* pcie20_intd */ - <0xff 324>, /* lpass_qca_slimbus_bam_ee1_irq */ - <0xff 432>, /* smmu_Cirpt[8] */ - <0xff 433>, /* smmu_Cirpt[9] */ - <0xff 461>, /* o_ocimem_nonsec_irq */ - <0xff 69>, /* o_pwr_dcvsh_interrupt */ - <0xff 70>, /* o_perf_dcvsh_interrupt */ - <0xff 166>, /* o_lm_int_2qgic */ - <0xff 238>, /* crypto_bam_irq[0] */ - <0xff 132>; /* qup_irq */ - + qcom,gic-map = + <0x1f 212>, /* usb30_power_event_irq */ + <0x2 216>, /* tsens1_upper_lower_int */ + <0x34 275>, /* qmp_usb3_lfps_rxterm_irq_cx */ + <0x57 358>, /* spmi_periph_irq[0] */ + <0x4f 379>, /* usb2phy_intr */ + <0x50 384>, /* sp_rmb_sp2soc_irq */ + <0xff 16>, /* APC0_qgicQTmrHypPhysIrptReq */ + <0xff 17>, /* APC3_qgicQTmrSecPhysIrptReq */ + <0xff 18>, /* APC0_qgicQTmrNonSecPhysIrptReq */ + <0xff 19>, /* APC3_qgicQTmrVirtIrptReq */ + <0xff 20>, /* APC0_dbgCommRxFull */ + <0xff 21>, /* APC3_dbgCommTxEmpty */ + <0xff 22>, /* APC0_qgicPerfMonIrptReq */ + <0xff 23>, /* corespm_vote_int[7] */ + <0xff 24>, /* APC0_qgicExtFaultIrptReq */ + <0xff 28>, /* qgicWakeupSync */ + <0xff 29>, /* APCC_cti_SPI_intx */ + <0xff 30>, /* APCC_cti_SPI_inty */ + <0xff 32>, /* l2spm_vote_int[0] */ + <0xff 33>, /* l2spm_vote_int[1] */ + <0xff 34>, /* APCC_qgicL2ErrorIrptReq */ + <0xff 35>, /* WDT_barkInt */ + <0xff 36>, /* WDT_biteExpired */ + <0xff 39>, /* QTMR_qgicFrm0VirtIrq */ + <0xff 40>, /* QTMR_qgicFrm0PhyIrq */ + <0xff 41>, /* QTMR_qgicFrm1PhyIrq */ + <0xff 42>, /* QTMR_qgicFrm2PhyIrq */ + <0xff 43>, /* QTMR_qgicFrm3PhyIrq */ + <0xff 44>, /* QTMR_qgicFrm4PhyIrq */ + <0xff 45>, /* QTMR_qgicFrm5PhyIrq */ + <0xff 46>, /* QTMR_qgicFrm6PhyIrq */ + <0xff 47>, /* rbif_Irq[0] */ + <0xff 48>, /* rbif_Irq[1] */ + <0xff 52>, /* cci_spm_vote_summary_int */ + <0xff 54>, /* ~nERRORIRQ */ + <0xff 55>, /* nEVNTCNTOVERFLOW_cci */ + <0xff 56>, /* QTMR_qgicFrm0VirtIrq */ + <0xff 57>, /* QTMR_qgicFrm0PhyIrq */ + <0xff 58>, /* QTMR_qgicFrm1PhyIrq */ + <0xff 59>, /* QTMR_qgicFrm2PhyIrq */ + <0xff 60>, /* QTMR_qgicFrm3PhyIrq */ + <0xff 61>, /* QTMR_qgicFrm4PhyIrq */ + <0xff 62>, /* QTMR_qgicFrm5PhyIrq */ + <0xff 63>, /* QTMR_qgicFrm6PhyIrq */ + <0xff 64>, /* wakeup_counter_irq_OR */ + <0xff 65>, /* apc0_vs_alarm */ + <0xff 66>, /* apc1_vs_alarm */ + <0xff 67>, /* o_pwr_osm_irq */ + <0xff 68>, /* o_perf_osm_irq */ + <0xff 69>, /* o_pwr_dcvsh_interrupt */ + <0xff 70>, /* o_perf_dcvsh_interrupt */ + <0xff 73>, /* L2_EXTERRIRQ_C0 */ + <0xff 74>, /* L2_EXTERRIRQ_C1 */ + <0xff 75>, /* L2_INTERRIRQ_C0 */ + <0xff 76>, /* L2_INTERRIRQ_C1 */ + <0xff 77>, /* L2SPM_svicInt[0] */ + <0xff 78>, /* L2SPM_svicInt[1] */ + <0xff 79>, /* L2SPM_svicIntSwDone[0] */ + <0xff 80>, /* L2SPM_svicIntSwDone[1] */ + <0xff 81>, /* l2_avs_err[0] */ + <0xff 82>, /* l2_avs_err[1] */ + <0xff 83>, /* l2_avs_ack[0] */ + <0xff 84>, /* l2_avs_ack[1] */ + <0xff 96>, /* uart_dm_intr */ + <0xff 97>, /* uart_dm_intr */ + <0xff 98>, /* o_qm_interrupt */ + <0xff 100>, /* jpeg_vbif_irpt */ + <0xff 101>, /* processor_1_user_int */ + <0xff 102>, /* processor_1_kernel_int */ + <0xff 106>, /* dir_conn_irq_lpa_dsp_2 */ + <0xff 107>, /* dir_conn_irq_lpa_dsp_1 */ + <0xff 109>, /* camss_vbif_0_irq */ + <0xff 110>, /* csiphy_irq */ + <0xff 111>, /* csiphy_irq */ + <0xff 112>, /* csiphy_irq */ + <0xff 115>, /* mdp_irq */ + <0xff 116>, /* vbif_irpt */ + <0xff 117>, /* dir_conn_irq_lpa_dsp_0 */ + <0xff 119>, /* lcc_audio_wrapper_q6 */ + <0xff 122>, /* PIMEM TPDM BC interrupt */ + <0xff 123>, /* PIMEM TPDM TC interrupt */ + <0xff 124>, /* dir_conn_irq_sensors_1 */ + <0xff 125>, /* dir_conn_irq_sensors_0 */ + <0xff 126>, /* qup_irq */ + <0xff 127>, /* qup_irq */ + <0xff 128>, /* qup_irq */ + <0xff 129>, /* qup_irq */ + <0xff 130>, /* qup_irq */ + <0xff 131>, /* qup_irq */ + <0xff 132>, /* qup_irq */ + <0xff 133>, /* qup_irq */ + <0xff 134>, /* qup_irq */ + <0xff 135>, /* qup_irq */ + <0xff 136>, /* qup_irq */ + <0xff 137>, /* qup_irq */ + <0xff 138>, /* qup_irq */ + <0xff 139>, /* uart_dm_intr */ + <0xff 140>, /* uart_dm_intr */ + <0xff 141>, /* uart_dm_intr */ + <0xff 145>, /* uart_dm_intr */ + <0xff 146>, /* uart_dm_intr */ + <0xff 147>, /* uart_dm_intr */ + <0xff 148>, /* osmmu_Cirpt[4] */ + <0xff 149>, /* osmmu_Cirpt[5] */ + <0xff 151>, /* tsif_irq[0] */ + <0xff 152>, /* tsif_irq[1] */ + <0xff 153>, /* tspp_irq */ + <0xff 154>, /* bam_irq */ + <0xff 155>, /* dir_conn_irq_lpa_dsp_5 */ + <0xff 156>, /* dir_conn_irq_lpa_dsp_4 */ + <0xff 157>, /* sdcc_irq */ + <0xff 158>, /* sdcc_irq */ + <0xff 159>, /* lpass_qos_apps_interrupt */ + <0xff 160>, /* smmu_PMIrpt */ + <0xff 161>, /* sdcc_irq */ + <0xff 162>, /* sdcc_irq */ + <0xff 163>, /* usb30_ctrl_irq[0] */ + <0xff 164>, /* usb30_bam_irq */ + <0xff 165>, /* usb30_hs_phy_irq */ + <0xff 166>, /* o_lm_int_2qgic */ + <0xff 167>, /* pcie20_inta */ + <0xff 168>, /* pcie20_intb */ + <0xff 169>, /* smmu_Cirpt[12] */ + <0xff 170>, /* pcie20_intc */ + <0xff 171>, /* pcie20_intd */ + <0xff 172>, /* dcvs_int(8) */ + <0xff 173>, /* dcvs_int(9) */ + <0xff 184>, /* dir_conn_irq_lpa_dsp_3 */ + <0xff 185>, /* camss_vbif_2_irq */ + <0xff 186>, /* mnoc_obs_mainFault */ + <0xff 188>, /* q6ss_irq_out(4) */ + <0xff 189>, /* q6ss_irq_out(5) */ + <0xff 190>, /* q6ss_irq_out(6) */ + <0xff 191>, /* q6ss_irq_out(7) */ + <0xff 192>, /* audio_out0_irq */ + <0xff 194>, /* q6ss_wdog_exp_irq */ + <0xff 195>, /* lpass_slimbus_core_ee1_irq */ + <0xff 196>, /* lpass_slimbus_bam_ee1_irq */ + <0xff 197>, /* resampler_irq[0] */ + <0xff 199>, /* qdss_usb_trace_bam_irq */ + <0xff 200>, /* rpm_ipc[4] */ + <0xff 201>, /* rpm_ipc[5] */ + <0xff 202>, /* rpm_ipc[6] */ + <0xff 203>, /* rpm_ipc[7] */ + <0xff 204>, /* rpm_ipc[20] */ + <0xff 205>, /* rpm_ipc[21] */ + <0xff 206>, /* rpm_ipc[22] */ + <0xff 207>, /* rpm_ipc[23] */ + <0xff 208>, /* q6ss_irq_out(4) */ + <0xff 209>, /* q6ss_irq_out(5) */ + <0xff 210>, /* q6ss_irq_out(6) */ + <0xff 211>, /* q6ss_irq_out(7) */ + <0xff 213>, /* secure_wdog_bark_irq */ + <0xff 214>, /* tsens1_tsens_max_min_int */ + <0xff 215>, /* o_bimc_intr[0] */ + <0xff 217>, /* ocimem_nonsec_irq */ + <0xff 218>, /* sscaon_tmr_timeout_irq */ + <0xff 219>, /* q6ss_irq_out(28) */ + <0xff 220>, /* spmi_protocol_irq */ + <0xff 221>, /* q6ss_irq_out(29) */ + <0xff 222>, /* q6ss_irq_out(30) */ + <0xff 223>, /* spdm_offline_irq */ + <0xff 224>, /* spdm_realtime_irq */ + <0xff 225>, /* snoc_obs_mainFault */ + <0xff 226>, /* cnoc_obs_mainFault */ + <0xff 227>, /* o_ss_xpu3_sec_intr */ + <0xff 228>, /* o_tcsr_xpu3_non_sec_summary_intr */ + <0xff 229>, /* o_timeout_slave_kpss_summary_intr */ + <0xff 230>, /* o_tcsr_vmidmt_client_sec_summary_intr */ + <0xff 231>, /* o_tcsr_vmidmt_client_non_sec */ + <0xff 232>, /* o_tcsr_vmidmt_cfg_sec_summary_intr */ + <0xff 233>, /* o_tcsr_vmidmt_cfg_non_sec */ + <0xff 234>, /* q6ss_irq_out(31) */ + <0xff 235>, /* cpr_irq[0] */ + <0xff 236>, /* crypto_core_irq[0] */ + <0xff 237>, /* crypto_core_irq[1] */ + <0xff 238>, /* crypto_bam_irq[0] */ + <0xff 239>, /* crypto_bam_irq[1] */ + <0xff 240>, /* summary_irq_hmss */ + <0xff 241>, /* dir_conn_irq_hmss_7 */ + <0xff 242>, /* dir_conn_irq_hmss_6 */ + <0xff 243>, /* dir_conn_irq_hmss_5 */ + <0xff 244>, /* dir_conn_irq_hmss_4 */ + <0xff 245>, /* dir_conn_irq_hmss_3 */ + <0xff 246>, /* dir_conn_irq_hmss_2 */ + <0xff 247>, /* dir_conn_irq_hmss_1 */ + <0xff 248>, /* dir_conn_irq_hmss_0 */ + <0xff 249>, /* summary_irq_hmss_tz */ + <0xff 250>, /* cpr_irq[3] */ + <0xff 251>, /* cpr_irq[2] */ + <0xff 252>, /* cpr_irq[1] */ + <0xff 253>, /* sdcc_pwr_cmd_irq */ + <0xff 254>, /* sdio_wakeup_irq */ + <0xff 255>, /* cpr_irq[0] */ + <0xff 256>, /* smmu_Cirpt[13] */ + <0xff 257>, /* smmu_Cirpt[14] */ + <0xff 258>, /* smmu_Cirpt[0] */ + <0xff 259>, /* sdcc_pwr_cmd_irq */ + <0xff 260>, /* sdio_wakeup_irq */ + <0xff 261>, /* o_tcsr_mmu_nsgcfglrpt_summary_intr */ + <0xff 262>, /* o_tcsr_mmu_gcfglrpt_summary_intr */ + <0xff 263>, /* o_tcsr_mmu_nsglrpt_summary_intr */ + <0xff 264>, /* o_tcsr_mmu_glrpt_summary_intr */ + <0xff 265>, /* vbif_irpt */ + <0xff 266>, /* smmu_PMIrpt */ + <0xff 267>, /* smmu_Cirpt[3] */ + <0xff 268>, /* q6ss_irq_out(31) */ + <0xff 269>, /* rpm_wdog_expired_irq */ + <0xff 270>, /* bam_irq */ + <0xff 271>, /* bam_irq */ + <0xff 272>, /* q6ss_irq_out(28) */ + <0xff 273>, /* q6ss_irq_out(29) */ + <0xff 274>, /* q6ss_irq_out(30) */ + <0xff 276>, /* osmmu_Cirpt [4] */ + <0xff 277>, /* osmmu_Cirpt [5] */ + <0xff 278>, /* usb30_ctrl_irq[1] */ + <0xff 279>, /* osmmu_Cirpt [6] */ + <0xff 280>, /* osmmu_Cirpt [7] */ + <0xff 281>, /* osmmu_Cirpt [8] */ + <0xff 282>, /* osmmu_Cirpt [9] */ + <0xff 283>, /* osmmu_Cirpt [10] */ + <0xff 284>, /* osmmu_Cirpt [11] */ + <0xff 285>, /* osmmu_Cirpt [12] */ + <0xff 286>, /* osmmu_Cirpt [13] */ + <0xff 287>, /* osmmu_Cirpt [14] */ + <0xff 288>, /* osmmu_Cirpt [15] */ + <0xff 289>, /* ufs_ice_sec_level_irq */ + <0xff 290>, /* cpr_irq[4] */ + <0xff 291>, /* smmu_Cirpt[2] */ + <0xff 292>, /* osmmu_Cirpt [16] */ + <0xff 293>, /* osmmu_Cirpt [17] */ + <0xff 294>, /* osmmu_Cirpt [18] */ + <0xff 295>, /* osmmu_Cirpt [0] */ + <0xff 296>, /* osmmu_PMIrpt */ + <0xff 297>, /* ufs_intrq */ + <0xff 298>, /* osmmu_Cirpt [1] */ + <0xff 299>, /* osmmu_Cirpt [2] */ + <0xff 300>, /* osmmu_Cirpt [3] */ + <0xff 301>, /* smmu_Cirpt[1] */ + <0xff 302>, /* qdss_etrbytecnt_irq */ + <0xff 303>, /* smmu_Cirpt[0] */ + <0xff 304>, /* osmmu_Cirpt [19] */ + <0xff 305>, /* osmmu_Cirpt [20] */ + <0xff 306>, /* osmmu_Cirpt [21] */ + <0xff 307>, /* osmmu_Cirpt [22] */ + <0xff 308>, /* osmmu_Cirpt [23] */ + <0xff 310>, /* pcie20_global_int */ + <0xff 311>, /* pcie20_int_edma_int */ + <0xff 316>, /* lpass_hdmitx_interrupt_ext */ + <0xff 317>, /* rbif_irq */ + <0xff 318>, /* gpu_cc_gpu_cx_gds_hw_ctrl_irq_out */ + <0xff 319>, /* VENUS_IRQ */ + <0xff 323>, /* lpass_slimbus1_core_ee1_irq */ + <0xff 324>, /* lpass_slimbus1_bam_ee1_irq */ + <0xff 325>, /* camss_irq18 */ + <0xff 326>, /* camss_irq0 */ + <0xff 327>, /* camss_irq1 */ + <0xff 328>, /* camss_irq2 */ + <0xff 329>, /* camss_irq3 */ + <0xff 330>, /* camss_irq4 */ + <0xff 331>, /* camss_irq5 */ + <0xff 332>, /* GC_SYS_irq_0 */ + <0xff 333>, /* GC_SYS_irq_1 */ + <0xff 334>, /* GC_SYS_irq_2 */ + <0xff 335>, /* GC_SYS_irq_3 */ + <0xff 336>, /* camss_irq13 */ + <0xff 337>, /* camss_irq14 */ + <0xff 338>, /* camss_irq15 */ + <0xff 339>, /* camss_irq16 */ + <0xff 340>, /* camss_irq17 */ + <0xff 341>, /* camss_irq6 */ + <0xff 342>, /* smmu_Cirpt[15] */ + <0xff 343>, /* bam_irq[0] */ + <0xff 344>, /* uart_dm_intr */ + <0xff 345>, /* camss_irq7 */ + <0xff 346>, /* camss_irq8 */ + <0xff 347>, /* camss_irq9 */ + <0xff 348>, /* camss_irq10 */ + <0xff 350>, /* camss_irq12 */ + <0xff 351>, /* sif_aud_dec_out_irq_ext */ + <0xff 356>, /* vbif_nrt_irpt */ + <0xff 357>, /* Nonfatal pIMEM interrupt */ + <0xff 359>, /* spmi_periph_irq[1] */ + <0xff 360>, /* fatal pIMEM interrupt */ + <0xff 361>, /* osmmu_Cirpt[0] */ + <0xff 362>, /* osmmu_Cirpt[1] */ + <0xff 363>, /* osmmu_Cirpt[2] */ + <0xff 364>, /* osmmu_Cirpt[3] */ + <0xff 365>, /* ipa_irq(0) */ + <0xff 366>, /* osmmu_PMIrpt */ + <0xff 380>, /* sp_sp2apps_irq[0] */ + <0xff 381>, /* sp_sp2apps_irq[1] */ + <0xff 382>, /* sp_sp2apps_irq[2] */ + <0xff 383>, /* sp_sp2apps_irq[3] */ + <0xff 385>, /* osmmu_CIrpt[12] */ + <0xff 386>, /* osmmu_CIrpt[13] */ + <0xff 387>, /* osmmu_CIrpt[14] */ + <0xff 388>, /* osmmu_CIrpt[15] */ + <0xff 389>, /* osmmu_CIrpt[16] */ + <0xff 390>, /* osmmu_CIrpt[17] */ + <0xff 391>, /* osmmu_CIrpt[18] */ + <0xff 392>, /* osmmu_CIrpt[19] */ + <0xff 393>, /* o_dcc_crc_fail_int */ + <0xff 395>, /* aggre1_obs_mainfault */ + <0xff 396>, /* aggr1_smmu_cirpt[0] */ + <0xff 397>, /* aggr1_smmu_cirpt[1] */ + <0xff 398>, /* aggr1_smmu_cirpt[2] */ + <0xff 399>, /* aggr1_smmu_cirpt[3] */ + <0xff 400>, /* aggr1_smmu_cirpt[4] */ + <0xff 401>, /* aggr1_smmu_cirpt[5] */ + <0xff 402>, /* aggr1_smmu_cirpt[6] */ + <0xff 403>, /* aggr1_smmu_pmirpt */ + <0xff 404>, /* aggre2noc_obs_mainFault */ + <0xff 405>, /* osmmu_CIrpt[0] */ + <0xff 406>, /* osmmu_CIrpt[1] */ + <0xff 407>, /* osmmu_CIrpt[2] */ + <0xff 408>, /* osmmu_CIrpt[3] */ + <0xff 409>, /* osmmu_CIrpt[4] */ + <0xff 410>, /* osmmu_CIrpt[5] */ + <0xff 411>, /* o_dcc_task_done_int */ + <0xff 412>, /* vsense_alarm_irq */ + <0xff 413>, /* osmmu_PMIrpt */ + <0xff 414>, /* pmic_arb_trans_done_irq[0] */ + <0xff 415>, /* pmic_arb_trans_done_irq[1] */ + <0xff 416>, /* rpm_ipc[28] */ + <0xff 417>, /* rpm_ipc[29] */ + <0xff 418>, /* rpm_ipc[30] */ + <0xff 419>, /* rpm_ipc[31] */ + <0xff 420>, /* qup_irq */ + <0xff 421>, /* qup_irq */ + <0xff 422>, /* wd_bite_apps */ + <0xff 423>, /* lpass_qos_apps_interrupt */ + <0xff 424>, /* ipa_irq(2) */ + <0xff 425>, /* smmu_Cirpt[1] */ + <0xff 426>, /* smmu_Cirpt[2] */ + <0xff 427>, /* smmu_Cirpt[3] */ + <0xff 428>, /* smmu_Cirpt[4] */ + <0xff 429>, /* smmu_Cirpt[5] */ + <0xff 430>, /* smmu_Cirpt[6] */ + <0xff 431>, /* smmu_Cirpt[7] */ + <0xff 432>, /* smmu_Cirpt[8] */ + <0xff 433>, /* smmu_Cirpt[9] */ + <0xff 434>, /* smmu_Cirpt[10] */ + <0xff 435>, /* smmu_Cirpt[11] */ + <0xff 436>, /* smmu_Cirpt[16] */ + <0xff 437>, /* pcie20_0_int_msi_dev0 */ + <0xff 438>, /* pcie20_0_int_msi_dev1 */ + <0xff 439>, /* pcie20_0_int_msi_dev2 */ + <0xff 440>, /* pcie20_0_int_msi_dev3 */ + <0xff 441>, /* pcie20_0_int_msi_dev4 */ + <0xff 442>, /* pcie20_0_int_msi_dev5 */ + <0xff 443>, /* pcie20_0_int_msi_dev6 */ + <0xff 444>, /* pcie20_0_int_msi_dev7 */ + <0xff 445>, /* o_wcss_apps_intr[0] */ + <0xff 446>, /* o_wcss_apps_intr[1] */ + <0xff 447>, /* o_wcss_apps_intr[2] */ + <0xff 448>, /* o_wcss_apps_intr[3] */ + <0xff 449>, /* o_wcss_apps_intr[4] */ + <0xff 450>, /* o_wcss_apps_intr[5] */ + <0xff 452>, /* o_wcss_apps_intr[6] */ + <0xff 453>, /* o_wcss_apps_intr[7] */ + <0xff 454>, /* o_wcss_apps_intr[8] */ + <0xff 455>, /* o_wcss_apps_intr[9] */ + <0xff 456>, /* o_wcss_apps_intr[10] */ + <0xff 457>, /* o_wcss_apps_intr[11] */ + <0xff 458>, /* o_wcss_apps_intr[12] */ + <0xff 461>, /* o_ocimem_nonsec_irq */ + <0xff 462>, /* tsens1_tsens_critical_int */ + <0xff 463>, /* aggr1_smmu_cirpt[7] */ + <0xff 464>, /* ipa_bam_irq(0) */ + <0xff 465>, /* ipa_bam_irq(2) */ + <0xff 466>, /* ssc_uart_int */ + <0xff 468>, /* cri_cm_irq_tz */ + <0xff 469>, /* cri_cm_irq_hyp */ + <0xff 471>, /* mmss_bimc_smmu_gds_hw_ctrl_irq_out */ + <0xff 472>, /* gcc_gds_hw_ctrl_irq_out */ + <0xff 473>, /* lcc_audio_core_smmu_gds_hw_ctrl */ + <0xff 477>, /* tsens0_tsens_critical_int */ + <0xff 478>, /* tsens0_tsens_max_min_int */ + <0xff 480>, /* q6ss_wdog_expired_irq */ + <0xff 481>, /* mss_ipc_out_irq[4] */ + <0xff 482>, /* mss_ipc_out_irq[5] */ + <0xff 483>, /* mss_ipc_out_irq[6] */ + <0xff 484>, /* mss_ipc_out_irq[7] */ + <0xff 485>, /* mss_ipc_out_irq[28] */ + <0xff 486>, /* mss_ipc_out_irq[29] */ + <0xff 487>, /* mss_ipc_out_irq[30] */ + <0xff 488>, /* mss_ipc_out_irq[31] */ + <0xff 489>, /* skl_core_irq */ + <0xff 490>, /* tsens0_upper_lower_int */ + <0xff 494>, /* osmmu_CIrpt[6] */ + <0xff 495>, /* osmmu_CIrpt[7] */ + <0xff 496>, /* osmmu_CIrpt[8] */ + <0xff 497>, /* osmmu_CIrpt[9] */ + <0xff 498>, /* osmmu_CIrpt[10] */ + <0xff 499>, /* osmmu_CIrpt[11] */ + <0xff 503>; /* o_bimc_intr[1] */ qcom,gpio-parent = <&tlmm>; qcom,gpio-map = <3 1>, diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi index 3bb5943634f2..b484b94692b5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi @@ -58,3 +58,10 @@ < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >, < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >; }; + +&mdss_mdp { + qcom,vbif-settings = <0x00d0 0x00002020>; + qcom,max-bandwidth-low-kbps = <9400000>; + qcom,max-bandwidth-high-kbps = <9400000>; + qcom,max-bandwidth-per-pipe-kbps = <4700000>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 33e8c9c4993d..0e2cc7361e1b 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -1751,7 +1751,7 @@ qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <61 512 0 0>, - <61 512 240000 960000>; + <61 512 240000 800000>; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; extcon = <&pmicobalt_pdphy>; @@ -1766,6 +1766,7 @@ clock-names = "core_clk", "iface_clk", "bus_aggr_clk", "utmi_clk", "sleep_clk", "xo"; + qcom,core-clk-rate = <120000000>; dwc3@a800000 { compatible = "snps,dwc3"; reg = <0x0a800000 0xcd00>; @@ -2806,7 +2807,7 @@ qcom,qsee-ipc-irq-spss { qcom,rx-irq-clr = <0x1d08008 0x4>; - qcom,rx-irq-clr-mask = <0x2>; + qcom,rx-irq-clr-mask = <0x1>; qcom,dev-name = "qsee_ipc_irq_spss"; interrupts = <0 349 4>; label = "spss"; @@ -2841,10 +2842,6 @@ }; &gdsc_ufs { - clock-names = "bus_clk", "ice_clk", "unipro_clk"; - clocks = <&clock_gcc clk_gcc_ufs_axi_clk>, - <&clock_gcc clk_gcc_ufs_ice_core_clk>, - <&clock_gcc clk_gcc_ufs_unipro_core_clk>; status = "ok"; }; @@ -2947,6 +2944,7 @@ #include "msmcobalt-pm.dtsi" #include "msm-arm-smmu-cobalt.dtsi" +#include "msm-arm-smmu-impl-defs-cobalt.dtsi" #include "msmcobalt-ion.dtsi" #include "msmcobalt-camera.dtsi" #include "msmcobalt-vidc.dtsi" diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 9ccf55322de1..4b3ebd3d1636 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -314,6 +314,16 @@ #clock-cells = <1>; }; + clock_mmss: qcom,dummycc { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + }; + + clock_gfx: qcom,dummycc { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + }; + qcom,ipc-spinlock@1f40000 { compatible = "qcom,ipc-spinlock-sfpb"; reg = <0x1f40000 0x8000>; diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 3a9fcfc95d00..1f9740b86e43 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -11,6 +11,7 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_RT_GROUP_SCHED=y CONFIG_SCHED_HMP=y @@ -238,8 +239,11 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_NETDEVICES=y @@ -383,6 +387,7 @@ CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_HDMI_PANEL=y CONFIG_FB_MSM_MDSS_DP_PANEL=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set @@ -467,6 +472,7 @@ CONFIG_GSI=y CONFIG_IPA3=y CONFIG_RMNET_IPA3=y CONFIG_GPIO_USB_DETECT=y +CONFIG_SEEMP_CORE=y CONFIG_USB_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index a3bad54c0b5b..ba867a7573e6 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -11,6 +11,7 @@ CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUPS=y CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y @@ -240,8 +241,11 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_NETDEVICES=y @@ -386,6 +390,7 @@ CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_HDMI_PANEL=y CONFIG_FB_MSM_MDSS_DP_PANEL=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set @@ -477,6 +482,7 @@ CONFIG_GSI=y CONFIG_IPA3=y CONFIG_RMNET_IPA3=y CONFIG_GPIO_USB_DETECT=y +CONFIG_SEEMP_CORE=y CONFIG_USB_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c index 3b3d1b2e37b1..a88ae0f59e63 100644 --- a/drivers/bluetooth/btfm_slim.c +++ b/drivers/bluetooth/btfm_slim.c @@ -132,7 +132,8 @@ int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, /* Define the channel with below parameters */ prop.prot = SLIM_AUTO_ISO; prop.baser = SLIM_RATE_4000HZ; - prop.dataf = SLIM_CH_DATAF_LPCM_AUDIO; + prop.dataf = (rates == 48000) ? SLIM_CH_DATAF_NOT_DEFINED + : SLIM_CH_DATAF_LPCM_AUDIO; prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE; prop.ratem = (rates/4000); prop.sampleszbits = 16; diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h index 1161708d6a90..dbb4c563d802 100644 --- a/drivers/bluetooth/btfm_slim.h +++ b/drivers/bluetooth/btfm_slim.h @@ -39,7 +39,7 @@ enum { BTFM_FM_SLIM_TX = 0, BTFM_BT_SCO_SLIM_TX, - BTFM_BT_SCO_SLIM_RX, + BTFM_BT_SCO_A2DP_SLIM_RX, BTFM_BT_SPLIT_A2DP_SLIM_RX, BTFM_SLIM_NUM_CODEC_DAIS }; diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index 2194b8cc6f6f..d7d24ff07801 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -102,7 +102,7 @@ int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, ch = btfmslim->tx_chs; rxport = 0; break; - case BTFM_BT_SCO_SLIM_RX: + case BTFM_BT_SCO_A2DP_SLIM_RX: case BTFM_BT_SPLIT_A2DP_SLIM_RX: ch = btfmslim->rx_chs; rxport = 1; @@ -150,7 +150,7 @@ int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream, ch = btfmslim->tx_chs; rxport = 0; break; - case BTFM_BT_SCO_SLIM_RX: + case BTFM_BT_SCO_A2DP_SLIM_RX: case BTFM_BT_SPLIT_A2DP_SLIM_RX: ch = btfmslim->rx_chs; rxport = 1; @@ -267,7 +267,7 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai, *tx_num = num; *rx_num = 0; break; - case BTFM_BT_SCO_SLIM_RX: + case BTFM_BT_SCO_A2DP_SLIM_RX: case BTFM_BT_SPLIT_A2DP_SLIM_RX: if (!rx_slot || !rx_num) { BTFMSLIM_ERR("Invalid rx_slot %p or rx_num %p", @@ -335,7 +335,7 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { }, .ops = &btfmslim_dai_ops, }, - { /* Bluetooth SCO NBS voice uplink: bt -> modem */ + { /* Bluetooth SCO voice uplink: bt -> modem */ .name = "btfm_bt_sco_slim_tx", .id = BTFM_BT_SCO_SLIM_TX, .capture = { @@ -350,15 +350,15 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { }, .ops = &btfmslim_dai_ops, }, - { /* Bluetooth SCO NBS voice downlink: modem -> bt */ - .name = "btfm_bt_sco_slim_rx", - .id = BTFM_BT_SCO_SLIM_RX, + { /* Bluetooth SCO voice downlink: modem -> bt or A2DP Playback */ + .name = "btfm_bt_sco_a2dp_slim_rx", + .id = BTFM_BT_SCO_A2DP_SLIM_RX, .playback = { - .stream_name = "SCO RX Playback", - /* 8 KHz or 16 KHz */ - .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .stream_name = "SCO A2DP RX Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 + | SNDRV_PCM_RATE_48000, /* 8 or 16 or 48 Khz*/ .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ - .rate_max = 16000, + .rate_max = 48000, .rate_min = 8000, .channels_min = 1, .channels_max = 1, diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index 3300085be9a7..7d7bd2441c6e 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -15,7 +15,7 @@ /* WCN3990 Port assignment */ struct btfmslim_ch wcn3990_rxport[] = { - {.id = BTFM_BT_SCO_SLIM_RX, .name = "SCO_Rx", + {.id = BTFM_BT_SCO_A2DP_SLIM_RX, .name = "SCO_A2P_Rx", .port = CHRK_SB_PGD_PORT_RX_SCO}, {.id = BTFM_BT_SPLIT_A2DP_SLIM_RX, .name = "A2P_Rx", .port = CHRK_SB_PGD_PORT_RX_A2P}, diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile index ecf0b09bb49a..baf22bf1df9a 100644 --- a/drivers/clk/msm/Makefile +++ b/drivers/clk/msm/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COMMON_CLK_MSM) += clock-pll.o obj-$(CONFIG_COMMON_CLK_MSM) += clock-alpha-pll.o obj-$(CONFIG_COMMON_CLK_MSM) += clock-rpm.o obj-$(CONFIG_COMMON_CLK_MSM) += clock-voter.o +obj-$(CONFIG_COMMON_CLK_MSM) += reset.o obj-$(CONFIG_MSM_CLK_CONTROLLER_V2) += msm-clock-controller.o diff --git a/drivers/clk/msm/clock-gcc-8996.c b/drivers/clk/msm/clock-gcc-8996.c index edd78e29957d..a9e0b53c3b22 100644 --- a/drivers/clk/msm/clock-gcc-8996.c +++ b/drivers/clk/msm/clock-gcc-8996.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-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 @@ -31,6 +31,7 @@ #include <dt-bindings/clock/msm-clocks-8996.h> #include <dt-bindings/clock/msm-clocks-hwio-8996.h> +#include "reset.h" #include "vdd-level-8996.h" static void __iomem *virt_base; @@ -3142,6 +3143,26 @@ static struct branch_clk gcc_aggre0_noc_mpu_cfg_ahb_clk = { }, }; +static const struct msm_reset_map gcc_msm8996_resets[] = { + [QUSB2PHY_PRIM_BCR] = { 0x12038 }, + [QUSB2PHY_SEC_BCR] = { 0x1203c }, + [BLSP1_BCR] = { 0x17000 }, + [BLSP2_BCR] = { 0x25000 }, + [BOOT_ROM_BCR] = { 0x38000 }, + [PRNG_BCR] = { 0x34000 }, + [UFS_BCR] = { 0x75000 }, + [USB_20_BCR] = { 0x12000 }, + [USB_30_BCR] = { 0x0f000 }, + [USB3_PHY_BCR] = { 0x50020 }, + [USB3PHY_PHY_BCR] = { 0x50024 }, + [PCIE_0_PHY_BCR] = { 0x6c01c }, + [PCIE_1_PHY_BCR] = { 0x6d038 }, + [PCIE_2_PHY_BCR] = { 0x6e038 }, + [PCIE_PHY_BCR] = { 0x6f000 }, + [PCIE_PHY_NOCSR_COM_PHY_BCR] = { 0x6f00C }, + [PCIE_PHY_COM_BCR] = { 0x6f014 }, +}; + static struct mux_clk gcc_debug_mux; static struct mux_clk gcc_debug_mux_v2; static struct clk_ops clk_ops_debug_mux; @@ -3711,6 +3732,10 @@ static int msm_gcc_8996_probe(struct platform_device *pdev) */ clk_set_flags(&gcc_mmss_bimc_gfx_clk.c, CLKFLAG_RETAIN_MEM); + /* Register block resets */ + msm_reset_controller_register(pdev, gcc_msm8996_resets, + ARRAY_SIZE(gcc_msm8996_resets), virt_base); + dev_info(&pdev->dev, "Registered GCC clocks.\n"); return 0; } diff --git a/drivers/clk/msm/clock-mmss-8996.c b/drivers/clk/msm/clock-mmss-8996.c index ba81731ce1cb..91c871cae225 100644 --- a/drivers/clk/msm/clock-mmss-8996.c +++ b/drivers/clk/msm/clock-mmss-8996.c @@ -32,6 +32,7 @@ #include "vdd-level-8996.h" #include "clock.h" +#include "reset.h" static void __iomem *virt_base; static void __iomem *virt_base_gpu; @@ -3032,6 +3033,17 @@ static struct branch_clk vmem_maxi_clk = { }, }; +static const struct msm_reset_map mmss_msm8996_resets[] = { + [VIDEO_BCR] = { 0x1020 }, + [MDSS_BCR] = { 0x2300 }, + [CAMSS_MICRO_BCR] = { 0x3490 }, + [CAMSS_JPEG_BCR] = { 0x35a0 }, + [CAMSS_VFE0_BCR] = { 0x3660 }, + [CAMSS_VFE1_BCR] = { 0x3670 }, + [FD_BCR] = { 0x3b60 }, + [GPU_GX_BCR] = { 0x4020 }, +}; + static struct mux_clk mmss_gcc_dbg_clk = { .ops = &mux_reg_ops, .en_mask = BIT(16), @@ -3778,6 +3790,11 @@ int msm_mmsscc_8996_probe(struct platform_device *pdev) if (rc) return rc; } + + /* Register block resets */ + msm_reset_controller_register(pdev, mmss_msm8996_resets, + ARRAY_SIZE(mmss_msm8996_resets), virt_base); + dev_info(&pdev->dev, "Registered MMSS clocks.\n"); return platform_driver_register(&msm_clock_gpu_driver); diff --git a/drivers/clk/msm/gdsc.c b/drivers/clk/msm/gdsc.c index 5ea2a9ccd1bb..cdaba72532d4 100644 --- a/drivers/clk/msm/gdsc.c +++ b/drivers/clk/msm/gdsc.c @@ -20,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/reset.h> #include <linux/regulator/of_regulator.h> #include <linux/slab.h> #include <linux/clk.h> @@ -48,7 +49,9 @@ struct gdsc { struct regulator_desc rdesc; void __iomem *gdscr; struct clk **clocks; + struct reset_control **reset_clocks; int clock_count; + int reset_count; bool toggle_mem; bool toggle_periph; bool toggle_logic; @@ -247,9 +250,8 @@ static int gdsc_enable(struct regulator_dev *rdev) } } } else { - for (i = 0; i < sc->clock_count; i++) - if (likely(i != sc->root_clk_idx)) - clk_reset(sc->clocks[i], CLK_RESET_DEASSERT); + for (i = 0; i < sc->reset_count; i++) + reset_control_deassert(sc->reset_clocks[i]); sc->resets_asserted = false; } @@ -342,9 +344,8 @@ static int gdsc_disable(struct regulator_dev *rdev) wmb(); } } else { - for (i = sc->clock_count-1; i >= 0; i--) - if (likely(i != sc->root_clk_idx)) - clk_reset(sc->clocks[i], CLK_RESET_ASSERT); + for (i = sc->reset_count-1; i >= 0; i--) + reset_control_assert(sc->reset_clocks[i]); sc->resets_asserted = true; } @@ -605,6 +606,39 @@ static int gdsc_probe(struct platform_device *pdev) } if (!sc->toggle_logic) { + sc->reset_count = of_property_count_strings(pdev->dev.of_node, + "reset-names"); + if (sc->reset_count == -EINVAL) { + sc->reset_count = 0; + } else if (IS_ERR_VALUE(sc->reset_count)) { + dev_err(&pdev->dev, "Failed to get reset reset names\n"); + return -EINVAL; + } + + sc->reset_clocks = devm_kzalloc(&pdev->dev, + sizeof(struct reset_control *) * + sc->reset_count, + GFP_KERNEL); + if (!sc->reset_clocks) + return -ENOMEM; + + for (i = 0; i < sc->reset_count; i++) { + const char *reset_name; + + of_property_read_string_index(pdev->dev.of_node, + "reset-names", i, &reset_name); + sc->reset_clocks[i] = devm_reset_control_get(&pdev->dev, + reset_name); + if (IS_ERR(sc->reset_clocks[i])) { + int rc = PTR_ERR(sc->reset_clocks[i]); + + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get %s\n", + reset_name); + return rc; + } + } + regval &= ~SW_COLLAPSE_MASK; writel_relaxed(regval, sc->gdscr); diff --git a/drivers/clk/msm/reset.c b/drivers/clk/msm/reset.c new file mode 100644 index 000000000000..41e0357aea3e --- /dev/null +++ b/drivers/clk/msm/reset.c @@ -0,0 +1,94 @@ +/* + * 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/device.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/reset-controller.h> + +#include "reset.h" + +static int msm_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + rcdev->ops->assert(rcdev, id); + udelay(1); + rcdev->ops->deassert(rcdev, id); + return 0; +} + +static int +msm_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct msm_reset_controller *rst; + const struct msm_reset_map *map; + u32 regval; + + rst = to_msm_reset_controller(rcdev); + map = &rst->reset_map[id]; + + regval = readl_relaxed(rst->base + map->reg); + regval |= BIT(map->bit); + writel_relaxed(regval, rst->base + map->reg); + + return 0; +} + +static int +msm_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct msm_reset_controller *rst; + const struct msm_reset_map *map; + u32 regval; + + rst = to_msm_reset_controller(rcdev); + map = &rst->reset_map[id]; + + regval = readl_relaxed(rst->base + map->reg); + regval &= ~BIT(map->bit); + writel_relaxed(regval, rst->base + map->reg); + + return 0; +} + +struct reset_control_ops msm_reset_ops = { + .reset = msm_reset, + .assert = msm_reset_assert, + .deassert = msm_reset_deassert, +}; +EXPORT_SYMBOL_GPL(msm_reset_ops); + +int msm_reset_controller_register(struct platform_device *pdev, + const struct msm_reset_map *map, unsigned int num_resets, + void __iomem *virt_base) +{ + struct msm_reset_controller *reset; + int ret = 0; + + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); + if (!reset) + return -ENOMEM; + + reset->rcdev.of_node = pdev->dev.of_node; + reset->rcdev.ops = &msm_reset_ops; + reset->rcdev.owner = pdev->dev.driver->owner; + reset->rcdev.nr_resets = num_resets; + reset->reset_map = map; + reset->base = virt_base; + + ret = reset_controller_register(&reset->rcdev); + if (ret) + dev_err(&pdev->dev, "Failed to register with reset controller\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(msm_reset_controller_register); diff --git a/drivers/clk/msm/reset.h b/drivers/clk/msm/reset.h new file mode 100644 index 000000000000..538a432fed60 --- /dev/null +++ b/drivers/clk/msm/reset.h @@ -0,0 +1,39 @@ +/* + * 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 __DRIVERS_CLK_RESET_H +#define __DRIVERS_CLK_RESET_H + +#include <linux/platform_device.h> +#include <linux/reset-controller.h> + +struct msm_reset_map { + unsigned int reg; + u8 bit; +}; + +struct msm_reset_controller { + const struct msm_reset_map *reset_map; + struct reset_controller_dev rcdev; + void __iomem *base; +}; + +#define to_msm_reset_controller(r) \ + container_of(r, struct msm_reset_controller, rcdev) + +extern struct reset_control_ops msm_reset_ops; + +int msm_reset_controller_register(struct platform_device *pdev, + const struct msm_reset_map *map, unsigned int nr_resets, + void __iomem *virt_base); +#endif diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 3f8a3927ff92..2b0df3f0e04e 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -44,6 +44,7 @@ #include <asm/arch_timer.h> #include <asm/cacheflush.h> #include <asm/suspend.h> +#include <asm/cpuidle.h> #include "lpm-levels.h" #include "lpm-workarounds.h" #include <trace/events/power.h> @@ -914,7 +915,6 @@ unlock_and_return: } #if !defined(CONFIG_CPU_V7) -#include <asm/cpuidle.h> asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64); bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) { @@ -976,7 +976,7 @@ bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) update_debug_pc_event(CPU_ENTER, state_id, 0xdeaffeed, 0xdeaffeed, true); stop_critical_timings(); - success = !cpu_suspend(state_id); + success = !arm_cpuidle_suspend(state_id); start_critical_timings(); update_debug_pc_event(CPU_EXIT, state_id, success, 0xdeaffeed, true); diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 3e856d0bbbe9..795d553f3318 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1237,6 +1237,13 @@ static void qcom_ice_debug(struct platform_device *pdev) qcom_ice_readl(ice_dev, QCOM_ICE_REGS_NON_SEC_IRQ_MASK), qcom_ice_readl(ice_dev, QCOM_ICE_REGS_NON_SEC_IRQ_CLR)); + if (ICE_REV(ice_dev->ice_hw_version, MAJOR) > 2) { + pr_err("%s: ICE INVALID CCFG ERR STTS: 0x%08x\n", + ice_dev->ice_instance_type, + qcom_ice_readl(ice_dev, + QCOM_ICE_INVALID_CCFG_ERR_STTS)); + } + if ((ICE_REV(ice_dev->ice_hw_version, MAJOR) > 2) || ((ICE_REV(ice_dev->ice_hw_version, MAJOR) == 2) && (ICE_REV(ice_dev->ice_hw_version, MINOR) >= 1))) { diff --git a/drivers/crypto/msm/iceregs.h b/drivers/crypto/msm/iceregs.h index 4fa682e4a26d..b59dccb679da 100644 --- a/drivers/crypto/msm/iceregs.h +++ b/drivers/crypto/msm/iceregs.h @@ -39,8 +39,19 @@ #define QCOM_ICE_REGS_PARAMETERS_3 0x001C #define QCOM_ICE_REGS_PARAMETERS_4 0x0020 #define QCOM_ICE_REGS_PARAMETERS_5 0x0024 + + +/* QCOM ICE v3.X only */ +#define QCOM_ICE_GENERAL_ERR_STTS 0x0040 +#define QCOM_ICE_INVALID_CCFG_ERR_STTS 0x0030 +#define QCOM_ICE_GENERAL_ERR_MASK 0x0044 + + +/* QCOM ICE v2.X only */ #define QCOM_ICE_REGS_NON_SEC_IRQ_STTS 0x0040 #define QCOM_ICE_REGS_NON_SEC_IRQ_MASK 0x0044 + + #define QCOM_ICE_REGS_NON_SEC_IRQ_CLR 0x0048 #define QCOM_ICE_REGS_STREAM1_ERROR_SYNDROME1 0x0050 #define QCOM_ICE_REGS_STREAM1_ERROR_SYNDROME2 0x0054 diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 11b323e9d40c..7ad7fdfb8181 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -2647,8 +2647,10 @@ void kgsl_active_count_put(struct kgsl_device *device) device->requested_state == KGSL_STATE_NONE) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP); kgsl_schedule_work(&device->idle_check_ws); - } else if (!nap_on) + } else if (!nap_on) { kgsl_pwrscale_update_stats(device); + kgsl_pwrscale_update(device); + } mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 529edb16565a..69028bd45fdd 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1110,6 +1110,17 @@ config TOUCHSCREEN_COLIBRI_VF50 To compile this driver as a module, choose M here: the module will be called colibri_vf50_ts. +config TOUCHSCREEN_MSTAR21XX + tristate "Mstar touchscreens" + depends on I2C + help + Say Y here if you have a mstar touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called msg21xx_ts. + config TOUCHSCREEN_ROHM_BU21023 tristate "ROHM BU21023/24 Dual touch support resistive touchscreens" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index e04e787cea6e..e1777f11d77b 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -97,3 +97,4 @@ obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o +obj-$(CONFIG_TOUCHSCREEN_MSTAR21XX) += msg21xx_ts.o diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index d619c1d06e9e..45ce036b1693 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -3,7 +3,7 @@ * FocalTech ft5x06 TouchScreen driver. * * Copyright (c) 2010 Focal tech Ltd. - * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2012-2016, 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 @@ -24,13 +24,19 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/regulator/consumer.h> +#include <linux/firmware.h> #include <linux/input/ft5x06_ts.h> -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_FB) +#include <linux/notifier.h> +#include <linux/fb.h> + +#elif defined(CONFIG_HAS_EARLYSUSPEND) #include <linux/earlysuspend.h> /* Early-suspend level */ -#define FT5X06_SUSPEND_LEVEL 1 +#define FT_SUSPEND_LEVEL 1 #endif #define CFG_MAX_TOUCH_POINTS 5 @@ -50,33 +56,136 @@ #define POINT_READ_BUF (3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS) -/*register address*/ -#define FT5X06_REG_PMODE 0xA5 -#define FT5X06_REG_FW_VER 0xA6 -#define FT5X06_REG_POINT_RATE 0x88 -#define FT5X06_REG_THGROUP 0x80 - -/* power register bits*/ -#define FT5X06_PMODE_ACTIVE 0x00 -#define FT5X06_PMODE_MONITOR 0x01 -#define FT5X06_PMODE_STANDBY 0x02 -#define FT5X06_PMODE_HIBERNATE 0x03 - -#define FT5X06_VTG_MIN_UV 2600000 -#define FT5X06_VTG_MAX_UV 3300000 -#define FT5X06_I2C_VTG_MIN_UV 1800000 -#define FT5X06_I2C_VTG_MAX_UV 1800000 +/* register address*/ +#define FT_REG_DEV_MODE 0x00 +#define FT_DEV_MODE_REG_CAL 0x02 +#define FT_REG_ID 0xA3 +#define FT_REG_PMODE 0xA5 +#define FT_REG_FW_VER 0xA6 +#define FT_REG_POINT_RATE 0x88 +#define FT_REG_THGROUP 0x80 +#define FT_REG_ECC 0xCC +#define FT_REG_RESET_FW 0x07 + +/* power register bits */ +#define FT_PMODE_ACTIVE 0x00 +#define FT_PMODE_MONITOR 0x01 +#define FT_PMODE_STANDBY 0x02 +#define FT_PMODE_HIBERNATE 0x03 +#define FT_FACTORYMODE_VALUE 0x40 +#define FT_WORKMODE_VALUE 0x00 +#define FT_RST_CMD_REG 0xFC +#define FT_READ_ID_REG 0x90 +#define FT_ERASE_APP_REG 0x61 +#define FT_ERASE_PANEL_REG 0x63 +#define FT_FW_START_REG 0xBF + + +#define FT_VTG_MIN_UV 2600000 +#define FT_VTG_MAX_UV 3300000 +#define FT_I2C_VTG_MIN_UV 1800000 +#define FT_I2C_VTG_MAX_UV 1800000 + +#define FT_COORDS_ARR_SIZE 4 +#define MAX_BUTTONS 4 + +#define FT_8BIT_SHIFT 8 +#define FT_4BIT_SHIFT 4 +#define FT_FW_NAME_MAX_LEN 50 + +#define FT5316_ID 0x0A +#define FT5306I_ID 0x55 + +#define FT_UPGRADE_AA 0xAA +#define FT_UPGRADE_55 0x55 + +/* upgrade config of FT5606 */ +#define FT5606_UPGRADE_AA_DELAY 50 +#define FT5606_UPGRADE_55_DELAY 10 +#define FT5606_UPGRADE_ID_1 0x79 +#define FT5606_UPGRADE_ID_2 0x06 +#define FT5606_UPGRADE_READID_DELAY 100 +#define FT5606_UPGRADE_EARSE_DELAY 2000 + +/* upgrade config of FT5316 */ +#define FT5316_UPGRADE_AA_DELAY 50 +#define FT5316_UPGRADE_55_DELAY 30 +#define FT5316_UPGRADE_ID_1 0x79 +#define FT5316_UPGRADE_ID_2 0x07 +#define FT5316_UPGRADE_READID_DELAY 1 +#define FT5316_UPGRADE_EARSE_DELAY 1500 + +/* upgrade config of FT5x06(x=2,3,4) */ +#define FT5X06_UPGRADE_AA_DELAY 50 +#define FT5X06_UPGRADE_55_DELAY 30 +#define FT5X06_UPGRADE_ID_1 0x79 +#define FT5X06_UPGRADE_ID_2 0x03 +#define FT5X06_UPGRADE_READID_DELAY 1 +#define FT5X06_UPGRADE_EARSE_DELAY 2000 + +/* upgrade config of FT6208 */ +#define FT6208_UPGRADE_AA_DELAY 60 +#define FT6208_UPGRADE_55_DELAY 10 +#define FT6208_UPGRADE_ID_1 0x79 +#define FT6208_UPGRADE_ID_2 0x05 +#define FT6208_UPGRADE_READID_DELAY 10 +#define FT6208_UPGRADE_EARSE_DELAY 2000 + +#define FT_UPGRADE_INFO(x, y) do { \ + x->delay_55 = y##_UPGRADE_55_DELAY; \ + x->delay_aa = y##_UPGRADE_AA_DELAY; \ + x->upgrade_id_1 = y##_UPGRADE_ID_1; \ + x->upgrade_id_2 = y##_UPGRADE_ID_2; \ + x->delay_readid = y##_UPGRADE_READID_DELAY; \ + x->delay_earse_flash = y##_UPGRADE_EARSE_DELAY; \ + } while (0) + +#define FT_FW_MIN_SIZE 8 +#define FT_FW_MAX_SIZE 32768 +#define FT_FW_FILE_VER(x) ((x)->data[(x)->size - 2]) +#define FT_FW_CHECK(x) \ + (((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \ + && (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \ + && (((x)->data[(x)->size - 3] ^ (x)->data[(x)->size - 4]) == 0xFF))) + +#define FT_MAX_TRIES 5 +#define FT_RETRY_DLY 20 + +#define FT_MAX_WR_BUF 10 +#define FT_MAX_RD_BUF 2 +#define FT_FW_PKT_LEN 128 +#define FT_FW_PKT_META_LEN 6 +#define FT_FW_PKT_DLY_MS 20 +#define FT_FW_LAST_PKT 0x6ffa +#define FT_EARSE_DLY_MS 100 + +#define FT_UPGRADE_LOOP 3 +#define FT_CAL_START 0x04 +#define FT_CAL_FIN 0x00 +#define FT_CAL_STORE 0x05 +#define FT_CAL_RETRY 100 +#define FT_REG_CAL 0x00 +#define FT_CAL_MASK 0x70 struct ts_event { - u16 x[CFG_MAX_TOUCH_POINTS]; /*x coordinate */ - u16 y[CFG_MAX_TOUCH_POINTS]; /*y coordinate */ + u16 x[CFG_MAX_TOUCH_POINTS]; /* x coordinate */ + u16 y[CFG_MAX_TOUCH_POINTS]; /* y coordinate */ /* touch event: 0 -- down; 1-- contact; 2 -- contact */ u8 touch_event[CFG_MAX_TOUCH_POINTS]; - u8 finger_id[CFG_MAX_TOUCH_POINTS]; /*touch ID */ + u8 finger_id[CFG_MAX_TOUCH_POINTS]; /* touch ID */ u16 pressure; u8 touch_point; }; +struct upgrade_info { + u16 delay_aa; /* delay of write FT_UPGRADE_AA */ + u16 delay_55; /* delay of write FT_UPGRADE_55 */ + u8 upgrade_id_1; /* upgrade id 1 */ + u8 upgrade_id_2; /* upgrade id 2 */ + u16 delay_readid; /* delay of read id */ + u16 delay_earse_flash; /* delay of earse flash */ +}; + struct ft5x06_ts_data { struct i2c_client *client; struct input_dev *input_dev; @@ -84,7 +193,12 @@ struct ft5x06_ts_data { const struct ft5x06_ts_platform_data *pdata; struct regulator *vdd; struct regulator *vcc_i2c; -#ifdef CONFIG_HAS_EARLYSUSPEND + char fw_name[FT_FW_NAME_MAX_LEN]; + bool loading_fw; + u8 family_id; +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) struct early_suspend early_suspend; #endif }; @@ -149,6 +263,21 @@ static int ft5x06_i2c_write(struct i2c_client *client, char *writebuf, return ret; } +static int ft5x0x_write_reg(struct i2c_client *client, u8 addr, const u8 val) +{ + u8 buf[2] = {0}; + + buf[0] = addr; + buf[1] = val; + + return ft5x06_i2c_write(client, buf, sizeof(buf)); +} + +static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val) +{ + return ft5x06_i2c_read(client, &addr, 1, val, 1); +} + static void ft5x06_report_value(struct ft5x06_ts_data *data) { struct ts_event *event = &data->event; @@ -289,8 +418,8 @@ static int ft5x06_power_init(struct ft5x06_ts_data *data, bool on) } if (regulator_count_voltages(data->vdd) > 0) { - rc = regulator_set_voltage(data->vdd, FT5X06_VTG_MIN_UV, - FT5X06_VTG_MAX_UV); + rc = regulator_set_voltage(data->vdd, FT_VTG_MIN_UV, + FT_VTG_MAX_UV); if (rc) { dev_err(&data->client->dev, "Regulator set_vtg failed vdd rc=%d\n", rc); @@ -307,8 +436,8 @@ static int ft5x06_power_init(struct ft5x06_ts_data *data, bool on) } if (regulator_count_voltages(data->vcc_i2c) > 0) { - rc = regulator_set_voltage(data->vcc_i2c, FT5X06_I2C_VTG_MIN_UV, - FT5X06_I2C_VTG_MAX_UV); + rc = regulator_set_voltage(data->vcc_i2c, FT_I2C_VTG_MIN_UV, + FT_I2C_VTG_MAX_UV); if (rc) { dev_err(&data->client->dev, "Regulator set_vtg failed vcc_i2c rc=%d\n", rc); @@ -322,19 +451,19 @@ reg_vcc_i2c_put: regulator_put(data->vcc_i2c); reg_vdd_set_vtg: if (regulator_count_voltages(data->vdd) > 0) - regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV); + regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV); reg_vdd_put: regulator_put(data->vdd); return rc; pwr_deinit: if (regulator_count_voltages(data->vdd) > 0) - regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV); + regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV); regulator_put(data->vdd); if (regulator_count_voltages(data->vcc_i2c) > 0) - regulator_set_voltage(data->vcc_i2c, 0, FT5X06_I2C_VTG_MAX_UV); + regulator_set_voltage(data->vcc_i2c, 0, FT_I2C_VTG_MAX_UV); regulator_put(data->vcc_i2c); return 0; @@ -349,8 +478,8 @@ static int ft5x06_ts_suspend(struct device *dev) disable_irq(data->client->irq); if (gpio_is_valid(data->pdata->reset_gpio)) { - txbuf[0] = FT5X06_REG_PMODE; - txbuf[1] = FT5X06_PMODE_HIBERNATE; + txbuf[0] = FT_REG_PMODE; + txbuf[1] = FT_PMODE_HIBERNATE; ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf)); } @@ -371,7 +500,27 @@ static int ft5x06_ts_resume(struct device *dev) return 0; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct ft5x06_ts_data *ft5x06_data = + container_of(self, struct ft5x06_ts_data, fb_notif); + + if (evdata && evdata->data && event == FB_EVENT_BLANK && + ft5x06_data && ft5x06_data->client) { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK) + ft5x06_ts_resume(&ft5x06_data->client->dev); + else if (*blank == FB_BLANK_POWERDOWN) + ft5x06_ts_suspend(&ft5x06_data->client->dev); + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) static void ft5x06_ts_early_suspend(struct early_suspend *handler) { struct ft5x06_ts_data *data = container_of(handler, @@ -392,23 +541,478 @@ static void ft5x06_ts_late_resume(struct early_suspend *handler) #endif static const struct dev_pm_ops ft5x06_ts_pm_ops = { -#ifndef CONFIG_HAS_EARLYSUSPEND +#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND)) .suspend = ft5x06_ts_suspend, .resume = ft5x06_ts_resume, #endif }; #endif +static int ft5x06_auto_cal(struct i2c_client *client) +{ + u8 temp = 0, i; + + /* set to factory mode */ + msleep(2 * FT_STARTUP_DLY); + ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE); + msleep(FT_STARTUP_DLY); + + /* start calibration */ + ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START); + msleep(2 * FT_STARTUP_DLY); + for (i = 0; i < FT_CAL_RETRY; i++) { + ft5x0x_read_reg(client, FT_REG_CAL, &temp); + /* return to normal mode, calibration finish */ + if (((temp & FT_CAL_MASK) >> FT_4BIT_SHIFT) == FT_CAL_FIN) + break; + } + + /* calibration OK */ + msleep(2 * FT_STARTUP_DLY); + ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE); + msleep(FT_STARTUP_DLY); + + /* store calibration data */ + ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE); + msleep(2 * FT_STARTUP_DLY); + + /* set to normal mode */ + ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE); + msleep(2 * FT_STARTUP_DLY); + + return 0; +} + +static int ft5x06_get_upgrade_info(u8 family_id, struct upgrade_info *info) +{ + switch (family_id) { + case FT5306I_ID: + FT_UPGRADE_INFO(info, FT5X06); + break; + case FT5316_ID: + FT_UPGRADE_INFO(info, FT5316); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ft5x06_fw_upgrade_start(struct i2c_client *client, + const u8 *data, u32 data_len) +{ + struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client); + struct upgrade_info info; + u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0}; + u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN]; + int rc, i, j, temp; + u32 pkt_num, pkt_len; + u8 fw_ecc; + + rc = ft5x06_get_upgrade_info(ts_data->family_id, &info); + if (rc < 0) { + dev_err(&client->dev, "Cannot get upgrade information!\n"); + return -EINVAL; + } + + for (i = 0; i < FT_UPGRADE_LOOP; i++) { + /* reset - write 0xaa and 0x55 to register 0xfc */ + ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_AA); + msleep(info.delay_aa); + + ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_55); + msleep(info.delay_55); + + /* Enter upgrade mode */ + w_buf[0] = FT_UPGRADE_55; + w_buf[1] = FT_UPGRADE_AA; + do { + i++; + rc = ft5x06_i2c_write(client, w_buf, 2); + msleep(FT_RETRY_DLY); + } while (rc <= 0 && i < FT_MAX_TRIES); + + /* check READ_ID */ + msleep(info.delay_readid); + w_buf[0] = FT_READ_ID_REG; + w_buf[1] = 0x00; + w_buf[2] = 0x00; + w_buf[3] = 0x00; + + ft5x06_i2c_read(client, w_buf, 4, r_buf, 2); + + if (r_buf[0] != info.upgrade_id_1 + || r_buf[1] != info.upgrade_id_2) { + dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i); + } else + break; + } + + if (i >= FT_UPGRADE_LOOP) { + dev_err(&client->dev, "Abort upgrade\n"); + return -EIO; + } + + /* erase app and panel paramenter area */ + w_buf[0] = FT_ERASE_APP_REG; + ft5x06_i2c_write(client, w_buf, 1); + msleep(info.delay_earse_flash); + + w_buf[0] = FT_ERASE_PANEL_REG; + ft5x06_i2c_write(client, w_buf, 1); + msleep(FT_EARSE_DLY_MS); + + /* program firmware */ + data_len = data_len - 8; + pkt_num = (data_len) / FT_FW_PKT_LEN; + pkt_len = FT_FW_PKT_LEN; + pkt_buf[0] = FT_FW_START_REG; + pkt_buf[1] = 0x00; + fw_ecc = 0; + + for (i = 0; i < pkt_num; i++) { + temp = i * FT_FW_PKT_LEN; + pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT); + pkt_buf[3] = (u8) temp; + pkt_buf[4] = (u8) (pkt_len >> FT_8BIT_SHIFT); + pkt_buf[5] = (u8) pkt_len; + + for (j = 0; j < FT_FW_PKT_LEN; j++) { + pkt_buf[6 + j] = data[i * FT_FW_PKT_LEN + j]; + fw_ecc ^= pkt_buf[6 + j]; + } + + ft5x06_i2c_write(client, pkt_buf, + FT_FW_PKT_LEN + FT_FW_PKT_META_LEN); + msleep(FT_FW_PKT_DLY_MS); + } + + /* send remaining bytes */ + if ((data_len) % FT_FW_PKT_LEN > 0) { + temp = pkt_num * FT_FW_PKT_LEN; + pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT); + pkt_buf[3] = (u8) temp; + temp = (data_len) % FT_FW_PKT_LEN; + pkt_buf[4] = (u8) (temp >> FT_8BIT_SHIFT); + pkt_buf[5] = (u8) temp; + + for (i = 0; i < temp; i++) { + pkt_buf[6 + i] = data[pkt_num * FT_FW_PKT_LEN + i]; + fw_ecc ^= pkt_buf[6 + i]; + } + + ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN); + msleep(FT_FW_PKT_DLY_MS); + } + + /* send the finishing packet */ + for (i = 0; i < 6; i++) { + temp = FT_FW_LAST_PKT + i; + pkt_buf[2] = (u8) (temp >> 8); + pkt_buf[3] = (u8) temp; + temp = 1; + pkt_buf[4] = (u8) (temp >> 8); + pkt_buf[5] = (u8) temp; + pkt_buf[6] = data[data_len + i]; + fw_ecc ^= pkt_buf[6]; + ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN); + msleep(FT_FW_PKT_DLY_MS); + } + + /* verify checksum */ + w_buf[0] = FT_REG_ECC; + ft5x06_i2c_read(client, w_buf, 1, r_buf, 1); + if (r_buf[0] != fw_ecc) { + dev_err(&client->dev, "ECC error! dev_ecc=%02x fw_ecc=%02x\n", + r_buf[0], fw_ecc); + return -EIO; + } + + /* reset */ + w_buf[0] = FT_REG_RESET_FW; + ft5x06_i2c_write(client, w_buf, 1); + msleep(FT_STARTUP_DLY); + + return 0; +} + +static int ft5x06_fw_upgrade(struct device *dev, bool force) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + const struct firmware *fw = NULL; + int rc; + u8 val = 0; + + rc = request_firmware(&fw, data->fw_name, dev); + if (rc < 0) { + dev_err(dev, "Request firmware failed - %s (%d)\n", + data->fw_name, rc); + return rc; + } + + if (fw->size < FT_FW_MIN_SIZE || fw->size > FT_FW_MAX_SIZE) { + dev_err(dev, "Invalid firmware size (%d)\n", fw->size); + rc = -EIO; + goto rel_fw; + } + + /* check firmware version */ + rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val); + if (rc < 0) { + dev_err(dev, "Get firmware version failed\n"); + goto rel_fw; + } + + if (val == FT_FW_FILE_VER(fw) && !force) { + dev_err(dev, "No need to update (0x%x)\n", val); + rc = -EFAULT; + goto rel_fw; + } + + dev_info(dev, "upgrade to fw ver 0x%x from 0x%x\n", + FT_FW_FILE_VER(fw), val); + + /* start firmware upgrade */ + if (FT_FW_CHECK(fw)) { + rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size); + if (rc < 0) + dev_err(dev, "update failed (%d)\n", rc); + else + ft5x06_auto_cal(data->client); + } else { + dev_err(dev, "FW format error\n"); + rc = -EIO; + } + +rel_fw: + release_firmware(fw); + return rc; +} + +static ssize_t ft5x06_update_fw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 2, "%d\n", data->loading_fw); +} + +static ssize_t ft5x06_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + unsigned long val; + int rc; + + if (size > 2) + return -EINVAL; + + rc = kstrtoul(buf, 10, &val); + if (rc != 0) + return rc; + + mutex_lock(&data->input_dev->mutex); + if (!data->loading_fw && val) { + data->loading_fw = true; + ft5x06_fw_upgrade(dev, false); + data->loading_fw = false; + } + mutex_unlock(&data->input_dev->mutex); + + return size; +} + +static DEVICE_ATTR(update_fw, 0664, ft5x06_update_fw_show, + ft5x06_update_fw_store); + +static ssize_t ft5x06_force_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + unsigned long val; + int rc; + + if (size > 2) + return -EINVAL; + + rc = kstrtoul(buf, 10, &val); + if (rc != 0) + return rc; + + mutex_lock(&data->input_dev->mutex); + if (!data->loading_fw && val) { + data->loading_fw = true; + ft5x06_fw_upgrade(dev, true); + data->loading_fw = false; + } + mutex_unlock(&data->input_dev->mutex); + + return size; +} + +static DEVICE_ATTR(force_update_fw, 0664, ft5x06_update_fw_show, + ft5x06_force_update_fw_store); + +static ssize_t ft5x06_fw_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + + return snprintf(buf, FT_FW_NAME_MAX_LEN - 1, "%s\n", data->fw_name); +} + +static ssize_t ft5x06_fw_name_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct ft5x06_ts_data *data = dev_get_drvdata(dev); + + if (size > FT_FW_NAME_MAX_LEN - 1) + return -EINVAL; + + strlcpy(data->fw_name, buf, size); + if (data->fw_name[size-1] == '\n') + data->fw_name[size-1] = 0; + + return size; +} + +static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store); + +#ifdef CONFIG_OF +static int ft5x06_get_dt_coords(struct device *dev, char *name, + struct ft5x06_ts_platform_data *pdata) +{ + u32 coords[FT_COORDS_ARR_SIZE]; + struct property *prop; + struct device_node *np = dev->of_node; + int coords_size, rc; + + prop = of_find_property(np, name, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + coords_size = prop->length / sizeof(u32); + if (coords_size != FT_COORDS_ARR_SIZE) { + dev_err(dev, "invalid %s\n", name); + return -EINVAL; + } + + rc = of_property_read_u32_array(np, name, coords, coords_size); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read %s\n", name); + return rc; + } + + if (!strcmp(name, "focaltech,panel-coords")) { + pdata->panel_minx = coords[0]; + pdata->panel_miny = coords[1]; + pdata->panel_maxx = coords[2]; + pdata->panel_maxy = coords[3]; + } else if (!strcmp(name, "focaltech,display-coords")) { + pdata->x_min = coords[0]; + pdata->y_min = coords[1]; + pdata->x_max = coords[2]; + pdata->y_max = coords[3]; + } else { + dev_err(dev, "unsupported property %s\n", name); + return -EINVAL; + } + + return 0; +} + +static int ft5x06_parse_dt(struct device *dev, + struct ft5x06_ts_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + struct property *prop; + u32 temp_val, num_buttons; + u32 button_map[MAX_BUTTONS]; + + rc = ft5x06_get_dt_coords(dev, "focaltech,panel-coords", pdata); + if (rc && (rc != -EINVAL)) + return rc; + + rc = ft5x06_get_dt_coords(dev, "focaltech,display-coords", pdata); + if (rc) + return rc; + + pdata->i2c_pull_up = of_property_read_bool(np, + "focaltech,i2c-pull-up"); + + pdata->no_force_update = of_property_read_bool(np, + "focaltech,no-force-update"); + /* reset, irq gpio info */ + pdata->reset_gpio = of_get_named_gpio_flags(np, "focaltech,reset-gpio", + 0, &pdata->reset_gpio_flags); + if (pdata->reset_gpio < 0) + return pdata->reset_gpio; + + pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio", + 0, &pdata->irq_gpio_flags); + if (pdata->irq_gpio < 0) + return pdata->irq_gpio; + + rc = of_property_read_u32(np, "focaltech,family-id", &temp_val); + if (!rc) + pdata->family_id = temp_val; + else + return rc; + + prop = of_find_property(np, "focaltech,button-map", NULL); + if (prop) { + num_buttons = prop->length / sizeof(temp_val); + if (num_buttons > MAX_BUTTONS) + return -EINVAL; + + rc = of_property_read_u32_array(np, + "focaltech,button-map", button_map, + num_buttons); + if (rc) { + dev_err(dev, "Unable to read key codes\n"); + return rc; + } + } + + return 0; +} +#else +static int ft5x06_parse_dt(struct device *dev, + struct ft5x06_ts_platform_data *pdata) +{ + return -ENODEV; +} +#endif + static int ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct ft5x06_ts_platform_data *pdata = client->dev.platform_data; + struct ft5x06_ts_platform_data *pdata; struct ft5x06_ts_data *data; struct input_dev *input_dev; u8 reg_value; u8 reg_addr; int err; + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct ft5x06_ts_platform_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + err = ft5x06_parse_dt(&client->dev, pdata); + if (err) + return err; + } else + pdata = client->dev.platform_data; + if (!pdata) { dev_err(&client->dev, "Invalid pdata\n"); return -EINVAL; @@ -446,9 +1050,9 @@ static int ft5x06_ts_probe(struct i2c_client *client, __set_bit(BTN_TOUCH, input_dev->keybit); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, + input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0); input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, CFG_MAX_TOUCH_POINTS, 0, 0); @@ -523,25 +1127,44 @@ static int ft5x06_ts_probe(struct i2c_client *client, /* make sure CTP already finish startup process */ msleep(FT_STARTUP_DLY); - /*get some register information */ - reg_addr = FT5X06_REG_FW_VER; + /* check the controller id */ + reg_addr = FT_REG_ID; err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1); - if (err) + if (err < 0) { dev_err(&client->dev, "version read failed"); + return err; + } + + dev_info(&client->dev, "Device ID = 0x%x\n", reg_value); - dev_info(&client->dev, "[FTS] Firmware version = 0x%x\n", reg_value); + if (pdata->family_id != reg_value) { + dev_err(&client->dev, "%s:Unsupported controller\n", __func__); + goto free_reset_gpio; + } + + data->family_id = reg_value; + + /* get some register information */ + reg_addr = FT_REG_FW_VER; + err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1); + if (err < 0) + dev_err(&client->dev, "version read failed"); - reg_addr = FT5X06_REG_POINT_RATE; + dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value); + + reg_addr = FT_REG_POINT_RATE; ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1); - if (err) + if (err < 0) dev_err(&client->dev, "report rate read failed"); - dev_info(&client->dev, "[FTS] report rate is %dHz.\n", reg_value * 10); - reg_addr = FT5X06_REG_THGROUP; + dev_dbg(&client->dev, "report rate = %dHz\n", reg_value * 10); + + reg_addr = FT_REG_THGROUP; err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1); - if (err) + if (err < 0) dev_err(&client->dev, "threshold read failed"); - dev_dbg(&client->dev, "[FTS] touch threshold is %d.\n", reg_value * 4); + + dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4); err = request_threaded_irq(client->irq, NULL, ft5x06_ts_interrupt, pdata->irqflags, @@ -551,9 +1174,36 @@ static int ft5x06_ts_probe(struct i2c_client *client, goto free_reset_gpio; } -#ifdef CONFIG_HAS_EARLYSUSPEND + err = device_create_file(&client->dev, &dev_attr_fw_name); + if (err) { + dev_err(&client->dev, "sys file creation failed\n"); + goto irq_free; + } + + err = device_create_file(&client->dev, &dev_attr_update_fw); + if (err) { + dev_err(&client->dev, "sys file creation failed\n"); + goto free_fw_name_sys; + } + + err = device_create_file(&client->dev, &dev_attr_force_update_fw); + if (err) { + dev_err(&client->dev, "sys file creation failed\n"); + goto free_update_fw_sys; + } + + +#if defined(CONFIG_FB) + data->fb_notif.notifier_call = fb_notifier_callback; + + err = fb_register_client(&data->fb_notif); + + if (err) + dev_err(&client->dev, "Unable to register fb_notifier: %d\n", + err); +#elif defined(CONFIG_HAS_EARLYSUSPEND) data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + - FT5X06_SUSPEND_LEVEL; + FT_SUSPEND_LEVEL; data->early_suspend.suspend = ft5x06_ts_early_suspend; data->early_suspend.resume = ft5x06_ts_late_resume; register_early_suspend(&data->early_suspend); @@ -561,12 +1211,18 @@ static int ft5x06_ts_probe(struct i2c_client *client, return 0; +free_update_fw_sys: + device_remove_file(&client->dev, &dev_attr_update_fw); +free_fw_name_sys: + device_remove_file(&client->dev, &dev_attr_fw_name); +irq_free: + free_irq(client->irq, data); free_reset_gpio: if (gpio_is_valid(pdata->reset_gpio)) gpio_free(pdata->reset_gpio); free_irq_gpio: if (gpio_is_valid(pdata->irq_gpio)) - gpio_free(pdata->reset_gpio); + gpio_free(pdata->irq_gpio); pwr_off: if (pdata->power_on) pdata->power_on(false); @@ -591,7 +1247,14 @@ static int ft5x06_ts_remove(struct i2c_client *client) { struct ft5x06_ts_data *data = i2c_get_clientdata(client); -#ifdef CONFIG_HAS_EARLYSUSPEND + device_remove_file(&client->dev, &dev_attr_force_update_fw); + device_remove_file(&client->dev, &dev_attr_update_fw); + device_remove_file(&client->dev, &dev_attr_fw_name); + +#if defined(CONFIG_FB) + if (fb_unregister_client(&data->fb_notif)) + dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); +#elif defined(CONFIG_HAS_EARLYSUSPEND) unregister_early_suspend(&data->early_suspend); #endif free_irq(client->irq, data); @@ -600,7 +1263,7 @@ static int ft5x06_ts_remove(struct i2c_client *client) gpio_free(data->pdata->reset_gpio); if (gpio_is_valid(data->pdata->irq_gpio)) - gpio_free(data->pdata->reset_gpio); + gpio_free(data->pdata->irq_gpio); if (data->pdata->power_on) data->pdata->power_on(false); @@ -625,12 +1288,22 @@ static const struct i2c_device_id ft5x06_ts_id[] = { MODULE_DEVICE_TABLE(i2c, ft5x06_ts_id); +#ifdef CONFIG_OF +static const struct of_device_id ft5x06_match_table[] = { + { .compatible = "focaltech,5x06",}, + { }, +}; +#else +#define ft5x06_match_table NULL +#endif + static struct i2c_driver ft5x06_ts_driver = { .probe = ft5x06_ts_probe, .remove = __devexit_p(ft5x06_ts_remove), .driver = { .name = "ft5x06_ts", .owner = THIS_MODULE, + .of_match_table = ft5x06_match_table, #ifdef CONFIG_PM .pm = &ft5x06_ts_pm_ops, #endif diff --git a/drivers/input/touchscreen/it7258_ts_i2c.c b/drivers/input/touchscreen/it7258_ts_i2c.c index c60a2b5a94b0..9080a13069a8 100644 --- a/drivers/input/touchscreen/it7258_ts_i2c.c +++ b/drivers/input/touchscreen/it7258_ts_i2c.c @@ -1,7 +1,7 @@ /* drivers/input/touchscreen/it7258_ts_i2c.c * * Copyright (C) 2014 ITE Tech. Inc. - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-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 @@ -30,7 +30,7 @@ #include <linux/string.h> #define MAX_BUFFER_SIZE 144 -#define DEVICE_NAME "IT7260" +#define DEVICE_NAME "it7260" #define SCREEN_X_RESOLUTION 320 #define SCREEN_Y_RESOLUTION 320 #define DEBUGFS_DIR_NAME "ts_debug" @@ -99,18 +99,20 @@ #define FW_WRITE_CHUNK_SIZE 128 #define FW_WRITE_RETRY_COUNT 4 #define CHIP_FLASH_SIZE 0x8000 -#define DEVICE_READY_MAX_WAIT 10 +#define DEVICE_READY_COUNT_MAX 500 +#define DEVICE_READY_COUNT_20 20 +#define IT_I2C_WAIT_10MS 10 +#define IT_I2C_READ_RET 2 +#define IT_I2C_WRITE_RET 1 /* result of reading with BUF_QUERY bits */ #define CMD_STATUS_BITS 0x07 #define CMD_STATUS_DONE 0x00 #define CMD_STATUS_BUSY 0x01 #define CMD_STATUS_ERROR 0x02 +#define CMD_STATUS_NO_CONN 0x07 #define PT_INFO_BITS 0xF8 -#define BT_INFO_NONE 0x00 #define PT_INFO_YES 0x80 -/* no new data but finder(s) still down */ -#define BT_INFO_NONE_BUT_DOWN 0x08 #define PD_FLAGS_DATA_TYPE_BITS 0xF0 /* other types (like chip-detected gestures) exist but we do not care */ @@ -133,22 +135,21 @@ #define PINCTRL_STATE_ACTIVE "pmx_ts_active" #define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" #define PINCTRL_STATE_RELEASE "pmx_ts_release" -#define IT_I2C_WAIT 1000 -struct FingerData { +struct finger_data { uint8_t xLo; uint8_t hi; uint8_t yLo; uint8_t pressure; } __packed; -struct PointData { +struct point_data { uint8_t flags; uint8_t palm; - struct FingerData fd[3]; + struct finger_data fd[3]; } __packed; -struct IT7260_ts_platform_data { +struct it7260_ts_platform_data { u32 irq_gpio; u32 irq_gpio_flags; u32 reset_gpio; @@ -172,10 +173,10 @@ struct IT7260_ts_platform_data { bool low_reset; }; -struct IT7260_ts_data { +struct it7260_ts_data { struct i2c_client *client; struct input_dev *input_dev; - const struct IT7260_ts_platform_data *pdata; + const struct it7260_ts_platform_data *pdata; struct regulator *vdd; struct regulator *avdd; bool device_needs_wakeup; @@ -204,44 +205,49 @@ struct IT7260_ts_data { /* Function declarations */ static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); -static int IT7260_ts_resume(struct device *dev); -static int IT7260_ts_suspend(struct device *dev); +static int it7260_ts_resume(struct device *dev); +static int it7260_ts_suspend(struct device *dev); -static struct IT7260_ts_data *gl_ts; - -static int IT7260_debug_suspend_set(void *_data, u64 val) +static int it7260_debug_suspend_set(void *_data, u64 val) { + struct it7260_ts_data *ts_data = _data; + if (val) - IT7260_ts_suspend(&gl_ts->client->dev); + it7260_ts_suspend(&ts_data->client->dev); else - IT7260_ts_resume(&gl_ts->client->dev); + it7260_ts_resume(&ts_data->client->dev); return 0; } -static int IT7260_debug_suspend_get(void *_data, u64 *val) +static int it7260_debug_suspend_get(void *_data, u64 *val) { - *val = gl_ts->suspended; + struct it7260_ts_data *ts_data = _data; + + mutex_lock(&ts_data->input_dev->mutex); + *val = ts_data->suspended; + mutex_lock(&ts_data->input_dev->mutex); return 0; } -DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, IT7260_debug_suspend_get, - IT7260_debug_suspend_set, "%lld\n"); +DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, it7260_debug_suspend_get, + it7260_debug_suspend_set, "%lld\n"); /* internal use func - does not make sure chip is ready before read */ -static bool IT7260_i2cReadNoReadyCheck(uint8_t buf_index, uint8_t *buffer, - uint16_t buf_len) +static int it7260_i2c_read_no_ready_check(struct it7260_ts_data *ts_data, + uint8_t buf_index, uint8_t *buffer, uint16_t buf_len) { + int ret; struct i2c_msg msgs[2] = { { - .addr = gl_ts->client->addr, + .addr = ts_data->client->addr, .flags = I2C_M_NOSTART, .len = 1, .buf = &buf_index }, { - .addr = gl_ts->client->addr, + .addr = ts_data->client->addr, .flags = I2C_M_RD, .len = buf_len, .buf = buffer @@ -250,15 +256,20 @@ static bool IT7260_i2cReadNoReadyCheck(uint8_t buf_index, uint8_t *buffer, memset(buffer, 0xFF, buf_len); - return i2c_transfer(gl_ts->client->adapter, msgs, 2); + ret = i2c_transfer(ts_data->client->adapter, msgs, 2); + if (ret < 0) + dev_err(&ts_data->client->dev, "i2c read failed %d\n", ret); + + return ret; } -static bool IT7260_i2cWriteNoReadyCheck(uint8_t buf_index, - const uint8_t *buffer, uint16_t buf_len) +static int it7260_i2c_write_no_ready_check(struct it7260_ts_data *ts_data, + uint8_t buf_index, const uint8_t *buffer, uint16_t buf_len) { uint8_t txbuf[257]; + int ret; struct i2c_msg msg = { - .addr = gl_ts->client->addr, + .addr = ts_data->client->addr, .flags = 0, .len = buf_len + 1, .buf = txbuf @@ -266,110 +277,178 @@ static bool IT7260_i2cWriteNoReadyCheck(uint8_t buf_index, /* just to be careful */ if (buf_len > sizeof(txbuf) - 1) { - dev_err(&gl_ts->client->dev, "buf length is out of limit\n"); + dev_err(&ts_data->client->dev, "buf length is out of limit\n"); return false; } txbuf[0] = buf_index; memcpy(txbuf + 1, buffer, buf_len); - return i2c_transfer(gl_ts->client->adapter, &msg, 1); + ret = i2c_transfer(ts_data->client->adapter, &msg, 1); + if (ret < 0) + dev_err(&ts_data->client->dev, "i2c write failed %d\n", ret); + + return ret; } /* - * Device is apparently always ready for i2c but not for actual - * register reads/writes. This function ascertains it is ready - * for that too. the results of this call often were ignored. + * Device is apparently always ready for I2C communication but not for + * actual register reads/writes. This function checks if it is ready + * for that too. The results of this call often were ignored. + * If forever is set to TRUE, then check the device's status until it + * becomes ready with 500 retries at max. Otherwise retry 25 times only. + * If slowly is set to TRUE, then add sleep of 50 ms in each retry, + * otherwise don't sleep. */ -static bool IT7260_waitDeviceReady(bool forever, bool slowly) +static int it7260_wait_device_ready(struct it7260_ts_data *ts_data, + bool forever, bool slowly) { uint8_t query; - uint32_t count = DEVICE_READY_MAX_WAIT; + uint32_t count = DEVICE_READY_COUNT_20; + int ret; + + if (ts_data->fw_cfg_uploading || forever) + count = DEVICE_READY_COUNT_MAX; do { - if (!IT7260_i2cReadNoReadyCheck(BUF_QUERY, &query, - sizeof(query))) - query = CMD_STATUS_BUSY; + ret = it7260_i2c_read_no_ready_check(ts_data, BUF_QUERY, &query, + sizeof(query)); + if (ret < 0 && ((query & CMD_STATUS_BITS) + == CMD_STATUS_NO_CONN)) + continue; - if (slowly) - msleep(IT_I2C_WAIT); - if (!forever) - count--; + if ((query & CMD_STATUS_BITS) == CMD_STATUS_DONE) + break; - } while ((query & CMD_STATUS_BUSY) && count); + query = CMD_STATUS_BUSY; + if (slowly) + msleep(IT_I2C_WAIT_10MS); + } while (--count); - return !query; + return ((!(query & CMD_STATUS_BITS)) ? 0 : -ENODEV); } -static bool IT7260_i2cRead(uint8_t buf_index, uint8_t *buffer, - uint16_t buf_len) +static int it7260_i2c_read(struct it7260_ts_data *ts_data, uint8_t buf_index, + uint8_t *buffer, uint16_t buf_len) { - IT7260_waitDeviceReady(false, false); - return IT7260_i2cReadNoReadyCheck(buf_index, buffer, buf_len); + int ret; + + ret = it7260_wait_device_ready(ts_data, false, false); + if (ret < 0) + return ret; + + return it7260_i2c_read_no_ready_check(ts_data, buf_index, + buffer, buf_len); } -static bool IT7260_i2cWrite(uint8_t buf_index, const uint8_t *buffer, - uint16_t buf_len) +static int it7260_i2c_write(struct it7260_ts_data *ts_data, uint8_t buf_index, + const uint8_t *buffer, uint16_t buf_len) { - IT7260_waitDeviceReady(false, false); - return IT7260_i2cWriteNoReadyCheck(buf_index, buffer, buf_len); + int ret; + + ret = it7260_wait_device_ready(ts_data, false, false); + if (ret < 0) + return ret; + + return it7260_i2c_write_no_ready_check(ts_data, buf_index, + buffer, buf_len); } -static bool IT7260_firmware_reinitialize(u8 command) +static int it7260_firmware_reinitialize(struct it7260_ts_data *ts_data, + u8 command) { uint8_t cmd[] = {command}; uint8_t rsp[2]; + int ret; - if (!IT7260_i2cWrite(BUF_COMMAND, cmd, sizeof(cmd))) - return false; + ret = it7260_i2c_write(ts_data, BUF_COMMAND, cmd, sizeof(cmd)); + if (ret != IT_I2C_WRITE_RET) { + dev_err(&ts_data->client->dev, + "failed to write fw reinit command %d\n", ret); + return ret; + } - if (!IT7260_i2cRead(BUF_RESPONSE, rsp, sizeof(rsp))) - return false; + ret = it7260_i2c_read(ts_data, BUF_RESPONSE, rsp, sizeof(rsp)); + if (ret != IT_I2C_READ_RET) { + dev_err(&ts_data->client->dev, + "failed to read any response from chip %d\n", ret); + return ret; + } /* a reply of two zero bytes signifies success */ - return !rsp[0] && !rsp[1]; + if (rsp[0] == 0 && rsp[1] == 0) + return 0; + else + return -EIO; } -static bool IT7260_enter_exit_fw_ugrade_mode(bool enter) +static int it7260_enter_exit_fw_ugrade_mode(struct it7260_ts_data *ts_data, + bool enter) { uint8_t cmd[] = {CMD_FIRMWARE_UPGRADE, 0, 'I', 'T', '7', '2', '6', '0', 0x55, 0xAA}; uint8_t resp[2]; + int ret; cmd[1] = enter ? SUB_CMD_ENTER_FW_UPGRADE_MODE : SUB_CMD_EXIT_FW_UPGRADE_MODE; - if (!IT7260_i2cWrite(BUF_COMMAND, cmd, sizeof(cmd))) - return false; - if (!IT7260_i2cRead(BUF_RESPONSE, resp, sizeof(resp))) - return false; + ret = it7260_i2c_write(ts_data, BUF_COMMAND, cmd, sizeof(cmd)); + if (ret != IT_I2C_WRITE_RET) { + dev_err(&ts_data->client->dev, + "failed to write CMD_FIRMWARE_UPGRADE %d\n", ret); + return ret; + } + + ret = it7260_i2c_read(ts_data, BUF_RESPONSE, resp, sizeof(resp)); + if (ret != IT_I2C_READ_RET) { + dev_err(&ts_data->client->dev, + "failed to read any response from chip %d\n", ret); + return ret; + } /* a reply of two zero bytes signifies success */ - return !resp[0] && !resp[1]; + if (resp[0] == 0 && resp[1] == 0) + return 0; + else + return -EIO; } -static bool IT7260_chipSetStartOffset(uint16_t offset) +static int it7260_set_start_offset(struct it7260_ts_data *ts_data, + uint16_t offset) { uint8_t cmd[] = {CMD_SET_START_OFFSET, 0, ((uint8_t)(offset)), ((uint8_t)((offset) >> 8))}; uint8_t resp[2]; + int ret; - if (!IT7260_i2cWrite(BUF_COMMAND, cmd, 4)) - return false; - + ret = it7260_i2c_write(ts_data, BUF_COMMAND, cmd, 4); + if (ret != IT_I2C_WRITE_RET) { + dev_err(&ts_data->client->dev, + "failed to write CMD_SET_START_OFFSET %d\n", ret); + return ret; + } - if (!IT7260_i2cRead(BUF_RESPONSE, resp, sizeof(resp))) - return false; + ret = it7260_i2c_read(ts_data, BUF_RESPONSE, resp, sizeof(resp)); + if (ret != IT_I2C_READ_RET) { + dev_err(&ts_data->client->dev, + "failed to read any response from chip %d\n", ret); + return ret; + } /* a reply of two zero bytes signifies success */ - return !resp[0] && !resp[1]; + if (resp[0] == 0 && resp[1] == 0) + return 0; + else + return -EIO; } /* write fw_length bytes from fw_data at chip offset wr_start_offset */ -static bool IT7260_fw_flash_write_verify(unsigned int fw_length, - const uint8_t *fw_data, uint16_t wr_start_offset) +static int it7260_fw_flash_write_verify(struct it7260_ts_data *ts_data, + unsigned int fw_length, const uint8_t *fw_data, + uint16_t wr_start_offset) { uint32_t cur_data_off; @@ -399,17 +478,18 @@ static bool IT7260_fw_flash_write_verify(unsigned int fw_length, retries++) { /* set write offset and write the data */ - IT7260_chipSetStartOffset( + it7260_set_start_offset(ts_data, wr_start_offset + cur_data_off); - IT7260_i2cWrite(BUF_COMMAND, cmd_write, + it7260_i2c_write(ts_data, BUF_COMMAND, cmd_write, cur_wr_size + 2); /* set offset and read the data back */ - IT7260_chipSetStartOffset( + it7260_set_start_offset(ts_data, wr_start_offset + cur_data_off); - IT7260_i2cWrite(BUF_COMMAND, cmd_read, + it7260_i2c_write(ts_data, BUF_COMMAND, cmd_read, sizeof(cmd_read)); - IT7260_i2cRead(BUF_RESPONSE, buf_read, cur_wr_size); + it7260_i2c_read(ts_data, BUF_RESPONSE, buf_read, + cur_wr_size); /* verify. If success break out of retry loop */ i = 0; @@ -421,68 +501,96 @@ static bool IT7260_fw_flash_write_verify(unsigned int fw_length, } /* if we've failed after all the retries, tell the caller */ if (retries == FW_WRITE_RETRY_COUNT) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "write of data offset %u failed on try %u at byte %u/%u\n", cur_data_off, retries, i, cur_wr_size); - return false; + return -EIO; } } - return true; + return 0; } /* * this code to get versions from the chip via i2c transactions, and save * them in driver data structure. */ -static void IT7260_get_chip_versions(struct device *dev) +static void it7260_get_chip_versions(struct it7260_ts_data *ts_data) { static const u8 cmd_read_fw_ver[] = {CMD_READ_VERSIONS, SUB_CMD_READ_FIRMWARE_VERSION}; static const u8 cmd_read_cfg_ver[] = {CMD_READ_VERSIONS, SUB_CMD_READ_CONFIG_VERSION}; u8 ver_fw[VERSION_LENGTH], ver_cfg[VERSION_LENGTH]; - bool ret = true; + int ret; - ret = IT7260_i2cWrite(BUF_COMMAND, cmd_read_fw_ver, + ret = it7260_i2c_write(ts_data, BUF_COMMAND, cmd_read_fw_ver, sizeof(cmd_read_fw_ver)); - if (ret) { - ret = IT7260_i2cRead(BUF_RESPONSE, ver_fw, VERSION_LENGTH); - if (ret) - memcpy(gl_ts->fw_ver, ver_fw + (5 * sizeof(u8)), + if (ret == IT_I2C_WRITE_RET) { + /* + * Sometimes, the controller may not respond immediately after + * writing the command, so wait for device to get ready. + */ + ret = it7260_wait_device_ready(ts_data, true, false); + if (ret < 0) + dev_err(&ts_data->client->dev, + "failed to read chip status %d\n", ret); + + ret = it7260_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, + ver_fw, VERSION_LENGTH); + if (ret == IT_I2C_READ_RET) + memcpy(ts_data->fw_ver, ver_fw + (5 * sizeof(u8)), VER_BUFFER_SIZE * sizeof(u8)); + else + dev_err(&ts_data->client->dev, + "failed to read fw-ver from chip %d\n", ret); + } else { + dev_err(&ts_data->client->dev, + "failed to write fw-read command %d\n", ret); } - if (!ret) - dev_err(dev, "failed to read fw version from chip\n"); - ret = IT7260_i2cWrite(BUF_COMMAND, cmd_read_cfg_ver, + ret = it7260_i2c_write(ts_data, BUF_COMMAND, cmd_read_cfg_ver, sizeof(cmd_read_cfg_ver)); - if (ret) { - ret = IT7260_i2cRead(BUF_RESPONSE, ver_cfg, VERSION_LENGTH) - && ret; - if (ret) - memcpy(gl_ts->cfg_ver, ver_cfg + (1 * sizeof(u8)), + if (ret == IT_I2C_WRITE_RET) { + /* + * Sometimes, the controller may not respond immediately after + * writing the command, so wait for device to get ready. + */ + ret = it7260_wait_device_ready(ts_data, true, false); + if (ret < 0) + dev_err(&ts_data->client->dev, + "failed to read chip status %d\n", ret); + + ret = it7260_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, + ver_cfg, VERSION_LENGTH); + if (ret == IT_I2C_READ_RET) + memcpy(ts_data->cfg_ver, ver_cfg + (1 * sizeof(u8)), VER_BUFFER_SIZE * sizeof(u8)); + else + dev_err(&ts_data->client->dev, + "failed to read cfg-ver from chip %d\n", ret); + } else { + dev_err(&ts_data->client->dev, + "failed to write cfg-read command %d\n", ret); } - if (!ret) - dev_err(dev, "failed to read cfg version from chip\n"); - dev_info(dev, "Current fw{%X.%X.%X.%X} cfg{%X.%X.%X.%X}\n", - gl_ts->fw_ver[0], gl_ts->fw_ver[1], gl_ts->fw_ver[2], - gl_ts->fw_ver[3], gl_ts->cfg_ver[0], gl_ts->cfg_ver[1], - gl_ts->cfg_ver[2], gl_ts->cfg_ver[3]); + dev_info(&ts_data->client->dev, "Current fw{%X.%X.%X.%X} cfg{%X.%X.%X.%X}\n", + ts_data->fw_ver[0], ts_data->fw_ver[1], ts_data->fw_ver[2], + ts_data->fw_ver[3], ts_data->cfg_ver[0], ts_data->cfg_ver[1], + ts_data->cfg_ver[2], ts_data->cfg_ver[3]); } -static int IT7260_cfg_upload(struct device *dev, bool force) +static int it7260_cfg_upload(struct it7260_ts_data *ts_data, bool force) { const struct firmware *cfg = NULL; int ret; - bool success, cfg_upgrade = false; + bool cfg_upgrade = false; + struct device *dev = &ts_data->client->dev; - ret = request_firmware(&cfg, gl_ts->cfg_name, dev); + ret = request_firmware(&cfg, ts_data->cfg_name, dev); if (ret) { dev_err(dev, "failed to get config data %s for it7260 %d\n", - gl_ts->cfg_name, ret); + ts_data->cfg_name, ret); return ret; } @@ -493,43 +601,59 @@ static int IT7260_cfg_upload(struct device *dev, bool force) */ if (force) cfg_upgrade = true; - else if (IT_CFG_CHECK(gl_ts->cfg_ver, cfg)) + else if (IT_CFG_CHECK(ts_data->cfg_ver, cfg)) cfg_upgrade = true; if (!cfg_upgrade) { - dev_err(dev, "CFG upgrade no required ...\n"); + dev_err(dev, "CFG upgrade not required ...\n"); + dev_info(dev, + "Chip CFG : %X.%X.%X.%X Binary CFG : %X.%X.%X.%X\n", + ts_data->cfg_ver[0], ts_data->cfg_ver[1], + ts_data->cfg_ver[2], ts_data->cfg_ver[3], + cfg->data[cfg->size - 8], cfg->data[cfg->size - 7], + cfg->data[cfg->size - 6], cfg->data[cfg->size - 5]); ret = -EFAULT; goto out; } else { dev_info(dev, "Config upgrading...\n"); - disable_irq(gl_ts->client->irq); + disable_irq(ts_data->client->irq); /* enter cfg upload mode */ - success = IT7260_enter_exit_fw_ugrade_mode(true); - if (!success) { - dev_err(dev, "Can't enter cfg upgrade mode\n"); - ret = -EIO; + ret = it7260_enter_exit_fw_ugrade_mode(ts_data, true); + if (ret < 0) { + dev_err(dev, "Can't enter cfg upgrade mode %d\n", ret); + enable_irq(ts_data->client->irq); goto out; } /* flash config data if requested */ - success = IT7260_fw_flash_write_verify(cfg->size, cfg->data, - CHIP_FLASH_SIZE - cfg->size); - if (!success) { - dev_err(dev, "failed to upgrade touch cfg data\n"); - IT7260_enter_exit_fw_ugrade_mode(false); - IT7260_firmware_reinitialize(CMD_FIRMWARE_REINIT_6F); + ret = it7260_fw_flash_write_verify(ts_data, cfg->size, + cfg->data, CHIP_FLASH_SIZE - cfg->size); + if (ret < 0) { + dev_err(dev, + "failed to upgrade touch cfg data %d\n", ret); + ret = it7260_enter_exit_fw_ugrade_mode(ts_data, false); + if (ret < 0) + dev_err(dev, + "Can't exit cfg upgrade mode%d\n", ret); + + ret = it7260_firmware_reinitialize(ts_data, + CMD_FIRMWARE_REINIT_6F); + if (ret < 0) + dev_err(dev, "Can't reinit cfg %d\n", ret); + ret = -EIO; + enable_irq(ts_data->client->irq); goto out; } else { - memcpy(gl_ts->cfg_ver, cfg->data + + memcpy(ts_data->cfg_ver, cfg->data + (cfg->size - 8 * sizeof(u8)), VER_BUFFER_SIZE * sizeof(u8)); dev_info(dev, "CFG upgrade is success. New cfg ver: %X.%X.%X.%X\n", - gl_ts->cfg_ver[0], gl_ts->cfg_ver[1], - gl_ts->cfg_ver[2], gl_ts->cfg_ver[3]); + ts_data->cfg_ver[0], ts_data->cfg_ver[1], + ts_data->cfg_ver[2], ts_data->cfg_ver[3]); } - enable_irq(gl_ts->client->irq); + enable_irq(ts_data->client->irq); } out: @@ -538,16 +662,17 @@ out: return ret; } -static int IT7260_fw_upload(struct device *dev, bool force) +static int it7260_fw_upload(struct it7260_ts_data *ts_data, bool force) { const struct firmware *fw = NULL; int ret; - bool success, fw_upgrade = false; + bool fw_upgrade = false; + struct device *dev = &ts_data->client->dev; - ret = request_firmware(&fw, gl_ts->fw_name, dev); + ret = request_firmware(&fw, ts_data->fw_name, dev); if (ret) { dev_err(dev, "failed to get firmware %s for it7260 %d\n", - gl_ts->fw_name, ret); + ts_data->fw_name, ret); return ret; } @@ -558,40 +683,55 @@ static int IT7260_fw_upload(struct device *dev, bool force) */ if (force) fw_upgrade = true; - else if (IT_FW_CHECK(gl_ts->fw_ver, fw)) + else if (IT_FW_CHECK(ts_data->fw_ver, fw)) fw_upgrade = true; if (!fw_upgrade) { dev_err(dev, "FW upgrade not required ...\n"); + dev_info(dev, "Chip FW : %X.%X.%X.%X Binary FW : %X.%X.%X.%X\n", + ts_data->fw_ver[0], ts_data->fw_ver[1], + ts_data->fw_ver[2], ts_data->fw_ver[3], + fw->data[8], fw->data[9], fw->data[10], fw->data[11]); ret = -EFAULT; goto out; } else { dev_info(dev, "Firmware upgrading...\n"); - disable_irq(gl_ts->client->irq); + disable_irq(ts_data->client->irq); /* enter fw upload mode */ - success = IT7260_enter_exit_fw_ugrade_mode(true); - if (!success) { - dev_err(dev, "Can't enter fw upgrade mode\n"); - ret = -EIO; + ret = it7260_enter_exit_fw_ugrade_mode(ts_data, true); + if (ret < 0) { + dev_err(dev, "Can't enter fw upgrade mode %d\n", ret); + enable_irq(ts_data->client->irq); goto out; } /* flash the firmware if requested */ - success = IT7260_fw_flash_write_verify(fw->size, fw->data, 0); - if (!success) { - dev_err(dev, "failed to upgrade touch firmware\n"); - IT7260_enter_exit_fw_ugrade_mode(false); - IT7260_firmware_reinitialize(CMD_FIRMWARE_REINIT_6F); + ret = it7260_fw_flash_write_verify(ts_data, fw->size, + fw->data, 0); + if (ret < 0) { + dev_err(dev, + "failed to upgrade touch firmware %d\n", ret); + ret = it7260_enter_exit_fw_ugrade_mode(ts_data, false); + if (ret < 0) + dev_err(dev, + "Can't exit fw upgrade mode %d\n", ret); + + ret = it7260_firmware_reinitialize(ts_data, + CMD_FIRMWARE_REINIT_6F); + if (ret < 0) + dev_err(dev, "Can't reinit firmware %d\n", ret); + ret = -EIO; + enable_irq(ts_data->client->irq); goto out; } else { - memcpy(gl_ts->fw_ver, fw->data + (8 * sizeof(u8)), + memcpy(ts_data->fw_ver, fw->data + (8 * sizeof(u8)), VER_BUFFER_SIZE * sizeof(u8)); dev_info(dev, "FW upgrade is success. New fw ver: %X.%X.%X.%X\n", - gl_ts->fw_ver[0], gl_ts->fw_ver[1], - gl_ts->fw_ver[2], gl_ts->fw_ver[3]); + ts_data->fw_ver[0], ts_data->fw_ver[1], + ts_data->fw_ver[2], ts_data->fw_ver[3]); } - enable_irq(gl_ts->client->irq); + enable_irq(ts_data->client->irq); } out: @@ -600,16 +740,18 @@ out: return ret; } -static int IT7260_ts_chipLowPowerMode(const u8 sleep_type) +static int it7260_ts_chip_low_power_mode(struct it7260_ts_data *ts_data, + const u8 sleep_type) { const uint8_t cmd_sleep[] = {CMD_PWR_CTL, 0x00, sleep_type}; uint8_t dummy; if (sleep_type) - IT7260_i2cWriteNoReadyCheck(BUF_COMMAND, cmd_sleep, + it7260_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_sleep, sizeof(cmd_sleep)); else - IT7260_i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy)); + it7260_i2c_read_no_ready_check(ts_data, BUF_QUERY, &dummy, + sizeof(dummy)); msleep(WAIT_CHANGE_MODE); return 0; @@ -618,32 +760,33 @@ static int IT7260_ts_chipLowPowerMode(const u8 sleep_type) static ssize_t sysfs_fw_upgrade_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); int mode = 0, ret; - if (gl_ts->suspended) { + if (ts_data->suspended) { dev_err(dev, "Device is suspended, can't flash fw!!!\n"); return -EBUSY; } ret = kstrtoint(buf, 10, &mode); - if (!ret) { + if (ret) { dev_err(dev, "failed to read input for sysfs\n"); return -EINVAL; } - mutex_lock(&gl_ts->fw_cfg_mutex); + mutex_lock(&ts_data->fw_cfg_mutex); if (mode == 1) { - gl_ts->fw_cfg_uploading = true; - ret = IT7260_fw_upload(dev, false); + ts_data->fw_cfg_uploading = true; + ret = it7260_fw_upload(ts_data, false); if (ret) { dev_err(dev, "Failed to flash fw: %d", ret); - gl_ts->fw_upgrade_result = false; + ts_data->fw_upgrade_result = false; } else { - gl_ts->fw_upgrade_result = true; + ts_data->fw_upgrade_result = true; } - gl_ts->fw_cfg_uploading = false; + ts_data->fw_cfg_uploading = false; } - mutex_unlock(&gl_ts->fw_cfg_mutex); + mutex_unlock(&ts_data->fw_cfg_mutex); return count; } @@ -651,32 +794,33 @@ static ssize_t sysfs_fw_upgrade_store(struct device *dev, static ssize_t sysfs_cfg_upgrade_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); int mode = 0, ret; - if (gl_ts->suspended) { + if (ts_data->suspended) { dev_err(dev, "Device is suspended, can't flash cfg!!!\n"); return -EBUSY; } ret = kstrtoint(buf, 10, &mode); - if (!ret) { + if (ret) { dev_err(dev, "failed to read input for sysfs\n"); return -EINVAL; } - mutex_lock(&gl_ts->fw_cfg_mutex); + mutex_lock(&ts_data->fw_cfg_mutex); if (mode == 1) { - gl_ts->fw_cfg_uploading = true; - ret = IT7260_cfg_upload(dev, false); + ts_data->fw_cfg_uploading = true; + ret = it7260_cfg_upload(ts_data, false); if (ret) { dev_err(dev, "Failed to flash cfg: %d", ret); - gl_ts->cfg_upgrade_result = false; + ts_data->cfg_upgrade_result = false; } else { - gl_ts->cfg_upgrade_result = true; + ts_data->cfg_upgrade_result = true; } - gl_ts->fw_cfg_uploading = false; + ts_data->fw_cfg_uploading = false; } - mutex_unlock(&gl_ts->fw_cfg_mutex); + mutex_unlock(&ts_data->fw_cfg_mutex); return count; } @@ -684,46 +828,51 @@ static ssize_t sysfs_cfg_upgrade_store(struct device *dev, static ssize_t sysfs_fw_upgrade_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + return scnprintf(buf, MAX_BUFFER_SIZE, "%d\n", - gl_ts->fw_upgrade_result); + ts_data->fw_upgrade_result); } static ssize_t sysfs_cfg_upgrade_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + return scnprintf(buf, MAX_BUFFER_SIZE, "%d\n", - gl_ts->cfg_upgrade_result); + ts_data->cfg_upgrade_result); } static ssize_t sysfs_force_fw_upgrade_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); int mode = 0, ret; - if (gl_ts->suspended) { + if (ts_data->suspended) { dev_err(dev, "Device is suspended, can't flash fw!!!\n"); return -EBUSY; } ret = kstrtoint(buf, 10, &mode); - if (!ret) { + if (ret) { dev_err(dev, "failed to read input for sysfs\n"); return -EINVAL; } - mutex_lock(&gl_ts->fw_cfg_mutex); + mutex_lock(&ts_data->fw_cfg_mutex); if (mode == 1) { - gl_ts->fw_cfg_uploading = true; - ret = IT7260_fw_upload(dev, true); + ts_data->fw_cfg_uploading = true; + ret = it7260_fw_upload(ts_data, true); if (ret) { dev_err(dev, "Failed to force flash fw: %d", ret); - gl_ts->fw_upgrade_result = false; + ts_data->fw_upgrade_result = false; } else { - gl_ts->fw_upgrade_result = true; + ts_data->fw_upgrade_result = true; } - gl_ts->fw_cfg_uploading = false; + ts_data->fw_cfg_uploading = false; } - mutex_unlock(&gl_ts->fw_cfg_mutex); + mutex_unlock(&ts_data->fw_cfg_mutex); return count; } @@ -731,32 +880,33 @@ static ssize_t sysfs_force_fw_upgrade_store(struct device *dev, static ssize_t sysfs_force_cfg_upgrade_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); int mode = 0, ret; - if (gl_ts->suspended) { + if (ts_data->suspended) { dev_err(dev, "Device is suspended, can't flash cfg!!!\n"); return -EBUSY; } ret = kstrtoint(buf, 10, &mode); - if (!ret) { + if (ret) { dev_err(dev, "failed to read input for sysfs\n"); return -EINVAL; } - mutex_lock(&gl_ts->fw_cfg_mutex); + mutex_lock(&ts_data->fw_cfg_mutex); if (mode == 1) { - gl_ts->fw_cfg_uploading = true; - ret = IT7260_cfg_upload(dev, true); + ts_data->fw_cfg_uploading = true; + ret = it7260_cfg_upload(ts_data, true); if (ret) { dev_err(dev, "Failed to force flash cfg: %d", ret); - gl_ts->cfg_upgrade_result = false; + ts_data->cfg_upgrade_result = false; } else { - gl_ts->cfg_upgrade_result = true; + ts_data->cfg_upgrade_result = true; } - gl_ts->fw_cfg_uploading = false; + ts_data->fw_cfg_uploading = false; } - mutex_unlock(&gl_ts->fw_cfg_mutex); + mutex_unlock(&ts_data->fw_cfg_mutex); return count; } @@ -764,51 +914,65 @@ static ssize_t sysfs_force_cfg_upgrade_store(struct device *dev, static ssize_t sysfs_force_fw_upgrade_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, MAX_BUFFER_SIZE, "%d", gl_ts->fw_upgrade_result); + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + + return snprintf(buf, MAX_BUFFER_SIZE, "%d", ts_data->fw_upgrade_result); } static ssize_t sysfs_force_cfg_upgrade_show(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, MAX_BUFFER_SIZE, "%d", gl_ts->cfg_upgrade_result); + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + + return snprintf(buf, MAX_BUFFER_SIZE, "%d", + ts_data->cfg_upgrade_result); } static ssize_t sysfs_calibration_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + return scnprintf(buf, MAX_BUFFER_SIZE, "%d\n", - gl_ts->calibration_success); + ts_data->calibration_success); } -static bool IT7260_chipSendCalibrationCmd(bool auto_tune_on) +static int it7260_ts_send_calibration_cmd(struct it7260_ts_data *ts_data, + bool auto_tune_on) { uint8_t cmd_calibrate[] = {CMD_CALIBRATE, 0, auto_tune_on ? 1 : 0, 0, 0}; - return IT7260_i2cWrite(BUF_COMMAND, cmd_calibrate, + + return it7260_i2c_write(ts_data, BUF_COMMAND, cmd_calibrate, sizeof(cmd_calibrate)); } static ssize_t sysfs_calibration_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); uint8_t resp; + int ret; - if (!IT7260_chipSendCalibrationCmd(false)) { + ret = it7260_ts_send_calibration_cmd(ts_data, false); + if (ret < 0) { dev_err(dev, "failed to send calibration command\n"); } else { - gl_ts->calibration_success = - IT7260_i2cRead(BUF_RESPONSE, &resp, sizeof(resp)); + ret = it7260_i2c_read(ts_data, BUF_RESPONSE, &resp, + sizeof(resp)); + if (ret == IT_I2C_READ_RET) + ts_data->calibration_success = true; /* * previous logic that was here never called - * IT7260_firmware_reinitialize() due to checking a + * it7260_firmware_reinitialize() due to checking a * guaranteed-not-null value against null. We now * call it. Hopefully this is OK */ if (!resp) - dev_dbg(dev, "IT7260_firmware_reinitialize-> %s\n", - IT7260_firmware_reinitialize(CMD_FIRMWARE_REINIT_6F) - ? "success" : "fail"); + dev_dbg(dev, "it7260_firmware_reinitialize-> %s\n", + it7260_firmware_reinitialize(ts_data, + CMD_FIRMWARE_REINIT_6F) ? "success" : "fail"); } return count; @@ -817,21 +981,22 @@ static ssize_t sysfs_calibration_store(struct device *dev, static ssize_t sysfs_point_show(struct device *dev, struct device_attribute *attr, char *buf) { - uint8_t point_data[sizeof(struct PointData)]; - bool readSuccess; + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + uint8_t pt_data[sizeof(struct point_data)]; + int readSuccess; ssize_t ret; - readSuccess = IT7260_i2cReadNoReadyCheck(BUF_POINT_INFO, point_data, - sizeof(point_data)); + readSuccess = it7260_i2c_read_no_ready_check(ts_data, BUF_POINT_INFO, + pt_data, sizeof(pt_data)); - if (readSuccess) { + if (readSuccess == IT_I2C_READ_RET) { ret = scnprintf(buf, MAX_BUFFER_SIZE, "point_show read ret[%d]--point[%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x]\n", - readSuccess, point_data[0], point_data[1], - point_data[2], point_data[3], point_data[4], - point_data[5], point_data[6], point_data[7], - point_data[8], point_data[9], point_data[10], - point_data[11], point_data[12], point_data[13]); + readSuccess, pt_data[0], pt_data[1], + pt_data[2], pt_data[3], pt_data[4], + pt_data[5], pt_data[6], pt_data[7], + pt_data[8], pt_data[9], pt_data[10], + pt_data[11], pt_data[12], pt_data[13]); } else { ret = scnprintf(buf, MAX_BUFFER_SIZE, "failed to read point data\n"); @@ -844,51 +1009,57 @@ static ssize_t sysfs_point_show(struct device *dev, static ssize_t sysfs_version_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + return scnprintf(buf, MAX_BUFFER_SIZE, "fw{%X.%X.%X.%X} cfg{%X.%X.%X.%X}\n", - gl_ts->fw_ver[0], gl_ts->fw_ver[1], gl_ts->fw_ver[2], - gl_ts->fw_ver[3], gl_ts->cfg_ver[0], gl_ts->cfg_ver[1], - gl_ts->cfg_ver[2], gl_ts->cfg_ver[3]); + ts_data->fw_ver[0], ts_data->fw_ver[1], + ts_data->fw_ver[2], ts_data->fw_ver[3], + ts_data->cfg_ver[0], ts_data->cfg_ver[1], + ts_data->cfg_ver[2], ts_data->cfg_ver[3]); } static ssize_t sysfs_sleep_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); /* * The usefulness of this was questionable at best - we were at least * leaking a byte of kernel data (by claiming to return a byte but not * writing to buf. To fix this now we actually return the sleep status */ - *buf = gl_ts->suspended ? '1' : '0'; + *buf = ts_data->suspended ? '1' : '0'; + return 1; } static ssize_t sysfs_sleep_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); int go_to_sleep, ret; ret = kstrtoint(buf, 10, &go_to_sleep); - /* (gl_ts->suspended == true && goToSleepVal > 0) means + /* (ts_data->suspended == true && goToSleepVal > 0) means * device is already suspended and you want it to be in sleep, - * (gl_ts->suspended == false && goToSleepVal == 0) means + * (ts_data->suspended == false && goToSleepVal == 0) means * device is already active and you also want it to be active. */ - if ((gl_ts->suspended && go_to_sleep > 0) || - (!gl_ts->suspended && go_to_sleep == 0)) + if ((ts_data->suspended && go_to_sleep > 0) || + (!ts_data->suspended && go_to_sleep == 0)) dev_err(dev, "duplicate request to %s chip\n", go_to_sleep ? "sleep" : "wake"); else if (go_to_sleep) { - disable_irq(gl_ts->client->irq); - IT7260_ts_chipLowPowerMode(PWR_CTL_SLEEP_MODE); + disable_irq(ts_data->client->irq); + it7260_ts_chip_low_power_mode(ts_data, PWR_CTL_SLEEP_MODE); dev_dbg(dev, "touch is going to sleep...\n"); } else { - IT7260_ts_chipLowPowerMode(PWR_CTL_ACTIVE_MODE); - enable_irq(gl_ts->client->irq); + it7260_ts_chip_low_power_mode(ts_data, PWR_CTL_ACTIVE_MODE); + enable_irq(ts_data->client->irq); dev_dbg(dev, "touch is going to wake!\n"); } - gl_ts->suspended = go_to_sleep; + ts_data->suspended = go_to_sleep; return count; } @@ -896,6 +1067,7 @@ static ssize_t sysfs_sleep_store(struct device *dev, static ssize_t sysfs_cfg_name_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); char *strptr; if (count >= MAX_BUFFER_SIZE) { @@ -909,7 +1081,7 @@ static ssize_t sysfs_cfg_name_store(struct device *dev, return -EINVAL; } - strlcpy(gl_ts->cfg_name, buf, count); + strlcpy(ts_data->cfg_name, buf, count); return count; } @@ -917,9 +1089,11 @@ static ssize_t sysfs_cfg_name_store(struct device *dev, static ssize_t sysfs_cfg_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - if (strnlen(gl_ts->cfg_name, MAX_BUFFER_SIZE) > 0) + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + + if (strnlen(ts_data->cfg_name, MAX_BUFFER_SIZE) > 0) return scnprintf(buf, MAX_BUFFER_SIZE, "%s\n", - gl_ts->cfg_name); + ts_data->cfg_name); else return scnprintf(buf, MAX_BUFFER_SIZE, "No config file name given\n"); @@ -928,6 +1102,7 @@ static ssize_t sysfs_cfg_name_show(struct device *dev, static ssize_t sysfs_fw_name_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); char *strptr; if (count >= MAX_BUFFER_SIZE) { @@ -941,16 +1116,18 @@ static ssize_t sysfs_fw_name_store(struct device *dev, return -EINVAL; } - strlcpy(gl_ts->fw_name, buf, count); + strlcpy(ts_data->fw_name, buf, count); return count; } static ssize_t sysfs_fw_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - if (strnlen(gl_ts->fw_name, MAX_BUFFER_SIZE) > 0) + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); + + if (strnlen(ts_data->fw_name, MAX_BUFFER_SIZE) > 0) return scnprintf(buf, MAX_BUFFER_SIZE, "%s\n", - gl_ts->fw_name); + ts_data->fw_name); else return scnprintf(buf, MAX_BUFFER_SIZE, "No firmware file name given\n"); @@ -997,59 +1174,47 @@ static const struct attribute_group it7260_attr_group = { .attrs = it7260_attributes, }; -static void IT7260_chipExternalCalibration(bool autoTuneEnabled) -{ - uint8_t resp[2]; - - dev_dbg(&gl_ts->client->dev, "sent calibration command -> %d\n", - IT7260_chipSendCalibrationCmd(autoTuneEnabled)); - IT7260_waitDeviceReady(true, true); - IT7260_i2cReadNoReadyCheck(BUF_RESPONSE, resp, sizeof(resp)); - IT7260_firmware_reinitialize(CMD_FIRMWARE_REINIT_C); -} - -void IT7260_sendCalibrationCmd(void) -{ - IT7260_chipExternalCalibration(false); -} -EXPORT_SYMBOL(IT7260_sendCalibrationCmd); - -static void IT7260_ts_release_all(void) +static void it7260_ts_release_all(struct it7260_ts_data *ts_data) { int finger; - for (finger = 0; finger < gl_ts->pdata->num_of_fingers; finger++) { - input_mt_slot(gl_ts->input_dev, finger); - input_mt_report_slot_state(gl_ts->input_dev, + for (finger = 0; finger < ts_data->pdata->num_of_fingers; finger++) { + input_mt_slot(ts_data->input_dev, finger); + input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, 0); } - input_report_key(gl_ts->input_dev, BTN_TOUCH, 0); - input_sync(gl_ts->input_dev); + input_report_key(ts_data->input_dev, BTN_TOUCH, 0); + input_sync(ts_data->input_dev); } -static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid) +static irqreturn_t it7260_ts_threaded_handler(int irq, void *devid) { - struct PointData point_data; - struct input_dev *input_dev = gl_ts->input_dev; + struct point_data pt_data; + struct it7260_ts_data *ts_data = devid; + struct input_dev *input_dev = ts_data->input_dev; u8 dev_status, finger, touch_count = 0, finger_status; u8 pressure = FD_PRESSURE_NONE; u16 x, y; bool palm_detected; + int ret; /* verify there is point data to read & it is readable and valid */ - IT7260_i2cReadNoReadyCheck(BUF_QUERY, &dev_status, sizeof(dev_status)); - if (!((dev_status & PT_INFO_BITS) & PT_INFO_YES)) - return IRQ_HANDLED; - if (!IT7260_i2cReadNoReadyCheck(BUF_POINT_INFO, (void *)&point_data, - sizeof(point_data))) { - dev_err(&gl_ts->client->dev, + ret = it7260_i2c_read_no_ready_check(ts_data, BUF_QUERY, &dev_status, + sizeof(dev_status)); + if (ret == IT_I2C_READ_RET) + if (!((dev_status & PT_INFO_BITS) & PT_INFO_YES)) + return IRQ_HANDLED; + ret = it7260_i2c_read_no_ready_check(ts_data, BUF_POINT_INFO, + (void *)&pt_data, sizeof(pt_data)); + if (ret != IT_I2C_READ_RET) { + dev_err(&ts_data->client->dev, "failed to read point data buffer\n"); return IRQ_HANDLED; } /* Check if controller moves from idle to active state */ - if ((point_data.flags & PD_FLAGS_DATA_TYPE_BITS) != + if ((pt_data.flags & PD_FLAGS_DATA_TYPE_BITS) != PD_FLAGS_DATA_TYPE_TOUCH) { /* * This code adds the touch-to-wake functionality to the ITE @@ -1061,40 +1226,40 @@ static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid) * schedule a work that tells the pm core to relax once the CPU * cores are up. */ - if (gl_ts->device_needs_wakeup) { - pm_stay_awake(&gl_ts->client->dev); + if (ts_data->device_needs_wakeup) { + pm_stay_awake(&ts_data->client->dev); input_report_key(input_dev, KEY_WAKEUP, 1); input_sync(input_dev); input_report_key(input_dev, KEY_WAKEUP, 0); input_sync(input_dev); - schedule_work(&gl_ts->work_pm_relax); + schedule_work(&ts_data->work_pm_relax); return IRQ_HANDLED; } } - palm_detected = point_data.palm & PD_PALM_FLAG_BIT; - if (palm_detected && gl_ts->pdata->palm_detect_en) { + palm_detected = pt_data.palm & PD_PALM_FLAG_BIT; + if (palm_detected && ts_data->pdata->palm_detect_en) { input_report_key(input_dev, - gl_ts->pdata->palm_detect_keycode, 1); + ts_data->pdata->palm_detect_keycode, 1); input_sync(input_dev); input_report_key(input_dev, - gl_ts->pdata->palm_detect_keycode, 0); + ts_data->pdata->palm_detect_keycode, 0); input_sync(input_dev); } - for (finger = 0; finger < gl_ts->pdata->num_of_fingers; finger++) { - finger_status = point_data.flags & (0x01 << finger); + for (finger = 0; finger < ts_data->pdata->num_of_fingers; finger++) { + finger_status = pt_data.flags & (0x01 << finger); input_mt_slot(input_dev, finger); input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, finger_status != 0); - x = point_data.fd[finger].xLo + - (((u16)(point_data.fd[finger].hi & 0x0F)) << 8); - y = point_data.fd[finger].yLo + - (((u16)(point_data.fd[finger].hi & 0xF0)) << 4); + x = pt_data.fd[finger].xLo + + (((u16)(pt_data.fd[finger].hi & 0x0F)) << 8); + y = pt_data.fd[finger].yLo + + (((u16)(pt_data.fd[finger].hi & 0xF0)) << 4); - pressure = point_data.fd[finger].pressure & FD_PRESSURE_BITS; + pressure = pt_data.fd[finger].pressure & FD_PRESSURE_BITS; if (finger_status) { if (pressure >= FD_PRESSURE_LIGHT) { @@ -1114,35 +1279,66 @@ static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid) return IRQ_HANDLED; } -static void IT7260_ts_work_func(struct work_struct *work) +static void it7260_ts_work_func(struct work_struct *work) { - pm_relax(&gl_ts->client->dev); + struct it7260_ts_data *ts_data = container_of(work, + struct it7260_ts_data, work_pm_relax); + + pm_relax(&ts_data->client->dev); } -static int IT7260_chipIdentify(void) +static int it7260_ts_chip_identify(struct it7260_ts_data *ts_data) { static const uint8_t cmd_ident[] = {CMD_IDENT_CHIP}; static const uint8_t expected_id[] = {0x0A, 'I', 'T', 'E', '7', '2', '6', '0'}; uint8_t chip_id[10] = {0,}; + int ret; - IT7260_waitDeviceReady(false, false); + /* + * Sometimes, the controller may not respond immediately after + * writing the command, so wait for device to get ready. + * FALSE means to retry 20 times at max to read the chip status. + * TRUE means to add delay in each retry. + */ + ret = it7260_wait_device_ready(ts_data, false, true); + if (ret < 0) { + dev_err(&ts_data->client->dev, + "failed to read chip status %d\n", ret); + return ret; + } - if (!IT7260_i2cWriteNoReadyCheck(BUF_COMMAND, cmd_ident, - sizeof(cmd_ident))) { - dev_err(&gl_ts->client->dev, "failed to write CMD_IDENT_CHIP\n"); - return -ENODEV; + ret = it7260_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_ident, + sizeof(cmd_ident)); + if (ret != IT_I2C_WRITE_RET) { + dev_err(&ts_data->client->dev, + "failed to write CMD_IDENT_CHIP %d\n", ret); + return ret; + } + + /* + * Sometimes, the controller may not respond immediately after + * writing the command, so wait for device to get ready. + * TRUE means to retry 500 times at max to read the chip status. + * FALSE means to avoid unnecessary delays in each retry. + */ + ret = it7260_wait_device_ready(ts_data, true, false); + if (ret < 0) { + dev_err(&ts_data->client->dev, + "failed to read chip status %d\n", ret); + return ret; } - IT7260_waitDeviceReady(false, false); - if (!IT7260_i2cReadNoReadyCheck(BUF_RESPONSE, chip_id, - sizeof(chip_id))) { - dev_err(&gl_ts->client->dev, "failed to read chip-id\n"); - return -ENODEV; + ret = it7260_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, chip_id, + sizeof(chip_id)); + if (ret != IT_I2C_READ_RET) { + dev_err(&ts_data->client->dev, + "failed to read chip-id %d\n", ret); + return ret; } - dev_info(&gl_ts->client->dev, - "IT7260_chipIdentify read id: %02X %c%c%c%c%c%c%c %c%c\n", + dev_info(&ts_data->client->dev, + "it7260_ts_chip_identify read id: %02X %c%c%c%c%c%c%c %c%c\n", chip_id[0], chip_id[1], chip_id[2], chip_id[3], chip_id[4], chip_id[5], chip_id[6], chip_id[7], chip_id[8], chip_id[9]); @@ -1150,11 +1346,11 @@ static int IT7260_chipIdentify(void) return -EINVAL; if (chip_id[8] == '5' && chip_id[9] == '6') - dev_info(&gl_ts->client->dev, "rev BX3 found\n"); + dev_info(&ts_data->client->dev, "rev BX3 found\n"); else if (chip_id[8] == '6' && chip_id[9] == '6') - dev_info(&gl_ts->client->dev, "rev BX4 found\n"); + dev_info(&ts_data->client->dev, "rev BX4 found\n"); else - dev_info(&gl_ts->client->dev, "unknown revision (0x%02X 0x%02X) found\n", + dev_info(&ts_data->client->dev, "unknown revision (0x%02X 0x%02X) found\n", chip_id[8], chip_id[9]); return 0; @@ -1166,44 +1362,44 @@ static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA) regulator_set_optimum_mode(reg, load_uA) : 0; } -static int IT7260_regulator_configure(bool on) +static int it7260_regulator_configure(struct it7260_ts_data *ts_data, bool on) { int retval; if (on == false) goto hw_shutdown; - gl_ts->vdd = devm_regulator_get(&gl_ts->client->dev, "vdd"); - if (IS_ERR(gl_ts->vdd)) { - dev_err(&gl_ts->client->dev, + ts_data->vdd = devm_regulator_get(&ts_data->client->dev, "vdd"); + if (IS_ERR(ts_data->vdd)) { + dev_err(&ts_data->client->dev, "%s: Failed to get vdd regulator\n", __func__); - return PTR_ERR(gl_ts->vdd); + return PTR_ERR(ts_data->vdd); } - if (regulator_count_voltages(gl_ts->vdd) > 0) { - retval = regulator_set_voltage(gl_ts->vdd, + if (regulator_count_voltages(ts_data->vdd) > 0) { + retval = regulator_set_voltage(ts_data->vdd, IT_VTG_MIN_UV, IT_VTG_MAX_UV); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "regulator set_vtg failed retval =%d\n", retval); goto err_set_vtg_vdd; } } - gl_ts->avdd = devm_regulator_get(&gl_ts->client->dev, "avdd"); - if (IS_ERR(gl_ts->avdd)) { - dev_err(&gl_ts->client->dev, + ts_data->avdd = devm_regulator_get(&ts_data->client->dev, "avdd"); + if (IS_ERR(ts_data->avdd)) { + dev_err(&ts_data->client->dev, "%s: Failed to get i2c regulator\n", __func__); - retval = PTR_ERR(gl_ts->avdd); + retval = PTR_ERR(ts_data->avdd); goto err_get_vtg_i2c; } - if (regulator_count_voltages(gl_ts->avdd) > 0) { - retval = regulator_set_voltage(gl_ts->avdd, + if (regulator_count_voltages(ts_data->avdd) > 0) { + retval = regulator_set_voltage(ts_data->avdd, IT_I2C_VTG_MIN_UV, IT_I2C_VTG_MAX_UV); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "reg set i2c vtg failed retval =%d\n", retval); goto err_set_vtg_i2c; @@ -1214,55 +1410,55 @@ static int IT7260_regulator_configure(bool on) err_set_vtg_i2c: err_get_vtg_i2c: - if (regulator_count_voltages(gl_ts->vdd) > 0) - regulator_set_voltage(gl_ts->vdd, 0, IT_VTG_MAX_UV); + if (regulator_count_voltages(ts_data->vdd) > 0) + regulator_set_voltage(ts_data->vdd, 0, IT_VTG_MAX_UV); err_set_vtg_vdd: return retval; hw_shutdown: - if (regulator_count_voltages(gl_ts->vdd) > 0) - regulator_set_voltage(gl_ts->vdd, 0, IT_VTG_MAX_UV); - if (regulator_count_voltages(gl_ts->avdd) > 0) - regulator_set_voltage(gl_ts->avdd, 0, IT_I2C_VTG_MAX_UV); + if (regulator_count_voltages(ts_data->vdd) > 0) + regulator_set_voltage(ts_data->vdd, 0, IT_VTG_MAX_UV); + if (regulator_count_voltages(ts_data->avdd) > 0) + regulator_set_voltage(ts_data->avdd, 0, IT_I2C_VTG_MAX_UV); return 0; }; -static int IT7260_power_on(bool on) +static int it7260_power_on(struct it7260_ts_data *ts_data, bool on) { int retval; if (on == false) goto power_off; - retval = reg_set_optimum_mode_check(gl_ts->vdd, + retval = reg_set_optimum_mode_check(ts_data->vdd, IT_ACTIVE_LOAD_UA); if (retval < 0) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "Regulator vdd set_opt failed rc=%d\n", retval); return retval; } - retval = regulator_enable(gl_ts->vdd); + retval = regulator_enable(ts_data->vdd); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "Regulator vdd enable failed rc=%d\n", retval); goto error_reg_en_vdd; } - retval = reg_set_optimum_mode_check(gl_ts->avdd, + retval = reg_set_optimum_mode_check(ts_data->avdd, IT_I2C_ACTIVE_LOAD_UA); if (retval < 0) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "Regulator avdd set_opt failed rc=%d\n", retval); goto error_reg_opt_i2c; } - retval = regulator_enable(gl_ts->avdd); + retval = regulator_enable(ts_data->avdd); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "Regulator avdd enable failed rc=%d\n", retval); goto error_reg_en_avdd; @@ -1271,118 +1467,119 @@ static int IT7260_power_on(bool on) return 0; error_reg_en_avdd: - reg_set_optimum_mode_check(gl_ts->avdd, 0); + reg_set_optimum_mode_check(ts_data->avdd, 0); error_reg_opt_i2c: - regulator_disable(gl_ts->vdd); + regulator_disable(ts_data->vdd); error_reg_en_vdd: - reg_set_optimum_mode_check(gl_ts->vdd, 0); + reg_set_optimum_mode_check(ts_data->vdd, 0); return retval; power_off: - reg_set_optimum_mode_check(gl_ts->vdd, 0); - regulator_disable(gl_ts->vdd); - reg_set_optimum_mode_check(gl_ts->avdd, 0); - regulator_disable(gl_ts->avdd); + reg_set_optimum_mode_check(ts_data->vdd, 0); + regulator_disable(ts_data->vdd); + reg_set_optimum_mode_check(ts_data->avdd, 0); + regulator_disable(ts_data->avdd); return 0; } -static int IT7260_gpio_configure(bool on) +static int it7260_gpio_configure(struct it7260_ts_data *ts_data, bool on) { int retval = 0; if (on) { - if (gpio_is_valid(gl_ts->pdata->irq_gpio)) { + if (gpio_is_valid(ts_data->pdata->irq_gpio)) { /* configure touchscreen irq gpio */ - retval = gpio_request(gl_ts->pdata->irq_gpio, + retval = gpio_request(ts_data->pdata->irq_gpio, "ite_irq_gpio"); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "unable to request irq gpio [%d]\n", retval); goto err_irq_gpio_req; } - retval = gpio_direction_input(gl_ts->pdata->irq_gpio); + retval = gpio_direction_input(ts_data->pdata->irq_gpio); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "unable to set direction for irq gpio [%d]\n", retval); goto err_irq_gpio_dir; } } else { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "irq gpio not provided\n"); goto err_irq_gpio_req; } - if (gpio_is_valid(gl_ts->pdata->reset_gpio)) { + if (gpio_is_valid(ts_data->pdata->reset_gpio)) { /* configure touchscreen reset out gpio */ - retval = gpio_request(gl_ts->pdata->reset_gpio, + retval = gpio_request(ts_data->pdata->reset_gpio, "ite_reset_gpio"); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "unable to request reset gpio [%d]\n", retval); goto err_reset_gpio_req; } retval = gpio_direction_output( - gl_ts->pdata->reset_gpio, 1); + ts_data->pdata->reset_gpio, 1); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "unable to set direction for reset gpio [%d]\n", retval); goto err_reset_gpio_dir; } - if (gl_ts->pdata->low_reset) - gpio_set_value(gl_ts->pdata->reset_gpio, 0); + if (ts_data->pdata->low_reset) + gpio_set_value(ts_data->pdata->reset_gpio, 0); else - gpio_set_value(gl_ts->pdata->reset_gpio, 1); + gpio_set_value(ts_data->pdata->reset_gpio, 1); - msleep(gl_ts->pdata->reset_delay); + msleep(ts_data->pdata->reset_delay); } else { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "reset gpio not provided\n"); goto err_reset_gpio_req; } } else { - if (gpio_is_valid(gl_ts->pdata->irq_gpio)) - gpio_free(gl_ts->pdata->irq_gpio); - if (gpio_is_valid(gl_ts->pdata->reset_gpio)) { + if (gpio_is_valid(ts_data->pdata->irq_gpio)) + gpio_free(ts_data->pdata->irq_gpio); + if (gpio_is_valid(ts_data->pdata->reset_gpio)) { /* * This is intended to save leakage current * only. Even if the call(gpio_direction_input) * fails, only leakage current will be more but * functionality will not be affected. */ - retval = gpio_direction_input(gl_ts->pdata->reset_gpio); + retval = gpio_direction_input( + ts_data->pdata->reset_gpio); if (retval) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "unable to set direction for gpio reset [%d]\n", retval); } - gpio_free(gl_ts->pdata->reset_gpio); + gpio_free(ts_data->pdata->reset_gpio); } } return 0; err_reset_gpio_dir: - if (gpio_is_valid(gl_ts->pdata->reset_gpio)) - gpio_free(gl_ts->pdata->reset_gpio); + if (gpio_is_valid(ts_data->pdata->reset_gpio)) + gpio_free(ts_data->pdata->reset_gpio); err_reset_gpio_req: err_irq_gpio_dir: - if (gpio_is_valid(gl_ts->pdata->irq_gpio)) - gpio_free(gl_ts->pdata->irq_gpio); + if (gpio_is_valid(ts_data->pdata->irq_gpio)) + gpio_free(ts_data->pdata->irq_gpio); err_irq_gpio_req: return retval; } #if CONFIG_OF -static int IT7260_get_dt_coords(struct device *dev, char *name, - struct IT7260_ts_platform_data *pdata) +static int it7260_get_dt_coords(struct device *dev, char *name, + struct it7260_ts_platform_data *pdata) { u32 coords[IT7260_COORDS_ARR_SIZE]; struct property *prop; @@ -1435,9 +1632,10 @@ static int IT7260_get_dt_coords(struct device *dev, char *name, return 0; } -static int IT7260_parse_dt(struct device *dev, - struct IT7260_ts_platform_data *pdata) +static int it7260_parse_dt(struct device *dev, + struct it7260_ts_platform_data *pdata) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); struct device_node *np = dev->of_node; u32 temp_val; int rc; @@ -1481,9 +1679,9 @@ static int IT7260_parse_dt(struct device *dev, return rc; } - snprintf(gl_ts->fw_name, MAX_BUFFER_SIZE, "%s", + snprintf(ts_data->fw_name, MAX_BUFFER_SIZE, "%s", (pdata->fw_name != NULL) ? pdata->fw_name : FW_NAME); - snprintf(gl_ts->cfg_name, MAX_BUFFER_SIZE, "%s", + snprintf(ts_data->cfg_name, MAX_BUFFER_SIZE, "%s", (pdata->cfg_name != NULL) ? pdata->cfg_name : CFG_NAME); rc = of_property_read_u32(np, "ite,reset-delay", &temp_val); @@ -1504,25 +1702,25 @@ static int IT7260_parse_dt(struct device *dev, pdata->low_reset = of_property_read_bool(np, "ite,low-reset"); - rc = IT7260_get_dt_coords(dev, "ite,display-coords", pdata); + rc = it7260_get_dt_coords(dev, "ite,display-coords", pdata); if (rc && (rc != -EINVAL)) return rc; - rc = IT7260_get_dt_coords(dev, "ite,panel-coords", pdata); + rc = it7260_get_dt_coords(dev, "ite,panel-coords", pdata); if (rc && (rc != -EINVAL)) return rc; return 0; } #else -static inline int IT7260_ts_parse_dt(struct device *dev, - struct IT7260_ts_platform_data *pdata) +static inline int it7260_ts_parse_dt(struct device *dev, + struct it7260_ts_platform_data *pdata) { return 0; } #endif -static int IT7260_ts_pinctrl_init(struct IT7260_ts_data *ts_data) +static int it7260_ts_pinctrl_init(struct it7260_ts_data *ts_data) { int retval; @@ -1576,11 +1774,12 @@ err_pinctrl_get: return retval; } -static int IT7260_ts_probe(struct i2c_client *client, +static int it7260_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const uint8_t cmd_start[] = {CMD_UNKNOWN_7}; - struct IT7260_ts_platform_data *pdata; + struct it7260_ts_data *ts_data; + struct it7260_ts_platform_data *pdata; uint8_t rsp[2]; int ret = -1, err; struct dentry *temp; @@ -1590,40 +1789,39 @@ static int IT7260_ts_probe(struct i2c_client *client, return -ENODEV; } - gl_ts = devm_kzalloc(&client->dev, sizeof(*gl_ts), GFP_KERNEL); - if (!gl_ts) + ts_data = devm_kzalloc(&client->dev, sizeof(*ts_data), GFP_KERNEL); + if (!ts_data) return -ENOMEM; - gl_ts->client = client; - i2c_set_clientdata(client, gl_ts); - - if (client->dev.platform_data == NULL) - return -ENODEV; + ts_data->client = client; + i2c_set_clientdata(client, ts_data); if (client->dev.of_node) { pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - ret = IT7260_parse_dt(&client->dev, pdata); + ret = it7260_parse_dt(&client->dev, pdata); if (ret) return ret; } else { pdata = client->dev.platform_data; } - if (!pdata) + if (!pdata) { + dev_err(&client->dev, "No platform data found\n"); return -ENOMEM; + } - gl_ts->pdata = pdata; + ts_data->pdata = pdata; - ret = IT7260_regulator_configure(true); + ret = it7260_regulator_configure(ts_data, true); if (ret < 0) { dev_err(&client->dev, "Failed to configure regulators\n"); goto err_reg_configure; } - ret = IT7260_power_on(true); + ret = it7260_power_on(ts_data, true); if (ret < 0) { dev_err(&client->dev, "Failed to power on\n"); goto err_power_device; @@ -1635,81 +1833,82 @@ static int IT7260_ts_probe(struct i2c_client *client, */ msleep(DELAY_VTG_REG_EN); - ret = IT7260_ts_pinctrl_init(gl_ts); - if (!ret && gl_ts->ts_pinctrl) { + ret = it7260_ts_pinctrl_init(ts_data); + if (!ret && ts_data->ts_pinctrl) { /* * Pinctrl handle is optional. If pinctrl handle is found * let pins to be configured in active state. If not * found continue further without error. */ - ret = pinctrl_select_state(gl_ts->ts_pinctrl, - gl_ts->pinctrl_state_active); + ret = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_active); if (ret < 0) { - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "failed to select pin to active state %d", ret); } } else { - ret = IT7260_gpio_configure(true); + ret = it7260_gpio_configure(ts_data, true); if (ret < 0) { dev_err(&client->dev, "Failed to configure gpios\n"); goto err_gpio_config; } } - ret = IT7260_chipIdentify(); + ret = it7260_ts_chip_identify(ts_data); if (ret) { dev_err(&client->dev, "Failed to identify chip %d!!!", ret); goto err_identification_fail; } - IT7260_get_chip_versions(&client->dev); + it7260_get_chip_versions(ts_data); - gl_ts->input_dev = input_allocate_device(); - if (!gl_ts->input_dev) { + ts_data->input_dev = input_allocate_device(); + if (!ts_data->input_dev) { dev_err(&client->dev, "failed to allocate input device\n"); ret = -ENOMEM; goto err_input_alloc; } /* Initialize mutex for fw and cfg upgrade */ - mutex_init(&gl_ts->fw_cfg_mutex); - - gl_ts->input_dev->name = DEVICE_NAME; - gl_ts->input_dev->phys = "I2C"; - gl_ts->input_dev->id.bustype = BUS_I2C; - gl_ts->input_dev->id.vendor = 0x0001; - gl_ts->input_dev->id.product = 0x7260; - set_bit(EV_SYN, gl_ts->input_dev->evbit); - set_bit(EV_KEY, gl_ts->input_dev->evbit); - set_bit(EV_ABS, gl_ts->input_dev->evbit); - set_bit(INPUT_PROP_DIRECT, gl_ts->input_dev->propbit); - set_bit(BTN_TOUCH, gl_ts->input_dev->keybit); - input_set_abs_params(gl_ts->input_dev, ABS_MT_POSITION_X, - gl_ts->pdata->disp_minx, gl_ts->pdata->disp_maxx, 0, 0); - input_set_abs_params(gl_ts->input_dev, ABS_MT_POSITION_Y, - gl_ts->pdata->disp_miny, gl_ts->pdata->disp_maxy, 0, 0); - input_mt_init_slots(gl_ts->input_dev, gl_ts->pdata->num_of_fingers, 0); - - input_set_drvdata(gl_ts->input_dev, gl_ts); + mutex_init(&ts_data->fw_cfg_mutex); + + ts_data->input_dev->name = DEVICE_NAME; + ts_data->input_dev->phys = "I2C"; + ts_data->input_dev->id.bustype = BUS_I2C; + ts_data->input_dev->id.vendor = 0x0001; + ts_data->input_dev->id.product = 0x7260; + set_bit(EV_SYN, ts_data->input_dev->evbit); + set_bit(EV_KEY, ts_data->input_dev->evbit); + set_bit(EV_ABS, ts_data->input_dev->evbit); + set_bit(INPUT_PROP_DIRECT, ts_data->input_dev->propbit); + set_bit(BTN_TOUCH, ts_data->input_dev->keybit); + input_set_abs_params(ts_data->input_dev, ABS_MT_POSITION_X, + ts_data->pdata->disp_minx, ts_data->pdata->disp_maxx, 0, 0); + input_set_abs_params(ts_data->input_dev, ABS_MT_POSITION_Y, + ts_data->pdata->disp_miny, ts_data->pdata->disp_maxy, 0, 0); + input_mt_init_slots(ts_data->input_dev, + ts_data->pdata->num_of_fingers, 0); + + input_set_drvdata(ts_data->input_dev, ts_data); if (pdata->wakeup) { - set_bit(KEY_WAKEUP, gl_ts->input_dev->keybit); - INIT_WORK(&gl_ts->work_pm_relax, IT7260_ts_work_func); + set_bit(KEY_WAKEUP, ts_data->input_dev->keybit); + INIT_WORK(&ts_data->work_pm_relax, it7260_ts_work_func); device_init_wakeup(&client->dev, pdata->wakeup); } if (pdata->palm_detect_en) - set_bit(gl_ts->pdata->palm_detect_keycode, - gl_ts->input_dev->keybit); + set_bit(ts_data->pdata->palm_detect_keycode, + ts_data->input_dev->keybit); - if (input_register_device(gl_ts->input_dev)) { + if (input_register_device(ts_data->input_dev)) { dev_err(&client->dev, "failed to register input device\n"); goto err_input_register; } - if (request_threaded_irq(client->irq, NULL, IT7260_ts_threaded_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, gl_ts)) { + if (request_threaded_irq(client->irq, NULL, it7260_ts_threaded_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts_data)) { dev_err(&client->dev, "request_irq failed\n"); goto err_irq_reg; } @@ -1720,30 +1919,31 @@ static int IT7260_ts_probe(struct i2c_client *client, } #if defined(CONFIG_FB) - gl_ts->fb_notif.notifier_call = fb_notifier_callback; + ts_data->fb_notif.notifier_call = fb_notifier_callback; - ret = fb_register_client(&gl_ts->fb_notif); + ret = fb_register_client(&ts_data->fb_notif); if (ret) dev_err(&client->dev, "Unable to register fb_notifier %d\n", ret); #endif - IT7260_i2cWriteNoReadyCheck(BUF_COMMAND, cmd_start, sizeof(cmd_start)); + it7260_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_start, + sizeof(cmd_start)); msleep(pdata->reset_delay); - IT7260_i2cReadNoReadyCheck(BUF_RESPONSE, rsp, sizeof(rsp)); + it7260_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, rsp, sizeof(rsp)); msleep(pdata->reset_delay); - gl_ts->dir = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL); - if (gl_ts->dir == NULL || IS_ERR(gl_ts->dir)) { + ts_data->dir = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL); + if (ts_data->dir == NULL || IS_ERR(ts_data->dir)) { dev_err(&client->dev, "%s: Failed to create debugfs directory, ret = %ld\n", - __func__, PTR_ERR(gl_ts->dir)); - ret = PTR_ERR(gl_ts->dir); + __func__, PTR_ERR(ts_data->dir)); + ret = PTR_ERR(ts_data->dir); goto err_create_debugfs_dir; } - temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, gl_ts->dir, - gl_ts, &debug_suspend_fops); + temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, ts_data->dir, + ts_data, &debug_suspend_fops); if (temp == NULL || IS_ERR(temp)) { dev_err(&client->dev, "%s: Failed to create suspend debugfs file, ret = %ld\n", @@ -1755,40 +1955,40 @@ static int IT7260_ts_probe(struct i2c_client *client, return 0; err_create_debugfs_file: - debugfs_remove_recursive(gl_ts->dir); + debugfs_remove_recursive(ts_data->dir); err_create_debugfs_dir: #if defined(CONFIG_FB) - if (fb_unregister_client(&gl_ts->fb_notif)) + if (fb_unregister_client(&ts_data->fb_notif)) dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); #endif sysfs_remove_group(&(client->dev.kobj), &it7260_attr_group); err_sysfs_grp_create: - free_irq(client->irq, gl_ts); + free_irq(client->irq, ts_data); err_irq_reg: - input_unregister_device(gl_ts->input_dev); + input_unregister_device(ts_data->input_dev); err_input_register: if (pdata->wakeup) { - cancel_work_sync(&gl_ts->work_pm_relax); + cancel_work_sync(&ts_data->work_pm_relax); device_init_wakeup(&client->dev, false); } - if (gl_ts->input_dev) - input_free_device(gl_ts->input_dev); - gl_ts->input_dev = NULL; + if (ts_data->input_dev) + input_free_device(ts_data->input_dev); + ts_data->input_dev = NULL; err_input_alloc: err_identification_fail: - if (gl_ts->ts_pinctrl) { - if (IS_ERR_OR_NULL(gl_ts->pinctrl_state_release)) { - devm_pinctrl_put(gl_ts->ts_pinctrl); - gl_ts->ts_pinctrl = NULL; + if (ts_data->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { + devm_pinctrl_put(ts_data->ts_pinctrl); + ts_data->ts_pinctrl = NULL; } else { - err = pinctrl_select_state(gl_ts->ts_pinctrl, - gl_ts->pinctrl_state_release); + err = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_release); if (err) - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "failed to select relase pinctrl state %d\n", err); } @@ -1800,54 +2000,55 @@ err_identification_fail: } err_gpio_config: - IT7260_power_on(false); + it7260_power_on(ts_data, false); err_power_device: - IT7260_regulator_configure(false); + it7260_regulator_configure(ts_data, false); err_reg_configure: return ret; } -static int IT7260_ts_remove(struct i2c_client *client) +static int it7260_ts_remove(struct i2c_client *client) { + struct it7260_ts_data *ts_data = i2c_get_clientdata(client); int ret; - debugfs_remove_recursive(gl_ts->dir); + debugfs_remove_recursive(ts_data->dir); #if defined(CONFIG_FB) - if (fb_unregister_client(&gl_ts->fb_notif)) + if (fb_unregister_client(&ts_data->fb_notif)) dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); #endif sysfs_remove_group(&(client->dev.kobj), &it7260_attr_group); - free_irq(client->irq, gl_ts); - input_unregister_device(gl_ts->input_dev); - if (gl_ts->input_dev) - input_free_device(gl_ts->input_dev); - gl_ts->input_dev = NULL; - if (gl_ts->pdata->wakeup) { - cancel_work_sync(&gl_ts->work_pm_relax); + free_irq(client->irq, ts_data); + input_unregister_device(ts_data->input_dev); + if (ts_data->input_dev) + input_free_device(ts_data->input_dev); + ts_data->input_dev = NULL; + if (ts_data->pdata->wakeup) { + cancel_work_sync(&ts_data->work_pm_relax); device_init_wakeup(&client->dev, false); } - if (gl_ts->ts_pinctrl) { - if (IS_ERR_OR_NULL(gl_ts->pinctrl_state_release)) { - devm_pinctrl_put(gl_ts->ts_pinctrl); - gl_ts->ts_pinctrl = NULL; + if (ts_data->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { + devm_pinctrl_put(ts_data->ts_pinctrl); + ts_data->ts_pinctrl = NULL; } else { - ret = pinctrl_select_state(gl_ts->ts_pinctrl, - gl_ts->pinctrl_state_release); + ret = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_release); if (ret) - dev_err(&gl_ts->client->dev, + dev_err(&ts_data->client->dev, "failed to select relase pinctrl state %d\n", ret); } } else { - if (gpio_is_valid(gl_ts->pdata->reset_gpio)) - gpio_free(gl_ts->pdata->reset_gpio); - if (gpio_is_valid(gl_ts->pdata->irq_gpio)) - gpio_free(gl_ts->pdata->irq_gpio); + if (gpio_is_valid(ts_data->pdata->reset_gpio)) + gpio_free(ts_data->pdata->reset_gpio); + if (gpio_is_valid(ts_data->pdata->irq_gpio)) + gpio_free(ts_data->pdata->irq_gpio); } - IT7260_power_on(false); - IT7260_regulator_configure(false); + it7260_power_on(ts_data, false); + it7260_regulator_configure(ts_data, false); return 0; } @@ -1856,17 +2057,19 @@ static int IT7260_ts_remove(struct i2c_client *client) static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { + struct it7260_ts_data *ts_data = container_of(self, + struct it7260_ts_data, fb_notif); struct fb_event *evdata = data; int *blank; - if (evdata && evdata->data && gl_ts && gl_ts->client) { + if (evdata && evdata->data && ts_data && ts_data->client) { if (event == FB_EVENT_BLANK) { blank = evdata->data; if (*blank == FB_BLANK_UNBLANK) - IT7260_ts_resume(&(gl_ts->client->dev)); + it7260_ts_resume(&(ts_data->client->dev)); else if (*blank == FB_BLANK_POWERDOWN || *blank == FB_BLANK_VSYNC_SUSPEND) - IT7260_ts_suspend(&(gl_ts->client->dev)); + it7260_ts_suspend(&(ts_data->client->dev)); } } @@ -1875,30 +2078,32 @@ static int fb_notifier_callback(struct notifier_block *self, #endif #ifdef CONFIG_PM -static int IT7260_ts_resume(struct device *dev) +static int it7260_ts_resume(struct device *dev) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); int retval; if (device_may_wakeup(dev)) { - if (gl_ts->device_needs_wakeup) { + if (ts_data->device_needs_wakeup) { /* Set active current for the avdd regulator */ - if (gl_ts->pdata->avdd_lpm_cur) { - retval = reg_set_optimum_mode_check(gl_ts->avdd, + if (ts_data->pdata->avdd_lpm_cur) { + retval = reg_set_optimum_mode_check( + ts_data->avdd, IT_I2C_ACTIVE_LOAD_UA); if (retval < 0) dev_err(dev, "Regulator avdd set_opt failed at resume rc=%d\n", retval); } - gl_ts->device_needs_wakeup = false; - disable_irq_wake(gl_ts->client->irq); + ts_data->device_needs_wakeup = false; + disable_irq_wake(ts_data->client->irq); } return 0; } - if (gl_ts->ts_pinctrl) { - retval = pinctrl_select_state(gl_ts->ts_pinctrl, - gl_ts->pinctrl_state_active); + if (ts_data->ts_pinctrl) { + retval = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_active); if (retval < 0) { dev_err(dev, "Cannot get default pinctrl state %d\n", retval); @@ -1906,50 +2111,53 @@ static int IT7260_ts_resume(struct device *dev) } } - enable_irq(gl_ts->client->irq); - gl_ts->suspended = false; + enable_irq(ts_data->client->irq); + ts_data->suspended = false; return 0; err_pinctrl_select_suspend: return retval; } -static int IT7260_ts_suspend(struct device *dev) +static int it7260_ts_suspend(struct device *dev) { + struct it7260_ts_data *ts_data = dev_get_drvdata(dev); int retval; - if (gl_ts->fw_cfg_uploading) { + if (ts_data->fw_cfg_uploading) { dev_dbg(dev, "Fw/cfg uploading. Can't go to suspend.\n"); return -EBUSY; } if (device_may_wakeup(dev)) { - if (!gl_ts->device_needs_wakeup) { + if (!ts_data->device_needs_wakeup) { /* put the device in low power idle mode */ - IT7260_ts_chipLowPowerMode(PWR_CTL_LOW_POWER_MODE); + it7260_ts_chip_low_power_mode(ts_data, + PWR_CTL_LOW_POWER_MODE); /* Set lpm current for avdd regulator */ - if (gl_ts->pdata->avdd_lpm_cur) { - retval = reg_set_optimum_mode_check(gl_ts->avdd, - gl_ts->pdata->avdd_lpm_cur); + if (ts_data->pdata->avdd_lpm_cur) { + retval = reg_set_optimum_mode_check( + ts_data->avdd, + ts_data->pdata->avdd_lpm_cur); if (retval < 0) dev_err(dev, "Regulator avdd set_opt failed at suspend rc=%d\n", retval); } - gl_ts->device_needs_wakeup = true; - enable_irq_wake(gl_ts->client->irq); + ts_data->device_needs_wakeup = true; + enable_irq_wake(ts_data->client->irq); } return 0; } - disable_irq(gl_ts->client->irq); + disable_irq(ts_data->client->irq); - IT7260_ts_release_all(); + it7260_ts_release_all(ts_data); - if (gl_ts->ts_pinctrl) { - retval = pinctrl_select_state(gl_ts->ts_pinctrl, - gl_ts->pinctrl_state_suspend); + if (ts_data->ts_pinctrl) { + retval = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_suspend); if (retval < 0) { dev_err(dev, "Cannot get idle pinctrl state %d\n", retval); @@ -1957,7 +2165,7 @@ static int IT7260_ts_suspend(struct device *dev) } } - gl_ts->suspended = true; + ts_data->suspended = true; return 0; @@ -1965,49 +2173,49 @@ err_pinctrl_select_suspend: return retval; } -static const struct dev_pm_ops IT7260_ts_dev_pm_ops = { - .suspend = IT7260_ts_suspend, - .resume = IT7260_ts_resume, +static const struct dev_pm_ops it7260_ts_dev_pm_ops = { + .suspend = it7260_ts_suspend, + .resume = it7260_ts_resume, }; #else -static int IT7260_ts_resume(struct device *dev) +static int it7260_ts_resume(struct device *dev) { return 0; } -static int IT7260_ts_suspend(struct device *dev) +static int it7260_ts_suspend(struct device *dev) { return 0; } #endif -static const struct i2c_device_id IT7260_ts_id[] = { +static const struct i2c_device_id it7260_ts_id[] = { { DEVICE_NAME, 0}, {} }; -MODULE_DEVICE_TABLE(i2c, IT7260_ts_id); +MODULE_DEVICE_TABLE(i2c, it7260_ts_id); -static const struct of_device_id IT7260_match_table[] = { +static const struct of_device_id it7260_match_table[] = { { .compatible = "ite,it7260_ts",}, {}, }; -static struct i2c_driver IT7260_ts_driver = { +static struct i2c_driver it7260_ts_driver = { .driver = { .owner = THIS_MODULE, .name = DEVICE_NAME, - .of_match_table = IT7260_match_table, + .of_match_table = it7260_match_table, #ifdef CONFIG_PM - .pm = &IT7260_ts_dev_pm_ops, + .pm = &it7260_ts_dev_pm_ops, #endif }, - .probe = IT7260_ts_probe, - .remove = IT7260_ts_remove, - .id_table = IT7260_ts_id, + .probe = it7260_ts_probe, + .remove = it7260_ts_remove, + .id_table = it7260_ts_id, }; -module_i2c_driver(IT7260_ts_driver); +module_i2c_driver(it7260_ts_driver); -MODULE_DESCRIPTION("IT7260 Touchscreen Driver"); +MODULE_DESCRIPTION("it7260 Touchscreen Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/msg21xx_ts.c b/drivers/input/touchscreen/msg21xx_ts.c index 4eb7fd4b1cc9..8f2c4da578fc 100644 --- a/drivers/input/touchscreen/msg21xx_ts.c +++ b/drivers/input/touchscreen/msg21xx_ts.c @@ -5,6 +5,8 @@ * * Copyright (C) 2012 Bruce Ding <bruce.ding@mstarsemi.com> * + * Copyright (c) 2014-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 as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,72 +19,55 @@ */ #include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/input.h> +#include <linux/input/mt.h> #include <linux/interrupt.h> #include <linux/i2c.h> -#include <linux/timer.h> #include <linux/gpio.h> - +#include <linux/of_gpio.h> #include <linux/sysfs.h> #include <linux/init.h> #include <linux/mutex.h> -#include <mach/gpio.h> -#include <linux/spinlock.h> #include <linux/delay.h> #include <linux/slab.h> - -#include <linux/syscalls.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/fcntl.h> +#include <linux/firmware.h> #include <linux/string.h> -#include <asm/unistd.h> -#include <linux/cdev.h> -#include <asm/uaccess.h> -#if defined(CONFIG_HAS_EARLYSUSPEND) -#include <linux/earlysuspend.h> -#endif -#include <linux/input.h> +#include <linux/kthread.h> +#include <linux/regulator/consumer.h> + #if defined(CONFIG_FB) #include <linux/notifier.h> #include <linux/fb.h> #endif -#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR +#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR #include <linux/input/vir_ps.h> #endif -/*=============================================================*/ -// Macro Definition -/*=============================================================*/ +/* Macro Definition */ #define TOUCH_DRIVER_DEBUG 0 #if (TOUCH_DRIVER_DEBUG == 1) -#define DBG(fmt, arg...) pr_err(fmt, ##arg) //pr_info(fmt, ##arg) +#define DBG(fmt, arg...) pr_info(fmt, ##arg) #else #define DBG(fmt, arg...) #endif -/*=============================================================*/ -// Constant Value & Variable Definition -/*=============================================================*/ +/* Constant Value & Variable Definition */ -#define U8 unsigned char -#define U16 unsigned short -#define U32 unsigned int -#define S8 signed char -#define S16 signed short -#define S32 signed int +#define MSTAR_VTG_MIN_UV 2800000 +#define MSTAR_VTG_MAX_UV 3300000 +#define MSTAR_I2C_VTG_MIN_UV 1800000 +#define MSTAR_I2C_VTG_MAX_UV 1800000 + +#define MAX_BUTTONS 4 +#define FT_COORDS_ARR_SIZE 4 +#define MSTAR_FW_NAME_MAX_LEN 50 + +#define MSTAR_CHIPTOP_REGISTER_BANK 0x1E +#define MSTAR_CHIPTOP_REGISTER_ICTYPE 0xCC +#define MSTAR_INIT_SW_ID 0x7FF -#define TOUCH_SCREEN_X_MIN (0) -#define TOUCH_SCREEN_Y_MIN (0) -/* - * Note. - * Please change the below touch screen resolution according to the touch panel that you are using. - */ -#define TOUCH_SCREEN_X_MAX (480) -#define TOUCH_SCREEN_Y_MAX (800) /* * Note. * Please do not change the below setting. @@ -90,62 +75,29 @@ #define TPD_WIDTH (2048) #define TPD_HEIGHT (2048) -/* - * Note. - * Please change the below GPIO pin setting to follow the platform that you are using - */ -static int int_gpio = 1; -static int reset_gpio = 0; -#define MS_TS_MSG21XX_GPIO_RST reset_gpio -#define MS_TS_MSG21XX_GPIO_INT int_gpio -//---------------------------------------------------------------------// - -//#define SYSFS_AUTHORITY_CHANGE_FOR_CTS_TEST - -#ifdef SYSFS_AUTHORITY_CHANGE_FOR_CTS_TEST -#define SYSFS_AUTHORITY (0644) -#else -#define SYSFS_AUTHORITY (0777) -#endif - -#define FIRMWARE_AUTOUPDATE #ifdef FIRMWARE_AUTOUPDATE -typedef enum { - SWID_START = 1, - SWID_TRULY = SWID_START, - SWID_NULL, -} SWID_ENUM; +enum { + SWID_START = 1, + SWID_TRULY = SWID_START, + SWID_NULL, +}; -unsigned char MSG_FIRMWARE[1][33*1024] = -{ - { - #include "msg21xx_truly_update_bin.h" - } +static unsigned char MSG_FIRMWARE[1][33*1024] = { { + #include "msg21xx_truly_update_bin.h" + } }; #endif #define CONFIG_TP_HAVE_KEY -/* - * Note. - * If the below virtual key value definition are not consistent with those that defined in key layout file of platform, - * please change the below virtual key value to follow the platform that you are using. - */ -#ifdef CONFIG_TP_HAVE_KEY -#define TOUCH_KEY_MENU (139) //229 -#define TOUCH_KEY_HOME (172) //102 -#define TOUCH_KEY_BACK (158) -#define TOUCH_KEY_SEARCH (217) - -const U16 tp_key_array[] = {TOUCH_KEY_MENU, TOUCH_KEY_HOME, TOUCH_KEY_BACK, TOUCH_KEY_SEARCH}; -#define MAX_KEY_NUM (sizeof(tp_key_array)/sizeof(tp_key_array[0])) -#endif +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" -#define SLAVE_I2C_ID_DBBUS (0xC4>>1) -#define SLAVE_I2C_ID_DWI2C (0x4C>>1) +#define SLAVE_I2C_ID_DBBUS (0xC4>>1) -#define DEMO_MODE_PACKET_LENGTH (8) -#define MAX_TOUCH_NUM (2) //5 +#define DEMO_MODE_PACKET_LENGTH (8) +#define MAX_TOUCH_NUM (2) #define TP_PRINT #ifdef TP_PRINT @@ -153,1605 +105,2089 @@ static int tp_print_proc_read(void); static void tp_print_create_entry(void); #endif -static char *fw_version = NULL; // customer firmware version -static U16 fw_version_major = 0; -static U16 fw_version_minor = 0; -static U8 temp[94][1024]; -static U32 crc32_table[256]; -static int FwDataCnt = 0; -static U8 bFwUpdating = 0; -static struct class *firmware_class = NULL; -static struct device *firmware_cmd_dev = NULL; +static char *fw_version; /* customer firmware version */ +static unsigned short fw_version_major; +static unsigned short fw_version_minor; +static unsigned char temp[94][1024]; +static unsigned int crc32_table[256]; +static int FwDataCnt; +static unsigned char bFwUpdating; +static struct class *firmware_class; +static struct device *firmware_cmd_dev; + +static struct i2c_client *i2c_client; + +static u32 button_map[MAX_BUTTONS]; +static u32 num_buttons; + +static unsigned short update_bin_major, update_bin_minor; +static unsigned short main_sw_id = MSTAR_INIT_SW_ID; +static unsigned short info_sw_id = MSTAR_INIT_SW_ID; +static unsigned int bin_conf_crc32; + +struct msg21xx_ts_platform_data { + const char *name; + char fw_name[MSTAR_FW_NAME_MAX_LEN]; + char *fw_version; + unsigned short fw_version_major; + unsigned short fw_version_minor; + u32 irqflags; + u32 irq_gpio; + u32 irq_gpio_flags; + u32 reset_gpio; + u32 reset_gpio_flags; + u32 family_id; + u32 x_max; + u32 y_max; + u32 x_min; + u32 y_min; + u32 panel_minx; + u32 panel_miny; + u32 panel_maxx; + u32 panel_maxy; + u32 num_max_touches; + bool no_force_update; + bool i2c_pull_up; + bool ignore_id_check; + int (*power_init)(bool); + int (*power_on)(bool); + int (*power_init)(bool); + int (*power_on)(bool); +}; -static struct i2c_client *i2c_client = NULL; +static struct msg21xx_ts_platform_data *pdata; + +struct msg21xx_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + const struct msg21xx_ts_platform_data *pdata; + struct regulator *vdd; + struct regulator *vcc_i2c; + bool loading_fw; + u8 family_id; + struct dentry *dir; + u16 addr; + bool suspended; + char *ts_info; + u8 *tch_data; + u32 tch_data_len; + u8 fw_ver[3]; + u8 fw_vendor_id; +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#endif + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; + struct mutex ts_mutex; +}; + +static struct msg21xx_ts_data *ts_data; #if defined(CONFIG_FB) -static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); -static struct notifier_block msg21xx_fb_notif; -#elif defined (CONFIG_HAS_EARLYSUSPEND) -static struct early_suspend mstar_ts_early_suspend; +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); #endif #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR -static U8 bEnableTpProximity = 0; -static U8 bFaceClosingTp = 0; +static unsigned char bEnableTpProximity; +static unsigned char bFaceClosingTp; #endif -static U8 bTpInSuspend = 0; -static int irq_msg21xx = -1; -static struct work_struct msg21xx_wk; static struct mutex msg21xx_mutex; -static struct input_dev *input_dev = NULL; +static struct input_dev *input_dev; -/*=============================================================*/ -// Data Type Definition -/*=============================================================*/ -typedef struct -{ - U16 x; - U16 y; -} touchPoint_t; +/* Data Type Definition */ -/// max 80+1+1 = 82 bytes -typedef struct -{ - touchPoint_t point[MAX_TOUCH_NUM]; - U8 count; - U8 keycode; -} touchInfo_t; +struct touchPoint_t { + unsigned short x; + unsigned short y; +}; -enum i2c_speed -{ - I2C_SLOW = 0, - I2C_NORMAL = 1, /* Enable erasing/writing for 10 msec. */ - I2C_FAST = 2, /* Disable EWENB before 10 msec timeout. */ +struct touchInfo_t { + struct touchPoint_t point[MAX_TOUCH_NUM]; + unsigned char count; + unsigned char keycode; }; -typedef enum -{ - EMEM_ALL = 0, - EMEM_MAIN, - EMEM_INFO, -} EMEM_TYPE_t; -/*=============================================================*/ -// Function Definition -/*=============================================================*/ +enum EMEM_TYPE_t { + EMEM_ALL = 0, + EMEM_MAIN, + EMEM_INFO, +}; + +/* Function Definition */ -/// CRC -static U32 _CRC_doReflect(U32 ref, S8 ch) +static unsigned int _CRC_doReflect(unsigned int ref, signed char ch) { - U32 value = 0; - U32 i = 0; - - for (i = 1; i < (ch + 1); i ++) - { - if (ref & 1) - { - value |= 1 << (ch - i); - } - ref >>= 1; - } - - return value; + unsigned int value = 0; + unsigned int i = 0; + + for (i = 1; i < (ch + 1); i++) { + if (ref & 1) + value |= 1 << (ch - i); + ref >>= 1; + } + + return value; } -U32 _CRC_getValue(U32 text, U32 prevCRC) +static unsigned int _CRC_getValue(unsigned int text, unsigned int prevCRC) { - U32 ulCRC = prevCRC; + unsigned int ulCRC = prevCRC; - ulCRC = (ulCRC >> 8) ^ crc32_table[(ulCRC & 0xFF) ^ text]; + ulCRC = (ulCRC >> 8) ^ crc32_table[(ulCRC & 0xFF) ^ text]; - return ulCRC; + return ulCRC; } static void _CRC_initTable(void) { - U32 magic_number = 0x04c11db7; - U32 i, j; - - for (i = 0; i <= 0xFF; i ++) - { - crc32_table[i] = _CRC_doReflect (i, 8) << 24; - for (j = 0; j < 8; j ++) - { - crc32_table[i] = (crc32_table[i] << 1) ^ (crc32_table[i] & (0x80000000L) ? magic_number : 0); - } - crc32_table[i] = _CRC_doReflect(crc32_table[i], 32); - } + unsigned int magic_number = 0x04c11db7; + unsigned int i, j; + + for (i = 0; i <= 0xFF; i++) { + crc32_table[i] = _CRC_doReflect(i, 8) << 24; + for (j = 0; j < 8; j++) + crc32_table[i] = (crc32_table[i] << 1) ^ + (crc32_table[i] & (0x80000000L) ? + magic_number : 0); + crc32_table[i] = _CRC_doReflect(crc32_table[i], 32); + } } static void reset_hw(void) { - DBG("reset_hw()\n"); - - gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0); - mdelay(100); /* Note that the RST must be in LOW 10ms at least */ - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1); - mdelay(100); /* Enable the interrupt service thread/routine for INT after 50ms */ + DBG("reset_hw()\n"); + + gpio_direction_output(pdata->reset_gpio, 1); + gpio_set_value_cansleep(pdata->reset_gpio, 0); + msleep(100); /* Note that the RST must be in LOW 10ms at least */ + gpio_set_value_cansleep(pdata->reset_gpio, 1); + /* Enable the interrupt service thread/routine for INT after 50ms */ + msleep(100); } -static int read_i2c_seq(U8 addr, U8* buf, U16 size) +static int read_i2c_seq(unsigned char addr, unsigned char *buf, + unsigned short size) { - int rc = 0; - struct i2c_msg msgs[] = - { - { - .addr = addr, - .flags = I2C_M_RD, // read flag - .len = size, - .buf = buf, - }, - }; - - /* If everything went ok (i.e. 1 msg transmitted), return #bytes - transmitted, else error code. */ - if (i2c_client != NULL) - { - rc = i2c_transfer(i2c_client->adapter, msgs, 1); - if (rc < 0) - { - DBG("read_i2c_seq() error %d\n", rc); - } - } - else - { - DBG("i2c_client is NULL\n"); - } - - return rc; + int rc = 0; + struct i2c_msg msgs[] = { + { + .addr = addr, + .flags = I2C_M_RD, /* read flag*/ + .len = size, + .buf = buf, + }, + }; + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + * transmitted, else error code. + */ + if (i2c_client != NULL) { + rc = i2c_transfer(i2c_client->adapter, msgs, 1); + if (rc < 0) + DBG("read_i2c_seq() error %d\n", rc); + } else { + DBG("i2c_client is NULL\n"); + } + + return rc; } -static int write_i2c_seq(U8 addr, U8* buf, U16 size) +static int write_i2c_seq(unsigned char addr, unsigned char *buf, + unsigned short size) { - int rc = 0; - struct i2c_msg msgs[] = - { - { - .addr = addr, - .flags = 0, // if read flag is undefined, then it means write flag. - .len = size, - .buf = buf, - }, - }; - - /* If everything went ok (i.e. 1 msg transmitted), return #bytes - transmitted, else error code. */ - if (i2c_client != NULL) - { - rc = i2c_transfer(i2c_client->adapter, msgs, 1); - if ( rc < 0 ) - { - DBG("write_i2c_seq() error %d\n", rc); - } - } - else - { - DBG("i2c_client is NULL\n"); - } - - return rc; + int rc = 0; + struct i2c_msg msgs[] = { + { + .addr = addr, + /* if read flag is undefined, + * then it means write flag. + */ + .flags = 0, + .len = size, + .buf = buf, + }, + }; + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + * transmitted, else error code. + */ + if (i2c_client != NULL) { + rc = i2c_transfer(i2c_client->adapter, msgs, 1); + if (rc < 0) + DBG("write_i2c_seq() error %d\n", rc); + } else { + DBG("i2c_client is NULL\n"); + } + + return rc; } -static U16 read_reg(U8 bank, U8 addr) +static unsigned short read_reg(unsigned char bank, unsigned char addr) { - U8 tx_data[3] = {0x10, bank, addr}; - U8 rx_data[2] = {0}; + unsigned char tx_data[3] = {0x10, bank, addr}; + unsigned char rx_data[2] = {0}; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 3); - read_i2c_seq(SLAVE_I2C_ID_DBBUS, &rx_data[0], 2); + write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 3); + read_i2c_seq(SLAVE_I2C_ID_DBBUS, &rx_data[0], 2); - return (rx_data[1] << 8 | rx_data[0]); + return rx_data[1] << 8 | rx_data[0]; } -static void write_reg(U8 bank, U8 addr, U16 data) +static void write_reg(unsigned char bank, unsigned char addr, + unsigned short data) { - U8 tx_data[5] = {0x10, bank, addr, data & 0xFF, data >> 8}; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 5); -} + unsigned char tx_data[5] = {0x10, bank, addr, data & 0xFF, data >> 8}; -static void write_reg_8bit(U8 bank, U8 addr, U8 data) -{ - U8 tx_data[4] = {0x10, bank, addr, data}; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 4); + write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 5); } -void dbbusDWIICEnterSerialDebugMode(void) +static void write_reg_8bit(unsigned char bank, unsigned char addr, + unsigned char data) { - U8 data[5]; - - // Enter the Serial Debug Mode - data[0] = 0x53; - data[1] = 0x45; - data[2] = 0x52; - data[3] = 0x44; - data[4] = 0x42; + unsigned char tx_data[4] = {0x10, bank, addr, data}; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 5); + write_i2c_seq(SLAVE_I2C_ID_DBBUS, &tx_data[0], 4); } -void dbbusDWIICStopMCU(void) +static void dbbusDWIICEnterSerialDebugMode(void) { - U8 data[1]; + unsigned char data[5]; - // Stop the MCU - data[0] = 0x37; + /* Enter the Serial Debug Mode */ + data[0] = 0x53; + data[1] = 0x45; + data[2] = 0x52; + data[3] = 0x44; + data[4] = 0x42; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); + write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 5); } -void dbbusDWIICIICUseBus(void) +static void dbbusDWIICStopMCU(void) { - U8 data[1]; + unsigned char data[1]; - // IIC Use Bus - data[0] = 0x35; + /* Stop the MCU */ + data[0] = 0x37; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); + write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); } -void dbbusDWIICIICReshape(void) +static void dbbusDWIICIICUseBus(void) { - U8 data[1]; + unsigned char data[1]; - // IIC Re-shape - data[0] = 0x71; + /* IIC Use Bus */ + data[0] = 0x35; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); + write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); } -void dbbusDWIICIICNotUseBus(void) +static void dbbusDWIICIICReshape(void) { - U8 data[1]; + unsigned char data[1]; - // IIC Not Use Bus - data[0] = 0x34; + /* IIC Re-shape */ + data[0] = 0x71; - write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); + write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); } -void dbbusDWIICNotStopMCU(void) +static unsigned char get_ic_type(void) { - U8 data[1]; - - // Not Stop the MCU - data[0] = 0x36; + unsigned char ic_type = 0; + unsigned char bank; + unsigned char addr; + + reset_hw(); + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + msleep(300); + + /* stop mcu */ + write_reg_8bit(0x0F, 0xE6, 0x01); + /* disable watch dog */ + write_reg(0x3C, 0x60, 0xAA55); + /* get ic type */ + bank = MSTAR_CHIPTOP_REGISTER_BANK; + addr = MSTAR_CHIPTOP_REGISTER_ICTYPE; + ic_type = (0xff)&(read_reg(bank, addr)); + + if (ic_type != 1 /* msg2133 */ + && ic_type != 2 /* msg21xxA */ + && ic_type != 3) /* msg26xxM */ { + ic_type = 0; + } + + reset_hw(); + + return ic_type; +} - write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); +static int msg21xx_read_firmware_id(void) +{ + unsigned char dbbus_tx_data[3] = {0}; + unsigned char dbbus_rx_data[4] = {0}; + int ret = 0; + + dbbus_tx_data[0] = 0x53; + dbbus_tx_data[1] = 0x00; + dbbus_tx_data[2] = 0x2A; + mutex_lock(&msg21xx_mutex); + write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 3); + read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4); + mutex_unlock(&msg21xx_mutex); + pdata->fw_version_major = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0]; + pdata->fw_version_minor = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2]; + + dev_dbg(&i2c_client->dev, "major num = %d, minor num = %d\n", + pdata->fw_version_major, pdata->fw_version_minor); + + if (pdata->fw_version == NULL) + pdata->fw_version = kzalloc(sizeof(char), GFP_KERNEL); + + snprintf(pdata->fw_version, sizeof(char) * 7, "%03d%03d", + pdata->fw_version_major, + pdata->fw_version_minor); + + return ret; } -void dbbusDWIICExitSerialDebugMode(void) +static int firmware_erase_c33(enum EMEM_TYPE_t emem_type) { - U8 data[1]; + /* stop mcu */ + write_reg(0x0F, 0xE6, 0x0001); - // Exit the Serial Debug Mode - data[0] = 0x45; + /* disable watch dog */ + write_reg_8bit(0x3C, 0x60, 0x55); + write_reg_8bit(0x3C, 0x61, 0xAA); - write_i2c_seq(SLAVE_I2C_ID_DBBUS, data, 1); + /* set PROGRAM password */ + write_reg_8bit(0x16, 0x1A, 0xBA); + write_reg_8bit(0x16, 0x1B, 0xAB); - // Delay some interval to guard the next transaction - //udelay ( 200 ); // delay about 0.2ms -} + write_reg_8bit(0x16, 0x18, 0x80); -//---------------------------------------------------------------------// + if (emem_type == EMEM_ALL) + write_reg_8bit(0x16, 0x08, 0x10); -static U8 get_ic_type(void) -{ - U8 ic_type = 0; - - reset_hw(); - dbbusDWIICEnterSerialDebugMode(); - dbbusDWIICStopMCU(); - dbbusDWIICIICUseBus(); - dbbusDWIICIICReshape(); - mdelay ( 300 ); - - // stop mcu - write_reg_8bit ( 0x0F, 0xE6, 0x01 ); - // disable watch dog - write_reg ( 0x3C, 0x60, 0xAA55 ); - // get ic type - ic_type = (0xff)&(read_reg(0x1E, 0xCC)); - - if (ic_type != 1 //msg2133 - && ic_type != 2 //msg21xxA - && ic_type != 3) //msg26xxM - { - ic_type = 0; - } - - reset_hw(); - - return ic_type; -} + write_reg_8bit(0x16, 0x18, 0x40); + msleep(20); -static int get_customer_firmware_version(void) -{ - U8 dbbus_tx_data[3] = {0}; - U8 dbbus_rx_data[4] = {0}; - int ret = 0; + /* clear pce */ + write_reg_8bit(0x16, 0x18, 0x80); - DBG("get_customer_firmware_version()\n"); + /* erase trigger */ + if (emem_type == EMEM_MAIN) + write_reg_8bit(0x16, 0x0E, 0x04); /* erase main */ + else + write_reg_8bit(0x16, 0x0E, 0x08); /* erase all block */ - dbbus_tx_data[0] = 0x53; - dbbus_tx_data[1] = 0x00; - dbbus_tx_data[2] = 0x2A; - mutex_lock(&msg21xx_mutex); - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4); - mutex_unlock(&msg21xx_mutex); - fw_version_major = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0]; - fw_version_minor = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2]; + return 1; +} - DBG("*** major = %d ***\n", fw_version_major); - DBG("*** minor = %d ***\n", fw_version_minor); +static void _ReadBinConfig(void); +static unsigned int _CalMainCRC32(void); - if (fw_version == NULL) - { - fw_version = kzalloc(sizeof(char), GFP_KERNEL); - } +static int check_fw_update(void) +{ + int ret = 0; + + msg21xx_read_firmware_id(); + _ReadBinConfig(); + if (main_sw_id == info_sw_id) { + if (_CalMainCRC32() == bin_conf_crc32) { + /*check upgrading*/ + if ((update_bin_major == pdata->fw_version_major) && + (update_bin_minor > pdata->fw_version_minor)) { + ret = 1; + } + } + } + return ret; - sprintf(fw_version, "%03d%03d", fw_version_major, fw_version_minor); +} - return ret; +static ssize_t firmware_update_c33(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size, + enum EMEM_TYPE_t emem_type, + bool isForce) { + unsigned int i, j; + unsigned int crc_main, crc_main_tp; + unsigned int crc_info, crc_info_tp; + unsigned short reg_data = 0; + int update_pass = 1; + + crc_main = 0xffffffff; + crc_info = 0xffffffff; + + reset_hw(); + + if (!check_fw_update() && !isForce) { + DBG("****no need to update\n"); + reset_hw(); + FwDataCnt = 0; + return size; + } + reset_hw(); + msleep(300); + + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + msleep(300); + + /* erase main */ + firmware_erase_c33(EMEM_MAIN); + msleep(1000); + + reset_hw(); + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + msleep(300); + + /* polling 0x3CE4 is 0x1C70 */ + if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { + do { + reg_data = read_reg(0x3C, 0xE4); + } while (reg_data != 0x1C70); + } + + switch (emem_type) { + case EMEM_ALL: + write_reg(0x3C, 0xE4, 0xE38F); /* for all-blocks */ + break; + case EMEM_MAIN: + write_reg(0x3C, 0xE4, 0x7731); /* for main block */ + break; + case EMEM_INFO: + write_reg(0x3C, 0xE4, 0x7731); /* for info block */ + + write_reg_8bit(0x0F, 0xE6, 0x01); + + write_reg_8bit(0x3C, 0xE4, 0xC5); + write_reg_8bit(0x3C, 0xE5, 0x78); + + write_reg_8bit(MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x9F); + write_reg_8bit(MSTAR_CHIPTOP_REGISTER_BANK, 0x05, 0x82); + + write_reg_8bit(0x0F, 0xE6, 0x00); + msleep(100); + break; + } + + /* polling 0x3CE4 is 0x2F43 */ + do { + reg_data = read_reg(0x3C, 0xE4); + } while (reg_data != 0x2F43); + + /* calculate CRC 32 */ + _CRC_initTable(); + + /* total 32 KB : 2 byte per R/W */ + for (i = 0; i < 32; i++) { + if (i == 31) { + fw_bin_data[i][1014] = 0x5A; + fw_bin_data[i][1015] = 0xA5; + + for (j = 0; j < 1016; j++) + crc_main = _CRC_getValue(fw_bin_data[i][j], + crc_main); + } else { + for (j = 0; j < 1024; j++) + crc_main = _CRC_getValue(fw_bin_data[i][j], + crc_main); + } + + for (j = 0; j < 8; j++) + write_i2c_seq(ts_data->client->addr, + &fw_bin_data[i][j * 128], 128); + msleep(100); + + /* polling 0x3CE4 is 0xD0BC */ + do { + reg_data = read_reg(0x3C, 0xE4); + } while (reg_data != 0xD0BC); + + write_reg(0x3C, 0xE4, 0x2F43); + } + + if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { + /* write file done and check crc */ + write_reg(0x3C, 0xE4, 0x1380); + } + msleep(20); + + if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { + /* polling 0x3CE4 is 0x9432 */ + do { + reg_data = read_reg(0x3C, 0xE4); + } while (reg_data != 0x9432); + } + + crc_main = crc_main ^ 0xffffffff; + crc_info = crc_info ^ 0xffffffff; + + if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { + /* CRC Main from TP */ + crc_main_tp = read_reg(0x3C, 0x80); + crc_main_tp = (crc_main_tp << 16) | read_reg(0x3C, 0x82); + + /* CRC Info from TP */ + crc_info_tp = read_reg(0x3C, 0xA0); + crc_info_tp = (crc_info_tp << 16) | read_reg(0x3C, 0xA2); + } + + update_pass = 1; + if ((emem_type == EMEM_ALL) || (emem_type == EMEM_MAIN)) { + if (crc_main_tp != crc_main) + update_pass = 0; + } + + if (!update_pass) { + DBG("update_C33 failed\n"); + reset_hw(); + FwDataCnt = 0; + return 0; + } + + DBG("update_C33 OK\n"); + reset_hw(); + FwDataCnt = 0; + return size; } -static int firmware_erase_c33 ( EMEM_TYPE_t emem_type ) +static unsigned int _CalMainCRC32(void) { - // stop mcu - write_reg ( 0x0F, 0xE6, 0x0001 ); + unsigned int ret = 0; + unsigned short reg_data = 0; + + reset_hw(); - //disable watch dog - write_reg_8bit ( 0x3C, 0x60, 0x55 ); - write_reg_8bit ( 0x3C, 0x61, 0xAA ); + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + msleep(100); - // set PROGRAM password - write_reg_8bit ( 0x16, 0x1A, 0xBA ); - write_reg_8bit ( 0x16, 0x1B, 0xAB ); + /* Stop MCU */ + write_reg(0x0F, 0xE6, 0x0001); - write_reg_8bit ( 0x16, 0x18, 0x80 ); + /* Stop Watchdog */ + write_reg_8bit(0x3C, 0x60, 0x55); + write_reg_8bit(0x3C, 0x61, 0xAA); - if ( emem_type == EMEM_ALL ) - { - write_reg_8bit ( 0x16, 0x08, 0x10 ); //mark - } + /* cmd */ + write_reg(0x3C, 0xE4, 0xDF4C); + write_reg(0x1E, 0x04, 0x7d60); + /* TP SW reset */ + write_reg(0x1E, 0x04, 0x829F); - write_reg_8bit ( 0x16, 0x18, 0x40 ); - mdelay ( 10 ); + /* MCU run */ + write_reg(0x0F, 0xE6, 0x0000); - // clear pce - write_reg_8bit ( 0x16, 0x18, 0x80 ); + /* polling 0x3CE4 */ + do { + reg_data = read_reg(0x3C, 0xE4); + } while (reg_data != 0x9432); - // erase trigger - if ( emem_type == EMEM_MAIN ) - { - write_reg_8bit ( 0x16, 0x0E, 0x04 ); //erase main - } - else - { - write_reg_8bit ( 0x16, 0x0E, 0x08 ); //erase all block - } + /* Cal CRC Main from TP */ + ret = read_reg(0x3C, 0x80); + ret = (ret << 16) | read_reg(0x3C, 0x82); - return ( 1 ); + DBG("[21xxA]:Current main crc32=0x%x\n", ret); + return ret; } -static ssize_t firmware_update_c33 ( struct device *dev, struct device_attribute *attr, - const char *buf, size_t size, EMEM_TYPE_t emem_type ) +static void _ReadBinConfig(void) { - U32 i, j; - U32 crc_main, crc_main_tp; - U32 crc_info, crc_info_tp; - U16 reg_data = 0; - int update_pass = 1; - - crc_main = 0xffffffff; - crc_info = 0xffffffff; - - reset_hw(); - dbbusDWIICEnterSerialDebugMode(); - dbbusDWIICStopMCU(); - dbbusDWIICIICUseBus(); - dbbusDWIICIICReshape(); - mdelay ( 300 ); - - //erase main - firmware_erase_c33 ( EMEM_MAIN ); - mdelay ( 1000 ); - - reset_hw(); - dbbusDWIICEnterSerialDebugMode(); - dbbusDWIICStopMCU(); - dbbusDWIICIICUseBus(); - dbbusDWIICIICReshape(); - mdelay ( 300 ); - - ///////////////////////// - // Program - ///////////////////////// - - //polling 0x3CE4 is 0x1C70 - if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) - { - do - { - reg_data = read_reg ( 0x3C, 0xE4 ); - } - while ( reg_data != 0x1C70 ); - } - - switch ( emem_type ) - { - case EMEM_ALL: - write_reg ( 0x3C, 0xE4, 0xE38F ); // for all-blocks - break; - case EMEM_MAIN: - write_reg ( 0x3C, 0xE4, 0x7731 ); // for main block - break; - case EMEM_INFO: - write_reg ( 0x3C, 0xE4, 0x7731 ); // for info block - - write_reg_8bit ( 0x0F, 0xE6, 0x01 ); - - write_reg_8bit ( 0x3C, 0xE4, 0xC5 ); - write_reg_8bit ( 0x3C, 0xE5, 0x78 ); - - write_reg_8bit ( 0x1E, 0x04, 0x9F ); - write_reg_8bit ( 0x1E, 0x05, 0x82 ); - - write_reg_8bit ( 0x0F, 0xE6, 0x00 ); - mdelay ( 100 ); - break; - } - - // polling 0x3CE4 is 0x2F43 - do - { - reg_data = read_reg ( 0x3C, 0xE4 ); - } - while ( reg_data != 0x2F43 ); - - // calculate CRC 32 - _CRC_initTable (); - - for ( i = 0; i < 32; i++ ) // total 32 KB : 2 byte per R/W - { - if ( i == 31 ) - { - temp[i][1014] = 0x5A; - temp[i][1015] = 0xA5; - - for ( j = 0; j < 1016; j++ ) - { - crc_main = _CRC_getValue ( temp[i][j], crc_main); - } - } - else - { - for ( j = 0; j < 1024; j++ ) - { - crc_main = _CRC_getValue ( temp[i][j], crc_main); - } - } - - //write_i2c_seq(SLAVE_I2C_ID_DWI2C, temp[i], 1024); - for (j = 0; j < 8; j++) - { - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &temp[i][j*128], 128 ); - } - msleep (100); - - // polling 0x3CE4 is 0xD0BC - do - { - reg_data = read_reg ( 0x3C, 0xE4 ); - } - while ( reg_data != 0xD0BC ); - - write_reg ( 0x3C, 0xE4, 0x2F43 ); - } - - if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) - { - // write file done and check crc - write_reg ( 0x3C, 0xE4, 0x1380 ); - } - mdelay ( 10 ); - - if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) - { - // polling 0x3CE4 is 0x9432 - do - { - reg_data = read_reg ( 0x3C, 0xE4 ); - }while ( reg_data != 0x9432 ); - } - - crc_main = crc_main ^ 0xffffffff; - crc_info = crc_info ^ 0xffffffff; - - if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) - { - // CRC Main from TP - crc_main_tp = read_reg ( 0x3C, 0x80 ); - crc_main_tp = ( crc_main_tp << 16 ) | read_reg ( 0x3C, 0x82 ); - - // CRC Info from TP - crc_info_tp = read_reg ( 0x3C, 0xA0 ); - crc_info_tp = ( crc_info_tp << 16 ) | read_reg ( 0x3C, 0xA2 ); - } - - update_pass = 1; - if ( ( emem_type == EMEM_ALL ) || ( emem_type == EMEM_MAIN ) ) - { - if ( crc_main_tp != crc_main ) - update_pass = 0; - - /* - if ( crc_info_tp != crc_info ) - update_pass = 0; - */ - } - - if ( !update_pass ) - { - DBG( "update_C33 failed\n" ); - reset_hw(); - FwDataCnt = 0; - return 0; - } - - DBG( "update_C33 OK\n" ); - reset_hw(); - FwDataCnt = 0; - return size; + unsigned char dbbus_tx_data[5] = {0}; + unsigned char dbbus_rx_data[4] = {0}; + unsigned short reg_data = 0; + + reset_hw(); + + dbbusDWIICEnterSerialDebugMode(); + dbbusDWIICStopMCU(); + dbbusDWIICIICUseBus(); + dbbusDWIICIICReshape(); + msleep(100); + + /* Stop MCU */ + write_reg(0x0F, 0xE6, 0x0001); + + /* Stop Watchdog */ + write_reg_8bit(0x3C, 0x60, 0x55); + write_reg_8bit(0x3C, 0x61, 0xAA); + + /* cmd */ + write_reg(0x3C, 0xE4, 0xA4AB); + write_reg(MSTAR_CHIPTOP_REGISTER_BANK, 0x04, 0x7d60); + /* TP SW reset */ + write_reg(0x1E, 0x04, 0x829F); + /* TP SW reset*/ + + /* MCU run */ + write_reg(0x0F, 0xE6, 0x0000); + + /* polling 0x3CE4 */ + do { + reg_data = read_reg(0x3C, 0xE4); + } while (reg_data != 0x5B58); + + dbbus_tx_data[0] = 0x72; + dbbus_tx_data[1] = 0x7F; + dbbus_tx_data[2] = 0x55; + dbbus_tx_data[3] = 0x00; + dbbus_tx_data[4] = 0x04; + write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 5); + read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4); + if ((dbbus_rx_data[0] >= 0x30 && dbbus_rx_data[0] <= 0x39) + && (dbbus_rx_data[1] >= 0x30 && dbbus_rx_data[1] <= 0x39) + && (dbbus_rx_data[2] >= 0x31 && dbbus_rx_data[2] <= 0x39)) { + main_sw_id = (dbbus_rx_data[0] - 0x30) * 100 + + (dbbus_rx_data[1] - 0x30) * 10 + + (dbbus_rx_data[2] - 0x30); + } + + dbbus_tx_data[0] = 0x72; + dbbus_tx_data[1] = 0x7F; + dbbus_tx_data[2] = 0xFC; + dbbus_tx_data[3] = 0x00; + dbbus_tx_data[4] = 0x04; + write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 5); + read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4); + bin_conf_crc32 = dbbus_rx_data[0]; + bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[1]; + bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[2]; + bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[3]; + + dbbus_tx_data[0] = 0x72; + dbbus_tx_data[1] = 0x83; + dbbus_tx_data[2] = 0x00; + dbbus_tx_data[3] = 0x00; + dbbus_tx_data[4] = 0x04; + write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 5); + read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4); + if ((dbbus_rx_data[0] >= 0x30 && dbbus_rx_data[0] <= 0x39) + && (dbbus_rx_data[1] >= 0x30 && dbbus_rx_data[1] <= 0x39) + && (dbbus_rx_data[2] >= 0x31 && dbbus_rx_data[2] <= 0x39)) { + info_sw_id = (dbbus_rx_data[0] - 0x30) * 100 + + (dbbus_rx_data[1] - 0x30) * 10 + + (dbbus_rx_data[2] - 0x30); + } + + DBG("[21xxA]:main_sw_id = %d, info_sw_id = %d, bin_conf_crc32=0x%x\n", + main_sw_id, info_sw_id, bin_conf_crc32); } -#ifdef FIRMWARE_AUTOUPDATE -unsigned short main_sw_id = 0x7FF, info_sw_id = 0x7FF; -U32 bin_conf_crc32 = 0; - -static U32 _CalMainCRC32(void) +static ssize_t firmware_update_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - U32 ret=0; - U16 reg_data=0; - - reset_hw(); - - dbbusDWIICEnterSerialDebugMode(); - dbbusDWIICStopMCU(); - dbbusDWIICIICUseBus(); - dbbusDWIICIICReshape(); - msleep ( 100 ); + DBG("*** firmware_update_show() pdata->fw_version = %s ***\n", + pdata->fw_version); - //Stop MCU - write_reg ( 0x0F, 0xE6, 0x0001 ); - - // Stop Watchdog - write_reg_8bit ( 0x3C, 0x60, 0x55 ); - write_reg_8bit ( 0x3C, 0x61, 0xAA ); - - //cmd - write_reg ( 0x3C, 0xE4, 0xDF4C ); - write_reg ( 0x1E, 0x04, 0x7d60 ); - // TP SW reset - write_reg ( 0x1E, 0x04, 0x829F ); + return snprintf(buf, sizeof(char) - 1, "%s\n", pdata->fw_version); +} - //MCU run - write_reg ( 0x0F, 0xE6, 0x0000 ); +static ssize_t firmware_update_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + bFwUpdating = 1; + disable_irq(ts_data->client->irq); - //polling 0x3CE4 - do - { - reg_data = read_reg ( 0x3C, 0xE4 ); - }while ( reg_data != 0x9432 ); + DBG("*** update fw size = %d ***\n", FwDataCnt); + size = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, false); - // Cal CRC Main from TP - ret = read_reg ( 0x3C, 0x80 ); - ret = ( ret << 16 ) | read_reg ( 0x3C, 0x82 ); + enable_irq(ts_data->client->irq); + bFwUpdating = 0; - DBG("[21xxA]:Current main crc32=0x%x\n",ret); - return (ret); + return size; } -static void _ReadBinConfig ( void ) -{ - U8 dbbus_tx_data[5]={0}; - U8 dbbus_rx_data[4]={0}; - U16 reg_data=0; - - reset_hw(); - - dbbusDWIICEnterSerialDebugMode(); - dbbusDWIICStopMCU(); - dbbusDWIICIICUseBus(); - dbbusDWIICIICReshape(); - msleep ( 100 ); - - //Stop MCU - write_reg ( 0x0F, 0xE6, 0x0001 ); - - // Stop Watchdog - write_reg_8bit ( 0x3C, 0x60, 0x55 ); - write_reg_8bit ( 0x3C, 0x61, 0xAA ); - - //cmd - write_reg ( 0x3C, 0xE4, 0xA4AB ); - write_reg ( 0x1E, 0x04, 0x7d60 ); - - // TP SW reset - write_reg ( 0x1E, 0x04, 0x829F ); - - //MCU run - write_reg ( 0x0F, 0xE6, 0x0000 ); - - //polling 0x3CE4 - do - { - reg_data = read_reg ( 0x3C, 0xE4 ); - } - while ( reg_data != 0x5B58 ); - - dbbus_tx_data[0] = 0x72; - dbbus_tx_data[1] = 0x7F; - dbbus_tx_data[2] = 0x55; - dbbus_tx_data[3] = 0x00; - dbbus_tx_data[4] = 0x04; - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 5 ); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4 ); - if ((dbbus_rx_data[0]>=0x30 && dbbus_rx_data[0]<=0x39) - &&(dbbus_rx_data[1]>=0x30 && dbbus_rx_data[1]<=0x39) - &&(dbbus_rx_data[2]>=0x31 && dbbus_rx_data[2]<=0x39)) - { - main_sw_id = (dbbus_rx_data[0]-0x30)*100+(dbbus_rx_data[1]-0x30)*10+(dbbus_rx_data[2]-0x30); - } - - dbbus_tx_data[0] = 0x72; - dbbus_tx_data[1] = 0x7F; - dbbus_tx_data[2] = 0xFC; - dbbus_tx_data[3] = 0x00; - dbbus_tx_data[4] = 0x04; - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 5 ); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4 ); - bin_conf_crc32 = dbbus_rx_data[0]; - bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[1]; - bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[2]; - bin_conf_crc32 = (bin_conf_crc32<<8)|dbbus_rx_data[3]; - - dbbus_tx_data[0] = 0x72; - dbbus_tx_data[1] = 0x83; - dbbus_tx_data[2] = 0x00; - dbbus_tx_data[3] = 0x00; - dbbus_tx_data[4] = 0x04; - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 5 ); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4 ); - if ((dbbus_rx_data[0]>=0x30 && dbbus_rx_data[0]<=0x39) - &&(dbbus_rx_data[1]>=0x30 && dbbus_rx_data[1]<=0x39) - &&(dbbus_rx_data[2]>=0x31 && dbbus_rx_data[2]<=0x39)) - { - info_sw_id = (dbbus_rx_data[0]-0x30)*100+(dbbus_rx_data[1]-0x30)*10+(dbbus_rx_data[2]-0x30); - } - - DBG("[21xxA]:main_sw_id = %d, info_sw_id = %d, bin_conf_crc32=0x%x\n", main_sw_id, info_sw_id, bin_conf_crc32); -} +static DEVICE_ATTR(update, (S_IRUGO | S_IWUSR), + firmware_update_show, + firmware_update_store); -static int fwAutoUpdate(void *unused) +static int prepare_fw_data(struct device *dev) { - int time = 0; - ssize_t ret = 0; - - for (time = 0; time < 5; time++) - { - DBG("fwAutoUpdate time = %d\n",time); - ret = firmware_update_c33(NULL, NULL, NULL, 1, EMEM_MAIN); - if (ret == 1) - { - DBG("AUTO_UPDATE OK!!!"); - break; - } - } - if (time == 5) - { - DBG("AUTO_UPDATE failed!!!"); - } - enable_irq(irq_msg21xx); - return 0; + int count; + int i; + int ret; + const struct firmware *fw = NULL; + + ret = request_firmware(&fw, pdata->fw_name, dev); + if (ret < 0) { + dev_err(dev, "Request firmware failed - %s (%d)\n", + pdata->fw_name, ret); + return ret; + } + DBG("*** prepare_fw_data() ret = %d, size = %d***\n", ret, fw->size); + + count = fw->size / 1024; + + for (i = 0; i < count; i++) { + memcpy(fw_bin_data[FwDataCnt], fw->data + (i * 1024), 1024); + FwDataCnt++; + } + update_bin_major = (fw->data[0x7f4f] << 8) + fw->data[0x7f4e]; + update_bin_minor = (fw->data[0x7f51] << 8) + fw->data[0x7f50]; + DBG("*** prepare_fw_data bin major = %d ***\n", update_bin_major); + DBG("*** prepare_fw_data bin minor = %d ***\n", update_bin_minor); + + DBG("***FwDataCnt = %d ***\n", FwDataCnt); + + return fw->size; } -#endif -//------------------------------------------------------------------------------// -static ssize_t firmware_update_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t firmware_update_smart_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) { - DBG("*** firmware_update_show() fw_version = %s ***\n", fw_version); + int ret; - return sprintf(buf, "%s\n", fw_version); + ret = prepare_fw_data(dev); + if (ret < 0) { + dev_err(dev, "Request firmware failed -(%d)\n", ret); + return ret; + } + bFwUpdating = 1; + disable_irq(ts_data->client->irq); + + DBG("*** update fw size = %d ***\n", FwDataCnt); + ret = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, false); + if (ret == 0) + DBG("*** firmware_update_c33 ret = %d ***\n", ret); + + enable_irq(ts_data->client->irq); + bFwUpdating = 0; + + return ret; } -static ssize_t firmware_update_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) +static ssize_t firmware_force_update_smart_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) { - bFwUpdating = 1; - disable_irq(irq_msg21xx); + int ret; - DBG("*** update fw size = %d ***\n", FwDataCnt); - size = firmware_update_c33 (dev, attr, buf, size, EMEM_MAIN); + ret = prepare_fw_data(dev); + if (ret < 0) { + dev_err(dev, "Request firmware failed -(%d)\n", ret); + return ret; + } + bFwUpdating = 1; + disable_irq(ts_data->client->irq); - enable_irq(irq_msg21xx); - bFwUpdating = 0; + DBG("*** update fw size = %d ***\n", FwDataCnt); + ret = firmware_update_c33(dev, attr, buf, size, EMEM_MAIN, true); + if (ret == 0) + DBG("*** firmware_update_c33 et = %d ***\n", ret); - return size; + enable_irq(ts_data->client->irq); + bFwUpdating = 0; + + return ret; } -static DEVICE_ATTR(update, SYSFS_AUTHORITY, firmware_update_show, firmware_update_store); +static DEVICE_ATTR(update_fw, (S_IRUGO | S_IWUSR), + firmware_update_show, + firmware_update_smart_store); + +static DEVICE_ATTR(force_update_fw, (S_IRUGO | S_IWUSR), + firmware_update_show, + firmware_force_update_smart_store); static ssize_t firmware_version_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { - DBG("*** firmware_version_show() fw_version = %s ***\n", fw_version); - - return sprintf(buf, "%s\n", fw_version); + msg21xx_read_firmware_id(); + return snprintf(buf, 8, "%s\n", pdata->fw_version); } static ssize_t firmware_version_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) + struct device_attribute *attr, + const char *buf, + size_t size) { - get_customer_firmware_version(); + msg21xx_read_firmware_id(); + DBG("*** firmware_version_store() pdata->fw_version = %s ***\n", + pdata->fw_version); + + return size; +} - DBG("*** firmware_version_store() fw_version = %s ***\n", fw_version); +static DEVICE_ATTR(version, (S_IRUGO | S_IWUSR), + firmware_version_show, + firmware_version_store); - return size; + +static ssize_t msg21xx_fw_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, MSTAR_FW_NAME_MAX_LEN - 1, "%s\n", pdata->fw_name); } -static DEVICE_ATTR(version, SYSFS_AUTHORITY, firmware_version_show, firmware_version_store); +static ssize_t msg21xx_fw_name_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + + if (size > MSTAR_FW_NAME_MAX_LEN - 1) + return -EINVAL; + + strlcpy(pdata->fw_name, buf, size); + if (pdata->fw_name[size - 1] == '\n') + pdata->fw_name[size - 1] = 0; + + return size; +} + +static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR), + msg21xx_fw_name_show, msg21xx_fw_name_store); static ssize_t firmware_data_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { - DBG("*** firmware_data_show() FwDataCnt = %d ***\n", FwDataCnt); + DBG("*** firmware_data_show() FwDataCnt = %d ***\n", FwDataCnt); - return FwDataCnt; + return FwDataCnt; } static ssize_t firmware_data_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) + struct device_attribute *attr, + const char *buf, + size_t size) { - int count = size / 1024; - int i; + int count = size / 1024; + int i; - for (i = 0; i < count; i ++) - { - memcpy(temp[FwDataCnt], buf+(i*1024), 1024); + for (i = 0; i < count; i++) { + memcpy(fw_bin_data[FwDataCnt], buf + (i * 1024), 1024); - FwDataCnt ++; - } + FwDataCnt++; + } - DBG("***FwDataCnt = %d ***\n", FwDataCnt); + DBG("***FwDataCnt = %d ***\n", FwDataCnt); - if (buf != NULL) - { - DBG("*** buf[0] = %c ***\n", buf[0]); - } + if (buf != NULL) + DBG("*** buf[0] = %c ***\n", buf[0]); - return size; + return size; } -static DEVICE_ATTR(data, SYSFS_AUTHORITY, firmware_data_show, firmware_data_store); +static DEVICE_ATTR(data, (S_IRUGO | S_IWUSR), + firmware_data_show, firmware_data_store); #ifdef TP_PRINT static ssize_t tp_print_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { - tp_print_proc_read(); + tp_print_proc_read(); - return sprintf(buf, "%d\n", bTpInSuspend); + return snprintf(buf, sizeof(char) - 1, "%d\n", ts_data->suspended); } static ssize_t tp_print_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) + struct device_attribute *attr, + const char *buf, + size_t size) { - DBG("*** tp_print_store() ***\n"); + DBG("*** tp_print_store() ***\n"); - return size; + return size; } -static DEVICE_ATTR(tpp, SYSFS_AUTHORITY, tp_print_show, tp_print_store); +static DEVICE_ATTR(tpp, (S_IRUGO | S_IWUSR), + tp_print_show, tp_print_store); #endif -//------------------------------------------------------------------------------// #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR static void _msg_enable_proximity(void) { - U8 tx_data[4] = {0}; - - DBG("_msg_enable_proximity!"); - tx_data[0] = 0x52; - tx_data[1] = 0x00; - tx_data[2] = 0x47; - tx_data[3] = 0xa0; - mutex_lock(&msg21xx_mutex); - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &tx_data[0], 4); - mutex_unlock(&msg21xx_mutex); - - bEnableTpProximity = 1; + unsigned char tx_data[4] = {0}; + + DBG("_msg_enable_proximity!"); + tx_data[0] = 0x52; + tx_data[1] = 0x00; + tx_data[2] = 0x47; + tx_data[3] = 0xa0; + mutex_lock(&msg21xx_mutex); + write_i2c_seq(ts_data->client->addr, &tx_data[0], 4); + mutex_unlock(&msg21xx_mutex); + + bEnableTpProximity = 1; } static void _msg_disable_proximity(void) { - U8 tx_data[4] = {0}; - - DBG("_msg_disable_proximity!"); - tx_data[0] = 0x52; - tx_data[1] = 0x00; - tx_data[2] = 0x47; - tx_data[3] = 0xa1; - mutex_lock(&msg21xx_mutex); - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &tx_data[0], 4); - mutex_unlock(&msg21xx_mutex); - - bEnableTpProximity = 0; - bFaceClosingTp = 0; + unsigned char tx_data[4] = {0}; + + DBG("_msg_disable_proximity!"); + tx_data[0] = 0x52; + tx_data[1] = 0x00; + tx_data[2] = 0x47; + tx_data[3] = 0xa1; + mutex_lock(&msg21xx_mutex); + write_i2c_seq(ts_data->client->addr, &tx_data[0], 4); + mutex_unlock(&msg21xx_mutex); + + bEnableTpProximity = 0; + bFaceClosingTp = 0; } -void tsps_msg21xx_enable(int en) +static void tsps_msg21xx_enable(int en) { - if (en) - { - _msg_enable_proximity(); - } - else - { - _msg_disable_proximity(); - } + if (en) + _msg_enable_proximity(); + else + _msg_disable_proximity(); } -int tsps_msg21xx_data(void) +static int tsps_msg21xx_data(void) { - return bFaceClosingTp; + return bFaceClosingTp; } #endif -static U8 calculate_checksum(U8 *msg, S32 length) +static int msg21xx_pinctrl_init(void) { - S32 Checksum = 0; - S32 i; + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts_data->ts_pinctrl = devm_pinctrl_get(&(i2c_client->dev)); + if (IS_ERR_OR_NULL(ts_data->ts_pinctrl)) { + retval = PTR_ERR(ts_data->ts_pinctrl); + dev_dbg(&i2c_client->dev, + "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + ts_data->pinctrl_state_active = pinctrl_lookup_state( + ts_data->ts_pinctrl, PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(ts_data->pinctrl_state_active)) { + retval = PTR_ERR(ts_data->pinctrl_state_active); + dev_dbg(&i2c_client->dev, + "Can't lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + ts_data->pinctrl_state_suspend = pinctrl_lookup_state( + ts_data->ts_pinctrl, PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(ts_data->pinctrl_state_suspend)) { + retval = PTR_ERR(ts_data->pinctrl_state_suspend); + dev_dbg(&i2c_client->dev, + "Can't lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + + ts_data->pinctrl_state_release = pinctrl_lookup_state( + ts_data->ts_pinctrl, PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { + retval = PTR_ERR(ts_data->pinctrl_state_release); + dev_dbg(&i2c_client->dev, + "Can't lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts_data->ts_pinctrl); +err_pinctrl_get: + ts_data->ts_pinctrl = NULL; + return retval; +} - for (i = 0; i < length; i ++) - { - Checksum += msg[i]; - } +static unsigned char calculate_checksum(unsigned char *msg, int length) +{ + int checksum = 0, i; - return (U8)((-Checksum) & 0xFF); + for (i = 0; i < length; i++) + checksum += msg[i]; + + return (unsigned char)((-checksum) & 0xFF); } -static S32 parse_info(touchInfo_t *info) +static int parse_info(struct touchInfo_t *info) { - U8 data[DEMO_MODE_PACKET_LENGTH] = {0}; - U8 checksum = 0; - U32 x = 0, y = 0; - U32 x2 = 0, y2 = 0; - U32 delta_x = 0, delta_y = 0; - - mutex_lock(&msg21xx_mutex); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &data[0], DEMO_MODE_PACKET_LENGTH); - mutex_unlock(&msg21xx_mutex); - checksum = calculate_checksum(&data[0], (DEMO_MODE_PACKET_LENGTH-1)); - DBG("check sum: [%x] == [%x]? \n", data[DEMO_MODE_PACKET_LENGTH-1], checksum); - - if(data[DEMO_MODE_PACKET_LENGTH-1] != checksum) - { - DBG("WRONG CHECKSUM\n"); - return -1; - } - - if(data[0] != 0x52) - { - DBG("WRONG HEADER\n"); - return -1; - } - - info->keycode = 0xFF; - if ((data[1] == 0xFF) && (data[2] == 0xFF) && (data[3] == 0xFF) && (data[4] == 0xFF) && (data[6] == 0xFF)) - { - if ((data[5] == 0xFF) || (data[5] == 0)) - { - info->keycode = 0xFF; - } - else if ((data[5] == 1) || (data[5] == 2) || (data[5] == 4) || (data[5] == 8)) - { - if (data[5] == 1) - { - info->keycode = 0; - } - else if (data[5] == 2) - { - info->keycode = 1; - } - else if (data[5] == 4) - { - info->keycode = 2; - } - else if (data[5] == 8) - { - info->keycode = 3; - } - } - #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR - else if (bEnableTpProximity &&((data[5] == 0x80) || (data[5] == 0x40))) - { - if (data[5] == 0x80) - { - bFaceClosingTp = 1; - } - else if (data[5] == 0x40) - { - bFaceClosingTp = 0; - } - DBG("bEnableTpProximity=%d; bFaceClosingTp=%d; data[5]=%x;\n", bEnableTpProximity, bFaceClosingTp, data[5]); - return -1; - } - #endif - else - { - DBG("WRONG KEY\n"); - return -1; - } - } - else - { - x = (((data[1] & 0xF0 ) << 4) | data[2]); - y = ((( data[1] & 0x0F) << 8) | data[3]); - delta_x = (((data[4] & 0xF0) << 4 ) | data[5]); - delta_y = (((data[4] & 0x0F) << 8 ) | data[6]); - - if ((delta_x == 0) && (delta_y == 0)) - { - info->point[0].x = x * TOUCH_SCREEN_X_MAX / TPD_WIDTH; - info->point[0].y = y * TOUCH_SCREEN_Y_MAX/ TPD_HEIGHT; - info->count = 1; - } - else - { - if (delta_x > 2048) - { - delta_x -= 4096; - } - if (delta_y > 2048) - { - delta_y -= 4096; - } - x2 = (U32)((S16)x + (S16)delta_x); - y2 = (U32)((S16)y + (S16)delta_y); - info->point[0].x = x * TOUCH_SCREEN_X_MAX / TPD_WIDTH; - info->point[0].y = y * TOUCH_SCREEN_Y_MAX/ TPD_HEIGHT; - info->point[1].x = x2 * TOUCH_SCREEN_X_MAX / TPD_WIDTH; - info->point[1].y = y2 * TOUCH_SCREEN_Y_MAX/ TPD_HEIGHT; - info->count = 2; - } - } - - return 0; + unsigned char data[DEMO_MODE_PACKET_LENGTH] = {0}; + unsigned char checksum = 0; + unsigned int x = 0, y = 0; + unsigned int x2 = 0, y2 = 0; + unsigned int delta_x = 0, delta_y = 0; + + mutex_lock(&msg21xx_mutex); + read_i2c_seq(ts_data->client->addr, &data[0], DEMO_MODE_PACKET_LENGTH); + mutex_unlock(&msg21xx_mutex); + checksum = calculate_checksum(&data[0], (DEMO_MODE_PACKET_LENGTH-1)); + DBG("check sum: [%x] == [%x]?\n", + data[DEMO_MODE_PACKET_LENGTH-1], checksum); + + if (data[DEMO_MODE_PACKET_LENGTH-1] != checksum) { + DBG("WRONG CHECKSUM\n"); + return -EINVAL; + } + + if (data[0] != 0x52) { + DBG("WRONG HEADER\n"); + return -EINVAL; + } + + info->keycode = 0xFF; + if ((data[1] == 0xFF) && (data[2] == 0xFF) && + (data[3] == 0xFF) && (data[4] == 0xFF) && + (data[6] == 0xFF)) { + if ((data[5] == 0xFF) || (data[5] == 0)) { + info->keycode = 0xFF; + } else if ((data[5] == 1) || (data[5] == 2) || + (data[5] == 4) || (data[5] == 8)) { + info->keycode = data[5] >> 1; + + DBG("info->keycode index %d\n", info->keycode); + } + #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR + else if (bEnableTpProximity && ((data[5] == 0x80) || + (data[5] == 0x40))) { + if (data[5] == 0x80) + bFaceClosingTp = 1; + else if (data[5] == 0x40) + bFaceClosingTp = 0; + + return -EINVAL; + } + #endif + else { + DBG("WRONG KEY\n"); + return -EINVAL; + } + } else { + x = (((data[1] & 0xF0) << 4) | data[2]); + y = (((data[1] & 0x0F) << 8) | data[3]); + delta_x = (((data[4] & 0xF0) << 4) | data[5]); + delta_y = (((data[4] & 0x0F) << 8) | data[6]); + + if ((delta_x == 0) && (delta_y == 0)) { + info->point[0].x = x * pdata->x_max / TPD_WIDTH; + info->point[0].y = y * pdata->y_max / TPD_HEIGHT; + info->count = 1; + } else { + if (delta_x > 2048) + delta_x -= 4096; + + if (delta_y > 2048) + delta_y -= 4096; + + x2 = (unsigned int)((signed short)x + + (signed short)delta_x); + y2 = (unsigned int)((signed short)y + + (signed short)delta_y); + info->point[0].x = x * pdata->x_max / TPD_WIDTH; + info->point[0].y = y * pdata->y_max / TPD_HEIGHT; + info->point[1].x = x2 * pdata->x_max / TPD_WIDTH; + info->point[1].y = y2 * pdata->y_max / TPD_HEIGHT; + info->count = 2; + } + } + + return 0; } -static void touch_driver_touch_pressed(int x, int y) +static void touch_driver_touch_released(void) { - DBG("point touch pressed"); + int i; + + DBG("point touch released\n"); + + for (i = 0; i < MAX_TOUCH_NUM; i++) { + input_mt_slot(input_dev, i); + input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0); + } - input_report_key(input_dev, BTN_TOUCH, 1); - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 1); - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); - input_mt_sync(input_dev); + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_key(input_dev, BTN_TOOL_FINGER, 0); + input_sync(input_dev); } -static void touch_driver_touch_released(void) +/* read data through I2C then report data to input + *sub-system when interrupt occurred + */ +static irqreturn_t msg21xx_ts_interrupt(int irq, void *dev_id) { - DBG("point touch released"); + struct touchInfo_t info; + int i = 0; + static int last_keycode = 0xFF; + static int last_count; + + DBG("touch_driver_do_work()\n"); + + memset(&info, 0x0, sizeof(info)); + if (parse_info(&info) == 0) { + #ifdef CONFIG_TP_HAVE_KEY + if (info.keycode != 0xFF) { /* key touch pressed */ + if (info.keycode < num_buttons) { + if (info.keycode != last_keycode) { + DBG("key touch pressed"); + + input_report_key(input_dev, + BTN_TOUCH, 1); + input_report_key(input_dev, + button_map[info.keycode], 1); + + last_keycode = info.keycode; + } else { + /* pass duplicate key-pressing */ + DBG("REPEATED KEY\n"); + } + } else { + DBG("WRONG KEY\n"); + } + } else { /* key touch released */ + if (last_keycode != 0xFF) { + DBG("key touch released"); + + input_report_key(input_dev, + BTN_TOUCH, 0); + input_report_key(input_dev, + button_map[last_keycode], + 0); + + last_keycode = 0xFF; + } + } + #endif /* CONFIG_TP_HAVE_KEY */ + + if (info.count > 0) { /* point touch pressed */ + for (i = 0; i < info.count; i++) { + input_mt_slot(input_dev, i); + input_mt_report_slot_state(input_dev, + MT_TOOL_FINGER, 1); + input_report_abs(input_dev, + ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input_dev, + ABS_MT_POSITION_X, + info.point[i].x); + input_report_abs(input_dev, + ABS_MT_POSITION_Y, + info.point[i].y); + } + } + + if (last_count > info.count) { + for (i = info.count; i < MAX_TOUCH_NUM; i++) { + input_mt_slot(input_dev, i); + input_mt_report_slot_state(input_dev, + MT_TOOL_FINGER, 0); + } + } + last_count = info.count; + + input_report_key(input_dev, BTN_TOUCH, info.count > 0); + input_report_key(input_dev, BTN_TOOL_FINGER, info.count > 0); + + input_sync(input_dev); + } + + return IRQ_HANDLED; +} - input_report_key(input_dev, BTN_TOUCH, 0); - input_mt_sync(input_dev); + +static int msg21xx_ts_power_init(void) +{ + int rc; + + ts_data->vdd = regulator_get(&i2c_client->dev, "vdd"); + if (IS_ERR(ts_data->vdd)) { + rc = PTR_ERR(ts_data->vdd); + dev_err(&i2c_client->dev, + "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + + if (regulator_count_voltages(ts_data->vdd) > 0) { + rc = regulator_set_voltage(ts_data->vdd, MSTAR_VTG_MIN_UV, + MSTAR_VTG_MAX_UV); + if (rc) { + dev_err(&i2c_client->dev, + "Regulator set_vtg failed vdd rc=%d\n", rc); + goto reg_vdd_put; + } + } + + ts_data->vcc_i2c = regulator_get(&i2c_client->dev, "vcc_i2c"); + if (IS_ERR(ts_data->vcc_i2c)) { + rc = PTR_ERR(ts_data->vcc_i2c); + dev_err(&i2c_client->dev, + "Regulator get failed vcc_i2c rc=%d\n", rc); + goto reg_vdd_set_vtg; + } + + if (regulator_count_voltages(ts_data->vcc_i2c) > 0) { + rc = regulator_set_voltage(ts_data->vcc_i2c, + MSTAR_I2C_VTG_MIN_UV, + MSTAR_I2C_VTG_MAX_UV); + if (rc) { + dev_err(&i2c_client->dev, + "Regulator set_vtg failed vcc_i2c rc=%d\n", rc); + goto reg_vcc_i2c_put; + } + } + + return 0; + +reg_vcc_i2c_put: + regulator_put(ts_data->vcc_i2c); +reg_vdd_set_vtg: + if (regulator_count_voltages(ts_data->vdd) > 0) + regulator_set_voltage(ts_data->vdd, 0, MSTAR_VTG_MAX_UV); +reg_vdd_put: + regulator_put(ts_data->vdd); + return rc; } -/* read data through I2C then report data to input sub-system when interrupt occurred */ -void touch_driver_do_work(struct work_struct *work) + +static int msg21xx_ts_power_deinit(void) { - touchInfo_t info; - int i = 0; - static int last_keycode = 0xFF; - static int last_count = 0; - - DBG("touch_driver_do_work()\n"); - - memset(&info, 0x0, sizeof(info)); - if (0 == parse_info(&info)) - { - #ifdef CONFIG_TP_HAVE_KEY - if (info.keycode != 0xFF) //key touch pressed - { - DBG("touch_driver_do_work() info.keycode=%x, last_keycode=%x, tp_key_array[%d]=%d\n", info.keycode, last_keycode, info.keycode, tp_key_array[info.keycode]); - if (info.keycode < MAX_KEY_NUM) - { - if (info.keycode != last_keycode) - { - DBG("key touch pressed"); - - input_report_key(input_dev, BTN_TOUCH, 1); - input_report_key(input_dev, tp_key_array[info.keycode], 1); - - last_keycode = info.keycode; - } - else - { - /// pass duplicate key-pressing - DBG("REPEATED KEY\n"); - } - } - else - { - DBG("WRONG KEY\n"); - } - } - else //key touch released - { - if (last_keycode != 0xFF) - { - DBG("key touch released"); - - input_report_key(input_dev, BTN_TOUCH, 0); - input_report_key(input_dev, tp_key_array[last_keycode], 0); - - last_keycode = 0xFF; - } - } - #endif //CONFIG_TP_HAVE_KEY - - if (info.count > 0) //point touch pressed - { - for (i = 0; i < info.count; i ++) - { - touch_driver_touch_pressed(info.point[i].x, info.point[i].y); - } - last_count = info.count; - } - else if (last_count > 0) //point touch released - { - touch_driver_touch_released(); - last_count = 0; - } - - input_sync(input_dev); - } - - enable_irq(irq_msg21xx); + if (regulator_count_voltages(ts_data->vdd) > 0) + regulator_set_voltage(ts_data->vdd, 0, MSTAR_VTG_MAX_UV); + + regulator_put(ts_data->vdd); + + if (regulator_count_voltages(ts_data->vcc_i2c) > 0) + regulator_set_voltage(ts_data->vcc_i2c, 0, + MSTAR_I2C_VTG_MAX_UV); + + regulator_put(ts_data->vcc_i2c); + return 0; } -/* The interrupt service routine will be triggered when interrupt occurred */ -irqreturn_t touch_driver_isr(int irq, void *dev_id) +static int msg21xx_ts_power_on(void) { - DBG("touch_driver_isr()\n"); + int rc; + + rc = regulator_enable(ts_data->vdd); + if (rc) { + dev_err(&i2c_client->dev, + "Regulator vdd enable failed rc=%d\n", rc); + return rc; + } + + rc = regulator_enable(ts_data->vcc_i2c); + if (rc) { + dev_err(&i2c_client->dev, + "Regulator vcc_i2c enable failed rc=%d\n", rc); + regulator_disable(ts_data->vdd); + } + + return rc; +} - disable_irq_nosync(irq_msg21xx); - schedule_work(&msg21xx_wk); +static int msg21xx_ts_power_off(void) +{ + int rc; + + DBG("*** %s ***\n", __func__); + rc = regulator_disable(vdd); + rc = regulator_disable(ts_data->vdd); + if (rc) { + dev_err(&i2c_client->dev, + "Regulator vdd disable failed rc=%d\n", rc); + return rc; + } + + rc = regulator_disable(ts_data->vcc_i2c); + if (rc) { + dev_err(&i2c_client->dev, + "Regulator vcc_i2c disable failed rc=%d\n", rc); + rc = regulator_enable(ts_data->vdd); + } + + return rc; +} - return IRQ_HANDLED; +static int msg21xx_ts_gpio_configure(bool on) +{ + int ret = 0; + + if (on) { + if (gpio_is_valid(pdata->irq_gpio)) { + ret = gpio_request(pdata->irq_gpio, "msg21xx_irq_gpio"); + if (ret) { + dev_err(&i2c_client->dev, + "Failed to request GPIO[%d], %d\n", + pdata->irq_gpio, ret); + goto err_irq_gpio_req; + } + ret = gpio_direction_input(pdata->irq_gpio); + if (ret) { + dev_err(&i2c_client->dev, + "Failed to set direction for gpio[%d], %d\n", + pdata->irq_gpio, ret); + goto err_irq_gpio_dir; + } + gpio_set_value_cansleep(pdata->irq_gpio, 1); + } else { + dev_err(&i2c_client->dev, "irq gpio not provided\n"); + goto err_irq_gpio_req; + } + + if (gpio_is_valid(pdata->reset_gpio)) { + ret = gpio_request(pdata->reset_gpio, + "msg21xx_reset_gpio"); + if (ret) { + dev_err(&i2c_client->dev, + "Failed to request GPIO[%d], %d\n", + pdata->reset_gpio, ret); + goto err_reset_gpio_req; + } + + /* power on TP */ + ret = gpio_direction_output(pdata->reset_gpio, 1); + if (ret) { + dev_err(&i2c_client->dev, + "Failed to set direction for GPIO[%d], %d\n", + pdata->reset_gpio, ret); + goto err_reset_gpio_dir; + } + msleep(100); + gpio_set_value_cansleep(pdata->reset_gpio, 0); + msleep(20); + gpio_set_value_cansleep(pdata->reset_gpio, 1); + msleep(200); + } else { + dev_err(&i2c_client->dev, "reset gpio not provided\n"); + goto err_reset_gpio_req; + } + + } else { + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); + if (gpio_is_valid(pdata->reset_gpio)) { + gpio_set_value_cansleep(pdata->reset_gpio, 0); + ret = gpio_direction_input(pdata->reset_gpio); + if (ret) + dev_err(&i2c_client->dev, + "Unable to set direction for gpio [%d]\n", + pdata->reset_gpio); + gpio_free(pdata->reset_gpio); + } + } + return 0; +err_reset_gpio_dir: + if (gpio_is_valid(pdata->reset_gpio)) + gpio_free(pdata->irq_gpio); +err_reset_gpio_req: +err_irq_gpio_dir: + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); +err_irq_gpio_req: + return ret; } -#if defined(CONFIG_FB) -static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +#ifdef CONFIG_PM +static int msg21xx_ts_resume(struct device *dev) { - struct fb_event *evdata = data; - int *blank; - - if (evdata && evdata->data && event == FB_EVENT_BLANK ) - { - blank = evdata->data; - if (*blank == FB_BLANK_UNBLANK) - { - if (bTpInSuspend) - { - gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1); - mdelay(10); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0); - mdelay(10); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1); - mdelay(200); - - touch_driver_touch_released(); - input_sync(input_dev); - - enable_irq(irq_msg21xx); - } - bTpInSuspend = 0; - } - else if (*blank == FB_BLANK_POWERDOWN) - { - if (bFwUpdating) - { - DBG("suspend bFwUpdating=%d\n", bFwUpdating); - return 0; - } - - #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR - if (bEnableTpProximity) - { - DBG("suspend bEnableTpProximity=%d\n", bEnableTpProximity); - return 0; - } - #endif - - if (bTpInSuspend == 0) - { - disable_irq(irq_msg21xx); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0); - } - bTpInSuspend = 1; - } - } - - return 0; + int retval; + + mutex_lock(&ts_data->ts_mutex); + if (ts_data->suspended) { + if (ts_data->ts_pinctrl) { + retval = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_active); + if (retval < 0) { + dev_err(dev, "Cannot get active pinctrl state\n"); + mutex_unlock(&ts_data->ts_mutex); + return retval; + } + } + + retval = msg21xx_ts_gpio_configure(true); + if (retval) { + dev_err(dev, "Failed to put gpios in active state %d", + retval); + mutex_unlock(&ts_data->ts_mutex); + return retval; + } + + enable_irq(ts_data->client->irq); + + retval = msg21xx_ts_power_on(); + if (retval) { + dev_err(dev, "msg21xx_ts power on failed"); + mutex_unlock(&ts_data->ts_mutex); + return retval; + } + + ts_data->suspended = 0; + } else { + dev_info(dev, "msg21xx_ts already in resume\n"); + } + mutex_unlock(&ts_data->ts_mutex); + + return 0; } -#endif -#ifdef CONFIG_HAS_EARLYSUSPEND -void touch_driver_early_suspend(struct early_suspend *p) +static int msg21xx_ts_suspend(struct device *dev) { - DBG("touch_driver_early_suspend()\n"); + int retval; - if (bFwUpdating) - { - DBG("suspend bFwUpdating=%d\n", bFwUpdating); - return; - } + if (bFwUpdating) { + DBG("suspend bFwUpdating=%d\n", bFwUpdating); + return 0; + } #ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR - if (bEnableTpProximity) - { - DBG("suspend bEnableTpProximity=%d\n", bEnableTpProximity); - return; - } + if (bEnableTpProximity) { + DBG("suspend bEnableTpProximity=%d\n", bEnableTpProximity); + return 0; + } #endif - if (bTpInSuspend == 0) - { - disable_irq(irq_msg21xx); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0); - } - bTpInSuspend = 1; + mutex_lock(&ts_data->ts_mutex); + if (ts_data->suspended == 0) { + disable_irq(ts_data->client->irq); + + touch_driver_touch_released(); + + retval = msg21xx_ts_power_off(); + if (retval) { + dev_err(dev, "msg21xx_ts power off failed"); + mutex_unlock(&ts_data->ts_mutex); + return retval; + } + + if (ts_data->ts_pinctrl) { + retval = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_suspend); + if (retval < 0) { + dev_err(&i2c_client->dev, "Cannot get idle pinctrl state\n"); + mutex_unlock(&ts_data->ts_mutex); + return retval; + } + } + + retval = msg21xx_ts_gpio_configure(false); + if (retval) { + dev_err(dev, "Failed to put gpios in idle state %d", + retval); + mutex_unlock(&ts_data->ts_mutex); + return retval; + } + + ts_data->suspended = 1; + } else { + dev_err(dev, "msg21xx_ts already in suspend\n"); + } + mutex_unlock(&ts_data->ts_mutex); + + + return 0; } - -void touch_driver_early_resume(struct early_suspend *p) +#else +static int msg21xx_ts_resume(struct device *dev) +{ + return 0; +} +static int msg21xx_ts_suspend(struct device *dev) { - DBG("touch_driver_early_resume() bTpInSuspend=%d\n", bTpInSuspend); - - if (bTpInSuspend) - { - gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1); - mdelay(10); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0); - mdelay(10); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1); - mdelay(200); - - touch_driver_touch_released(); - input_sync(input_dev); - - enable_irq(irq_msg21xx); - } - bTpInSuspend = 0; + return 0; } #endif -/* probe function is used for matching and initializing input device */ -static int touch_driver_probe(struct i2c_client *client, - const struct i2c_device_id *id) +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) { -#ifdef FIRMWARE_AUTOUPDATE - unsigned short update_bin_major = 0, update_bin_minor = 0; - int i, update_flag = 0; + struct fb_event *evdata = data; + int *blank; + + if (evdata && evdata->data && event == FB_EVENT_BLANK) { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK) + msg21xx_ts_resume(&i2c_client->dev); + else if (*blank == FB_BLANK_POWERDOWN) + msg21xx_ts_suspend(&i2c_client->dev); + } + + return 0; +} #endif - int ret = 0; - - if (input_dev != NULL) - { - DBG("input device has found\n"); - return -1; - } - - DBG("*** %s ***\n", __FUNCTION__); - - i2c_client = client; - - ret = gpio_request(MS_TS_MSG21XX_GPIO_RST, "reset"); - if (ret < 0) - { - pr_err("*** Failed to request GPIO %d, error %d ***\n", MS_TS_MSG21XX_GPIO_RST, ret); - goto err0; - } - - // power on TP - gpio_direction_output(MS_TS_MSG21XX_GPIO_RST, 1); - mdelay(100); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 0); - mdelay(10); - gpio_set_value(MS_TS_MSG21XX_GPIO_RST, 1); - mdelay(200); - if (0 == get_ic_type()) - { - pr_err("the currnet ic is not Mstar\n"); - ret = -1; - goto err0; - } - - mutex_init(&msg21xx_mutex); - - /* allocate an input device */ - input_dev = input_allocate_device(); - if (!input_dev) - { - ret = -ENOMEM; - pr_err("*** input device allocation failed ***\n"); - goto err1; - } - - input_dev->name = client->name; - input_dev->phys = "I2C"; - input_dev->dev.parent = &client->dev; - input_dev->id.bustype = BUS_I2C; - - /* set the supported event type for input device */ - set_bit(EV_ABS, input_dev->evbit); - set_bit(EV_SYN, input_dev->evbit); - set_bit(EV_KEY, input_dev->evbit); - set_bit(BTN_TOUCH, input_dev->keybit); - set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + +static int msg21xx_get_dt_coords(struct device *dev, char *name, + struct msg21xx_ts_platform_data *pdata) +{ + u32 coords[FT_COORDS_ARR_SIZE]; + struct property *prop; + struct device_node *np = dev->of_node; + int coords_size, rc; + + prop = of_find_property(np, name, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + coords_size = prop->length / sizeof(u32); + if (coords_size != FT_COORDS_ARR_SIZE) { + dev_err(dev, "invalid %s\n", name); + return -EINVAL; + } + + rc = of_property_read_u32_array(np, name, coords, coords_size); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read %s\n", name); + return rc; + } + + if (!strcmp(name, "mstar,panel-coords")) { + pdata->panel_minx = coords[0]; + pdata->panel_miny = coords[1]; + pdata->panel_maxx = coords[2]; + pdata->panel_maxy = coords[3]; + } else if (!strcmp(name, "mstar,display-coords")) { + pdata->x_min = coords[0]; + pdata->y_min = coords[1]; + pdata->x_max = coords[2]; + pdata->y_max = coords[3]; + } else { + dev_err(dev, "unsupported property %s\n", name); + return -EINVAL; + } + + return 0; +} + +static int msg21xx_parse_dt(struct device *dev, + struct msg21xx_ts_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + struct property *prop; + u32 temp_val; + + rc = msg21xx_get_dt_coords(dev, "mstar,panel-coords", pdata); + if (rc && (rc != -EINVAL)) + return rc; + + rc = msg21xx_get_dt_coords(dev, "mstar,display-coords", pdata); + if (rc) + return rc; + + /* reset, irq gpio info */ + pdata->reset_gpio = of_get_named_gpio_flags(np, "mstar,reset-gpio", + 0, &pdata->reset_gpio_flags); + if (pdata->reset_gpio < 0) + return pdata->reset_gpio; + + pdata->irq_gpio = of_get_named_gpio_flags(np, "mstar,irq-gpio", + 0, &pdata->irq_gpio_flags); + if (pdata->irq_gpio < 0) + return pdata->irq_gpio; + + + prop = of_find_property(np, "mstar,button-map", NULL); + if (prop) { + num_buttons = prop->length / sizeof(temp_val); + if (num_buttons > MAX_BUTTONS) + return -EINVAL; + + rc = of_property_read_u32_array(np, + "mstar,button-map", button_map, + num_buttons); + if (rc) { + dev_err(dev, "Unable to read key codes\n"); + return rc; + } + } + + return 0; +} + +/* probe function is used for matching and initializing input device */ +static int msg21xx_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) { + + int ret = 0; + + if (input_dev != NULL) { + DBG("input device has found\n"); + return -EINVAL; + } + + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct msg21xx_ts_platform_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = msg21xx_parse_dt(&client->dev, pdata); + if (ret) { + dev_err(&client->dev, "DT parsing failed\n"); + return ret; + } + } else + pdata = client->dev.platform_data; + + ts_data = devm_kzalloc(&client->dev, + sizeof(struct msg21xx_ts_data), GFP_KERNEL); + if (!ts_data) + return -ENOMEM; + + DBG("*** %s ***\n", __func__); + + i2c_client = client; + + ret = msg21xx_ts_power_init(); + if (ret) + dev_err(&client->dev, "Mstar power init failed\n"); + + ret = msg21xx_ts_power_on(); + if (ret) { + dev_err(&client->dev, "Mstar power on failed\n"); + goto exit_deinit_power; + } + + ret = msg21xx_pinctrl_init(); + if (!ret && ts_data->ts_pinctrl) { + ret = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_active); + if (ret < 0) + goto exit_pinctrl_select; + } else { + goto exit_pinctrl_init; + } + + ret = msg21xx_ts_gpio_configure(true); + if (ret) { + dev_err(&client->dev, "Failed to configure gpio %d\n", ret); + goto exit_gpio_config; + } + + if (get_ic_type() == 0) { + pr_err("the currnet ic is not Mstar\n"); + ret = -1; + goto err_wrong_ic_type; + } + + mutex_init(&msg21xx_mutex); + mutex_init(&ts_data->ts_mutex); + + /* allocate an input device */ + input_dev = input_allocate_device(); + if (!input_dev) { + ret = -ENOMEM; + pr_err("*** input device allocation failed ***\n"); + goto err_input_allocate_dev; + } + + input_dev->name = client->name; + input_dev->phys = "I2C"; + input_dev->dev.parent = &client->dev; + input_dev->id.bustype = BUS_I2C; + + /* set the supported event type for input device */ + set_bit(EV_ABS, input_dev->evbit); + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + set_bit(BTN_TOUCH, input_dev->keybit); + set_bit(BTN_TOOL_FINGER, input_dev->keybit); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + + ts_data->input_dev = input_dev; + ts_data->client = client; + ts_data->pdata = pdata; + + input_set_drvdata(input_dev, ts_data); + i2c_set_clientdata(client, ts_data); #ifdef CONFIG_TP_HAVE_KEY - { - int i; - for (i = 0; i < MAX_KEY_NUM; i ++) - { - input_set_capability(input_dev, EV_KEY, tp_key_array[i]); - } - } + { + int i; + + for (i = 0; i < num_buttons; i++) + input_set_capability(input_dev, EV_KEY, button_map[i]); + } #endif - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 2, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_X, TOUCH_SCREEN_X_MIN, TOUCH_SCREEN_X_MAX, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, TOUCH_SCREEN_Y_MIN, TOUCH_SCREEN_Y_MAX, 0, 0); - - /* register the input device to input sub-system */ - ret = input_register_device(input_dev); - if (ret < 0) - { - pr_err("*** Unable to register ms-touchscreen input device ***\n"); - goto err1; - } - - /* set sysfs for firmware */ - firmware_class = class_create(THIS_MODULE, "ms-touchscreen-msg20xx"); //client->name - if (IS_ERR(firmware_class)) - pr_err("Failed to create class(firmware)!\n"); - - firmware_cmd_dev = device_create(firmware_class, NULL, 0, NULL, "device"); - if (IS_ERR(firmware_cmd_dev)) - pr_err("Failed to create device(firmware_cmd_dev)!\n"); - - // version - if (device_create_file(firmware_cmd_dev, &dev_attr_version) < 0) - pr_err("Failed to create device file(%s)!\n", dev_attr_version.attr.name); - // update - if (device_create_file(firmware_cmd_dev, &dev_attr_update) < 0) - pr_err("Failed to create device file(%s)!\n", dev_attr_update.attr.name); - // data - if (device_create_file(firmware_cmd_dev, &dev_attr_data) < 0) - pr_err("Failed to create device file(%s)!\n", dev_attr_data.attr.name); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, + 0, 2, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, pdata->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, pdata->y_max, 0, 0); + ret = input_mt_init_slots(input_dev, MAX_TOUCH_NUM, 0); + if (ret) { + pr_err("Error %d initialising slots\n", ret); + goto err_free_mem; + } + + /* register the input device to input sub-system */ + ret = input_register_device(input_dev); + if (ret < 0) { + pr_err("*** Unable to register ms-touchscreen input device ***\n"); + goto err_input_reg_dev; + } + + /* set sysfs for firmware */ + firmware_class = class_create(THIS_MODULE, "ms-touchscreen-msg21xx"); + if (IS_ERR(firmware_class)) + pr_err("Failed to create class(firmware)!\n"); + + firmware_cmd_dev = device_create(firmware_class, NULL, 0, + NULL, "device"); + if (IS_ERR(firmware_cmd_dev)) + pr_err("Failed to create device(firmware_cmd_dev)!\n"); + + /* version */ + if (device_create_file(firmware_cmd_dev, &dev_attr_version) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_version.attr.name); + /* update */ + if (device_create_file(firmware_cmd_dev, &dev_attr_update) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_update.attr.name); + /* data */ + if (device_create_file(firmware_cmd_dev, &dev_attr_data) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_data.attr.name); + /* fw name*/ + if (device_create_file(firmware_cmd_dev, &dev_attr_fw_name) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_fw_name.attr.name); + /* smart fw update*/ + if (device_create_file(firmware_cmd_dev, &dev_attr_update_fw) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_update_fw.attr.name); + /* smart fw force update*/ + if (device_create_file(firmware_cmd_dev, &dev_attr_force_update_fw) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_force_update_fw.attr.name); #ifdef TP_PRINT - tp_print_create_entry(); + tp_print_create_entry(); #endif - dev_set_drvdata(firmware_cmd_dev, NULL); - - /* initialize the work queue */ - INIT_WORK(&msg21xx_wk, touch_driver_do_work); - - ret = gpio_request(MS_TS_MSG21XX_GPIO_INT, "interrupt"); - if (ret < 0) - { - pr_err("*** Failed to request GPIO %d, error %d ***\n", MS_TS_MSG21XX_GPIO_INT, ret); - goto err2; - } - gpio_direction_input(MS_TS_MSG21XX_GPIO_INT); - gpio_set_value(MS_TS_MSG21XX_GPIO_INT, 1); + dev_set_drvdata(firmware_cmd_dev, NULL); - irq_msg21xx = gpio_to_irq(MS_TS_MSG21XX_GPIO_INT); + ret = request_threaded_irq(client->irq, NULL, + msg21xx_ts_interrupt, + pdata->irq_gpio_flags | IRQF_ONESHOT, + "msg21xx", ts_data); + if (ret) + goto err_req_irq; - /* request an irq and register the isr */ - ret = request_irq(irq_msg21xx, touch_driver_isr, IRQF_TRIGGER_RISING, "msg21xx", NULL); - if (ret != 0) - { - pr_err("*** Unable to claim irq %d; error %d ***\n", MS_TS_MSG21XX_GPIO_INT, ret); - goto err3; - } - - disable_irq(irq_msg21xx); + disable_irq(ts_data->client->irq); #if defined(CONFIG_FB) - msg21xx_fb_notif.notifier_call = fb_notifier_callback; - ret = fb_register_client(&msg21xx_fb_notif); -#elif defined (CONFIG_HAS_EARLYSUSPEND) - mstar_ts_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; - mstar_ts_early_suspend.suspend = touch_driver_early_suspend; - mstar_ts_early_suspend.resume = touch_driver_early_resume; - register_early_suspend(&mstar_ts_early_suspend); + ts_data->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts_data->fb_notif); #endif -#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR - tsps_assist_register_callback("msg21xx", &tsps_msg21xx_enable, &tsps_msg21xx_data); +#ifdef CONFIG_TOUCHSCREEN_PROXIMITY_SENSOR + tsps_assist_register_callback("msg21xx", &tsps_msg21xx_enable, + &tsps_msg21xx_data); #endif #ifdef FIRMWARE_AUTOUPDATE - get_customer_firmware_version(); - _ReadBinConfig(); - - if (main_sw_id == info_sw_id) - { - if (_CalMainCRC32() == bin_conf_crc32) - { - if ((main_sw_id >= SWID_START) && (main_sw_id < SWID_NULL)) - { - update_bin_major= (MSG_FIRMWARE[main_sw_id-SWID_START][0x7f4f] << 8) + MSG_FIRMWARE[main_sw_id-SWID_START][0x7f4e]; - update_bin_minor= (MSG_FIRMWARE[main_sw_id-SWID_START][0x7f51] << 8) + MSG_FIRMWARE[main_sw_id-SWID_START][0x7f50]; - - //check upgrading - if ((update_bin_major == fw_version_major) && (update_bin_minor > fw_version_minor)) - { - update_flag = 1; - } - } - DBG("MAIN sw_id=%d,update_flag=%d,update_bin_major=%d,update_bin_minor=%d\n",main_sw_id,update_flag,update_bin_major,update_bin_minor); - } - else - { - if ((info_sw_id >= SWID_START) && (info_sw_id < SWID_NULL)) - { - update_bin_major= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4f] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4e]; - update_bin_minor= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f51] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f50]; - update_flag = 1; - } - DBG("INFO1 sw_id=%d,update_flag=%d,update_bin_major=%d,update_bin_minor=%d\n",info_sw_id,update_flag,update_bin_major,update_bin_minor); - } - } - else - { - if ((info_sw_id >= SWID_START) && (info_sw_id < SWID_NULL)) - { - update_bin_major= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4f] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f4e]; - update_bin_minor= (MSG_FIRMWARE[info_sw_id-SWID_START][0x7f51] << 8) + MSG_FIRMWARE[info_sw_id-SWID_START][0x7f50]; - update_flag = 1; - } - DBG("INFO2 sw_id=%d,update_flag=%d,update_bin_major=%d,update_bin_minor=%d\n",info_sw_id,update_flag,update_bin_major,update_bin_minor); - } - - if (update_flag == 1) - { - DBG("MSG21XX_fw_auto_update begin....\n"); - //transfer data - for (i = 0; i < 33; i++) - { - firmware_data_store(NULL, NULL, &(MSG_FIRMWARE[info_sw_id-SWID_START][i*1024]), 1024); - } - - kthread_run(fwAutoUpdate, 0, "MSG21XX_fw_auto_update"); - DBG("*** mstar touch screen registered ***\n"); - return 0; - } - - reset_hw(); + get_customer_firmware_version(); + _ReadBinConfig(); + + if (main_sw_id == info_sw_id) { + if (_CalMainCRC32() == bin_conf_crc32) { + if ((main_sw_id >= SWID_START) && + (main_sw_id < SWID_NULL)) { + update_bin_major = (MSG_FIRMWARE + [main_sw_id - SWID_START][0x7f4f] << 8) + + MSG_FIRMWARE[main_sw_id - SWID_START][0x7f4e]; + update_bin_minor = (MSG_FIRMWARE + [main_sw_id - SWID_START][0x7f51] << 8) + + MSG_FIRMWARE[main_sw_id - SWID_START][0x7f50]; + + /* check upgrading */ + if ((update_bin_major == fw_version_major) && + (update_bin_minor > fw_version_minor)) { + update_flag = 1; + } + } + } else { + if ((info_sw_id >= SWID_START) && + (info_sw_id < SWID_NULL)) { + update_bin_major = (MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f4f] << 8) + + MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f4e]; + update_bin_minor = (MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f51] << 8) + + MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f50]; + update_flag = 1; + } + } + } else { + if ((info_sw_id >= SWID_START) && (info_sw_id < SWID_NULL)) { + update_bin_major = (MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f4f] << 8) + + MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f4e]; + update_bin_minor = (MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f51] << 8) + + MSG_FIRMWARE + [info_sw_id - SWID_START][0x7f50]; + update_flag = 1; + } + } + + if (update_flag == 1) { + DBG("MSG21XX_fw_auto_update begin....\n"); + /* transfer data */ + for (i = 0; i < 33; i++) { + firmware_data_store(NULL, NULL, + &(MSG_FIRMWARE[info_sw_id - SWID_START][i * 1024]), + 1024); + } + + kthread_run(fwAutoUpdate, 0, "MSG21XX_fw_auto_update"); + DBG("*** mstar touch screen registered ***\n"); + return 0; + } + + reset_hw(); #endif - DBG("*** mstar touch screen registered ***\n"); - enable_irq(irq_msg21xx); - return 0; - -err3: - free_irq(irq_msg21xx, input_dev); - -err2: - gpio_free(MS_TS_MSG21XX_GPIO_INT); - -err1: - mutex_destroy(&msg21xx_mutex); - input_unregister_device(input_dev); - input_free_device(input_dev); - input_dev = NULL; - -err0: - gpio_free(MS_TS_MSG21XX_GPIO_RST); - - return ret; + DBG("*** mstar touch screen registered ***\n"); + enable_irq(ts_data->client->irq); + return 0; + +err_req_irq: + free_irq(ts_data->client->irq, ts_data); + +err_input_reg_dev: +err_input_allocate_dev: + mutex_destroy(&msg21xx_mutex); + mutex_destroy(&ts_data->ts_mutex); + input_unregister_device(input_dev); + input_free_device(input_dev); + input_dev = NULL; + +err_wrong_ic_type: + msg21xx_ts_gpio_configure(false); +exit_gpio_config: +exit_pinctrl_select: + if (ts_data->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { + devm_pinctrl_put(ts_data->ts_pinctrl); + ts_data->ts_pinctrl = NULL; + } else { + ret = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_release); + if (ret < 0) + pr_err("Cannot get release pinctrl state\n"); + } + } +exit_pinctrl_init: + msg21xx_ts_power_off(); +exit_deinit_power: + msg21xx_ts_power_deinit(); +err_free_mem: + input_free_device(input_dev); + + return ret; } -/* remove function is triggered when the input device is removed from input sub-system */ +/* remove function is triggered when the input device is removed + *from input sub-system + */ static int touch_driver_remove(struct i2c_client *client) { - DBG("touch_driver_remove()\n"); - - free_irq(irq_msg21xx, input_dev); - gpio_free(MS_TS_MSG21XX_GPIO_INT); - gpio_free(MS_TS_MSG21XX_GPIO_RST); - input_unregister_device(input_dev); - mutex_destroy(&msg21xx_mutex); - - return 0; + int retval = 0; + + DBG("touch_driver_remove()\n"); + + free_irq(ts_data->client->irq, ts_data); + gpio_free(pdata->irq_gpio); + gpio_free(pdata->reset_gpio); + + if (ts_data->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) { + devm_pinctrl_put(ts_data->ts_pinctrl); + ts_data->ts_pinctrl = NULL; + } else { + retval = pinctrl_select_state(ts_data->ts_pinctrl, + ts_data->pinctrl_state_release); + if (retval < 0) + pr_err("Cannot get release pinctrl state\n"); + } + } + + input_unregister_device(input_dev); + mutex_destroy(&msg21xx_mutex); + mutex_destroy(&ts_data->ts_mutex); + + return retval; } -/* The I2C device list is used for matching I2C device and I2C device driver. */ -static const struct i2c_device_id touch_device_id[] = -{ - {"msg21xx", 0}, - {}, /* should not omitted */ +/* The I2C device list is used for matching I2C device + *and I2C device driver. + */ +static const struct i2c_device_id touch_device_id[] = { + {"msg21xx", 0}, + {}, /* should not omitted */ }; -MODULE_DEVICE_TABLE(i2c, touch_device_id); - -static struct i2c_driver touch_device_driver = -{ - .driver = { - .name = "msg21xx", - .owner = THIS_MODULE, - }, - .probe = touch_driver_probe, - .remove = touch_driver_remove, - .id_table = touch_device_id, +static const struct of_device_id msg21xx_match_table[] = { + { .compatible = "mstar,msg21xx", }, + { }, }; -static int __init touch_driver_init(void) -{ - int ret; - - /* register driver */ - ret = i2c_add_driver(&touch_device_driver); - if (ret < 0) - { - DBG("add touch_device_driver i2c driver failed.\n"); - return -ENODEV; - } - DBG("add touch_device_driver i2c driver.\n"); - - return ret; -} +MODULE_DEVICE_TABLE(i2c, touch_device_id); -static void __exit touch_driver_exit(void) -{ - DBG("remove touch_device_driver i2c driver.\n"); +static struct i2c_driver touch_device_driver = { + .driver = { + .name = "ms-msg21xx", + .owner = THIS_MODULE, + .of_match_table = msg21xx_match_table, + }, + .probe = msg21xx_ts_probe, + .remove = touch_driver_remove, + .id_table = touch_device_id, +}; - i2c_del_driver(&touch_device_driver); -} +module_i2c_driver(touch_device_driver); #ifdef TP_PRINT #include <linux/proc_fs.h> -static U16 InfoAddr = 0x0F, PoolAddr = 0x10, TransLen = 256; -static U8 row, units, cnt; +static unsigned short InfoAddr = 0x0F, PoolAddr = 0x10, TransLen = 256; +static unsigned char row, units, cnt; static int tp_print_proc_read(void) { - U16 i, j; - U16 left, offset = 0; - U8 dbbus_tx_data[3] = {0}; - U8 u8Data; - S16 s16Data; - S32 s32Data; - char *buf = NULL; - - left = cnt*row*units; - if ((bTpInSuspend == 0) && (InfoAddr != 0x0F) && (PoolAddr != 0x10) && (left > 0)) - { - buf = kmalloc(left, GFP_KERNEL); - if (buf != NULL) - { - printk("tpp: \n"); - - while (left > 0) - { - dbbus_tx_data[0] = 0x53; - dbbus_tx_data[1] = ((PoolAddr + offset) >> 8) & 0xFF; - dbbus_tx_data[2] = (PoolAddr + offset) & 0xFF; - mutex_lock(&msg21xx_mutex); - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &buf[offset], left > TransLen ? TransLen : left); - mutex_unlock(&msg21xx_mutex); - - if (left > TransLen) - { - left -= TransLen; - offset += TransLen; - } - else - { - left = 0; - } - } - - for (i = 0; i < cnt; i++) - { - printk("tpp: "); - for (j = 0; j < row; j++) - { - if (units == 1) - { - u8Data = buf[i*row*units + j*units]; - printk("%d\t", u8Data); - } - else if (units == 2) - { - s16Data = buf[i*row*units + j*units] + (buf[i*row*units + j*units + 1] << 8); - printk("%d\t", s16Data); - } - else if (units == 4) - { - s32Data = buf[i*row*units + j*units] + (buf[i*row*units + j*units + 1] << 8) + (buf[i*row*units + j*units + 2] << 16) + (buf[i*row*units + j*units + 3] << 24); - printk("%d\t", s32Data); - } - } - printk("\n"); - } - - kfree(buf); - } - } - - return 0; + unsigned short i, j; + unsigned short left, offset = 0; + unsigned char dbbus_tx_data[3] = {0}; + unsigned char u8Data; + signed short s16Data; + int s32Data; + char *buf = NULL; + + left = cnt*row*units; + if ((ts_data->suspended == 0) && + (InfoAddr != 0x0F) && + (PoolAddr != 0x10) && + (left > 0)) { + buf = kmalloc(left, GFP_KERNEL); + if (buf != NULL) { + + while (left > 0) { + dbbus_tx_data[0] = 0x53; + dbbus_tx_data[1] = ((PoolAddr + offset) >> 8) + & 0xFF; + dbbus_tx_data[2] = (PoolAddr + offset) & 0xFF; + mutex_lock(&msg21xx_mutex); + write_i2c_seq(ts_data->client->addr, + &dbbus_tx_data[0], 3); + read_i2c_seq(ts_data->client->addr, + &buf[offset], + left > TransLen ? TransLen : left); + mutex_unlock(&msg21xx_mutex); + + if (left > TransLen) { + left -= TransLen; + offset += TransLen; + } else { + left = 0; + } + } + + for (i = 0; i < cnt; i++) { + for (j = 0; j < row; j++) { + if (units == 1) { + u8Data = buf[i * row * units + + j * units]; + } else if (units == 2) { + s16Data = buf[i * row * units + + j * units] + + (buf[i * row * units + + j * units + 1] << 8); + } else if (units == 4) { + s32Data = buf[i * row * units + + j * units] + + (buf[i * row * units + + j * units + 1] << 8) + + (buf[i * row * units + + j * units + 2] << 16) + + (buf[i * row * units + + j * units + 3] << 24); + } + } + } + + kfree(buf); + } + } + + return 0; } static void tp_print_create_entry(void) { - U8 dbbus_tx_data[3] = {0}; - U8 dbbus_rx_data[8] = {0}; - - dbbus_tx_data[0] = 0x53; - dbbus_tx_data[1] = 0x00; - dbbus_tx_data[2] = 0x58; - mutex_lock(&msg21xx_mutex); - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 4); - mutex_unlock(&msg21xx_mutex); - InfoAddr = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0]; - PoolAddr = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2]; - printk("InfoAddr=0x%X\n", InfoAddr); - printk("PoolAddr=0x%X\n", PoolAddr); - - if ((InfoAddr != 0x0F) && (PoolAddr != 0x10)) - { - msleep(10); - dbbus_tx_data[0] = 0x53; - dbbus_tx_data[1] = (InfoAddr >> 8) & 0xFF; - dbbus_tx_data[2] = InfoAddr & 0xFF; - mutex_lock(&msg21xx_mutex); - write_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_tx_data[0], 3); - read_i2c_seq(SLAVE_I2C_ID_DWI2C, &dbbus_rx_data[0], 8); - mutex_unlock(&msg21xx_mutex); - - units = dbbus_rx_data[0]; - row = dbbus_rx_data[1]; - cnt = dbbus_rx_data[2]; - TransLen = (dbbus_rx_data[7]<<8) + dbbus_rx_data[6]; - printk("tpp: row=%d, units=%d\n", row, units); - printk("tpp: cnt=%d, TransLen=%d\n", cnt, TransLen); - - // tpp - if (device_create_file(firmware_cmd_dev, &dev_attr_tpp) < 0) - { - pr_err("Failed to create device file(%s)!\n", dev_attr_tpp.attr.name); - } - } + unsigned char dbbus_tx_data[3] = {0}; + unsigned char dbbus_rx_data[8] = {0}; + + dbbus_tx_data[0] = 0x53; + dbbus_tx_data[1] = 0x00; + dbbus_tx_data[2] = 0x58; + mutex_lock(&msg21xx_mutex); + write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 3); + read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 4); + mutex_unlock(&msg21xx_mutex); + InfoAddr = (dbbus_rx_data[1]<<8) + dbbus_rx_data[0]; + PoolAddr = (dbbus_rx_data[3]<<8) + dbbus_rx_data[2]; + + if ((InfoAddr != 0x0F) && (PoolAddr != 0x10)) { + msleep(20); + dbbus_tx_data[0] = 0x53; + dbbus_tx_data[1] = (InfoAddr >> 8) & 0xFF; + dbbus_tx_data[2] = InfoAddr & 0xFF; + mutex_lock(&msg21xx_mutex); + write_i2c_seq(ts_data->client->addr, &dbbus_tx_data[0], 3); + read_i2c_seq(ts_data->client->addr, &dbbus_rx_data[0], 8); + mutex_unlock(&msg21xx_mutex); + + units = dbbus_rx_data[0]; + row = dbbus_rx_data[1]; + cnt = dbbus_rx_data[2]; + TransLen = (dbbus_rx_data[7]<<8) + dbbus_rx_data[6]; + + if (device_create_file(firmware_cmd_dev, &dev_attr_tpp) < 0) { + pr_err("Failed to create device file(%s)!\n", + dev_attr_tpp.attr.name); + } + } } #endif -module_init(touch_driver_init); -module_exit(touch_driver_exit); MODULE_AUTHOR("MStar Semiconductor, Inc."); MODULE_LICENSE("GPL v2"); - diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 55eff5ae04e4..c69927bd4ff2 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -386,6 +386,7 @@ struct arm_smmu_device { unsigned int *irqs; struct list_head list; + struct list_head static_cbndx_list; struct rb_root masters; int num_clocks; @@ -491,6 +492,18 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { 0, NULL}, }; +#define TYPE_TRANS (S2CR_TYPE_TRANS >> S2CR_TYPE_SHIFT) +#define TYPE_BYPASS (S2CR_TYPE_BYPASS >> S2CR_TYPE_SHIFT) +#define TYPE_FAULT (S2CR_TYPE_FAULT >> S2CR_TYPE_SHIFT) + +struct static_cbndx_entry { + struct list_head list; + u8 cbndx; + u8 smr_idx; + u16 sid; + u8 type; +}; + static int arm_smmu_enable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_disable_clocks_atomic(struct arm_smmu_device *smmu); static void arm_smmu_prepare_pgtable(void *addr, void *cookie); @@ -767,11 +780,103 @@ static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end) return idx; } +static int __arm_smmu_set_bitmap(unsigned long *map, int idx) +{ + return test_and_set_bit(idx, map); +} + +static struct static_cbndx_entry *arm_smmu_get_static_entry_from_sid( + struct arm_smmu_device *smmu, int sid) +{ + struct static_cbndx_entry *entry; + + list_for_each_entry(entry, &smmu->static_cbndx_list, list) { + if (entry->sid == sid) + return entry; + } + + return NULL; +} + +static struct static_cbndx_entry *arm_smmu_get_static_entry_from_context( + struct arm_smmu_device *smmu, int idx) +{ + struct static_cbndx_entry *entry; + + list_for_each_entry(entry, &smmu->static_cbndx_list, list) { + if (entry->type == TYPE_TRANS && entry->cbndx == idx) + return entry; + } + + return NULL; +} + +static struct static_cbndx_entry *arm_smmu_get_static_entry_from_smr( + struct arm_smmu_device *smmu, int idx) +{ + struct static_cbndx_entry *entry; + + list_for_each_entry(entry, &smmu->static_cbndx_list, list) { + if (entry->smr_idx == idx) + return entry; + } + + return NULL; +} + +static int arm_smmu_alloc_smr_idx(struct arm_smmu_device *smmu, int start, + int end, int sid) +{ + struct static_cbndx_entry *entry = arm_smmu_get_static_entry_from_sid( + smmu, sid); + + if (entry) + return entry->smr_idx; + else + return __arm_smmu_alloc_bitmap(smmu->smr_map, start, end); +} + +static int arm_smmu_alloc_context_idx(struct arm_smmu_device *smmu, int start, + int end, u16 *streamids, int num_streamids) +{ + struct static_cbndx_entry *entry = NULL; + int i; + + for (i = 0; i < num_streamids; ++i) { + entry = arm_smmu_get_static_entry_from_sid(smmu, streamids[i]); + if (entry && entry->type == TYPE_TRANS) + break; + } + + if (entry && entry->type == TYPE_TRANS) + return entry->cbndx; + else + return __arm_smmu_alloc_bitmap(smmu->context_map, start, end); +} + static void __arm_smmu_free_bitmap(unsigned long *map, int idx) { clear_bit(idx, map); } +static void arm_smmu_free_smr_idx(struct arm_smmu_device *smmu, int idx) +{ + struct static_cbndx_entry *entry = arm_smmu_get_static_entry_from_smr( + smmu, idx); + + if (!entry) + __arm_smmu_free_bitmap(smmu->smr_map, idx); +} + +static void arm_smmu_free_context_idx(struct arm_smmu_device *smmu, int idx) +{ + struct static_cbndx_entry *entry = + arm_smmu_get_static_entry_from_context(smmu, idx); + + if (!entry) + __arm_smmu_free_bitmap(smmu->context_map, idx); +} + static void arm_smmu_unprepare_clocks(struct arm_smmu_device *smmu) { int i; @@ -1582,7 +1687,8 @@ static int arm_smmu_restore_sec_cfg(struct arm_smmu_device *smmu) } static int arm_smmu_init_domain_context(struct iommu_domain *domain, - struct arm_smmu_device *smmu) + struct arm_smmu_device *smmu, + struct arm_smmu_master_cfg *master_cfg) { int irq, start, ret = 0; unsigned long ias, oas; @@ -1650,14 +1756,12 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, } if (cfg->cbndx == INVALID_CBNDX) { - ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, - smmu->num_context_banks); + ret = arm_smmu_alloc_context_idx(smmu, start, + smmu->num_context_banks, master_cfg->streamids, + master_cfg->num_streamids); if (IS_ERR_VALUE(ret)) goto out; cfg->cbndx = ret; - } else { - if (test_and_set_bit(cfg->cbndx, smmu->context_map)) - goto out; } if (smmu->version == ARM_SMMU_V1) { @@ -1764,7 +1868,7 @@ free_irqs: free_irq(irq, domain); } - __arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx); + arm_smmu_free_context_idx(smmu, cfg->cbndx); smmu_domain->smmu = NULL; } @@ -1847,8 +1951,8 @@ static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu, /* Allocate the SMRs on the SMMU */ for (i = 0; i < cfg->num_streamids; ++i) { - int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0, - smmu->num_mapping_groups); + int idx = arm_smmu_alloc_smr_idx(smmu, 0, + smmu->num_mapping_groups, cfg->streamids[i]); if (IS_ERR_VALUE(idx)) { dev_err(smmu->dev, "failed to allocate free SMR\n"); goto err_free_smrs; @@ -1873,7 +1977,7 @@ static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu, err_free_smrs: while (--i >= 0) - __arm_smmu_free_bitmap(smmu->smr_map, smrs[i].idx); + arm_smmu_free_smr_idx(smmu, smrs[i].idx); kfree(smrs); return -ENOSPC; } @@ -1893,7 +1997,7 @@ static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu, u8 idx = smrs[i].idx; writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(idx)); - __arm_smmu_free_bitmap(smmu->smr_map, idx); + arm_smmu_free_smr_idx(smmu, idx); } cfg->smrs = NULL; @@ -2051,32 +2155,18 @@ out: static int arm_smmu_populate_cb(struct arm_smmu_device *smmu, struct arm_smmu_domain *smmu_domain, struct device *dev) { - void __iomem *gr0_base; struct arm_smmu_master_cfg *cfg; struct arm_smmu_cfg *smmu_cfg = &smmu_domain->cfg; - int i; - u32 sid; + struct static_cbndx_entry *entry; - gr0_base = ARM_SMMU_GR0(smmu); cfg = find_smmu_master_cfg(dev); - if (!cfg) return -ENODEV; - sid = cfg->streamids[0]; - - for (i = 0; i < smmu->num_mapping_groups; i++) { - u32 smr, s2cr; - u8 cbndx; - - smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(i)); - - if (sid == ((smr >> SMR_ID_SHIFT) & SMR_ID_MASK)) { - s2cr = readl_relaxed(gr0_base + ARM_SMMU_GR0_S2CR(i)); - cbndx = (s2cr >> S2CR_CBNDX_SHIFT) & S2CR_CBNDX_MASK; - smmu_cfg->cbndx = cbndx; - return 0; - } + entry = arm_smmu_get_static_entry_from_sid(smmu, cfg->streamids[0]); + if (entry && entry->type == TYPE_TRANS) { + smmu_cfg->cbndx = entry->cbndx; + return 0; } return -EINVAL; @@ -2150,8 +2240,14 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) smmu_domain->slave_side_secure = true; } + cfg = find_smmu_master_cfg(dev); + if (!cfg) { + ret = -ENODEV; + goto err_disable_clocks; + } + /* Ensure that the domain is finalised */ - ret = arm_smmu_init_domain_context(domain, smmu); + ret = arm_smmu_init_domain_context(domain, smmu, cfg); if (IS_ERR_VALUE(ret)) goto err_disable_clocks; @@ -2177,12 +2273,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) } /* Looks ok, so add the device to the domain */ - cfg = find_smmu_master_cfg(dev); - if (!cfg) { - ret = -ENODEV; - goto err_destroy_domain_context; - } - ret = arm_smmu_domain_add_master(smmu_domain, cfg); if (ret) goto err_destroy_domain_context; @@ -3603,6 +3693,62 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return 0; } +static int arm_smmu_add_static_cbndx(struct arm_smmu_device *smmu, int sid, + int smr_idx) +{ + void __iomem *gr0_base; + u32 s2cr_reg; + struct static_cbndx_entry *entry; + + entry = devm_kzalloc(smmu->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + gr0_base = ARM_SMMU_GR0(smmu); + s2cr_reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_S2CR(smr_idx)); + entry->type = (s2cr_reg >> S2CR_TYPE_SHIFT) & S2CR_TYPE_MASK; + entry->smr_idx = smr_idx; + entry->sid = sid; + + if (entry->type == TYPE_TRANS) { + entry->cbndx = (s2cr_reg >> S2CR_CBNDX_SHIFT) & + S2CR_CBNDX_MASK; + __arm_smmu_set_bitmap(smmu->context_map, entry->cbndx); + pr_debug("Static context bank: smr:%d, sid:%d, cbndx:%d\n", + smr_idx, sid, entry->cbndx); + } + __arm_smmu_set_bitmap(smmu->smr_map, smr_idx); + list_add(&entry->list, &smmu->static_cbndx_list); + + return 0; +} + +static int arm_smmu_init_static_cbndx_list(struct arm_smmu_device *smmu) +{ + int i, ret = 0; + void __iomem *gr0_base = ARM_SMMU_GR0(smmu); + + for (i = 0; i < smmu->num_mapping_groups; ++i) { + u32 smr_reg, sid; + + smr_reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(i)); + if (smr_reg & SMR_VALID) { + u32 smr_mask = (smr_reg >> SMR_MASK_SHIFT) & + SMR_MASK_MASK; + + if (smr_mask != 0) + dev_warn(smmu->dev, + "Static smr mask not supported\n"); + sid = ((smr_reg >> SMR_ID_SHIFT) & SMR_ID_MASK); + ret = arm_smmu_add_static_cbndx(smmu, sid, i); + if (ret) + break; + } + } + + return ret; +} + static const struct of_device_id arm_smmu_of_match[] = { { .compatible = "arm,smmu-v1", .data = (void *)ARM_SMMU_V1 }, { .compatible = "arm,smmu-v2", .data = (void *)ARM_SMMU_V2 }, @@ -3632,6 +3778,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) mutex_init(&smmu->attach_lock); spin_lock_init(&smmu->atos_lock); spin_lock_init(&smmu->clock_refs_lock); + INIT_LIST_HEAD(&smmu->static_cbndx_list); of_id = of_match_node(arm_smmu_of_match, dev->of_node); if (!of_id) @@ -3713,6 +3860,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) smmu->sec_id = msm_dev_to_device_id(dev); err = arm_smmu_device_cfg_probe(smmu); + if (!err) + err = arm_smmu_init_static_cbndx_list(smmu); + arm_smmu_disable_clocks(smmu); if (err) goto out_put_masters; diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 18ae7fa5454b..9c2697dde76d 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -114,7 +114,6 @@ config IPA3 Kernel and user-space processes can call the IPA driver to configure IPA core. - config RMNET_IPA3 tristate "IPA3 RMNET WWAN Network Device" depends on IPA3 && MSM_QMI_INTERFACE @@ -124,6 +123,16 @@ config RMNET_IPA3 for RmNet Data Driver and also exchange of QMI messages between A7 and Q6 IPA-driver. +config IPA_UT + tristate "IPA Unit-Test Framework and Test Suites" + depends on IPA3 && DEBUG_FS + help + This Module implements IPA in-kernel test framework. + The framework supports defining and running tests, grouped + into suites according to the sub-unit of the IPA being tested. + The user interface to run and control the tests is debugfs file + system. + config SSM tristate "QTI Secure Service Module" depends on QSEECOM diff --git a/drivers/platform/msm/ipa/Makefile b/drivers/platform/msm/ipa/Makefile index 704dd0abfefa..15ed471f383c 100644 --- a/drivers/platform/msm/ipa/Makefile +++ b/drivers/platform/msm/ipa/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_IPA) += ipa_v2/ ipa_clients/ ipa_common obj-$(CONFIG_IPA3) += ipa_v3/ ipa_clients/ ipa_common +obj-$(CONFIG_IPA_UT) += test/ ipa_common += ipa_api.o ipa_rm.o ipa_rm_dependency_graph.o ipa_rm_peers_list.o ipa_rm_resource.o ipa_rm_inactivity_timer.o diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 09d1166e29a6..a08d157e2b0f 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -2533,6 +2533,50 @@ int ipa_stop_gsi_channel(u32 clnt_hdl) } EXPORT_SYMBOL(ipa_stop_gsi_channel); +/** + * ipa_get_version_string() - Get string representation of IPA version + * @ver: IPA version + * + * Return: Constant string representation + */ +const char *ipa_get_version_string(enum ipa_hw_type ver) +{ + const char *str; + + switch (ver) { + case IPA_HW_v1_0: + str = "1.0"; + break; + case IPA_HW_v1_1: + str = "1.1"; + break; + case IPA_HW_v2_0: + str = "2.0"; + break; + case IPA_HW_v2_1: + str = "2.1"; + break; + case IPA_HW_v2_5: + str = "2.5/2.6"; + break; + case IPA_HW_v2_6L: + str = "2.6L"; + break; + case IPA_HW_v3_0: + str = "3.0"; + break; + case IPA_HW_v3_1: + str = "3.1"; + break; + default: + str = "Invalid version"; + break; + } + + return str; +} +EXPORT_SYMBOL(ipa_get_version_string); + static struct of_device_id ipa_plat_drv_match[] = { { .compatible = "qcom,ipa", }, { .compatible = "qcom,ipa-smmu-ap-cb", }, diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h index 115348251d17..c5f75046cd2c 100644 --- a/drivers/platform/msm/ipa/ipa_common_i.h +++ b/drivers/platform/msm/ipa/ipa_common_i.h @@ -355,5 +355,6 @@ u8 *ipa_write_16(u16 hw, u8 *dest); u8 *ipa_write_8(u8 b, u8 *dest); u8 *ipa_pad_to_64(u8 *dest); u8 *ipa_pad_to_32(u8 *dest); +const char *ipa_get_version_string(enum ipa_hw_type ver); #endif /* _IPA_COMMON_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index c3c5ae38ec14..95ef9afbbd3e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -2131,6 +2131,12 @@ void ipa3_debugfs_remove(void) debugfs_remove_recursive(dent); } +struct dentry *ipa_debugfs_get_root(void) +{ + return dent; +} +EXPORT_SYMBOL(ipa_debugfs_get_root); + #else /* !CONFIG_DEBUG_FS */ void ipa3_debugfs_init(void) {} void ipa3_debugfs_remove(void) {} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 806510ea8867..a7587b2b9675 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2012,4 +2012,5 @@ int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr, u32 size, bool map); int ipa3_ntn_init(void); int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats); +struct dentry *ipa_debugfs_get_root(void); #endif /* _IPA3_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index 6c4d14b093c3..bcd2cb3bfd7a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -535,6 +535,11 @@ static int ipahal_imm_cmd_init(enum ipa_hw_type ipa_hw_type) IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type); + if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) { + IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type); + return -EINVAL; + } + memset(&zero_obj, 0, sizeof(zero_obj)); for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) { for (j = 0; j < IPA_IMM_CMD_MAX ; j++) { @@ -901,6 +906,11 @@ static int ipahal_pkt_status_init(enum ipa_hw_type ipa_hw_type) IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type); + if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) { + IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type); + return -EINVAL; + } + /* * Since structure alignment is implementation dependent, * add test to avoid different and incompatible data layouts. @@ -1269,6 +1279,12 @@ int ipahal_init(enum ipa_hw_type ipa_hw_type, void __iomem *base, goto bail_free_ctx; } + if (ipa_hw_type >= IPA_HW_MAX) { + IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type); + result = -EINVAL; + goto bail_free_ctx; + } + if (!base) { IPAHAL_ERR("invalid memory io mapping addr\n"); result = -EINVAL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index c47d353d9658..a3345d7ac305 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -1066,6 +1066,11 @@ int ipahal_reg_init(enum ipa_hw_type ipa_hw_type) IPAHAL_DBG_LOW("Entry - HW_TYPE=%d\n", ipa_hw_type); + if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) { + IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type); + return -EINVAL; + } + memset(&zero_obj, 0, sizeof(zero_obj)); for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) { for (j = 0; j < IPA_REG_MAX ; j++) { diff --git a/drivers/platform/msm/ipa/test/Makefile b/drivers/platform/msm/ipa/test/Makefile new file mode 100644 index 000000000000..62bb9a783c89 --- /dev/null +++ b/drivers/platform/msm/ipa/test/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_IPA_UT) += ipa_ut_mod.o +ipa_ut_mod-y := ipa_ut_framework.o ipa_test_example.o diff --git a/drivers/platform/msm/ipa/test/ipa_test_example.c b/drivers/platform/msm/ipa/test/ipa_test_example.c new file mode 100644 index 000000000000..0313375ec3d3 --- /dev/null +++ b/drivers/platform/msm/ipa/test/ipa_test_example.c @@ -0,0 +1,99 @@ +/* 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 "ipa_ut_framework.h" + +/** + * Example IPA Unit-test suite + * To be a reference for writing new suites and tests. + * This suite is also used as unit-test for the testing framework itself. + * Structure: + * 1- Define the setup and teardown functions + * Not Mandatory. Null may be used as well + * 2- For each test, define its Run() function + * 3- Use IPA_UT_DEFINE_SUITE_START() to start defining the suite + * 4- use IPA_UT_ADD_TEST() for adding tests within + * the suite definition block + * 5- IPA_UT_DEFINE_SUITE_END() close the suite definition + */ + +static int ipa_test_example_dummy; + +static int ipa_test_example_suite_setup(void **ppriv) +{ + IPA_UT_DBG("Start Setup - set 0x1234F\n"); + + ipa_test_example_dummy = 0x1234F; + *ppriv = (void *)&ipa_test_example_dummy; + + return 0; +} + +static int ipa_test_example_teardown(void *priv) +{ + IPA_UT_DBG("Start Teardown\n"); + IPA_UT_DBG("priv=0x%p - value=0x%x\n", priv, *((int *)priv)); + + return 0; +} + +static int ipa_test_example_test1(void *priv) +{ + IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv)); + ipa_test_example_dummy++; + + return 0; +} + +static int ipa_test_example_test2(void *priv) +{ + IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv)); + ipa_test_example_dummy++; + + return 0; +} + +static int ipa_test_example_test3(void *priv) +{ + IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv)); + ipa_test_example_dummy++; + + return 0; +} + +static int ipa_test_example_test4(void *priv) +{ + IPA_UT_LOG("priv=0x%p - value=0x%x\n", priv, *((int *)priv)); + ipa_test_example_dummy++; + + IPA_UT_TEST_FAIL_REPORT("failed on test"); + + return -EFAULT; +} + +/* Suite definition block */ +IPA_UT_DEFINE_SUITE_START(example, "Example suite", + ipa_test_example_suite_setup, ipa_test_example_teardown) +{ + IPA_UT_ADD_TEST(test1, "This is test number 1", + ipa_test_example_test1, false, IPA_HW_v1_0, IPA_HW_MAX), + + IPA_UT_ADD_TEST(test2, "This is test number 2", + ipa_test_example_test2, false, IPA_HW_v1_0, IPA_HW_MAX), + + IPA_UT_ADD_TEST(test3, "This is test number 3", + ipa_test_example_test3, false, IPA_HW_v1_1, IPA_HW_v2_6), + + IPA_UT_ADD_TEST(test4, "This is test number 4", + ipa_test_example_test4, false, IPA_HW_v1_1, IPA_HW_MAX), + +} IPA_UT_DEFINE_SUITE_END(example); diff --git a/drivers/platform/msm/ipa/test/ipa_ut_framework.c b/drivers/platform/msm/ipa/test/ipa_ut_framework.c new file mode 100644 index 000000000000..8816fc37c2e2 --- /dev/null +++ b/drivers/platform/msm/ipa/test/ipa_ut_framework.c @@ -0,0 +1,969 @@ +/* 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/mutex.h> +#include <linux/module.h> +#include <linux/debugfs.h> +#include <linux/device.h> +#include <linux/ipa.h> +#include "../ipa_v3/ipa_i.h" +#include "ipa_ut_framework.h" +#include "ipa_ut_suite_list.h" +#include "ipa_ut_i.h" + + +#define IPA_UT_DEBUG_WRITE_BUF_SIZE 256 +#define IPA_UT_DEBUG_READ_BUF_SIZE 1024 + +#define IPA_UT_READ_WRITE_DBG_FILE_MODE \ + (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP) + +/** + * struct ipa_ut_context - I/S context + * @inited: Will wait till IPA is ready. Will create the enable file + * @enabled: All tests and suite debugfs files are created + * @lock: Lock for mutual exclustion + * @ipa_dbgfs_root: IPA root debugfs folder + * @test_dbgfs_root: UT root debugfs folder. Sub-folder of IPA root + * @test_dbgfs_suites: Suites root debugfs folder. Sub-folder of UT root + */ +struct ipa_ut_context { + bool inited; + bool enabled; + struct mutex lock; + struct dentry *ipa_dbgfs_root; + struct dentry *test_dbgfs_root; + struct dentry *test_dbgfs_suites; +}; + +static ssize_t ipa_ut_dbgfs_enable_read(struct file *file, + char __user *ubuf, size_t count, loff_t *ppos); +static ssize_t ipa_ut_dbgfs_enable_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos); +static ssize_t ipa_ut_dbgfs_test_read(struct file *file, + char __user *ubuf, size_t count, loff_t *ppos); +static ssize_t ipa_ut_dbgfs_test_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos); +static int ipa_ut_dbgfs_all_test_open(struct inode *inode, + struct file *filp); +static int ipa_ut_dbgfs_regression_test_open(struct inode *inode, + struct file *filp); +static ssize_t ipa_ut_dbgfs_meta_test_read(struct file *file, + char __user *ubuf, size_t count, loff_t *ppos); +static ssize_t ipa_ut_dbgfs_meta_test_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos); + + +static const struct file_operations ipa_ut_dbgfs_enable_fops = { + .read = ipa_ut_dbgfs_enable_read, + .write = ipa_ut_dbgfs_enable_write, +}; +static const struct file_operations ipa_ut_dbgfs_test_fops = { + .read = ipa_ut_dbgfs_test_read, + .write = ipa_ut_dbgfs_test_write, +}; +static const struct file_operations ipa_ut_dbgfs_all_test_fops = { + .open = ipa_ut_dbgfs_all_test_open, + .read = ipa_ut_dbgfs_meta_test_read, + .write = ipa_ut_dbgfs_meta_test_write, +}; +static const struct file_operations ipa_ut_dbgfs_regression_test_fops = { + .open = ipa_ut_dbgfs_regression_test_open, + .read = ipa_ut_dbgfs_meta_test_read, + .write = ipa_ut_dbgfs_meta_test_write, +}; + +static struct ipa_ut_context *ipa_ut_ctx; +char *_IPA_UT_TEST_LOG_BUF_NAME; +struct ipa_ut_tst_fail_report _IPA_UT_TEST_FAIL_REPORT_DATA; + + +/** + * ipa_ut_show_suite_exec_summary() - Show tests run summary + * @suite: suite to print its running summary + * + * Print list of succeeded tests, failed tests and skipped tests + * + * Note: Assumes lock acquired + */ +static void ipa_ut_show_suite_exec_summary(const struct ipa_ut_suite *suite) +{ + int i; + + IPA_UT_DBG("Entry\n"); + + ipa_assert_on(!suite); + + pr_info("\n\n"); + pr_info("\t Suite '%s' summary\n", suite->meta_data->name); + pr_info("===========================\n"); + pr_info("Successful tests\n"); + pr_info("----------------\n"); + for (i = 0 ; i < suite->tests_cnt ; i++) { + if (suite->tests[i].res != IPA_UT_TEST_RES_SUCCESS) + continue; + pr_info("\t%s\n", suite->tests[i].name); + } + pr_info("\nFailed tests\n"); + pr_info("------------\n"); + for (i = 0 ; i < suite->tests_cnt ; i++) { + if (suite->tests[i].res != IPA_UT_TEST_RES_FAIL) + continue; + pr_info("\t%s\n", suite->tests[i].name); + } + pr_info("\nSkipped tests\n"); + pr_info("-------------\n"); + for (i = 0 ; i < suite->tests_cnt ; i++) { + if (suite->tests[i].res != IPA_UT_TEST_RES_SKIP) + continue; + pr_info("\t%s\n", suite->tests[i].name); + } + pr_info("\n"); +} + +/** + * ipa_ut_dbgfs_meta_test_write() - Debugfs write func for a for a meta test + * @params: write fops + * + * Used to run all/regression tests in a suite + * Create log buffer that the test can use to store ongoing logs + * IPA clocks need to be voted. + * Run setup() once before running the tests and teardown() once after + * If no such call-backs then ignore it; if failed then fail the suite + * Print tests progress during running + * Test log and fail report will be showed only if the test failed. + * Finally show Summary of the suite tests running + * + * Note: If test supported IPA H/W version mismatch, skip it + * If a test lack run function, skip it + * If test doesn't belong to regression and it is regression run, skip it + * Note: Running mode: Do not stop running on failure + * + * Return: Negative in failure, given characters amount in success + */ +static ssize_t ipa_ut_dbgfs_meta_test_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct ipa_ut_suite *suite; + int i; + enum ipa_hw_type ipa_ver; + int rc = 0; + long meta_type; + bool tst_fail = false; + + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + suite = file->f_inode->i_private; + ipa_assert_on(!suite); + meta_type = (long)(file->private_data); + IPA_UT_DBG("Meta test type %ld\n", meta_type); + + _IPA_UT_TEST_LOG_BUF_NAME = kzalloc(_IPA_UT_TEST_LOG_BUF_SIZE, + GFP_KERNEL); + if (!_IPA_UT_TEST_LOG_BUF_NAME) { + IPA_UT_ERR("failed to allocate %d bytes\n", + _IPA_UT_TEST_LOG_BUF_SIZE); + rc = -ENOMEM; + goto unlock_mutex; + } + + if (!suite->tests_cnt || !suite->tests) { + pr_info("No tests for suite '%s'\n", suite->meta_data->name); + goto free_mem; + } + + ipa_ver = ipa_get_hw_type(); + + IPA_ACTIVE_CLIENTS_INC_SPECIAL("IPA_UT"); + + if (suite->meta_data->setup) { + pr_info("*** Suite '%s': Run setup ***\n", + suite->meta_data->name); + rc = suite->meta_data->setup(&suite->meta_data->priv); + if (rc) { + IPA_UT_ERR("Setup failed for suite %s\n", + suite->meta_data->name); + rc = -EFAULT; + goto release_clock; + } + } else { + pr_info("*** Suite '%s': No Setup ***\n", + suite->meta_data->name); + } + + pr_info("*** Suite '%s': Run %s tests ***\n\n", + suite->meta_data->name, + meta_type == IPA_UT_META_TEST_REGRESSION ? "regression" : "all" + ); + for (i = 0 ; i < suite->tests_cnt ; i++) { + if (meta_type == IPA_UT_META_TEST_REGRESSION && + !suite->tests[i].run_in_regression) { + pr_info( + "*** Test '%s': Skip - Not in regression ***\n\n" + , suite->tests[i].name); + suite->tests[i].res = IPA_UT_TEST_RES_SKIP; + continue; + } + if (suite->tests[i].min_ipa_hw_ver > ipa_ver || + suite->tests[i].max_ipa_hw_ver < ipa_ver) { + pr_info( + "*** Test '%s': Skip - IPA VER mismatch ***\n\n" + , suite->tests[i].name); + suite->tests[i].res = IPA_UT_TEST_RES_SKIP; + continue; + } + if (!suite->tests[i].run) { + pr_info( + "*** Test '%s': Skip - No Run function ***\n\n" + , suite->tests[i].name); + suite->tests[i].res = IPA_UT_TEST_RES_SKIP; + continue; + } + + _IPA_UT_TEST_LOG_BUF_NAME[0] = '\0'; + _IPA_UT_TEST_FAIL_REPORT_DATA.valid = false; + pr_info("*** Test '%s': Running... ***\n", + suite->tests[i].name); + rc = suite->tests[i].run(suite->meta_data->priv); + if (rc) { + tst_fail = true; + suite->tests[i].res = IPA_UT_TEST_RES_FAIL; + pr_info("%s", _IPA_UT_TEST_LOG_BUF_NAME); + } else { + suite->tests[i].res = IPA_UT_TEST_RES_SUCCESS; + } + + pr_info(">>>>>>**** TEST '%s': %s ****<<<<<<\n", + suite->tests[i].name, tst_fail ? "FAIL" : "SUCCESS"); + + if (tst_fail && _IPA_UT_TEST_FAIL_REPORT_DATA.valid) { + pr_info("*** FAIL INFO:\n"); + pr_info("\tFILE = %s\n\tFUNC = %s()\n\tLINE = %d\n", + _IPA_UT_TEST_FAIL_REPORT_DATA.file, + _IPA_UT_TEST_FAIL_REPORT_DATA.func, + _IPA_UT_TEST_FAIL_REPORT_DATA.line); + pr_info("\t%s\n", _IPA_UT_TEST_FAIL_REPORT_DATA.info); + } + + pr_info("\n"); + } + + if (suite->meta_data->teardown) { + pr_info("*** Suite '%s': Run Teardown ***\n", + suite->meta_data->name); + rc = suite->meta_data->teardown(suite->meta_data->priv); + if (rc) { + IPA_UT_ERR("Teardown failed for suite %s\n", + suite->meta_data->name); + rc = -EFAULT; + goto release_clock; + } + } else { + pr_info("*** Suite '%s': No Teardown ***\n", + suite->meta_data->name); + } + + ipa_ut_show_suite_exec_summary(suite); + +release_clock: + IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IPA_UT"); +free_mem: + kfree(_IPA_UT_TEST_LOG_BUF_NAME); +unlock_mutex: + mutex_unlock(&ipa_ut_ctx->lock); + return ((!rc && !tst_fail) ? count : -EFAULT); +} + +/** + * ipa_ut_dbgfs_meta_test_read() - Debugfs read func for a meta test + * @params: read fops + * + * Meta test, is a test that describes other test or bunch of tests. + * for example, the 'all' test. Running this test will run all + * the tests in the suite. + * + * Show information regard the suite. E.g. name and description + * If regression - List the regression tests names + * + * Return: Amount of characters written to user space buffer + */ +static ssize_t ipa_ut_dbgfs_meta_test_read(struct file *file, + char __user *ubuf, size_t count, loff_t *ppos) +{ + char *buf; + struct ipa_ut_suite *suite; + int nbytes; + ssize_t cnt; + long meta_type; + int i; + + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + suite = file->f_inode->i_private; + ipa_assert_on(!suite); + meta_type = (long)(file->private_data); + IPA_UT_DBG("Meta test type %ld\n", meta_type); + + buf = kmalloc(IPA_UT_DEBUG_READ_BUF_SIZE, GFP_KERNEL); + if (!buf) { + IPA_UT_ERR("failed to allocate %d bytes\n", + IPA_UT_DEBUG_READ_BUF_SIZE); + cnt = 0; + goto unlock_mutex; + } + + if (meta_type == IPA_UT_META_TEST_ALL) { + nbytes = scnprintf(buf, IPA_UT_DEBUG_READ_BUF_SIZE, + "\tMeta-test running all the tests in the suite:\n" + "\tSuite Name: %s\n" + "\tDescription: %s\n" + "\tNumber of test in suite: %zu\n", + suite->meta_data->name, + suite->meta_data->desc ?: "", + suite->tests_cnt); + } else { + nbytes = scnprintf(buf, IPA_UT_DEBUG_READ_BUF_SIZE, + "\tMeta-test running regression tests in the suite:\n" + "\tSuite Name: %s\n" + "\tDescription: %s\n" + "\tRegression tests:\n", + suite->meta_data->name, + suite->meta_data->desc ?: ""); + for (i = 0 ; i < suite->tests_cnt ; i++) { + if (!suite->tests[i].run_in_regression) + continue; + nbytes += scnprintf(buf + nbytes, + IPA_UT_DEBUG_READ_BUF_SIZE - nbytes, + "\t\t%s\n", suite->tests[i].name); + } + } + + cnt = simple_read_from_buffer(ubuf, count, ppos, buf, nbytes); + kfree(buf); + +unlock_mutex: + mutex_unlock(&ipa_ut_ctx->lock); + return cnt; +} + +/** + * ipa_ut_dbgfs_regression_test_open() - Debugfs open function for + * 'regression' tests + * @params: open fops + * + * Mark "Regression tests" for meta-tests later operations. + * + * Return: Zero (always success). + */ +static int ipa_ut_dbgfs_regression_test_open(struct inode *inode, + struct file *filp) +{ + IPA_UT_DBG("Entry\n"); + + filp->private_data = (void *)(IPA_UT_META_TEST_REGRESSION); + + return 0; +} + +/** + * ipa_ut_dbgfs_all_test_open() - Debugfs open function for 'all' tests + * @params: open fops + * + * Mark "All tests" for meta-tests later operations. + * + * Return: Zero (always success). + */ +static int ipa_ut_dbgfs_all_test_open(struct inode *inode, + struct file *filp) +{ + IPA_UT_DBG("Entry\n"); + + filp->private_data = (void *)(IPA_UT_META_TEST_ALL); + + return 0; +} + +/** + * ipa_ut_dbgfs_test_write() - Debugfs write function for a test + * @params: write fops + * + * Used to run a test. + * Create log buffer that the test can use to store ongoing logs + * IPA clocks need to be voted. + * Run setup() before the test and teardown() after the tests. + * If no such call-backs then ignore it; if failed then fail the test + * If all succeeds, no printing to user + * If failed, test logs and failure report will be printed to user + * + * Note: Test must has run function and it's supported IPA H/W version + * must be matching. Otherwise test will fail. + * + * Return: Negative in failure, given characters amount in success + */ +static ssize_t ipa_ut_dbgfs_test_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct ipa_ut_test *test; + struct ipa_ut_suite *suite; + bool tst_fail = false; + int rc = 0; + enum ipa_hw_type ipa_ver; + + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + test = file->f_inode->i_private; + ipa_assert_on(!test); + + _IPA_UT_TEST_LOG_BUF_NAME = kzalloc(_IPA_UT_TEST_LOG_BUF_SIZE, + GFP_KERNEL); + if (!_IPA_UT_TEST_LOG_BUF_NAME) { + IPA_UT_ERR("failed to allocate %d bytes\n", + _IPA_UT_TEST_LOG_BUF_SIZE); + rc = -ENOMEM; + goto unlock_mutex; + } + + if (!test->run) { + IPA_UT_ERR("*** Test %s - No run func ***\n", + test->name); + rc = -EFAULT; + goto free_mem; + } + + ipa_ver = ipa_get_hw_type(); + if (test->min_ipa_hw_ver > ipa_ver || + test->max_ipa_hw_ver < ipa_ver) { + IPA_UT_ERR("Cannot run test %s on IPA HW Ver %s\n", + test->name, ipa_get_version_string(ipa_ver)); + rc = -EFAULT; + goto free_mem; + } + + IPA_ACTIVE_CLIENTS_INC_SPECIAL("IPA_UT"); + + suite = test->suite; + if (suite && suite->meta_data->setup) { + IPA_UT_DBG("*** Suite '%s': Run setup ***\n", + suite->meta_data->name); + rc = suite->meta_data->setup(&suite->meta_data->priv); + if (rc) { + IPA_UT_ERR("Setup failed for suite %s\n", + suite->meta_data->name); + rc = -EFAULT; + goto release_clock; + } + } else { + IPA_UT_DBG("*** Suite '%s': No Setup ***\n", + suite->meta_data->name); + } + + IPA_UT_DBG("*** Test '%s': Running... ***\n", test->name); + _IPA_UT_TEST_FAIL_REPORT_DATA.valid = false; + rc = test->run(suite->meta_data->priv); + if (rc) + tst_fail = true; + IPA_UT_DBG("*** Test %s - ***\n", tst_fail ? "FAIL" : "SUCCESS"); + if (tst_fail) { + pr_info("=================>>>>>>>>>>>\n"); + pr_info("%s\n", _IPA_UT_TEST_LOG_BUF_NAME); + pr_info("**** TEST %s FAILED ****\n", test->name); + if (_IPA_UT_TEST_FAIL_REPORT_DATA.valid) { + pr_info("*** FAIL INFO:\n"); + pr_info("\tFILE = %s\n\tFUNC = %s()\n\tLINE = %d\n", + _IPA_UT_TEST_FAIL_REPORT_DATA.file, + _IPA_UT_TEST_FAIL_REPORT_DATA.func, + _IPA_UT_TEST_FAIL_REPORT_DATA.line); + pr_info("\t%s\n", _IPA_UT_TEST_FAIL_REPORT_DATA.info); + } + pr_info("<<<<<<<<<<<=================\n"); + } + + if (suite && suite->meta_data->teardown) { + IPA_UT_DBG("*** Suite '%s': Run Teardown ***\n", + suite->meta_data->name); + rc = suite->meta_data->teardown(suite->meta_data->priv); + if (rc) { + IPA_UT_ERR("Teardown failed for suite %s\n", + suite->meta_data->name); + rc = -EFAULT; + goto release_clock; + } + } else { + IPA_UT_DBG("*** Suite '%s': No Teardown ***\n", + suite->meta_data->name); + } + +release_clock: + IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IPA_UT"); +free_mem: + kfree(_IPA_UT_TEST_LOG_BUF_NAME); +unlock_mutex: + mutex_unlock(&ipa_ut_ctx->lock); + return ((!rc && !tst_fail) ? count : -EFAULT); +} + +/** + * ipa_ut_dbgfs_test_read() - Debugfs read function for a test + * @params: read fops + * + * print information regard the test. E.g. name and description + * + * Return: Amount of characters written to user space buffer + */ +static ssize_t ipa_ut_dbgfs_test_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char *buf; + struct ipa_ut_test *test; + int nbytes; + ssize_t cnt; + + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + test = file->f_inode->i_private; + ipa_assert_on(!test); + + buf = kmalloc(IPA_UT_DEBUG_READ_BUF_SIZE, GFP_KERNEL); + if (!buf) { + IPA_UT_ERR("failed to allocate %d bytes\n", + IPA_UT_DEBUG_READ_BUF_SIZE); + cnt = 0; + goto unlock_mutex; + } + + nbytes = scnprintf(buf, IPA_UT_DEBUG_READ_BUF_SIZE, + "\t Test Name: %s\n" + "\t Description: %s\n" + "\t Suite Name: %s\n" + "\t Run In Regression: %s\n" + "\t Supported IPA versions: [%s -> %s]\n", + test->name, test->desc ?: "", test->suite->meta_data->name, + test->run_in_regression ? "Yes" : "No", + ipa_get_version_string(test->min_ipa_hw_ver), + test->max_ipa_hw_ver == IPA_HW_MAX ? "MAX" : + ipa_get_version_string(test->max_ipa_hw_ver)); + + if (nbytes > count) + IPA_UT_ERR("User buf too small - return partial info\n"); + + cnt = simple_read_from_buffer(ubuf, count, ppos, buf, nbytes); + kfree(buf); + +unlock_mutex: + mutex_unlock(&ipa_ut_ctx->lock); + return cnt; +} + +/** + * ipa_ut_framework_load_suites() - Load tests and expose them to user space + * + * Creates debugfs folder for each suite and then file for each test in it. + * Create debugfs "all" file for each suite for meta-test to run all tests. + * + * Note: Assumes lock acquired + * + * Return: Zero in success, otherwise in failure + */ +int ipa_ut_framework_load_suites(void) +{ + int suite_idx; + int tst_idx; + struct ipa_ut_suite *suite; + struct dentry *s_dent; + struct dentry *f_dent; + + IPA_UT_DBG("Entry\n"); + + for (suite_idx = IPA_UT_SUITE_FIRST_INDEX; + suite_idx < IPA_UT_SUITES_COUNT; suite_idx++) { + suite = IPA_UT_GET_SUITE(suite_idx); + + if (!suite->meta_data->name) { + IPA_UT_ERR("No suite name\n"); + return -EFAULT; + } + + s_dent = debugfs_create_dir(suite->meta_data->name, + ipa_ut_ctx->test_dbgfs_suites); + + if (!s_dent || IS_ERR(s_dent)) { + IPA_UT_ERR("fail create dbg entry - suite %s\n", + suite->meta_data->name); + return -EFAULT; + } + + for (tst_idx = 0; tst_idx < suite->tests_cnt ; tst_idx++) { + if (!suite->tests[tst_idx].name) { + IPA_UT_ERR("No test name on suite %s\n", + suite->meta_data->name); + return -EFAULT; + } + f_dent = debugfs_create_file( + suite->tests[tst_idx].name, + IPA_UT_READ_WRITE_DBG_FILE_MODE, s_dent, + &suite->tests[tst_idx], + &ipa_ut_dbgfs_test_fops); + if (!f_dent || IS_ERR(f_dent)) { + IPA_UT_ERR("fail create dbg entry - tst %s\n", + suite->tests[tst_idx].name); + return -EFAULT; + } + } + + /* entry for meta-test all to run all tests in suites */ + f_dent = debugfs_create_file(_IPA_UT_RUN_ALL_TEST_NAME, + IPA_UT_READ_WRITE_DBG_FILE_MODE, s_dent, + suite, &ipa_ut_dbgfs_all_test_fops); + if (!f_dent || IS_ERR(f_dent)) { + IPA_UT_ERR("fail to create dbg entry - %s\n", + _IPA_UT_RUN_ALL_TEST_NAME); + return -EFAULT; + } + + /* + * entry for meta-test regression to run all regression + * tests in suites + */ + f_dent = debugfs_create_file(_IPA_UT_RUN_REGRESSION_TEST_NAME, + IPA_UT_READ_WRITE_DBG_FILE_MODE, s_dent, + suite, &ipa_ut_dbgfs_regression_test_fops); + if (!f_dent || IS_ERR(f_dent)) { + IPA_UT_ERR("fail to create dbg entry - %s\n", + _IPA_UT_RUN_ALL_TEST_NAME); + return -EFAULT; + } + } + + return 0; +} + +/** + * ipa_ut_framework_enable() - Enable the framework + * + * Creates the tests and suites debugfs entries and load them. + * This will expose the tests to user space. + * + * Return: Zero in success, otherwise in failure + */ +static int ipa_ut_framework_enable(void) +{ + int ret = 0; + + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + + if (ipa_ut_ctx->enabled) { + IPA_UT_ERR("Already enabled\n"); + goto unlock_mutex; + } + + ipa_ut_ctx->test_dbgfs_suites = debugfs_create_dir("suites", + ipa_ut_ctx->test_dbgfs_root); + if (!ipa_ut_ctx->test_dbgfs_suites || + IS_ERR(ipa_ut_ctx->test_dbgfs_suites)) { + IPA_UT_ERR("failed to create suites debugfs dir\n"); + ret = -EFAULT; + goto unlock_mutex; + } + + if (ipa_ut_framework_load_suites()) { + IPA_UT_ERR("failed to load the suites into debugfs\n"); + ret = -EFAULT; + goto fail_clean_suites_dbgfs; + } + + ipa_ut_ctx->enabled = true; + goto unlock_mutex; + +fail_clean_suites_dbgfs: + debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_suites); +unlock_mutex: + mutex_unlock(&ipa_ut_ctx->lock); + return ret; +} + +/** + * ipa_ut_framework_disable() - Disable the framework + * + * Remove the tests and suites debugfs exposure. + * + * Return: Zero in success, otherwise in failure + */ +static int ipa_ut_framework_disable(void) +{ + int ret = 0; + + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + + if (!ipa_ut_ctx->enabled) { + IPA_UT_ERR("Already disabled\n"); + goto unlock_mutex; + } + + debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_suites); + + ipa_ut_ctx->enabled = false; + +unlock_mutex: + mutex_unlock(&ipa_ut_ctx->lock); + return ret; +} + +/** + * ipa_ut_dbgfs_enable_write() - Debugfs enable file write fops + * @params: write fops + * + * Input should be number. If 0, then disable. Otherwise enable. + * + * Return: if failed then negative value, if succeeds, amount of given chars + */ +static ssize_t ipa_ut_dbgfs_enable_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char lcl_buf[IPA_UT_DEBUG_WRITE_BUF_SIZE]; + s8 option = 0; + int ret; + + IPA_UT_DBG("Entry\n"); + + if (sizeof(lcl_buf) < count + 1) { + IPA_UT_ERR("No enough space\n"); + return -E2BIG; + } + + if (copy_from_user(lcl_buf, buf, count)) { + IPA_UT_ERR("fail to copy buf from user space\n"); + return -EFAULT; + } + + lcl_buf[count] = '\0'; + if (kstrtos8(lcl_buf, 0, &option)) { + IPA_UT_ERR("fail convert str to s8\n"); + return -EINVAL; + } + + if (option == 0) + ret = ipa_ut_framework_disable(); + else + ret = ipa_ut_framework_enable(); + + return ret ?: count; +} + +/** + * ipa_ut_dbgfs_enable_read() - Debugfs enable file read fops + * @params: read fops + * + * To show to user space if the I/S is enabled or disabled. + * + * Return: amount of characters returned to user space + */ +static ssize_t ipa_ut_dbgfs_enable_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + const char *status; + + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + status = ipa_ut_ctx->enabled ? + "Enabled - Write 0 to disable\n" : + "Disabled - Write 1 to enable\n"; + mutex_unlock(&ipa_ut_ctx->lock); + return simple_read_from_buffer(ubuf, count, ppos, + status, strlen(status)); +} + +/** + * ipa_ut_framework_init() - Unit-tests framework initialization + * + * Complete tests initialization: Each tests needs to point to it's + * corresponing suite. + * Creates the framework debugfs root directory under IPA directory. + * Create enable debugfs file - to enable/disable the framework. + * + * Return: Zero in success, otherwise in failure + */ +static int ipa_ut_framework_init(void) +{ + struct dentry *dfile_enable; + int ret; + int suite_idx; + int test_idx; + struct ipa_ut_suite *suite; + + IPA_UT_DBG("Entry\n"); + + ipa_assert_on(!ipa_ut_ctx); + + ipa_ut_ctx->ipa_dbgfs_root = ipa_debugfs_get_root(); + if (!ipa_ut_ctx->ipa_dbgfs_root) { + IPA_UT_ERR("No IPA debugfs root entry\n"); + return -EFAULT; + } + + mutex_lock(&ipa_ut_ctx->lock); + + /* tests needs to point to their corresponding suites structures */ + for (suite_idx = IPA_UT_SUITE_FIRST_INDEX; + suite_idx < IPA_UT_SUITES_COUNT; suite_idx++) { + suite = IPA_UT_GET_SUITE(suite_idx); + ipa_assert_on(!suite); + if (!suite->tests) { + IPA_UT_DBG("No tests for suite %s\n", + suite->meta_data->name); + continue; + } + for (test_idx = 0; test_idx < suite->tests_cnt; test_idx++) { + suite->tests[test_idx].suite = suite; + IPA_UT_DBG("Updating test %s info for suite %s\n", + suite->tests[test_idx].name, + suite->meta_data->name); + } + } + + ipa_ut_ctx->test_dbgfs_root = debugfs_create_dir("test", + ipa_ut_ctx->ipa_dbgfs_root); + if (!ipa_ut_ctx->test_dbgfs_root || + IS_ERR(ipa_ut_ctx->test_dbgfs_root)) { + IPA_UT_ERR("failed to create test debugfs dir\n"); + ret = -EFAULT; + goto unlock_mutex; + } + + dfile_enable = debugfs_create_file("enable", + IPA_UT_READ_WRITE_DBG_FILE_MODE, + ipa_ut_ctx->test_dbgfs_root, 0, &ipa_ut_dbgfs_enable_fops); + if (!dfile_enable || IS_ERR(dfile_enable)) { + IPA_UT_ERR("failed to create enable debugfs file\n"); + ret = -EFAULT; + goto fail_clean_dbgfs; + } + + ipa_ut_ctx->inited = true; + IPA_UT_DBG("Done\n"); + ret = 0; + goto unlock_mutex; + +fail_clean_dbgfs: + debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_root); +unlock_mutex: + mutex_unlock(&ipa_ut_ctx->lock); + return ret; +} + +/** + * ipa_ut_framework_destroy() - Destroy the UT framework info + * + * Disable it if enabled. + * Remove the debugfs entries using the root entry + */ +static void ipa_ut_framework_destroy(void) +{ + IPA_UT_DBG("Entry\n"); + + mutex_lock(&ipa_ut_ctx->lock); + if (ipa_ut_ctx->enabled) + ipa_ut_framework_disable(); + if (ipa_ut_ctx->inited) + debugfs_remove_recursive(ipa_ut_ctx->test_dbgfs_root); + mutex_unlock(&ipa_ut_ctx->lock); +} + +/** + * ipa_ut_ipa_ready_cb() - IPA ready CB + * + * Once IPA is ready starting initializing the unit-test framework + */ +static void ipa_ut_ipa_ready_cb(void *user_data) +{ + IPA_UT_DBG("Entry\n"); + (void)ipa_ut_framework_init(); +} + +/** + * ipa_ut_module_init() - Module init + * + * Create the framework context, wait for IPA driver readiness + * and Initialize it. + * If IPA driver already ready, continue initialization immediately. + * if not, wait for IPA ready notification by IPA driver context + */ +static int __init ipa_ut_module_init(void) +{ + int ret; + + IPA_UT_INFO("Loading IPA test module...\n"); + + ipa_ut_ctx = kzalloc(sizeof(struct ipa_ut_context), GFP_KERNEL); + if (!ipa_ut_ctx) { + IPA_UT_ERR("Failed to allocate ctx\n"); + return -ENOMEM; + } + mutex_init(&ipa_ut_ctx->lock); + + if (!ipa_is_ready()) { + IPA_UT_DBG("IPA driver not ready, registering callback\n"); + ret = ipa_register_ipa_ready_cb(ipa_ut_ipa_ready_cb, NULL); + + /* + * If we received -EEXIST, IPA has initialized. So we need + * to continue the initing process. + */ + if (ret != -EEXIST) { + if (ret) { + IPA_UT_ERR("IPA CB reg failed - %d\n", ret); + kfree(ipa_ut_ctx); + ipa_ut_ctx = NULL; + } + return ret; + } + } + + ret = ipa_ut_framework_init(); + if (ret) { + IPA_UT_ERR("framework init failed\n"); + kfree(ipa_ut_ctx); + ipa_ut_ctx = NULL; + } + return ret; +} + +/** + * ipa_ut_module_exit() - Module exit function + * + * Destroys the Framework and removes its context + */ +static void ipa_ut_module_exit(void) +{ + IPA_UT_DBG("Entry\n"); + + if (!ipa_ut_ctx) + return; + + ipa_ut_framework_destroy(); + kfree(ipa_ut_ctx); + ipa_ut_ctx = NULL; +} + +module_init(ipa_ut_module_init); +module_exit(ipa_ut_module_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("IPA Unit Test module"); diff --git a/drivers/platform/msm/ipa/test/ipa_ut_framework.h b/drivers/platform/msm/ipa/test/ipa_ut_framework.h new file mode 100644 index 000000000000..177be51bfe7d --- /dev/null +++ b/drivers/platform/msm/ipa/test/ipa_ut_framework.h @@ -0,0 +1,222 @@ +/* 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 _IPA_UT_FRAMEWORK_H_ +#define _IPA_UT_FRAMEWORK_H_ + +#include <linux/kernel.h> +#include "../ipa_common_i.h" +#include "ipa_ut_i.h" + +#define IPA_UT_DRV_NAME "ipa_ut" + +#define IPA_UT_DBG(fmt, args...) \ + do { \ + pr_debug(IPA_UT_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_UT_DBG_LOW(fmt, args...) \ + do { \ + pr_debug(IPA_UT_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_UT_ERR(fmt, args...) \ + do { \ + pr_err(IPA_UT_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_UT_INFO(fmt, args...) \ + do { \ + pr_info(IPA_UT_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + IPA_UT_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +/** + * struct ipa_ut_tst_fail_report - Information on test failure + * @valid: When a test posts a report, valid will be marked true + * @file: File name containing the failed test. + * @line: Number of line in the file where the test failed. + * @func: Function where the test failed in. + * @info: Information about the failure. + */ +struct ipa_ut_tst_fail_report { + bool valid; + const char *file; + int line; + const char *func; + const char *info; +}; + +/** + * Report on test failure + * To be used by tests. + */ +#define IPA_UT_TEST_FAIL_REPORT(__info) \ + do { \ + extern struct ipa_ut_tst_fail_report \ + _IPA_UT_TEST_FAIL_REPORT_DATA; \ + _IPA_UT_TEST_FAIL_REPORT_DATA.valid = true; \ + _IPA_UT_TEST_FAIL_REPORT_DATA.file = __FILENAME__; \ + _IPA_UT_TEST_FAIL_REPORT_DATA.line = __LINE__; \ + _IPA_UT_TEST_FAIL_REPORT_DATA.func = __func__; \ + if (__info) \ + _IPA_UT_TEST_FAIL_REPORT_DATA.info = __info; \ + else \ + _IPA_UT_TEST_FAIL_REPORT_DATA.info = ""; \ + } while (0) + +/** + * To be used by tests to log progress and ongoing information + * Logs are not printed to user, but saved to a buffer. + * I/S shall print the buffer at different occasions - e.g. in test failure + */ +#define IPA_UT_LOG(fmt, args...) \ + do { \ + extern char *_IPA_UT_TEST_LOG_BUF_NAME; \ + char __buf[512]; \ + IPA_UT_DBG(fmt, args); \ + scnprintf(__buf, sizeof(__buf), \ + fmt, args); \ + strlcat(_IPA_UT_TEST_LOG_BUF_NAME, __buf, sizeof(__buf)); \ + } while (0) + +/** + * struct ipa_ut_suite_meta - Suite meta-data + * @name: Suite unique name + * @desc: Suite description + * @setup: Setup Call-back of the suite + * @teardown: Teardown Call-back of the suite + * @priv: Private pointer of the suite + * + * Setup/Teardown will be called once for the suite when running a tests of it. + * priv field is shared between the Setup/Teardown and the tests + */ +struct ipa_ut_suite_meta { + char *name; + char *desc; + int (*setup)(void **ppriv); + int (*teardown)(void *priv); + void *priv; +}; + +/* Test suite data structure declaration */ +struct ipa_ut_suite; + +/** + * struct ipa_ut_test - Test information + * @name: Test name + * @desc: Test description + * @run: Test execution call-back + * @run_in_regression: To run this test as part of regression? + * @min_ipa_hw_ver: Minimum IPA H/W version where the test is supported? + * @max_ipa_hw_ver: Maximum IPA H/W version where the test is supported? + * @suite: Pointer to suite containing this test + * @res: Test execution result. Will be updated after running a test as part + * of suite tests run + */ +struct ipa_ut_test { + char *name; + char *desc; + int (*run)(void *priv); + bool run_in_regression; + int min_ipa_hw_ver; + int max_ipa_hw_ver; + struct ipa_ut_suite *suite; + enum ipa_ut_test_result res; +}; + +/** + * struct ipa_ut_suite - Suite information + * @meta_data: Pointer to meta-data structure of the suite + * @tests: Pointer to array of tests belongs to the suite + * @tests_cnt: Number of tests + */ +struct ipa_ut_suite { + struct ipa_ut_suite_meta *meta_data; + struct ipa_ut_test *tests; + size_t tests_cnt; +}; + + +/** + * Add a test to a suite. + * Will add entry to tests array and update its info with + * the given info, thus adding new test. + */ +#define IPA_UT_ADD_TEST(__name, __desc, __run, __run_in_regression, \ + __min_ipa_hw_ver, __max_ipa__hw_ver) \ + { \ + .name = #__name, \ + .desc = __desc, \ + .run = __run, \ + .run_in_regression = __run_in_regression, \ + .min_ipa_hw_ver = __min_ipa_hw_ver, \ + .max_ipa_hw_ver = __max_ipa__hw_ver, \ + .suite = NULL, \ + } + +/** + * Declare a suite + * Every suite need to be declared before it is registered. + */ +#define IPA_UT_DECLARE_SUITE(__name) \ + extern struct ipa_ut_suite _IPA_UT_SUITE_DATA(__name) + +/** + * Register a suite + * Registering a suite is mandatory so it will be considered. + */ +#define IPA_UT_REGISTER_SUITE(__name) \ + (&_IPA_UT_SUITE_DATA(__name)) + +/** + * Start/End suite definition + * Will create the suite global structures and adds adding tests to it. + * Use IPA_UT_ADD_TEST() with these macros to add tests when defining + * a suite + */ +#define IPA_UT_DEFINE_SUITE_START(__name, __desc, __setup, __teardown) \ + static struct ipa_ut_suite_meta _IPA_UT_SUITE_META_DATA(__name) = \ + { \ + .name = #__name, \ + .desc = __desc, \ + .setup = __setup, \ + .teardown = __teardown, \ + }; \ + static struct ipa_ut_test _IPA_UT_SUITE_TESTS(__name)[] = +#define IPA_UT_DEFINE_SUITE_END(__name) \ + ; \ + struct ipa_ut_suite _IPA_UT_SUITE_DATA(__name) = \ + { \ + .meta_data = &_IPA_UT_SUITE_META_DATA(__name), \ + .tests = _IPA_UT_SUITE_TESTS(__name), \ + .tests_cnt = ARRAY_SIZE(_IPA_UT_SUITE_TESTS(__name)), \ + } + +#endif /* _IPA_UT_FRAMEWORK_H_ */ diff --git a/drivers/platform/msm/ipa/test/ipa_ut_i.h b/drivers/platform/msm/ipa/test/ipa_ut_i.h new file mode 100644 index 000000000000..7cf5e53d0af1 --- /dev/null +++ b/drivers/platform/msm/ipa/test/ipa_ut_i.h @@ -0,0 +1,86 @@ +/* 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 _IPA_UT_I_H_ +#define _IPA_UT_I_H_ + +/* Suite data global structure name */ +#define _IPA_UT_SUITE_DATA(__name) ipa_ut_ ##__name ##_data + +/* Suite meta-data global structure name */ +#define _IPA_UT_SUITE_META_DATA(__name) ipa_ut_ ##__name ##_meta_data + +/* Suite global array of tests */ +#define _IPA_UT_SUITE_TESTS(__name) ipa_ut_ ##__name ##_tests + +/* Global array of all suites */ +#define _IPA_UT_ALL_SUITES ipa_ut_all_suites_data + +/* Meta-test "all" name - test to run all tests in given suite */ +#define _IPA_UT_RUN_ALL_TEST_NAME "all" + +/** + * Meta-test "regression" name - + * test to run all regression tests in given suite + */ +#define _IPA_UT_RUN_REGRESSION_TEST_NAME "regression" + + +/* Test Log buffer name and size */ +#define _IPA_UT_TEST_LOG_BUF_NAME ipa_ut_tst_log_buf +#define _IPA_UT_TEST_LOG_BUF_SIZE 2048 + +/* Global structure for test fail execution result information */ +#define _IPA_UT_TEST_FAIL_REPORT_DATA ipa_ut_tst_fail_report_data + +/* Start/End definitions of the array of suites */ +#define IPA_UT_DEFINE_ALL_SUITES_START \ + static struct ipa_ut_suite *_IPA_UT_ALL_SUITES[] = +#define IPA_UT_DEFINE_ALL_SUITES_END + +/** + * Suites iterator - Array-like container + * First index, number of elements and element fetcher + */ +#define IPA_UT_SUITE_FIRST_INDEX 0 +#define IPA_UT_SUITES_COUNT \ + ARRAY_SIZE(_IPA_UT_ALL_SUITES) +#define IPA_UT_GET_SUITE(__index) \ + _IPA_UT_ALL_SUITES[__index] + +/** + * enum ipa_ut_test_result - Test execution result + * @IPA_UT_TEST_RES_FAIL: Test executed and failed + * @IPA_UT_TEST_RES_SUCCESS: Test executed and succeeded + * @IPA_UT_TEST_RES_SKIP: Test was not executed. + * + * When running all tests in a suite, a specific test could + * be skipped and not executed. For example due to mismatch of + * IPA H/W version. + */ +enum ipa_ut_test_result { + IPA_UT_TEST_RES_FAIL, + IPA_UT_TEST_RES_SUCCESS, + IPA_UT_TEST_RES_SKIP, +}; + +/** + * enum ipa_ut_meta_test_type - Type of suite meta-test + * @IPA_UT_META_TEST_ALL: Represents all tests in suite + * @IPA_UT_META_TEST_REGRESSION: Represents all regression tests in suite + */ +enum ipa_ut_meta_test_type { + IPA_UT_META_TEST_ALL, + IPA_UT_META_TEST_REGRESSION, +}; + +#endif /* _IPA_UT_I_H_ */ diff --git a/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h new file mode 100644 index 000000000000..615ba671ebaa --- /dev/null +++ b/drivers/platform/msm/ipa/test/ipa_ut_suite_list.h @@ -0,0 +1,35 @@ +/* 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 _IPA_UT_SUITE_LIST_H_ +#define _IPA_UT_SUITE_LIST_H_ + +#include "ipa_ut_framework.h" +#include "ipa_ut_i.h" + +/** + * Declare every suite here so that it will be found later below + * No importance for order. + */ +IPA_UT_DECLARE_SUITE(example); + + +/** + * Register every suite inside the below block. + * Unregistered suites will be ignored + */ +IPA_UT_DEFINE_ALL_SUITES_START +{ + IPA_UT_REGISTER_SUITE(example), +} IPA_UT_DEFINE_ALL_SUITES_END; + +#endif /* _IPA_UT_SUITE_LIST_H_ */ diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index a45a5d103040..b1c3441b285a 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -225,9 +225,9 @@ static struct device_attribute power_supply_attrs[] = { /* Local extensions */ POWER_SUPPLY_ATTR(usb_hc), POWER_SUPPLY_ATTR(usb_otg), - POWER_SUPPLY_ATTR(charge_enabled), POWER_SUPPLY_ATTR(battery_charging_enabled), POWER_SUPPLY_ATTR(charging_enabled), + POWER_SUPPLY_ATTR(pin_enabled), POWER_SUPPLY_ATTR(input_suspend), POWER_SUPPLY_ATTR(input_voltage_regulation), POWER_SUPPLY_ATTR(input_current_max), diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h index cf7869ea1515..ef4ea8172035 100644 --- a/drivers/power/qcom-charger/fg-core.h +++ b/drivers/power/qcom-charger/fg-core.h @@ -40,7 +40,6 @@ #define SRAM_READ "fg_sram_read" #define SRAM_WRITE "fg_sram_write" -#define SRAM_UPDATE "fg_sram_update" #define PROFILE_LOAD "fg_profile_load" #define DELTA_SOC "fg_delta_soc" diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c index 2adc07ddc5a0..b350e53237b7 100644 --- a/drivers/power/qcom-charger/qpnp-fg-gen3.c +++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c @@ -413,13 +413,12 @@ static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id, if (id < 0 || id > FG_SRAM_MAX || chip->sp[id].len > sizeof(buf)) return -EINVAL; - vote(chip->awake_votable, SRAM_UPDATE, true, 0); rc = fg_sram_read(chip, chip->sp[id].address, chip->sp[id].offset, buf, chip->sp[id].len, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error reading address 0x%04x[%d] rc=%d\n", chip->sp[id].address, chip->sp[id].offset, rc); - goto out; + return rc; } for (i = 0, temp = 0; i < chip->sp[id].len; i++) @@ -427,9 +426,6 @@ static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id, *val = fg_decode(chip->sp, id, temp); return 0; -out: - vote(chip->awake_votable, SRAM_UPDATE, false, 0); - return rc; } #define BATT_TEMP_NUMR 1 diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 8fe882e078f0..18b02fbde5a6 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -349,13 +349,20 @@ static int smblib_detach_usb(struct smb_charger *chg) return rc; } -static int pl_notifier_call(struct notifier_block *nb, +static int smblib_notifier_call(struct notifier_block *nb, unsigned long ev, void *v) { struct power_supply *psy = v; - struct smb_charger *chg = container_of(nb, struct smb_charger, pl.nb); + struct smb_charger *chg = container_of(nb, struct smb_charger, nb); - if (strcmp(psy->desc->name, "parallel") == 0) { + if (!strcmp(psy->desc->name, "bms")) { + if (!chg->bms_psy) + chg->bms_psy = psy; + if (ev == PSY_EVENT_PROP_CHANGED && chg->batt_psy) + schedule_work(&chg->bms_update_work); + } + + if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) { chg->pl.psy = psy; schedule_work(&chg->pl_detect_work); } @@ -363,12 +370,12 @@ static int pl_notifier_call(struct notifier_block *nb, return NOTIFY_OK; } -static int register_pl_notifier(struct smb_charger *chg) +static int smblib_register_notifier(struct smb_charger *chg) { int rc; - chg->pl.nb.notifier_call = pl_notifier_call; - rc = power_supply_reg_notifier(&chg->pl.nb); + chg->nb.notifier_call = smblib_notifier_call; + rc = power_supply_reg_notifier(&chg->nb); if (rc < 0) { pr_err("Couldn't register psy notifier rc = %d\n", rc); return rc; @@ -740,8 +747,12 @@ int smblib_get_prop_batt_present(struct smb_charger *chg, int smblib_get_prop_batt_capacity(struct smb_charger *chg, union power_supply_propval *val) { - val->intval = 50; - return 0; + int rc = -EINVAL; + + if (chg->bms_psy) + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_CAPACITY, val); + return rc; } int smblib_get_prop_batt_status(struct smb_charger *chg, @@ -1677,9 +1688,12 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg, vote(chg->pl_disable_votable, TYPEC_SRC_VOTER, !rising || sink_attached, 0); - /* reset taper_end voter here */ - if (!rising || sink_attached) + if (!rising || sink_attached) { + /* icl votes to disable parallel charging */ + vote(chg->pl_disable_votable, USBIN_ICL_VOTER, true, 0); + /* reset taper_end voter here */ vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0); + } smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n", rising ? "rising" : "falling", @@ -1735,13 +1749,18 @@ static void smblib_hvdcp_detect_work(struct work_struct *work) } } +static void smblib_bms_update_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + bms_update_work); + power_supply_changed(chg->batt_psy); +} + static void smblib_pl_detect_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, pl_detect_work); - power_supply_unreg_notifier(&chg->pl.nb); - if (!get_effective_result_locked(chg->pl_disable_votable)) rerun_election(chg->pl_disable_votable); } @@ -1884,6 +1903,7 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->write_lock); + INIT_WORK(&chg->bms_update_work, smblib_bms_update_work); INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work); @@ -1898,14 +1918,12 @@ int smblib_init(struct smb_charger *chg) } chg->pl.psy = power_supply_get_by_name("parallel"); - if (!chg->pl.psy) { - rc = register_pl_notifier(chg); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't register notifier rc=%d\n", - rc); - return rc; - } + + rc = smblib_register_notifier(chg); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't register notifier rc=%d\n", rc); + return rc; } break; @@ -1932,5 +1950,7 @@ int smblib_deinit(struct smb_charger *chg) destroy_votable(chg->awake_votable); destroy_votable(chg->pl_disable_votable); + power_supply_unreg_notifier(&chg->nb); + return 0; } diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index 1521fdb3fccf..47839074b724 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -74,7 +74,6 @@ struct smb_params { }; struct parallel_params { - struct notifier_block nb; struct power_supply *psy; int *master_percent; int taper_percent; @@ -96,8 +95,12 @@ struct smb_charger { struct power_supply *batt_psy; struct power_supply *usb_psy; struct power_supply *dc_psy; + struct power_supply *bms_psy; struct power_supply_desc usb_psy_desc; + /* notifiers */ + struct notifier_block nb; + /* parallel charging */ struct parallel_params pl; @@ -120,6 +123,7 @@ struct smb_charger { struct votable *chg_disable_votable; /* work */ + struct work_struct bms_update_work; struct work_struct pl_detect_work; struct delayed_work hvdcp_detect_work; struct delayed_work ps_change_timeout_work; diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index 11d936762e3c..e9006cfc0b9e 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -357,6 +357,8 @@ static int smb138x_init_batt_psy(struct smb138x *chip) *****************************/ static enum power_supply_property smb138x_parallel_props[] = { + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_PIN_ENABLED, POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_CURRENT_MAX, @@ -368,8 +370,21 @@ static int smb138x_parallel_get_prop(struct power_supply *psy, { struct smb_charger *chg = power_supply_get_drvdata(psy); int rc = 0; + u8 temp; switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_5_REG, + &temp); + if (rc >= 0) + val->intval = (bool)(temp & CHARGING_ENABLE_BIT); + break; + case POWER_SUPPLY_PROP_PIN_ENABLED: + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_5_REG, + &temp); + if (rc >= 0) + val->intval = !(temp & DISABLE_CHARGING_BIT); + break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: rc = smblib_get_usb_suspend(chg, &val->intval); break; diff --git a/drivers/soc/qcom/core_hang_detect.c b/drivers/soc/qcom/core_hang_detect.c index 42f31e320b61..e9b7f612dccc 100644 --- a/drivers/soc/qcom/core_hang_detect.c +++ b/drivers/soc/qcom/core_hang_detect.c @@ -33,6 +33,7 @@ #define _WRITE(x, y, z) (((~(_VAL(z))) & y) | _VALUE(x, z)) #define MODULE_NAME "msm_hang_detect" +#define MAX_SYSFS_LEN 12 struct hang_detect { phys_addr_t threshold[NR_CPUS]; @@ -108,8 +109,7 @@ static ssize_t show_threshold(struct kobject *kobj, struct attribute *attr, { struct hang_detect *device = to_core_hang_dev(kobj); - return snprintf(buf, sizeof(device->threshold_val), - "%u\n", device->threshold_val); + return snprintf(buf, MAX_SYSFS_LEN, "0x%x\n", device->threshold_val); } static size_t store_threshold(struct kobject *kobj, struct attribute *attr, @@ -147,8 +147,8 @@ static ssize_t show_pmu_event_sel(struct kobject *kobj, struct attribute *attr, { struct hang_detect *hang_device = to_core_hang_dev(kobj); - return snprintf(buf, sizeof(hang_device->pmu_event_sel), - "%u\n", hang_device->pmu_event_sel); + return snprintf(buf, MAX_SYSFS_LEN, "0x%x\n", + hang_device->pmu_event_sel); } static size_t store_pmu_event_sel(struct kobject *kobj, struct attribute *attr, @@ -188,8 +188,7 @@ static ssize_t show_enable(struct kobject *kobj, struct attribute *attr, { struct hang_detect *hang_device = to_core_hang_dev(kobj); - return snprintf(buf, sizeof(hang_device->enabled), - "%u\n", hang_device->enabled); + return snprintf(buf, MAX_SYSFS_LEN, "%u\n", hang_device->enabled); } static size_t store_enable(struct kobject *kobj, struct attribute *attr, diff --git a/drivers/soc/qcom/gladiator_hang_detect.c b/drivers/soc/qcom/gladiator_hang_detect.c index fd8062ca523a..e2bbe26decc8 100644 --- a/drivers/soc/qcom/gladiator_hang_detect.c +++ b/drivers/soc/qcom/gladiator_hang_detect.c @@ -34,6 +34,7 @@ #define NR_GLA_REG 6 #define MODULE_NAME "gladiator_hang_detect" #define MAX_THRES 0xFFFFFFFF +#define MAX_LEN_SYSFS 12 struct hang_detect { phys_addr_t threshold[NR_GLA_REG]; @@ -199,8 +200,7 @@ static inline ssize_t generic_enable_show(struct kobject *kobj, uint32_t reg_value; get_enable(offset, hang_dev, ®_value); - return snprintf(buf, sizeof(hang_dev->ACE_enable), - "%d\n", reg_value); + return snprintf(buf, MAX_LEN_SYSFS, "%u\n", reg_value); } static inline ssize_t generic_threshold_show(struct kobject *kobj, @@ -210,9 +210,7 @@ static inline ssize_t generic_threshold_show(struct kobject *kobj, uint32_t reg_value; get_threshold(offset, hang_dev, ®_value); - return snprintf(buf, sizeof(hang_dev->ACE_threshold), - "%u\n", reg_value); - + return snprintf(buf, MAX_LEN_SYSFS, "0x%x\n", reg_value); } static inline size_t generic_threshold_store(struct kobject *kobj, diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c index 7e5f1661932f..dfd6b448a65f 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c +++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c @@ -316,14 +316,7 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl, open_cfg.notify_rx_intent_req = apr_tal_notify_rx_intent_req; open_cfg.notify_remote_rx_intent = apr_tal_notify_remote_rx_intent; open_cfg.priv = apr_ch; - /* - * The transport name "smd_trans" is required if far end is using SMD. - * In that case Glink will fall back to SMD and the client (APR in this - * case) will still work as if Glink is the communication channel. - * If far end is already using Glink, this property will be ignored in - * Glink layer and communication will be through Glink. - */ - open_cfg.transport = "smd_trans"; + open_cfg.transport = "smem"; apr_ch->channel_state = GLINK_REMOTE_DISCONNECTED; apr_ch->handle = glink_open(&open_cfg); @@ -420,13 +413,13 @@ static void apr_tal_link_state_cb(struct glink_link_state_cb_info *cb_info, } static struct glink_link_info mpss_link_info = { - .transport = NULL, + .transport = "smem", .edge = "mpss", .glink_link_state_notif_cb = apr_tal_link_state_cb, }; static struct glink_link_info lpass_link_info = { - .transport = NULL, + .transport = "smem", .edge = "lpass", .glink_link_state_notif_cb = apr_tal_link_state_cb, }; diff --git a/drivers/soc/qcom/qsee_ipc_irq_bridge.c b/drivers/soc/qcom/qsee_ipc_irq_bridge.c index d3a2212f07c4..ab43bbb7e86a 100644 --- a/drivers/soc/qcom/qsee_ipc_irq_bridge.c +++ b/drivers/soc/qcom/qsee_ipc_irq_bridge.c @@ -374,6 +374,9 @@ static int qiib_parse_node(struct device_node *node, struct qiib_dev *devp) } QIIB_DBG("%s: %s = %d\n", __func__, key, devp->irq_line); + irqtype = irqd_get_trigger_type(irq_get_irq_data(devp->irq_line)); + QIIB_DBG("%s: irqtype = %d\n", __func__, irqtype); + key = "label"; subsys_name = of_get_property(node, key, NULL); if (!subsys_name) { @@ -382,8 +385,8 @@ static int qiib_parse_node(struct device_node *node, struct qiib_dev *devp) } QIIB_DBG("%s: %s = %s\n", __func__, key, subsys_name); - if ((irqtype & IRQF_TRIGGER_HIGH) && !strcmp(devp->ssr_name, "mpss")) { - key = "qcom,irq-mask"; + if (irqtype & IRQF_TRIGGER_HIGH) { + key = "qcom,rx-irq-clr-mask"; ret = of_property_read_u32(node, key, &devp->irq_mask); if (ret) { QIIB_ERR("%s: missing key: %s\n", __func__, key); @@ -422,9 +425,6 @@ static int qiib_parse_node(struct device_node *node, struct qiib_dev *devp) goto ssr_reg_fail; } - irqtype = irqd_get_trigger_type(irq_get_irq_data(devp->irq_line)); - QIIB_DBG("%s: irqtype = %d\n", __func__, irqtype); - ret = request_irq(devp->irq_line, qiib_irq_handler, irqtype | IRQF_NO_SUSPEND, devp->dev_name, devp); diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 2bc425a437b2..9426e0751c4a 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -124,7 +124,7 @@ static void service_locator_svc_arrive(struct work_struct *work) qmi_handle_destroy(service_locator.clnt_handle); service_locator.clnt_handle = NULL; mutex_unlock(&service_locator.service_mutex); - pr_err("Unable to connnect to service\n"); + pr_err("Unable to connnect to service rc:%d\n", rc); return; } if (!service_inited) @@ -148,10 +148,12 @@ static void service_locator_recv_msg(struct work_struct *work) do { pr_debug("Notified about a Receive event\n"); - } while ((ret = qmi_recv_msg(service_locator.clnt_handle)) == 0); + ret = qmi_recv_msg(service_locator.clnt_handle); + if (ret != -ENOMSG) + pr_err("Error receiving message rc:%d. Retrying...\n", + ret); + } while (ret == 0); - if (ret != -ENOMSG) - pr_err("Error receiving message\n"); } static void store_get_domain_list_response(struct pd_qmi_client_data *pd, @@ -255,7 +257,7 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) rc = servreg_loc_send_msg(&req_desc, &resp_desc, req, resp, pd); if (rc < 0) { - pr_err("send msg failed! 0x%x\n", rc); + pr_err("send msg failed rc:%d\n", rc); goto out; } if (!domains_read) { @@ -325,7 +327,7 @@ static int init_service_locator(void) SERVREG_LOC_SERVICE_VERS_V01, SERVREG_LOC_SERVICE_INSTANCE_ID, &service_locator.notifier); if (rc < 0) { - pr_err("Notifier register failed!\n"); + pr_err("Notifier register failed rc:%d\n", rc); goto inited; } @@ -397,8 +399,8 @@ static void pd_locator_work(struct work_struct *work) } rc = service_locator_send_msg(data); if (rc) { - pr_err("Failed to get process domains for %s for client %s\n", - data->service_name, data->client_name); + pr_err("Failed to get process domains for %s for client %s rc:%d\n", + data->service_name, data->client_name, rc); pdqw->notifier->notifier_call(pdqw->notifier, LOCATOR_DOWN, NULL); goto err; diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c index 1ada600495df..81dde8ca1ae8 100644 --- a/drivers/soc/qcom/service-notifier.c +++ b/drivers/soc/qcom/service-notifier.c @@ -140,21 +140,11 @@ static int service_notif_queue_notification(struct service_notif_info enum qmi_servreg_notif_service_state_enum_type_v01 notif_type, void *info) { - int ret = 0; - - if (!service_notif) - return -EINVAL; - - if ((int) notif_type < QMI_STATE_MIN_VAL || - (int) notif_type > QMI_STATE_MAX_VAL) - return -EINVAL; + int ret; if (service_notif->curr_state == notif_type) return 0; - if (!service_notif->service_notif_rcvr_list.head) - return 0; - ret = srcu_notifier_call_chain(&service_notif->service_notif_rcvr_list, notif_type, info); return ret; @@ -244,8 +234,8 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, ind_desc.ei_array = qmi_servreg_notif_state_updated_ind_msg_v01_ei; rc = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len); if (rc < 0) { - pr_err("Failed to decode message!\n"); - goto send_ind_resp; + pr_err("Failed to decode message rc:%d\n", rc); + return; } pr_debug("Indication received from %s, state: 0x%x, trans-id: %d\n", @@ -263,15 +253,15 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, else { mutex_lock(¬if_add_lock); mutex_lock(&service_list_lock); - if (service_notif_queue_notification(service_notif, - ind_msg.curr_state, NULL)) - pr_err("Nnotification failed for %s\n", - ind_msg.service_name); + rc = service_notif_queue_notification(service_notif, + ind_msg.curr_state, NULL); + if (rc & NOTIFY_STOP_MASK) + pr_err("Notifier callback aborted for %s with error %d\n", + ind_msg.service_name, rc); service_notif->curr_state = ind_msg.curr_state; mutex_unlock(&service_list_lock); mutex_unlock(¬if_add_lock); } -send_ind_resp: data->ind_msg.transaction_id = ind_msg.transaction_id; snprintf(data->ind_msg.service_path, ARRAY_SIZE(data->ind_msg.service_path), "%s", @@ -320,7 +310,8 @@ static int send_notif_listener_msg_req(struct service_notif_info *service_notif, if ((int) resp.curr_state < QMI_STATE_MIN_VAL || (int) resp.curr_state > QMI_STATE_MAX_VAL) { - pr_err("Invalid notif info 0x%x\n", resp.curr_state); + pr_err("Invalid indication notification state %d\n", + resp.curr_state); rc = -EINVAL; } *curr_state = resp.curr_state; @@ -356,8 +347,8 @@ static void root_service_service_arrive(struct work_struct *work) SERVREG_NOTIF_SERVICE_ID, SERVREG_NOTIF_SERVICE_VERS, data->instance_id); if (rc < 0) { - pr_err("Could not connect handle to service(instance-id: %d)\n", - data->instance_id); + pr_err("Could not connect to service(instance-id: %d) rc:%d\n", + data->instance_id, rc); qmi_handle_destroy(data->clnt_handle); data->clnt_handle = NULL; return; @@ -369,8 +360,8 @@ static void root_service_service_arrive(struct work_struct *work) rc = qmi_register_ind_cb(data->clnt_handle, root_service_service_ind_cb, (void *)data); if (rc < 0) - pr_err("Indication callback register failed(instance-id: %d)\n", - data->instance_id); + pr_err("Indication callback register failed(instance-id: %d) rc:%d\n", + data->instance_id, rc); mutex_lock(¬if_add_lock); mutex_lock(&service_list_lock); @@ -379,15 +370,14 @@ static void root_service_service_arrive(struct work_struct *work) rc = register_notif_listener(service_notif, data, &curr_state); if (rc) { - pr_err("Notifier registration failed for %s\n", - service_notif->service_path); + pr_err("Notifier registration failed for %s rc:%d\n", + service_notif->service_path, rc); } else { rc = service_notif_queue_notification( - service_notif, - curr_state, NULL); - if (rc) - pr_err("Notifier failed for %s\n", - service_notif->service_path); + service_notif, curr_state, NULL); + if (rc & NOTIFY_STOP_MASK) + pr_err("Notifier callback aborted for %s error:%d\n", + service_notif->service_path, rc); service_notif->curr_state = curr_state; } } @@ -412,9 +402,9 @@ static void root_service_service_exit(struct qmi_client_info *data) rc = service_notif_queue_notification(service_notif, SERVREG_NOTIF_SERVICE_STATE_DOWN_V01, NULL); - if (rc) - pr_err("Notification failed for %s\n", - service_notif->service_path); + if (rc & NOTIFY_STOP_MASK) + pr_err("Notifier callback aborted for %s with error %d\n", + service_notif->service_path, rc); service_notif->curr_state = SERVREG_NOTIF_SERVICE_STATE_DOWN_V01; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 95191221bc3c..2c26ae1e3eb7 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1005,7 +1005,6 @@ struct dwc3 { /* IRQ timing statistics */ int irq; - struct tasklet_struct bh; unsigned long irq_cnt; unsigned bh_completion_time[MAX_INTR_STATS]; unsigned bh_handled_evt_cnt[MAX_INTR_STATS]; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 4d35de1c14c5..37a3c954a1dd 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -187,6 +187,7 @@ struct dwc3_msm { u32 bus_perf_client; struct msm_bus_scale_pdata *bus_scale_table; struct power_supply *usb_psy; + struct work_struct vbus_draw_work; bool in_host_mode; unsigned int tx_fifo_size; bool vbus_active; @@ -1595,6 +1596,15 @@ static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc) } +static void dwc3_msm_vbus_draw_work(struct work_struct *w) +{ + struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, + vbus_draw_work); + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + + dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw); +} + static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event) { struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); @@ -1680,7 +1690,7 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event) break; case DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT: dev_dbg(mdwc->dev, "DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT received\n"); - dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw); + schedule_work(&mdwc->vbus_draw_work); break; case DWC3_CONTROLLER_RESTART_USB_SESSION: dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESTART_USB_SESSION received\n"); @@ -1927,6 +1937,12 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) clk_disable_unprepare(mdwc->bus_aggr_clk); clk_disable_unprepare(mdwc->utmi_clk); + /* Memory core: OFF, Memory periphery: OFF */ + if (!mdwc->in_host_mode && !mdwc->vbus_active) { + clk_set_flags(mdwc->core_clk, CLKFLAG_NORETAIN_MEM); + clk_set_flags(mdwc->core_clk, CLKFLAG_NORETAIN_PERIPH); + } + clk_set_rate(mdwc->core_clk, 19200000); clk_disable_unprepare(mdwc->core_clk); /* @@ -2338,14 +2354,23 @@ static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc) return ret; } - /* - * Get Max supported clk frequency for USB Core CLK and request - * to set the same. - */ - mdwc->core_clk_rate = clk_round_rate(mdwc->core_clk, LONG_MAX); + if (!of_property_read_u32(mdwc->dev->of_node, "qcom,core-clk-rate", + (u32 *)&mdwc->core_clk_rate)) { + mdwc->core_clk_rate = clk_round_rate(mdwc->core_clk, + mdwc->core_clk_rate); + } else { + /* + * Get Max supported clk frequency for USB Core CLK and request + * to set the same. + */ + mdwc->core_clk_rate = clk_round_rate(mdwc->core_clk, LONG_MAX); + } + if (IS_ERR_VALUE(mdwc->core_clk_rate)) { dev_err(mdwc->dev, "fail to get core clk max freq.\n"); } else { + dev_dbg(mdwc->dev, "USB core frequency = %ld\n", + mdwc->core_clk_rate); ret = clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); if (ret) dev_err(mdwc->dev, "fail to set core_clk freq:%d\n", @@ -2582,6 +2607,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) INIT_WORK(&mdwc->resume_work, dwc3_resume_work); INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work); INIT_WORK(&mdwc->bus_vote_w, dwc3_msm_bus_vote_w); + INIT_WORK(&mdwc->vbus_draw_work, dwc3_msm_vbus_draw_work); INIT_DELAYED_WORK(&mdwc->sm_work, dwc3_otg_sm_work); mdwc->dwc3_wq = alloc_ordered_workqueue("dwc3_wq", 0); @@ -3165,7 +3191,8 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) { - union power_supply_propval pval = {0,}; + union power_supply_propval pval = {1000 * mA}; + int ret; if (mdwc->charging_disabled) return 0; @@ -3183,42 +3210,16 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned mA) dev_info(mdwc->dev, "Avail curr from USB = %u\n", mA); - if (mdwc->max_power <= 2 && mA > 2) { - /* Enable Charging */ - pval.intval = true; - if (power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_ONLINE, &pval)) - goto psy_error; - pval.intval = 1000 * mA; - if (power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &pval)) - goto psy_error; - } else if (mdwc->max_power > 0 && (mA == 0 || mA == 2)) { - /* Disable charging */ - pval.intval = false; - if (power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_ONLINE, &pval)) - goto psy_error; - } else { - /* Enable charging */ - pval.intval = true; - if (power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_ONLINE, &pval)) - goto psy_error; - } - /* Set max current limit in uA */ - pval.intval = 1000 * mA; - if (power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &pval)) - goto psy_error; + ret = power_supply_set_property(mdwc->usb_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); + if (ret) { + dev_dbg(mdwc->dev, "power supply error when setting property\n"); + return ret; + } mdwc->max_power = mA; return 0; - -psy_error: - dev_dbg(mdwc->dev, "power supply error when setting property\n"); - return -ENXIO; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7d97aeb21340..acaa99615d33 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2141,8 +2141,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g) atomic_read(&dwc->dev->power.usage_count)); dwc3_gadget_disable_irq(dwc); - tasklet_kill(&dwc->bh); - spin_lock_irqsave(&dwc->lock, flags); __dwc3_gadget_ep_disable(dwc->eps[0]); @@ -3380,15 +3378,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) return ret; } -static void dwc3_interrupt_bh(unsigned long param) -{ - struct dwc3 *dwc = (struct dwc3 *) param; - - pm_runtime_get(dwc->dev); - dwc3_thread_interrupt(dwc->irq, dwc); - enable_irq(dwc->irq); -} - static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) { struct dwc3 *dwc = _dwc; @@ -3412,7 +3401,6 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) dwc->bh_completion_time[dwc->bh_dbg_index] = temp_time; dwc->bh_dbg_index = (dwc->bh_dbg_index + 1) % 10; - pm_runtime_put(dwc->dev); return ret; } @@ -3478,10 +3466,8 @@ irqreturn_t dwc3_interrupt(int irq, void *_dwc) dwc->irq_event_count[dwc->irq_dbg_index] = temp_cnt / 4; dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS; - if (ret == IRQ_WAKE_THREAD) { - disable_irq_nosync(irq); - tasklet_schedule(&dwc->bh); - } + if (ret == IRQ_WAKE_THREAD) + dwc3_thread_interrupt(dwc->irq, dwc); return IRQ_HANDLED; } @@ -3529,9 +3515,6 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err3; } - dwc->bh.func = dwc3_interrupt_bh; - dwc->bh.data = (unsigned long)dwc; - dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index b22ea656367e..78c1ce793b5b 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -516,7 +516,6 @@ static void usb_cser_disable(struct usb_function *f) usb_cser_disconnect(port); usb_ep_disable(port->port_usb.notify); - usb_cser_free_req(port->port_usb.notify, port->port_usb.notify_req); port->port_usb.notify->driver_data = NULL; } @@ -817,7 +816,11 @@ static void cser_free_inst(struct usb_function_instance *fi) static void usb_cser_unbind(struct usb_configuration *c, struct usb_function *f) { + struct f_cdev *port = func_to_port(f); + usb_free_all_descriptors(f); + usb_cser_free_req(port->port_usb.notify, port->port_usb.notify_req); + port->port_usb.notify_req = NULL; } static int usb_cser_alloc_requests(struct usb_ep *ep, struct list_head *head, diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index f29c275c490b..7bc6b5340dd7 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -849,10 +849,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) POWER_SUPPLY_PROP_VOLTAGE_MAX, &val); pd->current_voltage = pd->requested_voltage; - val.intval = pd->requested_current * 1000; /* mA->uA */ - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &val); - /* recursive call; go back to beginning state */ usbpd_set_state(pd, PE_SNK_STARTUP); break; @@ -1615,7 +1611,12 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PD_ACTIVE, &val); pd->requested_voltage = 5000000; - pd->requested_current = max_sink_current; + + if (pd->requested_current) { + val.intval = pd->requested_current = 0; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, &val); + } val.intval = pd->requested_voltage; power_supply_set_property(pd->usb_psy, diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index b601cafba6fd..61e99f47f02f 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -460,6 +460,7 @@ struct mdss_data_type { struct ion_client *iclient; int iommu_attached; + u32 dbg_bus_flags; struct debug_bus *dbg_bus; u32 dbg_bus_size; struct vbif_debug_bus *vbif_dbg_bus; diff --git a/drivers/video/fbdev/msm/mdss_debug.h b/drivers/video/fbdev/msm/mdss_debug.h index 35ae81e4709e..59ba4f3e5578 100644 --- a/drivers/video/fbdev/msm/mdss_debug.h +++ b/drivers/video/fbdev/msm/mdss_debug.h @@ -31,6 +31,8 @@ #define XLOG_FUNC_EXIT 0x2222 #define MDSS_REG_BLOCK_NAME_LEN (5) +#define DEBUG_FLAGS_DSPP BIT(0) + enum mdss_dbg_reg_dump_flag { MDSS_DBG_DUMP_IN_LOG = BIT(0), MDSS_DBG_DUMP_IN_MEM = BIT(1), diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c index a34bce1200d8..32bfb151eddd 100644 --- a/drivers/video/fbdev/msm/mdss_debug_xlog.c +++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c @@ -234,6 +234,7 @@ static void mdss_dump_debug_bus(u32 bus_dump_flag, phys_addr_t phys = 0; int list_size = mdata->dbg_bus_size; int i; + u32 offset; if (!(mdata->dbg_bus && list_size)) return; @@ -267,8 +268,14 @@ static void mdss_dump_debug_bus(u32 bus_dump_flag, writel_relaxed(TEST_MASK(head->block_id, head->test_id), mdss_res->mdp_base + head->wr_addr); wmb(); /* make sure test bits were written */ + + if (mdata->dbg_bus_flags & DEBUG_FLAGS_DSPP) + offset = MDSS_MDP_DSPP_DEBUGBUS_STATUS; + else + offset = head->wr_addr + 0x4; + status = readl_relaxed(mdss_res->mdp_base + - head->wr_addr + 0x4); + offset); if (in_log) pr_err("waddr=0x%x blk=%d tst=%d val=0x%x\n", diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 3785a701e3c1..78dc17536416 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -459,6 +459,9 @@ void mdss_dsi_host_init(struct mdss_panel_data *pdata) /* enable contention detection for receiving */ mdss_dsi_lp_cd_rx(ctrl_pdata); + /* set DMA FIFO read watermark to 15/16 full */ + MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x50, 0x30); + wmb(); } diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index da60570c7085..921391dc4bde 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -56,7 +56,8 @@ #define C0_G_Y 0 /* G/luma */ /* wait for at most 2 vsync for lowest refresh rate (24hz) */ -#define KOFF_TIMEOUT msecs_to_jiffies(84) +#define KOFF_TIMEOUT_MS 84 +#define KOFF_TIMEOUT msecs_to_jiffies(KOFF_TIMEOUT_MS) #define OVERFETCH_DISABLE_TOP BIT(0) #define OVERFETCH_DISABLE_BOTTOM BIT(1) diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index f19161ad25c4..9e3c2b7cdd1b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -937,6 +937,785 @@ static struct debug_bus dbg_bus_8996[] = { { 0x418, 60, 0}, }; + +static struct debug_bus dbg_bus_msmcobalt[] = { + + /* + * sspp0 - 0x188 + * sspp1 - 0x298 + * dspp - 0x348 + * periph - 0x418 + */ + + /* Unpack 0 sspp 0*/ + { 0x188, 50, 2 }, + { 0x188, 60, 2 }, + { 0x188, 70, 2 }, + { 0x188, 85, 2 }, + /* Upack 0 sspp 1*/ + { 0x298, 50, 2 }, + { 0x298, 60, 2 }, + { 0x298, 70, 2 }, + { 0x298, 85, 2 }, + /* scheduler */ + { 0x348, 130, 0 }, + { 0x348, 130, 1 }, + { 0x348, 130, 2 }, + { 0x348, 130, 3 }, + { 0x348, 130, 4 }, + { 0x348, 130, 5 }, + + /* qseed */ + {0x188, 6, 0}, + {0x188, 6, 1}, + {0x188, 26, 0}, + {0x188, 26, 1}, + {0x298, 6, 0}, + {0x298, 6, 1}, + {0x298, 26, 0}, + {0x298, 26, 1}, + + /* scale */ + {0x188, 16, 0}, + {0x188, 16, 1}, + {0x188, 36, 0}, + {0x188, 36, 1}, + {0x298, 16, 0}, + {0x298, 16, 1}, + {0x298, 36, 0}, + {0x298, 36, 1}, + + /* fetch sspp0 */ + + /* vig 0 */ + { 0x188, 0, 0 }, + { 0x188, 0, 1 }, + { 0x188, 0, 2 }, + { 0x188, 0, 3 }, + { 0x188, 0, 4 }, + { 0x188, 0, 5 }, + { 0x188, 0, 6 }, + { 0x188, 0, 7 }, + + { 0x188, 1, 0 }, + { 0x188, 1, 1 }, + { 0x188, 1, 2 }, + { 0x188, 1, 3 }, + { 0x188, 1, 4 }, + { 0x188, 1, 5 }, + { 0x188, 1, 6 }, + { 0x188, 1, 7 }, + + { 0x188, 2, 0 }, + { 0x188, 2, 1 }, + { 0x188, 2, 2 }, + { 0x188, 2, 3 }, + { 0x188, 2, 4 }, + { 0x188, 2, 5 }, + { 0x188, 2, 6 }, + { 0x188, 2, 7 }, + + { 0x188, 4, 0 }, + { 0x188, 4, 1 }, + { 0x188, 4, 2 }, + { 0x188, 4, 3 }, + { 0x188, 4, 4 }, + { 0x188, 4, 5 }, + { 0x188, 4, 6 }, + { 0x188, 4, 7 }, + + { 0x188, 5, 0 }, + { 0x188, 5, 1 }, + { 0x188, 5, 2 }, + { 0x188, 5, 3 }, + { 0x188, 5, 4 }, + { 0x188, 5, 5 }, + { 0x188, 5, 6 }, + { 0x188, 5, 7 }, + + /* vig 2 */ + { 0x188, 20, 0 }, + { 0x188, 20, 1 }, + { 0x188, 20, 2 }, + { 0x188, 20, 3 }, + { 0x188, 20, 4 }, + { 0x188, 20, 5 }, + { 0x188, 20, 6 }, + { 0x188, 20, 7 }, + + { 0x188, 21, 0 }, + { 0x188, 21, 1 }, + { 0x188, 21, 2 }, + { 0x188, 21, 3 }, + { 0x188, 21, 4 }, + { 0x188, 21, 5 }, + { 0x188, 21, 6 }, + { 0x188, 21, 7 }, + + { 0x188, 22, 0 }, + { 0x188, 22, 1 }, + { 0x188, 22, 2 }, + { 0x188, 22, 3 }, + { 0x188, 22, 4 }, + { 0x188, 22, 5 }, + { 0x188, 22, 6 }, + { 0x188, 22, 7 }, + + { 0x188, 24, 0 }, + { 0x188, 24, 1 }, + { 0x188, 24, 2 }, + { 0x188, 24, 3 }, + { 0x188, 24, 4 }, + { 0x188, 24, 5 }, + { 0x188, 24, 6 }, + { 0x188, 24, 7 }, + + { 0x188, 25, 0 }, + { 0x188, 25, 1 }, + { 0x188, 25, 2 }, + { 0x188, 25, 3 }, + { 0x188, 25, 4 }, + { 0x188, 25, 5 }, + { 0x188, 25, 6 }, + { 0x188, 25, 7 }, + + /* dma 2 */ + { 0x188, 30, 0 }, + { 0x188, 30, 1 }, + { 0x188, 30, 2 }, + { 0x188, 30, 3 }, + { 0x188, 30, 4 }, + { 0x188, 30, 5 }, + { 0x188, 30, 6 }, + { 0x188, 30, 7 }, + + { 0x188, 31, 0 }, + { 0x188, 31, 1 }, + { 0x188, 31, 2 }, + { 0x188, 31, 3 }, + { 0x188, 31, 4 }, + { 0x188, 31, 5 }, + { 0x188, 31, 6 }, + { 0x188, 31, 7 }, + + { 0x188, 32, 0 }, + { 0x188, 32, 1 }, + { 0x188, 32, 2 }, + { 0x188, 32, 3 }, + { 0x188, 32, 4 }, + { 0x188, 32, 5 }, + { 0x188, 32, 6 }, + { 0x188, 32, 7 }, + + { 0x188, 33, 0 }, + { 0x188, 33, 1 }, + { 0x188, 33, 2 }, + { 0x188, 33, 3 }, + { 0x188, 33, 4 }, + { 0x188, 33, 5 }, + { 0x188, 33, 6 }, + { 0x188, 33, 7 }, + + { 0x188, 34, 0 }, + { 0x188, 34, 1 }, + { 0x188, 34, 2 }, + { 0x188, 34, 3 }, + { 0x188, 34, 4 }, + { 0x188, 34, 5 }, + { 0x188, 34, 6 }, + { 0x188, 34, 7 }, + + { 0x188, 35, 0 }, + { 0x188, 35, 1 }, + { 0x188, 35, 2 }, + { 0x188, 35, 3 }, + + /* dma 0 */ + { 0x188, 40, 0 }, + { 0x188, 40, 1 }, + { 0x188, 40, 2 }, + { 0x188, 40, 3 }, + { 0x188, 40, 4 }, + { 0x188, 40, 5 }, + { 0x188, 40, 6 }, + { 0x188, 40, 7 }, + + { 0x188, 41, 0 }, + { 0x188, 41, 1 }, + { 0x188, 41, 2 }, + { 0x188, 41, 3 }, + { 0x188, 41, 4 }, + { 0x188, 41, 5 }, + { 0x188, 41, 6 }, + { 0x188, 41, 7 }, + + { 0x188, 42, 0 }, + { 0x188, 42, 1 }, + { 0x188, 42, 2 }, + { 0x188, 42, 3 }, + { 0x188, 42, 4 }, + { 0x188, 42, 5 }, + { 0x188, 42, 6 }, + { 0x188, 42, 7 }, + + { 0x188, 44, 0 }, + { 0x188, 44, 1 }, + { 0x188, 44, 2 }, + { 0x188, 44, 3 }, + { 0x188, 44, 4 }, + { 0x188, 44, 5 }, + { 0x188, 44, 6 }, + { 0x188, 44, 7 }, + + { 0x188, 45, 0 }, + { 0x188, 45, 1 }, + { 0x188, 45, 2 }, + { 0x188, 45, 3 }, + { 0x188, 45, 4 }, + { 0x188, 45, 5 }, + { 0x188, 45, 6 }, + { 0x188, 45, 7 }, + + /* fetch sspp1 */ + /* vig 1 */ + { 0x298, 0, 0 }, + { 0x298, 0, 1 }, + { 0x298, 0, 2 }, + { 0x298, 0, 3 }, + { 0x298, 0, 4 }, + { 0x298, 0, 5 }, + { 0x298, 0, 6 }, + { 0x298, 0, 7 }, + + { 0x298, 1, 0 }, + { 0x298, 1, 1 }, + { 0x298, 1, 2 }, + { 0x298, 1, 3 }, + { 0x298, 1, 4 }, + { 0x298, 1, 5 }, + { 0x298, 1, 6 }, + { 0x298, 1, 7 }, + + { 0x298, 2, 0 }, + { 0x298, 2, 1 }, + { 0x298, 2, 2 }, + { 0x298, 2, 3 }, + { 0x298, 2, 4 }, + { 0x298, 2, 5 }, + { 0x298, 2, 6 }, + { 0x298, 2, 7 }, + + { 0x298, 4, 0 }, + { 0x298, 4, 1 }, + { 0x298, 4, 2 }, + { 0x298, 4, 3 }, + { 0x298, 4, 4 }, + { 0x298, 4, 5 }, + { 0x298, 4, 6 }, + { 0x298, 4, 7 }, + + { 0x298, 5, 0 }, + { 0x298, 5, 1 }, + { 0x298, 5, 2 }, + { 0x298, 5, 3 }, + { 0x298, 5, 4 }, + { 0x298, 5, 5 }, + { 0x298, 5, 6 }, + { 0x298, 5, 7 }, + + /* vig 3 */ + { 0x298, 20, 0 }, + { 0x298, 20, 1 }, + { 0x298, 20, 2 }, + { 0x298, 20, 3 }, + { 0x298, 20, 4 }, + { 0x298, 20, 5 }, + { 0x298, 20, 6 }, + { 0x298, 20, 7 }, + + { 0x298, 21, 0 }, + { 0x298, 21, 1 }, + { 0x298, 21, 2 }, + { 0x298, 21, 3 }, + { 0x298, 21, 4 }, + { 0x298, 21, 5 }, + { 0x298, 21, 6 }, + { 0x298, 21, 7 }, + + { 0x298, 22, 0 }, + { 0x298, 22, 1 }, + { 0x298, 22, 2 }, + { 0x298, 22, 3 }, + { 0x298, 22, 4 }, + { 0x298, 22, 5 }, + { 0x298, 22, 6 }, + { 0x298, 22, 7 }, + + { 0x298, 24, 0 }, + { 0x298, 24, 1 }, + { 0x298, 24, 2 }, + { 0x298, 24, 3 }, + { 0x298, 24, 4 }, + { 0x298, 24, 5 }, + { 0x298, 24, 6 }, + { 0x298, 24, 7 }, + + { 0x298, 25, 0 }, + { 0x298, 25, 1 }, + { 0x298, 25, 2 }, + { 0x298, 25, 3 }, + { 0x298, 25, 4 }, + { 0x298, 25, 5 }, + { 0x298, 25, 6 }, + { 0x298, 25, 7 }, + + /* dma 3 */ + { 0x298, 30, 0 }, + { 0x298, 30, 1 }, + { 0x298, 30, 2 }, + { 0x298, 30, 3 }, + { 0x298, 30, 4 }, + { 0x298, 30, 5 }, + { 0x298, 30, 6 }, + { 0x298, 30, 7 }, + + { 0x298, 31, 0 }, + { 0x298, 31, 1 }, + { 0x298, 31, 2 }, + { 0x298, 31, 3 }, + { 0x298, 31, 4 }, + { 0x298, 31, 5 }, + { 0x298, 31, 6 }, + { 0x298, 31, 7 }, + + { 0x298, 32, 0 }, + { 0x298, 32, 1 }, + { 0x298, 32, 2 }, + { 0x298, 32, 3 }, + { 0x298, 32, 4 }, + { 0x298, 32, 5 }, + { 0x298, 32, 6 }, + { 0x298, 32, 7 }, + + { 0x298, 33, 0 }, + { 0x298, 33, 1 }, + { 0x298, 33, 2 }, + { 0x298, 33, 3 }, + { 0x298, 33, 4 }, + { 0x298, 33, 5 }, + { 0x298, 33, 6 }, + { 0x298, 33, 7 }, + + { 0x298, 34, 0 }, + { 0x298, 34, 1 }, + { 0x298, 34, 2 }, + { 0x298, 34, 3 }, + { 0x298, 34, 4 }, + { 0x298, 34, 5 }, + { 0x298, 34, 6 }, + { 0x298, 34, 7 }, + + { 0x298, 35, 0 }, + { 0x298, 35, 1 }, + { 0x298, 35, 2 }, + + /* dma 1 */ + { 0x298, 40, 0 }, + { 0x298, 40, 1 }, + { 0x298, 40, 2 }, + { 0x298, 40, 3 }, + { 0x298, 40, 4 }, + { 0x298, 40, 5 }, + { 0x298, 40, 6 }, + { 0x298, 40, 7 }, + + { 0x298, 41, 0 }, + { 0x298, 41, 1 }, + { 0x298, 41, 2 }, + { 0x298, 41, 3 }, + { 0x298, 41, 4 }, + { 0x298, 41, 5 }, + { 0x298, 41, 6 }, + { 0x298, 41, 7 }, + + { 0x298, 42, 0 }, + { 0x298, 42, 1 }, + { 0x298, 42, 2 }, + { 0x298, 42, 3 }, + { 0x298, 42, 4 }, + { 0x298, 42, 5 }, + { 0x298, 42, 6 }, + { 0x298, 42, 7 }, + + { 0x298, 44, 0 }, + { 0x298, 44, 1 }, + { 0x298, 44, 2 }, + { 0x298, 44, 3 }, + { 0x298, 44, 4 }, + { 0x298, 44, 5 }, + { 0x298, 44, 6 }, + { 0x298, 44, 7 }, + + { 0x298, 45, 0 }, + { 0x298, 45, 1 }, + { 0x298, 45, 2 }, + { 0x298, 45, 3 }, + { 0x298, 45, 4 }, + { 0x298, 45, 5 }, + { 0x298, 45, 6 }, + { 0x298, 45, 7 }, + + /* cursor 1 */ + { 0x298, 80, 0 }, + { 0x298, 80, 1 }, + { 0x298, 80, 2 }, + { 0x298, 80, 3 }, + { 0x298, 80, 4 }, + { 0x298, 80, 5 }, + { 0x298, 80, 6 }, + { 0x298, 80, 7 }, + + { 0x298, 81, 0 }, + { 0x298, 81, 1 }, + { 0x298, 81, 2 }, + { 0x298, 81, 3 }, + { 0x298, 81, 4 }, + { 0x298, 81, 5 }, + { 0x298, 81, 6 }, + { 0x298, 81, 7 }, + + { 0x298, 82, 0 }, + { 0x298, 82, 1 }, + { 0x298, 82, 2 }, + { 0x298, 82, 3 }, + { 0x298, 82, 4 }, + { 0x298, 82, 5 }, + { 0x298, 82, 6 }, + { 0x298, 82, 7 }, + + { 0x298, 83, 0 }, + { 0x298, 83, 1 }, + { 0x298, 83, 2 }, + { 0x298, 83, 3 }, + { 0x298, 83, 4 }, + { 0x298, 83, 5 }, + { 0x298, 83, 6 }, + { 0x298, 83, 7 }, + + { 0x298, 84, 0 }, + { 0x298, 84, 1 }, + { 0x298, 84, 2 }, + { 0x298, 84, 3 }, + { 0x298, 84, 4 }, + { 0x298, 84, 5 }, + { 0x298, 84, 6 }, + { 0x298, 84, 7 }, + + /* dspp */ + { 0x348, 13, 0 }, + { 0x348, 19, 0 }, + { 0x348, 14, 0 }, + { 0x348, 14, 1 }, + { 0x348, 14, 3 }, + { 0x348, 20, 0 }, + { 0x348, 20, 1 }, + { 0x348, 20, 3 }, + + /* ppb_0 */ + { 0x348, 31, 0 }, + { 0x348, 33, 0 }, + { 0x348, 35, 0 }, + { 0x348, 42, 0 }, + + /* ppb_1 */ + { 0x348, 32, 0 }, + { 0x348, 34, 0 }, + { 0x348, 36, 0 }, + { 0x348, 43, 0 }, + + /* lm_lut */ + { 0x348, 109, 0 }, + { 0x348, 105, 0 }, + { 0x348, 103, 0 }, + + /* tear-check */ + { 0x418, 63, 0 }, + { 0x418, 64, 0 }, + { 0x418, 65, 0 }, + { 0x418, 73, 0 }, + { 0x418, 74, 0 }, + + /* crossbar */ + { 0x348, 0, 0}, + + /* rotator */ + { 0x348, 9, 0}, + + /* blend */ + /* LM0 */ + { 0x348, 63, 0}, + { 0x348, 63, 1}, + { 0x348, 63, 2}, + { 0x348, 63, 3}, + { 0x348, 63, 4}, + { 0x348, 63, 5}, + { 0x348, 63, 6}, + { 0x348, 63, 7}, + + { 0x348, 64, 0}, + { 0x348, 64, 1}, + { 0x348, 64, 2}, + { 0x348, 64, 3}, + { 0x348, 64, 4}, + { 0x348, 64, 5}, + { 0x348, 64, 6}, + { 0x348, 64, 7}, + + { 0x348, 65, 0}, + { 0x348, 65, 1}, + { 0x348, 65, 2}, + { 0x348, 65, 3}, + { 0x348, 65, 4}, + { 0x348, 65, 5}, + { 0x348, 65, 6}, + { 0x348, 65, 7}, + + { 0x348, 66, 0}, + { 0x348, 66, 1}, + { 0x348, 66, 2}, + { 0x348, 66, 3}, + { 0x348, 66, 4}, + { 0x348, 66, 5}, + { 0x348, 66, 6}, + { 0x348, 66, 7}, + + { 0x348, 67, 0}, + { 0x348, 67, 1}, + { 0x348, 67, 2}, + { 0x348, 67, 3}, + { 0x348, 67, 4}, + { 0x348, 67, 5}, + { 0x348, 67, 6}, + { 0x348, 67, 7}, + + { 0x348, 68, 0}, + { 0x348, 68, 1}, + { 0x348, 68, 2}, + { 0x348, 68, 3}, + { 0x348, 68, 4}, + { 0x348, 68, 5}, + { 0x348, 68, 6}, + { 0x348, 68, 7}, + + { 0x348, 69, 0}, + { 0x348, 69, 1}, + { 0x348, 69, 2}, + { 0x348, 69, 3}, + { 0x348, 69, 4}, + { 0x348, 69, 5}, + { 0x348, 69, 6}, + { 0x348, 69, 7}, + + /* LM1 */ + { 0x348, 70, 0}, + { 0x348, 70, 1}, + { 0x348, 70, 2}, + { 0x348, 70, 3}, + { 0x348, 70, 4}, + { 0x348, 70, 5}, + { 0x348, 70, 6}, + { 0x348, 70, 7}, + + { 0x348, 71, 0}, + { 0x348, 71, 1}, + { 0x348, 71, 2}, + { 0x348, 71, 3}, + { 0x348, 71, 4}, + { 0x348, 71, 5}, + { 0x348, 71, 6}, + { 0x348, 71, 7}, + + { 0x348, 72, 0}, + { 0x348, 72, 1}, + { 0x348, 72, 2}, + { 0x348, 72, 3}, + { 0x348, 72, 4}, + { 0x348, 72, 5}, + { 0x348, 72, 6}, + { 0x348, 72, 7}, + + { 0x348, 73, 0}, + { 0x348, 73, 1}, + { 0x348, 73, 2}, + { 0x348, 73, 3}, + { 0x348, 73, 4}, + { 0x348, 73, 5}, + { 0x348, 73, 6}, + { 0x348, 73, 7}, + + { 0x348, 74, 0}, + { 0x348, 74, 1}, + { 0x348, 74, 2}, + { 0x348, 74, 3}, + { 0x348, 74, 4}, + { 0x348, 74, 5}, + { 0x348, 74, 6}, + { 0x348, 74, 7}, + + { 0x348, 75, 0}, + { 0x348, 75, 1}, + { 0x348, 75, 2}, + { 0x348, 75, 3}, + { 0x348, 75, 4}, + { 0x348, 75, 5}, + { 0x348, 75, 6}, + { 0x348, 75, 7}, + + { 0x348, 76, 0}, + { 0x348, 76, 1}, + { 0x348, 76, 2}, + { 0x348, 76, 3}, + { 0x348, 76, 4}, + { 0x348, 76, 5}, + { 0x348, 76, 6}, + { 0x348, 76, 7}, + + /* LM2 */ + { 0x348, 77, 0}, + { 0x348, 77, 1}, + { 0x348, 77, 2}, + { 0x348, 77, 3}, + { 0x348, 77, 4}, + { 0x348, 77, 5}, + { 0x348, 77, 6}, + { 0x348, 77, 7}, + + { 0x348, 78, 0}, + { 0x348, 78, 1}, + { 0x348, 78, 2}, + { 0x348, 78, 3}, + { 0x348, 78, 4}, + { 0x348, 78, 5}, + { 0x348, 78, 6}, + { 0x348, 78, 7}, + + { 0x348, 79, 0}, + { 0x348, 79, 1}, + { 0x348, 79, 2}, + { 0x348, 79, 3}, + { 0x348, 79, 4}, + { 0x348, 79, 5}, + { 0x348, 79, 6}, + { 0x348, 79, 7}, + + { 0x348, 80, 0}, + { 0x348, 80, 1}, + { 0x348, 80, 2}, + { 0x348, 80, 3}, + { 0x348, 80, 4}, + { 0x348, 80, 5}, + { 0x348, 80, 6}, + { 0x348, 80, 7}, + + { 0x348, 81, 0}, + { 0x348, 81, 1}, + { 0x348, 81, 2}, + { 0x348, 81, 3}, + { 0x348, 81, 4}, + { 0x348, 81, 5}, + { 0x348, 81, 6}, + { 0x348, 81, 7}, + + { 0x348, 82, 0}, + { 0x348, 82, 1}, + { 0x348, 82, 2}, + { 0x348, 82, 3}, + { 0x348, 82, 4}, + { 0x348, 82, 5}, + { 0x348, 82, 6}, + { 0x348, 82, 7}, + + { 0x348, 83, 0}, + { 0x348, 83, 1}, + { 0x348, 83, 2}, + { 0x348, 83, 3}, + { 0x348, 83, 4}, + { 0x348, 83, 5}, + { 0x348, 83, 6}, + { 0x348, 83, 7}, + + /* csc */ + {0x188, 7, 0}, + {0x188, 7, 1}, + {0x188, 27, 0}, + {0x188, 27, 1}, + {0x298, 7, 0}, + {0x298, 7, 1}, + {0x298, 27, 0}, + {0x298, 27, 1}, + + /* pcc */ + { 0x188, 3, 3}, + { 0x188, 23, 3}, + { 0x188, 33, 3}, + { 0x188, 43, 3}, + { 0x298, 3, 3}, + { 0x298, 23, 3}, + { 0x298, 33, 3}, + { 0x298, 43, 3}, + + /* spa */ + { 0x188, 8, 0}, + { 0x188, 28, 0}, + { 0x298, 8, 0}, + { 0x298, 28, 0}, + { 0x348, 13, 0}, + { 0x348, 19, 0}, + + /* igc */ + { 0x188, 9, 0}, + { 0x188, 9, 1}, + { 0x188, 9, 3}, + { 0x188, 29, 0}, + { 0x188, 29, 1}, + { 0x188, 29, 3}, + { 0x188, 17, 0}, + { 0x188, 17, 1}, + { 0x188, 17, 3}, + { 0x188, 37, 0}, + { 0x188, 37, 1}, + { 0x188, 37, 3}, + { 0x188, 46, 0}, + { 0x188, 46, 1}, + { 0x188, 46, 3}, + + { 0x298, 9, 0}, + { 0x298, 9, 1}, + { 0x298, 9, 3}, + { 0x298, 29, 0}, + { 0x298, 29, 1}, + { 0x298, 29, 3}, + { 0x298, 17, 0}, + { 0x298, 17, 1}, + { 0x298, 17, 3}, + { 0x298, 37, 0}, + { 0x298, 37, 1}, + { 0x298, 37, 3}, + { 0x298, 46, 0}, + { 0x298, 46, 1}, + { 0x298, 46, 3}, + + { 0x348, 14, 0}, + { 0x348, 14, 1}, + { 0x348, 14, 3}, + { 0x348, 20, 0}, + { 0x348, 20, 1}, + { 0x348, 20, 3}, + + { 0x418, 60, 0}, +}; + + static struct vbif_debug_bus vbif_dbg_bus_8996[] = { {0x214, 0x21c, 16, 2, 0x10}, /* arb clients */ {0x214, 0x21c, 0, 14, 0x13}, /* xin blocks - axi side */ @@ -953,6 +1732,7 @@ void mdss_mdp_hw_rev_debug_caps_init(struct mdss_data_type *mdata) { mdata->dbg_bus = NULL; mdata->dbg_bus_size = 0; + mdata->dbg_bus_flags = 0; switch (mdata->mdp_rev) { case MDSS_MDP_HW_REV_107: @@ -966,6 +1746,17 @@ void mdss_mdp_hw_rev_debug_caps_init(struct mdss_data_type *mdata) mdata->nrt_vbif_dbg_bus_size = ARRAY_SIZE(nrt_vbif_dbg_bus_8996); break; + case MDSS_MDP_HW_REV_300: + case MDSS_MDP_HW_REV_301: + mdata->dbg_bus = dbg_bus_msmcobalt; + mdata->dbg_bus_size = ARRAY_SIZE(dbg_bus_msmcobalt); + mdata->vbif_dbg_bus = vbif_dbg_bus_8996; + mdata->vbif_dbg_bus_size = ARRAY_SIZE(vbif_dbg_bus_8996); + mdata->nrt_vbif_dbg_bus = nrt_vbif_dbg_bus_8996; + mdata->nrt_vbif_dbg_bus_size = + ARRAY_SIZE(nrt_vbif_dbg_bus_8996); + mdata->dbg_bus_flags = DEBUG_FLAGS_DSPP; + break; default: break; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h index de868bcd8f6f..f54cbb575535 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h +++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h @@ -819,6 +819,8 @@ enum mdss_mdp_pingpong_index { #define MDSS_MDP_REG_CDM_HDMI_PACK_OP_MODE 0x200 +#define MDSS_MDP_DSPP_DEBUGBUS_STATUS 0x34C + /* Following offsets are with respect to MDP base */ #define MDSS_MDP_MDP_OUT_CTL_0 0x410 #define MDSS_MDP_INTF_CMD_MISR_CTRL (MDSS_MDP_INTF_MISR_CTRL + 0x8) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index a1e5982bccda..0779f7e7afae 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1835,6 +1835,26 @@ int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, return ret; } +static int __mdss_mdp_wait4pingpong(struct mdss_mdp_cmd_ctx *ctx) +{ + int rc = 0; + s64 expected_time = ktime_to_ms(ktime_get()) + KOFF_TIMEOUT_MS; + s64 time; + + do { + rc = wait_event_timeout(ctx->pp_waitq, + atomic_read(&ctx->koff_cnt) == 0, + KOFF_TIMEOUT); + time = ktime_to_ms(ktime_get()); + + MDSS_XLOG(rc, time, expected_time, atomic_read(&ctx->koff_cnt)); + /* If we timed out, counter is valid and time is less, wait again */ + } while (atomic_read(&ctx->koff_cnt) && (rc == 0) && + (time < expected_time)); + + return rc; +} + static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg) { struct mdss_mdp_cmd_ctx *ctx; @@ -1856,9 +1876,7 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg) pr_debug("%s: intf_num=%d ctx=%p koff_cnt=%d\n", __func__, ctl->intf_num, ctx, atomic_read(&ctx->koff_cnt)); - rc = wait_event_timeout(ctx->pp_waitq, - atomic_read(&ctx->koff_cnt) == 0, - KOFF_TIMEOUT); + rc = __mdss_mdp_wait4pingpong(ctx); trace_mdp_cmd_wait_pingpong(ctl->num, atomic_read(&ctx->koff_cnt)); @@ -2526,6 +2544,11 @@ static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl, /* disable autorefresh */ mdss_mdp_pingpong_write(pp_base, MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0); + + if (is_pingpong_split(ctl->mfd)) + mdss_mdp_pingpong_write(mdata->slave_pingpong_base, + MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0); + ctx->autorefresh_state = MDP_AUTOREFRESH_OFF; ctx->autorefresh_frame_cnt = 0; @@ -2543,6 +2566,9 @@ static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl, static void __mdss_mdp_kickoff(struct mdss_mdp_ctl *ctl, struct mdss_mdp_cmd_ctx *ctx) { + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + bool is_pp_split = is_pingpong_split(ctl->mfd); + MDSS_XLOG(ctx->autorefresh_state); if ((ctx->autorefresh_state == MDP_AUTOREFRESH_ON_REQUESTED) || @@ -2555,8 +2581,14 @@ static void __mdss_mdp_kickoff(struct mdss_mdp_ctl *ctl, mdss_mdp_pingpong_write(ctl->mixer_left->pingpong_base, MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, BIT(31) | ctx->autorefresh_frame_cnt); + + if (is_pp_split) + mdss_mdp_pingpong_write(mdata->slave_pingpong_base, + MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, + BIT(31) | ctx->autorefresh_frame_cnt); + MDSS_XLOG(0x11, ctx->autorefresh_frame_cnt, - ctx->autorefresh_state); + ctx->autorefresh_state, is_pp_split); ctx->autorefresh_state = MDP_AUTOREFRESH_ON; } else { diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 35bd0932f321..3a39d4fdc895 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -1062,7 +1062,6 @@ static struct sync_fence *__create_fence(struct msm_fb_data_type *mfd, goto end; } - sync_fence_install(sync_fence, *fence_fd); end: return sync_fence; } @@ -1136,6 +1135,9 @@ static int __handle_buffer_fences(struct msm_fb_data_type *mfd, goto retire_fence_err; } + sync_fence_install(release_fence, commit->release_fence); + sync_fence_install(retire_fence, commit->retire_fence); + mutex_unlock(&sync_pt_data->sync_mutex); return ret; diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c index 9906f10a7911..9a00eff9ade9 100644 --- a/drivers/video/fbdev/msm/mdss_smmu.c +++ b/drivers/video/fbdev/msm/mdss_smmu.c @@ -172,6 +172,7 @@ static int mdss_smmu_attach_v2(struct mdss_data_type *mdata) struct mdss_smmu_client *mdss_smmu; int i, rc = 0; + mutex_lock(&mdp_iommu_lock); for (i = 0; i < MDSS_IOMMU_MAX_DOMAIN; i++) { if (!mdss_smmu_is_valid_domain_type(mdata, i)) continue; @@ -203,9 +204,12 @@ static int mdss_smmu_attach_v2(struct mdss_data_type *mdata) } } else { pr_err("iommu device not attached for domain[%d]\n", i); + mutex_unlock(&mdp_iommu_lock); return -ENODEV; } } + mutex_unlock(&mdp_iommu_lock); + return 0; err: @@ -217,6 +221,8 @@ err: mdss_smmu->domain_attached = false; } } + mutex_unlock(&mdp_iommu_lock); + return rc; } @@ -231,6 +237,7 @@ static int mdss_smmu_detach_v2(struct mdss_data_type *mdata) struct mdss_smmu_client *mdss_smmu; int i; + mutex_lock(&mdp_iommu_lock); for (i = 0; i < MDSS_IOMMU_MAX_DOMAIN; i++) { if (!mdss_smmu_is_valid_domain_type(mdata, i)) continue; @@ -239,6 +246,8 @@ static int mdss_smmu_detach_v2(struct mdss_data_type *mdata) if (mdss_smmu && mdss_smmu->dev && !mdss_smmu->handoff_pending) mdss_smmu_enable_power(mdss_smmu, false); } + mutex_unlock(&mdp_iommu_lock); + return 0; } diff --git a/include/dt-bindings/clock/msm-clocks-8996.h b/include/dt-bindings/clock/msm-clocks-8996.h index 2f9cfd0e008c..22109a6766db 100644 --- a/include/dt-bindings/clock/msm-clocks-8996.h +++ b/include/dt-bindings/clock/msm-clocks-8996.h @@ -540,4 +540,33 @@ #define clk_sys_apcsaux_clk 0x0b0dd513 #define clk_cpu_debug_mux 0xc7acaa31 +/* GCC block resets */ +#define QUSB2PHY_PRIM_BCR 0 +#define QUSB2PHY_SEC_BCR 1 +#define BLSP1_BCR 2 +#define BLSP2_BCR 3 +#define BOOT_ROM_BCR 4 +#define PRNG_BCR 5 +#define UFS_BCR 6 +#define USB_20_BCR 7 +#define USB_30_BCR 8 +#define USB3_PHY_BCR 9 +#define USB3PHY_PHY_BCR 10 +#define PCIE_0_PHY_BCR 11 +#define PCIE_1_PHY_BCR 12 +#define PCIE_2_PHY_BCR 13 +#define PCIE_PHY_BCR 14 +#define PCIE_PHY_COM_BCR 15 +#define PCIE_PHY_NOCSR_COM_PHY_BCR 16 + +/* MMSS Block resets */ +#define VIDEO_BCR 0 +#define MDSS_BCR 1 +#define CAMSS_MICRO_BCR 2 +#define CAMSS_JPEG_BCR 3 +#define CAMSS_VFE0_BCR 4 +#define CAMSS_VFE1_BCR 5 +#define FD_BCR 6 +#define GPU_GX_BCR 7 + #endif diff --git a/include/dt-bindings/clock/qcom,gcc-msmfalcon.h b/include/dt-bindings/clock/qcom,gcc-msmfalcon.h index d0a8419ee54c..6860d78e020e 100644 --- a/include/dt-bindings/clock/qcom,gcc-msmfalcon.h +++ b/include/dt-bindings/clock/qcom,gcc-msmfalcon.h @@ -14,230 +14,229 @@ #ifndef _DT_BINDINGS_CLK_MSM_GCC_FALCON_H #define _DT_BINDINGS_CLK_MSM_GCC_FALCON_H -/* Clocks */ -#define GPLL0 0 -#define GPLL1 1 -#define GPLL2 2 -#define GPLL3 3 -#define GPLL4 4 -#define GPLL5 5 -#define GPLL6 6 -#define MMSS_QM_CORE_CLK_SRC 7 -#define USB30_MASTER_CLK_SRC 8 -#define USB30_MOCK_UTMI_CLK_SRC 9 -#define USB3_PHY_AUX_CLK_SRC 10 -#define USB20_MASTER_CLK_SRC 11 -#define USB20_MOCK_UTMI_CLK_SRC 12 -#define SDCC2_APPS_CLK_SRC 13 -#define SDCC1_ICE_CORE_CLK_SRC 14 -#define SDCC1_APPS_CLK_SRC 15 -#define BLSP1_QUP1_SPI_APPS_CLK_SRC 16 -#define BLSP1_QUP1_I2C_APPS_CLK_SRC 17 -#define BLSP1_UART1_APPS_CLK_SRC 18 -#define BLSP1_QUP2_SPI_APPS_CLK_SRC 19 -#define BLSP1_QUP2_I2C_APPS_CLK_SRC 20 -#define BLSP1_UART2_APPS_CLK_SRC 21 -#define BLSP1_QUP3_SPI_APPS_CLK_SRC 22 -#define BLSP1_QUP3_I2C_APPS_CLK_SRC 23 -#define BLSP1_QUP4_SPI_APPS_CLK_SRC 24 -#define BLSP1_QUP4_I2C_APPS_CLK_SRC 25 -#define BLSP2_QUP1_SPI_APPS_CLK_SRC 26 -#define BLSP2_QUP1_I2C_APPS_CLK_SRC 27 -#define BLSP2_UART1_APPS_CLK_SRC 28 -#define BLSP2_QUP2_SPI_APPS_CLK_SRC 29 -#define BLSP2_QUP2_I2C_APPS_CLK_SRC 30 -#define BLSP2_UART2_APPS_CLK_SRC 31 -#define BLSP2_QUP3_SPI_APPS_CLK_SRC 32 -#define BLSP2_QUP3_I2C_APPS_CLK_SRC 33 -#define BLSP2_QUP4_SPI_APPS_CLK_SRC 34 -#define BLSP2_QUP4_I2C_APPS_CLK_SRC 35 -#define PDM2_CLK_SRC 36 -#define HMSS_AHB_CLK_SRC 37 -#define BIMC_HMSS_AXI_CLK_SRC 38 -#define HMSS_RBCPR_CLK_SRC 39 -#define HMSS_GPLL0_CLK_SRC 40 -#define HMSS_GPLL4_CLK_SRC 41 -#define GP1_CLK_SRC 42 -#define GP2_CLK_SRC 43 -#define GP3_CLK_SRC 44 -#define UFS_AXI_CLK_SRC 45 -#define UFS_ICE_CORE_CLK_SRC 46 -#define UFS_UNIPRO_CORE_CLK_SRC 47 -#define UFS_PHY_AUX_CLK_SRC 48 -#define QSPI_SER_CLK_SRC 49 -#define GLM_CLK_SRC 50 -#define GCC_MMSS_SYS_NOC_AXI_CLK 51 -#define GCC_MMSS_NOC_CFG_AHB_CLK 52 -#define GCC_MMSS_QM_CORE_CLK 53 -#define GCC_MMSS_QM_AHB_CLK 54 -#define GCC_USB30_MASTER_CLK 55 -#define GCC_USB30_SLEEP_CLK 56 -#define GCC_USB30_MOCK_UTMI_CLK 57 -#define GCC_USB3_PHY_AUX_CLK 58 -#define GCC_USB3_PHY_PIPE_CLK 59 -#define GCC_USB20_MASTER_CLK 60 -#define GCC_USB20_SLEEP_CLK 61 -#define GCC_USB20_MOCK_UTMI_CLK 62 -#define GCC_USB_PHY_CFG_AHB2PHY_CLK 63 -#define GCC_SDCC2_APPS_CLK 64 -#define GCC_SDCC2_AHB_CLK 65 -#define GCC_SDCC1_APPS_CLK 66 -#define GCC_SDCC1_AHB_CLK 67 -#define GCC_SDCC1_ICE_CORE_CLK 68 -#define GCC_BLSP1_AHB_CLK 69 -#define GCC_BLSP1_SLEEP_CLK 70 -#define GCC_BLSP1_QUP1_SPI_APPS_CLK 71 -#define GCC_BLSP1_QUP1_I2C_APPS_CLK 72 -#define GCC_BLSP1_UART1_APPS_CLK 73 -#define GCC_BLSP1_QUP2_SPI_APPS_CLK 74 -#define GCC_BLSP1_QUP2_I2C_APPS_CLK 75 -#define GCC_BLSP1_UART2_APPS_CLK 76 -#define GCC_BLSP1_QUP3_SPI_APPS_CLK 77 -#define GCC_BLSP1_QUP3_I2C_APPS_CLK 78 -#define GCC_BLSP1_QUP4_SPI_APPS_CLK 79 -#define GCC_BLSP1_QUP4_I2C_APPS_CLK 80 -#define GCC_BLSP2_AHB_CLK 81 -#define GCC_BLSP2_SLEEP_CLK 82 -#define GCC_BLSP2_QUP1_SPI_APPS_CLK 83 -#define GCC_BLSP2_QUP1_I2C_APPS_CLK 84 -#define GCC_BLSP2_UART1_APPS_CLK 85 -#define GCC_BLSP2_QUP2_SPI_APPS_CLK 86 -#define GCC_BLSP2_QUP2_I2C_APPS_CLK 87 -#define GCC_BLSP2_UART2_APPS_CLK 88 -#define GCC_BLSP2_QUP3_SPI_APPS_CLK 89 -#define GCC_BLSP2_QUP3_I2C_APPS_CLK 90 -#define GCC_BLSP2_QUP4_SPI_APPS_CLK 91 -#define GCC_BLSP2_QUP4_I2C_APPS_CLK 92 -#define GCC_PDM_AHB_CLK 93 -#define GCC_PDM_XO4_CLK 94 -#define GCC_PDM2_CLK 95 -#define GCC_PRNG_AHB_CLK 96 -#define GCC_BIMC_GFX_CLK 97 -#define GCC_MCCC_CFG_AHB_CLK 98 -#define GCC_LPASS_TRIG_CLK 99 -#define GCC_LPASS_AT_CLK 100 -#define GCC_TURING_TRIG_CLK 101 -#define GCC_TURING_AT_CLK 102 -#define GCC_HMSS_AHB_CLK 103 -#define GCC_BIMC_HMSS_AXI_CLK 104 -#define GCC_HMSS_RBCPR_CLK 105 -#define GCC_HMSS_TRIG_CLK 106 -#define GCC_HMSS_AT_CLK 107 -#define GCC_HMSS_DVM_BUS_CLK 108 -#define GCC_GP1_CLK 109 -#define GCC_GP2_CLK 110 -#define GCC_GP3_CLK 111 -#define GCC_UFS_AXI_CLK 112 -#define GCC_UFS_AHB_CLK 113 -#define GCC_UFS_TX_SYMBOL_0_CLK 114 -#define GCC_UFS_RX_SYMBOL_0_CLK 115 -#define GCC_UFS_UNIPRO_CORE_CLK 116 -#define GCC_UFS_ICE_CORE_CLK 117 -#define GCC_UFS_PHY_AUX_CLK 118 -#define GCC_UFS_RX_SYMBOL_1_CLK 119 -#define GCC_AGGRE2_USB3_AXI_CLK 120 -#define GCC_AGGRE2_UFS_AXI_CLK 121 -#define GCC_QSPI_AHB_CLK 122 -#define GCC_QSPI_SER_CLK 123 -#define GCC_GLM_AHB_CLK 124 -#define GCC_GLM_CLK 125 -#define GCC_GLM_XO_CLK 126 -#define GCC_WCSS_AHB_S0_CLK 127 -#define GCC_WCSS_AXI_M_CLK 128 -#define GCC_WCSS_ECAHB_CLK 129 -#define GCC_WCSS_SHDREG_AHB_CLK 130 -#define GCC_GPU_CFG_AHB_CLK 131 -#define GCC_GPU_BIMC_GFX_SRC_CLK 132 -#define GCC_GPU_BIMC_GFX_CLK 133 -#define GCC_GPU_SNOC_DVM_GFX_CLK 134 +#define BIMC_HMSS_AXI_CLK_SRC 0 +#define BLSP1_QUP1_I2C_APPS_CLK_SRC 1 +#define BLSP1_QUP1_SPI_APPS_CLK_SRC 2 +#define BLSP1_QUP2_I2C_APPS_CLK_SRC 3 +#define BLSP1_QUP2_SPI_APPS_CLK_SRC 4 +#define BLSP1_QUP3_I2C_APPS_CLK_SRC 5 +#define BLSP1_QUP3_SPI_APPS_CLK_SRC 6 +#define BLSP1_QUP4_I2C_APPS_CLK_SRC 7 +#define BLSP1_QUP4_SPI_APPS_CLK_SRC 8 +#define BLSP1_UART1_APPS_CLK_SRC 9 +#define BLSP1_UART2_APPS_CLK_SRC 10 +#define BLSP2_QUP1_I2C_APPS_CLK_SRC 11 +#define BLSP2_QUP1_SPI_APPS_CLK_SRC 12 +#define BLSP2_QUP2_I2C_APPS_CLK_SRC 13 +#define BLSP2_QUP2_SPI_APPS_CLK_SRC 14 +#define BLSP2_QUP3_I2C_APPS_CLK_SRC 15 +#define BLSP2_QUP3_SPI_APPS_CLK_SRC 16 +#define BLSP2_QUP4_I2C_APPS_CLK_SRC 17 +#define BLSP2_QUP4_SPI_APPS_CLK_SRC 18 +#define BLSP2_UART1_APPS_CLK_SRC 19 +#define BLSP2_UART2_APPS_CLK_SRC 20 +#define GCC_AGGRE2_UFS_AXI_CLK 21 +#define GCC_AGGRE2_USB3_AXI_CLK 22 +#define GCC_BIMC_GFX_CLK 23 +#define GCC_BIMC_HMSS_AXI_CLK 24 +#define GCC_BIMC_MSS_Q6_AXI_CLK 25 +#define GCC_BLSP1_AHB_CLK 26 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 27 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 28 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 29 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 30 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 31 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 32 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 33 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 34 +#define GCC_BLSP1_UART1_APPS_CLK 35 +#define GCC_BLSP1_UART2_APPS_CLK 36 +#define GCC_BLSP2_AHB_CLK 37 +#define GCC_BLSP2_QUP1_I2C_APPS_CLK 38 +#define GCC_BLSP2_QUP1_SPI_APPS_CLK 39 +#define GCC_BLSP2_QUP2_I2C_APPS_CLK 40 +#define GCC_BLSP2_QUP2_SPI_APPS_CLK 41 +#define GCC_BLSP2_QUP3_I2C_APPS_CLK 42 +#define GCC_BLSP2_QUP3_SPI_APPS_CLK 43 +#define GCC_BLSP2_QUP4_I2C_APPS_CLK 44 +#define GCC_BLSP2_QUP4_SPI_APPS_CLK 45 +#define GCC_BLSP2_UART1_APPS_CLK 46 +#define GCC_BLSP2_UART2_APPS_CLK 47 +#define GCC_BOOT_ROM_AHB_CLK 48 +#define GCC_CFG_NOC_USB2_AXI_CLK 49 +#define GCC_CFG_NOC_USB3_AXI_CLK 50 +#define GCC_GLM_AHB_CLK 51 +#define GCC_GLM_CLK 52 +#define GCC_GP1_CLK 53 +#define GCC_GP2_CLK 54 +#define GCC_GP3_CLK 55 +#define GCC_GPU_BIMC_GFX_CLK 56 +#define GCC_GPU_BIMC_GFX_SRC_CLK 57 +#define GCC_GPU_CFG_AHB_CLK 58 +#define GCC_GPU_SNOC_DVM_GFX_CLK 59 +#define GCC_HMSS_AHB_CLK 60 +#define GCC_HMSS_DVM_BUS_CLK 61 +#define GCC_HMSS_RBCPR_CLK 62 +#define GCC_MMSS_NOC_CFG_AHB_CLK 63 +#define GCC_MMSS_QM_AHB_CLK 64 +#define GCC_MMSS_QM_CORE_CLK 65 +#define GCC_MMSS_SYS_NOC_AXI_CLK 66 +#define GCC_PDM2_CLK 67 +#define GCC_PDM_AHB_CLK 68 +#define GCC_PRNG_AHB_CLK 69 +#define GCC_QSPI_AHB_CLK 70 +#define GCC_QSPI_SER_CLK 71 +#define GCC_SDCC1_AHB_CLK 72 +#define GCC_SDCC1_APPS_CLK 73 +#define GCC_SDCC1_ICE_CORE_CLK 74 +#define GCC_SDCC2_AHB_CLK 75 +#define GCC_SDCC2_APPS_CLK 76 +#define GCC_UFS_AHB_CLK 77 +#define GCC_UFS_AXI_CLK 78 +#define GCC_UFS_ICE_CORE_CLK 79 +#define GCC_UFS_PHY_AUX_CLK 80 +#define GCC_UFS_RX_SYMBOL_0_CLK 81 +#define GCC_UFS_RX_SYMBOL_1_CLK 82 +#define GCC_UFS_TX_SYMBOL_0_CLK 83 +#define GCC_UFS_UNIPRO_CORE_CLK 84 +#define GCC_USB20_MASTER_CLK 85 +#define GCC_USB20_MOCK_UTMI_CLK 86 +#define GCC_USB20_SLEEP_CLK 87 +#define GCC_USB30_MASTER_CLK 88 +#define GCC_USB30_MOCK_UTMI_CLK 89 +#define GCC_USB30_SLEEP_CLK 90 +#define GCC_USB3_PHY_AUX_CLK 91 +#define GCC_USB3_PHY_PIPE_CLK 92 +#define GCC_USB_PHY_CFG_AHB2PHY_CLK 93 +#define GCC_WCSS_AHB_S0_CLK 94 +#define GCC_WCSS_AXI_M_CLK 95 +#define GCC_WCSS_ECAHB_CLK 96 +#define GCC_WCSS_SHDREG_AHB_CLK 97 +#define GLM_CLK_SRC 98 +#define GP1_CLK_SRC 99 +#define GP2_CLK_SRC 100 +#define GP3_CLK_SRC 101 +#define GPLL0 102 +#define GPLL0_OUT_AUX 103 +#define GPLL0_OUT_AUX2 104 +#define GPLL0_OUT_EARLY 105 +#define GPLL0_OUT_MAIN 106 +#define GPLL0_OUT_TEST 107 +#define GPLL1 108 +#define GPLL1_OUT_AUX 109 +#define GPLL1_OUT_AUX2 110 +#define GPLL1_OUT_EARLY 111 +#define GPLL1_OUT_MAIN 112 +#define GPLL1_OUT_TEST 113 +#define GPLL2 114 +#define GPLL2_OUT_AUX 115 +#define GPLL2_OUT_AUX2 116 +#define GPLL2_OUT_EARLY 117 +#define GPLL2_OUT_MAIN 118 +#define GPLL2_OUT_TEST 119 +#define GPLL3 120 +#define GPLL3_OUT_AUX 121 +#define GPLL3_OUT_AUX2 122 +#define GPLL3_OUT_EARLY 123 +#define GPLL3_OUT_MAIN 124 +#define GPLL3_OUT_TEST 125 +#define GPLL4 126 +#define GPLL4_OUT_AUX 127 +#define GPLL4_OUT_AUX2 128 +#define GPLL4_OUT_EARLY 129 +#define GPLL4_OUT_MAIN 130 +#define GPLL4_OUT_TEST 131 +#define GPLL5 132 +#define GPLL5_OUT_AUX 133 +#define GPLL5_OUT_AUX2 134 +#define GPLL5_OUT_EARLY 135 +#define GPLL5_OUT_MAIN 136 +#define GPLL5_OUT_TEST 137 +#define GPLL6 138 +#define GPLL6_OUT_AUX 139 +#define GPLL6_OUT_AUX2 140 +#define GPLL6_OUT_EARLY 141 +#define GPLL6_OUT_MAIN 142 +#define GPLL6_OUT_TEST 143 +#define HMSS_AHB_CLK_SRC 144 +#define HMSS_GPLL0_CLK_SRC 145 +#define HMSS_GPLL4_CLK_SRC 146 +#define HMSS_RBCPR_CLK_SRC 147 +#define MMSS_QM_CORE_CLK_SRC 148 +#define PDM2_CLK_SRC 149 +#define QSPI_SER_CLK_SRC 150 +#define SDCC1_APPS_CLK_SRC 151 +#define SDCC1_ICE_CORE_CLK_SRC 152 +#define SDCC2_APPS_CLK_SRC 153 +#define UFS_AXI_CLK_SRC 154 +#define UFS_ICE_CORE_CLK_SRC 155 +#define UFS_PHY_AUX_CLK_SRC 156 +#define UFS_UNIPRO_CORE_CLK_SRC 157 +#define USB20_MASTER_CLK_SRC 158 +#define USB20_MOCK_UTMI_CLK_SRC 159 +#define USB30_MASTER_CLK_SRC 160 +#define USB30_MOCK_UTMI_CLK_SRC 161 +#define USB3_PHY_AUX_CLK_SRC 162 -/* Block Resets */ -#define GCC_SYSTEM_NOC_BCR 0 -#define GCC_CONFIG_NOC_BCR 1 -#define GCC_IMEM_BCR 2 -#define GCC_MMSS_BCR 3 -#define GCC_PIMEM_BCR 4 -#define GCC_QDSS_BCR 5 -#define GCC_USB_30_BCR 6 -#define GCC_USB_20_BCR 7 -#define GCC_QUSB2PHY_PRIM_BCR 8 -#define GCC_QUSB2PHY_SEC_BCR 9 -#define GCC_USB_PHY_CFG_AHB2PHY_BCR 10 -#define GCC_SDCC2_BCR 11 -#define GCC_SDCC1_BCR 12 -#define GCC_BLSP1_BCR 13 -#define GCC_BLSP1_QUP1_BCR 14 -#define GCC_BLSP1_UART1_BCR 15 -#define GCC_BLSP1_QUP2_BCR 16 -#define GCC_BLSP1_UART2_BCR 17 -#define GCC_BLSP1_QUP3_BCR 18 -#define GCC_BLSP1_QUP4_BCR 19 -#define GCC_BLSP2_BCR 20 -#define GCC_BLSP2_QUP1_BCR 21 -#define GCC_BLSP2_UART1_BCR 22 -#define GCC_BLSP2_QUP2_BCR 23 -#define GCC_BLSP2_UART2_BCR 24 -#define GCC_BLSP2_QUP3_BCR 25 -#define GCC_BLSP2_QUP4_BCR 26 -#define GCC_PDM_BCR 27 -#define GCC_PRNG_BCR 28 -#define GCC_TCSR_BCR 29 -#define GCC_BOOT_ROM_BCR 30 -#define GCC_MSG_RAM_BCR 31 -#define GCC_TLMM_BCR 32 -#define GCC_MPM_BCR 33 -#define GCC_SEC_CTRL_BCR 34 -#define GCC_SPMI_BCR 35 -#define GCC_SPDM_BCR 36 -#define GCC_CE1_BCR 37 -#define GCC_BIMC_BCR 38 -#define GCC_SNOC_BUS_TIMEOUT0_BCR 39 -#define GCC_SNOC_BUS_TIMEOUT1_BCR 40 -#define GCC_SNOC_BUS_TIMEOUT3_BCR 41 -#define GCC_SNOC_BUS_TIMEOUT_EXTREF_BCR 42 -#define GCC_SNOC_BUS_TIMEOUT4_BCR 43 -#define GCC_PNOC_BUS_TIMEOUT0_BCR 44 -#define GCC_CNOC_PERIPH_BUS_TIMEOUT1_BCR 45 -#define GCC_CNOC_PERIPH_BUS_TIMEOUT2_BCR 46 -#define GCC_CNOC_BUS_TIMEOUT0_BCR 47 -#define GCC_CNOC_BUS_TIMEOUT2_BCR 48 -#define GCC_CNOC_BUS_TIMEOUT3_BCR 49 -#define GCC_CNOC_BUS_TIMEOUT4_BCR 50 -#define GCC_CNOC_BUS_TIMEOUT5_BCR 51 -#define GCC_CNOC_BUS_TIMEOUT6_BCR 52 -#define GCC_CNOC_BUS_TIMEOUT7_BCR 53 -#define GCC_CNOC_BUS_TIMEOUT8_BCR 54 -#define GCC_CNOC_BUS_TIMEOUT9_BCR 55 -#define GCC_CNOC_BUS_TIMEOUT10_BCR 56 -#define GCC_CNOC_BUS_TIMEOUT11_BCR 57 -#define GCC_CNOC_BUS_TIMEOUT12_BCR 58 -#define GCC_CNOC_BUS_TIMEOUT13_BCR 59 -#define GCC_CNOC_BUS_TIMEOUT14_BCR 60 -#define GCC_CNOC_BUS_TIMEOUT_EXTREF_BCR 61 -#define GCC_APB2JTAG_BCR 62 -#define GCC_RBCPR_CX_BCR 63 -#define GCC_RBCPR_MX_BCR 64 -#define GCC_OBT_ODT_BCR 65 -#define GCC_UFS_BCR 66 -#define GCC_VS_BCR 67 -#define GCC_AGGRE2_NOC_BCR 68 -#define GCC_DCC_BCR 69 -#define GCC_QSPI_BCR 70 -#define GCC_IPA_BCR 71 -#define GCC_GLM_BCR 72 -#define GCC_MSMPU_BCR 73 -#define GCC_QREFS_VBG_CAL_BCR 74 -#define GCC_WCSS_BCR 75 -#define GCC_GPU_BCR 76 -#define GCC_AHB2PHY_EAST_BCR 77 -#define GCC_CM_PHY_REFGEN1_BCR 78 -#define GCC_CM_PHY_REFGEN2_BCR 79 -#define GCC_SRAM_SENSOR_BCR 80 +#define UFS_GDSC 0 +#define USB_30_GDSC 1 -/* GDSC */ -#define UFS_GDSC 0 -#define USB_30_GDSC 1 -#define DDR_DIM_WRAPPER_GDSC 2 -#define MMSS_GDSC 3 +#define GCC_QUSB2PHY_PRIM_BCR 0 +#define GCC_QUSB2PHY_SEC_BCR 1 +#define GCC_UFS_BCR 2 +#define GCC_USB3_DP_PHY_BCR 3 +#define GCC_USB3_PHY_BCR 4 +#define GCC_USB3PHY_PHY_BCR 5 +#define GCC_USB_20_BCR 6 +#define GCC_USB_30_BCR 7 +#define GCC_USB_PHY_CFG_AHB2PHY_BCR 8 + +/* RPM controlled clocks */ +#define RPM_CE1_CLK 1 +#define RPM_CE1_A_CLK 2 +#define RPM_CXO_CLK_SRC 3 +#define RPM_BIMC_CLK 4 +#define RPM_BIMC_A_CLK 5 +#define RPM_CNOC_CLK 6 +#define RPM_CNOC_A_CLK 7 +#define RPM_SNOC_CLK 8 +#define RPM_SNOC_A_CLK 9 +#define RPM_CNOC_PERIPH_CLK 10 +#define RPM_CNOC_PERIPH_A_CLK 11 +#define RPM_CNOC_PERIPH_KEEPALIVE_A_CLK 12 +#define RPM_LN_BB_CLK1 13 +#define RPM_LN_BB_CLK1_AO 14 +#define RPM_LN_BB_CLK1_PIN 15 +#define RPM_LN_BB_CLK1_PIN_AO 16 +#define RPM_BIMC_MSMBUS_CLK 17 +#define RPM_BIMC_MSMBUS_A_CLK 18 +#define RPM_CNOC_MSMBUS_CLK 19 +#define RPM_CNOC_MSMBUS_A_CLK 20 +#define RPM_CXO_CLK_SRC_AO 21 +#define RPM_CXO_DWC3_CLK 22 +#define RPM_CXO_LPM_CLK 23 +#define RPM_CXO_OTG_CLK 24 +#define RPM_CXO_PIL_LPASS_CLK 25 +#define RPM_CXO_PIL_SSC_CLK 26 +#define RPM_CXO_PIL_SPSS_CLK 27 +#define RPM_DIV_CLK1 28 +#define RPM_DIV_CLK1_AO 29 +#define RPM_IPA_CLK 30 +#define RPM_IPA_A_CLK 31 +#define RPM_MCD_CE1_CLK 32 +#define RPM_MMSSNOC_AXI_CLK 33 +#define RPM_MMSSNOC_AXI_A_CLK 34 +#define RPM_QCEDEV_CE1_CLK 35 +#define RPM_QCRYPTO_CE1_CLK 36 +#define RPM_QDSS_CLK 37 +#define RPM_QDSS_A_CLK 38 +#define RPM_QSEECOM_CE1_CLK 39 +#define RPM_RF_CLK2 40 +#define RPM_RF_CLK2_AO 41 +#define RPM_SCM_CE1_CLK 42 +#define RPM_SNOC_MSMBUS_CLK 43 +#define RPM_SNOC_MSMBUS_A_CLK 44 +#define RPM_AGGRE2_NOC_CLK 45 +#define RPM_AGGRE2_NOC_A_CLK 46 #endif diff --git a/include/dt-bindings/clock/qcom,gpu-msmfalcon.h b/include/dt-bindings/clock/qcom,gpu-msmfalcon.h index a167716e9cc6..427c6aae05d3 100644 --- a/include/dt-bindings/clock/qcom,gpu-msmfalcon.h +++ b/include/dt-bindings/clock/qcom,gpu-msmfalcon.h @@ -14,25 +14,27 @@ #ifndef _DT_BINDINGS_CLK_MSM_GPU_FALCON_H #define _DT_BINDINGS_CLK_MSM_GPU_FALCON_H -/* Clocks */ -#define GPU_PLL0_PLL 0 -#define GPU_PLL1_PLL 1 -#define GFX3D_CLK_SRC 2 -#define RBBMTIMER_CLK_SRC 3 -#define RBCPR_CLK_SRC 4 -#define GPUCC_CXO_CLK 5 -#define GPUCC_GFX3D_CLK 6 -#define GPUCC_RBBMTIMER_CLK 7 -#define GPUCC_RBCPR_CLK 8 +#define GFX3D_CLK_SRC 0 +#define GPU_PLL0_PLL 1 +#define GPU_PLL0_PLL_OUT_AUX 2 +#define GPU_PLL0_PLL_OUT_AUX2 3 +#define GPU_PLL0_PLL_OUT_EARLY 4 +#define GPU_PLL0_PLL_OUT_MAIN 5 +#define GPU_PLL0_PLL_OUT_TEST 6 +#define GPU_PLL1_PLL 7 +#define GPU_PLL1_PLL_OUT_AUX 8 +#define GPU_PLL1_PLL_OUT_AUX2 9 +#define GPU_PLL1_PLL_OUT_EARLY 10 +#define GPU_PLL1_PLL_OUT_MAIN 11 +#define GPU_PLL1_PLL_OUT_TEST 12 +#define GPUCC_CXO_CLK 13 +#define GPUCC_GFX3D_CLK 14 +#define GPUCC_RBBMTIMER_CLK 15 +#define GPUCC_RBCPR_CLK 16 +#define RBBMTIMER_CLK_SRC 18 +#define RBCPR_CLK_SRC 19 -/* Block Reset */ -#define GPU_CC_GPU_GX_BCR 0 -#define GPU_CC_GPU_CX_BCR 1 -#define GPU_CC_RBCPR_BCR 2 -#define GPU_CC_SPDM_BCR 3 - -/* GDSC */ -#define GPU_GX_GDSC 0 -#define GPU_CX_GDSC 1 +#define GPU_CX_GDSC 0 +#define GPU_GX_GDSC 1 #endif diff --git a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h index 57aed7c8f43f..ffb80a128dd6 100644 --- a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h +++ b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h @@ -14,181 +14,200 @@ #ifndef _DT_BINDINGS_CLK_MSM_MMCC_FALCON_H #define _DT_BINDINGS_CLK_MSM_MMCC_FALCON_H -/* Clocks */ -#define MMPLL3_PLL 0 -#define MMPLL4_PLL 1 -#define MMPLL5_PLL 2 -#define MMPLL6_PLL 3 -#define MMPLL7_PLL 4 -#define MMPLL8_PLL 5 -#define AHB_CLK_SRC 6 -#define VIDEO_CORE_CLK_SRC 7 -#define PCLK0_CLK_SRC 8 -#define PCLK1_CLK_SRC 9 -#define MDP_CLK_SRC 10 -#define ROT_CLK_SRC 11 -#define VSYNC_CLK_SRC 12 -#define BYTE0_CLK_SRC 13 -#define BYTE1_CLK_SRC 14 -#define ESC0_CLK_SRC 15 -#define ESC1_CLK_SRC 16 -#define DP_LINK_CLK_SRC 17 -#define DP_CRYPTO_CLK_SRC 18 -#define DP_PIXEL_CLK_SRC 19 -#define DP_AUX_CLK_SRC 20 -#define DP_GTC_CLK_SRC 21 -#define CAMSS_GP0_CLK_SRC 22 -#define CAMSS_GP1_CLK_SRC 23 -#define MCLK0_CLK_SRC 24 -#define MCLK1_CLK_SRC 25 -#define MCLK2_CLK_SRC 26 -#define MCLK3_CLK_SRC 27 -#define CCI_CLK_SRC 28 -#define CSI0PHYTIMER_CLK_SRC 29 -#define CSI1PHYTIMER_CLK_SRC 30 -#define CSI2PHYTIMER_CLK_SRC 31 -#define JPEG0_CLK_SRC 32 -#define VFE0_CLK_SRC 33 -#define VFE1_CLK_SRC 34 -#define CPP_CLK_SRC 35 -#define CSIPHY_CLK_SRC 36 -#define CSI0_CLK_SRC 37 -#define CSI1_CLK_SRC 38 -#define CSI2_CLK_SRC 39 -#define CSI3_CLK_SRC 40 -#define MMSS_CXO_CLK 41 -#define MMSS_SLEEP_CLK 42 -#define MMSS_MNOC_AHB_CLK 43 -#define MMSS_MISC_AHB_CLK 44 -#define MMSS_MISC_CXO_CLK 45 -#define MMSS_BIMC_SMMU_AHB_CLK 46 -#define MMSS_BIMC_SMMU_AXI_CLK 47 -#define MMSS_SNOC_DVM_AXI_CLK 48 -#define MMSS_THROTTLE_CAMSS_CXO_CLK 49 -#define MMSS_THROTTLE_CAMSS_AHB_CLK 50 -#define MMSS_THROTTLE_CAMSS_AXI_CLK 51 -#define MMSS_THROTTLE_MDSS_CXO_CLK 52 -#define MMSS_THROTTLE_MDSS_AHB_CLK 53 -#define MMSS_THROTTLE_MDSS_AXI_CLK 54 -#define MMSS_THROTTLE_VIDEO_CXO_CLK 55 -#define MMSS_THROTTLE_VIDEO_AHB_CLK 56 -#define MMSS_THROTTLE_VIDEO_AXI_CLK 57 -#define MMSS_VIDEO_CORE_CLK 58 -#define MMSS_VIDEO_AXI_CLK 59 -#define MMSS_VIDEO_AHB_CLK 60 -#define MMSS_MDSS_AHB_CLK 61 -#define MMSS_MDSS_HDMI_DP_AHB_CLK 62 -#define MMSS_MDSS_PCLK0_CLK 63 -#define MMSS_MDSS_PCLK1_CLK 64 -#define MMSS_MDSS_VSYNC_CLK 65 -#define MMSS_MDSS_BYTE0_CLK 66 -#define MMSS_MDSS_BYTE0_INTF_CLK 67 -#define MMSS_MDSS_BYTE1_CLK 68 -#define MMSS_MDSS_BYTE1_INTF_CLK 69 -#define MMSS_MDSS_ESC0_CLK 70 -#define MMSS_MDSS_ESC1_CLK 71 -#define MMSS_MDSS_DP_LINK_CLK 72 -#define MMSS_MDSS_DP_LINK_INTF_CLK 73 -#define MMSS_MDSS_DP_CRYPTO_CLK 74 -#define MMSS_MDSS_DP_PIXEL_CLK 75 -#define MMSS_MDSS_DP_AUX_CLK 76 -#define MMSS_MDSS_DP_GTC_CLK 77 -#define MMSS_CAMSS_TOP_AHB_CLK 78 -#define MMSS_CAMSS_AHB_CLK 79 -#define MMSS_CAMSS_GP0_CLK 80 -#define MMSS_CAMSS_GP1_CLK 81 -#define MMSS_CAMSS_MCLK0_CLK 82 -#define MMSS_CAMSS_MCLK1_CLK 83 -#define MMSS_CAMSS_MCLK2_CLK 84 -#define MMSS_CAMSS_MCLK3_CLK 85 -#define MMSS_CAMSS_CCI_CLK 86 -#define MMSS_CAMSS_CCI_AHB_CLK 87 -#define MMSS_CAMSS_CSI0PHYTIMER_CLK 88 -#define MMSS_CAMSS_CSI1PHYTIMER_CLK 89 -#define MMSS_CAMSS_CSI2PHYTIMER_CLK 90 -#define MMSS_CAMSS_JPEG_AHB_CLK 91 -#define MMSS_CAMSS_VFE_VBIF_AHB_CLK 92 -#define MMSS_CAMSS_VFE0_STREAM_CLK 93 -#define MMSS_CAMSS_VFE0_AHB_CLK 94 -#define MMSS_CAMSS_VFE1_STREAM_CLK 95 -#define MMSS_CAMSS_VFE1_AHB_CLK 96 -#define MMSS_CAMSS_CPP_VBIF_AHB_CLK 97 -#define MMSS_CAMSS_CPP_AHB_CLK 98 -#define MMSS_CAMSS_CSIPHY0_CLK 99 -#define MMSS_CAMSS_CSIPHY1_CLK 100 -#define MMSS_CAMSS_CSIPHY2_CLK 101 -#define MMSS_CSIPHY_AHB2CRIF_CLK 102 -#define MMSS_CAMSS_CSI0_CLK 103 -#define MMSS_CAMSS_CPHY_CSID0_CLK 104 -#define MMSS_CAMSS_CSI0_AHB_CLK 105 -#define MMSS_CAMSS_CSI0RDI_CLK 106 -#define MMSS_CAMSS_CSI0PIX_CLK 107 -#define MMSS_CAMSS_CSI1_CLK 108 -#define MMSS_CAMSS_CPHY_CSID1_CLK 109 -#define MMSS_CAMSS_CSI1_AHB_CLK 110 -#define MMSS_CAMSS_CSI1RDI_CLK 111 -#define MMSS_CAMSS_CSI1PIX_CLK 112 -#define MMSS_CAMSS_CSI2_CLK 113 -#define MMSS_CAMSS_CPHY_CSID2_CLK 114 -#define MMSS_CAMSS_CSI2_AHB_CLK 115 -#define MMSS_CAMSS_CSI2RDI_CLK 116 -#define MMSS_CAMSS_CSI2PIX_CLK 117 -#define MMSS_CAMSS_CSI3_CLK 118 -#define MMSS_CAMSS_CPHY_CSID3_CLK 119 -#define MMSS_CAMSS_CSI3_AHB_CLK 120 -#define MMSS_CAMSS_CSI3RDI_CLK 121 -#define MMSS_CAMSS_CSI3PIX_CLK 122 -#define MMSS_CAMSS_ISPIF_AHB_CLK 123 +#define AHB_CLK_SRC 0 +#define BYTE0_CLK_SRC 1 +#define BYTE1_CLK_SRC 2 +#define CAMSS_GP0_CLK_SRC 3 +#define CAMSS_GP1_CLK_SRC 4 +#define CCI_CLK_SRC 5 +#define CPP_CLK_SRC 6 +#define CSI0_CLK_SRC 7 +#define CSI0PHYTIMER_CLK_SRC 8 +#define CSI1_CLK_SRC 9 +#define CSI1PHYTIMER_CLK_SRC 10 +#define CSI2_CLK_SRC 11 +#define CSI2PHYTIMER_CLK_SRC 12 +#define CSI3_CLK_SRC 13 +#define CSIPHY_CLK_SRC 14 +#define DP_AUX_CLK_SRC 15 +#define DP_CRYPTO_CLK_SRC 16 +#define DP_GTC_CLK_SRC 17 +#define DP_LINK_CLK_SRC 18 +#define DP_PIXEL_CLK_SRC 19 +#define ESC0_CLK_SRC 20 +#define ESC1_CLK_SRC 21 +#define JPEG0_CLK_SRC 22 +#define MCLK0_CLK_SRC 23 +#define MCLK1_CLK_SRC 24 +#define MCLK2_CLK_SRC 25 +#define MCLK3_CLK_SRC 26 +#define MDP_CLK_SRC 27 +#define MMPLL0_PLL 28 +#define MMPLL0_PLL_OUT_AUX 29 +#define MMPLL0_PLL_OUT_AUX2 30 +#define MMPLL0_PLL_OUT_EARLY 31 +#define MMPLL0_PLL_OUT_MAIN 32 +#define MMPLL0_PLL_OUT_TEST 33 +#define MMPLL10_PLL 34 +#define MMPLL10_PLL_OUT_AUX 35 +#define MMPLL10_PLL_OUT_AUX2 36 +#define MMPLL10_PLL_OUT_EARLY 37 +#define MMPLL10_PLL_OUT_MAIN 38 +#define MMPLL10_PLL_OUT_TEST 39 +#define MMPLL1_PLL 40 +#define MMPLL1_PLL_OUT_AUX 41 +#define MMPLL1_PLL_OUT_AUX2 42 +#define MMPLL1_PLL_OUT_EARLY 43 +#define MMPLL1_PLL_OUT_MAIN 44 +#define MMPLL1_PLL_OUT_TEST 45 +#define MMPLL3_PLL 46 +#define MMPLL3_PLL_OUT_AUX 47 +#define MMPLL3_PLL_OUT_AUX2 48 +#define MMPLL3_PLL_OUT_EARLY 49 +#define MMPLL3_PLL_OUT_MAIN 50 +#define MMPLL3_PLL_OUT_TEST 51 +#define MMPLL4_PLL 52 +#define MMPLL4_PLL_OUT_AUX 53 +#define MMPLL4_PLL_OUT_AUX2 54 +#define MMPLL4_PLL_OUT_EARLY 55 +#define MMPLL4_PLL_OUT_MAIN 56 +#define MMPLL4_PLL_OUT_TEST 57 +#define MMPLL5_PLL 58 +#define MMPLL5_PLL_OUT_AUX 59 +#define MMPLL5_PLL_OUT_AUX2 60 +#define MMPLL5_PLL_OUT_EARLY 61 +#define MMPLL5_PLL_OUT_MAIN 62 +#define MMPLL5_PLL_OUT_TEST 63 +#define MMPLL6_PLL 64 +#define MMPLL6_PLL_OUT_AUX 65 +#define MMPLL6_PLL_OUT_AUX2 66 +#define MMPLL6_PLL_OUT_EARLY 67 +#define MMPLL6_PLL_OUT_MAIN 68 +#define MMPLL6_PLL_OUT_TEST 69 +#define MMPLL7_PLL 70 +#define MMPLL7_PLL_OUT_AUX 71 +#define MMPLL7_PLL_OUT_AUX2 72 +#define MMPLL7_PLL_OUT_EARLY 73 +#define MMPLL7_PLL_OUT_MAIN 74 +#define MMPLL7_PLL_OUT_TEST 75 +#define MMPLL8_PLL 76 +#define MMPLL8_PLL_OUT_AUX 77 +#define MMPLL8_PLL_OUT_AUX2 78 +#define MMPLL8_PLL_OUT_EARLY 79 +#define MMPLL8_PLL_OUT_MAIN 80 +#define MMPLL8_PLL_OUT_TEST 81 +#define MMSS_BIMC_SMMU_AHB_CLK 82 +#define MMSS_BIMC_SMMU_AXI_CLK 83 +#define MMSS_CAMSS_AHB_CLK 84 +#define MMSS_CAMSS_CCI_AHB_CLK 85 +#define MMSS_CAMSS_CCI_CLK 86 +#define MMSS_CAMSS_CPHY_CSID0_CLK 87 +#define MMSS_CAMSS_CPHY_CSID1_CLK 88 +#define MMSS_CAMSS_CPHY_CSID2_CLK 89 +#define MMSS_CAMSS_CPHY_CSID3_CLK 90 +#define MMSS_CAMSS_CPP_AHB_CLK 91 +#define MMSS_CAMSS_CPP_AXI_CLK 92 +#define MMSS_CAMSS_CPP_CLK 93 +#define MMSS_CAMSS_CPP_VBIF_AHB_CLK 94 +#define MMSS_CAMSS_CSI0_AHB_CLK 95 +#define MMSS_CAMSS_CSI0_CLK 96 +#define MMSS_CAMSS_CSI0PHYTIMER_CLK 97 +#define MMSS_CAMSS_CSI0PIX_CLK 98 +#define MMSS_CAMSS_CSI0RDI_CLK 99 +#define MMSS_CAMSS_CSI1_AHB_CLK 100 +#define MMSS_CAMSS_CSI1_CLK 101 +#define MMSS_CAMSS_CSI1PHYTIMER_CLK 102 +#define MMSS_CAMSS_CSI1PIX_CLK 103 +#define MMSS_CAMSS_CSI1RDI_CLK 104 +#define MMSS_CAMSS_CSI2_AHB_CLK 105 +#define MMSS_CAMSS_CSI2_CLK 106 +#define MMSS_CAMSS_CSI2PHYTIMER_CLK 107 +#define MMSS_CAMSS_CSI2PIX_CLK 108 +#define MMSS_CAMSS_CSI2RDI_CLK 109 +#define MMSS_CAMSS_CSI3_AHB_CLK 110 +#define MMSS_CAMSS_CSI3_CLK 111 +#define MMSS_CAMSS_CSI3PIX_CLK 112 +#define MMSS_CAMSS_CSI3RDI_CLK 113 +#define MMSS_CAMSS_CSI_VFE0_CLK 114 +#define MMSS_CAMSS_CSI_VFE1_CLK 115 +#define MMSS_CAMSS_CSIPHY0_CLK 116 +#define MMSS_CAMSS_CSIPHY1_CLK 117 +#define MMSS_CAMSS_CSIPHY2_CLK 118 +#define MMSS_CAMSS_GP0_CLK 119 +#define MMSS_CAMSS_GP1_CLK 120 +#define MMSS_CAMSS_ISPIF_AHB_CLK 121 +#define MMSS_CAMSS_JPEG0_CLK 122 +#define MMSS_CAMSS_JPEG_AHB_CLK 123 +#define MMSS_CAMSS_JPEG_AXI_CLK 124 +#define MMSS_CAMSS_MCLK0_CLK 125 +#define MMSS_CAMSS_MCLK1_CLK 126 +#define MMSS_CAMSS_MCLK2_CLK 127 +#define MMSS_CAMSS_MCLK3_CLK 128 +#define MMSS_CAMSS_MICRO_AHB_CLK 129 +#define MMSS_CAMSS_TOP_AHB_CLK 130 +#define MMSS_CAMSS_VFE0_AHB_CLK 131 +#define MMSS_CAMSS_VFE0_CLK 132 +#define MMSS_CAMSS_VFE0_STREAM_CLK 133 +#define MMSS_CAMSS_VFE1_AHB_CLK 134 +#define MMSS_CAMSS_VFE1_CLK 135 +#define MMSS_CAMSS_VFE1_STREAM_CLK 136 +#define MMSS_CAMSS_VFE_VBIF_AHB_CLK 137 +#define MMSS_CAMSS_VFE_VBIF_AXI_CLK 138 +#define MMSS_CSIPHY_AHB2CRIF_CLK 139 +#define MMSS_CXO_CLK 140 +#define MMSS_MDSS_AHB_CLK 141 +#define MMSS_MDSS_AXI_CLK 142 +#define MMSS_MDSS_BYTE0_CLK 143 +#define MMSS_MDSS_BYTE0_INTF_CLK 144 +#define MMSS_MDSS_BYTE1_CLK 145 +#define MMSS_MDSS_BYTE1_INTF_CLK 146 +#define MMSS_MDSS_DP_AUX_CLK 147 +#define MMSS_MDSS_DP_CRYPTO_CLK 148 +#define MMSS_MDSS_DP_GTC_CLK 149 +#define MMSS_MDSS_DP_LINK_CLK 150 +#define MMSS_MDSS_DP_LINK_INTF_CLK 151 +#define MMSS_MDSS_DP_PIXEL_CLK 152 +#define MMSS_MDSS_ESC0_CLK 153 +#define MMSS_MDSS_ESC1_CLK 154 +#define MMSS_MDSS_HDMI_DP_AHB_CLK 155 +#define MMSS_MDSS_MDP_CLK 156 +#define MMSS_MDSS_PCLK0_CLK 157 +#define MMSS_MDSS_PCLK1_CLK 158 +#define MMSS_MDSS_ROT_CLK 159 +#define MMSS_MDSS_VSYNC_CLK 160 +#define MMSS_MISC_AHB_CLK 161 +#define MMSS_MISC_CXO_CLK 162 +#define MMSS_MNOC_AHB_CLK 163 +#define MMSS_SNOC_DVM_AXI_CLK 164 +#define MMSS_THROTTLE_CAMSS_AHB_CLK 165 +#define MMSS_THROTTLE_CAMSS_AXI_CLK 166 +#define MMSS_THROTTLE_CAMSS_CXO_CLK 167 +#define MMSS_THROTTLE_MDSS_AHB_CLK 168 +#define MMSS_THROTTLE_MDSS_AXI_CLK 169 +#define MMSS_THROTTLE_MDSS_CXO_CLK 170 +#define MMSS_THROTTLE_VIDEO_AHB_CLK 171 +#define MMSS_THROTTLE_VIDEO_AXI_CLK 172 +#define MMSS_THROTTLE_VIDEO_CXO_CLK 173 +#define MMSS_VIDEO_AHB_CLK 174 +#define MMSS_VIDEO_AXI_CLK 175 +#define MMSS_VIDEO_CORE_CLK 176 +#define MMSS_VIDEO_SUBCORE0_CLK 177 +#define PCLK0_CLK_SRC 178 +#define PCLK1_CLK_SRC 179 +#define ROT_CLK_SRC 180 +#define VFE0_CLK_SRC 181 +#define VFE1_CLK_SRC 182 +#define VIDEO_CORE_CLK_SRC 183 +#define VSYNC_CLK_SRC 184 -/* Block Resets */ -#define MMSS_MNOCAHB_BCR 0 -#define MMSS_MISC_BCR 1 -#define MMSS_BTO_BCR 2 -#define MMSS_MNOCAXI_BCR 3 -#define MMSS_BIMC_SMMU_BCR 4 -#define MMSS_THROTTLE_CAMSS_BCR 5 -#define MMSS_THROTTLE_MDSS_BCR 6 -#define MMSS_THROTTLE_VIDEO_BCR 7 -#define MMSS_VIDEO_TOP_BCR 8 -#define MMSS_MDSS_BCR 9 -#define MMSS_CAMSS_TOP_BCR 10 -#define MMSS_CAMSS_AHB_BCR 11 -#define MMSS_CAMSS_MICRO_BCR 12 -#define MMSS_CAMSS_CCI_BCR 13 -#define MMSS_CAMSS_PHY0_BCR 14 -#define MMSS_CAMSS_PHY1_BCR 15 -#define MMSS_CAMSS_PHY2_BCR 16 -#define MMSS_CAMSS_JPEG_BCR 17 -#define MMSS_CAMSS_VFE_VBIF_BCR 18 -#define MMSS_CAMSS_VFE0_BCR 19 -#define MMSS_CAMSS_VFE1_BCR 20 -#define MMSS_CAMSS_CSI_VFE0_BCR 21 -#define MMSS_CAMSS_CSI_VFE1_BCR 22 -#define MMSS_CAMSS_CPP_TOP_BCR 23 -#define MMSS_CAMSS_CPP_BCR 24 -#define MMSS_CAMSS_CSIPHY_BCR 25 -#define MMSS_CAMSS_CSI0_BCR 26 -#define MMSS_CAMSS_CSI0RDI_BCR 27 -#define MMSS_CAMSS_CSI0PIX_BCR 28 -#define MMSS_CAMSS_CSI1_BCR 29 -#define MMSS_CAMSS_CSI1RDI_BCR 30 -#define MMSS_CAMSS_CSI1PIX_BCR 31 -#define MMSS_CAMSS_CSI2_BCR 32 -#define MMSS_CAMSS_CSI2RDI_BCR 33 -#define MMSS_CAMSS_CSI2PIX_BCR 34 -#define MMSS_CAMSS_CSI3_BCR 35 -#define MMSS_CAMSS_CSI3RDI_BCR 36 -#define MMSS_CAMSS_CSI3PIX_BCR 37 -#define MMSS_CAMSS_ISPIF_BCR 38 +#define BIMC_SMMU_GDSC 0 +#define CAMSS_CPP_GDSC 1 +#define CAMSS_TOP_GDSC 2 +#define CAMSS_VFE0_GDSC 3 +#define CAMSS_VFE1_GDSC 4 +#define MDSS_GDSC 5 +#define VIDEO_SUBCORE0_GDSC 6 +#define VIDEO_TOP_GDSC 7 -/* GDSC */ -#define VIDEO_TOP_GDSC 0 -#define VIDEO_SUBCORE0_GDSC 1 -#define CAMSS_VFE0_GDSC 2 -#define BIMC_SMMU_GDSC 3 -#define CAMSS_TOP_GDSC 4 -#define MDSS_GDSC 5 -#define CAMSS_CPP_GDSC 6 -#define CAMSS_VFE1_GDSC 7 #endif diff --git a/include/linux/input/ft5x06_ts.h b/include/linux/input/ft5x06_ts.h index a9577b62cb07..08ccbc9bd71c 100644 --- a/include/linux/input/ft5x06_ts.h +++ b/include/linux/input/ft5x06_ts.h @@ -3,7 +3,7 @@ * FocalTech ft5x06 TouchScreen driver header file. * * Copyright (c) 2010 Focal tech Ltd. - * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2012-2016, 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 @@ -18,12 +18,28 @@ #ifndef __LINUX_FT5X06_TS_H__ #define __LINUX_FT5X06_TS_H__ +#define FT5X06_ID 0x55 +#define FT5X16_ID 0x0A +#define FT5X36_ID 0x14 +#define FT6X06_ID 0x06 + struct ft5x06_ts_platform_data { - unsigned long irqflags; - u32 x_max; - u32 y_max; + u32 irqflags; u32 irq_gpio; + u32 irq_gpio_flags; u32 reset_gpio; + u32 reset_gpio_flags; + u32 family_id; + u32 x_max; + u32 y_max; + u32 x_min; + u32 y_min; + u32 panel_minx; + u32 panel_miny; + u32 panel_maxx; + u32 panel_maxy; + bool no_force_update; + bool i2c_pull_up; int (*power_init)(bool); int (*power_on)(bool); }; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 7d1e374e176c..56e78254286e 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -174,9 +174,9 @@ enum power_supply_property { /* Local extensions */ POWER_SUPPLY_PROP_USB_HC, POWER_SUPPLY_PROP_USB_OTG, - POWER_SUPPLY_PROP_CHARGE_ENABLED, POWER_SUPPLY_PROP_BATTERY_CHARGING_ENABLED, POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_PIN_ENABLED, POWER_SUPPLY_PROP_INPUT_SUSPEND, POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 8d9016e3557c..3464726c408a 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -2738,6 +2738,333 @@ struct afe_param_id_set_topology_cfg { u32 topology_id; } __packed; + +/* + * Generic encoder module ID. + * This module supports the following parameter IDs: + * #AVS_ENCODER_PARAM_ID_ENC_FMT_ID (cannot be set run time) + * #AVS_ENCODER_PARAM_ID_ENC_CFG_BLK (may be set run time) + * #AVS_ENCODER_PARAM_ID_ENC_BITRATE (may be set run time) + * #AVS_ENCODER_PARAM_ID_PACKETIZER_ID (cannot be set run time) + * Opcode - AVS_MODULE_ID_ENCODER + * AFE Command AFE_PORT_CMD_SET_PARAM_V2 supports this module ID. + */ +#define AFE_MODULE_ID_ENCODER 0x00013229 + +/* Macro for defining the packetizer ID: COP. */ +#define AFE_MODULE_ID_PACKETIZER_COP 0x0001322A + +/* + * Packetizer type parameter for the #AVS_MODULE_ID_ENCODER module. + * This parameter cannot be set runtime. + */ +#define AFE_ENCODER_PARAM_ID_PACKETIZER_ID 0x0001322E + +/* + * Encoder config block parameter for the #AVS_MODULE_ID_ENCODER module. + * This parameter may be set runtime. + */ +#define AFE_ENCODER_PARAM_ID_ENC_CFG_BLK 0x0001322C + +/* + * Encoder format ID parameter for the #AVS_MODULE_ID_ENCODER module. + * This parameter cannot be set runtime. + */ +#define AFE_ENCODER_PARAM_ID_ENC_FMT_ID 0x0001322B + +/* + * Data format to send compressed data + * is transmitted/received over Slimbus lines. + */ +#define AFE_SB_DATA_FORMAT_GENERIC_COMPRESSED 0x3 + +/* + * ID for AFE port module. This will be used to define port properties. + * This module supports following parameter IDs: + * #AFE_PARAM_ID_PORT_MEDIA_TYPE + * To configure the port property, the client must use the + * #AFE_PORT_CMD_SET_PARAM_V2 command, + * and fill the module ID with the respective parameter IDs as listed above. + * @apr_hdr_fields + * Opcode -- AFE_MODULE_PORT + */ +#define AFE_MODULE_PORT 0x000102a6 + +/* + * ID of the parameter used by #AFE_MODULE_PORT to set the port media type. + * parameter ID is currently supported using#AFE_PORT_CMD_SET_PARAM_V2 command. + */ +#define AFE_PARAM_ID_PORT_MEDIA_TYPE 0x000102a7 + +/* + * Macros for defining the "data_format" field in the + * #AFE_PARAM_ID_PORT_MEDIA_TYPE + */ +#define AFE_PORT_DATA_FORMAT_PCM 0x0 +#define AFE_PORT_DATA_FORMAT_GENERIC_COMPRESSED 0x1 + +/* + * Macro for defining the "minor_version" field in the + * #AFE_PARAM_ID_PORT_MEDIA_TYPE + */ +#define AFE_API_VERSION_PORT_MEDIA_TYPE 0x1 + +#define ASM_MEDIA_FMT_NONE 0x0 + +/* + * Media format ID for SBC encode configuration. + * @par SBC encode configuration (asm_sbc_enc_cfg_t) + * @table{weak__asm__sbc__enc__cfg__t} + */ +#define ASM_MEDIA_FMT_SBC 0x00010BF2 + +/* SBC channel Mono mode.*/ +#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_MONO 1 + +/* SBC channel Stereo mode. */ +#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_STEREO 2 + +/* SBC channel Dual Mono mode. */ +#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_DUAL_MONO 8 + +/* SBC channel Joint Stereo mode. */ +#define ASM_MEDIA_FMT_SBC_CHANNEL_MODE_JOINT_STEREO 9 + +/* SBC bit allocation method = loudness. */ +#define ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_LOUDNESS 0 + +/* SBC bit allocation method = SNR. */ +#define ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_SNR 1 + + +/* + * Payload of the SBC encoder configuration parameters in the + * #ASM_MEDIA_FMT_SBC media format. + */ +struct asm_sbc_enc_cfg_t { + /* + * Number of subbands. + * @values 4, 8 + */ + uint32_t num_subbands; + + /* + * Size of the encoded block in samples. + * @values 4, 8, 12, 16 + */ + uint32_t blk_len; + + /* + * Mode used to allocate bits between channels. + * @values + * 0 (Native mode) + * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_MONO + * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_STEREO + * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_DUAL_MONO + * #ASM_MEDIA_FMT_SBC_CHANNEL_MODE_JOINT_STEREO + * Native mode indicates that encoding must be performed with the number + * of channels at the input. + * If postprocessing outputs one-channel data, Mono mode is used. If + * postprocessing outputs two-channel data, Stereo mode is used. + * The number of channels must not change during encoding. + */ + uint32_t channel_mode; + + /* + * Encoder bit allocation method. + * @values + * #ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_LOUDNESS + * #ASM_MEDIA_FMT_SBC_ALLOCATION_METHOD_SNR @tablebulletend + */ + uint32_t alloc_method; + + /* + * Number of encoded bits per second. + * @values + * Mono channel -- Maximum of 320 kbps + * Stereo channel -- Maximum of 512 kbps @tablebulletend + */ + uint32_t bit_rate; + + /* + * Number of samples per second. + * @values 0 (Native mode), 16000, 32000, 44100, 48000 Hz + * Native mode indicates that encoding must be performed with the + * sampling rate at the input. + * The sampling rate must not change during encoding. + */ + uint32_t sample_rate; +}; + +#define ASM_MEDIA_FMT_AAC_AOT_LC 2 +#define ASM_MEDIA_FMT_AAC_AOT_SBR 5 +#define ASM_MEDIA_FMT_AAC_AOT_PS 29 +#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS 0 +#define ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW 3 + +struct asm_aac_enc_cfg_v2_t { + + /* Encoding rate in bits per second.*/ + uint32_t bit_rate; + + /* + * Encoding mode. + * Supported values: + * #ASM_MEDIA_FMT_AAC_AOT_LC + * #ASM_MEDIA_FMT_AAC_AOT_SBR + * #ASM_MEDIA_FMT_AAC_AOT_PS + */ + uint32_t enc_mode; + + /* + * AAC format flag. + * Supported values: + * #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_ADTS + * #ASM_MEDIA_FMT_AAC_FORMAT_FLAG_RAW + */ + uint16_t aac_fmt_flag; + + /* + * Number of channels to encode. + * Supported values: + * 0 - Native mode + * 1 - Mono + * 2 - Stereo + * Other values are not supported. + * @note1hang The eAAC+ encoder mode supports only stereo. + * Native mode indicates that encoding must be performed with the + * number of channels at the input. + * The number of channels must not change during encoding. + */ + uint32_t channel_cfg; + + /* + * Number of samples per second. + * Supported values: - 0 -- Native mode - For other values, + * Native mode indicates that encoding must be performed with the + * sampling rate at the input. + * The sampling rate must not change during encoding. + */ + uint32_t sample_rate; +} __packed; + +/* FMT ID for apt-X Classic */ +#define ASM_MEDIA_FMT_APTX 0x000131ff + +/* FMT ID for apt-X HD */ +#define ASM_MEDIA_FMT_APTX_HD 0x00013200 + +#define PCM_CHANNEL_L 1 +#define PCM_CHANNEL_R 2 +#define PCM_CHANNEL_C 3 + +struct asm_custom_enc_cfg_aptx_t { + uint32_t sample_rate; + /* Mono or stereo */ + uint16_t num_channels; + uint16_t reserved; + /* num_ch == 1, then PCM_CHANNEL_C, + * num_ch == 2, then {PCM_CHANNEL_L, PCM_CHANNEL_R} + */ + uint8_t channel_mapping[8]; + uint32_t custom_size; +} __packed; + +struct afe_enc_fmt_id_param_t { + /* + * Supported values: + * #ASM_MEDIA_FMT_SBC + * #ASM_MEDIA_FMT_AAC_V2 + * Any OpenDSP supported values + */ + uint32_t fmt_id; +} __packed; + +struct afe_port_media_type_t { + /* + * Minor version + * @values #AFE_API_VERSION_PORT_MEDIA_TYPE. + */ + uint32_t minor_version; + + /* + * Sampling rate of the port. + * @values + * #AFE_PORT_SAMPLE_RATE_8K + * #AFE_PORT_SAMPLE_RATE_11_025K + * #AFE_PORT_SAMPLE_RATE_12K + * #AFE_PORT_SAMPLE_RATE_16K + * #AFE_PORT_SAMPLE_RATE_22_05K + * #AFE_PORT_SAMPLE_RATE_24K + * #AFE_PORT_SAMPLE_RATE_32K + * #AFE_PORT_SAMPLE_RATE_44_1K + * #AFE_PORT_SAMPLE_RATE_48K + * #AFE_PORT_SAMPLE_RATE_88_2K + * #AFE_PORT_SAMPLE_RATE_96K + * #AFE_PORT_SAMPLE_RATE_176_4K + * #AFE_PORT_SAMPLE_RATE_192K + * #AFE_PORT_SAMPLE_RATE_352_8K + * #AFE_PORT_SAMPLE_RATE_384K + */ + uint32_t sample_rate; + + /* + * Bit width of the sample. + * @values 16, 24 + */ + uint16_t bit_width; + + /* + * Number of channels. + * @values 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT + */ + uint16_t num_channels; + + /* + * Data format supported by this port. + * If the port media type and device media type are different, + * it signifies a encoding/decoding use case + * @values + * #AFE_PORT_DATA_FORMAT_PCM + * #AFE_PORT_DATA_FORMAT_GENERIC_COMPRESSED + */ + uint16_t data_format; + + /*This field must be set to zero.*/ + uint16_t reserved; +} __packed; + +union afe_enc_config_data { + struct asm_sbc_enc_cfg_t sbc_config; + struct asm_aac_enc_cfg_v2_t aac_config; + struct asm_custom_enc_cfg_aptx_t aptx_config; +}; + +struct afe_enc_config { + u32 format; + union afe_enc_config_data data; +}; + +struct afe_enc_cfg_blk_param_t { + uint32_t enc_cfg_blk_size; + /* + *Size of the encoder configuration block that follows this member + */ + union afe_enc_config_data enc_blk_config; +}; + +/* + * Payload of the AVS_ENCODER_PARAM_ID_PACKETIZER_ID parameter. + */ +struct avs_enc_packetizer_id_param_t { + /* + * Supported values: + * #AVS_MODULE_ID_PACKETIZER_COP + * Any OpenDSP supported values + */ + uint32_t enc_packetizer_id; +}; + union afe_port_config { struct afe_param_id_pcm_cfg pcm; struct afe_param_id_i2s_cfg i2s; @@ -2751,6 +3078,10 @@ union afe_port_config { struct afe_param_id_set_topology_cfg topology; struct afe_param_id_tdm_cfg tdm; struct afe_param_id_usb_audio_cfg usb_audio; + struct afe_enc_fmt_id_param_t enc_fmt; + struct afe_port_media_type_t media_type; + struct afe_enc_cfg_blk_param_t enc_blk_param; + struct avs_enc_packetizer_id_param_t enc_pkt_id_param; } __packed; struct afe_audioif_config_command_no_payload { diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h index 5cd65357dd95..6be903a4c8d0 100644 --- a/include/sound/q6afe-v2.h +++ b/include/sound/q6afe-v2.h @@ -274,6 +274,9 @@ int afe_rt_proxy_port_read(phys_addr_t buf_addr_p, void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode); int afe_port_start(u16 port_id, union afe_port_config *afe_config, u32 rate); +int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config, + u32 rate, u16 afe_in_channels, + struct afe_enc_config *enc_config); int afe_spk_prot_feed_back_cfg(int src_port, int dst_port, int l_ch, int r_ch, u32 enable); int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib); diff --git a/include/uapi/linux/mfd/wcd9xxx/Kbuild b/include/uapi/linux/mfd/wcd9xxx/Kbuild index da9fe03b0bed..8e55965bbe7e 100755 --- a/include/uapi/linux/mfd/wcd9xxx/Kbuild +++ b/include/uapi/linux/mfd/wcd9xxx/Kbuild @@ -1 +1,2 @@ +header-y += wcd9xxx_registers.h header-y += wcd9320_registers.h diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h index 1dac14bd8427..a9fe10d8cd6e 100755..100644 --- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h +++ b/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h @@ -330,6 +330,8 @@ #define WCD9XXX_A_ANA_HPH (0x609) #define WCD9XXX_A_CDC_CLSH_CRC (0xC01) #define WCD9XXX_FLYBACK_EN (0x6A4) +#define WCD9XXX_FLYBACK_VNEG_CTRL_1 (0x6A5) +#define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 (0x6AF) #define WCD9XXX_RX_BIAS_FLYB_BUFF (0x6C7) #define WCD9XXX_HPH_L_EN (0x6D3) #define WCD9XXX_HPH_R_EN (0x6D6) @@ -341,4 +343,13 @@ #define WCD9XXX_CDC_RX2_RX_PATH_CTL (0xB69) #define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL (0xD41) #define WCD9XXX_CLASSH_CTRL_CCL_1 (0x69C) + +/* RX Gain control registers of codecs from and above WCD9335 */ +#define WCD9XXX_CDC_RX1_RX_VOL_CTL (0xB59) +#define WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL (0xB5C) +#define WCD9XXX_CDC_RX1_RX_PATH_SEC1 (0xB5E) +#define WCD9XXX_CDC_RX2_RX_VOL_CTL (0xB6D) +#define WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL (0xB70) +#define WCD9XXX_CDC_RX2_RX_PATH_SEC1 (0xB72) + #endif diff --git a/kernel/cpu.c b/kernel/cpu.c index 37731292f8a1..1cfd381642da 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -365,21 +365,6 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) goto out_release; } - /* - * By now we've cleared cpu_active_mask, wait for all preempt-disabled - * and RCU users of this state to go away such that all new such users - * will observe it. - * - * For CONFIG_PREEMPT we have preemptible RCU and its sync_rcu() might - * not imply sync_sched(), so wait for both. - * - * Do sync before park smpboot threads to take care the rcu boost case. - */ - if (IS_ENABLED(CONFIG_PREEMPT)) - synchronize_rcu_mult(call_rcu, call_rcu_sched); - else - synchronize_rcu(); - smpboot_park_threads(cpu); /* diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 2ade632197d5..2df78d45a096 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -2075,12 +2075,30 @@ static void cpuset_bind(struct cgroup_subsys_state *root_css) mutex_unlock(&cpuset_mutex); } +static int cpuset_allow_attach(struct cgroup_taskset *tset) +{ + const struct cred *cred = current_cred(), *tcred; + struct task_struct *task; + struct cgroup_subsys_state *css; + + cgroup_taskset_for_each(task, css, tset) { + tcred = __task_cred(task); + + if ((current != task) && !capable(CAP_SYS_ADMIN) && + cred->euid.val != tcred->uid.val && cred->euid.val != tcred->suid.val) + return -EACCES; + } + + return 0; +} + struct cgroup_subsys cpuset_cgrp_subsys = { .css_alloc = cpuset_css_alloc, .css_online = cpuset_css_online, .css_offline = cpuset_css_offline, .css_free = cpuset_css_free, .can_attach = cpuset_can_attach, + .allow_attach = cpuset_allow_attach, .cancel_attach = cpuset_cancel_attach, .attach = cpuset_attach, .bind = cpuset_bind, diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index bc0e504f33a6..80649934cf3b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -993,7 +993,7 @@ static struct genl_multicast_group genl_ctrl_groups[] = { static int genl_bind(struct net *net, int group) { - int i, err = -ENOENT; + int i, err = 0; down_read(&cb_lock); for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 1626d1553986..8e1aff46ac23 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -375,13 +375,13 @@ country DK: DFS-ETSI country DM: DFS-FCC (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (17), AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5735 - 5835 @ 80), (30) country DO: DFS-FCC (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (17), AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5735 - 5835 @ 80), (30) @@ -417,8 +417,8 @@ country EE: DFS-ETSI country EG: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (20) - (5250 - 5330 @ 20), (20), DFS + (5170 - 5250 @ 20), (23) + (5250 - 5330 @ 20), (23), DFS country ES: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -654,14 +654,14 @@ country IE: DFS-ETSI country IL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW country IN: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5735 - 5835 @ 80), (20) + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5735 - 5835 @ 80), (30) country IR: (2402 - 2482 @ 40), (20) @@ -737,8 +737,8 @@ country KH: DFS-ETSI country KN: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS (5735 - 5815 @ 80), (30) @@ -758,8 +758,8 @@ country KP: DFS-ETSI country KW: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW country KY: DFS-FCC (2402 - 2482 @ 40), (20) @@ -781,7 +781,7 @@ country LB: DFS-FCC country LC: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5250 - 5330 @ 80), (30), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS (5735 - 5815 @ 80), (30) @@ -866,8 +866,8 @@ country LV: DFS-ETSI country MA: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW country MC: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -984,19 +984,19 @@ country MX: DFS-FCC (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) -country NA: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5735 - 5815 @ 80), (30) - country MY: DFS-FCC (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (24), AUTO-BW (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5650 @ 160), (24), DFS - (5735 - 5835 @ 80), (24) + (5735 - 5815 @ 80), (24) + +country NA: DFS-ETSI + (2402 - 2482 @ 40), (20) + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5490 - 5710 @ 160), (30), DFS + (5735 - 5835 @ 80), (33) country NG: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1065,7 +1065,7 @@ country OM: DFS-ETSI country PA: DFS-FCC (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (17), AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5735 - 5835 @ 80), (30) @@ -1207,8 +1207,8 @@ country RS: DFS-ETSI country RU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5730 @ 160), (30), DFS (5735 - 5835 @ 80), (30) @@ -1298,7 +1298,7 @@ country SR: DFS-ETSI country SV: DFS-FCC (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (17) + (5170 - 5250 @ 20), (23) (5250 - 5330 @ 20), (23), DFS (5735 - 5835 @ 20), (30) @@ -1333,8 +1333,8 @@ country TH: DFS-FCC country TN: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW + (5250 - 5330 @ 80), (23), DFS, AUTO-BW country TR: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -1416,7 +1416,7 @@ country UY: DFS-FCC country UZ: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (20), DFS, AUTO-BW country VC: DFS-ETSI diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6fc326421108..dc6e95b977c9 100755 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -739,9 +739,6 @@ config SND_SOC_WSA881X_ANALOG tristate select REGMAP_I2C -config SND_SOC_MSM8X16_WCD - tristate - config SND_SOC_WCD9XXX tristate default y if SND_SOC_WCD9320=y || SND_SOC_WCD9330=y || SND_SOC_WCD9335=y @@ -984,4 +981,7 @@ config SND_SOC_MSM_HDMI_CODEC_RX help HDMI audio drivers should be built only if the platform supports hdmi panel. + +source "sound/soc/codecs/msm8x16/Kconfig" + endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4b79b277ce29..f237a2188fe1 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -140,7 +140,6 @@ audio-ext-clock-objs := audio-ext-clk.o snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o -snd-soc-msm8952-wcd-objs := msm8x16-wcd.o msm8x16-wcd-tables.o snd-soc-wsa881x-analog-objs := wsa881x-analog.o wsa881x-tables-analog.o snd-soc-wsa881x-analog-objs += wsa881x-regmap-analog.o wsa881x-irq.o snd-soc-wcd-dsp-utils-objs := wcd-dsp-utils.o @@ -348,7 +347,6 @@ obj-$(CONFIG_SND_SOC_WCD934X) += wcd934x/ obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock.o obj-$(CONFIG_SND_SOC_WCD9XXX) += snd-soc-wcd9xxx.o obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += snd-soc-wcd9xxx-v2.o -obj-$(CONFIG_SND_SOC_MSM8X16_WCD) += snd-soc-msm8952-wcd.o msm8916-wcd-irq.o obj-$(CONFIG_SND_SOC_WCD_CPE) += snd-soc-wcd-cpe.o obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o @@ -416,3 +414,4 @@ obj-$(CONFIG_SND_SOC_MSM_STUB) += snd-soc-msm-stub.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o +obj-y += msm8x16/ diff --git a/sound/soc/codecs/msm8x16/Kconfig b/sound/soc/codecs/msm8x16/Kconfig new file mode 100644 index 000000000000..d225b7a56925 --- /dev/null +++ b/sound/soc/codecs/msm8x16/Kconfig @@ -0,0 +1,3 @@ + +config SND_SOC_MSM8X16_WCD + tristate "MSM Internal PMIC based codec" diff --git a/sound/soc/codecs/msm8x16/Makefile b/sound/soc/codecs/msm8x16/Makefile new file mode 100644 index 000000000000..36a3d046a307 --- /dev/null +++ b/sound/soc/codecs/msm8x16/Makefile @@ -0,0 +1,3 @@ +snd-soc-msm8952-wcd-objs := msm8x16-wcd.o msm8x16-wcd-tables.o msm89xx-regmap.o +obj-$(CONFIG_SND_SOC_MSM8X16_WCD) += snd-soc-msm8952-wcd.o msm8916-wcd-irq.o + diff --git a/sound/soc/codecs/msm8916-wcd-irq.c b/sound/soc/codecs/msm8x16/msm8916-wcd-irq.c index 8fbd72964108..a722842b106b 100644 --- a/sound/soc/codecs/msm8916-wcd-irq.c +++ b/sound/soc/codecs/msm8x16/msm8916-wcd-irq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-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 @@ -56,20 +56,20 @@ char *irq_names[MAX_NUM_IRQS] = { }; int order[MAX_NUM_IRQS] = { - MSM8X16_WCD_IRQ_SPKR_CNP, - 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, - 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, + MSM89XX_IRQ_SPKR_CNP, + MSM89XX_IRQ_SPKR_CLIP, + MSM89XX_IRQ_SPKR_OCP, + MSM89XX_IRQ_MBHC_INSREM_DET1, + MSM89XX_IRQ_MBHC_RELEASE, + MSM89XX_IRQ_MBHC_PRESS, + MSM89XX_IRQ_MBHC_INSREM_DET, + MSM89XX_IRQ_MBHC_HS_DET, + MSM89XX_IRQ_EAR_OCP, + MSM89XX_IRQ_HPHR_OCP, + MSM89XX_IRQ_HPHL_OCP, + MSM89XX_IRQ_EAR_CNP, + MSM89XX_IRQ_HPHR_CNP, + MSM89XX_IRQ_HPHL_CNP, }; enum wcd9xxx_spmi_pm_state { @@ -101,18 +101,18 @@ void wcd9xxx_spmi_enable_irq(int irq) pr_debug("%s: irqno =%d\n", __func__, irq); if ((irq >= 0) && (irq <= 7)) { snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_DIGITAL_INT_EN_CLR, + MSM89XX_PMIC_DIGITAL_INT_EN_CLR, (0x01 << irq), 0x00); snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_DIGITAL_INT_EN_SET, + MSM89XX_PMIC_DIGITAL_INT_EN_SET, (0x01 << irq), (0x01 << irq)); } if ((irq > 7) && (irq <= 15)) { snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_ANALOG_INT_EN_CLR, + MSM89XX_PMIC_ANALOG_INT_EN_CLR, (0x01 << (irq - 8)), 0x00); snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_ANALOG_INT_EN_SET, + MSM89XX_PMIC_ANALOG_INT_EN_SET, (0x01 << (irq - 8)), (0x01 << (irq - 8))); } @@ -130,19 +130,19 @@ void wcd9xxx_spmi_disable_irq(int irq) pr_debug("%s: irqno =%d\n", __func__, irq); if ((irq >= 0) && (irq <= 7)) { snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_DIGITAL_INT_EN_SET, + MSM89XX_PMIC_DIGITAL_INT_EN_SET, (0x01 << (irq)), 0x00); snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_DIGITAL_INT_EN_CLR, + MSM89XX_PMIC_DIGITAL_INT_EN_CLR, (0x01 << irq), (0x01 << irq)); } if ((irq > 7) && (irq <= 15)) { snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_ANALOG_INT_EN_SET, + MSM89XX_PMIC_ANALOG_INT_EN_SET, (0x01 << (irq - 8)), 0x00); snd_soc_update_bits(map.codec, - MSM8X16_WCD_A_ANALOG_INT_EN_CLR, + MSM89XX_PMIC_ANALOG_INT_EN_CLR, (0x01 << (irq - 8)), (0x01 << (irq - 8))); } @@ -161,10 +161,6 @@ int wcd9xxx_spmi_request_irq(int irq, irq_handler_t handler, int rc; unsigned long irq_flags; - map.linuxirq[irq] = - spmi_get_irq_byname(map.spmi[BIT_BYTE(irq)], NULL, - irq_names[irq]); - if (strcmp(name, "mbhc sw intr")) irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT; @@ -234,7 +230,7 @@ static irqreturn_t wcd9xxx_spmi_irq_handler(int linux_irq, void *data) for (i = 0; i < NUM_IRQ_REGS; i++) { status[i] |= snd_soc_read(map.codec, BIT_BYTE(irq) * 0x100 + - MSM8X16_WCD_A_DIGITAL_INT_LATCHED_STS); + MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS); status[i] &= ~map.mask[i]; } for (i = 0; i < MAX_NUM_IRQS; i++) { @@ -418,10 +414,10 @@ void wcd9xxx_spmi_set_codec(struct snd_soc_codec *codec) map.codec = codec; } -void wcd9xxx_spmi_set_dev(struct platform_device *pdev, int i) +void wcd9xxx_spmi_set_dev(struct spmi_device *spmi, int i) { if (i < NUM_IRQ_REGS) - map.spmi[i] = pdev; + map.spmi[i] = spmi; } int wcd9xxx_spmi_irq_init(void) diff --git a/sound/soc/codecs/msm8916-wcd-irq.h b/sound/soc/codecs/msm8x16/msm8916-wcd-irq.h index 659e52cc2a5e..659e52cc2a5e 100644 --- a/sound/soc/codecs/msm8916-wcd-irq.h +++ b/sound/soc/codecs/msm8x16/msm8916-wcd-irq.h diff --git a/sound/soc/codecs/msm8x16/msm89xx-regmap.c b/sound/soc/codecs/msm8x16/msm89xx-regmap.c new file mode 100644 index 000000000000..007b74c8b867 --- /dev/null +++ b/sound/soc/codecs/msm8x16/msm89xx-regmap.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2015-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/regmap.h> +#include <linux/device.h> +#include "msm8x16-wcd.h" + +/* + * Default register reset values that are common across different versions + * are defined here. If a register reset value is changed based on version + * then remove it from this structure and add it in version specific + * structures. + */ +static struct reg_default + msm89xx_cdc_core_defaults[MSM89XX_CDC_CORE_CACHE_SIZE] = { + {MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x13}, + {MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 0x13}, + {MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_OTHR_CTL, 0x04}, + {MSM89XX_CDC_CORE_CLK_RX_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_SD_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_B5_CTL, 0x68}, + {MSM89XX_CDC_CORE_RX2_B5_CTL, 0x68}, + {MSM89XX_CDC_CORE_RX3_B5_CTL, 0x68}, + {MSM89XX_CDC_CORE_RX1_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_TOP_GAIN_UPDATE, 0x00}, + {MSM89XX_CDC_CORE_TOP_CTL, 0x01}, + {MSM89XX_CDC_CORE_COMP0_B1_CTL, 0x30}, + {MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xB5}, + {MSM89XX_CDC_CORE_COMP0_B3_CTL, 0x28}, + {MSM89XX_CDC_CORE_COMP0_B4_CTL, 0x37}, + {MSM89XX_CDC_CORE_COMP0_B5_CTL, 0x7F}, + {MSM89XX_CDC_CORE_COMP0_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS, 0x03}, + {MSM89XX_CDC_CORE_COMP0_FS_CFG, 0x03}, + {MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL, 0x02}, + {MSM89XX_CDC_CORE_DEBUG_DESER1_CTL, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_DESER2_CTL, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_CTL, 0x40}, + {MSM89XX_CDC_CORE_IIR2_CTL, 0x40}, + {MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX1_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX1_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX1_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX2_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX2_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_RX3_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_TX_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL, 0x00}, + {MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER, 0x00}, + {MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN, 0x00}, + {MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG, 0x00}, + {MSM89XX_CDC_CORE_TX1_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX2_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX3_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX4_MUX_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX1_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX2_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX3_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX4_CLK_FS_CTL, 0x03}, + {MSM89XX_CDC_CORE_TX1_DMIC_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX2_DMIC_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX3_DMIC_CTL, 0x00}, + {MSM89XX_CDC_CORE_TX4_DMIC_CTL, 0x00}, +}; + +static struct reg_default + msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE] = { + {MSM89XX_PMIC_DIGITAL_REVISION1, 0x00}, + {MSM89XX_PMIC_DIGITAL_REVISION2, 0x00}, + {MSM89XX_PMIC_DIGITAL_PERPH_TYPE, 0x23}, + {MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE, 0x01}, + {MSM89XX_PMIC_DIGITAL_INT_RT_STS, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_SET_TYPE, 0xFF}, + {MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH, 0xFF}, + {MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_EN_SET, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_EN_CLR, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_PENDING_STS, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_MID_SEL, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_PRIORITY, 0x00}, + {MSM89XX_PMIC_DIGITAL_GPIO_MODE, 0x00}, + {MSM89XX_PMIC_DIGITAL_PIN_CTL_OE, 0x01}, + {MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA, 0x00}, + {MSM89XX_PMIC_DIGITAL_PIN_STATUS, 0x00}, + {MSM89XX_PMIC_DIGITAL_HDRIVE_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL, 0x02}, + {MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL, 0x02}, + {MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1, 0x7C}, + {MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2, 0x7C}, + {MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3, 0x7C}, + {MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0, 0x00}, + {MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1, 0x00}, + {MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2, 0x00}, + {MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3, 0x00}, + {MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL, 0x00}, + {MSM89XX_PMIC_DIGITAL_DIG_DEBUG_EN, 0x00}, + {MSM89XX_PMIC_DIGITAL_SPARE_0, 0x00}, + {MSM89XX_PMIC_DIGITAL_SPARE_1, 0x00}, + {MSM89XX_PMIC_DIGITAL_SPARE_2, 0x00}, + {MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0x00}, + {MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL1, 0x00}, + {MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL2, 0x02}, + {MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x05}, + {MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_TEST1, 0x00}, + {MSM89XX_PMIC_DIGITAL_INT_TEST_VAL, 0x00}, + {MSM89XX_PMIC_DIGITAL_TRIM_NUM, 0x00}, + {MSM89XX_PMIC_DIGITAL_TRIM_CTRL, 0x00}, + {MSM89XX_PMIC_ANALOG_REVISION1, 0x00}, + {MSM89XX_PMIC_ANALOG_REVISION2, 0x00}, + {MSM89XX_PMIC_ANALOG_REVISION3, 0x00}, + {MSM89XX_PMIC_ANALOG_REVISION4, 0x00}, + {MSM89XX_PMIC_ANALOG_PERPH_TYPE, 0x23}, + {MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x09}, + {MSM89XX_PMIC_ANALOG_INT_RT_STS, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_SET_TYPE, 0x3F}, + {MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH, 0x3F}, + {MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_EN_SET, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_EN_CLR, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_LATCHED_STS, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_PENDING_STS, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_MID_SEL, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_PRIORITY, 0x00}, + {MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x00}, + {MSM89XX_PMIC_ANALOG_MICB_1_VAL, 0x20}, + {MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x00}, + {MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS, 0x49}, + {MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20}, + {MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2, 0x00}, + {MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x00}, + {MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x35}, + {MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08}, + {MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x00}, + {MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x98}, + {MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, 0x00}, + {MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL, 0x20}, + {MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, 0x40}, + {MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x61}, + {MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL, 0x80}, + {MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0x00}, + {MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x00}, + {MSM89XX_PMIC_ANALOG_TX_1_EN, 0x03}, + {MSM89XX_PMIC_ANALOG_TX_2_EN, 0x03}, + {MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1, 0xBF}, + {MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2, 0x8C}, + {MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL, 0x00}, + {MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x6B}, + {MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV, 0x51}, + {MSM89XX_PMIC_ANALOG_TX_3_EN, 0x02}, + {MSM89XX_PMIC_ANALOG_NCP_EN, 0x26}, + {MSM89XX_PMIC_ANALOG_NCP_CLK, 0x23}, + {MSM89XX_PMIC_ANALOG_NCP_DEGLITCH, 0x5B}, + {MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x08}, + {MSM89XX_PMIC_ANALOG_NCP_BIAS, 0x29}, + {MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0x24}, + {MSM89XX_PMIC_ANALOG_NCP_TEST, 0x00}, + {MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR, 0xD5}, + {MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER, 0xE8}, + {MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xCF}, + {MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0x6E}, + {MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, 0x18}, + {MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0x5A}, + {MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP, 0x69}, + {MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP, 0x29}, + {MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x80}, + {MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL, 0xDA}, + {MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0x16}, + {MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x00}, + {MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20}, + {MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x00}, + {MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20}, + {MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12}, + {MSM89XX_PMIC_ANALOG_RX_ATEST, 0x00}, + {MSM89XX_PMIC_ANALOG_RX_HPH_STATUS, 0x0C}, + {MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x00}, + {MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x00}, + {MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x00}, + {MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x83}, + {MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET, 0x91}, + {MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x29}, + {MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x4D}, + {MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1}, + {MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x1E}, + {MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC, 0xCB}, + {MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x00}, + {MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x02}, + {MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE, 0x14}, + {MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x00}, + {MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x1F}, + {MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x8C}, + {MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE, 0xC0}, + {MSM89XX_PMIC_ANALOG_BOOST_TEST1_1, 0x00}, + {MSM89XX_PMIC_ANALOG_BOOST_TEST_2, 0x00}, + {MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS, 0x00}, + {MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS, 0x00}, + {MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR, 0x00}, + {MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL, 0x00}, + {MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0x00}, + {MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL1, 0x00}, + {MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL2, 0x01}, + {MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x05}, + {MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_TEST1, 0x00}, + {MSM89XX_PMIC_ANALOG_INT_TEST_VAL, 0x00}, + {MSM89XX_PMIC_ANALOG_TRIM_NUM, 0x04}, + {MSM89XX_PMIC_ANALOG_TRIM_CTRL1, 0x00}, + {MSM89XX_PMIC_ANALOG_TRIM_CTRL2, 0x00}, + {MSM89XX_PMIC_ANALOG_TRIM_CTRL3, 0x00}, + {MSM89XX_PMIC_ANALOG_TRIM_CTRL4, 0x00}, +}; + +static bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg) +{ + return msm89xx_cdc_core_reg_readable[reg]; +} + +static bool msm89xx_pmic_cdc_readable_reg(struct device *dev, unsigned int reg) +{ + return msm89xx_pmic_cdc_reg_readable[reg]; +} + +static bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MSM89XX_CDC_CORE_RX1_B1_CTL: + case MSM89XX_CDC_CORE_RX2_B1_CTL: + case MSM89XX_CDC_CORE_RX3_B1_CTL: + case MSM89XX_CDC_CORE_RX1_B6_CTL: + case MSM89XX_CDC_CORE_RX2_B6_CTL: + case MSM89XX_CDC_CORE_RX3_B6_CTL: + case MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG: + case MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG: + case MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL: + case MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL: + case MSM89XX_CDC_CORE_CLK_MCLK_CTL: + case MSM89XX_CDC_CORE_CLK_PDM_CTL: + case MSM89XX_PMIC_ANALOG_BYPASS_MODE: + case MSM89XX_PMIC_ANALOG_BOOST_EN_CTL: + case MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL: + case MSM89XX_PMIC_ANALOG_CURRENT_LIMIT: + case MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL: + case MSM89XX_PMIC_ANALOG_NCP_FBCTRL: + case MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1: + return true; + default: + return false; + } +} + +static bool msm89xx_pmic_cdc_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MSM89XX_PMIC_DIGITAL_REVISION1: + case MSM89XX_PMIC_DIGITAL_REVISION2: + case MSM89XX_PMIC_DIGITAL_PERPH_TYPE: + case MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE: + case MSM89XX_PMIC_DIGITAL_INT_RT_STS: + case MSM89XX_PMIC_DIGITAL_INT_SET_TYPE: + case MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH: + case MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW: + case MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS: + case MSM89XX_PMIC_DIGITAL_INT_PENDING_STS: + case MSM89XX_PMIC_DIGITAL_PIN_STATUS: + case MSM89XX_PMIC_DIGITAL_SEC_ACCESS: + case MSM89XX_PMIC_ANALOG_SEC_ACCESS: + case MSM89XX_PMIC_ANALOG_REVISION1: + case MSM89XX_PMIC_ANALOG_REVISION2: + case MSM89XX_PMIC_ANALOG_REVISION3: + case MSM89XX_PMIC_ANALOG_REVISION4: + case MSM89XX_PMIC_ANALOG_PERPH_TYPE: + case MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE: + case MSM89XX_PMIC_ANALOG_INT_RT_STS: + case MSM89XX_PMIC_ANALOG_INT_SET_TYPE: + case MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH: + case MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW: + case MSM89XX_PMIC_ANALOG_INT_LATCHED_STS: + case MSM89XX_PMIC_ANALOG_INT_PENDING_STS: + case MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT: + case MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT: + case MSM89XX_PMIC_ANALOG_RX_HPH_STATUS: + case MSM89XX_PMIC_ANALOG_RX_EAR_STATUS: + case MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS: + case MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS: + return true; + default: + return false; + } +} + +struct regmap_config msm89xx_pmic_cdc_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MSM89XX_PMIC_CDC_CACHE_SIZE, + .fast_io = true, + .reg_defaults = msm89xx_pmic_cdc_defaults, + .num_reg_defaults = ARRAY_SIZE(msm89xx_pmic_cdc_defaults), + .readable_reg = msm89xx_pmic_cdc_readable_reg, + .volatile_reg = msm89xx_pmic_cdc_volatile_reg, + .cache_type = REGCACHE_RBTREE, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .can_multi_write = true, + .lock = enable_digital_callback, + .unlock = disable_digital_callback, + +}; + +struct regmap_config msm89xx_cdc_core_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = MSM89XX_CDC_CORE_CACHE_SIZE, + .reg_defaults = msm89xx_cdc_core_defaults, + .num_reg_defaults = ARRAY_SIZE(msm89xx_cdc_core_defaults), + .readable_reg = msm89xx_cdc_core_readable_reg, + .volatile_reg = msm89xx_cdc_core_volatile_reg, + .cache_type = REGCACHE_RBTREE, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .can_multi_write = true, +}; diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c b/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c new file mode 100644 index 000000000000..b969639b10eb --- /dev/null +++ b/sound/soc/codecs/msm8x16/msm8x16-wcd-tables.c @@ -0,0 +1,263 @@ +/* Copyright (c) 2015-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 "msm8x16-wcd.h" + +const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE] = { + [MSM89XX_PMIC_DIGITAL_REVISION1] = 1, + [MSM89XX_PMIC_DIGITAL_REVISION2] = 1, + [MSM89XX_PMIC_DIGITAL_PERPH_TYPE] = 1, + [MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE] = 1, + [MSM89XX_PMIC_DIGITAL_INT_RT_STS] = 1, + [MSM89XX_PMIC_DIGITAL_INT_SET_TYPE] = 1, + [MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH] = 1, + [MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW] = 1, + [MSM89XX_PMIC_DIGITAL_INT_EN_SET] = 1, + [MSM89XX_PMIC_DIGITAL_INT_EN_CLR] = 1, + [MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS] = 1, + [MSM89XX_PMIC_DIGITAL_INT_PENDING_STS] = 1, + [MSM89XX_PMIC_DIGITAL_INT_MID_SEL] = 1, + [MSM89XX_PMIC_DIGITAL_INT_PRIORITY] = 1, + [MSM89XX_PMIC_DIGITAL_GPIO_MODE] = 1, + [MSM89XX_PMIC_DIGITAL_PIN_CTL_OE] = 1, + [MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA] = 1, + [MSM89XX_PMIC_DIGITAL_PIN_STATUS] = 1, + [MSM89XX_PMIC_DIGITAL_HDRIVE_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_RST_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2] = 1, + [MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3] = 1, + [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0] = 1, + [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1] = 1, + [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2] = 1, + [MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3] = 1, + [MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_SPARE_0] = 1, + [MSM89XX_PMIC_DIGITAL_SPARE_1] = 1, + [MSM89XX_PMIC_DIGITAL_SPARE_2] = 1, + [MSM89XX_PMIC_ANALOG_REVISION1] = 1, + [MSM89XX_PMIC_ANALOG_REVISION2] = 1, + [MSM89XX_PMIC_ANALOG_REVISION3] = 1, + [MSM89XX_PMIC_ANALOG_REVISION4] = 1, + [MSM89XX_PMIC_ANALOG_PERPH_TYPE] = 1, + [MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE] = 1, + [MSM89XX_PMIC_ANALOG_INT_RT_STS] = 1, + [MSM89XX_PMIC_ANALOG_INT_SET_TYPE] = 1, + [MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH] = 1, + [MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW] = 1, + [MSM89XX_PMIC_ANALOG_INT_EN_SET] = 1, + [MSM89XX_PMIC_ANALOG_INT_EN_CLR] = 1, + [MSM89XX_PMIC_ANALOG_INT_LATCHED_STS] = 1, + [MSM89XX_PMIC_ANALOG_INT_PENDING_STS] = 1, + [MSM89XX_PMIC_ANALOG_INT_MID_SEL] = 1, + [MSM89XX_PMIC_ANALOG_INT_PRIORITY] = 1, + [MSM89XX_PMIC_ANALOG_MICB_1_EN] = 1, + [MSM89XX_PMIC_ANALOG_MICB_1_VAL] = 1, + [MSM89XX_PMIC_ANALOG_MICB_1_CTL] = 1, + [MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS] = 1, + [MSM89XX_PMIC_ANALOG_MICB_2_EN] = 1, + [MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT] = 1, + [MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT] = 1, + [MSM89XX_PMIC_ANALOG_TX_1_EN] = 1, + [MSM89XX_PMIC_ANALOG_TX_2_EN] = 1, + [MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1] = 1, + [MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2] = 1, + [MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL] = 1, + [MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS] = 1, + [MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV] = 1, + [MSM89XX_PMIC_ANALOG_TX_3_EN] = 1, + [MSM89XX_PMIC_ANALOG_NCP_EN] = 1, + [MSM89XX_PMIC_ANALOG_NCP_CLK] = 1, + [MSM89XX_PMIC_ANALOG_NCP_DEGLITCH] = 1, + [MSM89XX_PMIC_ANALOG_NCP_FBCTRL] = 1, + [MSM89XX_PMIC_ANALOG_NCP_BIAS] = 1, + [MSM89XX_PMIC_ANALOG_NCP_VCTRL] = 1, + [MSM89XX_PMIC_ANALOG_NCP_TEST] = 1, + [MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER] = 1, + [MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL] = 1, + [MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT] = 1, + [MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL] = 1, + [MSM89XX_PMIC_ANALOG_RX_EAR_CTL] = 1, + [MSM89XX_PMIC_ANALOG_RX_ATEST] = 1, + [MSM89XX_PMIC_ANALOG_RX_HPH_STATUS] = 1, + [MSM89XX_PMIC_ANALOG_RX_EAR_STATUS] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG] = 1, + [MSM89XX_PMIC_ANALOG_CURRENT_LIMIT] = 1, + [MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE] = 1, + [MSM89XX_PMIC_ANALOG_BYPASS_MODE] = 1, + [MSM89XX_PMIC_ANALOG_BOOST_EN_CTL] = 1, + [MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO] = 1, + [MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE] = 1, + [MSM89XX_PMIC_ANALOG_BOOST_TEST1_1] = 1, + [MSM89XX_PMIC_ANALOG_BOOST_TEST_2] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS] = 1, + [MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS] = 1, + [MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR] = 1, + [MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL] = 1, + [MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL] = 1, + [MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR] = 1, + [MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR] = 1, + [MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR] = 1, + [MSM89XX_PMIC_DIGITAL_SEC_ACCESS] = 1, + [MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3] = 1, + [MSM89XX_PMIC_ANALOG_SEC_ACCESS] = 1, +}; + +const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = { + [MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_SD_CTL] = 1, + [MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B3_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B4_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B5_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_B6_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1, + [MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1, + [MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1, + [MSM89XX_CDC_CORE_TOP_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1, + [MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1, + [MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1, + [MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1, + [MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1, + [MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1, + [MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1, + [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1, +}; diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.c b/sound/soc/codecs/msm8x16/msm8x16-wcd.c new file mode 100644 index 000000000000..481e1efdf015 --- /dev/null +++ b/sound/soc/codecs/msm8x16/msm8x16-wcd.c @@ -0,0 +1,6037 @@ +/* Copyright (c) 2015-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/init.h> +#include <linux/firmware.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/printk.h> +#include <linux/ratelimit.h> +#include <linux/debugfs.h> +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/spmi.h> +#include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> +#include <linux/mfd/wcd9xxx/core.h> +#include <linux/qdsp6v2/apr.h> +#include <linux/timer.h> +#include <linux/workqueue.h> +#include <linux/sched.h> +#include <sound/q6afe-v2.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> +#include <sound/q6core.h> +#include <soc/qcom/subsystem_notif.h> +#include "msm8x16-wcd.h" +#include "../wcd-mbhc-v2.h" +#include "msm8916-wcd-irq.h" + +#define DRV_NAME "msm-codec" +#define MSM89XX_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) +#define MSM89XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +#define NUM_INTERPOLATORS 3 +#define BITS_PER_REG 8 +#define MSM89XX_TX_PORT_NUMBER 4 + +#define MSM89XX_I2S_MASTER_MODE_MASK 0x08 +#define MSM89XX_DIGITAL_CODEC_BASE_ADDR 0x771C000 +#define PMIC_SLAVE_ID_0 0 +#define PMIC_SLAVE_ID_1 1 + +#define PMIC_MBG_OK 0x2C08 +#define PMIC_LDO7_EN_CTL 0x4646 +#define MASK_MSB_BIT 0x80 + +#define CODEC_DT_MAX_PROP_SIZE 40 +#define MSM89XX_DIGITAL_CODEC_REG_SIZE 0x400 +#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64 + +#define MCLK_RATE_9P6MHZ 9600000 +#define MCLK_RATE_12P288MHZ 12288000 + +#define BUS_DOWN 1 + +/* + *50 Milliseconds sufficient for DSP bring up in the modem + * after Sub System Restart + */ +#define ADSP_STATE_READY_TIMEOUT_MS 50 + +#define HPHL_PA_DISABLE (0x01 << 1) +#define HPHR_PA_DISABLE (0x01 << 2) +#define EAR_PA_DISABLE (0x01 << 3) +#define SPKR_PA_DISABLE (0x01 << 4) + +enum { + BOOST_SWITCH = 0, + BOOST_ALWAYS, + BYPASS_ALWAYS, + BOOST_ON_FOREVER, +}; + +#define EAR_PMD 0 +#define EAR_PMU 1 +#define SPK_PMD 2 +#define SPK_PMU 3 + +#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 MSM89XX_MBHC_BTN_COARSE_ADJ 100 /* in mV */ +#define MSM89XX_MBHC_BTN_FINE_ADJ 12 /* in mV */ + +#define VOLTAGE_CONVERTER(value, min_value, step_size)\ + ((value - min_value)/step_size) + +enum { + AIF1_PB = 0, + AIF1_CAP, + AIF2_VIFEED, + NUM_CODEC_DAIS, +}; + +enum { + RX_MIX1_INP_SEL_ZERO = 0, + RX_MIX1_INP_SEL_IIR1, + RX_MIX1_INP_SEL_IIR2, + RX_MIX1_INP_SEL_RX1, + RX_MIX1_INP_SEL_RX2, + RX_MIX1_INP_SEL_RX3, +}; + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); +static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[]; +/* By default enable the internal speaker boost */ +static bool spkr_boost_en = true; + +#define MSM89XX_ACQUIRE_LOCK(x) \ + mutex_lock_nested(&x, SINGLE_DEPTH_NESTING) + +#define MSM89XX_RELEASE_LOCK(x) mutex_unlock(&x) + + +/* Codec supports 2 IIR filters */ +enum { + IIR1 = 0, + IIR2, + IIR_MAX, +}; + +/* Codec supports 5 bands */ +enum { + BAND1 = 0, + BAND2, + BAND3, + BAND4, + BAND5, + BAND_MAX, +}; + +struct hpf_work { + struct msm8x16_wcd_priv *msm8x16_wcd; + u32 decimator; + u8 tx_hpf_cut_of_freq; + struct delayed_work dwork; +}; + +static struct hpf_work tx_hpf_work[NUM_DECIMATORS]; + +static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = { + "cdc-vdd-mic-bias", +}; + +static unsigned long rx_digital_gain_reg[] = { + MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL, + MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL, + MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL, +}; + +static unsigned long tx_digital_gain_reg[] = { + MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN, + MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN, +}; + +enum { + MSM89XX_SPMI_DIGITAL = 0, + MSM89XX_SPMI_ANALOG, + MSM89XX_CODEC_CORE, + MAX_MSM89XX_DEVICE +}; + +static struct wcd_mbhc_register + wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = { + + WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x18, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x08, 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x01, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC", + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, 0x06, 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN", + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x80, 7, 0), + WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC", + MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0xF0, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC", + MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, 0x0C, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF", + MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL, 0x03, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT", + MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x01, + 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT", + MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x02, + 1, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT", + MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x08, + 3, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT", + MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0x04, + 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN", + MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT", + MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT, 0xFF, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL", + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT", + MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, 0xFF, + 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL", + MSM89XX_PMIC_ANALOG_MICB_2_EN, 0xC0, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME", + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFC, 2, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN", + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN", + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN", + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, 0x30, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE", + MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT, + 0x10, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_VREF", + 0, 0, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL", + MSM89XX_PMIC_ANALOG_MICB_2_EN, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", + 0, 0, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", + 0, 0, 0, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", + 0, 0, 0, 0), +}; + +struct msm8x16_wcd_spmi { + struct spmi_device *spmi; + int base; +}; + +/* Multiply gain_adj and offset by 1000 and 100 to avoid float arithmetic */ +static const struct wcd_imped_i_ref imped_i_ref[] = { + {I_h4_UA, 8, 800, 9000, 10000}, + {I_pt5_UA, 10, 100, 990, 4600}, + {I_14_UA, 17, 14, 1050, 700}, + {I_l4_UA, 10, 4, 1165, 110}, + {I_1_UA, 0, 1, 1200, 65}, +}; + +static const struct wcd_mbhc_intr intr_ids = { + .mbhc_sw_intr = MSM89XX_IRQ_MBHC_HS_DET, + .mbhc_btn_press_intr = MSM89XX_IRQ_MBHC_PRESS, + .mbhc_btn_release_intr = MSM89XX_IRQ_MBHC_RELEASE, + .mbhc_hs_ins_intr = MSM89XX_IRQ_MBHC_INSREM_DET1, + .mbhc_hs_rem_intr = MSM89XX_IRQ_MBHC_INSREM_DET, + .hph_left_ocp = MSM89XX_IRQ_HPHL_OCP, + .hph_right_ocp = MSM89XX_IRQ_HPHR_OCP, +}; + +static int msm_digcdc_clock_control(bool flag); +static int msm8x16_wcd_dt_parse_vreg_info(struct device *dev, + struct msm8x16_wcd_regulator *vreg, + const char *vreg_name, bool ondemand); +static struct msm8x16_wcd_pdata *msm8x16_wcd_populate_dt_pdata( + struct device *dev); +static int msm8x16_wcd_enable_ext_mb_source(struct snd_soc_codec *codec, + bool turn_on); +static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec); +static void msm8x16_wcd_set_micb_v(struct snd_soc_codec *codec); +static void msm8x16_wcd_set_boost_v(struct snd_soc_codec *codec); +static void msm8x16_wcd_set_auto_zeroing(struct snd_soc_codec *codec, + bool enable); +static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec, + bool micbias1, bool micbias2); +static bool msm8x16_wcd_use_mb(struct snd_soc_codec *codec); + +struct msm8x16_wcd_spmi msm8x16_wcd_modules[MAX_MSM89XX_DEVICE]; + +static void *adsp_state_notifier; + +static struct snd_soc_codec *registered_codec; +static struct snd_soc_codec *registered_digcodec; + +static int get_codec_version(struct msm8x16_wcd_priv *msm8x16_wcd) +{ + if (msm8x16_wcd->codec_version == DIANGU) + return DIANGU; + else if (msm8x16_wcd->codec_version == CAJON_2_0) + return CAJON_2_0; + else if (msm8x16_wcd->codec_version == CAJON) + return CAJON; + else if (msm8x16_wcd->codec_version == CONGA) + return CONGA; + else if (msm8x16_wcd->pmic_rev == TOMBAK_2_0) + return TOMBAK_2_0; + else if (msm8x16_wcd->pmic_rev == TOMBAK_1_0) + return TOMBAK_1_0; + + pr_err("%s: unsupported codec version\n", __func__); + return UNSUPPORTED; +} + +static int msm_digcdc_clock_control(bool flag) +{ + int ret = -EINVAL; + struct msm8916_asoc_mach_data *pdata = NULL; + + pdata = snd_soc_card_get_drvdata(registered_codec->component.card); + + if (flag) { + mutex_lock(&pdata->cdc_mclk_mutex); + if (atomic_read(&pdata->mclk_enabled) == false) { + if (pdata->afe_clk_ver == AFE_CLK_VERSION_V1) { + pdata->digital_cdc_clk.clk_val = + pdata->mclk_freq; + ret = afe_set_digital_codec_core_clock( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_clk); + } else { + pdata->digital_cdc_core_clk.enable = 1; + ret = afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + } + if (ret < 0) { + pr_err("failed to enable the MCLK\n"); + goto err; + } + pr_err("enabled digital codec core clk\n"); + atomic_set(&pdata->mclk_enabled, true); + schedule_delayed_work(&pdata->disable_mclk_work, 50); + } +err: + mutex_unlock(&pdata->cdc_mclk_mutex); + return ret; + } + return 0; +} + +void enable_digital_callback(void *flag) +{ + msm_digcdc_clock_control(true); +} + +void disable_digital_callback(void *flag) +{ + msm_digcdc_clock_control(false); +} + +static int snd_soc_read_wrapper(struct snd_soc_codec *codec, u16 reg) +{ + int ret = -EINVAL; + struct msm8x16_wcd *msm8x16_wcd = codec->control_data; + + pr_err("%s reg = %x\n", __func__, reg); + mutex_lock(&msm8x16_wcd->io_lock); + if (MSM89XX_IS_PMIC_CDC_REG(reg)) + ret = snd_soc_read(codec, reg); + else if (MSM89XX_IS_CDC_CORE_REG(reg)) + ret = snd_soc_read(registered_digcodec, reg); + mutex_unlock(&msm8x16_wcd->io_lock); + + return ret; +} + +static int snd_soc_write_wrapper(struct snd_soc_codec *codec, u16 reg, u8 val) +{ + int ret = -EINVAL; + struct msm8x16_wcd *msm8x16_wcd = codec->control_data; + + pr_err("%s reg = %x\n", __func__, reg); + mutex_lock(&msm8x16_wcd->io_lock); + if (MSM89XX_IS_PMIC_CDC_REG(reg)) + ret = snd_soc_write(codec, reg, val); + else if (MSM89XX_IS_CDC_CORE_REG(reg)) + ret = snd_soc_write(registered_digcodec, reg, val); + mutex_unlock(&msm8x16_wcd->io_lock); + + return ret; +} + +static int snd_soc_update_bits_wrapper(struct snd_soc_codec *codec, + u16 reg, u8 mask, u8 val) +{ + int ret = -EINVAL; + struct msm8x16_wcd *msm8x16_wcd = codec->control_data; + + pr_err("%s reg = %x\n", __func__, reg); + mutex_lock(&msm8x16_wcd->io_lock); + if (MSM89XX_IS_PMIC_CDC_REG(reg)) + ret = snd_soc_update_bits(codec, reg, mask, val); + else if (MSM89XX_IS_CDC_CORE_REG(reg)) + ret = snd_soc_update_bits(registered_digcodec, reg, mask, val); + mutex_unlock(&msm8x16_wcd->io_lock); + + return ret; +} + +static void wcd_mbhc_meas_imped(struct snd_soc_codec *codec, + s16 *impedance_l, s16 *impedance_r) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if ((msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_BOTH) || + (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL)) { + /* Enable ZDET_L_MEAS_EN */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x08, 0x08); + /* Wait for 2ms for measurement to complete */ + usleep_range(2000, 2100); + /* Read Left impedance value from Result1 */ + *impedance_l = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT); + /* Enable ZDET_R_MEAS_EN */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x08, 0x00); + } + if ((msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_BOTH) || + (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR)) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x04, 0x04); + /* Wait for 2ms for measurement to complete */ + usleep_range(2000, 2100); + /* Read Right impedance value from Result1 */ + *impedance_r = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x04, 0x00); + } +} + +static void msm8x16_set_ref_current(struct snd_soc_codec *codec, + enum wcd_curr_ref curr_ref) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + pr_err("%s: curr_ref: %d\n", __func__, curr_ref); + + if (get_codec_version(msm8x16_wcd) < CAJON) + pr_err("%s: Setting ref current not required\n", __func__); + + msm8x16_wcd->imped_i_ref = imped_i_ref[curr_ref]; + + switch (curr_ref) { + case I_h4_UA: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0x07, 0x01); + break; + case I_pt5_UA: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0x07, 0x04); + break; + case I_14_UA: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0x07, 0x03); + break; + case I_l4_UA: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0x07, 0x01); + break; + case I_1_UA: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0x07, 0x00); + break; + default: + pr_err("%s: No ref current set\n", __func__); + break; + } +} + +static bool msm8x16_adj_ref_current(struct snd_soc_codec *codec, + s16 *impedance_l, s16 *impedance_r) +{ + int i = 2; + s16 compare_imp = 0; + + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR) + compare_imp = *impedance_r; + else + compare_imp = *impedance_l; + + if (get_codec_version(msm8x16_wcd) < CAJON) { + pr_err("%s: Reference current adjustment not required\n", + __func__); + return false; + } + + while (compare_imp < imped_i_ref[i].min_val) { + msm8x16_set_ref_current(codec, + imped_i_ref[++i].curr_ref); + wcd_mbhc_meas_imped(codec, + impedance_l, impedance_r); + compare_imp = (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR) + ? *impedance_r : *impedance_l; + } + + return true; +} + +void msm8x16_wcd_spk_ext_pa_cb( + int (*codec_spk_ext_pa)(struct snd_soc_codec *codec, + int enable), struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + pr_err("%s: Enter\n", __func__); + msm8x16_wcd->codec_spk_ext_pa_cb = codec_spk_ext_pa; +} + +void msm8x16_wcd_hph_comp_cb( + int (*codec_hph_comp_gpio)(bool enable), struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + pr_err("%s: Enter\n", __func__); + msm8x16_wcd->codec_hph_comp_gpio = codec_hph_comp_gpio; +} + +static void msm8x16_wcd_compute_impedance(struct snd_soc_codec *codec, s16 l, + s16 r, uint32_t *zl, uint32_t *zr, bool high) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + uint32_t rl = 0, rr = 0; + struct wcd_imped_i_ref R = msm8x16_wcd->imped_i_ref; + int codec_ver = get_codec_version(msm8x16_wcd); + + switch (codec_ver) { + case TOMBAK_1_0: + case TOMBAK_2_0: + case CONGA: + if (high) { + pr_err("%s: This plug has high range impedance\n", + __func__); + rl = (uint32_t)(((100 * (l * 400 - 200))/96) - 230); + rr = (uint32_t)(((100 * (r * 400 - 200))/96) - 230); + } else { + pr_err("%s: This plug has low range impedance\n", + __func__); + rl = (uint32_t)(((1000 * (l * 2 - 1))/1165) - (13/10)); + rr = (uint32_t)(((1000 * (r * 2 - 1))/1165) - (13/10)); + } + break; + case CAJON: + case CAJON_2_0: + case DIANGU: + if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL) { + rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) - + (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN); + rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5))) + - R.offset * R.gain_adj)/(R.gain_adj * 100)); + } else if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR) { + rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5))) + - R.offset * R.gain_adj)/(R.gain_adj * 100)); + rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))- + (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN); + } else if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_NONE) { + rr = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * r - 5)) - + (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN); + rl = (uint32_t)(((DEFAULT_MULTIPLIER * (10 * l - 5))- + (DEFAULT_OFFSET * DEFAULT_GAIN))/DEFAULT_GAIN); + } else { + rr = (uint32_t)(((10000 * (R.multiplier * (10 * r - 5))) + - R.offset * R.gain_adj)/(R.gain_adj * 100)); + rl = (uint32_t)(((10000 * (R.multiplier * (10 * l - 5))) + - R.offset * R.gain_adj)/(R.gain_adj * 100)); + } + break; + default: + pr_err("%s: No codec mentioned\n", __func__); + break; + } + *zl = rl; + *zr = rr; +} + +static struct firmware_cal *msm8x16_wcd_get_hwdep_fw_cal( + struct snd_soc_codec *codec, + enum wcd_cal_type type) +{ + struct msm8x16_wcd_priv *msm8x16_wcd; + struct firmware_cal *hwdep_cal; + + if (!codec) { + pr_err("%s: NULL codec pointer\n", __func__); + return NULL; + } + msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + hwdep_cal = wcdcal_get_fw_cal(msm8x16_wcd->fw_data, type); + if (!hwdep_cal) { + dev_err(codec->dev, "%s: cal not sent by %d\n", + __func__, type); + return NULL; + } + return hwdep_cal; +} + +static void wcd9xxx_spmi_irq_control(struct snd_soc_codec *codec, + int irq, bool enable) +{ + if (enable) + wcd9xxx_spmi_enable_irq(irq); + else + wcd9xxx_spmi_disable_irq(irq); +} + +static void msm8x16_mbhc_clk_setup(struct snd_soc_codec *codec, + bool enable) +{ + if (enable) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x08, 0x08); + else + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x08, 0x00); +} + +static int msm8x16_mbhc_map_btn_code_to_num(struct snd_soc_codec *codec) +{ + int btn_code; + int btn; + + btn_code = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT); + + switch (btn_code) { + case 0: + btn = 0; + break; + case 1: + btn = 1; + break; + case 3: + btn = 2; + break; + case 7: + btn = 3; + break; + case 15: + btn = 4; + break; + default: + btn = -EINVAL; + break; + }; + + return btn; +} + +static bool msm8x16_spmi_lock_sleep(struct wcd_mbhc *mbhc, bool lock) +{ + if (lock) + return wcd9xxx_spmi_lock_sleep(); + wcd9xxx_spmi_unlock_sleep(); + return 0; +} + +static bool msm8x16_wcd_micb_en_status(struct wcd_mbhc *mbhc, int micb_num) +{ + if (micb_num == MIC_BIAS_1) + return (snd_soc_read_wrapper(mbhc->codec, + MSM89XX_PMIC_ANALOG_MICB_1_EN) & + 0x80); + if (micb_num == MIC_BIAS_2) + return (snd_soc_read_wrapper(mbhc->codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN) & + 0x80); + return false; +} + +static void msm8x16_wcd_enable_master_bias(struct snd_soc_codec *codec, + bool enable) +{ + if (enable) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, + 0x30, 0x30); + else + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, + 0x30, 0x00); +} + +static void msm8x16_wcd_mbhc_common_micb_ctrl(struct snd_soc_codec *codec, + int event, bool enable) +{ + u16 reg; + u8 mask; + u8 val; + + switch (event) { + case MBHC_COMMON_MICB_PRECHARGE: + reg = MSM89XX_PMIC_ANALOG_MICB_1_CTL; + mask = 0x60; + val = (enable ? 0x60 : 0x00); + break; + case MBHC_COMMON_MICB_SET_VAL: + reg = MSM89XX_PMIC_ANALOG_MICB_1_VAL; + mask = 0xFF; + val = (enable ? 0xC0 : 0x00); + break; + case MBHC_COMMON_MICB_TAIL_CURR: + reg = MSM89XX_PMIC_ANALOG_MICB_1_EN; + mask = 0x04; + val = (enable ? 0x04 : 0x00); + break; + }; + snd_soc_update_bits_wrapper(codec, reg, mask, val); +} + +static void msm8x16_wcd_mbhc_internal_micbias_ctrl(struct snd_soc_codec *codec, + int micbias_num, bool enable) +{ + if (micbias_num == 1) { + if (enable) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS, + 0x10, 0x10); + else + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS, + 0x10, 0x00); + } +} + +static bool msm8x16_wcd_mbhc_hph_pa_on_status(struct snd_soc_codec *codec) +{ + return (snd_soc_read_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN) & + 0x30) ? true : false; +} + +static void msm8x16_wcd_mbhc_program_btn_thr(struct snd_soc_codec *codec, + s16 *btn_low, s16 *btn_high, + int num_btn, bool is_micbias) +{ + int i; + u32 course, fine, reg_val; + u16 reg_addr = MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL; + s16 *btn_voltage; + + btn_voltage = ((is_micbias) ? btn_high : btn_low); + + for (i = 0; i < num_btn; i++) { + course = (btn_voltage[i] / MSM89XX_MBHC_BTN_COARSE_ADJ); + fine = ((btn_voltage[i] % MSM89XX_MBHC_BTN_COARSE_ADJ) / + MSM89XX_MBHC_BTN_FINE_ADJ); + + reg_val = (course << 5) | (fine << 2); + snd_soc_update_bits_wrapper(codec, reg_addr, 0xFC, reg_val); + pr_err("%s: course: %d fine: %d reg_addr: %x reg_val: %x\n", + __func__, course, fine, reg_addr, reg_val); + reg_addr++; + } +} + +static void msm8x16_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, + uint32_t *zr) +{ + struct snd_soc_codec *codec = mbhc->codec; + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + s16 impedance_l, impedance_r; + s16 impedance_l_fixed; + s16 reg0, reg1, reg2, reg3, reg4; + bool high = false; + bool min_range_used = false; + + WCD_MBHC_RSC_ASSERT_LOCKED(mbhc); + reg0 = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER); + reg1 = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL); + reg2 = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2); + reg3 = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN); + reg4 = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL); + + msm8x16_wcd->imped_det_pin = WCD_MBHC_DET_BOTH; + mbhc->hph_type = WCD_MBHC_HPH_NONE; + + /* disable FSM and micbias and enable pullup*/ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x80, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0xA5, 0x25); + /* + * Enable legacy electrical detection current sources + * and disable fast ramp and enable manual switching + * of extra capacitance + */ + pr_err("%s: Setup for impedance det\n", __func__); + + msm8x16_set_ref_current(codec, I_h4_UA); + + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, + 0x06, 0x02); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, + 0x02, 0x02); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, + 0x02, 0x00); + + pr_err("%s: Start performing impedance detection\n", + __func__); + + wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r); + + if (impedance_l > 2 || impedance_r > 2) { + high = true; + if (!mbhc->mbhc_cfg->mono_stero_detection) { + /* Set ZDET_CHG to 0 to discharge ramp */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x02, 0x00); + /* wait 40ms for the discharge ramp to complete */ + usleep_range(40000, 40100); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, + 0x03, 0x00); + msm8x16_wcd->imped_det_pin = (impedance_l > 2 && + impedance_r > 2) ? + WCD_MBHC_DET_NONE : + ((impedance_l > 2) ? + WCD_MBHC_DET_HPHR : + WCD_MBHC_DET_HPHL); + if (msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_NONE) + goto exit; + } else { + if (get_codec_version(msm8x16_wcd) >= CAJON) { + if (impedance_l == 63 && impedance_r == 63) { + pr_err("%s: HPHL and HPHR are floating\n", + __func__); + msm8x16_wcd->imped_det_pin = + WCD_MBHC_DET_NONE; + mbhc->hph_type = WCD_MBHC_HPH_NONE; + } else if (impedance_l == 63 + && impedance_r < 63) { + pr_err("%s: Mono HS with HPHL floating\n", + __func__); + msm8x16_wcd->imped_det_pin = + WCD_MBHC_DET_HPHR; + mbhc->hph_type = WCD_MBHC_HPH_MONO; + } else if (impedance_r == 63 && + impedance_l < 63) { + pr_err("%s: Mono HS with HPHR floating\n", + __func__); + msm8x16_wcd->imped_det_pin = + WCD_MBHC_DET_HPHL; + mbhc->hph_type = WCD_MBHC_HPH_MONO; + } else if (impedance_l > 3 && impedance_r > 3 && + (impedance_l == impedance_r)) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, + 0x06, 0x06); + wcd_mbhc_meas_imped(codec, &impedance_l, + &impedance_r); + if (impedance_r == impedance_l) + pr_err("%s: Mono Headset\n", + __func__); + msm8x16_wcd->imped_det_pin = + WCD_MBHC_DET_NONE; + mbhc->hph_type = + WCD_MBHC_HPH_MONO; + } else { + pr_err("%s: STEREO headset is found\n", + __func__); + msm8x16_wcd->imped_det_pin = + WCD_MBHC_DET_BOTH; + mbhc->hph_type = WCD_MBHC_HPH_STEREO; + } + } + } + } + + msm8x16_set_ref_current(codec, I_pt5_UA); + msm8x16_set_ref_current(codec, I_14_UA); + + /* Enable RAMP_L, RAMP_R & ZDET_CHG*/ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, + 0x03, 0x03); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x02, 0x02); + /* wait for 50msec for the HW to apply ramp on HPHL and HPHR */ + usleep_range(50000, 50100); + /* Enable ZDET_DISCHG_CAP_CTL to add extra capacitance */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x01, 0x01); + /* wait for 5msec for the voltage to get stable */ + usleep_range(5000, 5100); + + + wcd_mbhc_meas_imped(codec, &impedance_l, &impedance_r); + + min_range_used = msm8x16_adj_ref_current(codec, + &impedance_l, &impedance_r); + if (!mbhc->mbhc_cfg->mono_stero_detection) { + /* Set ZDET_CHG to 0 to discharge ramp */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x02, 0x00); + /* wait for 40msec for the capacitor to discharge */ + usleep_range(40000, 40100); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, + 0x03, 0x00); + goto exit; + } + + /* we are setting ref current to the minimun range or the measured + * value larger than the minimum value, so min_range_used is true. + * If the headset is mono headset with either HPHL or HPHR floating + * then we have already done the mono stereo detection and do not + * need to continue further. + */ + + if (!min_range_used || + msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHL || + msm8x16_wcd->imped_det_pin == WCD_MBHC_DET_HPHR) + goto exit; + + + /* Disable Set ZDET_CONN_RAMP_L and enable ZDET_CONN_FIXED_L */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, + 0x02, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL, + 0x02, 0x02); + /* Set ZDET_CHG to 0 */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x02, 0x00); + /* wait for 40msec for the capacitor to discharge */ + usleep_range(40000, 40100); + + /* Set ZDET_CONN_RAMP_R to 0 */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, + 0x01, 0x00); + /* Enable ZDET_L_MEAS_EN */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x08, 0x08); + /* wait for 2msec for the HW to compute left inpedance value */ + usleep_range(2000, 2100); + /* Read Left impedance value from Result1 */ + impedance_l_fixed = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT); + /* Disable ZDET_L_MEAS_EN */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x08, 0x00); + /* + * Assume impedance_l is L1, impedance_l_fixed is L2. + * If the following condition is met, we can take this + * headset as mono one with impedance of L2. + * Otherwise, take it as stereo with impedance of L1. + * Condition: + * abs[(L2-0.5L1)/(L2+0.5L1)] < abs [(L2-L1)/(L2+L1)] + */ + if ((abs(impedance_l_fixed - impedance_l/2) * + (impedance_l_fixed + impedance_l)) >= + (abs(impedance_l_fixed - impedance_l) * + (impedance_l_fixed + impedance_l/2))) { + pr_err("%s: STEREO plug type detected\n", + __func__); + mbhc->hph_type = WCD_MBHC_HPH_STEREO; + } else { + pr_err("%s: MONO plug type detected\n", + __func__); + mbhc->hph_type = WCD_MBHC_HPH_MONO; + impedance_l = impedance_l_fixed; + } + /* Enable ZDET_CHG */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x02, 0x02); + /* wait for 10msec for the capacitor to charge */ + usleep_range(10000, 10100); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, + 0x02, 0x02); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL, + 0x02, 0x00); + /* Set ZDET_CHG to 0 to discharge HPHL */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, + 0x02, 0x00); + /* wait for 40msec for the capacitor to discharge */ + usleep_range(40000, 40100); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL, + 0x02, 0x00); + +exit: + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL, reg4); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, reg3); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL, reg1); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER, reg0); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2, reg2); + msm8x16_wcd_compute_impedance(codec, impedance_l, impedance_r, + zl, zr, high); + + pr_err("%s: RL %d ohm, RR %d ohm\n", __func__, *zl, *zr); + pr_err("%s: Impedance detection completed\n", __func__); +} + +static int msm8x16_register_notifier(struct snd_soc_codec *codec, + struct notifier_block *nblock, + bool enable) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = + snd_soc_codec_get_drvdata(codec); + + if (enable) + return blocking_notifier_chain_register(&msm8x16_wcd->notifier, + nblock); + return blocking_notifier_chain_unregister( + &msm8x16_wcd->notifier, nblock); +} + +static int msm8x16_wcd_request_irq(struct snd_soc_codec *codec, + int irq, irq_handler_t handler, + const char *name, void *data) +{ + return wcd9xxx_spmi_request_irq(irq, handler, name, data); +} + +static int msm8x16_wcd_free_irq(struct snd_soc_codec *codec, + int irq, void *data) +{ + return wcd9xxx_spmi_free_irq(irq, data); +} + +static const struct wcd_mbhc_cb mbhc_cb = { + .enable_mb_source = msm8x16_wcd_enable_ext_mb_source, + .trim_btn_reg = msm8x16_trim_btn_reg, + .compute_impedance = msm8x16_wcd_mbhc_calc_impedance, + .set_micbias_value = msm8x16_wcd_set_micb_v, + .set_auto_zeroing = msm8x16_wcd_set_auto_zeroing, + .get_hwdep_fw_cal = msm8x16_wcd_get_hwdep_fw_cal, + .set_cap_mode = msm8x16_wcd_configure_cap, + .register_notifier = msm8x16_register_notifier, + .request_irq = msm8x16_wcd_request_irq, + .irq_control = wcd9xxx_spmi_irq_control, + .free_irq = msm8x16_wcd_free_irq, + .clk_setup = msm8x16_mbhc_clk_setup, + .map_btn_code_to_num = msm8x16_mbhc_map_btn_code_to_num, + .lock_sleep = msm8x16_spmi_lock_sleep, + .micbias_enable_status = msm8x16_wcd_micb_en_status, + .mbhc_bias = msm8x16_wcd_enable_master_bias, + .mbhc_common_micb_ctrl = msm8x16_wcd_mbhc_common_micb_ctrl, + .micb_internal = msm8x16_wcd_mbhc_internal_micbias_ctrl, + .hph_pa_on_status = msm8x16_wcd_mbhc_hph_pa_on_status, + .set_btn_thr = msm8x16_wcd_mbhc_program_btn_thr, + .extn_use_mb = msm8x16_wcd_use_mb, +}; + +static const uint32_t wcd_imped_val[] = {4, 8, 12, 13, 16, + 20, 24, 28, 32, + 36, 40, 44, 48}; + +void msm8x16_notifier_call(struct snd_soc_codec *codec, + const enum wcd_notify_event event) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + pr_err("%s: notifier call event %d\n", __func__, event); + blocking_notifier_call_chain(&msm8x16_wcd->notifier, event, + &msm8x16_wcd->mbhc); +} + +static void msm8x16_wcd_boost_on(struct snd_soc_codec *codec) +{ + u8 dest = 0x00; + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + + if ((dest & MASK_MSB_BIT) == 0) { + pr_err("PMIC MBG not ON, enable codec hw_en MB bit again\n"); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30); + /* Allow 1ms for PMIC MBG state to be updated */ + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + } + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, + 0x0F, 0x0F); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_SEC_ACCESS, + 0xA5); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, + 0x0F); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, + 0x30); + if (get_codec_version(msm8x16_wcd) < CAJON_2_0) { + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, + 0x82); + } else { + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, + 0xA2); + } + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, + 0x69, 0x69); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, + 0x01, 0x01); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, + 0x88, 0x88); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, + 0x03, 0x03); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, + 0xE1, 0xE1); + if (get_codec_version(msm8x16_wcd) < CAJON_2_0) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x20, 0x20); + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, + 0xDF, 0xDF); + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, + 0x40, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x20, 0x20); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, + 0x80, 0x80); + usleep_range(500, 510); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, + 0x40, 0x40); + usleep_range(500, 510); + } +} + +static void msm8x16_wcd_boost_off(struct snd_soc_codec *codec) +{ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, + 0xDF, 0x5F); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x20, 0x00); +} + +static void msm8x16_wcd_bypass_on(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (get_codec_version(msm8x16_wcd) < CAJON_2_0) { + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_SEC_ACCESS, + 0xA5); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, + 0x07); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x02, 0x02); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x01, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x40, 0x40); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x80, 0x80); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, + 0xDF, 0xDF); + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x20, 0x20); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x20, 0x20); + } +} + +static void msm8x16_wcd_bypass_off(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (get_codec_version(msm8x16_wcd) < CAJON_2_0) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, + 0x80, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x80, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x02, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x40, 0x00); + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_BYPASS_MODE, + 0x20, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x20, 0x00); + } +} + +static void msm8x16_wcd_boost_mode_sequence(struct snd_soc_codec *codec, + int flag) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (flag == EAR_PMU) { + switch (msm8x16_wcd->boost_option) { + case BOOST_SWITCH: + if (msm8x16_wcd->ear_pa_boost_set) { + msm8x16_wcd_boost_off(codec); + msm8x16_wcd_bypass_on(codec); + } + break; + case BOOST_ALWAYS: + msm8x16_wcd_boost_on(codec); + break; + case BYPASS_ALWAYS: + msm8x16_wcd_bypass_on(codec); + break; + case BOOST_ON_FOREVER: + msm8x16_wcd_boost_on(codec); + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + break; + } + } else if (flag == EAR_PMD) { + switch (msm8x16_wcd->boost_option) { + case BOOST_SWITCH: + if (msm8x16_wcd->ear_pa_boost_set) + msm8x16_wcd_bypass_off(codec); + break; + case BOOST_ALWAYS: + msm8x16_wcd_boost_off(codec); + /* 80ms for EAR boost to settle down */ + msleep(80); + break; + case BYPASS_ALWAYS: + /* nothing to do as bypass on always */ + break; + case BOOST_ON_FOREVER: + /* nothing to do as boost on forever */ + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + break; + } + } else if (flag == SPK_PMU) { + switch (msm8x16_wcd->boost_option) { + case BOOST_SWITCH: + if (msm8x16_wcd->spk_boost_set) { + msm8x16_wcd_bypass_off(codec); + msm8x16_wcd_boost_on(codec); + } + break; + case BOOST_ALWAYS: + msm8x16_wcd_boost_on(codec); + break; + case BYPASS_ALWAYS: + msm8x16_wcd_bypass_on(codec); + break; + case BOOST_ON_FOREVER: + msm8x16_wcd_boost_on(codec); + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + break; + } + } else if (flag == SPK_PMD) { + switch (msm8x16_wcd->boost_option) { + case BOOST_SWITCH: + if (msm8x16_wcd->spk_boost_set) { + msm8x16_wcd_boost_off(codec); + /* + * Add 40 ms sleep for the spk + * boost to settle down + */ + msleep(40); + } + break; + case BOOST_ALWAYS: + msm8x16_wcd_boost_off(codec); + /* + * Add 40 ms sleep for the spk + * boost to settle down + */ + msleep(40); + break; + case BYPASS_ALWAYS: + /* nothing to do as bypass on always */ + break; + case BOOST_ON_FOREVER: + /* nothing to do as boost on forever */ + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + break; + } + } +} + +static int msm8x16_wcd_dt_parse_vreg_info(struct device *dev, + struct msm8x16_wcd_regulator *vreg, const char *vreg_name, + bool ondemand) +{ + int len, ret = 0; + const __be32 *prop; + char prop_name[CODEC_DT_MAX_PROP_SIZE]; + struct device_node *regnode = NULL; + u32 prop_val; + + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply", + vreg_name); + regnode = of_parse_phandle(dev->of_node, prop_name, 0); + + if (!regnode) { + dev_err(dev, "Looking up %s property in node %s failed\n", + prop_name, dev->of_node->full_name); + return -ENODEV; + } + + dev_err(dev, "Looking up %s property in node %s\n", + prop_name, dev->of_node->full_name); + + vreg->name = vreg_name; + vreg->ondemand = ondemand; + + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, + "qcom,%s-voltage", vreg_name); + prop = of_get_property(dev->of_node, prop_name, &len); + + if (!prop || (len != (2 * sizeof(__be32)))) { + dev_err(dev, "%s %s property\n", + prop ? "invalid format" : "no", prop_name); + return -EINVAL; + } + vreg->min_uv = be32_to_cpup(&prop[0]); + vreg->max_uv = be32_to_cpup(&prop[1]); + + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, + "qcom,%s-current", vreg_name); + + ret = of_property_read_u32(dev->of_node, prop_name, &prop_val); + if (ret) { + dev_err(dev, "Looking up %s property in node %s failed", + prop_name, dev->of_node->full_name); + return -EFAULT; + } + vreg->optimum_ua = prop_val; + + dev_err(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name, + vreg->min_uv, vreg->max_uv, vreg->optimum_ua, vreg->ondemand); + return 0; +} + +static void msm8x16_wcd_dt_parse_boost_info(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + const char *prop_name = "qcom,cdc-boost-voltage"; + int boost_voltage, ret; + + ret = of_property_read_u32(codec->dev->of_node, prop_name, + &boost_voltage); + if (ret) { + dev_err(codec->dev, "Looking up %s property in node %s failed\n", + prop_name, codec->dev->of_node->full_name); + boost_voltage = DEFAULT_BOOST_VOLTAGE; + } + if (boost_voltage < MIN_BOOST_VOLTAGE || + boost_voltage > MAX_BOOST_VOLTAGE) { + dev_err(codec->dev, + "Incorrect boost voltage. Reverting to default\n"); + boost_voltage = DEFAULT_BOOST_VOLTAGE; + } + + msm8x16_wcd_priv->boost_voltage = + VOLTAGE_CONVERTER(boost_voltage, MIN_BOOST_VOLTAGE, + BOOST_VOLTAGE_STEP); + dev_err(codec->dev, "Boost voltage value is: %d\n", + boost_voltage); +} + +static void msm8x16_wcd_dt_parse_micbias_info(struct device *dev, + struct wcd9xxx_micbias_setting *micbias) +{ + const char *prop_name = "qcom,cdc-micbias-cfilt-mv"; + int ret; + + ret = of_property_read_u32(dev->of_node, prop_name, + &micbias->cfilt1_mv); + if (ret) { + dev_err(dev, "Looking up %s property in node %s failed", + prop_name, dev->of_node->full_name); + micbias->cfilt1_mv = MICBIAS_DEFAULT_VAL; + } +} + +static struct msm8x16_wcd_pdata *msm8x16_wcd_populate_dt_pdata( + struct device *dev) +{ + struct msm8x16_wcd_pdata *pdata; + int ret, static_cnt, ond_cnt, idx, i; + const char *name = NULL; + const char *static_prop_name = "qcom,cdc-static-supplies"; + const char *ond_prop_name = "qcom,cdc-on-demand-supplies"; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + static_cnt = of_property_count_strings(dev->of_node, static_prop_name); + if (IS_ERR_VALUE(static_cnt)) { + dev_err(dev, "%s: Failed to get static supplies %d\n", __func__, + static_cnt); + ret = -EINVAL; + goto err; + } + + /* On-demand supply list is an optional property */ + ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name); + if (IS_ERR_VALUE(ond_cnt)) + ond_cnt = 0; + + WARN_ON(static_cnt <= 0 || ond_cnt < 0); + if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) { + dev_err(dev, "%s: Num of supplies %u > max supported %zd\n", + __func__, (static_cnt + ond_cnt), + ARRAY_SIZE(pdata->regulator)); + ret = -EINVAL; + goto err; + } + + for (idx = 0; idx < static_cnt; idx++) { + ret = of_property_read_string_index(dev->of_node, + static_prop_name, idx, + &name); + if (ret) { + dev_err(dev, "%s: of read string %s idx %d error %d\n", + __func__, static_prop_name, idx, ret); + goto err; + } + + dev_err(dev, "%s: Found static cdc supply %s\n", __func__, + name); + ret = msm8x16_wcd_dt_parse_vreg_info(dev, + &pdata->regulator[idx], + name, false); + if (ret) { + dev_err(dev, "%s:err parsing vreg for %s idx %d\n", + __func__, name, idx); + goto err; + } + } + + for (i = 0; i < ond_cnt; i++, idx++) { + ret = of_property_read_string_index(dev->of_node, ond_prop_name, + i, &name); + if (ret) { + dev_err(dev, "%s: err parsing on_demand for %s idx %d\n", + __func__, ond_prop_name, i); + goto err; + } + + dev_err(dev, "%s: Found on-demand cdc supply %s\n", __func__, + name); + ret = msm8x16_wcd_dt_parse_vreg_info(dev, + &pdata->regulator[idx], + name, true); + if (ret) { + dev_err(dev, "%s: err parsing vreg on_demand for %s idx %d\n", + __func__, name, idx); + goto err; + } + } + msm8x16_wcd_dt_parse_micbias_info(dev, &pdata->micbias); + return pdata; +err: + devm_kfree(dev, pdata); + dev_err(dev, "%s: Failed to populate DT data ret = %d\n", + __func__, ret); + return NULL; +} + +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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + struct on_demand_supply *supply; + + if (w->shift >= ON_DEMAND_SUPPLIES_MAX) { + dev_err(codec->dev, "%s: error index > MAX Demand supplies", + __func__); + ret = -EINVAL; + goto out; + } + dev_err(codec->dev, "%s: supply: %s event: %d ref: %d\n", + __func__, on_demand_supply_name[w->shift], event, + atomic_read(&msm8x16_wcd->on_demand_list[w->shift].ref)); + + supply = &msm8x16_wcd->on_demand_list[w->shift]; + WARN_ONCE(!supply->supply, "%s isn't defined\n", + on_demand_supply_name[w->shift]); + if (!supply->supply) { + dev_err(codec->dev, "%s: err supply not present ond for %d", + __func__, w->shift); + goto out; + } + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (atomic_inc_return(&supply->ref) == 1) + ret = regulator_enable(supply->supply); + if (ret) + dev_err(codec->dev, "%s: Failed to enable %s\n", + __func__, + on_demand_supply_name[w->shift]); + break; + case SND_SOC_DAPM_POST_PMD: + if (atomic_read(&supply->ref) == 0) { + dev_err(codec->dev, "%s: %s supply has been disabled.\n", + __func__, on_demand_supply_name[w->shift]); + goto out; + } + if (atomic_dec_return(&supply->ref) == 0) + ret = regulator_disable(supply->supply); + if (ret) + dev_err(codec->dev, "%s: Failed to disable %s\n", + __func__, + on_demand_supply_name[w->shift]); + break; + default: + break; + } +out: + return ret; +} + +static int msm8x16_wcd_codec_enable_clock_block(struct snd_soc_codec *codec, + int enable) +{ + struct msm8916_asoc_mach_data *pdata = NULL; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + if (enable) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C); + if (pdata->mclk_freq == MCLK_RATE_12P288MHZ) + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x00); + else if (pdata->mclk_freq == MCLK_RATE_9P6MHZ) + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TOP_CTL, 0x01, 0x01); + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x00); + + } + 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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: event = %d\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + msm8x16_wcd_codec_enable_clock_block(codec, 1); + if (!(strcmp(w->name, "EAR CP"))) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x80, 0x80); + msm8x16_wcd_boost_mode_sequence(codec, EAR_PMU); + } else if (get_codec_version(msm8x16_wcd) == DIANGU) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x80, 0x80); + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_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_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x80, 0x00); + if (msm8x16_wcd->boost_option != BOOST_ALWAYS) { + dev_err(codec->dev, + "%s: boost_option:%d, tear down ear\n", + __func__, msm8x16_wcd->boost_option); + msm8x16_wcd_boost_mode_sequence(codec, EAR_PMD); + } + /* + * Reset pa select bit from ear to hph after ear pa + * is disabled and HPH DAC disable to reduce ear + * turn off pop and avoid HPH pop in concurrency + */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x00); + } else { + if (get_codec_version(msm8x16_wcd) < DIANGU) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x40, 0x00); + if (msm8x16_wcd->rx_bias_count == 0) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x80, 0x00); + dev_err(codec->dev, "%s: rx_bias_count = %d\n", + __func__, msm8x16_wcd->rx_bias_count); + } + break; + } + return 0; +} + +static int msm8x16_wcd_ear_pa_boost_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = + (msm8x16_wcd->ear_pa_boost_set ? 1 : 0); + dev_err(codec->dev, "%s: msm8x16_wcd->ear_pa_boost_set = %d\n", + __func__, msm8x16_wcd->ear_pa_boost_set); + return 0; +} + +static int msm8x16_wcd_ear_pa_boost_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = + snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + msm8x16_wcd->ear_pa_boost_set = + (ucontrol->value.integer.value[0] ? true : false); + return 0; +} + +static int msm8x16_wcd_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + + ear_pa_gain = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL); + + ear_pa_gain = (ear_pa_gain >> 5) & 0x1; + + if (ear_pa_gain == 0x00) { + ucontrol->value.integer.value[0] = 0; + } else if (ear_pa_gain == 0x01) { + ucontrol->value.integer.value[0] = 1; + } else { + dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n", + __func__, ear_pa_gain); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = ear_pa_gain; + dev_err(codec->dev, "%s: ear_pa_gain = 0x%x\n", + __func__, ear_pa_gain); + return 0; +} + +static int msm8x16_wcd_loopback_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8916_asoc_mach_data *pdata = NULL; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return pdata->lb_mode; +} + +static int msm8x16_wcd_loopback_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8916_asoc_mach_data *pdata = NULL; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 0: + pdata->lb_mode = false; + break; + case 1: + pdata->lb_mode = true; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int msm8x16_wcd_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 0: + ear_pa_gain = 0x00; + break; + case 1: + ear_pa_gain = 0x20; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_EAR_CTL, + 0x20, ear_pa_gain); + return 0; +} + +static int msm8x16_wcd_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (msm8x16_wcd->hph_mode == NORMAL_MODE) { + ucontrol->value.integer.value[0] = 0; + } else if (msm8x16_wcd->hph_mode == HD2_MODE) { + ucontrol->value.integer.value[0] = 1; + } else { + dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n", + __func__, msm8x16_wcd->hph_mode); + } + + dev_err(codec->dev, "%s: msm8x16_wcd->hph_mode = %d\n", __func__, + msm8x16_wcd->hph_mode); + return 0; +} + +static int msm8x16_wcd_hph_mode_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 0: + msm8x16_wcd->hph_mode = NORMAL_MODE; + break; + case 1: + if (get_codec_version(msm8x16_wcd) >= DIANGU) + msm8x16_wcd->hph_mode = HD2_MODE; + break; + default: + msm8x16_wcd->hph_mode = NORMAL_MODE; + break; + } + dev_err(codec->dev, "%s: msm8x16_wcd->hph_mode_set = %d\n", + __func__, msm8x16_wcd->hph_mode); + return 0; +} + +static int msm8x16_wcd_boost_option_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (msm8x16_wcd->boost_option == BOOST_SWITCH) { + ucontrol->value.integer.value[0] = 0; + } else if (msm8x16_wcd->boost_option == BOOST_ALWAYS) { + ucontrol->value.integer.value[0] = 1; + } else if (msm8x16_wcd->boost_option == BYPASS_ALWAYS) { + ucontrol->value.integer.value[0] = 2; + } else if (msm8x16_wcd->boost_option == BOOST_ON_FOREVER) { + ucontrol->value.integer.value[0] = 3; + } else { + dev_err(codec->dev, "%s: ERROR: Unsupported Boost option= %d\n", + __func__, msm8x16_wcd->boost_option); + return -EINVAL; + } + + dev_err(codec->dev, "%s: msm8x16_wcd->boost_option = %d\n", __func__, + msm8x16_wcd->boost_option); + return 0; +} + +static int msm8x16_wcd_boost_option_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 0: + msm8x16_wcd->boost_option = BOOST_SWITCH; + break; + case 1: + msm8x16_wcd->boost_option = BOOST_ALWAYS; + break; + case 2: + msm8x16_wcd->boost_option = BYPASS_ALWAYS; + msm8x16_wcd_bypass_on(codec); + break; + case 3: + msm8x16_wcd->boost_option = BOOST_ON_FOREVER; + msm8x16_wcd_boost_on(codec); + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + return -EINVAL; + } + dev_err(codec->dev, "%s: msm8x16_wcd->boost_option_set = %d\n", + __func__, msm8x16_wcd->boost_option); + return 0; +} + +static int msm8x16_wcd_ext_spk_boost_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (msm8x16_wcd->ext_spk_boost_set == false) + ucontrol->value.integer.value[0] = 0; + else + ucontrol->value.integer.value[0] = 1; + + dev_err(codec->dev, "%s: msm8x16_wcd->ext_spk_boost_set = %d\n", + __func__, msm8x16_wcd->ext_spk_boost_set); + return 0; +} + +static int msm8x16_wcd_ext_spk_boost_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 0: + msm8x16_wcd->ext_spk_boost_set = false; + break; + case 1: + msm8x16_wcd->ext_spk_boost_set = true; + break; + default: + return -EINVAL; + } + dev_err(codec->dev, "%s: msm8x16_wcd->spk_boost_set = %d\n", + __func__, msm8x16_wcd->spk_boost_set); + return 0; +} +static int msm8x16_wcd_get_iir_enable_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = + (snd_soc_read_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) & + (1 << band_idx)) != 0; + + dev_err(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0]); + return 0; +} + +static int msm8x16_wcd_put_iir_enable_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_update_bits_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx), + (1 << band_idx), (value << band_idx)); + + dev_err(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + ((snd_soc_read_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_CTL + 64 * iir_idx)) & + (1 << band_idx)) != 0)); + + return 0; +} +static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec, + int iir_idx, int band_idx, + int coeff_idx) +{ + uint32_t value = 0; + + /* Address does not automatically update if reading */ + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_read_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)); + + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_read_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8); + + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_read_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16); + + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_read_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + + 64 * iir_idx)) & 0x3f) << 24); + + return value; + +} + +static int msm8x16_wcd_get_iir_band_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = + get_iir_band_coeff(codec, iir_idx, band_idx, 0); + ucontrol->value.integer.value[1] = + get_iir_band_coeff(codec, iir_idx, band_idx, 1); + ucontrol->value.integer.value[2] = + get_iir_band_coeff(codec, iir_idx, band_idx, 2); + ucontrol->value.integer.value[3] = + get_iir_band_coeff(codec, iir_idx, band_idx, 3); + ucontrol->value.integer.value[4] = + get_iir_band_coeff(codec, iir_idx, band_idx, 4); + + dev_err(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[1], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[2], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[3], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[4]); + return 0; +} + +static void set_iir_band_coeff(struct snd_soc_codec *codec, + int iir_idx, int band_idx, + uint32_t value) +{ + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value & 0xFF)); + + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value >> 8) & 0xFF); + + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL + 64 * iir_idx), + (value >> 24) & 0x3F); + +} + +static int msm8x16_wcd_put_iir_band_audio_mixer( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + /* Mask top bit it is reserved */ + /* Updates addr automatically for each B2 write */ + snd_soc_write_wrapper(codec, + (MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL + 64 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[0]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[1]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[2]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[3]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[4]); + + dev_err(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 0), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 1), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 2), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 3), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 4)); + return 0; +} + +static int msm8x16_wcd_compander_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + int comp_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int rx_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + dev_err(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n", + __func__, comp_idx, rx_idx, + msm8x16_wcd->comp_enabled[rx_idx]); + + ucontrol->value.integer.value[0] = msm8x16_wcd->comp_enabled[rx_idx]; + + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int msm8x16_wcd_compander_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + int comp_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int rx_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + + dev_err(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + if (get_codec_version(msm8x16_wcd) >= DIANGU) { + if (!value) + msm8x16_wcd->comp_enabled[rx_idx] = 0; + else + msm8x16_wcd->comp_enabled[rx_idx] = comp_idx; + } + + dev_err(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n", + __func__, comp_idx, rx_idx, + msm8x16_wcd->comp_enabled[rx_idx]); + + return 0; +} + +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 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_1P5_DB", "POS_6_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_boost_option_ctrl_text[] = { + "BOOST_SWITCH", "BOOST_ALWAYS", "BYPASS_ALWAYS", + "BOOST_ON_FOREVER"}; +static const struct soc_enum msm8x16_wcd_boost_option_ctl_enum[] = { + SOC_ENUM_SINGLE_EXT(4, msm8x16_wcd_boost_option_ctrl_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), +}; + +static const char * const msm8x16_wcd_ext_spk_boost_ctrl_text[] = { + "DISABLE", "ENABLE"}; +static const struct soc_enum msm8x16_wcd_ext_spk_boost_ctl_enum[] = { + SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ext_spk_boost_ctrl_text), +}; + +static const char * const msm8x16_wcd_hph_mode_ctrl_text[] = { + "NORMAL", "HD2"}; +static const struct soc_enum msm8x16_wcd_hph_mode_ctl_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm8x16_wcd_hph_mode_ctrl_text), + msm8x16_wcd_hph_mode_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(MSM89XX_CDC_CORE_TX1_MUX_CTL, 4, 3, cf_text); + +static const struct soc_enum cf_dec2_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX2_MUX_CTL, 4, 3, cf_text); + +static const struct soc_enum cf_rxmix1_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX1_B4_CTL, 0, 3, cf_text); + +static const struct soc_enum cf_rxmix2_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX2_B4_CTL, 0, 3, cf_text); + +static const struct soc_enum cf_rxmix3_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_RX3_B4_CTL, 0, 3, cf_text); + +static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = { + + SOC_ENUM_EXT("RX HPH Mode", msm8x16_wcd_hph_mode_ctl_enum[0], + msm8x16_wcd_hph_mode_get, msm8x16_wcd_hph_mode_set), + + SOC_ENUM_EXT("Boost Option", msm8x16_wcd_boost_option_ctl_enum[0], + msm8x16_wcd_boost_option_get, msm8x16_wcd_boost_option_set), + + SOC_ENUM_EXT("EAR PA Boost", msm8x16_wcd_ear_pa_boost_ctl_enum[0], + msm8x16_wcd_ear_pa_boost_get, msm8x16_wcd_ear_pa_boost_set), + + SOC_ENUM_EXT("EAR PA Gain", msm8x16_wcd_ear_pa_gain_enum[0], + msm8x16_wcd_pa_gain_get, msm8x16_wcd_pa_gain_put), + + SOC_ENUM_EXT("Ext Spk Boost", msm8x16_wcd_ext_spk_boost_ctl_enum[0], + msm8x16_wcd_ext_spk_boost_get, msm8x16_wcd_ext_spk_boost_set), + + SOC_ENUM_EXT("LOOPBACK Mode", msm8x16_wcd_loopback_mode_ctl_enum[0], + msm8x16_wcd_loopback_mode_get, msm8x16_wcd_loopback_mode_put), + + SOC_SINGLE_TLV("ADC1 Volume", MSM89XX_PMIC_ANALOG_TX_1_EN, 3, + 8, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", MSM89XX_PMIC_ANALOG_TX_2_EN, 3, + 8, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", MSM89XX_PMIC_ANALOG_TX_3_EN, 3, + 8, 0, analog_gain), + + SOC_SINGLE_SX_TLV("RX1 Digital Volume", + MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Digital Volume", + MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Digital Volume", + MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL, + 0, -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("DEC1 Volume", + MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC2 Volume", + MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN, + 0, -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP4 Volume", + MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("IIR2 INP1 Volume", + MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL, + 0, -84, 40, digital_gain), + + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + + SOC_SINGLE("TX1 HPF Switch", + MSM89XX_CDC_CORE_TX1_MUX_CTL, 3, 1, 0), + SOC_SINGLE("TX2 HPF Switch", + MSM89XX_CDC_CORE_TX2_MUX_CTL, 3, 1, 0), + + SOC_SINGLE("RX1 HPF Switch", + MSM89XX_CDC_CORE_RX1_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX2 HPF Switch", + MSM89XX_CDC_CORE_RX2_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX3 HPF Switch", + MSM89XX_CDC_CORE_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), + + SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0, + msm8x16_wcd_get_iir_enable_audio_mixer, + msm8x16_wcd_put_iir_enable_audio_mixer), + + SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5, + msm8x16_wcd_get_iir_band_audio_mixer, + msm8x16_wcd_put_iir_band_audio_mixer), + + SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM89XX_RX1, 1, 0, + msm8x16_wcd_compander_get, msm8x16_wcd_compander_set), + + SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM89XX_RX2, 1, 0, + msm8x16_wcd_compander_get, msm8x16_wcd_compander_set), +}; + +static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + uint32_t zl, zr; + bool hphr; + struct soc_multi_mixer_control *mc; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *priv = snd_soc_codec_get_drvdata(codec); + + mc = (struct soc_multi_mixer_control *)(kcontrol->private_value); + + hphr = mc->shift; + ret = wcd_mbhc_get_impedance(&priv->mbhc, &zl, &zr); + if (ret) + pr_err("%s: Failed to get mbhc imped", __func__); + pr_err("%s: zl %u, zr %u\n", __func__, zl, zr); + ucontrol->value.integer.value[0] = hphr ? zr : zl; + + return 0; +} + +static const struct snd_kcontrol_new impedance_detect_controls[] = { + SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, + tombak_hph_impedance_get, NULL), + SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, + tombak_hph_impedance_get, NULL), +}; + +static int tombak_get_hph_type(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct msm8x16_wcd_priv *priv = snd_soc_codec_get_drvdata(codec); + struct wcd_mbhc *mbhc; + + if (!priv) { + pr_err("%s: msm8x16-wcd private data is NULL\n", + __func__); + return -EINVAL; + } + + mbhc = &priv->mbhc; + if (!mbhc) { + pr_err("%s: mbhc not initialized\n", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = (u32) mbhc->hph_type; + pr_err("%s: hph_type = %u\n", __func__, mbhc->hph_type); + + return 0; +} + +static const struct snd_kcontrol_new hph_type_detect_controls[] = { + SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, + tombak_get_hph_type, NULL), +}; + +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 dec3_mux_text[] = { + "ZERO", "DMIC3" +}; + +static const char * const dec4_mux_text[] = { + "ZERO", "DMIC4" +}; + +static const char * const adc2_mux_text[] = { + "ZERO", "INP2", "INP3" +}; + +static const char * const ext_spk_text[] = { + "Off", "On" +}; + +static const char * const wsa_spk_text[] = { + "ZERO", "WSA" +}; + +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 struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +static const struct soc_enum ext_spk_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(ext_spk_text), ext_spk_text); + +static const struct soc_enum wsa_spk_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(wsa_spk_text), wsa_spk_text); + +/* RX1 MIX1 */ +static const struct soc_enum rx_mix1_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL, + 0, 6, rx_mix1_text); + +static const struct soc_enum rx_mix1_inp2_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B1_CTL, + 3, 6, rx_mix1_text); + +static const struct soc_enum rx_mix1_inp3_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B2_CTL, + 0, 6, rx_mix1_text); + +/* RX1 MIX2 */ +static const struct soc_enum rx_mix2_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX1_B3_CTL, + 0, 3, rx_mix2_text); + +/* RX2 MIX1 */ +static const struct soc_enum rx2_mix1_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, + 0, 6, rx_mix1_text); + +static const struct soc_enum rx2_mix1_inp2_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, + 3, 6, rx_mix1_text); + +static const struct soc_enum rx2_mix1_inp3_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B1_CTL, + 0, 6, rx_mix1_text); + +/* RX2 MIX2 */ +static const struct soc_enum rx2_mix2_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX2_B3_CTL, + 0, 3, rx_mix2_text); + +/* RX3 MIX1 */ +static const struct soc_enum rx3_mix1_inp1_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, + 0, 6, rx_mix1_text); + +static const struct soc_enum rx3_mix1_inp2_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, + 3, 6, rx_mix1_text); + +static const struct soc_enum rx3_mix1_inp3_chain_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_RX3_B1_CTL, + 0, 6, rx_mix1_text); + +/* DEC */ +static const struct soc_enum dec1_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL, + 0, 6, dec_mux_text); + +static const struct soc_enum dec2_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_TX_B1_CTL, + 3, 6, dec_mux_text); + +static const struct soc_enum dec3_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX3_MUX_CTL, 0, + ARRAY_SIZE(dec3_mux_text), dec3_mux_text); + +static const struct soc_enum dec4_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_TX4_MUX_CTL, 0, + ARRAY_SIZE(dec4_mux_text), dec4_mux_text); + +static const struct soc_enum rdac2_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL, + 0, 3, rdac2_mux_text); + +static const struct soc_enum iir1_inp1_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL, + 0, 6, iir_inp1_text); + +static const struct soc_enum iir2_inp1_mux_enum = + SOC_ENUM_SINGLE(MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL, + 0, 6, iir_inp1_text); + +static const struct snd_kcontrol_new ext_spk_mux = + SOC_DAPM_ENUM("Ext Spk Switch Mux", ext_spk_enum); + +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 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 int msm8x16_wcd_put_dec_enum(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *w = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int dec_mux, decimator; + char *dec_name = NULL; + char *widget_name = NULL; + char *temp; + u16 tx_mux_ctl_reg; + u8 adc_dmic_sel = 0x0; + int ret = 0; + char *dec_num; + + if (ucontrol->value.enumerated.item[0] > e->items) { + dev_err(codec->dev, "%s: Invalid enum value: %d\n", + __func__, ucontrol->value.enumerated.item[0]); + return -EINVAL; + } + dec_mux = ucontrol->value.enumerated.item[0]; + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) { + dev_err(codec->dev, "%s: failed to copy string\n", + __func__); + 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 DEC selected\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(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n" + , __func__, w->name, decimator, dec_mux); + + switch (decimator) { + case 1: + case 2: + if ((dec_mux == 4) || (dec_mux == 5)) + adc_dmic_sel = 0x1; + else + adc_dmic_sel = 0x0; + break; + default: + dev_err(codec->dev, "%s: Invalid Decimator = %u\n", + __func__, decimator); + ret = -EINVAL; + goto out; + } + + tx_mux_ctl_reg = + MSM89XX_CDC_CORE_TX1_MUX_CTL + 32 * (decimator - 1); + + snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel); + + ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + +out: + kfree(widget_name); + return ret; +} + +#define MSM89XX_DEC_ENUM(xname, xenum) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_double, \ + .get = snd_soc_dapm_get_enum_double, \ + .put = msm8x16_wcd_put_dec_enum, \ + .private_value = (unsigned long)&xenum } + +static const struct snd_kcontrol_new dec1_mux = + MSM89XX_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum); + +static const struct snd_kcontrol_new dec2_mux = + MSM89XX_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum); + +static const struct snd_kcontrol_new dec3_mux = + SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum); + +static const struct snd_kcontrol_new dec4_mux = + SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_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 char * const ear_text[] = { + "ZERO", "Switch", +}; + +static const struct soc_enum ear_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(ear_text), ear_text); + +static const struct snd_kcontrol_new ear_pa_mux[] = { + SOC_DAPM_ENUM("EAR_S", ear_enum) +}; + +static const struct snd_kcontrol_new wsa_spk_mux[] = { + SOC_DAPM_ENUM("WSA Spk Switch", wsa_spk_enum) +}; + +static const struct snd_kcontrol_new iir2_inp1_mux = + SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum); + +static const char * const hph_text[] = { + "ZERO", "Switch", +}; + +static const struct soc_enum hph_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 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_mux[] = { + SOC_DAPM_ENUM("SPK", hph_enum) +}; + +static const char * const lo_text[] = { + "ZERO", "Switch", +}; + +static const struct soc_enum lo_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(hph_text), hph_text); + +static const struct snd_kcontrol_new lo_mux[] = { + SOC_DAPM_ENUM("LINE_OUT", lo_enum) +}; + +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_err(codec->dev, "%s %d\n", __func__, enable); + + if (enable) { + wcd8x16->adc_count++; + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, + 0x20, 0x20); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x10, 0x10); + } else { + wcd8x16->adc_count--; + if (!wcd8x16->adc_count) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x10, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, + 0x20, 0x0); + } + } +} + +static int msm8x16_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; + u8 init_bit_shift; + + dev_err(codec->dev, "%s %d\n", __func__, event); + + adc_reg = MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2; + + if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN) + init_bit_shift = 5; + else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) || + (w->reg == MSM89XX_PMIC_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 == MSM89XX_PMIC_ANALOG_TX_2_EN) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_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_wrapper(codec, + adc_reg, 1 << init_bit_shift, + 1 << init_bit_shift); + if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL, + 0x03, 0x00); + else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) || + (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN)) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_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_wrapper(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 == MSM89XX_PMIC_ANALOG_TX_2_EN) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_CTL, 0x02, 0x00); + if (w->reg == MSM89XX_PMIC_ANALOG_TX_1_EN) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL, + 0x03, 0x02); + else if ((w->reg == MSM89XX_PMIC_ANALOG_TX_2_EN) || + (w->reg == MSM89XX_PMIC_ANALOG_TX_3_EN)) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s %d %s\n", __func__, event, w->name); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x01); + switch (msm8x16_wcd->boost_option) { + case BOOST_SWITCH: + if (!msm8x16_wcd->spk_boost_set) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, + 0x10, 0x10); + break; + case BOOST_ALWAYS: + case BOOST_ON_FOREVER: + break; + case BYPASS_ALWAYS: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, + 0x10, 0x10); + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + break; + } + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0xE0); + if (get_codec_version(msm8x16_wcd) != TOMBAK_1_0) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x01); + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + switch (msm8x16_wcd->boost_option) { + case BOOST_SWITCH: + if (msm8x16_wcd->spk_boost_set) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, + 0xEF, 0xEF); + else + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, + 0x10, 0x00); + break; + case BOOST_ALWAYS: + case BOOST_ON_FOREVER: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, + 0xEF, 0xEF); + break; + case BYPASS_ALWAYS: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00); + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + break; + } + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00); + snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x80); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x01); + msm8x16_wcd->mute_mask |= SPKR_PA_DISABLE; + /* + * Add 1 ms sleep for the mute to take effect + */ + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x10); + if (get_codec_version(msm8x16_wcd) < CAJON_2_0) + msm8x16_wcd_boost_mode_sequence(codec, SPK_PMD); + snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x00); + switch (msm8x16_wcd->boost_option) { + case BOOST_SWITCH: + if (msm8x16_wcd->spk_boost_set) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, + 0xEF, 0x69); + break; + case BOOST_ALWAYS: + case BOOST_ON_FOREVER: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, + 0xEF, 0x69); + break; + case BYPASS_ALWAYS: + break; + default: + pr_err("%s: invalid boost option: %d\n", __func__, + msm8x16_wcd->boost_option); + break; + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0xE0, 0x00); + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, 0x01, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x10, 0x00); + if (get_codec_version(msm8x16_wcd) != TOMBAK_1_0) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x01, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); + if (get_codec_version(msm8x16_wcd) >= CAJON_2_0) + msm8x16_wcd_boost_mode_sequence(codec, SPK_PMD); + break; + } + 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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + struct msm8916_asoc_mach_data *pdata = NULL; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + + dev_err(codec->dev, "%s event %d w->name %s\n", __func__, + event, w->name); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + msm8x16_wcd_codec_enable_clock_block(codec, 1); + snd_soc_update_bits_wrapper(codec, w->reg, 0x80, 0x80); + msm8x16_wcd_boost_mode_sequence(codec, SPK_PMU); + break; + case SND_SOC_DAPM_POST_PMD: + if (msm8x16_wcd->rx_bias_count == 0) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x80, 0x00); + } + return 0; +} + +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); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + 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 = &(msm8x16_wcd->dmic_1_2_clk_cnt); + dmic_clk_reg = MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL; + dev_err(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_wrapper(codec, dmic_clk_reg, + 0x0E, 0x02); + snd_soc_update_bits_wrapper(codec, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + if (dmic == 1) + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TX1_DMIC_CTL, 0x07, 0x01); + if (dmic == 2) + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TX2_DMIC_CTL, 0x07, 0x01); + break; + case SND_SOC_DAPM_POST_PMD: + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) + snd_soc_update_bits_wrapper(codec, dmic_clk_reg, + dmic_clk_en, 0); + break; + } + return 0; +} + +static bool msm8x16_wcd_use_mb(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (get_codec_version(msm8x16_wcd) < CAJON) + return true; + else + return false; +} + +static void msm8x16_wcd_set_auto_zeroing(struct snd_soc_codec *codec, + bool enable) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (get_codec_version(msm8x16_wcd) < CONGA) { + if (enable) + /* + * Set autozeroing for special headset detection and + * buttons to work. + */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0x18, 0x10); + else + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN, + 0x18, 0x00); + + } else { + pr_err("%s: Auto Zeroing is not required from CONGA\n", + __func__); + } +} + +static void msm8x16_trim_btn_reg(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if (get_codec_version(msm8x16_wcd) == TOMBAK_1_0) { + pr_err("%s: This device needs to be trimmed\n", __func__); + /* + * Calculate the trim value for each device used + * till is comes in production by hardware team + */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SEC_ACCESS, + 0xA5, 0xA5); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_TRIM_CTRL2, + 0xFF, 0x30); + } else { + pr_err("%s: This device is trimmed at ATE\n", __func__); + } +} +static int msm8x16_wcd_enable_ext_mb_source(struct snd_soc_codec *codec, + bool turn_on) +{ + int ret = 0; + static int count; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + dev_err(codec->dev, "%s turn_on: %d count: %d\n", __func__, turn_on, + count); + if (turn_on) { + if (!count) { + ret = snd_soc_dapm_force_enable_pin(dapm, + "MICBIAS_REGULATOR"); + snd_soc_dapm_sync(dapm); + } + count++; + } else { + if (count > 0) + count--; + if (!count) { + ret = snd_soc_dapm_disable_pin(dapm, + "MICBIAS_REGULATOR"); + snd_soc_dapm_sync(dapm); + } + } + + if (ret) + dev_err(codec->dev, "%s: Failed to %s external micbias source\n", + __func__, turn_on ? "enable" : "disabled"); + else + dev_err(codec->dev, "%s: %s external micbias source\n", + __func__, turn_on ? "Enabled" : "Disabled"); + + return ret; +} + +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 msm8x16_wcd_priv *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; + + dev_err(codec->dev, "%s %d\n", __func__, event); + switch (w->reg) { + case MSM89XX_PMIC_ANALOG_MICB_1_EN: + case MSM89XX_PMIC_ANALOG_MICB_2_EN: + micb_int_reg = MSM89XX_PMIC_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_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_2_EN) & 0x80); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strnstr(w->name, internal1_text, strlen(w->name))) { + if (get_codec_version(msm8x16_wcd) >= CAJON) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2, + 0x02, 0x02); + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0x80, 0x80); + } else if (strnstr(w->name, internal2_text, strlen(w->name))) { + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0x10, 0x10); + snd_soc_update_bits_wrapper(codec, + w->reg, 0x60, 0x00); + } else if (strnstr(w->name, internal3_text, strlen(w->name))) { + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0x2, 0x2); + /* + * update MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2 + * for external bias only, not for external2. + */ + } else if (!strnstr(w->name, external2_text, strlen(w->name)) && + strnstr(w->name, external_text, + strlen(w->name))) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2, + 0x02, 0x02); + } + if (!strnstr(w->name, external_text, strlen(w->name))) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_EN, 0x05, 0x04); + if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN) + msm8x16_wcd_configure_cap(codec, true, micbias2); + + break; + case SND_SOC_DAPM_POST_PMU: + if (get_codec_version(msm8x16_wcd) <= TOMBAK_2_0) + usleep_range(20000, 20100); + if (strnstr(w->name, internal1_text, strlen(w->name))) { + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0x40, 0x40); + } else if (strnstr(w->name, internal2_text, strlen(w->name))) { + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0x08, 0x08); + msm8x16_notifier_call(codec, + WCD_EVENT_POST_MICBIAS_2_ON); + } else if (strnstr(w->name, internal3_text, 30)) { + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0x01, 0x01); + } else if (strnstr(w->name, external2_text, strlen(w->name))) { + msm8x16_notifier_call(codec, + WCD_EVENT_POST_MICBIAS_2_ON); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, internal1_text, strlen(w->name))) { + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0xC0, 0x40); + } else if (strnstr(w->name, internal2_text, strlen(w->name))) { + msm8x16_notifier_call(codec, + WCD_EVENT_POST_MICBIAS_2_OFF); + } else if (strnstr(w->name, internal3_text, 30)) { + snd_soc_update_bits_wrapper(codec, + micb_int_reg, 0x2, 0x0); + } else if (strnstr(w->name, external2_text, strlen(w->name))) { + /* + * send micbias turn off event to mbhc driver and then + * break, as no need to set MICB_1_EN register. + */ + msm8x16_notifier_call(codec, + WCD_EVENT_POST_MICBIAS_2_OFF); + break; + } + if (w->reg == MSM89XX_PMIC_ANALOG_MICB_1_EN) + msm8x16_wcd_configure_cap(codec, false, micbias2); + break; + } + return 0; +} + +static void tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct msm8x16_wcd_priv *msm8x16_wcd; + struct snd_soc_codec *codec; + u16 tx_mux_ctl_reg; + u8 hpf_cut_of_freq; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + msm8x16_wcd = hpf_work->msm8x16_wcd; + codec = hpf_work->msm8x16_wcd->codec; + hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq; + + tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL + + (hpf_work->decimator - 1) * 32; + + dev_err(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV, 0xFF, 0x51); + + snd_soc_update_bits_wrapper(codec, + tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4); +} + + +#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_set_iir_gain(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + int value = 0, reg; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (w->shift == 0) + reg = MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL; + else if (w->shift == 1) + reg = MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL; + value = snd_soc_read_wrapper(codec, reg); + snd_soc_write_wrapper(codec, reg, value); + break; + default: + pr_err("%s: event = %d not expected\n", __func__, event); + } + return 0; +} + +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); + struct msm8916_asoc_mach_data *pdata = NULL; + unsigned int decimator; + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + char *dec_name = NULL; + char *widget_name = NULL; + char *temp; + int ret = 0, i; + u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg; + u8 dec_hpf_cut_of_freq; + int offset; + char *dec_num; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + dev_err(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, "1234"); + 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 == MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL) { + dec_reset_reg = MSM89XX_CDC_CORE_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 = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG + + 32 * (decimator - 1); + tx_mux_ctl_reg = MSM89XX_CDC_CORE_TX1_MUX_CTL + + 32 * (decimator - 1); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (decimator == 3 || decimator == 4) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL, + 0xFF, 0x5); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x2); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x2); + } + /* Enableable TX digital mute */ + snd_soc_update_bits_wrapper(codec, tx_vol_ctl_reg, 0x01, 0x01); + for (i = 0; i < NUM_DECIMATORS; i++) { + if (decimator == i + 1) + msm8x16_wcd->dec_active[i] = true; + } + + dec_hpf_cut_of_freq = + snd_soc_read_wrapper(codec, tx_mux_ctl_reg); + + dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4; + + tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq = + dec_hpf_cut_of_freq; + + if (dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ) { + + /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */ + snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x30, + CF_MIN_3DB_150HZ << 4); + } + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV, + 0xFF, 0x42); + + break; + case SND_SOC_DAPM_POST_PMU: + /* enable HPF */ + snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x08, 0x00); + + if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq != + CF_MIN_3DB_150HZ) { + + schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork, + msecs_to_jiffies(300)); + } + /* apply the digital gain after the decimator is enabled*/ + if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg)) + snd_soc_write_wrapper(codec, + tx_digital_gain_reg[w->shift + offset], + snd_soc_read_wrapper(codec, + tx_digital_gain_reg[w->shift + offset]) + ); + if (pdata->lb_mode) { + pr_err("%s: loopback mode unmute the DEC\n", + __func__); + snd_soc_update_bits_wrapper(codec, + tx_vol_ctl_reg, 0x01, 0x00); + } + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits_wrapper(codec, tx_vol_ctl_reg, 0x01, 0x01); + msleep(20); + snd_soc_update_bits_wrapper(codec, tx_mux_ctl_reg, 0x08, 0x08); + cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits_wrapper(codec, + dec_reset_reg, 1 << w->shift, 1 << w->shift); + snd_soc_update_bits_wrapper(codec, + dec_reset_reg, 1 << w->shift, 0x0); + snd_soc_update_bits_wrapper(codec, + tx_mux_ctl_reg, 0x08, 0x08); + snd_soc_update_bits_wrapper(codec, + tx_mux_ctl_reg, 0x30, + (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4); + snd_soc_update_bits_wrapper(codec, + tx_vol_ctl_reg, 0x01, 0x00); + for (i = 0; i < NUM_DECIMATORS; i++) { + if (decimator == i + 1) + msm8x16_wcd->dec_active[i] = false; + } + if (decimator == 3 || decimator == 4) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL, + 0xFF, 0x0); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x0); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_TX1_DMIC_CTL + + (decimator - 1) * 0x20, 0x7, 0x0); + } + break; + } +out: + kfree(widget_name); + return ret; +} + +static int msm89xx_wcd_codec_enable_vdd_spkr(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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + if (!msm8x16_wcd->ext_spk_boost_set) { + dev_err(codec->dev, "%s: ext_boost not supported/disabled\n", + __func__); + return 0; + } + dev_err(codec->dev, "%s: %s %d\n", __func__, w->name, event); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (msm8x16_wcd->spkdrv_reg) { + ret = regulator_enable(msm8x16_wcd->spkdrv_reg); + if (ret) + dev_err(codec->dev, + "%s Failed to enable spkdrv reg %s\n", + __func__, MSM89XX_VDD_SPKDRV_NAME); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (msm8x16_wcd->spkdrv_reg) { + ret = regulator_disable(msm8x16_wcd->spkdrv_reg); + if (ret) + dev_err(codec->dev, + "%s: Failed to disable spkdrv_reg %s\n", + __func__, MSM89XX_VDD_SPKDRV_NAME); + } + break; + } + return 0; +} + +static int msm8x16_wcd_codec_config_compander(struct snd_soc_codec *codec, + int interp_n, int event) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: event %d shift %d, enabled %d\n", + __func__, event, interp_n, + msm8x16_wcd->comp_enabled[interp_n]); + + /* compander is not enabled */ + if (!msm8x16_wcd->comp_enabled[interp_n]) + return 0; + + switch (msm8x16_wcd->comp_enabled[interp_n]) { + case COMPANDER_1: + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x09); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x01); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 1 << interp_n, 1 << interp_n); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x01); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0x50); + /* add sleep for compander to settle */ + usleep_range(1000, 1100); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B3_CTL, 0xFF, 0x28); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0xF0, 0xB0); + + /* Enable Compander GPIO */ + if (msm8x16_wcd->codec_hph_comp_gpio) + msm8x16_wcd->codec_hph_comp_gpio(1); + } else if (SND_SOC_DAPM_EVENT_OFF(event)) { + /* Disable Compander GPIO */ + if (msm8x16_wcd->codec_hph_comp_gpio) + msm8x16_wcd->codec_hph_comp_gpio(0); + + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B2_CTL, 0x0F, 0x05); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_COMP0_B1_CTL, + 1 << interp_n, 0); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_RX_B2_CTL, 0x01, 0x00); + } + break; + default: + dev_err(codec->dev, "%s: Invalid compander %d\n", __func__, + msm8x16_wcd->comp_enabled[interp_n]); + break; + }; + + return 0; +} + +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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s %d %s\n", __func__, event, w->name); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msm8x16_wcd_codec_config_compander(codec, w->shift, event); + /* apply the digital gain after the interpolator is enabled*/ + if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg)) + snd_soc_write_wrapper(codec, + rx_digital_gain_reg[w->shift], + snd_soc_read_wrapper(codec, + rx_digital_gain_reg[w->shift]) + ); + break; + case SND_SOC_DAPM_POST_PMD: + msm8x16_wcd_codec_config_compander(codec, w->shift, event); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, + 1 << w->shift, 1 << w->shift); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_RX_RESET_CTL, + 1 << w->shift, 0x0); + /* + * disable the mute enabled during the PMD of this device + */ + if ((w->shift == 0) && + (msm8x16_wcd->mute_mask & HPHL_PA_DISABLE)) { + pr_err("disabling HPHL mute\n"); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00); + if (get_codec_version(msm8x16_wcd) >= CAJON) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP, + 0xF0, 0x20); + msm8x16_wcd->mute_mask &= ~(HPHL_PA_DISABLE); + } else if ((w->shift == 1) && + (msm8x16_wcd->mute_mask & HPHR_PA_DISABLE)) { + pr_err("disabling HPHR mute\n"); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00); + if (get_codec_version(msm8x16_wcd) >= CAJON) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP, + 0xF0, 0x20); + msm8x16_wcd->mute_mask &= ~(HPHR_PA_DISABLE); + } else if ((w->shift == 2) && + (msm8x16_wcd->mute_mask & SPKR_PA_DISABLE)) { + pr_err("disabling SPKR mute\n"); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00); + msm8x16_wcd->mute_mask &= ~(SPKR_PA_DISABLE); + } else if ((w->shift == 0) && + (msm8x16_wcd->mute_mask & EAR_PA_DISABLE)) { + pr_err("disabling EAR mute\n"); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00); + msm8x16_wcd->mute_mask &= ~(EAR_PA_DISABLE); + } + } + return 0; +} + + +/* The register address is the same as other codec so it can use resmgr */ +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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + msm8x16_wcd->rx_bias_count++; + if (msm8x16_wcd->rx_bias_count == 1) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, + 0x80, 0x80); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, + 0x01, 0x01); + } + break; + case SND_SOC_DAPM_POST_PMD: + msm8x16_wcd->rx_bias_count--; + if (msm8x16_wcd->rx_bias_count == 0) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, + 0x01, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, + 0x80, 0x00); + } + break; + } + dev_err(codec->dev, "%s rx_bias_count = %d\n", + __func__, msm8x16_wcd->rx_bias_count); + return 0; +} + +static uint32_t wcd_get_impedance_value(uint32_t imped) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wcd_imped_val) - 1; i++) { + if (imped >= wcd_imped_val[i] && + imped < wcd_imped_val[i + 1]) + break; + } + + pr_err("%s: selected impedance value = %d\n", + __func__, wcd_imped_val[i]); + return wcd_imped_val[i]; +} + +void wcd_imped_config(struct snd_soc_codec *codec, + uint32_t imped, bool set_gain) +{ + uint32_t value; + int codec_version; + struct msm8x16_wcd_priv *msm8x16_wcd = + snd_soc_codec_get_drvdata(codec); + + value = wcd_get_impedance_value(imped); + + if (value < wcd_imped_val[0]) { + pr_err("%s, detected impedance is less than 4 Ohm\n", + __func__); + return; + } + if (value >= wcd_imped_val[ARRAY_SIZE(wcd_imped_val) - 1]) { + pr_err("%s, invalid imped, greater than 48 Ohm\n = %d\n", + __func__, value); + return; + } + + codec_version = get_codec_version(msm8x16_wcd); + + if (set_gain) { + switch (codec_version) { + case TOMBAK_1_0: + case TOMBAK_2_0: + case CONGA: + /* + * For 32Ohm load and higher loads, Set 0x19E + * bit 5 to 1 (POS_6_DB_DI). For loads lower + * than 32Ohm (such as 16Ohm load), Set 0x19E + * bit 5 to 0 (POS_1P5_DB_DI) + */ + if (value >= 32) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, + 0x20, 0x20); + else + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, + 0x20, 0x00); + break; + case CAJON: + case CAJON_2_0: + case DIANGU: + if (value >= 13) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, + 0x20, 0x20); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_NCP_VCTRL, + 0x07, 0x07); + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, + 0x20, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_NCP_VCTRL, + 0x07, 0x04); + } + break; + } + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, + 0x20, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_NCP_VCTRL, + 0x07, 0x04); + } + + pr_err("%s: Exit\n", __func__); +} + +static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + uint32_t impedl, impedr; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + int ret; + + dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event); + ret = wcd_mbhc_get_impedance(&msm8x16_wcd->mbhc, + &impedl, &impedr); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (get_codec_version(msm8x16_wcd) > CAJON) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, + 0x08, 0x08); + if (get_codec_version(msm8x16_wcd) == CAJON || + get_codec_version(msm8x16_wcd) == CAJON_2_0) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, + 0x80, 0x80); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, + 0x80, 0x80); + } + if (get_codec_version(msm8x16_wcd) > CAJON) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, + 0x08, 0x00); + if (msm8x16_wcd->hph_mode == HD2_MODE) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x80); + } + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x01); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x02); + if (!ret) + wcd_imped_config(codec, impedl, true); + else + dev_err(codec->dev, "Failed to get mbhc impedance %d\n", + ret); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_imped_config(codec, impedl, false); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00); + if (msm8x16_wcd->hph_mode == HD2_MODE) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B3_CTL, 0x80, 0x00); + } + break; + } + return 0; +} + +static int msm8x16_wcd_lo_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); + + dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x10); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x20); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x80); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x80); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x40); + break; + case SND_SOC_DAPM_POST_PMD: + usleep_range(20000, 20100); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x80, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x40, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x80, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x40, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, 0x20, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x10, 0x00); + break; + } + return 0; +} + +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); + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (msm8x16_wcd->hph_mode == HD2_MODE) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 0x80); + } + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x02); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x01); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00); + if (msm8x16_wcd->hph_mode == HD2_MODE) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B3_CTL, 0x80, 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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: %s event = %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (w->shift == 5) + msm8x16_notifier_call(codec, + WCD_EVENT_PRE_HPHL_PA_ON); + else if (w->shift == 4) + msm8x16_notifier_call(codec, + WCD_EVENT_PRE_HPHR_PA_ON); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x20, 0x20); + break; + + case SND_SOC_DAPM_POST_PMU: + usleep_range(7000, 7100); + if (w->shift == 5) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x04); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00); + } else if (w->shift == 4) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x04); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x00); + } + break; + + case SND_SOC_DAPM_PRE_PMD: + if (w->shift == 5) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01); + msleep(20); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST, 0x04, 0x00); + msm8x16_wcd->mute_mask |= HPHL_PA_DISABLE; + msm8x16_notifier_call(codec, + WCD_EVENT_PRE_HPHL_PA_OFF); + } else if (w->shift == 4) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX2_B6_CTL, 0x01, 0x01); + msleep(20); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST, 0x04, 0x00); + msm8x16_wcd->mute_mask |= HPHR_PA_DISABLE; + msm8x16_notifier_call(codec, + WCD_EVENT_PRE_HPHR_PA_OFF); + } + if (get_codec_version(msm8x16_wcd) >= CAJON) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP, + 0xF0, 0x30); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (w->shift == 5) { + clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, + &msm8x16_wcd->mbhc.hph_pa_dac_state); + msm8x16_notifier_call(codec, + WCD_EVENT_POST_HPHL_PA_OFF); + } else if (w->shift == 4) { + clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, + &msm8x16_wcd->mbhc.hph_pa_dac_state); + msm8x16_notifier_call(codec, + WCD_EVENT_POST_HPHR_PA_OFF); + } + usleep_range(4000, 4100); + usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS); + + dev_err(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"}, + {"AIF2 VI", NULL, "TX_I2S_CLK"}, + + {"I2S TX1", NULL, "DEC1 MUX"}, + {"I2S TX2", NULL, "DEC2 MUX"}, + {"AIF2 VI", NULL, "DEC3 MUX"}, + {"AIF2 VI", NULL, "DEC4 MUX"}, + + /* RDAC Connections */ + {"HPHR DAC", NULL, "RDAC2 MUX"}, + {"RDAC2 MUX", "RX1", "RX1 CHAIN"}, + {"RDAC2 MUX", "RX2", "RX2 CHAIN"}, + + /* WSA */ + {"WSA_SPK OUT", NULL, "WSA Spk Switch"}, + {"WSA Spk Switch", "WSA", "EAR PA"}, + + /* 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"}, + + {"Ext Spk", NULL, "Ext Spk Switch"}, + {"Ext Spk Switch", "On", "HPHL PA"}, + {"Ext Spk Switch", "On", "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"}, + {"SPK", "Switch", "SPK DAC"}, + {"SPK DAC", NULL, "RX3 CHAIN"}, + {"SPK DAC", NULL, "VDD_SPKDRV"}, + + /* lineout */ + {"LINEOUT", NULL, "LINEOUT PA"}, + {"LINEOUT PA", NULL, "SPK_RX_BIAS"}, + {"LINEOUT PA", NULL, "LINE_OUT"}, + {"LINE_OUT", "Switch", "LINEOUT DAC"}, + {"LINEOUT DAC", NULL, "RX3 CHAIN"}, + + /* lineout to WSA */ + {"WSA_SPK OUT", NULL, "LINEOUT PA"}, + + {"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"}, + + {"DEC3 MUX", "DMIC3", "DMIC3"}, + {"DEC4 MUX", "DMIC4", "DMIC4"}, + {"DEC3 MUX", NULL, "CDC_CONN"}, + {"DEC4 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_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = + snd_soc_codec_get_drvdata(dai->codec); + + dev_err(dai->codec->dev, "%s(): substream = %s stream = %d\n", + __func__, + substream->name, substream->stream); + /* + * If status_mask is BU_DOWN it means SSR is not complete. + * So retun error. + */ + if (test_bit(BUS_DOWN, &msm8x16_wcd->status_mask)) { + dev_err(dai->codec->dev, "Error, Device is not up post SSR\n"); + return -EINVAL; + } + return 0; +} + +static void msm8x16_wcd_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + dev_err(dai->codec->dev, + "%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); +} + +int msm8x16_wcd_mclk_enable(struct snd_soc_codec *codec, + int mclk_enable, bool dapm) +{ + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: mclk_enable = %u, dapm = %d\n", + __func__, mclk_enable, dapm); + if (mclk_enable) { + msm8x16_wcd->mclk_enabled = true; + msm8x16_wcd_codec_enable_clock_block(codec, 1); + } else { + if (!msm8x16_wcd->mclk_enabled) { + dev_err(codec->dev, "Error, MCLK already diabled\n"); + return -EINVAL; + } + msm8x16_wcd->mclk_enabled = false; + msm8x16_wcd_codec_enable_clock_block(codec, 0); + } + return 0; +} + +static int msm8x16_wcd_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + dev_err(dai->codec->dev, "%s\n", __func__); + return 0; +} + +static int msm8x16_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + dev_err(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_err(dai->codec->dev, "%s\n", __func__); + return 0; +} + +static int msm8x16_wcd_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) + +{ + dev_err(dai->codec->dev, "%s\n", __func__); + return 0; +} + +static int msm8x16_wcd_set_interpolator_rate(struct snd_soc_dai *dai, + u8 rx_fs_rate_reg_val, u32 sample_rate) +{ + snd_soc_update_bits_wrapper(dai->codec, + MSM89XX_CDC_CORE_RX1_B5_CTL, 0xF0, rx_fs_rate_reg_val); + snd_soc_update_bits_wrapper(dai->codec, + MSM89XX_CDC_CORE_RX2_B5_CTL, 0xF0, rx_fs_rate_reg_val); + 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, rx_clk_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; + rx_clk_fs_rate = 0x00; + break; + case 16000: + tx_fs_rate = 0x20; + rx_fs_rate = 0x20; + rx_clk_fs_rate = 0x01; + break; + case 32000: + tx_fs_rate = 0x40; + rx_fs_rate = 0x40; + rx_clk_fs_rate = 0x02; + break; + case 48000: + tx_fs_rate = 0x60; + rx_fs_rate = 0x60; + rx_clk_fs_rate = 0x03; + break; + case 96000: + tx_fs_rate = 0x80; + rx_fs_rate = 0x80; + rx_clk_fs_rate = 0x04; + break; + case 192000: + tx_fs_rate = 0xA0; + rx_fs_rate = 0xA0; + rx_clk_fs_rate = 0x05; + break; + default: + dev_err(dai->codec->dev, + "%s: Invalid sampling rate %d\n", __func__, + params_rate(params)); + return -EINVAL; + } + + snd_soc_update_bits_wrapper(dai->codec, + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x0F, rx_clk_fs_rate); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_CAPTURE: + 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_wrapper(dai->codec, + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x20); + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_update_bits_wrapper(dai->codec, + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 0x20, 0x00); + break; + default: + dev_err(dai->codec->dev, "%s: wrong format selected\n", + __func__); + return -EINVAL; + } + + return 0; +} + +int msm8x16_wcd_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = NULL; + u16 tx_vol_ctl_reg = 0; + u8 decimator = 0, i; + struct msm8x16_wcd_priv *msm8x16_wcd; + + pr_err("%s: Digital Mute val = %d\n", __func__, mute); + + if (!dai || !dai->codec) { + pr_err("%s: Invalid params\n", __func__); + return -EINVAL; + } + codec = dai->codec; + msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + if ((dai->id != AIF1_CAP) && (dai->id != AIF2_VIFEED)) { + dev_err(codec->dev, "%s: Not capture use case skip\n", + __func__); + return 0; + } + + mute = (mute) ? 1 : 0; + if (!mute) { + /* + * 15 ms is an emperical value for the mute time + * that was arrived by checking the pop level + * to be inaudible + */ + usleep_range(15000, 15010); + } + + for (i = 0; i < NUM_DECIMATORS; i++) { + if (msm8x16_wcd->dec_active[i]) + decimator = i + 1; + if (decimator && decimator <= NUM_DECIMATORS) { + pr_err("%s: Mute = %d Decimator = %d", __func__, + mute, decimator); + tx_vol_ctl_reg = MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG + + 32 * (decimator - 1); + snd_soc_update_bits_wrapper(codec, + tx_vol_ctl_reg, 0x01, mute); + } + decimator = 0; + } + 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, + .get_channel_map = msm8x16_wcd_get_channel_map, + .digital_mute = msm8x16_wcd_digital_mute, +}; + +static struct snd_soc_dai_driver msm8x16_wcd_i2s_dai[] = { + { + .name = "msm8x16_wcd_i2s_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = MSM89XX_RATES, + .formats = MSM89XX_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 3, + }, + .ops = &msm8x16_wcd_dai_ops, + }, + { + .name = "msm8x16_wcd_i2s_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = MSM89XX_RATES, + .formats = MSM89XX_FORMATS, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &msm8x16_wcd_dai_ops, + }, + { + .name = "cajon_vifeedback", + .id = AIF2_VIFEED, + .capture = { + .stream_name = "VIfeed", + .rates = MSM89XX_RATES, + .formats = MSM89XX_FORMATS, + .rate_max = 48000, + .rate_min = 48000, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &msm8x16_wcd_dai_ops, + }, +}; + +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: + dev_err(codec->dev, + "%s: PMU:Sleeping 20ms after disabling mute\n", + __func__); + break; + case SND_SOC_DAPM_POST_PMD: + dev_err(codec->dev, + "%s: PMD:Sleeping 20ms after disabling mute\n", + __func__); + snd_soc_update_bits_wrapper(codec, w->reg, + 1 << w->shift, 0x00); + msleep(20); + break; + } + return 0; +} + +static int msm8x16_wcd_codec_enable_lo_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); + + dev_err(codec->dev, "%s: %d %s\n", __func__, event, w->name); + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX3_B6_CTL, 0x01, 0x00); + break; + } + + return 0; +} + +static int msm8x16_wcd_codec_enable_spk_ext_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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + dev_err(codec->dev, "%s: %s event = %d\n", __func__, w->name, event); + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dev_err(codec->dev, + "%s: enable external speaker PA\n", __func__); + if (msm8x16_wcd->codec_spk_ext_pa_cb) + msm8x16_wcd->codec_spk_ext_pa_cb(codec, 1); + break; + case SND_SOC_DAPM_PRE_PMD: + dev_err(codec->dev, + "%s: enable external speaker PA\n", __func__); + if (msm8x16_wcd->codec_spk_ext_pa_cb) + msm8x16_wcd->codec_spk_ext_pa_cb(codec, 0); + break; + } + return 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 msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dev_err(codec->dev, + "%s: Sleeping 20ms after select EAR PA\n", + __func__); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x80, 0x80); + if (get_codec_version(msm8x16_wcd) < CONGA) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x2A); + break; + case SND_SOC_DAPM_POST_PMU: + dev_err(codec->dev, + "%s: Sleeping 20ms after enabling EAR PA\n", + __func__); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x40, 0x40); + usleep_range(7000, 7100); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x00); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_RX1_B6_CTL, 0x01, 0x01); + msleep(20); + msm8x16_wcd->mute_mask |= EAR_PA_DISABLE; + if (msm8x16_wcd->boost_option == BOOST_ALWAYS) { + dev_err(codec->dev, + "%s: boost_option:%d, tear down ear\n", + __func__, msm8x16_wcd->boost_option); + msm8x16_wcd_boost_mode_sequence(codec, EAR_PMD); + } + break; + case SND_SOC_DAPM_POST_PMD: + dev_err(codec->dev, + "%s: Sleeping 7ms after disabling EAR PA\n", + __func__); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x40, 0x00); + usleep_range(7000, 7100); + if (get_codec_version(msm8x16_wcd) < CONGA) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME, 0xFF, 0x16); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = { + /*RX stuff */ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("WSA_SPK OUT"), + + 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_MUX("EAR_S", SND_SOC_NOPM, 0, 0, + ear_pa_mux), + + SND_SOC_DAPM_MUX("WSA Spk Switch", SND_SOC_NOPM, 0, 0, + wsa_spk_mux), + + 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_SPK("Ext Spk", msm8x16_wcd_codec_enable_spk_ext_pa), + + SND_SOC_DAPM_OUTPUT("HEADPHONE"), + SND_SOC_DAPM_PGA_E("HPHL PA", MSM89XX_PMIC_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", + MSM89XX_PMIC_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", MSM89XX_PMIC_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", + MSM89XX_PMIC_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_MUX("SPK", SND_SOC_NOPM, 0, 0, + spkr_mux), + + SND_SOC_DAPM_DAC("SPK DAC", NULL, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 7, 0), + + SND_SOC_DAPM_MUX("LINE_OUT", + SND_SOC_NOPM, 0, 0, lo_mux), + + SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL, + SND_SOC_NOPM, 0, 0, msm8x16_wcd_lo_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* Speaker */ + SND_SOC_DAPM_OUTPUT("SPK_OUT"), + + /* Lineout */ + SND_SOC_DAPM_OUTPUT("LINEOUT"), + + SND_SOC_DAPM_PGA_E("SPK PA", MSM89XX_PMIC_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_PGA_E("LINEOUT PA", MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL, + 5, 0, NULL, 0, msm8x16_wcd_codec_enable_lo_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0, + msm89xx_wcd_codec_enable_vdd_spkr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("Ext Spk Switch", SND_SOC_NOPM, 0, 0, + &ext_spk_mux), + + 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", + MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX1, 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", + MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX2, 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", + MSM89XX_CDC_CORE_CLK_RX_B1_CTL, MSM89XX_RX3, 0, NULL, + 0, msm8x16_wcd_codec_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM89XX_PMIC_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", MSM89XX_CDC_CORE_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", MSM89XX_CDC_CORE_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", MSM89XX_CDC_CORE_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", MSM89XX_PMIC_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", MSM89XX_PMIC_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_S("RX_BIAS", 1, 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_S("SPK_RX_BIAS", 1, 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, MSM89XX_CDC_CORE_CLK_OTHR_CTL, + 2, 0, NULL, 0), + + + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1", + MSM89XX_PMIC_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_MICBIAS_E("MIC BIAS Internal2", + MSM89XX_PMIC_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_MICBIAS_E("MIC BIAS Internal3", + MSM89XX_PMIC_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, MSM89XX_PMIC_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, MSM89XX_PMIC_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, MSM89XX_PMIC_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_MICBIAS_E("MIC BIAS External", + MSM89XX_PMIC_ANALOG_MICB_1_EN, 7, 0, + msm8x16_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MICBIAS_E("MIC BIAS External2", + MSM89XX_PMIC_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", + MSM89XX_CDC_CORE_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", + MSM89XX_CDC_CORE_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_E("DEC3 MUX", + MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 2, 0, + &dec3_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("DEC4 MUX", + MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL, 3, 0, + &dec4_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), + + SND_SOC_DAPM_AIF_OUT("AIF2 VI", "VIfeed", 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), + + SND_SOC_DAPM_INPUT("DMIC3"), + + SND_SOC_DAPM_INPUT("DMIC4"), + + /* Sidetone */ + SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux), + SND_SOC_DAPM_PGA_E("IIR1", MSM89XX_CDC_CORE_CLK_SD_CTL, 0, 0, NULL, 0, + msm8x16_wcd_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux), + SND_SOC_DAPM_PGA_E("IIR2", MSM89XX_CDC_CORE_CLK_SD_CTL, 1, 0, NULL, 0, + msm8x16_wcd_codec_set_iir_gain, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", + MSM89XX_CDC_CORE_CLK_RX_I2S_CTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", + MSM89XX_CDC_CORE_CLK_TX_I2S_CTL, 4, 0, + NULL, 0), +}; + +static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults[] = { + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1), +}; + +static const struct msm8x16_wcd_reg_mask_val msm8x16_wcd_reg_defaults_2_0[] = { + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BOOST_EN_CTL, 0x5F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO, 0x88), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80), +}; + +static const struct msm8x16_wcd_reg_mask_val msm8909_wcd_reg_defaults[] = { + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0x28), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE, 0x0A), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80), +}; + +static const struct msm8x16_wcd_reg_mask_val cajon_wcd_reg_defaults[] = { + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0x82), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80), +}; + +static const struct msm8x16_wcd_reg_mask_val cajon2p0_wcd_reg_defaults[] = { + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SEC_ACCESS, 0xA5), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3, 0x0F), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS, 0x4C), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_CURRENT_LIMIT, 0xA2), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_FBCTRL, 0xA8), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_NCP_VCTRL, 0xA4), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET, 0x41), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, 0x69), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG, 0x01), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL, 0xE1), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x03), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_EAR_STATUS, 0x10), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_BYPASS_MODE, 0x18), + MSM89XX_REG_VAL(MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA, 0xFA), + MSM89XX_REG_VAL(MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80), +}; + +static void msm8x16_wcd_update_reg_defaults(struct snd_soc_codec *codec) +{ + u32 i, version; + struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); + + version = get_codec_version(msm8x16_wcd); + if (version == TOMBAK_1_0) { + for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults); i++) + snd_soc_write_wrapper(codec, + msm8x16_wcd_reg_defaults[i].reg, + msm8x16_wcd_reg_defaults[i].val); + } else if (version == TOMBAK_2_0) { + for (i = 0; i < ARRAY_SIZE(msm8x16_wcd_reg_defaults_2_0); i++) + snd_soc_write_wrapper(codec, + msm8x16_wcd_reg_defaults_2_0[i].reg, + msm8x16_wcd_reg_defaults_2_0[i].val); + } else if (version == CONGA) { + for (i = 0; i < ARRAY_SIZE(msm8909_wcd_reg_defaults); i++) + snd_soc_write_wrapper(codec, + msm8909_wcd_reg_defaults[i].reg, + msm8909_wcd_reg_defaults[i].val); + } else if (version == CAJON) { + for (i = 0; i < ARRAY_SIZE(cajon_wcd_reg_defaults); i++) + snd_soc_write_wrapper(codec, + cajon_wcd_reg_defaults[i].reg, + cajon_wcd_reg_defaults[i].val); + } else if (version == CAJON_2_0 || version == DIANGU) { + for (i = 0; i < ARRAY_SIZE(cajon2p0_wcd_reg_defaults); i++) + snd_soc_write_wrapper(codec, + cajon2p0_wcd_reg_defaults[i].reg, + cajon2p0_wcd_reg_defaults[i].val); + } +} + +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 + */ + {MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL, 0xFF, 0x12}, + {MSM89XX_PMIC_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_wrapper(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 int msm8x16_wcd_bringup(struct snd_soc_codec *codec) +{ + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_DIGITAL_SEC_ACCESS, + 0xA5); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x01); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_SEC_ACCESS, + 0xA5); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x01); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_DIGITAL_SEC_ACCESS, + 0xA5); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4, 0x00); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_SEC_ACCESS, + 0xA5); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4, 0x00); + return 0; +} + +static struct regulator *wcd8x16_wcd_codec_find_regulator( + const struct msm8x16_wcd *msm8x16, + const char *name) +{ + int i; + + for (i = 0; i < msm8x16->num_of_supplies; i++) { + if (msm8x16->supplies[i].supply && + !strcmp(msm8x16->supplies[i].supply, name)) + return msm8x16->supplies[i].consumer; + } + + dev_err(msm8x16->dev, "Error: regulator not found:%s\n" + , name); + return NULL; +} + +static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) +{ + struct msm8916_asoc_mach_data *pdata = NULL; + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + int i; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + dev_err(codec->dev, "%s: device down!\n", __func__); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_TX_1_EN, 0x3); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_TX_2_EN, 0x3); + if (msm8x16_wcd_priv->boost_option == BOOST_ON_FOREVER) { + if ((snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL) + & 0x80) == 0) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_MCLK_CTL, 0x01, 0x01); + snd_soc_update_bits_wrapper(codec, + MSM89XX_CDC_CORE_CLK_PDM_CTL, 0x03, 0x03); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, + 0x0C, 0x0C); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL, + 0x84, 0x84); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL, + 0x10, 0x10); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, + 0x1F, 0x1F); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC, + 0x90, 0x90); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, + 0xFF, 0xFF); + usleep_range(20, 21); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL, + 0xFF, 0xFF); + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, + 0xE9, 0xE9); + } + } + msm8x16_wcd_boost_off(codec); + msm8x16_wcd_priv->hph_mode = NORMAL_MODE; + for (i = 0; i < MSM89XX_RX_MAX; i++) + msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE; + + /* 40ms to allow boost to discharge */ + msleep(40); + /* Disable PA to avoid pop during codec bring up */ + snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN, + 0x30, 0x00); + snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL, + 0x80, 0x00); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x20); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x20); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_RX_EAR_CTL, 0x12); + snd_soc_write_wrapper(codec, + MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93); + + msm8x16_wcd_bringup(codec); + atomic_set(&pdata->mclk_enabled, false); + set_bit(BUS_DOWN, &msm8x16_wcd_priv->status_mask); + snd_soc_card_change_online_state(codec->component.card, 0); + return 0; +} + +static int msm8x16_wcd_device_up(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + int ret = 0; + + dev_err(codec->dev, "%s: device up!\n", __func__); + + clear_bit(BUS_DOWN, &msm8x16_wcd_priv->status_mask); + + snd_soc_card_change_online_state(codec->component.card, 1); + /* 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); + + snd_soc_write_wrapper(codec, MSM89XX_PMIC_DIGITAL_INT_EN_SET, + MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR); + snd_soc_write_wrapper(codec, MSM89XX_PMIC_DIGITAL_INT_EN_CLR, + MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR); + + msm8x16_wcd_set_boost_v(codec); + + msm8x16_wcd_set_micb_v(codec); + if (msm8x16_wcd_priv->boost_option == BOOST_ON_FOREVER) + msm8x16_wcd_boost_on(codec); + else if (msm8x16_wcd_priv->boost_option == BYPASS_ALWAYS) + msm8x16_wcd_bypass_on(codec); + + msm8x16_wcd_configure_cap(codec, false, false); + wcd_mbhc_stop(&msm8x16_wcd_priv->mbhc); + wcd_mbhc_deinit(&msm8x16_wcd_priv->mbhc); + ret = wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, true); + if (ret) + dev_err(codec->dev, "%s: mbhc initialization failed\n", + __func__); + else + wcd_mbhc_start(&msm8x16_wcd_priv->mbhc, + msm8x16_wcd_priv->mbhc.mbhc_cfg); + + + return 0; +} + +static int adsp_state_callback(struct notifier_block *nb, unsigned long value, + void *priv) +{ + bool timedout; + unsigned long timeout; + + if (value == SUBSYS_BEFORE_SHUTDOWN) + msm8x16_wcd_device_down(registered_codec); + else if (value == SUBSYS_AFTER_POWERUP) { + + dev_err(registered_codec->dev, + "ADSP is about to power up. bring up codec\n"); + + if (!q6core_is_adsp_ready()) { + dev_err(registered_codec->dev, + "ADSP isn't ready\n"); + timeout = jiffies + + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS); + while (!(timedout = time_after(jiffies, timeout))) { + if (!q6core_is_adsp_ready()) { + dev_err(registered_codec->dev, + "ADSP isn't ready\n"); + } else { + dev_err(registered_codec->dev, + "ADSP is ready\n"); + break; + } + } + } else { + dev_err(registered_codec->dev, + "%s: DSP is ready\n", __func__); + } + + msm8x16_wcd_device_up(registered_codec); + } + return NOTIFY_OK; +} + +static struct notifier_block adsp_state_notifier_block = { + .notifier_call = adsp_state_callback, + .priority = -INT_MAX, +}; + +int msm8x16_wcd_hs_detect(struct snd_soc_codec *codec, + struct wcd_mbhc_config *mbhc_cfg) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + + return wcd_mbhc_start(&msm8x16_wcd_priv->mbhc, mbhc_cfg); +} +EXPORT_SYMBOL(msm8x16_wcd_hs_detect); + +void msm8x16_wcd_hs_detect_exit(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + + wcd_mbhc_stop(&msm8x16_wcd_priv->mbhc); +} +EXPORT_SYMBOL(msm8x16_wcd_hs_detect_exit); + +void msm8x16_update_int_spk_boost(bool enable) +{ + pr_err("%s: enable = %d\n", __func__, enable); + spkr_boost_en = enable; +} +EXPORT_SYMBOL(msm8x16_update_int_spk_boost); + +static void msm8x16_wcd_set_micb_v(struct snd_soc_codec *codec) +{ + + struct msm8x16_wcd *msm8x16 = codec->control_data; + struct msm8x16_wcd_pdata *pdata = msm8x16->dev->platform_data; + u8 reg_val; + + reg_val = VOLTAGE_CONVERTER(pdata->micbias.cfilt1_mv, MICBIAS_MIN_VAL, + MICBIAS_STEP_SIZE); + dev_err(codec->dev, "cfilt1_mv %d reg_val %x\n", + (u32)pdata->micbias.cfilt1_mv, reg_val); + snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_MICB_1_VAL, + 0xF8, (reg_val << 3)); +} + +static void msm8x16_wcd_set_boost_v(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + + snd_soc_update_bits_wrapper(codec, MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE, + 0x1F, msm8x16_wcd_priv->boost_voltage); +} + +static void msm8x16_wcd_configure_cap(struct snd_soc_codec *codec, + bool micbias1, bool micbias2) +{ + + struct msm8916_asoc_mach_data *pdata = NULL; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + + pr_err("\n %s: micbias1 %x micbias2 = %d\n", __func__, micbias1, + micbias2); + if (micbias1 && micbias2) { + if ((pdata->micbias1_cap_mode + == MICBIAS_EXT_BYP_CAP) || + (pdata->micbias2_cap_mode + == MICBIAS_EXT_BYP_CAP)) + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_EN, + 0x40, (MICBIAS_EXT_BYP_CAP << 6)); + else + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_EN, + 0x40, (MICBIAS_NO_EXT_BYP_CAP << 6)); + } else if (micbias2) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_EN, + 0x40, (pdata->micbias2_cap_mode << 6)); + } else if (micbias1) { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_EN, + 0x40, (pdata->micbias1_cap_mode << 6)); + } else { + snd_soc_update_bits_wrapper(codec, + MSM89XX_PMIC_ANALOG_MICB_1_EN, + 0x40, 0x00); + } +} + +static int msm89xx_digcodec_probe(struct snd_soc_codec *codec) +{ + registered_digcodec = codec; + + return 0; +} + + +static int msm89xx_digcodec_remove(struct snd_soc_codec *codec) +{ + return 0; +} + +static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv; + int i, ret; + + dev_err(codec->dev, "%s()\n", __func__); + + msm8x16_wcd_priv = kzalloc(sizeof(struct msm8x16_wcd_priv), GFP_KERNEL); + if (!msm8x16_wcd_priv) + return -ENOMEM; + + for (i = 0; i < NUM_DECIMATORS; i++) { + tx_hpf_work[i].msm8x16_wcd = msm8x16_wcd_priv; + tx_hpf_work[i].decimator = i + 1; + INIT_DELAYED_WORK(&tx_hpf_work[i].dwork, + tx_hpf_corner_freq_callback); + } + + codec->control_data = dev_get_drvdata(codec->dev); + snd_soc_codec_set_drvdata(codec, msm8x16_wcd_priv); + msm8x16_wcd_priv->codec = codec; + + msm8x16_wcd_priv->spkdrv_reg = + wcd8x16_wcd_codec_find_regulator(codec->control_data, + MSM89XX_VDD_SPKDRV_NAME); + msm8x16_wcd_priv->pmic_rev = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_DIGITAL_REVISION1); + msm8x16_wcd_priv->codec_version = snd_soc_read_wrapper(codec, + MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE); + if (msm8x16_wcd_priv->codec_version == CONGA) { + dev_err(codec->dev, "%s :Conga REV: %d\n", __func__, + msm8x16_wcd_priv->codec_version); + msm8x16_wcd_priv->ext_spk_boost_set = true; + } else { + dev_err(codec->dev, "%s :PMIC REV: %d\n", __func__, + msm8x16_wcd_priv->pmic_rev); + if (msm8x16_wcd_priv->pmic_rev == TOMBAK_1_0 && + msm8x16_wcd_priv->codec_version == CAJON_2_0) { + msm8x16_wcd_priv->codec_version = DIANGU; + dev_err(codec->dev, "%s : Diangu detected\n", + __func__); + } else if (msm8x16_wcd_priv->pmic_rev == TOMBAK_1_0 && + (snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_NCP_FBCTRL) + & 0x80)) { + msm8x16_wcd_priv->codec_version = CAJON; + dev_err(codec->dev, "%s : Cajon detected\n", __func__); + } else if (msm8x16_wcd_priv->pmic_rev == TOMBAK_2_0 && + (snd_soc_read_wrapper(codec, + MSM89XX_PMIC_ANALOG_NCP_FBCTRL) + & 0x80)) { + msm8x16_wcd_priv->codec_version = CAJON_2_0; + dev_err(codec->dev, "%s : Cajon 2.0 detected\n", + __func__); + } + } + /* + * set to default boost option BOOST_SWITCH, user mixer path can change + * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen. + */ + msm8x16_wcd_priv->boost_option = BOOST_SWITCH; + msm8x16_wcd_priv->hph_mode = NORMAL_MODE; + + for (i = 0; i < MSM89XX_RX_MAX; i++) + msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE; + + msm8x16_wcd_dt_parse_boost_info(codec); + msm8x16_wcd_set_boost_v(codec); + + snd_soc_add_codec_controls(codec, impedance_detect_controls, + ARRAY_SIZE(impedance_detect_controls)); + snd_soc_add_codec_controls(codec, hph_type_detect_controls, + ARRAY_SIZE(hph_type_detect_controls)); + + msm8x16_wcd_bringup(codec); + msm8x16_wcd_codec_init_reg(codec); + msm8x16_wcd_update_reg_defaults(codec); + + wcd9xxx_spmi_set_codec(codec); + + msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = + wcd8x16_wcd_codec_find_regulator( + codec->control_data, + on_demand_supply_name[ON_DEMAND_MICBIAS]); + atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0); + + BLOCKING_INIT_NOTIFIER_HEAD(&msm8x16_wcd_priv->notifier); + + msm8x16_wcd_priv->fw_data = kzalloc(sizeof(*(msm8x16_wcd_priv->fw_data)) + , GFP_KERNEL); + if (!msm8x16_wcd_priv->fw_data) { + kfree(msm8x16_wcd_priv); + return -ENOMEM; + } + + set_bit(WCD9XXX_MBHC_CAL, msm8x16_wcd_priv->fw_data->cal_bit); + ret = wcd_cal_create_hwdep(msm8x16_wcd_priv->fw_data, + WCD9XXX_CODEC_HWDEP_NODE, codec); + if (ret < 0) { + dev_err(codec->dev, "%s hwdep failed %d\n", __func__, ret); + kfree(msm8x16_wcd_priv->fw_data); + kfree(msm8x16_wcd_priv); + return ret; + } + + wcd_mbhc_init(&msm8x16_wcd_priv->mbhc, codec, &mbhc_cb, &intr_ids, + wcd_mbhc_registers, true); + + msm8x16_wcd_priv->mclk_enabled = false; + msm8x16_wcd_priv->clock_active = false; + msm8x16_wcd_priv->config_mode_active = false; + + /*Update speaker boost configuration*/ + msm8x16_wcd_priv->spk_boost_set = spkr_boost_en; + pr_err("%s: speaker boost configured = %d\n", + __func__, msm8x16_wcd_priv->spk_boost_set); + + /* Set initial MICBIAS voltage level */ + msm8x16_wcd_set_micb_v(codec); + + /* Set initial cap mode */ + msm8x16_wcd_configure_cap(codec, false, false); + registered_codec = codec; + adsp_state_notifier = + subsys_notif_register_notifier("adsp", + &adsp_state_notifier_block); + if (!adsp_state_notifier) { + dev_err(codec->dev, "Failed to register adsp state notifier\n"); + kfree(msm8x16_wcd_priv->fw_data); + kfree(msm8x16_wcd_priv); + registered_codec = NULL; + return -ENOMEM; + } + return 0; +} + +static int msm8x16_wcd_codec_remove(struct snd_soc_codec *codec) +{ + struct msm8x16_wcd_priv *msm8x16_wcd_priv = + snd_soc_codec_get_drvdata(codec); + struct msm8x16_wcd *msm8x16_wcd; + + msm8x16_wcd = codec->control_data; + msm8x16_wcd_priv->spkdrv_reg = NULL; + msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL; + atomic_set(&msm8x16_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0); + kfree(msm8x16_wcd_priv->fw_data); + kfree(msm8x16_wcd_priv); + + return 0; +} + +static int msm8x16_wcd_enable_static_supplies_to_optimum( + struct msm8x16_wcd *msm8x16, + struct msm8x16_wcd_pdata *pdata) +{ + int i; + int ret = 0; + + for (i = 0; i < msm8x16->num_of_supplies; i++) { + if (pdata->regulator[i].ondemand) + continue; + if (regulator_count_voltages(msm8x16->supplies[i].consumer) <= + 0) + continue; + + ret = regulator_set_voltage(msm8x16->supplies[i].consumer, + pdata->regulator[i].min_uv, + pdata->regulator[i].max_uv); + if (ret) { + dev_err(msm8x16->dev, + "Setting volt failed for regulator %s err %d\n", + msm8x16->supplies[i].supply, ret); + } + + ret = regulator_set_load(msm8x16->supplies[i].consumer, + pdata->regulator[i].optimum_ua); + dev_err(msm8x16->dev, "Regulator %s set optimum mode\n", + msm8x16->supplies[i].supply); + } + + return ret; +} + +static int msm8x16_wcd_disable_static_supplies_to_optimum( + struct msm8x16_wcd *msm8x16, + struct msm8x16_wcd_pdata *pdata) +{ + int i; + int ret = 0; + + for (i = 0; i < msm8x16->num_of_supplies; i++) { + if (pdata->regulator[i].ondemand) + continue; + if (regulator_count_voltages(msm8x16->supplies[i].consumer) <= + 0) + continue; + regulator_set_voltage(msm8x16->supplies[i].consumer, 0, + pdata->regulator[i].max_uv); + regulator_set_load(msm8x16->supplies[i].consumer, 0); + dev_err(msm8x16->dev, "Regulator %s set optimum mode\n", + msm8x16->supplies[i].supply); + } + + return ret; +} + +int msm8x16_wcd_suspend(struct snd_soc_codec *codec) +{ + struct msm8916_asoc_mach_data *pdata = NULL; + struct msm8x16_wcd *msm8x16 = codec->control_data; + struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + pr_err("%s: mclk cnt = %d, mclk_enabled = %d\n", + __func__, atomic_read(&pdata->mclk_rsc_ref), + atomic_read(&pdata->mclk_enabled)); + if (atomic_read(&pdata->mclk_enabled) == true) { + cancel_delayed_work_sync( + &pdata->disable_mclk_work); + mutex_lock(&pdata->cdc_mclk_mutex); + if (atomic_read(&pdata->mclk_enabled) == true) { + if (pdata->afe_clk_ver == AFE_CLK_VERSION_V1) { + pdata->digital_cdc_clk.clk_val = 0; + afe_set_digital_codec_core_clock( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_clk); + } else { + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2( + AFE_PORT_ID_PRIMARY_MI2S_RX, + &pdata->digital_cdc_core_clk); + } + atomic_set(&pdata->mclk_enabled, false); + } + mutex_unlock(&pdata->cdc_mclk_mutex); + } + msm8x16_wcd_disable_static_supplies_to_optimum(msm8x16, msm8x16_pdata); + return 0; +} + +int msm8x16_wcd_resume(struct snd_soc_codec *codec) +{ + struct msm8916_asoc_mach_data *pdata = NULL; + struct msm8x16_wcd *msm8x16 = codec->control_data; + struct msm8x16_wcd_pdata *msm8x16_pdata = msm8x16->dev->platform_data; + + pdata = snd_soc_card_get_drvdata(codec->component.card); + msm8x16_wcd_enable_static_supplies_to_optimum(msm8x16, msm8x16_pdata); + return 0; +} + +static struct regmap *msm89xx_pmic_cdc_regmap; +static struct regmap *msm89xx_pmic_cdc_get_regmap(struct device *dev) +{ + return msm89xx_pmic_cdc_regmap; +} + +static const struct snd_soc_codec_driver soc_codec_dev_msm8x16_wcd = { + .probe = msm8x16_wcd_codec_probe, + .remove = msm8x16_wcd_codec_remove, + + .suspend = msm8x16_wcd_suspend, + .resume = msm8x16_wcd_resume, + + .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), + .get_regmap = msm89xx_pmic_cdc_get_regmap, +}; + +static int msm8x16_wcd_init_supplies(struct msm8x16_wcd *msm8x16, + struct msm8x16_wcd_pdata *pdata) +{ + int ret; + int i; + + msm8x16->supplies = kzalloc(sizeof(struct regulator_bulk_data) * + ARRAY_SIZE(pdata->regulator), + GFP_KERNEL); + if (!msm8x16->supplies) { + ret = -ENOMEM; + goto err; + } + + msm8x16->num_of_supplies = 0; + + if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) { + dev_err(msm8x16->dev, "%s: Array Size out of bound\n", + __func__); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) { + if (pdata->regulator[i].name) { + msm8x16->supplies[i].supply = pdata->regulator[i].name; + msm8x16->num_of_supplies++; + } + } + + ret = regulator_bulk_get(msm8x16->dev, msm8x16->num_of_supplies, + msm8x16->supplies); + if (ret != 0) { + dev_err(msm8x16->dev, "Failed to get supplies: err = %d\n", + ret); + goto err_supplies; + } + + for (i = 0; i < msm8x16->num_of_supplies; i++) { + if (regulator_count_voltages(msm8x16->supplies[i].consumer) <= + 0) + continue; + + ret = regulator_set_voltage(msm8x16->supplies[i].consumer, + pdata->regulator[i].min_uv, + pdata->regulator[i].max_uv); + if (ret) { + dev_err(msm8x16->dev, "Setting regulator voltage failed for regulator %s err = %d\n", + msm8x16->supplies[i].supply, ret); + goto err_get; + } + + ret = regulator_set_load(msm8x16->supplies[i].consumer, + pdata->regulator[i].optimum_ua); + if (ret < 0) { + dev_err(msm8x16->dev, "Setting regulator optimum mode failed for regulator %s err = %d\n", + msm8x16->supplies[i].supply, ret); + goto err_get; + } else { + ret = 0; + } + } + + return ret; + +err_get: + regulator_bulk_free(msm8x16->num_of_supplies, msm8x16->supplies); +err_supplies: + kfree(msm8x16->supplies); +err: + return ret; +} + +static int msm8x16_wcd_enable_static_supplies(struct msm8x16_wcd *msm8x16, + struct msm8x16_wcd_pdata *pdata) +{ + int i; + int ret = 0; + + for (i = 0; i < msm8x16->num_of_supplies; i++) { + if (pdata->regulator[i].ondemand) + continue; + ret = regulator_enable(msm8x16->supplies[i].consumer); + if (ret) { + dev_err(msm8x16->dev, "Failed to enable %s\n", + msm8x16->supplies[i].supply); + break; + } + dev_err(msm8x16->dev, "Enabled regulator %s\n", + msm8x16->supplies[i].supply); + } + + while (ret && --i) + if (!pdata->regulator[i].ondemand) + regulator_disable(msm8x16->supplies[i].consumer); + + return ret; +} + + + +static void msm8x16_wcd_disable_supplies(struct msm8x16_wcd *msm8x16, + struct msm8x16_wcd_pdata *pdata) +{ + int i; + + regulator_bulk_disable(msm8x16->num_of_supplies, + msm8x16->supplies); + for (i = 0; i < msm8x16->num_of_supplies; i++) { + if (regulator_count_voltages(msm8x16->supplies[i].consumer) <= + 0) + continue; + regulator_set_voltage(msm8x16->supplies[i].consumer, 0, + pdata->regulator[i].max_uv); + regulator_set_load(msm8x16->supplies[i].consumer, 0); + } + regulator_bulk_free(msm8x16->num_of_supplies, msm8x16->supplies); + kfree(msm8x16->supplies); +} + +static struct snd_soc_dai_driver msm_codec_dais[] = { + { + .name = "msm-codec-rx", + .playback = { /* Support maximum range */ + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, + { + .name = "msm-codec-tx", + .capture = { /* Support maximum range */ + .stream_name = "Record", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, +}; + +static struct regmap *msm89xx_codec_regmap; +static struct regmap *msm89xx_codec_get_regmap(struct device *dev) +{ + return msm89xx_codec_regmap; +} + +static struct snd_soc_codec_driver soc_msm89xx_codec = { + .probe = msm89xx_digcodec_probe, + .remove = msm89xx_digcodec_remove, + .get_regmap = msm89xx_codec_get_regmap, +}; + +static const struct of_device_id msm89xx_codec_of_match[] = { + { .compatible = "qcom,msm-codec-core", + .data = "msm_codec"}, + { .compatible = "qcom,pmic-codec-digital", + .data = "pmic-digital-codec"}, + { .compatible = "qcom,pmic-codec-analog", + .data = "pmic-analog-codec"}, + {}, +}; +MODULE_DEVICE_TABLE(of, msm89xx_codec_of_match); + +static struct msm8x16_wcd *temp_89xx; +static int msm89xx_codec_probe(struct platform_device *pdev) +{ + int ret = 0; + struct msm8x16_wcd *msm8x16 = NULL; + struct msm8x16_wcd_pdata *pdata; + int adsp_state; + static int dev_registered_cnt; + const struct of_device_id *match; + const char *addr_prop_name = "qcom,dig-cdc-base-addr"; + u32 dig_cdc_addr; + char __iomem *dig_base; + + adsp_state = apr_get_subsys_state(); + if (adsp_state != APR_SUBSYS_LOADED) { + dev_err(&pdev->dev, "Adsp is not loaded yet %d\n", + adsp_state); + return -EPROBE_DEFER; + } + + match = of_match_node(msm89xx_codec_of_match, + pdev->dev.of_node); + + dev_dbg(&pdev->dev, "%s(%d):%s\n", + __func__, __LINE__, (char *)match->data); + + if (!strcmp(match->data, "pmic-digital-codec")) { + device_init_wakeup(&pdev->dev, true); + + if (pdev->dev.of_node) { + dev_err(&pdev->dev, "%s:Platform data from device tree\n", + __func__); + pdata = msm8x16_wcd_populate_dt_pdata(&pdev->dev); + pdev->dev.platform_data = pdata; + } else { + dev_err(&pdev->dev, "%s:Platform data from board file\n", + __func__); + pdata = pdev->dev.platform_data; + } + if (pdata == NULL) { + dev_err(&pdev->dev, "%s:Platform data failed to populate\n", + __func__); + goto rtn; + } + msm8x16 = kzalloc(sizeof(struct msm8x16_wcd), GFP_KERNEL); + if (msm8x16 == NULL) { + ret = -ENOMEM; + goto rtn; + } + + msm8x16->dev = &pdev->dev; + ret = msm8x16_wcd_init_supplies(msm8x16, pdata); + if (ret) { + dev_err(&pdev->dev, "%s: Fail to enable Codec supplies\n", + __func__); + goto err_codec; + } + + ret = msm8x16_wcd_enable_static_supplies(msm8x16, pdata); + if (ret) { + dev_err(&pdev->dev, + "%s: Fail to enable Codec pre-reset supplies\n", + __func__); + goto err_codec; + } + usleep_range(5, 6); + + mutex_init(&msm8x16->io_lock); + dev_set_drvdata(&pdev->dev, msm8x16); + temp_89xx = msm8x16; + dev_registered_cnt++; + } else if (!strcmp(match->data, "pmic-analog-codec")) { + if (wcd9xxx_spmi_irq_init()) { + dev_err(&pdev->dev, + "%s: irq initialization failed\n", __func__); + } else { + dev_err(&pdev->dev, + "%s: irq initialization passed\n", __func__); + } + dev_registered_cnt++; + } else if (!strcmp(match->data, "msm-codec")) { + ret = of_property_read_u32(pdev->dev.of_node, addr_prop_name, + &dig_cdc_addr); + if (ret) { + dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, addr_prop_name); + dig_cdc_addr = MSM89XX_DIGITAL_CODEC_BASE_ADDR; + } + dig_base = ioremap(dig_cdc_addr, + MSM89XX_DIGITAL_CODEC_REG_SIZE); + if (dig_base == NULL) { + dev_err(&pdev->dev, "%s ioremap failed\n", __func__); + return -ENOMEM; + } + msm89xx_codec_regmap = + devm_regmap_init_mmio_clk(&pdev->dev, NULL, + dig_base, &msm89xx_cdc_core_regmap_config); + snd_soc_register_codec(&pdev->dev, &soc_msm89xx_codec, + msm_codec_dais, ARRAY_SIZE(msm_codec_dais)); + dev_registered_cnt++; + } + + if ((dev_registered_cnt == MAX_MSM89XX_DEVICE) && (!ret)) { + msm89xx_pmic_cdc_regmap = + devm_regmap_init_spmi_ext( + (struct spmi_device *) &pdev->dev.parent, + &msm89xx_pmic_cdc_regmap_config); + ret = snd_soc_register_codec(temp_89xx->dev, + &soc_codec_dev_msm8x16_wcd, + msm8x16_wcd_i2s_dai, + ARRAY_SIZE(msm8x16_wcd_i2s_dai)); + if (ret) { + dev_err(&pdev->dev, + "%s:snd_soc_register_codec failed with error %d\n", + __func__, ret); + goto err_supplies; + } + } + return ret; +err_supplies: + msm8x16_wcd_disable_supplies(msm8x16, pdata); +err_codec: + kfree(msm8x16); +rtn: + return ret; +} + +static int msm89xx_codec_remove(struct platform_device *pdev) +{ + struct msm8x16_wcd *msm8x16 = dev_get_drvdata(&pdev->dev); + + mutex_destroy(&msm8x16->io_lock); + kfree(msm8x16); + + return 0; +} + +static struct platform_driver msm_codec_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + .of_match_table = of_match_ptr(msm89xx_codec_of_match) + }, + .probe = msm89xx_codec_probe, + .remove = msm89xx_codec_remove, +}; +module_platform_driver(msm_codec_driver); + +MODULE_DESCRIPTION("MSM89xx Audio codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/msm8x16/msm8x16-wcd.h b/sound/soc/codecs/msm8x16/msm8x16-wcd.h new file mode 100644 index 000000000000..d2e782b07cb2 --- /dev/null +++ b/sound/soc/codecs/msm8x16/msm8x16-wcd.h @@ -0,0 +1,341 @@ +/* Copyright (c) 2015-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 MSM8X16_WCD_H +#define MSM8X16_WCD_H + +#include <sound/soc.h> +#include <sound/jack.h> +#include <sound/q6afe-v2.h> +#include "../wcd-mbhc-v2.h" +#include "../wcdcal-hwdep.h" +#include "msm8x16_wcd_registers.h" + +#define MICBIAS_EXT_BYP_CAP 0x00 +#define MICBIAS_NO_EXT_BYP_CAP 0x01 + +#define MSM89XX_NUM_IRQ_REGS 2 +#define MAX_REGULATOR 7 +#define MSM89XX_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 MSM89XX_IS_CDC_CORE_REG(reg) \ + (((reg >= 0x00) && (reg <= 0x3FF)) ? 1 : 0) +#define MSM89XX_IS_PMIC_CDC_REG(reg) \ + (((reg >= 0xF000) && (reg <= 0xF1FF)) ? 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 4 +#define MSM89XX_VDD_SPKDRV_NAME "cdc-vdd-spkdrv" + +#define DEFAULT_MULTIPLIER 800 +#define DEFAULT_GAIN 9 +#define DEFAULT_OFFSET 100 + +extern const u8 msm89xx_pmic_cdc_reg_readable[MSM89XX_PMIC_CDC_CACHE_SIZE]; +extern const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE]; +extern struct regmap_config msm89xx_cdc_core_regmap_config; +extern struct regmap_config msm89xx_pmic_cdc_regmap_config; + +enum codec_versions { + TOMBAK_1_0, + TOMBAK_2_0, + CONGA, + CAJON, + CAJON_2_0, + DIANGU, + UNSUPPORTED, +}; + +/* Support different hph modes */ +enum { + NORMAL_MODE = 0, + HD2_MODE, +}; + +/* Codec supports 1 compander */ +enum { + COMPANDER_NONE = 0, + COMPANDER_1, /* HPHL/R */ + COMPANDER_MAX, +}; + +enum wcd_curr_ref { + I_h4_UA = 0, + I_pt5_UA, + I_14_UA, + I_l4_UA, + I_1_UA, +}; + +enum wcd_mbhc_imp_det_pin { + WCD_MBHC_DET_NONE = 0, + WCD_MBHC_DET_HPHL, + WCD_MBHC_DET_HPHR, + WCD_MBHC_DET_BOTH, +}; + + +/* Each micbias can be assigned to one of three cfilters + * Vbatt_min >= .15V + ldoh_v + * ldoh_v >= .15v + cfiltx_mv + * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv + * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv + * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv + * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv + */ + +struct wcd9xxx_micbias_setting { + u8 ldoh_v; + u32 cfilt1_mv; /* in mv */ + u32 cfilt2_mv; /* in mv */ + u32 cfilt3_mv; /* in mv */ + /* Different WCD9xxx series codecs may not + * have 4 mic biases. If a codec has fewer + * mic biases, some of these properties will + * not be used. + */ + u8 bias1_cfilt_sel; + u8 bias2_cfilt_sel; + u8 bias3_cfilt_sel; + u8 bias4_cfilt_sel; + u8 bias1_cap_mode; + u8 bias2_cap_mode; + u8 bias3_cap_mode; + u8 bias4_cap_mode; + bool bias2_is_headset_only; +}; + +enum msm8x16_wcd_pid_current { + MSM89XX_PID_MIC_2P5_UA, + MSM89XX_PID_MIC_5_UA, + MSM89XX_PID_MIC_10_UA, + MSM89XX_PID_MIC_20_UA, +}; + +struct msm8x16_wcd_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +enum msm8x16_wcd_mbhc_analog_pwr_cfg { + MSM89XX_ANALOG_PWR_COLLAPSED = 0, + MSM89XX_ANALOG_PWR_ON, + MSM89XX_NUM_ANALOG_PWR_CONFIGS, +}; + +/* Number of input and output I2S port */ +enum { + MSM89XX_RX1 = 0, + MSM89XX_RX2, + MSM89XX_RX3, + MSM89XX_RX_MAX, +}; + +enum { + MSM89XX_TX1 = 0, + MSM89XX_TX2, + MSM89XX_TX3, + MSM89XX_TX4, + MSM89XX_TX_MAX, +}; + +enum { + /* INTR_REG 0 - Digital Periph */ + MSM89XX_IRQ_SPKR_CNP = 0, + MSM89XX_IRQ_SPKR_CLIP, + MSM89XX_IRQ_SPKR_OCP, + MSM89XX_IRQ_MBHC_INSREM_DET1, + MSM89XX_IRQ_MBHC_RELEASE, + MSM89XX_IRQ_MBHC_PRESS, + MSM89XX_IRQ_MBHC_INSREM_DET, + MSM89XX_IRQ_MBHC_HS_DET, + /* INTR_REG 1 - Analog Periph */ + MSM89XX_IRQ_EAR_OCP, + MSM89XX_IRQ_HPHR_OCP, + MSM89XX_IRQ_HPHL_OCP, + MSM89XX_IRQ_EAR_CNP, + MSM89XX_IRQ_HPHR_CNP, + MSM89XX_IRQ_HPHL_CNP, + MSM89XX_NUM_IRQS, +}; + +enum { + ON_DEMAND_MICBIAS = 0, + ON_DEMAND_SPKDRV, + 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, +}; + +struct msm8x16_wcd_regulator { + const char *name; + int min_uv; + int max_uv; + int optimum_ua; + bool ondemand; + struct regulator *regulator; +}; + +struct on_demand_supply { + struct regulator *supply; + atomic_t ref; +}; + +struct wcd_imped_i_ref { + enum wcd_curr_ref curr_ref; + int min_val; + int multiplier; + int gain_adj; + int offset; +}; + +struct msm8916_asoc_mach_data { + int codec_type; + int ext_pa; + int us_euro_gpio; + int spk_ext_pa_gpio; + int mclk_freq; + int lb_mode; + int afe_clk_ver; + u8 micbias1_cap_mode; + u8 micbias2_cap_mode; + atomic_t mclk_rsc_ref; + atomic_t mclk_enabled; + atomic_t wsa_mclk_rsc_ref; + struct mutex cdc_mclk_mutex; + struct mutex wsa_mclk_mutex; + struct delayed_work disable_mclk_work; + struct afe_digital_clk_cfg digital_cdc_clk; + struct afe_clk_set digital_cdc_core_clk; + void __iomem *vaddr_gpio_mux_spkr_ctl; + void __iomem *vaddr_gpio_mux_mic_ctl; + void __iomem *vaddr_gpio_mux_quin_ctl; + void __iomem *vaddr_gpio_mux_pcm_ctl; + struct on_demand_supply wsa_switch_supply; +}; + +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; + u32 is_lpass; +}; + +enum msm8x16_wcd_micbias_num { + MSM89XX_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; +}; + +struct msm8x16_wcd_priv { + struct snd_soc_codec *codec; + u16 pmic_rev; + u16 codec_version; + u32 boost_voltage; + 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; + u16 boost_option; + /* mode to select hd2 */ + u32 hph_mode; + /* compander used for each rx chain */ + u32 comp_enabled[MSM89XX_RX_MAX]; + bool spk_boost_set; + bool ear_pa_boost_set; + bool ext_spk_boost_set; + bool dec_active[NUM_DECIMATORS]; + struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX]; + struct regulator *spkdrv_reg; + /* mbhc module */ + struct wcd_mbhc mbhc; + /* cal info for codec */ + struct fw_info *fw_data; + struct blocking_notifier_head notifier; + int (*codec_spk_ext_pa_cb)(struct snd_soc_codec *codec, int enable); + int (*codec_hph_comp_gpio)(bool enable); + unsigned long status_mask; + struct wcd_imped_i_ref imped_i_ref; + enum wcd_mbhc_imp_det_pin imped_det_pin; +}; + +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 void msm8x16_update_int_spk_boost(bool enable); + +extern void msm8x16_wcd_spk_ext_pa_cb( + int (*codec_spk_ext_pa)(struct snd_soc_codec *codec, + int enable), struct snd_soc_codec *codec); + +extern void msm8x16_wcd_hph_comp_cb( + int (*codec_hph_comp_gpio)(bool enable), + struct snd_soc_codec *codec); +void enable_digital_callback(void *flag); +void disable_digital_callback(void *flag); + +#endif + diff --git a/sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h b/sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h new file mode 100644 index 000000000000..280e6f28682a --- /dev/null +++ b/sound/soc/codecs/msm8x16/msm8x16_wcd_registers.h @@ -0,0 +1,585 @@ + /* Copyright (c) 2015-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 MSM8X16_WCD_REGISTERS_H +#define MSM8X16_WCD_REGISTERS_H + +#define CDC_DIG_BASE 0xF000 +#define CDC_ANA_BASE 0xF100 + +#define MSM89XX_PMIC_DIGITAL_REVISION1 (CDC_DIG_BASE+0x000) +#define MSM89XX_PMIC_DIGITAL_REVISION1__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_REVISION2 (CDC_DIG_BASE+0x001) +#define MSM89XX_PMIC_DIGITAL_REVISION2__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_PERPH_TYPE (CDC_DIG_BASE+0x004) +#define MSM89XX_PMIC_DIGITAL_PERPH_TYPE__POR (0x23) +#define MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE (CDC_DIG_BASE+0x005) +#define MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE__POR (0x01) +#define MSM89XX_PMIC_DIGITAL_INT_RT_STS (CDC_DIG_BASE+0x010) +#define MSM89XX_PMIC_DIGITAL_INT_RT_STS__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_SET_TYPE (CDC_DIG_BASE+0x011) +#define MSM89XX_PMIC_DIGITAL_INT_SET_TYPE__POR (0xFF) +#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH (CDC_DIG_BASE+0x012) +#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_HIGH__POR (0xFF) +#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW (CDC_DIG_BASE+0x013) +#define MSM89XX_PMIC_DIGITAL_INT_POLARITY_LOW__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR (CDC_DIG_BASE+0x014) +#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_CLR__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_EN_SET (CDC_DIG_BASE+0x015) +#define MSM89XX_PMIC_DIGITAL_INT_EN_SET__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_EN_CLR (CDC_DIG_BASE+0x016) +#define MSM89XX_PMIC_DIGITAL_INT_EN_CLR__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS (CDC_DIG_BASE+0x018) +#define MSM89XX_PMIC_DIGITAL_INT_LATCHED_STS__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_PENDING_STS (CDC_DIG_BASE+0x019) +#define MSM89XX_PMIC_DIGITAL_INT_PENDING_STS__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_MID_SEL (CDC_DIG_BASE+0x01A) +#define MSM89XX_PMIC_DIGITAL_INT_MID_SEL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_PRIORITY (CDC_DIG_BASE+0x01B) +#define MSM89XX_PMIC_DIGITAL_INT_PRIORITY__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_GPIO_MODE (CDC_DIG_BASE+0x040) +#define MSM89XX_PMIC_DIGITAL_GPIO_MODE__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_PIN_CTL_OE (CDC_DIG_BASE+0x041) +#define MSM89XX_PMIC_DIGITAL_PIN_CTL_OE__POR (0x01) +#define MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA (CDC_DIG_BASE+0x042) +#define MSM89XX_PMIC_DIGITAL_PIN_CTL_DATA__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_PIN_STATUS (CDC_DIG_BASE+0x043) +#define MSM89XX_PMIC_DIGITAL_PIN_STATUS__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_HDRIVE_CTL (CDC_DIG_BASE+0x044) +#define MSM89XX_PMIC_DIGITAL_HDRIVE_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_RST_CTL (CDC_DIG_BASE+0x046) +#define MSM89XX_PMIC_DIGITAL_CDC_RST_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL (CDC_DIG_BASE+0x048) +#define MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL (CDC_DIG_BASE+0x049) +#define MSM89XX_PMIC_DIGITAL_CDC_ANA_CLK_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL (CDC_DIG_BASE+0x04A) +#define MSM89XX_PMIC_DIGITAL_CDC_DIG_CLK_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL (CDC_DIG_BASE+0x050) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX1_CTL__POR (0x02) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL (CDC_DIG_BASE+0x051) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_TX2_CTL__POR (0x02) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL (CDC_DIG_BASE+0x052) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_HPHR_DAC_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL (CDC_DIG_BASE+0x053) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX1_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL (CDC_DIG_BASE+0x054) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX2_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL (CDC_DIG_BASE+0x055) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX3_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL (CDC_DIG_BASE+0x056) +#define MSM89XX_PMIC_DIGITAL_CDC_CONN_RX_LB_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1 (CDC_DIG_BASE+0x058) +#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL1__POR (0x7C) +#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2 (CDC_DIG_BASE+0x059) +#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL2__POR (0x7C) +#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3 (CDC_DIG_BASE+0x05A) +#define MSM89XX_PMIC_DIGITAL_CDC_RX_CTL3__POR (0x7C) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0 (CDC_DIG_BASE+0x05B) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA0__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1 (CDC_DIG_BASE+0x05C) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA1__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2 (CDC_DIG_BASE+0x05D) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA2__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3 (CDC_DIG_BASE+0x05E) +#define MSM89XX_PMIC_DIGITAL_DEM_BYPASS_DATA3__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL (CDC_DIG_BASE+0x068) +#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_CTL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_EN (CDC_DIG_BASE+0x069) +#define MSM89XX_PMIC_DIGITAL_DIG_DEBUG_EN__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_SPARE_0 (CDC_DIG_BASE+0x070) +#define MSM89XX_PMIC_DIGITAL_SPARE_0__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_SPARE_1 (CDC_DIG_BASE+0x071) +#define MSM89XX_PMIC_DIGITAL_SPARE_1__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_SPARE_2 (CDC_DIG_BASE+0x072) +#define MSM89XX_PMIC_DIGITAL_SPARE_2__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_SEC_ACCESS (CDC_DIG_BASE+0x0D0) +#define MSM89XX_PMIC_DIGITAL_SEC_ACCESS__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL1 (CDC_DIG_BASE+0x0D8) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL1__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL2 (CDC_DIG_BASE+0x0D9) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL2__POR (0x01) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3 (CDC_DIG_BASE+0x0DA) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL3__POR (0x05) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4 (CDC_DIG_BASE+0x0DB) +#define MSM89XX_PMIC_DIGITAL_PERPH_RESET_CTL4__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_TEST1 (CDC_DIG_BASE+0x0E0) +#define MSM89XX_PMIC_DIGITAL_INT_TEST1__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_INT_TEST_VAL (CDC_DIG_BASE+0x0E1) +#define MSM89XX_PMIC_DIGITAL_INT_TEST_VAL__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_TRIM_NUM (CDC_DIG_BASE+0x0F0) +#define MSM89XX_PMIC_DIGITAL_TRIM_NUM__POR (0x00) +#define MSM89XX_PMIC_DIGITAL_TRIM_CTRL (CDC_DIG_BASE+0x0F1) +#define MSM89XX_PMIC_DIGITAL_TRIM_CTRL__POR (0x00) + +#define MSM89XX_PMIC_ANALOG_REVISION1 (CDC_ANA_BASE+0x00) +#define MSM89XX_PMIC_ANALOG_REVISION1__POR (0x00) +#define MSM89XX_PMIC_ANALOG_REVISION2 (CDC_ANA_BASE+0x01) +#define MSM89XX_PMIC_ANALOG_REVISION2__POR (0x00) +#define MSM89XX_PMIC_ANALOG_REVISION3 (CDC_ANA_BASE+0x02) +#define MSM89XX_PMIC_ANALOG_REVISION3__POR (0x00) +#define MSM89XX_PMIC_ANALOG_REVISION4 (CDC_ANA_BASE+0x03) +#define MSM89XX_PMIC_ANALOG_REVISION4__POR (0x00) +#define MSM89XX_PMIC_ANALOG_PERPH_TYPE (CDC_ANA_BASE+0x04) +#define MSM89XX_PMIC_ANALOG_PERPH_TYPE__POR (0x23) +#define MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE (CDC_ANA_BASE+0x05) +#define MSM89XX_PMIC_ANALOG_PERPH_SUBTYPE__POR (0x09) +#define MSM89XX_PMIC_ANALOG_INT_RT_STS (CDC_ANA_BASE+0x10) +#define MSM89XX_PMIC_ANALOG_INT_RT_STS__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_SET_TYPE (CDC_ANA_BASE+0x11) +#define MSM89XX_PMIC_ANALOG_INT_SET_TYPE__POR (0x3F) +#define MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH (CDC_ANA_BASE+0x12) +#define MSM89XX_PMIC_ANALOG_INT_POLARITY_HIGH__POR (0x3F) +#define MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW (CDC_ANA_BASE+0x13) +#define MSM89XX_PMIC_ANALOG_INT_POLARITY_LOW__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR (CDC_ANA_BASE+0x14) +#define MSM89XX_PMIC_ANALOG_INT_LATCHED_CLR__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_EN_SET (CDC_ANA_BASE+0x15) +#define MSM89XX_PMIC_ANALOG_INT_EN_SET__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_EN_CLR (CDC_ANA_BASE+0x16) +#define MSM89XX_PMIC_ANALOG_INT_EN_CLR__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_LATCHED_STS (CDC_ANA_BASE+0x18) +#define MSM89XX_PMIC_ANALOG_INT_LATCHED_STS__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_PENDING_STS (CDC_ANA_BASE+0x19) +#define MSM89XX_PMIC_ANALOG_INT_PENDING_STS__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_MID_SEL (CDC_ANA_BASE+0x1A) +#define MSM89XX_PMIC_ANALOG_INT_MID_SEL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_PRIORITY (CDC_ANA_BASE+0x1B) +#define MSM89XX_PMIC_ANALOG_INT_PRIORITY__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MICB_1_EN (CDC_ANA_BASE+0x40) +#define MSM89XX_PMIC_ANALOG_MICB_1_EN__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MICB_1_VAL (CDC_ANA_BASE+0x41) +#define MSM89XX_PMIC_ANALOG_MICB_1_VAL__POR (0x20) +#define MSM89XX_PMIC_ANALOG_MICB_1_CTL (CDC_ANA_BASE+0x42) +#define MSM89XX_PMIC_ANALOG_MICB_1_CTL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS (CDC_ANA_BASE+0x43) +#define MSM89XX_PMIC_ANALOG_MICB_1_INT_RBIAS__POR (0x49) +#define MSM89XX_PMIC_ANALOG_MICB_2_EN (CDC_ANA_BASE+0x44) +#define MSM89XX_PMIC_ANALOG_MICB_2_EN__POR (0x20) +#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2 (CDC_ANA_BASE+0x45) +#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL_2__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL (CDC_ANA_BASE+0x46) +#define MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1 (CDC_ANA_BASE+0x47) +#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1__POR (0x35) +#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2 (CDC_ANA_BASE+0x50) +#define MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_2__POR (0x08) +#define MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL (CDC_ANA_BASE+0x51) +#define MSM89XX_PMIC_ANALOG_MBHC_FSM_CTL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER (CDC_ANA_BASE+0x52) +#define MSM89XX_PMIC_ANALOG_MBHC_DBNC_TIMER__POR (0x98) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL (CDC_ANA_BASE+0x53) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN0_ZDETL_CTL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL (CDC_ANA_BASE+0x54) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN1_ZDETM_CTL__POR (0x20) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL (CDC_ANA_BASE+0x55) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN2_ZDETH_CTL__POR (0x40) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL (CDC_ANA_BASE+0x56) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN3_CTL__POR (0x61) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL (CDC_ANA_BASE+0x57) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN4_CTL__POR (0x80) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT (CDC_ANA_BASE+0x58) +#define MSM89XX_PMIC_ANALOG_MBHC_BTN_RESULT__POR (0x00) +#define MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT (CDC_ANA_BASE+0x59) +#define MSM89XX_PMIC_ANALOG_MBHC_ZDET_ELECT_RESULT__POR (0x00) +#define MSM89XX_PMIC_ANALOG_TX_1_EN (CDC_ANA_BASE+0x60) +#define MSM89XX_PMIC_ANALOG_TX_1_EN__POR (0x03) +#define MSM89XX_PMIC_ANALOG_TX_2_EN (CDC_ANA_BASE+0x61) +#define MSM89XX_PMIC_ANALOG_TX_2_EN__POR (0x03) +#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1 (CDC_ANA_BASE+0x62) +#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_1__POR (0xBF) +#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2 (CDC_ANA_BASE+0x63) +#define MSM89XX_PMIC_ANALOG_TX_1_2_TEST_CTL_2__POR (0x8C) +#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL (CDC_ANA_BASE+0x64) +#define MSM89XX_PMIC_ANALOG_TX_1_2_ATEST_CTL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS (CDC_ANA_BASE+0x65) +#define MSM89XX_PMIC_ANALOG_TX_1_2_OPAMP_BIAS__POR (0x6B) +#define MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV (CDC_ANA_BASE+0x66) +#define MSM89XX_PMIC_ANALOG_TX_1_2_TXFE_CLKDIV__POR (0x51) +#define MSM89XX_PMIC_ANALOG_TX_3_EN (CDC_ANA_BASE+0x67) +#define MSM89XX_PMIC_ANALOG_TX_3_EN__POR (0x02) +#define MSM89XX_PMIC_ANALOG_NCP_EN (CDC_ANA_BASE+0x80) +#define MSM89XX_PMIC_ANALOG_NCP_EN__POR (0x26) +#define MSM89XX_PMIC_ANALOG_NCP_CLK (CDC_ANA_BASE+0x81) +#define MSM89XX_PMIC_ANALOG_NCP_CLK__POR (0x23) +#define MSM89XX_PMIC_ANALOG_NCP_DEGLITCH (CDC_ANA_BASE+0x82) +#define MSM89XX_PMIC_ANALOG_NCP_DEGLITCH__POR (0x5B) +#define MSM89XX_PMIC_ANALOG_NCP_FBCTRL (CDC_ANA_BASE+0x83) +#define MSM89XX_PMIC_ANALOG_NCP_FBCTRL__POR (0x08) +#define MSM89XX_PMIC_ANALOG_NCP_BIAS (CDC_ANA_BASE+0x84) +#define MSM89XX_PMIC_ANALOG_NCP_BIAS__POR (0x29) +#define MSM89XX_PMIC_ANALOG_NCP_VCTRL (CDC_ANA_BASE+0x85) +#define MSM89XX_PMIC_ANALOG_NCP_VCTRL__POR (0x24) +#define MSM89XX_PMIC_ANALOG_NCP_TEST (CDC_ANA_BASE+0x86) +#define MSM89XX_PMIC_ANALOG_NCP_TEST__POR (0x00) +#define MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR (CDC_ANA_BASE+0x87) +#define MSM89XX_PMIC_ANALOG_NCP_CLIM_ADDR__POR (0xD5) +#define MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER (CDC_ANA_BASE+0x90) +#define MSM89XX_PMIC_ANALOG_RX_CLOCK_DIVIDER__POR (0xE8) +#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL (CDC_ANA_BASE+0x91) +#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_CTL__POR (0xCF) +#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT (CDC_ANA_BASE+0x92) +#define MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT__POR (0x6E) +#define MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC (CDC_ANA_BASE+0x93) +#define MSM89XX_PMIC_ANALOG_RX_COM_BIAS_DAC__POR (0x18) +#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA (CDC_ANA_BASE+0x94) +#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_PA__POR (0x5A) +#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP (CDC_ANA_BASE+0x95) +#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_LDO_OCP__POR (0x69) +#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP (CDC_ANA_BASE+0x96) +#define MSM89XX_PMIC_ANALOG_RX_HPH_BIAS_CNP__POR (0x29) +#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN (CDC_ANA_BASE+0x97) +#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_EN__POR (0x80) +#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL (CDC_ANA_BASE+0x98) +#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_CTL__POR (0xDA) +#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME (CDC_ANA_BASE+0x99) +#define MSM89XX_PMIC_ANALOG_RX_HPH_CNP_WG_TIME__POR (0x16) +#define MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST (CDC_ANA_BASE+0x9A) +#define MSM89XX_PMIC_ANALOG_RX_HPH_L_TEST__POR (0x00) +#define MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL (CDC_ANA_BASE+0x9B) +#define MSM89XX_PMIC_ANALOG_RX_HPH_L_PA_DAC_CTL__POR (0x20) +#define MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST (CDC_ANA_BASE+0x9C) +#define MSM89XX_PMIC_ANALOG_RX_HPH_R_TEST__POR (0x00) +#define MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL (CDC_ANA_BASE+0x9D) +#define MSM89XX_PMIC_ANALOG_RX_HPH_R_PA_DAC_CTL__POR (0x20) +#define MSM89XX_PMIC_ANALOG_RX_EAR_CTL (CDC_ANA_BASE+0x9E) +#define MSM89XX_PMIC_ANALOG_RX_EAR_CTL___POR (0x12) +#define MSM89XX_PMIC_ANALOG_RX_ATEST (CDC_ANA_BASE+0x9F) +#define MSM89XX_PMIC_ANALOG_RX_ATEST__POR (0x00) +#define MSM89XX_PMIC_ANALOG_RX_HPH_STATUS (CDC_ANA_BASE+0xA0) +#define MSM89XX_PMIC_ANALOG_RX_HPH_STATUS__POR (0x0C) +#define MSM89XX_PMIC_ANALOG_RX_EAR_STATUS (CDC_ANA_BASE+0xA1) +#define MSM89XX_PMIC_ANALOG_RX_EAR_STATUS__POR (0x00) +#define MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL (CDC_ANA_BASE+0xAC) +#define MSM89XX_PMIC_ANALOG_RX_LO_DAC_CTL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_RX_LO_EN_CTL (CDC_ANA_BASE+0xAD) +#define MSM89XX_PMIC_ANALOG_RX_RX_LO_EN_CTL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL (CDC_ANA_BASE+0xB0) +#define MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL__POR (0x83) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET (CDC_ANA_BASE+0xB1) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CLIP_DET__POR (0x91) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL (CDC_ANA_BASE+0xB2) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_CTL__POR (0x29) +#define MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET (CDC_ANA_BASE+0xB3) +#define MSM89XX_PMIC_ANALOG_SPKR_ANA_BIAS_SET__POR (0x4D) +#define MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL (CDC_ANA_BASE+0xB4) +#define MSM89XX_PMIC_ANALOG_SPKR_OCP_CTL__POR (0xE1) +#define MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL (CDC_ANA_BASE+0xB5) +#define MSM89XX_PMIC_ANALOG_SPKR_PWRSTG_CTL__POR (0x1E) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC (CDC_ANA_BASE+0xB6) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_MISC__POR (0xCB) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG (CDC_ANA_BASE+0xB7) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_DBG__POR (0x00) +#define MSM89XX_PMIC_ANALOG_CURRENT_LIMIT (CDC_ANA_BASE+0xC0) +#define MSM89XX_PMIC_ANALOG_CURRENT_LIMIT__POR (0x02) +#define MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE (CDC_ANA_BASE+0xC1) +#define MSM89XX_PMIC_ANALOG_OUTPUT_VOLTAGE__POR (0x14) +#define MSM89XX_PMIC_ANALOG_BYPASS_MODE (CDC_ANA_BASE+0xC2) +#define MSM89XX_PMIC_ANALOG_BYPASS_MODE__POR (0x00) +#define MSM89XX_PMIC_ANALOG_BOOST_EN_CTL (CDC_ANA_BASE+0xC3) +#define MSM89XX_PMIC_ANALOG_BOOST_EN_CTL__POR (0x1F) +#define MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO (CDC_ANA_BASE+0xC4) +#define MSM89XX_PMIC_ANALOG_SLOPE_COMP_IP_ZERO__POR (0x8C) +#define MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE (CDC_ANA_BASE+0xC5) +#define MSM89XX_PMIC_ANALOG_RDSON_MAX_DUTY_CYCLE__POR (0xC0) +#define MSM89XX_PMIC_ANALOG_BOOST_TEST1_1 (CDC_ANA_BASE+0xC6) +#define MSM89XX_PMIC_ANALOG_BOOST_TEST1_1__POR (0x00) +#define MSM89XX_PMIC_ANALOG_BOOST_TEST_2 (CDC_ANA_BASE+0xC7) +#define MSM89XX_PMIC_ANALOG_BOOST_TEST_2__POR (0x00) +#define MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS (CDC_ANA_BASE+0xC8) +#define MSM89XX_PMIC_ANALOG_SPKR_SAR_STATUS__POR (0x00) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS (CDC_ANA_BASE+0xC9) +#define MSM89XX_PMIC_ANALOG_SPKR_DRV_STATUS__POR (0x00) +#define MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR (CDC_ANA_BASE+0xCE) +#define MSM89XX_PMIC_ANALOG_PBUS_ADD_CSR__POR (0x00) +#define MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL (CDC_ANA_BASE+0xCF) +#define MSM89XX_PMIC_ANALOG_PBUS_ADD_SEL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_SEC_ACCESS (CDC_ANA_BASE+0xD0) +#define MSM89XX_PMIC_ANALOG_SEC_ACCESS__POR (0x00) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL1 (CDC_ANA_BASE+0xD8) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL1__POR (0x00) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL2 (CDC_ANA_BASE+0xD9) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL2__POR (0x01) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3 (CDC_ANA_BASE+0xDA) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL3__POR (0x05) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4 (CDC_ANA_BASE+0xDB) +#define MSM89XX_PMIC_ANALOG_PERPH_RESET_CTL4__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_TEST1 (CDC_ANA_BASE+0xE0) +#define MSM89XX_PMIC_ANALOG_INT_TEST1__POR (0x00) +#define MSM89XX_PMIC_ANALOG_INT_TEST_VAL (CDC_ANA_BASE+0xE1) +#define MSM89XX_PMIC_ANALOG_INT_TEST_VAL__POR (0x00) +#define MSM89XX_PMIC_ANALOG_TRIM_NUM (CDC_ANA_BASE+0xF0) +#define MSM89XX_PMIC_ANALOG_TRIM_NUM__POR (0x04) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL1 (CDC_ANA_BASE+0xF1) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL1__POR (0x00) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL2 (CDC_ANA_BASE+0xF2) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL2__POR (0x00) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL3 (CDC_ANA_BASE+0xF3) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL3__POR (0x00) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL4 (CDC_ANA_BASE+0xF4) +#define MSM89XX_PMIC_ANALOG_TRIM_CTRL4__POR (0x00) + +#define MSM89XX_PMIC_CDC_NUM_REGISTERS \ + (MSM89XX_PMIC_ANALOG_TRIM_CTRL4+1) +#define MSM89XX_PMIC_CDC_MAX_REGISTER \ + (MSM89XX_PMIC_CDC_NUM_REGISTERS-1) +#define MSM89XX_PMIC_CDC_CACHE_SIZE \ + MSM89XX_PMIC_CDC_NUM_REGISTERS + + +#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL (0x00) +#define MSM89XX_CDC_CORE_CLK_RX_RESET_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL (0x04) +#define MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL (0x08) +#define MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL (0x0C) +#define MSM89XX_CDC_CORE_CLK_RX_I2S_CTL__POR (0x13) +#define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL (0x10) +#define MSM89XX_CDC_CORE_CLK_TX_I2S_CTL__POR (0x13) +#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL (0x14) +#define MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL (0x18) +#define MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_OTHR_CTL (0x1C) +#define MSM89XX_CDC_CORE_CLK_OTHR_CTL__POR (0x04) +#define MSM89XX_CDC_CORE_CLK_RX_B1_CTL (0x20) +#define MSM89XX_CDC_CORE_CLK_RX_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_MCLK_CTL (0x24) +#define MSM89XX_CDC_CORE_CLK_MCLK_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_PDM_CTL (0x28) +#define MSM89XX_CDC_CORE_CLK_PDM_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_SD_CTL (0x2C) +#define MSM89XX_CDC_CORE_CLK_SD_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL (0x30) +#define MSM89XX_CDC_CORE_CLK_WSA_VI_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CLK_RX_B2_CTL (0x34) +#define MSM89XX_CDC_CORE_CLK_RX_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX1_B1_CTL (0x40) +#define MSM89XX_CDC_CORE_RX1_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX2_B1_CTL (0x60) +#define MSM89XX_CDC_CORE_RX2_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX3_B1_CTL (0x80) +#define MSM89XX_CDC_CORE_RX3_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX1_B2_CTL (0x44) +#define MSM89XX_CDC_CORE_RX1_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX2_B2_CTL (0x64) +#define MSM89XX_CDC_CORE_RX2_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX3_B2_CTL (0x84) +#define MSM89XX_CDC_CORE_RX3_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX1_B3_CTL (0x48) +#define MSM89XX_CDC_CORE_RX1_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX2_B3_CTL (0x68) +#define MSM89XX_CDC_CORE_RX2_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX3_B3_CTL (0x88) +#define MSM89XX_CDC_CORE_RX3_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX1_B4_CTL (0x4C) +#define MSM89XX_CDC_CORE_RX1_B4_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX2_B4_CTL (0x6C) +#define MSM89XX_CDC_CORE_RX2_B4_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX3_B4_CTL (0x8C) +#define MSM89XX_CDC_CORE_RX3_B4_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX1_B5_CTL (0x50) +#define MSM89XX_CDC_CORE_RX1_B5_CTL__POR (0x68) +#define MSM89XX_CDC_CORE_RX2_B5_CTL (0x70) +#define MSM89XX_CDC_CORE_RX2_B5_CTL__POR (0x68) +#define MSM89XX_CDC_CORE_RX3_B5_CTL (0x90) +#define MSM89XX_CDC_CORE_RX3_B5_CTL__POR (0x68) +#define MSM89XX_CDC_CORE_RX1_B6_CTL (0x54) +#define MSM89XX_CDC_CORE_RX1_B6_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX2_B6_CTL (0x74) +#define MSM89XX_CDC_CORE_RX2_B6_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX3_B6_CTL (0x94) +#define MSM89XX_CDC_CORE_RX3_B6_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL (0x58) +#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL (0x78) +#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL (0x98) +#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL (0x5C) +#define MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL (0x7C) +#define MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL (0x9C) +#define MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE (0xA0) +#define MSM89XX_CDC_CORE_TOP_GAIN_UPDATE__POR (0x00) +#define MSM89XX_CDC_CORE_TOP_CTL (0xA4) +#define MSM89XX_CDC_CORE_TOP_CTL__POR (0x01) +#define MSM89XX_CDC_CORE_COMP0_B1_CTL (0xB0) +#define MSM89XX_CDC_CORE_COMP0_B1_CTL__POR (0x30) +#define MSM89XX_CDC_CORE_COMP0_B2_CTL (0xB4) +#define MSM89XX_CDC_CORE_COMP0_B2_CTL__POR (0xB5) +#define MSM89XX_CDC_CORE_COMP0_B3_CTL (0xB8) +#define MSM89XX_CDC_CORE_COMP0_B3_CTL__POR (0x28) +#define MSM89XX_CDC_CORE_COMP0_B4_CTL (0xBC) +#define MSM89XX_CDC_CORE_COMP0_B4_CTL__POR (0x37) +#define MSM89XX_CDC_CORE_COMP0_B5_CTL (0xC0) +#define MSM89XX_CDC_CORE_COMP0_B5_CTL__POR (0x7F) +#define MSM89XX_CDC_CORE_COMP0_B6_CTL (0xC4) +#define MSM89XX_CDC_CORE_COMP0_B6_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS (0xC8) +#define MSM89XX_CDC_CORE_COMP0_SHUT_DOWN_STATUS__POR (0x03) +#define MSM89XX_CDC_CORE_COMP0_FS_CFG (0xCC) +#define MSM89XX_CDC_CORE_COMP0_FS_CFG__POR (0x03) +#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL (0xD0) +#define MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL__POR (0x02) +#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL (0xE0) +#define MSM89XX_CDC_CORE_DEBUG_DESER1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL (0xE4) +#define MSM89XX_CDC_CORE_DEBUG_DESER2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG (0xE8) +#define MSM89XX_CDC_CORE_DEBUG_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG (0xEC) +#define MSM89XX_CDC_CORE_DEBUG_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG (0xF0) +#define MSM89XX_CDC_CORE_DEBUG_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL (0x100) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL (0x140) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL (0x104) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL (0x144) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL (0x108) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL (0x148) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL (0x10C) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL (0x14C) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL (0x110) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL (0x150) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL (0x114) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL (0x154) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL (0x118) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL (0x158) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL (0x11C) +#define MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL (0x15C) +#define MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_CTL (0x120) +#define MSM89XX_CDC_CORE_IIR1_CTL__POR (0x40) +#define MSM89XX_CDC_CORE_IIR2_CTL (0x160) +#define MSM89XX_CDC_CORE_IIR2_CTL__POR (0x40) +#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL (0x124) +#define MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL (0x164) +#define MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL (0x128) +#define MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL (0x168) +#define MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL (0x12C) +#define MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL (0x16C) +#define MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL (0x180) +#define MSM89XX_CDC_CORE_CONN_RX1_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL (0x184) +#define MSM89XX_CDC_CORE_CONN_RX1_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL (0x188) +#define MSM89XX_CDC_CORE_CONN_RX1_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL (0x18C) +#define MSM89XX_CDC_CORE_CONN_RX2_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL (0x190) +#define MSM89XX_CDC_CORE_CONN_RX2_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL (0x194) +#define MSM89XX_CDC_CORE_CONN_RX2_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL (0x198) +#define MSM89XX_CDC_CORE_CONN_RX3_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL (0x19C) +#define MSM89XX_CDC_CORE_CONN_RX3_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_TX_B1_CTL (0x1A0) +#define MSM89XX_CDC_CORE_CONN_TX_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL (0x1A8) +#define MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL (0x1AC) +#define MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL (0x1B0) +#define MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL (0x1B4) +#define MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL (0x1B8) +#define MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL (0x1BC) +#define MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL (0x1C0) +#define MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL (0x1C4) +#define MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL (0x1C8) +#define MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER (0x280) +#define MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER__POR (0x00) +#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER (0x2A0) +#define MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER__POR (0x00) +#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER (0x2C0) +#define MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER__POR (0x00) +#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER (0x2E0) +#define MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER__POR (0x00) +#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN (0x284) +#define MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN__POR (0x00) +#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN (0x2A4) +#define MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN__POR (0x00) +#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN (0x2C4) +#define MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN__POR (0x00) +#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN (0x2E4) +#define MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN__POR (0x00) +#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG (0x288) +#define MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG__POR (0x00) +#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG (0x2A8) +#define MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG__POR (0x00) +#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG (0x2C8) +#define MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG__POR (0x00) +#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG (0x2E8) +#define MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG__POR (0x00) +#define MSM89XX_CDC_CORE_TX1_MUX_CTL (0x28C) +#define MSM89XX_CDC_CORE_TX1_MUX_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX2_MUX_CTL (0x2AC) +#define MSM89XX_CDC_CORE_TX2_MUX_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX3_MUX_CTL (0x2CC) +#define MSM89XX_CDC_CORE_TX3_MUX_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX4_MUX_CTL (0x2EC) +#define MSM89XX_CDC_CORE_TX4_MUX_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX1_CLK_FS_CTL (0x290) +#define MSM89XX_CDC_CORE_TX1_CLK_FS_CTL__POR (0x03) +#define MSM89XX_CDC_CORE_TX2_CLK_FS_CTL (0x2B0) +#define MSM89XX_CDC_CORE_TX2_CLK_FS_CTL__POR (0x03) +#define MSM89XX_CDC_CORE_TX3_CLK_FS_CTL (0x2D0) +#define MSM89XX_CDC_CORE_TX3_CLK_FS_CTL__POR (0x03) +#define MSM89XX_CDC_CORE_TX4_CLK_FS_CTL (0x2F0) +#define MSM89XX_CDC_CORE_TX4_CLK_FS_CTL__POR (0x03) +#define MSM89XX_CDC_CORE_TX1_DMIC_CTL (0x294) +#define MSM89XX_CDC_CORE_TX1_DMIC_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX2_DMIC_CTL (0x2B4) +#define MSM89XX_CDC_CORE_TX2_DMIC_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX3_DMIC_CTL (0x2D4) +#define MSM89XX_CDC_CORE_TX3_DMIC_CTL__POR (0x00) +#define MSM89XX_CDC_CORE_TX4_DMIC_CTL (0x2F4) +#define MSM89XX_CDC_CORE_TX4_DMIC_CTL__POR (0x00) + +#define MSM89XX_CDC_CORE_NUM_REGISTERS \ + (MSM89XX_CDC_CORE_TX4_DMIC_CTL+1) +#define MSM89XX_CDC_CORE_MAX_REGISTER \ + (MSM89XX_CDC_CORE_NUM_REGISTERS-1) +#define MSM89XX_CDC_CORE_CACHE_SIZE \ + MSM89XX_CDC_CORE_NUM_REGISTERS +#endif diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 11993bb9a639..e922a5a0e262 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -356,6 +356,7 @@ enum { ANC_MIC_AMIC4, ANC_MIC_AMIC5, ANC_MIC_AMIC6, + CLASSH_CONFIG, }; enum { @@ -4501,6 +4502,7 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, int hph_mode = tasha->hph_mode; u8 dem_inp; int ret = 0; + uint32_t impedl = 0, impedr = 0; dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__, w->name, event, hph_mode); @@ -4534,6 +4536,16 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CFG0, 0x10, 0x10); + ret = wcd_mbhc_get_impedance(&tasha->mbhc, + &impedl, &impedr); + if (!ret) { + wcd_clsh_imped_config(codec, impedl, false); + set_bit(CLASSH_CONFIG, &tasha->status_mask); + } else + dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n", + __func__, ret); + + break; case SND_SOC_DAPM_POST_PMU: /* 1000us required as per HW requirement */ @@ -4563,6 +4575,15 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, WCD_CLSH_STATE_HPHL, ((hph_mode == CLS_H_LOHIFI) ? CLS_H_HIFI : hph_mode)); + + if (test_bit(CLASSH_CONFIG, &tasha->status_mask)) { + wcd_clsh_imped_config(codec, impedl, true); + clear_bit(CLASSH_CONFIG, &tasha->status_mask); + } else + dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n", + __func__, ret); + + break; }; @@ -12047,7 +12068,7 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = { {WCD9335_RCO_CTRL_2, 0x0F, 0x08}, {WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10}, {WCD9335_FLYBACK_CTRL_1, 0x20, 0x20}, - {WCD9335_HPH_OCP_CTL, 0xFF, 0x5A}, + {WCD9335_HPH_OCP_CTL, 0xFF, 0x7A}, {WCD9335_HPH_L_TEST, 0x01, 0x01}, {WCD9335_HPH_R_TEST, 0x01, 0x01}, {WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12}, @@ -12060,6 +12081,12 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = { {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4}, {WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08}, {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, + {WCD9335_DIFF_LO_CORE_OUT_PROG, 0xFC, 0xA0}, + {WCD9335_SE_LO_COM1, 0xFF, 0xC0}, + {WCD9335_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_CDC_RX5_RX_PATH_SEC0, 0xFC, 0xF8}, + {WCD9335_CDC_RX6_RX_PATH_SEC0, 0xFC, 0xF8}, }; static const struct tasha_reg_mask_val tasha_codec_reg_defaults[] = { @@ -12094,7 +12121,6 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_common_val[] = { {WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, {WCD9335_ANA_LO_1_2, 0x3C, 0X3C}, {WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00}, - {WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40}, {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03}, {WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02}, {WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01}, @@ -12188,6 +12214,7 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_1_x_val[] = { {WCD9335_DIFF_LO_CORE_OUT_PROG, 0xFC, 0xD8}, {WCD9335_CDC_RX5_RX_PATH_SEC3, 0xBD, 0xBD}, {WCD9335_CDC_RX6_RX_PATH_SEC3, 0xBD, 0xBD}, + {WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40}, }; static void tasha_update_reg_reset_values(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c index 5d4ac1f99de0..615922274690 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.c +++ b/sound/soc/codecs/wcd9xxx-common-v2.c @@ -21,6 +21,7 @@ #include "wcd9xxx-common-v2.h" #define WCD_USLEEP_RANGE 50 +#define MAX_IMPED_PARAMS 6 enum { DAC_GAIN_0DB = 0, @@ -49,10 +50,161 @@ enum { DELTA_I_50MA, }; +struct wcd_imped_val { + u32 imped_val; + u8 index; +}; + +static const struct wcd_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = { + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf5}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x0}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x0}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfe}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01}, + }, + { + {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00}, + {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xff}, + {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00}, + }, +}; + +static const struct wcd_imped_val imped_index[] = { + {4, 0}, + {5, 1}, + {6, 2}, + {7, 3}, + {8, 4}, + {9, 5}, + {10, 6}, + {11, 7}, + {12, 8}, + {13, 9}, +}; + static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_codec *, struct wcd_clsh_cdc_data *, u8 req_state, bool en, int mode); +static int get_impedance_index(int imped) +{ + int i = 0; + + if (imped < imped_index[i].imped_val) { + pr_debug("%s, detected impedance is less than 4 Ohm\n", + __func__); + i = 0; + goto ret; + } + if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) { + pr_debug("%s, detected impedance is greater than 12 Ohm\n", + __func__); + i = ARRAY_SIZE(imped_index) - 1; + goto ret; + } + for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) { + if (imped >= imped_index[i].imped_val && + imped < imped_index[i + 1].imped_val) + break; + } +ret: + pr_debug("%s: selected impedance index = %d\n", + __func__, imped_index[i].index); + return imped_index[i].index; +} + +/* + * Function: wcd_clsh_imped_config + * Params: codec, imped, reset + * Description: + * This function updates HPHL and HPHR gain settings + * according to the impedance value. + */ +void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, bool reset) +{ + int i; + int index = 0; + + /* reset = 1, which means request is to reset the register values */ + if (reset) { + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_update_bits(codec, imped_table[index][i].reg, + imped_table[index][i].mask, 0); + return; + } + index = get_impedance_index(imped); + if (index >= (ARRAY_SIZE(imped_index) - 1)) { + pr_debug("%s, impedance not in range = %d\n", __func__, imped); + return; + } + for (i = 0; i < MAX_IMPED_PARAMS; i++) + snd_soc_update_bits(codec, imped_table[index][i].reg, + imped_table[index][i].mask, + imped_table[index][i].val); +} +EXPORT_SYMBOL(wcd_clsh_imped_config); + static bool is_native_44_1_active(struct snd_soc_codec *codec) { bool native_active = false; @@ -338,6 +490,22 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec, } } +static void wcd_clsh_set_flyback_vneg_ctl(struct snd_soc_codec *codec, + bool enable) +{ + if (enable) { + snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0, + 0x00); + snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, (0x07 << 5)); + } else { + snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0, + (0x07 << 5)); + snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, (0x02 << 5)); + } +} + static void wcd_clsh_set_flyback_current(struct snd_soc_codec *codec, int mode) { struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); @@ -373,6 +541,7 @@ static void wcd_clsh_state_lo(struct snd_soc_codec *codec, if (is_enable) { wcd_clsh_set_buck_regulator_mode(codec, mode); + wcd_clsh_set_flyback_vneg_ctl(codec, true); wcd_clsh_set_buck_mode(codec, mode); wcd_clsh_set_flyback_mode(codec, mode); wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true); @@ -383,6 +552,7 @@ static void wcd_clsh_state_lo(struct snd_soc_codec *codec, wcd_clsh_flyback_ctrl(codec, clsh_d, mode, false); wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL); wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL); + wcd_clsh_set_flyback_vneg_ctl(codec, false); wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL); } } @@ -562,6 +732,7 @@ static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec, WCD9XXX_A_CDC_CLSH_K1_LSB, 0xFF, 0xC0); wcd_clsh_set_flyback_mode(codec, mode); + wcd_clsh_set_flyback_vneg_ctl(codec, false); wcd_clsh_set_buck_mode(codec, mode); wcd_clsh_set_hph_mode(codec, mode); wcd_clsh_set_gain_path(codec, mode); @@ -597,6 +768,7 @@ static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec, if ((clsh_d->state & WCD_CLSH_STATE_HPH_ST) != WCD_CLSH_STATE_HPH_ST) { wcd_enable_clsh_block(codec, clsh_d, false); + wcd_clsh_set_flyback_vneg_ctl(codec, true); wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL); wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL); } diff --git a/sound/soc/codecs/wcd9xxx-common-v2.h b/sound/soc/codecs/wcd9xxx-common-v2.h index 2ad91189d3cb..d3c52e73a7da 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.h +++ b/sound/soc/codecs/wcd9xxx-common-v2.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-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 @@ -136,6 +136,12 @@ struct vbat_monitor_reg { u32 writes[MAX_VBAT_MONITOR_WRITES]; } __packed; +struct wcd_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + extern void wcd_clsh_fsm(struct snd_soc_codec *codec, struct wcd_clsh_cdc_data *cdc_clsh_d, u8 clsh_event, u8 req_state, @@ -143,6 +149,8 @@ extern void wcd_clsh_fsm(struct snd_soc_codec *codec, extern void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh); extern int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh); +extern void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, + bool reset); enum { RESERVED = 0, diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c index 945250babf2d..763854061966 100644 --- a/sound/soc/msm/msmcobalt.c +++ b/sound/soc/msm/msmcobalt.c @@ -174,7 +174,7 @@ static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_96", "KHZ_192"}; -static char const *bt_sco_sample_rate_text[] = {"KHZ_8", "KHZ_16"}; +static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"}; static const char *const usb_ch_text[] = {"One", "Two"}; static char const *ch_text[] = {"Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; @@ -206,7 +206,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); -static SOC_ENUM_SINGLE_EXT_DECL(bt_sco_sample_rate, bt_sco_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_sample_rate, hdmi_rx_sample_rate_text); @@ -611,29 +611,44 @@ static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol, return 1; } -static int msm_bt_sco_sample_rate_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { /* * Slimbus_7_Rx/Tx sample rate values should always be in sync (same) * when used for BT_SCO use case. Return either Rx or Tx sample rate * value. */ - ucontrol->value.integer.value[0] = slim_rx_cfg[SLIM_RX_7].sample_rate; + switch (slim_rx_cfg[SLIM_RX_7].sample_rate) { + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } pr_debug("%s: sample rate = %d", __func__, slim_rx_cfg[SLIM_RX_7].sample_rate); return 0; } -static int msm_bt_sco_sample_rate_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { case 1: slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ; slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ; break; + case 2: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; case 0: default: slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ; @@ -1134,9 +1149,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), - SOC_ENUM_EXT("BT_SCO SampleRate", bt_sco_sample_rate, - msm_bt_sco_sample_rate_get, - msm_bt_sco_sample_rate_put), + SOC_ENUM_EXT("BT SampleRate", bt_sample_rate, + msm_bt_sample_rate_get, + msm_bt_sample_rate_put), SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate, usb_audio_rx_sample_rate_get, usb_audio_rx_sample_rate_put), @@ -1341,6 +1356,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, break; case MSM_BACKEND_DAI_SLIMBUS_7_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_rx_cfg[SLIM_RX_7].bit_format); rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate; channels->min = channels->max = slim_rx_cfg[SLIM_RX_7].channels; @@ -3131,7 +3148,11 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { .cpu_dai_name = "msm-dai-q6-dev.16398", .platform_name = "msm-pcm-routing", .codec_name = "btfmslim_slave", - .codec_dai_name = "btfm_bt_sco_slim_rx", + /* BT codec driver determines capabilities based on + * dai name, bt codecdai name should always contains + * supported usecase information + */ + .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx", .no_pcm = 1, .dpcm_playback = 1, .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX, @@ -3950,8 +3971,6 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) goto err; } - spdev = pdev; - ret = msm_populate_dai_link_component_of_node(card); if (ret) { ret = -EPROBE_DEFER; @@ -3989,6 +4008,7 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) goto err; } dev_info(&pdev->dev, "Sound card %s registered\n", card->name); + spdev = pdev; ret = of_property_read_string(pdev->dev.of_node, "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 7684d27d60a0..c439c5cf2de5 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -37,6 +37,14 @@ #define CHANNEL_STATUS_MASK 0x4 #define AFE_API_VERSION_CLOCK_SET 1 +enum { + ENC_FMT_NONE, + ENC_FMT_SBC = ASM_MEDIA_FMT_SBC, + ENC_FMT_AAC_V2 = ASM_MEDIA_FMT_AAC_V2, + ENC_FMT_APTX = ASM_MEDIA_FMT_APTX, + ENC_FMT_APTX_HD = ASM_MEDIA_FMT_APTX_HD, +}; + static const struct afe_clk_set lpass_clk_set_default = { AFE_API_VERSION_CLOCK_SET, Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT, @@ -157,6 +165,8 @@ struct msm_dai_q6_dai_data { u32 channels; u32 bitwidth; u32 cal_mode; + u32 afe_in_channels; + struct afe_enc_config enc_config; union afe_port_config port_config; }; @@ -1330,9 +1340,20 @@ static int msm_dai_q6_prepare(struct snd_pcm_substream *substream, int rc = 0; if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { - rc = afe_port_start(dai->id, &dai_data->port_config, - dai_data->rate); - + if (dai_data->enc_config.format != ENC_FMT_NONE) { + pr_debug("%s: calling AFE_PORT_START_V2 with enc_format: %d\n", + __func__, dai_data->enc_config.format); + rc = afe_port_start_v2(dai->id, &dai_data->port_config, + dai_data->rate, + dai_data->afe_in_channels, + &dai_data->enc_config); + if (rc < 0) + pr_err("%s: afe_port_start_v2 failed error: %d\n", + __func__, rc); + } else { + rc = afe_port_start(dai->id, &dai_data->port_config, + dai_data->rate); + } if (IS_ERR_VALUE(rc)) dev_err(dai->dev, "fail to open AFE port 0x%x\n", dai->id); @@ -1941,6 +1962,151 @@ static int msm_dai_q6_usb_audio_cfg_get(struct snd_kcontrol *kcontrol, return 0; } +static int msm_dai_q6_afe_enc_cfg_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(struct afe_enc_config); + + return 0; +} + +static int msm_dai_q6_afe_enc_cfg_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0; + struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data; + + if (dai_data) { + int format_size = sizeof(dai_data->enc_config.format); + + pr_debug("%s:encoder config for %d format\n", + __func__, dai_data->enc_config.format); + memcpy(ucontrol->value.bytes.data, + &dai_data->enc_config.format, + format_size); + switch (dai_data->enc_config.format) { + case ENC_FMT_SBC: + memcpy(ucontrol->value.bytes.data + format_size, + &dai_data->enc_config.data, + sizeof(struct asm_sbc_enc_cfg_t)); + break; + case ENC_FMT_AAC_V2: + memcpy(ucontrol->value.bytes.data + format_size, + &dai_data->enc_config.data, + sizeof(struct asm_aac_enc_cfg_v2_t)); + break; + case ENC_FMT_APTX: + case ENC_FMT_APTX_HD: + memcpy(ucontrol->value.bytes.data + format_size, + &dai_data->enc_config.data, + sizeof(struct asm_aac_enc_cfg_v2_t)); + break; + default: + pr_debug("%s: unknown format = %d\n", + __func__, dai_data->enc_config.format); + ret = -EINVAL; + break; + } + } + + return ret; +} + +static int msm_dai_q6_afe_enc_cfg_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0; + struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data; + + if (dai_data) { + int format_size = sizeof(dai_data->enc_config.format); + + memset(&dai_data->enc_config, 0x0, + sizeof(struct afe_enc_config)); + memcpy(&dai_data->enc_config.format, + ucontrol->value.bytes.data, + format_size); + pr_debug("%s: Received encoder config for %d format\n", + __func__, dai_data->enc_config.format); + switch (dai_data->enc_config.format) { + case ENC_FMT_SBC: + memcpy(&dai_data->enc_config.data, + ucontrol->value.bytes.data + format_size, + sizeof(struct asm_sbc_enc_cfg_t)); + break; + case ENC_FMT_AAC_V2: + memcpy(&dai_data->enc_config.data, + ucontrol->value.bytes.data + format_size, + sizeof(struct asm_aac_enc_cfg_v2_t)); + break; + case ENC_FMT_APTX: + case ENC_FMT_APTX_HD: + memcpy(&dai_data->enc_config.data, + ucontrol->value.bytes.data + format_size, + sizeof(struct asm_custom_enc_cfg_aptx_t)); + break; + default: + pr_debug("%s: Ignore enc config for unknown format = %d\n", + __func__, dai_data->enc_config.format); + ret = -EINVAL; + break; + } + } else + ret = -EINVAL; + + return ret; +} + +static const char *const afe_input_chs_text[] = {"Zero", "One", "Two"}; + +static const struct soc_enum afe_input_chs_enum[] = { + SOC_ENUM_SINGLE_EXT(3, afe_input_chs_text), +}; + +static int msm_dai_q6_afe_input_channel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data; + + if (dai_data) { + ucontrol->value.integer.value[0] = dai_data->afe_in_channels; + pr_debug("%s:afe input channel = %d\n", + __func__, dai_data->afe_in_channels); + } + + return 0; +} + +static int msm_dai_q6_afe_input_channel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data; + + if (dai_data) { + dai_data->afe_in_channels = ucontrol->value.integer.value[0]; + pr_debug("%s: updating afe input channel : %d\n", + __func__, dai_data->afe_in_channels); + } + + return 0; +} + +static const struct snd_kcontrol_new afe_enc_config_controls[] = { + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_INACTIVE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SLIM_7_RX Encoder Config", + .info = msm_dai_q6_afe_enc_cfg_info, + .get = msm_dai_q6_afe_enc_cfg_get, + .put = msm_dai_q6_afe_enc_cfg_put, + }, + SOC_ENUM_EXT("AFE Input Channels", afe_input_chs_enum[0], + msm_dai_q6_afe_input_channel_get, + msm_dai_q6_afe_input_channel_put), +}; + static const char * const afe_cal_mode_text[] = { "CAL_MODE_DEFAULT", "CAL_MODE_NONE" }; @@ -2020,6 +2186,17 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) snd_ctl_new1(&sb_config_controls[1], dai_data)); break; + case SLIMBUS_7_RX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&afe_enc_config_controls[0], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&afe_enc_config_controls[1], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&afe_enc_config_controls[2], + dai_data)); + break; case RT_PROXY_DAI_001_RX: rc = snd_ctl_add(dai->component->card->snd_card, snd_ctl_new1(&rt_proxy_config_controls[0], diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 8ca9bb7b2ad8..9e3d85b807aa 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -244,205 +244,209 @@ static void msm_pcm_routng_cfg_matrix_map_pp(struct route_payload payload, #define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { - { PRIMARY_I2S_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_RX}, - { PRIMARY_I2S_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_TX}, - { SLIMBUS_0_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_RX}, - { SLIMBUS_0_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_TX}, - { HDMI_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_HDMI}, - { INT_BT_SCO_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_RX}, - { INT_BT_SCO_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_TX}, - { INT_FM_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_RX}, - { INT_FM_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_TX}, - { RT_PROXY_PORT_001_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_RX}, - { RT_PROXY_PORT_001_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_TX}, - { AFE_PORT_ID_PRIMARY_PCM_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_AUXPCM_RX}, - { AFE_PORT_ID_PRIMARY_PCM_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_AUXPCM_TX}, - { VOICE_PLAYBACK_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_VOICE_PLAYBACK_TX}, - { VOICE2_PLAYBACK_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_VOICE2_PLAYBACK_TX}, - { VOICE_RECORD_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_RX}, - { VOICE_RECORD_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_TX}, - { MI2S_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_MI2S_RX}, - { MI2S_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_MI2S_TX}, - { SECONDARY_I2S_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_I2S_RX}, - { SLIMBUS_1_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_RX}, - { SLIMBUS_1_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_TX}, - { SLIMBUS_4_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX}, - { SLIMBUS_4_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX}, - { SLIMBUS_3_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_RX}, - { SLIMBUS_3_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_TX}, - { SLIMBUS_5_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_TX}, - { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_STUB_RX}, - { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_STUB_TX}, - { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_STUB_1_TX}, - { AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, + { PRIMARY_I2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_RX}, + { PRIMARY_I2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_I2S_TX}, + { SLIMBUS_0_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_RX}, + { SLIMBUS_0_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_0_TX}, + { HDMI_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_HDMI}, + { INT_BT_SCO_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_RX}, + { INT_BT_SCO_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_SCO_TX}, + { INT_FM_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_RX}, + { INT_FM_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_FM_TX}, + { RT_PROXY_PORT_001_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_RX}, + { RT_PROXY_PORT_001_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_AFE_PCM_TX}, + { AFE_PORT_ID_PRIMARY_PCM_RX, 0, 0, 0, 0, 0, 0, 0, 0, + LPASS_BE_AUXPCM_RX}, + { AFE_PORT_ID_PRIMARY_PCM_TX, 0, 0, 0, 0, 0, 0, 0, 0, + LPASS_BE_AUXPCM_TX}, + { VOICE_PLAYBACK_TX, 0, 0, 0, 0, 0, 0, 0, 0, + LPASS_BE_VOICE_PLAYBACK_TX}, + { VOICE2_PLAYBACK_TX, 0, 0, 0, 0, 0, 0, 0, 0, + LPASS_BE_VOICE2_PLAYBACK_TX}, + { VOICE_RECORD_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_RX}, + { VOICE_RECORD_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INCALL_RECORD_TX}, + { MI2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_MI2S_RX}, + { MI2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_MI2S_TX}, + { SECONDARY_I2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_I2S_RX}, + { SLIMBUS_1_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_RX}, + { SLIMBUS_1_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_TX}, + { SLIMBUS_4_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX}, + { SLIMBUS_4_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX}, + { SLIMBUS_3_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_RX}, + { SLIMBUS_3_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_TX}, + { SLIMBUS_5_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_TX}, + { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_STUB_RX}, + { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_STUB_TX}, + { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_STUB_1_TX}, + { AFE_PORT_ID_QUATERNARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_MI2S_RX}, - { AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_MI2S_TX}, - { AFE_PORT_ID_SECONDARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_MI2S_RX}, - { AFE_PORT_ID_SECONDARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_MI2S_TX}, - { AFE_PORT_ID_PRIMARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_MI2S_RX}, - { AFE_PORT_ID_PRIMARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_MI2S_TX}, - { AFE_PORT_ID_TERTIARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_MI2S_RX}, - { AFE_PORT_ID_TERTIARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_MI2S_TX}, - { AUDIO_PORT_ID_I2S_RX, 0, 0, 0, 0, 0, 0, 0, + { AUDIO_PORT_ID_I2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_AUDIO_I2S_RX}, - { AFE_PORT_ID_SECONDARY_PCM_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_PCM_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_AUXPCM_RX}, - { AFE_PORT_ID_SECONDARY_PCM_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_PCM_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_AUXPCM_TX}, - { SLIMBUS_6_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX}, - { SLIMBUS_6_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX}, - { AFE_PORT_ID_SPDIF_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SPDIF_RX}, - { AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, 0, 0, 0, 0, 0, 0, + { SLIMBUS_6_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX}, + { SLIMBUS_6_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX}, + { AFE_PORT_ID_SPDIF_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SPDIF_RX}, + { AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_MI2S_RX_SD1}, - { SLIMBUS_5_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX}, - { AFE_PORT_ID_QUINARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, + { SLIMBUS_5_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX}, + { AFE_PORT_ID_QUINARY_MI2S_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUIN_MI2S_RX}, - { AFE_PORT_ID_QUINARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUINARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUIN_MI2S_TX}, - { AFE_PORT_ID_SENARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SENARY_MI2S_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SENARY_MI2S_TX}, - { AFE_PORT_ID_PRIMARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_0}, - { AFE_PORT_ID_PRIMARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_0}, - { AFE_PORT_ID_PRIMARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_1}, - { AFE_PORT_ID_PRIMARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_1}, - { AFE_PORT_ID_PRIMARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_2}, - { AFE_PORT_ID_PRIMARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_2}, - { AFE_PORT_ID_PRIMARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_3}, - { AFE_PORT_ID_PRIMARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_3}, - { AFE_PORT_ID_PRIMARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_4}, - { AFE_PORT_ID_PRIMARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_4}, - { AFE_PORT_ID_PRIMARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_5}, - { AFE_PORT_ID_PRIMARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_5}, - { AFE_PORT_ID_PRIMARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_6}, - { AFE_PORT_ID_PRIMARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_6}, - { AFE_PORT_ID_PRIMARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_RX_7}, - { AFE_PORT_ID_PRIMARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_PRIMARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_PRI_TDM_TX_7}, - { AFE_PORT_ID_SECONDARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_0}, - { AFE_PORT_ID_SECONDARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_0}, - { AFE_PORT_ID_SECONDARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_1}, - { AFE_PORT_ID_SECONDARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_1}, - { AFE_PORT_ID_SECONDARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_2}, - { AFE_PORT_ID_SECONDARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_2}, - { AFE_PORT_ID_SECONDARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_3}, - { AFE_PORT_ID_SECONDARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_3}, - { AFE_PORT_ID_SECONDARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_4}, - { AFE_PORT_ID_SECONDARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_4}, - { AFE_PORT_ID_SECONDARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_5}, - { AFE_PORT_ID_SECONDARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_5}, - { AFE_PORT_ID_SECONDARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_6}, - { AFE_PORT_ID_SECONDARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_6}, - { AFE_PORT_ID_SECONDARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_RX_7}, - { AFE_PORT_ID_SECONDARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_SECONDARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SEC_TDM_TX_7}, - { AFE_PORT_ID_TERTIARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_0}, - { AFE_PORT_ID_TERTIARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_0}, - { AFE_PORT_ID_TERTIARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_1}, - { AFE_PORT_ID_TERTIARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_1}, - { AFE_PORT_ID_TERTIARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_2}, - { AFE_PORT_ID_TERTIARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_2}, - { AFE_PORT_ID_TERTIARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_3}, - { AFE_PORT_ID_TERTIARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_3}, - { AFE_PORT_ID_TERTIARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_4}, - { AFE_PORT_ID_TERTIARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_4}, - { AFE_PORT_ID_TERTIARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_5}, - { AFE_PORT_ID_TERTIARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_5}, - { AFE_PORT_ID_TERTIARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_6}, - { AFE_PORT_ID_TERTIARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_6}, - { AFE_PORT_ID_TERTIARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_RX_7}, - { AFE_PORT_ID_TERTIARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_TERTIARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_TERT_TDM_TX_7}, - { AFE_PORT_ID_QUATERNARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_0}, - { AFE_PORT_ID_QUATERNARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_0}, - { AFE_PORT_ID_QUATERNARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_1}, - { AFE_PORT_ID_QUATERNARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX_1, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_1}, - { AFE_PORT_ID_QUATERNARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_2}, - { AFE_PORT_ID_QUATERNARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX_2, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_2}, - { AFE_PORT_ID_QUATERNARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_3}, - { AFE_PORT_ID_QUATERNARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX_3, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_3}, - { AFE_PORT_ID_QUATERNARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_4}, - { AFE_PORT_ID_QUATERNARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX_4, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_4}, - { AFE_PORT_ID_QUATERNARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_5}, - { AFE_PORT_ID_QUATERNARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX_5, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_5}, - { AFE_PORT_ID_QUATERNARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_6}, - { AFE_PORT_ID_QUATERNARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX_6, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_6}, - { AFE_PORT_ID_QUATERNARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_RX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_RX_7}, - { AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, + { AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_7}, - { INT_BT_A2DP_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_A2DP_RX}, - { SLIMBUS_7_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX}, - { SLIMBUS_7_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX}, - { SLIMBUS_8_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX}, - { SLIMBUS_8_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX}, - { AFE_PORT_ID_USB_RX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_RX}, - { AFE_PORT_ID_USB_TX, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_TX}, + { INT_BT_A2DP_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_A2DP_RX}, + { SLIMBUS_7_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX}, + { SLIMBUS_7_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX}, + { SLIMBUS_8_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX}, + { SLIMBUS_8_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX}, + { AFE_PORT_ID_USB_RX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_RX}, + { AFE_PORT_ID_USB_TX, 0, 0, 0, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_TX}, }; /* Track ASM playback & capture sessions of DAI */ @@ -828,7 +832,15 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode, (msm_bedais[i].active) && (test_bit(fe_id, &msm_bedais[i].fe_sessions))) { int app_type, app_type_idx, copp_idx, acdb_dev_id; - channels = msm_bedais[i].channel; + + /* + * check if ADM needs to be configured with different + * channel mapping than backend + */ + if (!msm_bedais[i].adm_override_ch) + channels = msm_bedais[i].channel; + else + channels = msm_bedais[i].adm_override_ch; bit_width = msm_routing_get_bit_width( msm_bedais[i].format); @@ -976,7 +988,14 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode, (msm_bedais[i].active) && (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) { int app_type, app_type_idx, copp_idx, acdb_dev_id; - channels = msm_bedais[i].channel; + /* + * check if ADM needs to be configured with different + * channel mapping than backend + */ + if (!msm_bedais[i].adm_override_ch) + channels = msm_bedais[i].channel; + else + channels = msm_bedais[i].adm_override_ch; msm_bedais[i].compr_passthr_mode = LEGACY_PCM; @@ -1188,7 +1207,14 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) if (msm_bedais[reg].active && fdai->strm_id != INVALID_SESSION) { int app_type, app_type_idx, copp_idx, acdb_dev_id; - channels = msm_bedais[reg].channel; + /* + * check if ADM needs to be configured with different + * channel mapping than backend + */ + if (!msm_bedais[reg].adm_override_ch) + channels = msm_bedais[reg].channel; + else + channels = msm_bedais[reg].adm_override_ch; if (session_type == SESSION_TYPE_TX && fdai->be_srate && (fdai->be_srate != msm_bedais[reg].sample_rate)) { @@ -1855,6 +1881,68 @@ static int msm_routing_lsm_func_put(struct snd_kcontrol *kcontrol, return afe_port_set_mad_type(port_id, mad_type); } +static const char *const adm_override_chs_text[] = {"Zero", "One", "Two"}; + +static SOC_ENUM_SINGLE_EXT_DECL(slim_7_rx_adm_override_chs, + adm_override_chs_text); + +static int msm_routing_adm_get_backend_idx(struct snd_kcontrol *kcontrol) +{ + int backend_id; + + if (strnstr(kcontrol->id.name, "SLIM7_RX", sizeof("SLIM7_RX"))) { + backend_id = MSM_BACKEND_DAI_SLIMBUS_7_RX; + } else { + pr_err("%s: unsupported backend id: %s", + __func__, kcontrol->id.name); + return -EINVAL; + } + + return backend_id; +} +static int msm_routing_adm_channel_config_get( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int backend_id = msm_routing_adm_get_backend_idx(kcontrol); + + if (backend_id >= 0) { + mutex_lock(&routing_lock); + ucontrol->value.integer.value[0] = + msm_bedais[backend_id].adm_override_ch; + pr_debug("%s: adm channel count %ld for BE:%d\n", __func__, + ucontrol->value.integer.value[0], backend_id); + mutex_unlock(&routing_lock); + } + + return 0; +} + +static int msm_routing_adm_channel_config_put( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int backend_id = msm_routing_adm_get_backend_idx(kcontrol); + + if (backend_id >= 0) { + mutex_lock(&routing_lock); + msm_bedais[backend_id].adm_override_ch = + ucontrol->value.integer.value[0]; + pr_debug("%s:updating BE :%d adm channels: %d\n", + __func__, backend_id, + msm_bedais[backend_id].adm_override_ch); + mutex_unlock(&routing_lock); + } + + return 0; +} + +static const struct snd_kcontrol_new adm_channel_config_controls[] = { + SOC_ENUM_EXT("SLIM7_RX ADM Channels", slim_7_rx_adm_override_chs, + msm_routing_adm_channel_config_get, + msm_routing_adm_channel_config_put), +}; + static int msm_routing_slim_0_rx_aanc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -9641,7 +9729,14 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream) app_type_cfg[app_type_idx].bit_width; } else sample_rate = bedai->sample_rate; - channels = bedai->channel; + /* + * check if ADM needs to be configured with different + * channel mapping than backend + */ + if (!bedai->adm_override_ch) + channels = bedai->channel; + else + channels = bedai->adm_override_ch; acdb_dev_id = fe_dai_app_type_cfg[i].acdb_dev_id; topology = msm_routing_get_adm_topology(path_type, i); copp_idx = adm_open(bedai->port_id, path_type, @@ -9919,7 +10014,9 @@ static int msm_routing_probe(struct snd_soc_platform *platform) msm_dts_eagle_add_controls(platform); snd_soc_add_platform_controls(platform, msm_source_tracking_controls, - ARRAY_SIZE(msm_source_tracking_controls)); + ARRAY_SIZE(msm_source_tracking_controls)); + snd_soc_add_platform_controls(platform, adm_channel_config_controls, + ARRAY_SIZE(adm_channel_config_controls)); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 992d0d48e999..f422fd7d3e85 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -360,6 +360,7 @@ struct msm_pcm_routing_bdai_data { unsigned int sample_rate; unsigned int channel; unsigned int format; + unsigned int adm_override_ch; u32 compr_passthr_mode; char *name; }; diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index b76cb7f4b210..16c7ef4c0bf5 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -292,11 +292,13 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) this_afe.tx_cb(data->opcode, data->token, data->payload, this_afe.tx_private_data); + this_afe.tx_cb = NULL; } if (this_afe.rx_cb) { this_afe.rx_cb(data->opcode, data->token, data->payload, this_afe.rx_private_data); + this_afe.rx_cb = NULL; } return 0; @@ -2632,8 +2634,113 @@ exit: return ret; } -int afe_port_start(u16 port_id, union afe_port_config *afe_config, - u32 rate) /* This function is no blocking */ +static int q6afe_send_enc_config(u16 port_id, + union afe_enc_config_data *cfg, u32 format, + union afe_port_config afe_config, u16 afe_in_channels) +{ + struct afe_audioif_config_command config; + int index; + int ret; + int payload_size = sizeof(config) - sizeof(struct apr_hdr) - + sizeof(config.param) - sizeof(config.port); + + pr_debug("%s:update DSP for enc format = %d\n", __func__, format); + if (format != ASM_MEDIA_FMT_SBC && format != ASM_MEDIA_FMT_AAC_V2 && + format != ASM_MEDIA_FMT_APTX && format != ASM_MEDIA_FMT_APTX_HD) { + pr_err("%s:Unsuppported format Ignore AFE config\n", __func__); + return 0; + } + memset(&config, 0, sizeof(config)); + index = q6audio_get_port_index(port_id); + config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + config.hdr.pkt_size = sizeof(config); + config.hdr.src_port = 0; + config.hdr.dest_port = 0; + config.hdr.token = index; + + config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + config.param.port_id = q6audio_get_port_id(port_id); + config.param.payload_size = payload_size + sizeof(config.port.enc_fmt); + config.param.payload_address_lsw = 0x00; + config.param.payload_address_msw = 0x00; + config.param.mem_map_handle = 0x00; + config.pdata.module_id = AFE_MODULE_ID_ENCODER; + config.pdata.param_id = AFE_ENCODER_PARAM_ID_ENC_FMT_ID; + config.pdata.param_size = sizeof(config.port.enc_fmt); + config.port.enc_fmt.fmt_id = format; + pr_debug("%s:sending AFE_ENCODER_PARAM_ID_ENC_FMT_ID payload: %d\n", + __func__, config.param.payload_size); + ret = afe_apr_send_pkt(&config, &this_afe.wait[index]); + if (ret) { + pr_err("%s:unable to send AFE_ENCODER_PARAM_ID_ENC_FMT_ID", + __func__); + goto exit; + } + + config.param.payload_size = payload_size + + sizeof(config.port.enc_blk_param); + pr_debug("%s:send AFE_ENCODER_PARAM_ID_ENC_CFG_BLK to DSP payload:%d\n", + __func__, config.param.payload_size); + config.pdata.param_id = AFE_ENCODER_PARAM_ID_ENC_CFG_BLK; + config.pdata.param_size = sizeof(config.port.enc_blk_param); + config.port.enc_blk_param.enc_cfg_blk_size = + sizeof(config.port.enc_blk_param.enc_blk_config); + config.port.enc_blk_param.enc_blk_config = *cfg; + ret = afe_apr_send_pkt(&config, &this_afe.wait[index]); + if (ret) { + pr_err("%s: AFE_ENCODER_PARAM_ID_ENC_CFG_BLK for port 0x%x failed %d\n", + __func__, port_id, ret); + goto exit; + } + + config.param.payload_size = + payload_size + sizeof(config.port.enc_pkt_id_param); + pr_debug("%s:sending AFE_ENCODER_PARAM_ID_PACKETIZER to DSP payload = %d", + __func__, config.param.payload_size); + config.pdata.param_id = AFE_ENCODER_PARAM_ID_PACKETIZER_ID; + config.pdata.param_size = sizeof(config.port.enc_pkt_id_param); + config.port.enc_pkt_id_param.enc_packetizer_id = + AFE_MODULE_ID_PACKETIZER_COP; + ret = afe_apr_send_pkt(&config, &this_afe.wait[index]); + if (ret) { + pr_err("%s: AFE_ENCODER_PARAM_ID_PACKETIZER for port 0x%x failed %d\n", + __func__, port_id, ret); + goto exit; + } + + config.param.payload_size = + payload_size + sizeof(config.port.media_type); + config.pdata.param_size = sizeof(config.port.media_type); + + pr_debug("%s:Sending AFE_API_VERSION_PORT_MEDIA_TYPE to DSP", __func__); + config.pdata.module_id = AFE_MODULE_PORT; + config.pdata.param_id = AFE_PARAM_ID_PORT_MEDIA_TYPE; + config.port.media_type.minor_version = AFE_API_VERSION_PORT_MEDIA_TYPE; + config.port.media_type.sample_rate = afe_config.slim_sch.sample_rate; + config.port.media_type.bit_width = afe_config.slim_sch.bit_width; + if (afe_in_channels != 0) + config.port.media_type.num_channels = afe_in_channels; + else + config.port.media_type.num_channels = + afe_config.slim_sch.num_channels; + config.port.media_type.data_format = AFE_PORT_DATA_FORMAT_PCM; + config.port.media_type.reserved = 0; + + ret = afe_apr_send_pkt(&config, &this_afe.wait[index]); + if (ret) { + pr_err("%s: AFE_API_VERSION_PORT_MEDIA_TYPE for port 0x%x failed %d\n", + __func__, port_id, ret); + goto exit; + } + +exit: + return ret; +} + +static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, + u32 rate, u16 afe_in_channels, + union afe_enc_config_data *cfg, u32 enc_format) { struct afe_audioif_config_command config; int ret = 0; @@ -2850,7 +2957,11 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, config.pdata.param_size = sizeof(config.port); config.port = *afe_config; - + if ((enc_format != ASM_MEDIA_FMT_NONE) && + (cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) { + config.port.slim_sch.data_format = + AFE_SB_DATA_FORMAT_GENERIC_COMPRESSED; + } ret = afe_apr_send_pkt(&config, &this_afe.wait[index]); if (ret) { pr_err("%s: AFE enable for port 0x%x failed %d\n", @@ -2858,6 +2969,19 @@ int afe_port_start(u16 port_id, union afe_port_config *afe_config, goto fail_cmd; } + if ((enc_format != ASM_MEDIA_FMT_NONE) && + (cfg_type == AFE_PARAM_ID_SLIMBUS_CONFIG)) { + pr_debug("%s: Found AFE encoder support for SLIMBUS enc_format = %d\n", + __func__, enc_format); + ret = q6afe_send_enc_config(port_id, cfg, enc_format, + *afe_config, afe_in_channels); + if (ret) { + pr_err("%s: AFE encoder config for port 0x%x failed %d\n", + __func__, port_id, ret); + goto fail_cmd; + } + } + port_index = afe_get_port_index(port_id); if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) { this_afe.afe_sample_rates[port_index] = rate; @@ -2890,6 +3014,47 @@ fail_cmd: return ret; } +/** + * afe_port_start - to configure AFE session with + * specified port configuration + * + * @port_id: AFE port id number + * @afe_config: port configutation + * @rate: sampling rate of port + * + * Returns 0 on success or error value on port start failure. + */ +int afe_port_start(u16 port_id, union afe_port_config *afe_config, + u32 rate) +{ + return __afe_port_start(port_id, afe_config, rate, + 0, NULL, ASM_MEDIA_FMT_NONE); +} +EXPORT_SYMBOL(afe_port_start); + +/** + * afe_port_start_v2 - to configure AFE session with + * specified port configuration and encoder params + * + * @port_id: AFE port id number + * @afe_config: port configutation + * @rate: sampling rate of port + * @cfg: AFE encoder configuration information to setup encoder + * @afe_in_channels: AFE input channel configuration, this needs + * update only if input channel is differ from AFE output + * + * Returns 0 on success or error value on port start failure. + */ +int afe_port_start_v2(u16 port_id, union afe_port_config *afe_config, + u32 rate, u16 afe_in_channels, + struct afe_enc_config *enc_cfg) +{ + return __afe_port_start(port_id, afe_config, rate, + afe_in_channels, &enc_cfg->data, + enc_cfg->format); +} +EXPORT_SYMBOL(afe_port_start_v2); + int afe_get_port_index(u16 port_id) { switch (port_id) { |