diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-08-13 13:18:43 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-08-13 13:18:43 -0600 |
| commit | 558d430357afca640b3f4634e5bc617825250733 (patch) | |
| tree | adca105427aa4a646032cc75aaf66b4c8ef69903 | |
| parent | 777125f27bfb2bd37e46c5ee17d595531ced4716 (diff) | |
| parent | d43110ab63411fa3ac53e92d4f646842149f185a (diff) | |
Promotion of kernel.lnx.4.4-160813.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1048182 I2da2eba03ef30f3942ba3f8644efab98635002da defconfig: arm64: msmcortex: enable display xlog debug f
1034085 I810ad8c102124ce22de72d83b6df58c8fc991251 usb: dwc3-msm: Do dwc3_msm_gadget_vbus_draw() in sleepab
1049455 I2f8fba73a831d3bb711fe9310c5758221359819e usb: gadget: f_fs: Unlock mutex before unregistering gad
1042302 I792c043ca4d85e236c209605e80392a05d26b983 input: touchscreen: correct condition checks in ITE tech
1044467 I61d99454dab2fa90b4ed6577d1a58685088eb968 pinctrl: qcom: Update TLMM configuration for msmfalcon
1046961 I79abc586ad8c14a25afd56559c579a1415df9f0e input: ft5x06_ts: Add support for FB notifications
1042302 I30dd0cf0b15538e67f50725754d5059e2fe721d0 input: touchscreen: increase number of checks for touch
1048345 I41ad4af44504e3f192a989a763a4093cae03b76c soc: qcom: Fix error checks in service-notifier
1050785 I91f636b2c1cc1890b4ca28f52e5190561bc5d927 msm: mdss: dsi: fix lcd mode selection gpio config when
1040200 Ide4ed54970c62f6485809c3bd63960536b4ace4f msm: ipa: Add support for IPA unit-test framework
1046961 I48189abe60b4bd9d54a1bbc4657707213d8eb166 input: ft5x06: Add support for firmware upgrade
1050156 Ic23796c5a1388c41d533ca0f4fad04d01fe9e965 ARM: msmcortex_defconfig: Enable NCM function driver
1051878 If9ff41037d22d7be7f09c9468e8d4cc92280a28e USB: dwc3-msm: Add support for setting specific frequenc
1050517 I83651b3b3515e0923d7431cfe8b70e6059b51067 clk: msm: Add support for reset controller for GDSC
1049477 I7e442daf51c6ece39b8fe5cc8a38d3405163c9b5 usb: dwc3: Use clock API to control the memory power sta
1034085 I2c5ec90cc8c45019ad75056b6feb7e6319f85514 usb: dwc3-msm: Remove call to set POWER_SUPPLY_PROP_ONLI
1048282 I7716cff99b824b55e48aea57b9da91c16a8ecac1 usb: gadget: f_cdev: Fix memory leak upon composition sw
1051569 Ife9e165f6aa2112c1440819d659b97b5502a3f07 usb: dwc3: Remove tasklet bottom half handler
1051104 I642d5d4adc6978ddfa84f6d9dc4ae6428efc7894 soc: qcom: irq-helper: Fix spelling mistake
1049455 I1638001ff4a94f08224b188aa42425f3d732fa2b usb: f_fs: Prevent gadget unbind if it is already unboun
1040746 I365976021dcf02fbc3687091371d7d72cb711605 ARM: dts: msm: adjust mdp ot limits for msmcobalt
1046961 Ibcdd8c3579f401ac0632d670e1b7c674aa67ba8d input: ft5x06_ts: Add DT support
1050517 Ic9d00c0a03507a55ca6c96f977a6ddf55b4b5db7 clk: msm: Add reset controller support
1045208 Iafc3a9dda252417fcd06e3d9d24fb73b4d6f8e58 input: msg21xx_ts: release touch when finger leaves the
1044467 Ie0c46cbbcbc3edabd5e0f867b4393a27e55db9f5 ARM: dts: msm: Update TLMM base address for msmfalcon
1050763 Ie65f79051bfc452c63067c21efcfd9d98429bb15 drivers: soc: Set APR Glink transport to SMEM
1042302 982219 Ib609d6e76ea70cd3b49c4ea6f09c75bf52521aa8 input: touchscreen: remove global variable from ITE tech
1022917 I03e1a7f5ef3cf1b1907c03a3d38965ce3a611bc4 drivers: mfd: wcd9xxx: Add support to configure dmic clo
1046168 Ib0cd2ed579bd370cc8979cafcc14acb083a408b6 ASoC: msm8x16: Initial change for internal codec support
1052720 I5a98b6128f5d54163ab5d03c4c023a748e6a4e95 clock: qcom: Update the list of clocks supported on MSMF
1037107 Icbef00d61f8705429105f241161362ad9f1f9d30 usb: pd: Only request current amount for explicit contra
1049455 I15011d79fc2f054e64f8bbd1f8f5db8944b46ada usb: gadget: f_fs: Add support for ipc logging
1051104 I7a623463a142a4db1db7247cf7c5dfeb5b99283c defconfig: Enable irq-helper on msmcobalt
1051164 I36b60ba2283b0bbe36f492e1410603b8c2050cc4 ASoC: msm: qdsp6v2: set correct loopback mode
1042302 980427 I9f69eb541e31de6a04db7468ca12a04a837d2b40 input: touchscreen: identify ITE tech controller until r
1022917 I968e1fe6b099ebf5334eadb209219181293b207f ASoC: wcd9335: Configure DMIC clock rate for ECPP path
1026204 Ie9523558c23a8edc7a7ee058937658dd87ef5b16 msm: vidc: Add support for color space information
1046484 I94ae8c769ec2868a291e75a2f47c85bd8a449937 msm: gsi: fix memory corruption from debugfs
1044467 If39ad62cc591565793cd1d8a0f2a454e0b7d5c58 pinctrl: qcom: Update SDC pins for msmfalcon
1047798 If889cd278fea7e13f941635f72047dcb9141ec2e soc: qcom: core,gladiator hang: Change the sysfs print f
1048402 I315e191227e14e207187673b8efb5401143dec9d ASoC: msmcobalt: fix wrong platform device pointer assig
1048939 I667aef9208d14b2dff5944ad6ad9b053797c4ac9 usb: gadget: gsi: Use pm_runtime related API from state
1045916 Id5f204647205b2fde9e5cb422a3ddc8cc4f3a5a0 soc: qcom: glink: Receive remote rx_intent with a cookie
1036145 I725245178ab02c5ec39b89998f5c2ca3d494c8ee qcom-charger: smb138x-charger: add parallel enable statu
1050153 I1c1ef35ea7ef6c2552a22b85c5af260ade413777 soc: qcom: pil: Add flag to know if modem SSR happened.
1048939 I1bdfe16273186b594f83fd03936a461895701996 usb: gadget: gsi: Optimize TRB's buffer allocation funct
1051661 I5c61c970e17cba44c555e60418a9ece80c61488f lpm-levels: Use arm_cpuidle_suspend instead of cpu_suspe
1045208 Ic49a18de64ec210a0636405394ba7a8f52f336a9 input: msg21xx_ts: update mstar driver to enable msg2138
1045916 I97ca857c21d8873574a180d289e2fbca29c8a891 ARM: dts: msm: Add G-Link SPI Transport device for msmco
1051756 I4a3f415263b94d4eab16de05bbb9843b7bb04113 defconfig: Enable memory latency monitors and governor
1042302 982219 Iba07517fd32dbeb3079df9c0346ea0c044b88f63 input: touchscreen: correct return values in ITE tech dr
1030755 I55bc9cda07ef3c2d3ff5713f1ce83d8b344bed6a bluetooth: Add Split A2DP slimbus
1049984 I6dda3b5e8b314d392e51f492b23ce0342e47800a msm: wlan: Update db.txt for some countries
1048182 I67bc99d1939ec7176be2e73fdbe6960e677a5cad msm: mdss: add mdp debug bus for msmcobalt
1045916 I1936bb0542bcd531726bf987ef806969ce96d498 soc: qcom: glink_spi_xprt: Add support for GLink SPI Tra
1040746 I3559ed2b6984ac9cec8e219f59f634410aaf57c9 ARM: dts: msm: adjust mdp bw limits for msmcobalt v2
1049455 Iec93a9d4cb2a10b833cbba0d5256b64161147de2 usb: gadget: configfs: Synchronizing bind/unbind using m
1045045 Ib651dd59b30e4924f4e199cfd4fae64df6030d9d ASoC: msm: qdsp6v2: Fix crash during WFD playback and SS
1045904 I56581533ffff3b61f5b5ee128841ab61b62674d7 ASoC: msm: qdsp6v2: support for AFE encoder
1051416 Ic1b61b2bbb7ce74c9e9422b5e22ee9078251de21 cpuset: Add allow_attach hook for cpusets on android.
1051104 I4737975961b18f1095e3cd78d07a2bca22931291 soc: qcom: irq-helper: Add header file of irq-helper
1051756 Ic4838fd58d40d283ac301facc64b06813eb3bd7d PM / devfreq: memlat: Remove kfree() on probe fails
1036145 I79f95b145176b66d6b8cec5a21922ea16c2c8206 power_supply: add PIN_ENABLED property
1044351 I13161bd8b2a7777abbe2521178c5b1b1b6416eea mdss: display-port: add support to send HPD event to fra
997059 I44925240705608510266a51225cc02611637c571 ASoC: msm: set pointers to NULL after kfree
1050071 Ibeef761044deea375dc7684c0a160609b610b8f6 regulator: cpr3-mmss-regulator: add support for force hi
1050071 Ie9d4e825e5c6040036642cdaf22d1f67b6129685 ARM: dts: msm: increase VDD_GFX CPR ceiling voltages for
1031648 I754c85a2ed02d0b1e40fd1e27b10ff84c463ac83 ARM: dts: msm: Enable the GPU QDSS STM for msmcobalt
1051115 I1809fcef844d275175814e636591b87e91432609 usb: phy: qusb: Fix typo with emulation related property
1045916 I268d96f04b034edad2fadea8ef2c14fe8d8de251 defconfig: msmcortex: Enable G-Link SPI Transport driver
1052589 Id559d9ef9d1e0a25e3bbdc81503978f01c6ed85f Revert "genetlink: disallow subscribing to unknown mcast
1042302 I88e024700de43cc9f712fd7fa509fcb387f9cd21 input: touchscreen: don't allow ITE tech driver to do in
1045904 I22173ef9a7586cc7b9bc4b40afa1c02f5317c3a7 ASoC: msmcobalt: add BT audio support
1032820 I710c1f743d7502e93989e8cc487078366570e723 ASoC: msm: qdsp6v2: check param length for EAC3 format
1051371 If2a7eaf11ad05ced3c52ff87be934745b7dc713b msm: ipa3: update BCR Regsiter values for IPA v3.1 and v
1050517 I3e9f7f85bf1faf0e1bb501196ba9d7e197111a03 clk: msm: Add support for block reset clocks
1045208 Ib6046de5230c395b48818d01f26eb9394046808b input: msg21xx_ts: add support for firmware upgrade
1050071 Ifa54325a1364f10b6f1760c52ad029612114759c regulator: cpr3-mmss-regulator: update msmcobalt partial
1051878 Ia452476bd3bb7316a86efd08fed52c54f3efa34e ARM: dts: msm: Update USB core clock frequency to allow
1048727 I3a1ecc89f379a90d9fdacf0baa9b6c8498bb93fb msm: mdss: fix spurious wait4pingpong timeouts
1050670 Iba47db8936b49309360791c1c6b482dcfcffd4d7 msm: ipa: do not use skb clones for lan clients
1045904 I93ad53016a28efe0d8592ac0092d6c8896a66072 ASoC: msm: q6dspv2: add adm channel config support
1042302 982219 Ic8b66317f414fe3bfcd0f9c5b03369cc304edb55 input: touchscreen: correct function and variable names
1049499 I795d14fd4bc3b5f31897a70009546238117b0825 msm: vidc: Allow venus to power collapse in batch mode
1048706 I702b4ff11582047b00e3f0d5433d29c84f34e913 msm: ipa: Add parameters validation to handle static ana
1037191 I6d9d92f7291df2d92f9faf3c4e80b832422b3ddf ARM: dts: msm: Add SMMU implementation defined settings
1048941 I97763004454d082d3cc2d9d9dbef7da923608600 sched: Remove synchronize rcu/sched calls from _cpu_down
Change-Id: I89d1085e144b7f28cd97520eb36af1fede881fcd
CRs-Fixed: 1031648, 1046484, 1051756, 1051661, 1037107, 1050156, 1051104, 1049984, 1048182, 1050153, 1034085, 1049477, 1040200, 1045208, 1026204, 1046961, 1049455, 1051115, 982219, 1051878, 1022917, 1045916, 1049499, 1048282, 1050071, 1052720, 1050763, 1047798, 1030755, 1044351, 1050785, 980427, 1048941, 1036145, 1045045, 1051416, 1037191, 1044467, 1051569, 1042302, 1048727, 1050517, 1051371, 1048402, 1040746, 1048706, 1050670, 1048939, 1045904, 1032820, 1051164, 1052589, 997059, 1048345, 1046168
144 files changed, 19860 insertions, 3412 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/glink_spi_xprt.txt b/Documentation/devicetree/bindings/arm/msm/glink_spi_xprt.txt new file mode 100644 index 000000000000..0a78eb6b91fd --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/glink_spi_xprt.txt @@ -0,0 +1,44 @@ +Qualcomm Technologies, Inc. G-link SPI Transport + +Required properties: +-compatible : should be "qcom,glink-spi-xprt". +-label : the name of the subsystem this link connects to. + +Optional properties: +-qcom,remote-fifo-config: Reference to the FIFO configuratio in the remote + processor. +-qcom,qos-config: Reference to the qos configuration elements.It depends on + ramp-time. +-qcom,ramp-time: Worst case time in microseconds to transition to this power + state. Power states are numbered by array index position. + +Example: + + glink_spi_xprt_wdsp: qcom,glink-spi-xprt-wdsp { + compatible = "qcom,glink-spi-xprt"; + label = "wdsp"; + qcom,remote-fifo-config = <&glink_fifo_wdsp>; + qcom,qos-config = <&glink_qos_wdsp>; + qcom,ramp-time = <0x10>, + <0x20>, + <0x30>, + <0x40>; + }; + + glink_fifo_wdsp: qcom,glink-fifo-config-wdsp { + compatible = "qcom,glink-fifo-config"; + qcom,out-read-idx-reg = <0x12000>; + qcom,out-write-idx-reg = <0x12004>; + qcom,in-read-idx-reg = <0x1200C>; + qcom,in-write-idx-reg = <0x12010>; + }; + + glink_qos_wdsp: qcom,glink-qos-config-wdsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x80 0x0>, + <0x70 0x1>, + <0x60 0x2>, + <0x50 0x3>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; 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 d585595f21c6..c0a7a240b922 100644 --- a/Documentation/devicetree/bindings/sound/wcd_codec.txt +++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt @@ -92,6 +92,14 @@ Optional properties: involving DMIC will use the rate defined by cdc-dmic-sample-rate. + - qcom,cdc-ecpp-dmic-rate: Specifies the sample rate of digital mic in HZ to be + used by ECPP (Echo Cancellation Ping Pong) block + on the codec. The valid set of values are same + as that of cdc-dmic-sample-rate, but this rate will + only be used by ECPP and all other audio use cases + involving DMIC will use the rate defined by + cdc-dmic-sample-rate. + - qcom,cdc-dmic-clk-drv-strength: Specifies the drive strength for digital microphone clock in the codec. Accepted values are 2,4,8 and 16. The clock drive strentgh is in uA. Codec driver will @@ -375,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. @@ -427,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/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/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-gpu.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi index 6ab19b298aa7..d273d757dba5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi @@ -79,6 +79,8 @@ qcom,snapshot-size = <1048576>; //bytes + qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size + clocks = <&clock_gfx clk_gpucc_gfx3d_clk>, <&clock_gcc clk_gcc_gpu_cfg_ahb_clk>, <&clock_gpu clk_gpucc_rbbmtimer_clk>, 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-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 5833b30d1fd1..9f8ecea15568 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -944,20 +944,20 @@ qcom,cpr-voltage-ceiling = <896000 896000 896000 896000 896000 1032000>, - <632000 696000 768000 828000 896000 - 1032000>, - <632000 696000 768000 828000 896000 - 1032000>, - <632000 696000 768000 828000 896000 - 1032000>, - <632000 696000 768000 828000 896000 - 1032000>, - <632000 696000 768000 828000 896000 - 1032000>, - <632000 696000 768000 828000 896000 - 1032000>, - <632000 696000 768000 828000 896000 - 1032000>; + <672000 740000 800000 868000 976000 + 1100000>, + <672000 740000 800000 868000 976000 + 1100000>, + <672000 740000 800000 868000 976000 + 1100000>, + <672000 740000 800000 868000 976000 + 1100000>, + <672000 740000 800000 868000 976000 + 1100000>, + <672000 740000 800000 868000 976000 + 1100000>, + <672000 740000 800000 868000 976000 + 1100000>; qcom,cpr-voltage-floor = <896000 896000 896000 896000 896000 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 c9a2abf0d5b5..83ad8861103b 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -1309,6 +1309,35 @@ qcom,rx-ring-size = <0x800>; }; + glink_spi_xprt_wdsp: qcom,glink-spi-xprt-wdsp { + compatible = "qcom,glink-spi-xprt"; + label = "wdsp"; + qcom,remote-fifo-config = <&glink_fifo_wdsp>; + qcom,qos-config = <&glink_qos_wdsp>; + qcom,ramp-time = <0x10>, + <0x20>, + <0x30>, + <0x40>; + }; + + glink_fifo_wdsp: qcom,glink-fifo-config-wdsp { + compatible = "qcom,glink-fifo-config"; + qcom,out-read-idx-reg = <0x12000>; + qcom,out-write-idx-reg = <0x12004>; + qcom,in-read-idx-reg = <0x1200C>; + qcom,in-write-idx-reg = <0x12010>; + }; + + glink_qos_wdsp: qcom,glink-qos-config-wdsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x80 0x0>, + <0x70 0x1>, + <0x60 0x2>, + <0x50 0x3>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; + qcom,glink_pkt { compatible = "qcom,glinkpkt"; @@ -1737,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>; @@ -2918,6 +2948,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-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi index a397310d4a61..6a000e4d4fd0 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi @@ -11,9 +11,9 @@ */ &soc { - tlmm: pinctrl@03400000 { + tlmm: pinctrl@03000000 { compatible = "qcom,msmfalcon-pinctrl"; - reg = <0x03400000 0xc00000>; + reg = <0x03000000 0xc00000>; interrupts = <0 208 0>; gpio-controller; #gpio-cells = <2>; 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 f9d9a882db1f..a09e952927f7 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -383,6 +383,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 @@ -419,6 +420,7 @@ CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_MTP=y @@ -481,6 +483,7 @@ CONFIG_MSM_GLINK=y CONFIG_MSM_GLINK_LOOPBACK_SERVER=y CONFIG_MSM_GLINK_SMD_XPRT=y CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y CONFIG_MSM_SPCOM=y CONFIG_MSM_SMEM_LOGGING=y CONFIG_MSM_SMP2P=y @@ -495,6 +498,7 @@ CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SPM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_IRQ_HELPER=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_ICNSS=y CONFIG_MSM_RUN_QUEUE_STATS=y @@ -517,7 +521,9 @@ CONFIG_MSM_RPM_STATS_LOG=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index bdfcbb4d1621..cfc2c30ca91f 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -386,6 +386,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 @@ -421,6 +422,7 @@ CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_MTP=y @@ -494,6 +496,7 @@ CONFIG_MSM_GLINK=y CONFIG_MSM_GLINK_LOOPBACK_SERVER=y CONFIG_MSM_GLINK_SMD_XPRT=y CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y CONFIG_MSM_SPCOM=y CONFIG_MSM_SMEM_LOGGING=y CONFIG_MSM_SMP2P=y @@ -510,6 +513,7 @@ CONFIG_MSM_GLINK_PKT=y CONFIG_MSM_SPM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_IRQ_HELPER=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_ICNSS=y CONFIG_MSM_GLADIATOR_ERP_V2=y @@ -538,7 +542,9 @@ CONFIG_MSM_RPM_STATS_LOG=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_SPDM_SCM=y CONFIG_DEVFREQ_SPDM=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/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index 370d7d95042b..4fb0a5ffda50 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -311,19 +311,19 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) hw->of_node = of_parse_phandle(dev->of_node, "qcom,target-dev", 0); if (!hw->of_node) { dev_err(dev, "Couldn't find a target device\n"); - goto err_out; + return -ENODEV; } if (get_mask_from_dev_handle(pdev, &cpu_grp->cpus)) { dev_err(dev, "CPU list is empty\n"); - goto err_out; + return -ENODEV; } hw->num_cores = cpumask_weight(&cpu_grp->cpus); hw->core_stats = devm_kzalloc(dev, hw->num_cores * sizeof(*(hw->core_stats)), GFP_KERNEL); if (!hw->core_stats) - goto err_out; + return -ENOMEM; for_each_cpu(cpu, &cpu_grp->cpus) hw->core_stats[cpu - cpumask_first(&cpu_grp->cpus)].id = cpu; @@ -335,14 +335,10 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) ret = register_memlat(dev, hw); if (ret) { pr_err("Mem Latency Gov registration failed\n"); - goto err_out; + return ret; } return 0; - -err_out: - kfree(cpu_grp); - return -EINVAL; } static struct of_device_id match_table[] = { 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/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index cbe77022404b..9b9b74436d88 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -675,6 +675,12 @@ static int get_hfi_extradata_index(enum hal_extradata_id index) case HAL_EXTRADATA_PQ_INFO: ret = HFI_PROPERTY_PARAM_VENC_OVERRIDE_QP_EXTRADATA; break; + case HAL_EXTRADATA_VUI_DISPLAY_INFO: + ret = HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA; + break; + case HAL_EXTRADATA_VPX_COLORSPACE: + ret = HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA; + break; default: dprintk(VIDC_WARN, "Extradata index not found: %d\n", index); break; @@ -2127,6 +2133,26 @@ int create_pkt_cmd_session_set_property( pkt->size += sizeof(u32) + sizeof(struct hfi_enable); break; } + case HAL_PARAM_VENC_VIDEO_SIGNAL_INFO: + { + struct hal_video_signal_info *hal = pdata; + struct hfi_video_signal_metadata *signal_info = + (struct hfi_video_signal_metadata *) + &pkt->rg_property_data[1]; + + signal_info->enable = true; + signal_info->video_format = MSM_VIDC_NTSC; + signal_info->video_full_range = hal->full_range; + signal_info->color_description = MSM_VIDC_COLOR_DESC_PRESENT; + signal_info->color_primaries = hal->color_space; + signal_info->transfer_characteristics = hal->transfer_chars; + signal_info->matrix_coeffs = hal->matrix_coeffs; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO; + pkt->size += sizeof(u32) + sizeof(*signal_info); + break; + } /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ case HAL_CONFIG_BUFFER_REQUIREMENTS: case HAL_CONFIG_PRIORITY: diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 0c26cc7debaf..96fefea39241 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -247,7 +247,7 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { .name = "Extradata Type", .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE, - .maximum = V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI, + .maximum = V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE, .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE, .menu_skip_mask = ~( (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) | @@ -273,7 +273,10 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { (1 << V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI) | (1 << V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP) | (1 << V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI) | - (1 << V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI) + (1 << + V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE) ), .qmenu = mpeg_video_vidc_extradata, }, diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 55e54f7eb008..c08084a54e86 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1242,6 +1242,46 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .default_value = V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE, .step = 1, }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE, + .name = "Set Color space", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_BT709_5, + .maximum = MSM_VIDC_BT2020, + .default_value = MSM_VIDC_BT601_6_625, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE, + .name = "Set Color space range", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_ENABLE, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS, + .name = "Set Color space transfer characterstics", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_TRANSFER_BT709_5, + .maximum = MSM_VIDC_TRANSFER_BT_2020_12, + .default_value = MSM_VIDC_TRANSFER_601_6_625, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS, + .name = "Set Color space matrix coefficients", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_MATRIX_BT_709_5, + .maximum = MSM_VIDC_MATRIX_BT_2020_CONST, + .default_value = MSM_VIDC_MATRIX_601_6_625, + .step = 1, + .qmenu = NULL, + }, + }; #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls) @@ -2105,6 +2145,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) int baselayerid = 0; int frameqp = 0; int pic_order_cnt = 0; + struct hal_video_signal_info signal_info = {0}; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); @@ -3093,6 +3134,64 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) pdata = &pic_order_cnt; break; } + case V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE: + { + signal_info.color_space = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE: + { + signal_info.full_range = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS: + { + signal_info.transfer_chars = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS: + { + signal_info.matrix_coeffs = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC: if (ctrl->val == V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE) { rc = msm_venc_set_csc(inst); @@ -3516,10 +3615,6 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) } hdev = inst->core->device; - if (msm_vidc_vpe_csc_601_to_709) { - msm_venc_set_csc(inst); - } - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 8541e06d997a..1f071ba36ec1 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -77,6 +77,8 @@ const char *const mpeg_video_vidc_extradata[] = { "Extradata display colour SEI", "Extradata light level SEI", "Extradata PQ Info", + "Extradata display VUI", + "Extradata vpx color space", }; struct getprop_buf { @@ -210,7 +212,8 @@ int msm_comm_ctrl_init(struct msm_vidc_inst *inst, } if (!ctrl) { - dprintk(VIDC_ERR, "%s - invalid ctrl\n", __func__); + dprintk(VIDC_ERR, "%s - invalid ctrl %s\n", __func__, + drv_ctrls[idx].name); return -EINVAL; } @@ -1719,6 +1722,19 @@ static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq, return vb; } +static void msm_vidc_try_suspend(struct msm_vidc_inst *inst) +{ + bool batch_mode; + + batch_mode = msm_comm_g_ctrl_for_id(inst, V4L2_CID_VIDC_QBUF_MODE) + == V4L2_VIDC_QBUF_BATCHED; + if (batch_mode) { + dprintk(VIDC_DBG, + "Trying to suspend Venus after finishing Batch\n"); + msm_comm_suspend(inst->core->id); + } +} + static void handle_ebd(enum hal_command_response cmd, void *data) { struct msm_vidc_cb_data_done *response = data; @@ -1790,6 +1806,8 @@ static void handle_ebd(enum hal_command_response cmd, void *data) msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD); } + msm_vidc_try_suspend(inst); + put_inst(inst); } @@ -2089,6 +2107,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data) msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FBD); } + msm_vidc_try_suspend(inst); err_handle_fbd: put_inst(inst); } @@ -4692,6 +4711,13 @@ enum hal_extradata_id msm_comm_get_hal_extradata_index( case V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO: ret = HAL_EXTRADATA_PQ_INFO; break; + + case V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY: + ret = HAL_EXTRADATA_VUI_DISPLAY_INFO; + break; + case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE: + ret = HAL_EXTRADATA_VPX_COLORSPACE; + break; default: dprintk(VIDC_WARN, "Extradata not found: %d\n", index); break; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index fb79661dd2d7..7976d6e8a603 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -171,8 +171,6 @@ struct dentry *msm_vidc_debugfs_init_drv(void) &msm_vidc_fw_low_power_mode) && __debugfs_create(u32, "debug_output", &msm_vidc_debug_out) && __debugfs_create(u32, "hw_rsp_timeout", &msm_vidc_hw_rsp_timeout) && - __debugfs_create(bool, "enable_vpe_csc_601_709", - &msm_vidc_vpe_csc_601_to_709) && __debugfs_create(bool, "sys_idle_indicator", &msm_vidc_sys_idle_indicator) && __debugfs_create(u32, "firmware_unload_delay", diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 20e217cc0445..50c0eb351d4f 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1297,17 +1297,9 @@ static int venus_hfi_suspend(void *dev) return -ENOTSUPP; } - mutex_lock(&device->lock); + dprintk(VIDC_DBG, "Suspending Venus\n"); + rc = flush_delayed_work(&venus_hfi_pm_work); - if (device->power_enabled) { - dprintk(VIDC_DBG, "Venus is busy\n"); - rc = -EBUSY; - } else { - dprintk(VIDC_DBG, "Venus is power suspended\n"); - rc = 0; - } - - mutex_unlock(&device->lock); return rc; } diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index 330710631211..4cbb59d12f92 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -85,6 +85,7 @@ #define HFI_EXTRADATA_STREAM_USERDATA 0x0000000E #define HFI_EXTRADATA_FRAME_QP 0x0000000F #define HFI_EXTRADATA_FRAME_BITS_INFO 0x00000010 +#define HFI_EXTRADATA_VPX_COLORSPACE 0x00000014 #define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000 #define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001 #define HFI_EXTRADATA_INDEX 0x7F100002 diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 36df3a1d45a1..34ab36a4647b 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -125,6 +125,8 @@ enum hal_extradata_id { HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI, HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI, HAL_EXTRADATA_PQ_INFO, + HAL_EXTRADATA_VUI_DISPLAY_INFO, + HAL_EXTRADATA_VPX_COLORSPACE, }; enum hal_property { @@ -239,6 +241,7 @@ enum hal_property { HAL_CONFIG_VENC_BLUR_RESOLUTION, HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED, HAL_PARAM_VENC_H264_TRANSFORM_8x8, + HAL_PARAM_VENC_VIDEO_SIGNAL_INFO, }; enum hal_domain { @@ -992,6 +995,13 @@ struct hal_vpe_color_space_conversion { u32 csc_limit[HAL_MAX_LIMIT_COEFFS]; }; +struct hal_video_signal_info { + u32 color_space; + u32 transfer_chars; + u32 matrix_coeffs; + bool full_range; +}; + enum vidc_resource_id { VIDC_RESOURCE_NONE, VIDC_RESOURCE_OCMEM, diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index ff043e9a819b..23240746baf1 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -350,7 +350,7 @@ struct hfi_buffer_info { (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01B) #define HFI_PROPERTY_PARAM_VENC_LTRMODE \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C) -#define HFI_PROPERTY_PARAM_VENC_VIDEO_FULL_RANGE \ +#define HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D) #define HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E) @@ -671,6 +671,16 @@ struct hfi_frame_size { u32 height; }; +struct hfi_video_signal_metadata { + u32 enable; + u32 video_format; + u32 video_full_range; + u32 color_description; + u32 color_primaries; + u32 transfer_characteristics; + u32 matrix_coeffs; +}; + struct hfi_h264_vui_timing_info { u32 enable; u32 fixed_frame_rate; diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c index 22d61d96a11d..38286831a02c 100644 --- a/drivers/mfd/wcd9xxx-utils.c +++ b/drivers/mfd/wcd9xxx-utils.c @@ -298,6 +298,7 @@ struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev) struct wcd9xxx_pdata *pdata; u32 dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED; u32 mad_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED; + u32 ecpp_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED; u32 dmic_clk_drive = WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED; u32 prop_val; @@ -358,6 +359,15 @@ struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev) pdata->mclk_rate, "mad_dmic_rate"); + if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-ecpp-dmic-rate", + &prop_val))) + ecpp_dmic_sample_rate = prop_val; + + pdata->ecpp_dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev, + ecpp_dmic_sample_rate, + pdata->mclk_rate, + "ecpp_dmic_rate"); + if (!(of_property_read_u32(dev->of_node, "qcom,cdc-dmic-clk-drv-strength", &prop_val))) diff --git a/drivers/pinctrl/qcom/pinctrl-msmfalcon.c b/drivers/pinctrl/qcom/pinctrl-msmfalcon.c index 14abb75fffe0..45db409eb7c1 100644 --- a/drivers/pinctrl/qcom/pinctrl-msmfalcon.c +++ b/drivers/pinctrl/qcom/pinctrl-msmfalcon.c @@ -25,9 +25,9 @@ .ngroups = ARRAY_SIZE(fname##_groups), \ } -#define SOUTH 0x00500000 -#define WEST 0x00100000 -#define EAST 0x00900000 +#define NORTH 0x00900000 +#define CENTER 0x00500000 +#define SOUTH 0x00100000 #define REG_SIZE 0x1000 #define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ { \ @@ -204,9 +204,16 @@ static const struct pinctrl_pin_desc msmfalcon_pins[] = { PINCTRL_PIN(108, "GPIO_108"), PINCTRL_PIN(109, "GPIO_109"), PINCTRL_PIN(110, "GPIO_110"), - PINCTRL_PIN(111, "SDC2_CLK"), - PINCTRL_PIN(112, "SDC2_CMD"), - PINCTRL_PIN(113, "SDC2_DATA"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "SDC1_CLK"), + PINCTRL_PIN(115, "SDC1_CMD"), + PINCTRL_PIN(116, "SDC1_DATA"), + PINCTRL_PIN(117, "SDC2_CLK"), + PINCTRL_PIN(118, "SDC2_CMD"), + PINCTRL_PIN(119, "SDC2_DATA"), + PINCTRL_PIN(120, "SDC1_RCLK"), }; #define DECLARE_MSM_GPIO_PINS(pin) \ @@ -322,88 +329,101 @@ DECLARE_MSM_GPIO_PINS(107); DECLARE_MSM_GPIO_PINS(108); DECLARE_MSM_GPIO_PINS(109); DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); -static const unsigned int sdc2_clk_pins[] = { 111 }; -static const unsigned int sdc2_cmd_pins[] = { 112 }; -static const unsigned int sdc2_data_pins[] = { 113 }; +static const unsigned int sdc1_clk_pins[] = { 114 }; +static const unsigned int sdc1_cmd_pins[] = { 115 }; +static const unsigned int sdc1_data_pins[] = { 116 }; +static const unsigned int sdc2_clk_pins[] = { 117 }; +static const unsigned int sdc2_cmd_pins[] = { 118 }; +static const unsigned int sdc2_data_pins[] = { 119 }; +static const unsigned int sdc1_rclk_pins[] = { 120 }; enum msmfalcon_functions { msm_mux_blsp_spi1, msm_mux_gpio, + msm_mux_blsp_uim1, msm_mux_tgu_ch0, - msm_mux_tgu_ch1, + msm_mux_qdss_gpio4, + msm_mux_atest_gpsadc1, msm_mux_blsp_uart1, + msm_mux_SMB_STAT, + msm_mux_phase_flag14, + msm_mux_blsp_i2c2, + msm_mux_phase_flag31, msm_mux_blsp_spi3, msm_mux_wlan1_adc1, msm_mux_atest_usb13, - msm_mux_bimc_dte1, - msm_mux_wlan1_adc0, - msm_mux_atest_usb12, - msm_mux_bimc_dte0, + msm_mux_tgu_ch1, + msm_mux_qdss_gpio5, + msm_mux_atest_gpsadc0, msm_mux_blsp_i2c1, - msm_mux_blsp_uim1, msm_mux_ddr_bist, msm_mux_atest_tsens2, msm_mux_atest_usb1, msm_mux_blsp_spi2, - msm_mux_phase_flag3, - msm_mux_phase_flag14, - msm_mux_blsp_i2c2, msm_mux_blsp_uim2, - msm_mux_phase_flag31, + msm_mux_phase_flag3, + msm_mux_bimc_dte1, + msm_mux_wlan1_adc0, + msm_mux_atest_usb12, + msm_mux_bimc_dte0, msm_mux_blsp_i2c3, - msm_mux_atest_gpsadc1, msm_mux_wlan2_adc1, msm_mux_atest_usb11, msm_mux_dbg_out, - msm_mux_atest_gpsadc0, msm_mux_wlan2_adc0, msm_mux_atest_usb10, + msm_mux_RCM_MARKER, msm_mux_blsp_spi4, msm_mux_pri_mi2s, msm_mux_phase_flag26, - msm_mux_qdss_gpio4, + msm_mux_qdss_cti, + msm_mux_DP_HOT, msm_mux_pri_mi2s_ws, msm_mux_phase_flag27, - msm_mux_qdss_gpio5, msm_mux_blsp_i2c4, msm_mux_phase_flag28, msm_mux_blsp_uart5, msm_mux_blsp_spi5, + msm_mux_blsp_uim5, msm_mux_phase_flag5, msm_mux_blsp_i2c5, - msm_mux_blsp_uim5, msm_mux_blsp_spi6, msm_mux_blsp_uart2, - msm_mux_qdss_cti, - msm_mux_sec_mi2s, - msm_mux_sndwire_clk, - msm_mux_phase_flag17, - msm_mux_vsense_clkout, - msm_mux_sndwire_data, - msm_mux_phase_flag18, - msm_mux_blsp_i2c7, - msm_mux_wsa_en1, - msm_mux_phase_flag19, + msm_mux_blsp_uim6, msm_mux_phase_flag11, msm_mux_vsense_data0, msm_mux_blsp_i2c6, - msm_mux_blsp_uim6, msm_mux_phase_flag12, msm_mux_vsense_data1, msm_mux_phase_flag13, msm_mux_vsense_mode, msm_mux_blsp_spi7, msm_mux_BLSP_UART, + msm_mux_sec_mi2s, + msm_mux_sndwire_clk, + msm_mux_phase_flag17, + msm_mux_vsense_clkout, + msm_mux_sndwire_data, + msm_mux_phase_flag18, + msm_mux_WSA_SPKR, + msm_mux_blsp_i2c7, + msm_mux_phase_flag19, msm_mux_vfr_1, - msm_mux_wsa_en2, msm_mux_phase_flag20, + msm_mux_NFC_INT, msm_mux_blsp_spi, msm_mux_m_voc, msm_mux_phase_flag21, + msm_mux_NFC_EN, msm_mux_phase_flag22, + msm_mux_NFC_DWL, msm_mux_BLSP_I2C, msm_mux_phase_flag23, + msm_mux_NFC_ESE, msm_mux_pwr_modem, msm_mux_phase_flag24, msm_mux_qdss_gpio, @@ -419,88 +439,92 @@ enum msmfalcon_functions { msm_mux_qspi_data2, msm_mux_jitter_bist, msm_mux_qdss_gpio3, + msm_mux_qdss_gpio7, + msm_mux_FL_R3LED, + msm_mux_CCI_TIMER0, + msm_mux_FL_STROBE, + msm_mux_CCI_TIMER1, + msm_mux_CAM_LDO1, + msm_mux_mdss_vsync0, + msm_mux_mdss_vsync1, + msm_mux_mdss_vsync2, + msm_mux_mdss_vsync3, + msm_mux_qdss_gpio9, + msm_mux_CAM_IRQ, + msm_mux_atest_usb2, msm_mux_cci_i2c, msm_mux_pll_bypassnl, msm_mux_atest_tsens, + msm_mux_atest_usb21, msm_mux_pll_reset, - msm_mux_qdss_gpio9, - msm_mux_CAM_IRQ, + msm_mux_atest_usb23, + msm_mux_qdss_gpio6, msm_mux_CCI_TIMER3, msm_mux_CCI_ASYNC, msm_mux_qspi_cs, msm_mux_qdss_gpio10, - msm_mux_CAM4_STANDBY, + msm_mux_CAM3_STANDBY, msm_mux_CCI_TIMER4, msm_mux_qdss_gpio11, - msm_mux_bt_reset, + msm_mux_CAM_LDO2, msm_mux_cci_async, msm_mux_qdss_gpio12, - msm_mux_CAM1_RST, - msm_mux_qdss_gpio6, - msm_mux_qdss_gpio7, - msm_mux_FL_FRONT, - msm_mux_CCI_TIMER0, - msm_mux_qdss_gpio8, - msm_mux_FL_STROBE, - msm_mux_CCI_TIMER1, - msm_mux_LASER_CE, - msm_mux_mdss_vsync0, - msm_mux_mdss_vsync1, - msm_mux_mdss_vsync2, - msm_mux_mdss_vsync3, + msm_mux_CAM0_RST, msm_mux_qdss_gpio13, - msm_mux_CAM2_RST, + msm_mux_CAM1_RST, msm_mux_qspi_clk, msm_mux_phase_flag30, msm_mux_qdss_gpio14, - msm_mux_CAM3_RST, msm_mux_qspi_resetn, msm_mux_phase_flag1, msm_mux_qdss_gpio15, - msm_mux_CAM1_STANDBY, + msm_mux_CAM0_STANDBY, msm_mux_phase_flag2, - msm_mux_CAM2_STANDBY, + msm_mux_CAM1_STANDBY, msm_mux_phase_flag9, - msm_mux_CAM3_STANDBY, + msm_mux_CAM2_STANDBY, msm_mux_qspi_data3, msm_mux_phase_flag15, - msm_mux_CAM4_RST, + msm_mux_qdss_gpio8, + msm_mux_CAM3_RST, msm_mux_CCI_TIMER2, msm_mux_phase_flag16, + msm_mux_LCD0_RESET, msm_mux_phase_flag6, - msm_mux_RCM_MARKER2, + msm_mux_SD_CARD, msm_mux_phase_flag29, - msm_mux_SS_SWITCH, + msm_mux_DP_EN, msm_mux_phase_flag25, + msm_mux_USBC_ORIENTATION, msm_mux_phase_flag10, + msm_mux_atest_usb20, msm_mux_gcc_gp1, msm_mux_phase_flag4, - msm_mux_USB_DIR, + msm_mux_atest_usb22, msm_mux_USB_PHY, msm_mux_gcc_gp2, msm_mux_atest_char, msm_mux_mdp_vsync, msm_mux_gcc_gp3, msm_mux_atest_char3, - msm_mux_Lcd_mode, - msm_mux_EDP_HOT, + msm_mux_FORCE_TOUCH, msm_mux_cri_trng0, msm_mux_atest_char2, msm_mux_cri_trng1, msm_mux_atest_char1, + msm_mux_AUDIO_USBC, msm_mux_audio_ref, msm_mux_MDP_VSYNC, msm_mux_cri_trng, msm_mux_atest_char0, msm_mux_US_EURO, - msm_mux_KEY_FOCUS, - msm_mux_NAV_PPS, + msm_mux_LCD_BACKLIGHT, msm_mux_blsp_spi8, msm_mux_sp_cmu, - msm_mux_SLT_PWR, + msm_mux_NAV_PPS, + msm_mux_GPS_TX, msm_mux_adsp_ext, msm_mux_TS_RESET, - msm_mux_TS_INT, msm_mux_ssc_irq, msm_mux_isense_dbg, msm_mux_phase_flag0, @@ -508,8 +532,10 @@ enum msmfalcon_functions { msm_mux_phase_flag8, msm_mux_tsense_pwm1, msm_mux_tsense_pwm2, + msm_mux_SENSOR_RST, + msm_mux_WMSS_RESETN, msm_mux_HAPTICS_PWM, - msm_mux_wmss_reset, + msm_mux_GPS_eLNA, msm_mux_mss_lte, msm_mux_uim2_data, msm_mux_uim2_clk, @@ -521,12 +547,12 @@ enum msmfalcon_functions { msm_mux_uim1_present, msm_mux_uim_batt, msm_mux_pa_indicator, - msm_mux_ssbi_gnss, msm_mux_ldo_en, msm_mux_ldo_update, msm_mux_qlink_request, msm_mux_qlink_enable, msm_mux_prng_rosc, + msm_mux_LCD_PWR, msm_mux_NA, }; @@ -534,27 +560,44 @@ static const char * const blsp_spi1_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3", "gpio46", }; static const char * const gpio_groups[] = { - "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", - "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", - "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", - "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", - "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", - "gpio36", "gpio37", "gpio38", "gpio39", "gpio53", "gpio57", "gpio59", - "gpio61", "gpio62", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", - "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", - "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", - "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", - "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio6", "gpio7", "gpio8", + "gpio9", "gpio10", "gpio11", "gpio14", "gpio15", "gpio16", "gpio17", + "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", + "gpio25", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio37", + "gpio38", "gpio39", "gpio57", "gpio58", "gpio59", "gpio61", "gpio65", + "gpio81", "gpio82", "gpio83", "gpio84", "gpio85", "gpio86", "gpio87", + "gpio88", "gpio89", "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", + "gpio95", "gpio96", "gpio97", "gpio98", "gpio99", "gpio100", "gpio101", + "gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107", + "gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113", +}; +static const char * const blsp_uim1_groups[] = { + "gpio0", "gpio1", }; static const char * const tgu_ch0_groups[] = { "gpio0", }; -static const char * const tgu_ch1_groups[] = { - "gpio1", +static const char * const qdss_gpio4_groups[] = { + "gpio0", "gpio36", +}; +static const char * const atest_gpsadc1_groups[] = { + "gpio0", }; static const char * const blsp_uart1_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3", }; +static const char * const SMB_STAT_groups[] = { + "gpio5", +}; +static const char * const phase_flag14_groups[] = { + "gpio5", +}; +static const char * const blsp_i2c2_groups[] = { + "gpio6", "gpio7", +}; +static const char * const phase_flag31_groups[] = { + "gpio6", +}; static const char * const blsp_spi3_groups[] = { "gpio8", "gpio9", "gpio10", "gpio11", "gpio30", "gpio65", }; @@ -564,24 +607,18 @@ static const char * const wlan1_adc1_groups[] = { static const char * const atest_usb13_groups[] = { "gpio8", }; -static const char * const bimc_dte1_groups[] = { - "gpio8", "gpio10", -}; -static const char * const wlan1_adc0_groups[] = { - "gpio9", +static const char * const tgu_ch1_groups[] = { + "gpio1", }; -static const char * const atest_usb12_groups[] = { - "gpio9", +static const char * const qdss_gpio5_groups[] = { + "gpio1", "gpio37", }; -static const char * const bimc_dte0_groups[] = { - "gpio9", "gpio11", +static const char * const atest_gpsadc0_groups[] = { + "gpio1", }; static const char * const blsp_i2c1_groups[] = { "gpio2", "gpio3", }; -static const char * const blsp_uim1_groups[] = { - "gpio2", "gpio3", -}; static const char * const ddr_bist_groups[] = { "gpio3", "gpio8", "gpio9", "gpio10", }; @@ -594,27 +631,27 @@ static const char * const atest_usb1_groups[] = { static const char * const blsp_spi2_groups[] = { "gpio4", "gpio5", "gpio6", "gpio7", }; +static const char * const blsp_uim2_groups[] = { + "gpio4", "gpio5", +}; static const char * const phase_flag3_groups[] = { "gpio4", }; -static const char * const phase_flag14_groups[] = { - "gpio5", +static const char * const bimc_dte1_groups[] = { + "gpio8", "gpio10", }; -static const char * const blsp_i2c2_groups[] = { - "gpio6", "gpio7", +static const char * const wlan1_adc0_groups[] = { + "gpio9", }; -static const char * const blsp_uim2_groups[] = { - "gpio6", "gpio7", +static const char * const atest_usb12_groups[] = { + "gpio9", }; -static const char * const phase_flag31_groups[] = { - "gpio6", +static const char * const bimc_dte0_groups[] = { + "gpio9", "gpio11", }; static const char * const blsp_i2c3_groups[] = { "gpio10", "gpio11", }; -static const char * const atest_gpsadc1_groups[] = { - "gpio10", -}; static const char * const wlan2_adc1_groups[] = { "gpio10", }; @@ -624,15 +661,15 @@ static const char * const atest_usb11_groups[] = { static const char * const dbg_out_groups[] = { "gpio11", }; -static const char * const atest_gpsadc0_groups[] = { - "gpio11", -}; static const char * const wlan2_adc0_groups[] = { "gpio11", }; static const char * const atest_usb10_groups[] = { "gpio11", }; +static const char * const RCM_MARKER_groups[] = { + "gpio12", "gpio13", +}; static const char * const blsp_spi4_groups[] = { "gpio12", "gpio13", "gpio14", "gpio15", }; @@ -642,8 +679,12 @@ static const char * const pri_mi2s_groups[] = { static const char * const phase_flag26_groups[] = { "gpio12", }; -static const char * const qdss_gpio4_groups[] = { - "gpio12", "gpio36", +static const char * const qdss_cti_groups[] = { + "gpio12", "gpio13", "gpio21", "gpio49", "gpio50", "gpio53", "gpio55", + "gpio66", +}; +static const char * const DP_HOT_groups[] = { + "gpio13", }; static const char * const pri_mi2s_ws_groups[] = { "gpio13", @@ -651,9 +692,6 @@ static const char * const pri_mi2s_ws_groups[] = { static const char * const phase_flag27_groups[] = { "gpio13", }; -static const char * const qdss_gpio5_groups[] = { - "gpio13", "gpio37", -}; static const char * const blsp_i2c4_groups[] = { "gpio14", "gpio15", }; @@ -666,51 +704,23 @@ static const char * const blsp_uart5_groups[] = { static const char * const blsp_spi5_groups[] = { "gpio16", "gpio17", "gpio18", "gpio19", }; +static const char * const blsp_uim5_groups[] = { + "gpio16", "gpio17", +}; static const char * const phase_flag5_groups[] = { "gpio17", }; static const char * const blsp_i2c5_groups[] = { "gpio18", "gpio19", }; -static const char * const blsp_uim5_groups[] = { - "gpio18", "gpio19", -}; static const char * const blsp_spi6_groups[] = { "gpio20", "gpio21", "gpio22", "gpio23", }; static const char * const blsp_uart2_groups[] = { "gpio20", "gpio21", "gpio22", "gpio23", }; -static const char * const qdss_cti_groups[] = { - "gpio20", "gpio21", "gpio24", "gpio25", "gpio26", "gpio49", "gpio50", - "gpio61", -}; -static const char * const sec_mi2s_groups[] = { - "gpio24", "gpio25", "gpio26", "gpio27", "gpio62", -}; -static const char * const sndwire_clk_groups[] = { - "gpio24", -}; -static const char * const phase_flag17_groups[] = { - "gpio24", -}; -static const char * const vsense_clkout_groups[] = { - "gpio24", -}; -static const char * const sndwire_data_groups[] = { - "gpio25", -}; -static const char * const phase_flag18_groups[] = { - "gpio25", -}; -static const char * const blsp_i2c7_groups[] = { - "gpio26", "gpio27", -}; -static const char * const wsa_en1_groups[] = { - "gpio26", -}; -static const char * const phase_flag19_groups[] = { - "gpio26", +static const char * const blsp_uim6_groups[] = { + "gpio20", "gpio21", }; static const char * const phase_flag11_groups[] = { "gpio21", @@ -721,9 +731,6 @@ static const char * const vsense_data0_groups[] = { static const char * const blsp_i2c6_groups[] = { "gpio22", "gpio23", }; -static const char * const blsp_uim6_groups[] = { - "gpio22", "gpio23", -}; static const char * const phase_flag12_groups[] = { "gpio22", }; @@ -743,15 +750,42 @@ static const char * const BLSP_UART_groups[] = { "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", }; -static const char * const vfr_1_groups[] = { - "gpio27", +static const char * const sec_mi2s_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", "gpio62", +}; +static const char * const sndwire_clk_groups[] = { + "gpio24", +}; +static const char * const phase_flag17_groups[] = { + "gpio24", +}; +static const char * const vsense_clkout_groups[] = { + "gpio24", +}; +static const char * const sndwire_data_groups[] = { + "gpio25", +}; +static const char * const phase_flag18_groups[] = { + "gpio25", +}; +static const char * const WSA_SPKR_groups[] = { + "gpio26", "gpio27", }; -static const char * const wsa_en2_groups[] = { +static const char * const blsp_i2c7_groups[] = { + "gpio26", "gpio27", +}; +static const char * const phase_flag19_groups[] = { + "gpio26", +}; +static const char * const vfr_1_groups[] = { "gpio27", }; static const char * const phase_flag20_groups[] = { "gpio27", }; +static const char * const NFC_INT_groups[] = { + "gpio28", +}; static const char * const blsp_spi_groups[] = { "gpio28", "gpio29", "gpio30", "gpio31", "gpio40", "gpio41", "gpio44", "gpio52", @@ -762,15 +796,24 @@ static const char * const m_voc_groups[] = { static const char * const phase_flag21_groups[] = { "gpio28", }; +static const char * const NFC_EN_groups[] = { + "gpio29", +}; static const char * const phase_flag22_groups[] = { "gpio29", }; +static const char * const NFC_DWL_groups[] = { + "gpio30", +}; static const char * const BLSP_I2C_groups[] = { "gpio30", "gpio31", "gpio44", "gpio52", }; static const char * const phase_flag23_groups[] = { "gpio30", }; +static const char * const NFC_ESE_groups[] = { + "gpio31", +}; static const char * const pwr_modem_groups[] = { "gpio31", }; @@ -778,7 +821,7 @@ static const char * const phase_flag24_groups[] = { "gpio31", }; static const char * const qdss_gpio_groups[] = { - "gpio31", "gpio41", "gpio68", "gpio69", + "gpio31", "gpio52", "gpio68", "gpio69", }; static const char * const cam_mclk_groups[] = { "gpio32", "gpio33", "gpio34", "gpio35", @@ -787,7 +830,7 @@ static const char * const pwr_nav_groups[] = { "gpio32", }; static const char * const qdss_gpio0_groups[] = { - "gpio32", "gpio62", + "gpio32", "gpio67", }; static const char * const qspi_data0_groups[] = { "gpio33", @@ -814,7 +857,46 @@ static const char * const jitter_bist_groups[] = { "gpio35", }; static const char * const qdss_gpio3_groups[] = { - "gpio35", "gpio65", + "gpio35", "gpio56", +}; +static const char * const qdss_gpio7_groups[] = { + "gpio39", "gpio71", +}; +static const char * const FL_R3LED_groups[] = { + "gpio40", +}; +static const char * const CCI_TIMER0_groups[] = { + "gpio40", +}; +static const char * const FL_STROBE_groups[] = { + "gpio41", +}; +static const char * const CCI_TIMER1_groups[] = { + "gpio41", +}; +static const char * const CAM_LDO1_groups[] = { + "gpio42", +}; +static const char * const mdss_vsync0_groups[] = { + "gpio42", +}; +static const char * const mdss_vsync1_groups[] = { + "gpio42", +}; +static const char * const mdss_vsync2_groups[] = { + "gpio42", +}; +static const char * const mdss_vsync3_groups[] = { + "gpio42", +}; +static const char * const qdss_gpio9_groups[] = { + "gpio42", "gpio76", +}; +static const char * const CAM_IRQ_groups[] = { + "gpio43", +}; +static const char * const atest_usb2_groups[] = { + "gpio35", }; static const char * const cci_i2c_groups[] = { "gpio36", "gpio37", "gpio38", "gpio39", @@ -825,14 +907,17 @@ static const char * const pll_bypassnl_groups[] = { static const char * const atest_tsens_groups[] = { "gpio36", }; +static const char * const atest_usb21_groups[] = { + "gpio36", +}; static const char * const pll_reset_groups[] = { "gpio37", }; -static const char * const qdss_gpio9_groups[] = { - "gpio42", "gpio76", +static const char * const atest_usb23_groups[] = { + "gpio37", }; -static const char * const CAM_IRQ_groups[] = { - "gpio43", +static const char * const qdss_gpio6_groups[] = { + "gpio38", "gpio70", }; static const char * const CCI_TIMER3_groups[] = { "gpio43", @@ -846,7 +931,7 @@ static const char * const qspi_cs_groups[] = { static const char * const qdss_gpio10_groups[] = { "gpio43", "gpio77", }; -static const char * const CAM4_STANDBY_groups[] = { +static const char * const CAM3_STANDBY_groups[] = { "gpio44", }; static const char * const CCI_TIMER4_groups[] = { @@ -855,7 +940,7 @@ static const char * const CCI_TIMER4_groups[] = { static const char * const qdss_gpio11_groups[] = { "gpio44", "gpio79", }; -static const char * const bt_reset_groups[] = { +static const char * const CAM_LDO2_groups[] = { "gpio45", }; static const char * const cci_async_groups[] = { @@ -864,49 +949,13 @@ static const char * const cci_async_groups[] = { static const char * const qdss_gpio12_groups[] = { "gpio45", "gpio80", }; -static const char * const CAM1_RST_groups[] = { +static const char * const CAM0_RST_groups[] = { "gpio46", }; -static const char * const qdss_gpio6_groups[] = { - "gpio38", "gpio70", -}; -static const char * const qdss_gpio7_groups[] = { - "gpio39", "gpio71", -}; -static const char * const FL_FRONT_groups[] = { - "gpio40", -}; -static const char * const CCI_TIMER0_groups[] = { - "gpio40", -}; -static const char * const qdss_gpio8_groups[] = { - "gpio40", "gpio75", -}; -static const char * const FL_STROBE_groups[] = { - "gpio41", -}; -static const char * const CCI_TIMER1_groups[] = { - "gpio41", -}; -static const char * const LASER_CE_groups[] = { - "gpio42", -}; -static const char * const mdss_vsync0_groups[] = { - "gpio42", -}; -static const char * const mdss_vsync1_groups[] = { - "gpio42", -}; -static const char * const mdss_vsync2_groups[] = { - "gpio42", -}; -static const char * const mdss_vsync3_groups[] = { - "gpio42", -}; static const char * const qdss_gpio13_groups[] = { "gpio46", "gpio78", }; -static const char * const CAM2_RST_groups[] = { +static const char * const CAM1_RST_groups[] = { "gpio47", }; static const char * const qspi_clk_groups[] = { @@ -918,9 +967,6 @@ static const char * const phase_flag30_groups[] = { static const char * const qdss_gpio14_groups[] = { "gpio47", "gpio72", }; -static const char * const CAM3_RST_groups[] = { - "gpio48", -}; static const char * const qspi_resetn_groups[] = { "gpio48", }; @@ -930,19 +976,19 @@ static const char * const phase_flag1_groups[] = { static const char * const qdss_gpio15_groups[] = { "gpio48", "gpio73", }; -static const char * const CAM1_STANDBY_groups[] = { +static const char * const CAM0_STANDBY_groups[] = { "gpio49", }; static const char * const phase_flag2_groups[] = { "gpio49", }; -static const char * const CAM2_STANDBY_groups[] = { +static const char * const CAM1_STANDBY_groups[] = { "gpio50", }; static const char * const phase_flag9_groups[] = { "gpio50", }; -static const char * const CAM3_STANDBY_groups[] = { +static const char * const CAM2_STANDBY_groups[] = { "gpio51", }; static const char * const qspi_data3_groups[] = { @@ -951,7 +997,10 @@ static const char * const qspi_data3_groups[] = { static const char * const phase_flag15_groups[] = { "gpio51", }; -static const char * const CAM4_RST_groups[] = { +static const char * const qdss_gpio8_groups[] = { + "gpio51", "gpio75", +}; +static const char * const CAM3_RST_groups[] = { "gpio52", }; static const char * const CCI_TIMER2_groups[] = { @@ -960,32 +1009,41 @@ static const char * const CCI_TIMER2_groups[] = { static const char * const phase_flag16_groups[] = { "gpio52", }; +static const char * const LCD0_RESET_groups[] = { + "gpio53", +}; static const char * const phase_flag6_groups[] = { "gpio53", }; -static const char * const RCM_MARKER2_groups[] = { +static const char * const SD_CARD_groups[] = { "gpio54", }; static const char * const phase_flag29_groups[] = { "gpio54", }; -static const char * const SS_SWITCH_groups[] = { - "gpio55", "gpio56", +static const char * const DP_EN_groups[] = { + "gpio55", }; static const char * const phase_flag25_groups[] = { "gpio55", }; +static const char * const USBC_ORIENTATION_groups[] = { + "gpio56", +}; static const char * const phase_flag10_groups[] = { "gpio56", }; +static const char * const atest_usb20_groups[] = { + "gpio56", +}; static const char * const gcc_gp1_groups[] = { "gpio57", "gpio78", }; static const char * const phase_flag4_groups[] = { "gpio57", }; -static const char * const USB_DIR_groups[] = { - "gpio58", +static const char * const atest_usb22_groups[] = { + "gpio57", }; static const char * const USB_PHY_groups[] = { "gpio58", @@ -1005,11 +1063,8 @@ static const char * const gcc_gp3_groups[] = { static const char * const atest_char3_groups[] = { "gpio59", }; -static const char * const Lcd_mode_groups[] = { - "gpio60", -}; -static const char * const EDP_HOT_groups[] = { - "gpio60", +static const char * const FORCE_TOUCH_groups[] = { + "gpio60", "gpio73", }; static const char * const cri_trng0_groups[] = { "gpio60", @@ -1023,6 +1078,9 @@ static const char * const cri_trng1_groups[] = { static const char * const atest_char1_groups[] = { "gpio61", }; +static const char * const AUDIO_USBC_groups[] = { + "gpio62", +}; static const char * const audio_ref_groups[] = { "gpio62", }; @@ -1038,20 +1096,20 @@ static const char * const atest_char0_groups[] = { static const char * const US_EURO_groups[] = { "gpio63", }; -static const char * const KEY_FOCUS_groups[] = { +static const char * const LCD_BACKLIGHT_groups[] = { "gpio64", }; -static const char * const NAV_PPS_groups[] = { - "gpio64", "gpio65", "gpio98", "gpio98", -}; static const char * const blsp_spi8_groups[] = { "gpio64", "gpio76", }; static const char * const sp_cmu_groups[] = { "gpio64", }; -static const char * const SLT_PWR_groups[] = { - "gpio65", +static const char * const NAV_PPS_groups[] = { + "gpio65", "gpio65", "gpio80", "gpio80", "gpio98", "gpio98", +}; +static const char * const GPS_TX_groups[] = { + "gpio65", "gpio80", "gpio98", }; static const char * const adsp_ext_groups[] = { "gpio65", @@ -1059,12 +1117,9 @@ static const char * const adsp_ext_groups[] = { static const char * const TS_RESET_groups[] = { "gpio66", }; -static const char * const TS_INT_groups[] = { - "gpio67", -}; static const char * const ssc_irq_groups[] = { - "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74", - "gpio75", "gpio76", "gpio77", + "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio74", + "gpio75", "gpio76", }; static const char * const isense_dbg_groups[] = { "gpio68", @@ -1084,12 +1139,18 @@ static const char * const tsense_pwm1_groups[] = { static const char * const tsense_pwm2_groups[] = { "gpio71", }; -static const char * const HAPTICS_PWM_groups[] = { +static const char * const SENSOR_RST_groups[] = { + "gpio77", +}; +static const char * const WMSS_RESETN_groups[] = { "gpio78", }; -static const char * const wmss_reset_groups[] = { +static const char * const HAPTICS_PWM_groups[] = { "gpio79", }; +static const char * const GPS_eLNA_groups[] = { + "gpio80", +}; static const char * const mss_lte_groups[] = { "gpio81", "gpio82", }; @@ -1123,9 +1184,6 @@ static const char * const uim_batt_groups[] = { static const char * const pa_indicator_groups[] = { "gpio92", }; -static const char * const ssbi_gnss_groups[] = { - "gpio94", -}; static const char * const ldo_en_groups[] = { "gpio97", }; @@ -1141,84 +1199,93 @@ static const char * const qlink_enable_groups[] = { static const char * const prng_rosc_groups[] = { "gpio102", }; +static const char * const LCD_PWR_groups[] = { + "gpio113", +}; static const struct msm_function msmfalcon_functions[] = { FUNCTION(blsp_spi1), FUNCTION(gpio), + FUNCTION(blsp_uim1), FUNCTION(tgu_ch0), - FUNCTION(tgu_ch1), + FUNCTION(qdss_gpio4), + FUNCTION(atest_gpsadc1), FUNCTION(blsp_uart1), + FUNCTION(SMB_STAT), + FUNCTION(phase_flag14), + FUNCTION(blsp_i2c2), + FUNCTION(phase_flag31), FUNCTION(blsp_spi3), FUNCTION(wlan1_adc1), FUNCTION(atest_usb13), - FUNCTION(bimc_dte1), - FUNCTION(wlan1_adc0), - FUNCTION(atest_usb12), - FUNCTION(bimc_dte0), + FUNCTION(tgu_ch1), + FUNCTION(qdss_gpio5), + FUNCTION(atest_gpsadc0), FUNCTION(blsp_i2c1), - FUNCTION(blsp_uim1), FUNCTION(ddr_bist), FUNCTION(atest_tsens2), FUNCTION(atest_usb1), FUNCTION(blsp_spi2), - FUNCTION(phase_flag3), - FUNCTION(phase_flag14), - FUNCTION(blsp_i2c2), FUNCTION(blsp_uim2), - FUNCTION(phase_flag31), + FUNCTION(phase_flag3), + FUNCTION(bimc_dte1), + FUNCTION(wlan1_adc0), + FUNCTION(atest_usb12), + FUNCTION(bimc_dte0), FUNCTION(blsp_i2c3), - FUNCTION(atest_gpsadc1), FUNCTION(wlan2_adc1), FUNCTION(atest_usb11), FUNCTION(dbg_out), - FUNCTION(atest_gpsadc0), FUNCTION(wlan2_adc0), FUNCTION(atest_usb10), + FUNCTION(RCM_MARKER), FUNCTION(blsp_spi4), FUNCTION(pri_mi2s), FUNCTION(phase_flag26), - FUNCTION(qdss_gpio4), + FUNCTION(qdss_cti), + FUNCTION(DP_HOT), FUNCTION(pri_mi2s_ws), FUNCTION(phase_flag27), - FUNCTION(qdss_gpio5), FUNCTION(blsp_i2c4), FUNCTION(phase_flag28), FUNCTION(blsp_uart5), FUNCTION(blsp_spi5), + FUNCTION(blsp_uim5), FUNCTION(phase_flag5), FUNCTION(blsp_i2c5), - FUNCTION(blsp_uim5), FUNCTION(blsp_spi6), FUNCTION(blsp_uart2), - FUNCTION(qdss_cti), - FUNCTION(sec_mi2s), - FUNCTION(sndwire_clk), - FUNCTION(phase_flag17), - FUNCTION(vsense_clkout), - FUNCTION(sndwire_data), - FUNCTION(phase_flag18), - FUNCTION(blsp_i2c7), - FUNCTION(wsa_en1), - FUNCTION(phase_flag19), + FUNCTION(blsp_uim6), FUNCTION(phase_flag11), FUNCTION(vsense_data0), FUNCTION(blsp_i2c6), - FUNCTION(blsp_uim6), FUNCTION(phase_flag12), FUNCTION(vsense_data1), FUNCTION(phase_flag13), FUNCTION(vsense_mode), FUNCTION(blsp_spi7), FUNCTION(BLSP_UART), + FUNCTION(sec_mi2s), + FUNCTION(sndwire_clk), + FUNCTION(phase_flag17), + FUNCTION(vsense_clkout), + FUNCTION(sndwire_data), + FUNCTION(phase_flag18), + FUNCTION(WSA_SPKR), + FUNCTION(blsp_i2c7), + FUNCTION(phase_flag19), FUNCTION(vfr_1), - FUNCTION(wsa_en2), FUNCTION(phase_flag20), + FUNCTION(NFC_INT), FUNCTION(blsp_spi), FUNCTION(m_voc), FUNCTION(phase_flag21), + FUNCTION(NFC_EN), FUNCTION(phase_flag22), + FUNCTION(NFC_DWL), FUNCTION(BLSP_I2C), FUNCTION(phase_flag23), + FUNCTION(NFC_ESE), FUNCTION(pwr_modem), FUNCTION(phase_flag24), FUNCTION(qdss_gpio), @@ -1234,88 +1301,92 @@ static const struct msm_function msmfalcon_functions[] = { FUNCTION(qspi_data2), FUNCTION(jitter_bist), FUNCTION(qdss_gpio3), + FUNCTION(qdss_gpio7), + FUNCTION(FL_R3LED), + FUNCTION(CCI_TIMER0), + FUNCTION(FL_STROBE), + FUNCTION(CCI_TIMER1), + FUNCTION(CAM_LDO1), + FUNCTION(mdss_vsync0), + FUNCTION(mdss_vsync1), + FUNCTION(mdss_vsync2), + FUNCTION(mdss_vsync3), + FUNCTION(qdss_gpio9), + FUNCTION(CAM_IRQ), + FUNCTION(atest_usb2), FUNCTION(cci_i2c), FUNCTION(pll_bypassnl), FUNCTION(atest_tsens), + FUNCTION(atest_usb21), FUNCTION(pll_reset), - FUNCTION(qdss_gpio9), - FUNCTION(CAM_IRQ), + FUNCTION(atest_usb23), + FUNCTION(qdss_gpio6), FUNCTION(CCI_TIMER3), FUNCTION(CCI_ASYNC), FUNCTION(qspi_cs), FUNCTION(qdss_gpio10), - FUNCTION(CAM4_STANDBY), + FUNCTION(CAM3_STANDBY), FUNCTION(CCI_TIMER4), FUNCTION(qdss_gpio11), - FUNCTION(bt_reset), + FUNCTION(CAM_LDO2), FUNCTION(cci_async), FUNCTION(qdss_gpio12), - FUNCTION(CAM1_RST), - FUNCTION(qdss_gpio6), - FUNCTION(qdss_gpio7), - FUNCTION(FL_FRONT), - FUNCTION(CCI_TIMER0), - FUNCTION(qdss_gpio8), - FUNCTION(FL_STROBE), - FUNCTION(CCI_TIMER1), - FUNCTION(LASER_CE), - FUNCTION(mdss_vsync0), - FUNCTION(mdss_vsync1), - FUNCTION(mdss_vsync2), - FUNCTION(mdss_vsync3), + FUNCTION(CAM0_RST), FUNCTION(qdss_gpio13), - FUNCTION(CAM2_RST), + FUNCTION(CAM1_RST), FUNCTION(qspi_clk), FUNCTION(phase_flag30), FUNCTION(qdss_gpio14), - FUNCTION(CAM3_RST), FUNCTION(qspi_resetn), FUNCTION(phase_flag1), FUNCTION(qdss_gpio15), - FUNCTION(CAM1_STANDBY), + FUNCTION(CAM0_STANDBY), FUNCTION(phase_flag2), - FUNCTION(CAM2_STANDBY), + FUNCTION(CAM1_STANDBY), FUNCTION(phase_flag9), - FUNCTION(CAM3_STANDBY), + FUNCTION(CAM2_STANDBY), FUNCTION(qspi_data3), FUNCTION(phase_flag15), - FUNCTION(CAM4_RST), + FUNCTION(qdss_gpio8), + FUNCTION(CAM3_RST), FUNCTION(CCI_TIMER2), FUNCTION(phase_flag16), + FUNCTION(LCD0_RESET), FUNCTION(phase_flag6), - FUNCTION(RCM_MARKER2), + FUNCTION(SD_CARD), FUNCTION(phase_flag29), - FUNCTION(SS_SWITCH), + FUNCTION(DP_EN), FUNCTION(phase_flag25), + FUNCTION(USBC_ORIENTATION), FUNCTION(phase_flag10), + FUNCTION(atest_usb20), FUNCTION(gcc_gp1), FUNCTION(phase_flag4), - FUNCTION(USB_DIR), + FUNCTION(atest_usb22), FUNCTION(USB_PHY), FUNCTION(gcc_gp2), FUNCTION(atest_char), FUNCTION(mdp_vsync), FUNCTION(gcc_gp3), FUNCTION(atest_char3), - FUNCTION(Lcd_mode), - FUNCTION(EDP_HOT), + FUNCTION(FORCE_TOUCH), FUNCTION(cri_trng0), FUNCTION(atest_char2), FUNCTION(cri_trng1), FUNCTION(atest_char1), + FUNCTION(AUDIO_USBC), FUNCTION(audio_ref), FUNCTION(MDP_VSYNC), FUNCTION(cri_trng), FUNCTION(atest_char0), FUNCTION(US_EURO), - FUNCTION(KEY_FOCUS), - FUNCTION(NAV_PPS), + FUNCTION(LCD_BACKLIGHT), FUNCTION(blsp_spi8), FUNCTION(sp_cmu), - FUNCTION(SLT_PWR), + FUNCTION(NAV_PPS), + FUNCTION(GPS_TX), FUNCTION(adsp_ext), FUNCTION(TS_RESET), - FUNCTION(TS_INT), FUNCTION(ssc_irq), FUNCTION(isense_dbg), FUNCTION(phase_flag0), @@ -1323,8 +1394,10 @@ static const struct msm_function msmfalcon_functions[] = { FUNCTION(phase_flag8), FUNCTION(tsense_pwm1), FUNCTION(tsense_pwm2), + FUNCTION(SENSOR_RST), + FUNCTION(WMSS_RESETN), FUNCTION(HAPTICS_PWM), - FUNCTION(wmss_reset), + FUNCTION(GPS_eLNA), FUNCTION(mss_lte), FUNCTION(uim2_data), FUNCTION(uim2_clk), @@ -1336,153 +1409,155 @@ static const struct msm_function msmfalcon_functions[] = { FUNCTION(uim1_present), FUNCTION(uim_batt), FUNCTION(pa_indicator), - FUNCTION(ssbi_gnss), FUNCTION(ldo_en), FUNCTION(ldo_update), FUNCTION(qlink_request), FUNCTION(qlink_enable), FUNCTION(prng_rosc), + FUNCTION(LCD_PWR), }; static const struct msm_pingroup msmfalcon_groups[] = { - PINGROUP(0, SOUTH, blsp_spi1, blsp_uart1, tgu_ch0, NA, NA, NA, NA, NA, - NA), - PINGROUP(1, SOUTH, blsp_spi1, blsp_uart1, tgu_ch1, NA, NA, NA, NA, NA, - NA), - PINGROUP(2, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, blsp_uim1, NA, NA, - NA, NA, NA), - PINGROUP(3, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, blsp_uim1, - ddr_bist, NA, atest_tsens2, atest_usb1, NA), - PINGROUP(4, WEST, blsp_spi2, phase_flag3, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(5, WEST, blsp_spi2, phase_flag14, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(6, WEST, blsp_spi2, blsp_i2c2, blsp_uim2, phase_flag31, NA, - NA, NA, NA, NA), - PINGROUP(7, WEST, blsp_spi2, blsp_i2c2, blsp_uim2, NA, NA, NA, NA, NA, - NA), - PINGROUP(8, WEST, blsp_spi3, ddr_bist, NA, NA, wlan1_adc1, atest_usb13, - bimc_dte1, NA, NA), - PINGROUP(9, WEST, blsp_spi3, ddr_bist, NA, NA, wlan1_adc0, atest_usb12, - bimc_dte0, NA, NA), - PINGROUP(10, WEST, blsp_spi3, blsp_i2c3, ddr_bist, NA, atest_gpsadc1, - wlan2_adc1, atest_usb11, bimc_dte1, NA), - PINGROUP(11, WEST, blsp_spi3, blsp_i2c3, dbg_out, atest_gpsadc0, - wlan2_adc0, atest_usb10, bimc_dte0, NA, NA), - PINGROUP(12, SOUTH, blsp_spi4, pri_mi2s, phase_flag26, qdss_gpio4, NA, + PINGROUP(0, SOUTH, blsp_spi1, blsp_uart1, blsp_uim1, tgu_ch0, NA, NA, + qdss_gpio4, atest_gpsadc1, NA), + PINGROUP(1, SOUTH, blsp_spi1, blsp_uart1, blsp_uim1, tgu_ch1, NA, NA, + qdss_gpio5, atest_gpsadc0, NA), + PINGROUP(2, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, + NA, NA), + PINGROUP(3, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, ddr_bist, NA, NA, + atest_tsens2, atest_usb1, NA), + PINGROUP(4, NORTH, blsp_spi2, blsp_uim2, NA, phase_flag3, NA, NA, NA, + NA, NA), + PINGROUP(5, SOUTH, blsp_spi2, blsp_uim2, NA, phase_flag14, NA, NA, NA, + NA, NA), + PINGROUP(6, SOUTH, blsp_spi2, blsp_i2c2, NA, phase_flag31, NA, NA, NA, + NA, NA), + PINGROUP(7, SOUTH, blsp_spi2, blsp_i2c2, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(8, NORTH, blsp_spi3, ddr_bist, NA, NA, NA, wlan1_adc1, + atest_usb13, bimc_dte1, NA), + PINGROUP(9, NORTH, blsp_spi3, ddr_bist, NA, NA, NA, wlan1_adc0, + atest_usb12, bimc_dte0, NA), + PINGROUP(10, NORTH, blsp_spi3, blsp_i2c3, ddr_bist, NA, NA, wlan2_adc1, + atest_usb11, bimc_dte1, NA), + PINGROUP(11, NORTH, blsp_spi3, blsp_i2c3, NA, dbg_out, wlan2_adc0, + atest_usb10, bimc_dte0, NA, NA), + PINGROUP(12, NORTH, blsp_spi4, pri_mi2s, NA, phase_flag26, qdss_cti, NA, NA, NA, NA), - PINGROUP(13, SOUTH, blsp_spi4, pri_mi2s_ws, NA, phase_flag27, - qdss_gpio5, NA, NA, NA, NA), - PINGROUP(14, SOUTH, blsp_spi4, blsp_i2c4, pri_mi2s, phase_flag28, NA, + PINGROUP(13, NORTH, blsp_spi4, DP_HOT, pri_mi2s_ws, NA, NA, + phase_flag27, qdss_cti, NA, NA), + PINGROUP(14, NORTH, blsp_spi4, blsp_i2c4, pri_mi2s, NA, phase_flag28, NA, NA, NA, NA), - PINGROUP(15, SOUTH, blsp_spi4, blsp_i2c4, pri_mi2s, NA, NA, NA, NA, NA, + PINGROUP(15, NORTH, blsp_spi4, blsp_i2c4, pri_mi2s, NA, NA, NA, NA, NA, NA), - PINGROUP(16, WEST, blsp_uart5, blsp_spi5, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(17, WEST, blsp_uart5, blsp_spi5, phase_flag5, NA, NA, NA, NA, + PINGROUP(16, CENTER, blsp_uart5, blsp_spi5, blsp_uim5, NA, NA, NA, NA, NA, NA), - PINGROUP(18, WEST, blsp_uart5, blsp_spi5, blsp_i2c5, blsp_uim5, NA, NA, - NA, NA, NA), - PINGROUP(19, WEST, blsp_uart5, blsp_spi5, blsp_i2c5, blsp_uim5, NA, NA, - NA, NA, NA), - PINGROUP(20, WEST, blsp_spi6, blsp_uart2, NA, qdss_cti, NA, NA, NA, NA, - NA), - PINGROUP(21, WEST, blsp_spi6, blsp_uart2, phase_flag11, qdss_cti, - vsense_data0, NA, NA, NA, NA), - PINGROUP(22, WEST, blsp_spi6, blsp_uart2, blsp_i2c6, blsp_uim6, + PINGROUP(17, CENTER, blsp_uart5, blsp_spi5, blsp_uim5, NA, phase_flag5, + NA, NA, NA, NA), + PINGROUP(18, CENTER, blsp_uart5, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, + NA, NA), + PINGROUP(19, CENTER, blsp_uart5, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, + NA, NA), + PINGROUP(20, SOUTH, blsp_spi6, blsp_uart2, blsp_uim6, NA, NA, NA, NA, + NA, NA), + PINGROUP(21, SOUTH, blsp_spi6, blsp_uart2, blsp_uim6, NA, phase_flag11, + qdss_cti, vsense_data0, NA, NA), + PINGROUP(22, CENTER, blsp_spi6, blsp_uart2, blsp_i2c6, NA, phase_flag12, vsense_data1, NA, NA, NA), - PINGROUP(23, WEST, blsp_spi6, blsp_uart2, blsp_i2c6, blsp_uim6, + PINGROUP(23, CENTER, blsp_spi6, blsp_uart2, blsp_i2c6, NA, phase_flag13, vsense_mode, NA, NA, NA), - PINGROUP(24, WEST, blsp_spi7, BLSP_UART, sec_mi2s, sndwire_clk, NA, - phase_flag17, qdss_cti, vsense_clkout, NA), - PINGROUP(25, WEST, blsp_spi7, BLSP_UART, sec_mi2s, sndwire_data, NA, - phase_flag18, qdss_cti, NA, NA), - PINGROUP(26, WEST, blsp_spi7, BLSP_UART, blsp_i2c7, sec_mi2s, wsa_en1, - phase_flag19, qdss_cti, NA, NA), - PINGROUP(27, WEST, blsp_spi7, BLSP_UART, blsp_i2c7, vfr_1, sec_mi2s, - wsa_en2, phase_flag20, NA, NA), - PINGROUP(28, SOUTH, blsp_spi, BLSP_UART, m_voc, phase_flag21, NA, NA, + PINGROUP(24, NORTH, blsp_spi7, BLSP_UART, sec_mi2s, sndwire_clk, NA, + NA, phase_flag17, vsense_clkout, NA), + PINGROUP(25, NORTH, blsp_spi7, BLSP_UART, sec_mi2s, sndwire_data, NA, + NA, phase_flag18, NA, NA), + PINGROUP(26, NORTH, blsp_spi7, BLSP_UART, blsp_i2c7, sec_mi2s, NA, + phase_flag19, NA, NA, NA), + PINGROUP(27, NORTH, blsp_spi7, BLSP_UART, blsp_i2c7, vfr_1, sec_mi2s, + NA, phase_flag20, NA, NA), + PINGROUP(28, CENTER, blsp_spi, BLSP_UART, m_voc, NA, phase_flag21, NA, NA, NA, NA), - PINGROUP(29, SOUTH, blsp_spi, BLSP_UART, NA, phase_flag22, NA, NA, NA, + PINGROUP(29, CENTER, blsp_spi, BLSP_UART, NA, NA, phase_flag22, NA, NA, NA, NA), - PINGROUP(30, SOUTH, blsp_spi, BLSP_UART, BLSP_I2C, blsp_spi3, - phase_flag23, NA, NA, NA, NA), - PINGROUP(31, SOUTH, blsp_spi, BLSP_UART, BLSP_I2C, pwr_modem, - phase_flag24, qdss_gpio, NA, NA, NA), - PINGROUP(32, SOUTH, cam_mclk, pwr_nav, NA, qdss_gpio0, NA, NA, NA, NA, + PINGROUP(30, CENTER, blsp_spi, BLSP_UART, BLSP_I2C, blsp_spi3, NA, + phase_flag23, NA, NA, NA), + PINGROUP(31, CENTER, blsp_spi, BLSP_UART, BLSP_I2C, pwr_modem, NA, + phase_flag24, qdss_gpio, NA, NA), + PINGROUP(32, SOUTH, cam_mclk, pwr_nav, NA, NA, qdss_gpio0, NA, NA, NA, NA), - PINGROUP(33, SOUTH, cam_mclk, qspi_data0, pwr_crypto, NA, qdss_gpio1, - NA, NA, NA, NA), - PINGROUP(34, SOUTH, cam_mclk, qspi_data1, agera_pll, NA, qdss_gpio2, - NA, NA, NA, NA), - PINGROUP(35, SOUTH, cam_mclk, qspi_data2, jitter_bist, NA, qdss_gpio3, - NA, NA, NA, NA), - PINGROUP(36, SOUTH, cci_i2c, pll_bypassnl, agera_pll, NA, qdss_gpio4, - atest_tsens, NA, NA, NA), - PINGROUP(37, SOUTH, cci_i2c, pll_reset, NA, qdss_gpio5, NA, NA, NA, NA, - NA), - PINGROUP(38, SOUTH, cci_i2c, NA, qdss_gpio6, NA, NA, NA, NA, NA, NA), - PINGROUP(39, SOUTH, cci_i2c, NA, qdss_gpio7, NA, NA, NA, NA, NA, NA), - PINGROUP(40, SOUTH, CCI_TIMER0, NA, blsp_spi, NA, qdss_gpio8, NA, NA, - NA, NA), - PINGROUP(41, SOUTH, CCI_TIMER1, NA, blsp_spi, NA, qdss_gpio, NA, NA, - NA, NA), + PINGROUP(33, SOUTH, cam_mclk, qspi_data0, pwr_crypto, NA, NA, + qdss_gpio1, NA, NA, NA), + PINGROUP(34, SOUTH, cam_mclk, qspi_data1, agera_pll, NA, NA, + qdss_gpio2, NA, NA, NA), + PINGROUP(35, SOUTH, cam_mclk, qspi_data2, jitter_bist, NA, NA, + qdss_gpio3, NA, atest_usb2, NA), + PINGROUP(36, SOUTH, cci_i2c, pll_bypassnl, agera_pll, NA, NA, + qdss_gpio4, atest_tsens, atest_usb21, NA), + PINGROUP(37, SOUTH, cci_i2c, pll_reset, NA, NA, qdss_gpio5, + atest_usb23, NA, NA, NA), + PINGROUP(38, SOUTH, cci_i2c, NA, NA, qdss_gpio6, NA, NA, NA, NA, NA), + PINGROUP(39, SOUTH, cci_i2c, NA, NA, qdss_gpio7, NA, NA, NA, NA, NA), + PINGROUP(40, SOUTH, CCI_TIMER0, NA, blsp_spi, NA, NA, NA, NA, NA, NA), + PINGROUP(41, SOUTH, CCI_TIMER1, NA, blsp_spi, NA, NA, NA, NA, NA, NA), PINGROUP(42, SOUTH, mdss_vsync0, mdss_vsync1, mdss_vsync2, mdss_vsync3, - NA, qdss_gpio9, NA, NA, NA), - PINGROUP(43, SOUTH, CCI_TIMER3, CCI_ASYNC, qspi_cs, NA, qdss_gpio10, - NA, NA, NA, NA), - PINGROUP(44, SOUTH, CCI_TIMER4, CCI_ASYNC, blsp_spi, BLSP_I2C, NA, - qdss_gpio11, NA, NA, NA), - PINGROUP(45, SOUTH, cci_async, NA, qdss_gpio12, NA, NA, NA, NA, NA, NA), - PINGROUP(46, SOUTH, blsp_spi1, NA, qdss_gpio13, NA, NA, NA, NA, NA, NA), - PINGROUP(47, SOUTH, qspi_clk, phase_flag30, qdss_gpio14, NA, NA, NA, - NA, NA, NA), - PINGROUP(48, SOUTH, qspi_resetn, phase_flag1, qdss_gpio15, NA, NA, NA, + NA, NA, qdss_gpio9, NA, NA), + PINGROUP(43, SOUTH, CCI_TIMER3, CCI_ASYNC, qspi_cs, NA, NA, + qdss_gpio10, NA, NA, NA), + PINGROUP(44, SOUTH, CCI_TIMER4, CCI_ASYNC, blsp_spi, BLSP_I2C, NA, NA, + qdss_gpio11, NA, NA), + PINGROUP(45, SOUTH, cci_async, NA, NA, qdss_gpio12, NA, NA, NA, NA, NA), + PINGROUP(46, SOUTH, blsp_spi1, NA, NA, qdss_gpio13, NA, NA, NA, NA, NA), + PINGROUP(47, SOUTH, qspi_clk, NA, phase_flag30, qdss_gpio14, NA, NA, NA, NA, NA), - PINGROUP(49, SOUTH, phase_flag2, qdss_cti, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(50, SOUTH, qspi_cs, phase_flag9, qdss_cti, NA, NA, NA, NA, NA, + PINGROUP(48, SOUTH, NA, phase_flag1, qdss_gpio15, NA, NA, NA, NA, NA, NA), - PINGROUP(51, SOUTH, qspi_data3, phase_flag15, NA, NA, NA, NA, NA, NA, - NA), - PINGROUP(52, EAST, CCI_TIMER2, blsp_spi, BLSP_I2C, phase_flag16, NA, - NA, NA, NA, NA), - PINGROUP(53, EAST, phase_flag6, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(54, EAST, NA, phase_flag29, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(55, WEST, phase_flag25, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(56, WEST, phase_flag10, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(57, SOUTH, gcc_gp1, phase_flag4, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(58, SOUTH, USB_PHY, gcc_gp2, NA, atest_char, NA, NA, NA, NA, + PINGROUP(49, SOUTH, NA, phase_flag2, qdss_cti, NA, NA, NA, NA, NA, NA), + PINGROUP(50, SOUTH, qspi_cs, NA, phase_flag9, qdss_cti, NA, NA, NA, NA, NA), - PINGROUP(59, EAST, mdp_vsync, gcc_gp3, NA, atest_char3, NA, NA, NA, NA, - NA), - PINGROUP(60, EAST, EDP_HOT, cri_trng0, NA, atest_char2, NA, NA, NA, NA, - NA), - PINGROUP(61, EAST, pri_mi2s, cri_trng1, NA, qdss_cti, atest_char1, NA, + PINGROUP(51, SOUTH, qspi_data3, NA, phase_flag15, qdss_gpio8, NA, NA, + NA, NA, NA), + PINGROUP(52, SOUTH, CCI_TIMER2, blsp_spi, BLSP_I2C, NA, phase_flag16, + qdss_gpio, NA, NA, NA), + PINGROUP(53, NORTH, NA, phase_flag6, qdss_cti, NA, NA, NA, NA, NA, NA), + PINGROUP(54, NORTH, NA, NA, phase_flag29, NA, NA, NA, NA, NA, NA), + PINGROUP(55, SOUTH, NA, phase_flag25, qdss_cti, NA, NA, NA, NA, NA, NA), + PINGROUP(56, SOUTH, NA, phase_flag10, qdss_gpio3, NA, atest_usb20, NA, NA, NA, NA), - PINGROUP(62, SOUTH, sec_mi2s, audio_ref, MDP_VSYNC, cri_trng, NA, - qdss_gpio0, atest_char0, NA, NA), - PINGROUP(63, SOUTH, NA, NA, qdss_gpio1, NA, NA, NA, NA, NA, NA), - PINGROUP(64, SOUTH, NAV_PPS, blsp_spi8, sp_cmu, NA, qdss_gpio2, NA, NA, + PINGROUP(57, SOUTH, gcc_gp1, NA, phase_flag4, atest_usb22, NA, NA, NA, NA, NA), - PINGROUP(65, SOUTH, NAV_PPS, blsp_spi3, NA, adsp_ext, NA, qdss_gpio3, + PINGROUP(58, SOUTH, USB_PHY, gcc_gp2, NA, NA, atest_char, NA, NA, NA, + NA), + PINGROUP(59, NORTH, mdp_vsync, gcc_gp3, NA, NA, atest_char3, NA, NA, + NA, NA), + PINGROUP(60, NORTH, cri_trng0, NA, NA, atest_char2, NA, NA, NA, NA, NA), + PINGROUP(61, NORTH, pri_mi2s, cri_trng1, NA, NA, atest_char1, NA, NA, + NA, NA), + PINGROUP(62, NORTH, sec_mi2s, audio_ref, MDP_VSYNC, cri_trng, NA, NA, + atest_char0, NA, NA), + PINGROUP(63, NORTH, NA, NA, NA, qdss_gpio1, NA, NA, NA, NA, NA), + PINGROUP(64, SOUTH, blsp_spi8, sp_cmu, NA, NA, qdss_gpio2, NA, NA, NA, + NA), + PINGROUP(65, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, blsp_spi3, adsp_ext, NA, NA, NA), - PINGROUP(66, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(67, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(68, SOUTH, isense_dbg, phase_flag0, qdss_gpio, NA, NA, NA, NA, + PINGROUP(66, NORTH, NA, NA, qdss_cti, NA, NA, NA, NA, NA, NA), + PINGROUP(67, NORTH, NA, NA, qdss_gpio0, NA, NA, NA, NA, NA, NA), + PINGROUP(68, NORTH, isense_dbg, NA, phase_flag0, qdss_gpio, NA, NA, NA, NA, NA), - PINGROUP(69, SOUTH, phase_flag7, qdss_gpio, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(70, SOUTH, phase_flag8, qdss_gpio6, NA, NA, NA, NA, NA, NA, + PINGROUP(69, NORTH, NA, phase_flag7, qdss_gpio, NA, NA, NA, NA, NA, NA), + PINGROUP(70, NORTH, NA, phase_flag8, qdss_gpio6, NA, NA, NA, NA, NA, NA), - PINGROUP(71, SOUTH, NA, qdss_gpio7, tsense_pwm1, tsense_pwm2, NA, NA, + PINGROUP(71, NORTH, NA, NA, qdss_gpio7, tsense_pwm1, tsense_pwm2, NA, NA, NA, NA), - PINGROUP(72, SOUTH, qdss_gpio14, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(73, SOUTH, NA, qdss_gpio15, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(74, SOUTH, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(75, WEST, NA, qdss_gpio8, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(76, WEST, blsp_spi8, NA, NA, qdss_gpio9, NA, NA, NA, NA, NA), - PINGROUP(77, SOUTH, NA, qdss_gpio10, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(78, SOUTH, gcc_gp1, qdss_gpio13, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(79, SOUTH, NA, qdss_gpio11, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(80, SOUTH, NA, qdss_gpio12, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(81, SOUTH, mss_lte, gcc_gp2, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(82, SOUTH, mss_lte, NA, gcc_gp3, NA, NA, NA, NA, NA, NA), + PINGROUP(72, NORTH, NA, qdss_gpio14, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(73, NORTH, NA, NA, qdss_gpio15, NA, NA, NA, NA, NA, NA), + PINGROUP(74, NORTH, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(75, NORTH, NA, NA, qdss_gpio8, NA, NA, NA, NA, NA, NA), + PINGROUP(76, NORTH, blsp_spi8, NA, NA, NA, qdss_gpio9, NA, NA, NA, NA), + PINGROUP(77, NORTH, NA, NA, qdss_gpio10, NA, NA, NA, NA, NA, NA), + PINGROUP(78, NORTH, gcc_gp1, NA, qdss_gpio13, NA, NA, NA, NA, NA, NA), + PINGROUP(79, SOUTH, NA, NA, qdss_gpio11, NA, NA, NA, NA, NA, NA), + PINGROUP(80, SOUTH, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, qdss_gpio12, NA, + NA, NA), + PINGROUP(81, CENTER, mss_lte, gcc_gp2, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(82, CENTER, mss_lte, gcc_gp3, NA, NA, NA, NA, NA, NA, NA), PINGROUP(83, SOUTH, uim2_data, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(84, SOUTH, uim2_clk, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(85, SOUTH, uim2_reset, NA, NA, NA, NA, NA, NA, NA, NA), @@ -1494,12 +1569,12 @@ static const struct msm_pingroup msmfalcon_groups[] = { PINGROUP(91, SOUTH, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(92, SOUTH, NA, NA, pa_indicator, NA, NA, NA, NA, NA, NA), PINGROUP(93, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(94, SOUTH, NA, ssbi_gnss, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(94, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(95, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(96, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(97, SOUTH, NA, NA, ldo_en, NA, NA, NA, NA, NA, NA), - PINGROUP(98, SOUTH, NA, NAV_PPS, NAV_PPS, ldo_update, NA, NA, NA, NA, - NA), + PINGROUP(97, SOUTH, NA, ldo_en, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(98, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, ldo_update, NA, NA, + NA, NA), PINGROUP(99, SOUTH, qlink_request, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(100, SOUTH, qlink_enable, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(101, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), @@ -1508,13 +1583,20 @@ static const struct msm_pingroup msmfalcon_groups[] = { PINGROUP(104, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(105, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), PINGROUP(106, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(107, EAST, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(108, EAST, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(109, EAST, NA, NA, NA, NA, NA, NA, NA, NA, NA), - PINGROUP(110, EAST, NA, NA, NA, NA, NA, NA, NA, NA, NA), - SDC_QDSD_PINGROUP(sdc2_clk, 0x999000, 14, 6), - SDC_QDSD_PINGROUP(sdc2_cmd, 0x999000, 11, 3), - SDC_QDSD_PINGROUP(sdc2_data, 0x999000, 9, 0), + PINGROUP(107, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(108, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(109, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(110, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(111, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(112, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + PINGROUP(113, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + SDC_QDSD_PINGROUP(sdc1_clk, 0x99a000, 13, 6), + SDC_QDSD_PINGROUP(sdc1_cmd, 0x99a000, 11, 3), + SDC_QDSD_PINGROUP(sdc1_data, 0x99a000, 9, 0), + SDC_QDSD_PINGROUP(sdc2_clk, 0x99b000, 14, 6), + SDC_QDSD_PINGROUP(sdc2_cmd, 0x99b000, 11, 3), + SDC_QDSD_PINGROUP(sdc2_data, 0x99b000, 9, 0), + SDC_QDSD_PINGROUP(sdc1_rclk, 0x99a000, 15, 0), }; static const struct msm_pinctrl_soc_data msmfalcon_pinctrl = { @@ -1524,7 +1606,7 @@ static const struct msm_pinctrl_soc_data msmfalcon_pinctrl = { .nfunctions = ARRAY_SIZE(msmfalcon_functions), .groups = msmfalcon_groups, .ngroups = ARRAY_SIZE(msmfalcon_groups), - .ngpios = 111, + .ngpios = 114, }; static int msmfalcon_pinctrl_probe(struct platform_device *pdev) 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/gsi/gsi_dbg.c b/drivers/platform/msm/gsi/gsi_dbg.c index bd8cdf3f9770..2ab8b79acc6d 100644 --- a/drivers/platform/msm/gsi/gsi_dbg.c +++ b/drivers/platform/msm/gsi/gsi_dbg.c @@ -653,11 +653,11 @@ static ssize_t gsi_rst_stats(struct file *file, } else if (ch_id < 0 || ch_id >= GSI_MAX_CHAN || !gsi_ctx->chan[ch_id].allocated) { goto error; + } else { + min = ch_id; + max = ch_id + 1; } - min = ch_id; - max = ch_id + 1; - for (ch_id = min; ch_id < max; ch_id++) memset(&gsi_ctx->chan[ch_id].stats, 0, sizeof(gsi_ctx->chan[ch_id].stats)); 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_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index 0bb863037772..005508fdcdc1 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -40,6 +40,8 @@ IPA_GENERIC_RX_BUFF_BASE_SZ) -\ IPA_GENERIC_RX_BUFF_BASE_SZ) +#define IPA_RX_BUFF_CLIENT_HEADROOM 256 + /* less 1 nominal MTU (1500 bytes) rounded to units of KB */ #define IPA_ADJUST_AGGR_BYTE_LIMIT(X) (((X) - IPA_MTU)/1000) @@ -2288,6 +2290,21 @@ static void ipa_cleanup_rx(struct ipa_sys_context *sys) } } +static struct sk_buff *ipa_skb_copy_for_client(struct sk_buff *skb, int len) +{ + struct sk_buff *skb2 = NULL; + + skb2 = __dev_alloc_skb(len + IPA_RX_BUFF_CLIENT_HEADROOM, GFP_KERNEL); + if (likely(skb2)) { + /* Set the data pointer */ + skb_reserve(skb2, IPA_RX_BUFF_CLIENT_HEADROOM); + memcpy(skb2->data, skb->data, len); + skb2->len = len; + skb_set_tail_pointer(skb2, len); + } + + return skb2; +} static int ipa_lan_rx_pyld_hdlr(struct sk_buff *skb, struct ipa_sys_context *sys) @@ -2484,7 +2501,8 @@ begin: sys->drop_packet = true; } - skb2 = skb_clone(skb, GFP_KERNEL); + skb2 = ipa_skb_copy_for_client(skb, + status->pkt_len + IPA_PKT_STATUS_SIZE); if (likely(skb2)) { if (skb->len < len + IPA_PKT_STATUS_SIZE) { IPADBG("SPL skb len %d len %d\n", @@ -2527,7 +2545,7 @@ begin: IPA_PKT_STATUS_SIZE); } } else { - IPAERR("fail to clone\n"); + IPAERR("fail to alloc skb\n"); if (skb->len < len) { sys->prev_skb = NULL; sys->len_rem = len - skb->len + 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/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index b89dcfe18925..395cf62c9728 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -41,8 +41,7 @@ #define IPA_TAG_SLEEP_MAX_USEC (2000) #define IPA_FORCE_CLOSE_TAG_PROCESS_TIMEOUT (10 * HZ) #define IPA_BCR_REG_VAL_v3_0 (0x00000001) -#define IPA_BCR_REG_VAL_v3_1 (0x00000003) -#define IPA_BCR_REG_VAL_v3_5_1 (0x0000003B) +#define IPA_BCR_REG_VAL_v3_5 (0x0000003B) #define IPA_AGGR_GRAN_MIN (1) #define IPA_AGGR_GRAN_MAX (32) #define IPA_EOT_COAL_GRAN_MIN (1) @@ -859,13 +858,12 @@ int ipa3_init_hw(void) switch (ipa3_ctx->ipa_hw_type) { case IPA_HW_v3_0: - val = IPA_BCR_REG_VAL_v3_0; - break; case IPA_HW_v3_1: - val = IPA_BCR_REG_VAL_v3_1; + val = IPA_BCR_REG_VAL_v3_0; break; + case IPA_HW_v3_5: case IPA_HW_v3_5_1: - val = IPA_BCR_REG_VAL_v3_5_1; + val = IPA_BCR_REG_VAL_v3_5; break; default: IPAERR("unknown HW type in dts\n"); 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/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/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c index e5055708a871..232bcf8fcf31 100644 --- a/drivers/regulator/cpr3-mmss-regulator.c +++ b/drivers/regulator/cpr3-mmss-regulator.c @@ -50,6 +50,9 @@ * @limitation: CPR limitation select fuse parameter value * @aging_init_quot_diff: Initial quotient difference between CPR aging * min and max sensors measured at time of manufacturing + * @force_highest_corner: Flag indicating that all corners must operate + * at the voltage of the highest corner. This is + * applicable to MSMCOBALT only. * * This struct holds the values for all of the fuses read from memory. */ @@ -60,6 +63,7 @@ struct cpr3_msm8996_mmss_fuses { u64 cpr_fusing_rev; u64 limitation; u64 aging_init_quot_diff; + u64 force_highest_corner; }; /* Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 */ @@ -158,6 +162,12 @@ msmcobalt_mmss_offset_voltage_param[MSM8996_MMSS_FUSE_CORNERS][2] = { {{65, 44, 47}, {} }, }; +static const struct cpr3_fuse_param +msmcobalt_cpr_force_highest_corner_param[] = { + {100, 45, 45}, + {}, +}; + #define MSM8996PRO_SOC_ID 4 #define MSMCOBALT_SOC_ID 5 @@ -243,6 +253,12 @@ enum msmcobalt_cpr_partial_binning { MSMCOBALT_CPR_PARTIAL_BINNING_SAFE_CORNER = 0xE, }; +/* + * The partial binning open-loop voltage fuse values only apply to the lowest + * two fuse corners (0 and 1, i.e. MinSVS and SVS). + */ +#define MSMCOBALT_CPR_PARTIAL_BINNING_MAX_FUSE_CORNER 1 + /** * cpr3_msm8996_mmss_read_fuse_data() - load MMSS specific fuse parameter values * @vreg: Pointer to the CPR3 regulator @@ -338,6 +354,19 @@ static int cpr3_msm8996_mmss_read_fuse_data(struct cpr3_regulator *vreg) } if (vreg->thread->ctrl->soc_revision == MSMCOBALT_SOC_ID) { + rc = cpr3_read_fuse_param(base, + msmcobalt_cpr_force_highest_corner_param, + &fuse->force_highest_corner); + if (rc) { + cpr3_err(vreg, "Unable to read CPR force highest corner fuse, rc=%d\n", + rc); + return rc; + } + if (fuse->force_highest_corner) + cpr3_info(vreg, "Fusing requires all operation at the highest corner\n"); + } + + if (vreg->thread->ctrl->soc_revision == MSMCOBALT_SOC_ID) { combo_max = CPR3_MSMCOBALT_MMSS_FUSE_COMBO_COUNT; vreg->fuse_combo = fuse->cpr_fusing_rev; } else if (vreg->thread->ctrl->soc_revision == MSM8996PRO_SOC_ID) { @@ -738,7 +767,8 @@ static int cpr3_msm8996_mmss_calculate_open_loop_voltages( */ if (is_msmcobalt && (volt_init == MSMCOBALT_CPR_PARTIAL_BINNING_NEXT_CORNER || - volt_init == MSMCOBALT_CPR_PARTIAL_BINNING_SAFE_CORNER)) + volt_init == MSMCOBALT_CPR_PARTIAL_BINNING_SAFE_CORNER) && + i <= MSMCOBALT_CPR_PARTIAL_BINNING_MAX_FUSE_CORNER) volt_init = MSM8996_MMSS_MIN_VOLTAGE_FUSE_VAL; fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse(ref_volt[i], @@ -849,19 +879,43 @@ static int cpr3_msmcobalt_partial_binning_override(struct cpr3_regulator *vreg) u32 proc_freq; struct cpr3_corner *corner; struct cpr3_corner *safe_corner; - int i, j, low, high, safe_fuse_corner; + int i, j, low, high, safe_fuse_corner, max_fuse_corner; if (vreg->thread->ctrl->soc_revision != MSMCOBALT_SOC_ID) return 0; - /* Loop over all fuse corners except for the highest one. */ - for (i = 0; i < vreg->fuse_corner_count - 1; i++) { + /* Handle the force highest corner fuse. */ + if (fuse->force_highest_corner) { + cpr3_info(vreg, "overriding CPR parameters for corners 0 to %d with quotients and voltages of corner %d\n", + vreg->corner_count - 2, vreg->corner_count - 1); + corner = &vreg->corner[vreg->corner_count - 1]; + for (i = 0; i < vreg->corner_count - 1; i++) { + proc_freq = vreg->corner[i].proc_freq; + vreg->corner[i] = *corner; + vreg->corner[i].proc_freq = proc_freq; + } + + /* + * Return since the potential partial binning fuse values are + * superceded by the force highest corner fuse value. + */ + return 0; + } + + /* + * Allow up to the max corner which can be fused with partial + * binning values. + */ + max_fuse_corner = min(MSMCOBALT_CPR_PARTIAL_BINNING_MAX_FUSE_CORNER, + vreg->fuse_corner_count - 2); + + for (i = 0; i <= max_fuse_corner; i++) { /* Determine which higher corners to override with (if any). */ if (fuse->init_voltage[i] != next && fuse->init_voltage[i] != safe) continue; - for (j = i + 1; j < vreg->fuse_corner_count - 1; j++) + for (j = i + 1; j <= max_fuse_corner; j++) if (fuse->init_voltage[j] != next && fuse->init_voltage[j] != safe) break; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 3f8aa534c220..c45cbfa8a786 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -104,6 +104,16 @@ config MSM_GLINK_SMEM_NATIVE_XPRT transport to only connecting with entities internal to the System-on-Chip. +config MSM_GLINK_SPI_XPRT + depends on MSM_GLINK + tristate "Generic Link (G-Link) SPI Transport" + help + G-Link SPI Transport is a Transport plug-in developed over SPI + bus. This transport plug-in performs marshaling of G-Link + commands & data to the appropriate SPI bus wire format and + allows for G-Link communication with remote subsystems that are + external to the System-on-Chip. + config MSM_SPCOM depends on MSM_GLINK bool "Secure Processor Communication over GLINK" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index f8450a4868ad..269b72c68b68 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_MSM_GLINK) += glink.o glink_debugfs.o glink_ssr.o obj-$(CONFIG_MSM_GLINK_LOOPBACK_SERVER) += glink_loopback_server.o obj-$(CONFIG_MSM_GLINK_SMD_XPRT) += glink_smd_xprt.o obj-$(CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT)+= glink_smem_native_xprt.o +obj-$(CONFIG_MSM_GLINK_SPI_XPRT) += glink_spi_xprt.o obj-$(CONFIG_MSM_SMEM_LOGGING) += smem_log.o obj-$(CONFIG_MSM_SYSMON_GLINK_COMM) += sysmon-glink.o sysmon-qmi.o obj-$(CONFIG_ARCH_MSM8996) += kryo-l2-accessors.o 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/glink.c b/drivers/soc/qcom/glink.c index 464fe17158cf..57e58a57fab7 100644 --- a/drivers/soc/qcom/glink.c +++ b/drivers/soc/qcom/glink.c @@ -372,10 +372,10 @@ static struct channel_ctx *ch_name_to_ch_ctx_create( const char *name); static void ch_push_remote_rx_intent(struct channel_ctx *ctx, size_t size, - uint32_t riid); + uint32_t riid, void *cookie); static int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size, - uint32_t *riid_ptr, size_t *intent_size); + uint32_t *riid_ptr, size_t *intent_size, void **cookie); static struct glink_core_rx_intent *ch_push_local_rx_intent( struct channel_ctx *ctx, const void *pkt_priv, size_t size); @@ -1139,11 +1139,12 @@ bool ch_check_duplicate_riid(struct channel_ctx *ctx, int riid) * @ctx: Local channel context * @size: Size of Intent * @riid_ptr: Pointer to return value of remote intent ID + * @cookie: Transport-specific cookie to return * * This functions searches for an RX intent that is >= to the requested size. */ int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size, - uint32_t *riid_ptr, size_t *intent_size) + uint32_t *riid_ptr, size_t *intent_size, void **cookie) { struct glink_core_rx_intent *intent; struct glink_core_rx_intent *intent_tmp; @@ -1177,6 +1178,7 @@ int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size, intent->intent_size); *riid_ptr = intent->id; *intent_size = intent->intent_size; + *cookie = intent->cookie; kfree(intent); spin_unlock_irqrestore( &ctx->rmt_rx_intent_lst_lock_lhc2, flags); @@ -1192,11 +1194,12 @@ int ch_pop_remote_rx_intent(struct channel_ctx *ctx, size_t size, * @ctx: Local channel context * @size: Size of Intent * @riid: Remote intent ID + * @cookie: Transport-specific cookie to cache * * This functions adds a remote RX intent to the remote RX intent list. */ void ch_push_remote_rx_intent(struct channel_ctx *ctx, size_t size, - uint32_t riid) + uint32_t riid, void *cookie) { struct glink_core_rx_intent *intent; unsigned long flags; @@ -1225,6 +1228,7 @@ void ch_push_remote_rx_intent(struct channel_ctx *ctx, size_t size, } intent->id = riid; intent->intent_size = size; + intent->cookie = cookie; spin_lock_irqsave(&ctx->rmt_rx_intent_lst_lock_lhc2, flags); list_add_tail(&intent->list, &ctx->rmt_rx_intent_list); @@ -2794,6 +2798,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, bool is_atomic = tx_flags & (GLINK_TX_SINGLE_THREADED | GLINK_TX_ATOMIC); unsigned long flags; + void *cookie = NULL; if (!size) return -EINVAL; @@ -2826,7 +2831,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, } /* find matching rx intent (first-fit algorithm for now) */ - if (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size)) { + if (ch_pop_remote_rx_intent(ctx, size, &riid, &intent_size, &cookie)) { if (!(tx_flags & GLINK_TX_REQ_INTENT)) { /* no rx intent available */ GLINK_ERR_CH(ctx, @@ -2856,7 +2861,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, } while (ch_pop_remote_rx_intent(ctx, size, &riid, - &intent_size)) { + &intent_size, &cookie)) { rwref_get(&ctx->ch_state_lhb2); rwref_read_put(&ctx->ch_state_lhb2); if (is_atomic) { @@ -2928,7 +2933,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, is_atomic ? GFP_ATOMIC : GFP_KERNEL); if (!tx_info) { GLINK_ERR_CH(ctx, "%s: No memory for allocation\n", __func__); - ch_push_remote_rx_intent(ctx, intent_size, riid); + ch_push_remote_rx_intent(ctx, intent_size, riid, cookie); rwref_read_put(&ctx->ch_state_lhb2); return -ENOMEM; } @@ -2946,6 +2951,7 @@ static int glink_tx_common(void *handle, void *pkt_priv, tx_info->vprovider = vbuf_provider; tx_info->pprovider = pbuf_provider; tx_info->intent_size = intent_size; + tx_info->cookie = cookie; /* schedule packet for transmit */ if ((tx_flags & GLINK_TX_SINGLE_THREADED) && @@ -3577,6 +3583,10 @@ int glink_xprt_name_to_id(const char *name, uint16_t *id) *id = SMEM_XPRT_ID; return 0; } + if (!strcmp(name, "spi")) { + *id = SPIV2_XPRT_ID; + return 0; + } if (!strcmp(name, "smd_trans")) { *id = SMD_TRANS_XPRT_ID; return 0; @@ -4844,7 +4854,35 @@ static void glink_core_remote_rx_intent_put(struct glink_transport_if *if_ptr, return; } - ch_push_remote_rx_intent(ctx, size, riid); + ch_push_remote_rx_intent(ctx, size, riid, NULL); + rwref_put(&ctx->ch_state_lhb2); +} + +/** + * glink_core_remote_rx_intent_put_cookie() - Receive remove intent + * + * @if_ptr: Pointer to transport instance + * @rcid: Remote Channel ID + * @riid: Remote Intent ID + * @size: Size of the remote intent ID + * @cookie: Transport-specific cookie to cache + */ +static void glink_core_remote_rx_intent_put_cookie( + struct glink_transport_if *if_ptr, + uint32_t rcid, uint32_t riid, size_t size, void *cookie) +{ + struct channel_ctx *ctx; + + ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid); + if (!ctx) { + /* unknown rcid received - this shouldn't happen */ + GLINK_ERR_XPRT(if_ptr->glink_core_priv, + "%s: invalid rcid received %u\n", __func__, + (unsigned)rcid); + return; + } + + ch_push_remote_rx_intent(ctx, size, riid, cookie); rwref_put(&ctx->ch_state_lhb2); } @@ -5050,6 +5088,7 @@ void glink_core_rx_cmd_tx_done(struct glink_transport_if *if_ptr, struct glink_core_tx_pkt *tx_pkt; unsigned long flags; size_t intent_size; + void *cookie; ctx = xprt_rcid_to_ch_ctx_get(if_ptr->glink_core_priv, rcid); if (!ctx) { @@ -5082,11 +5121,12 @@ void glink_core_rx_cmd_tx_done(struct glink_transport_if *if_ptr, ctx->notify_tx_done(ctx, ctx->user_priv, tx_pkt->pkt_priv, tx_pkt->data ? tx_pkt->data : tx_pkt->iovec); intent_size = tx_pkt->intent_size; + cookie = tx_pkt->cookie; ch_remove_tx_pending_remote_done(ctx, tx_pkt); spin_unlock_irqrestore(&ctx->tx_lists_lock_lhc3, flags); if (reuse) - ch_push_remote_rx_intent(ctx, intent_size, riid); + ch_push_remote_rx_intent(ctx, intent_size, riid, cookie); rwref_put(&ctx->ch_state_lhb2); } @@ -5525,6 +5565,8 @@ static struct glink_core_if core_impl = { .rx_get_pkt_ctx = glink_core_rx_get_pkt_ctx, .rx_put_pkt_ctx = glink_core_rx_put_pkt_ctx, .rx_cmd_remote_rx_intent_put = glink_core_remote_rx_intent_put, + .rx_cmd_remote_rx_intent_put_cookie = + glink_core_remote_rx_intent_put_cookie, .rx_cmd_remote_rx_intent_req = glink_core_rx_cmd_remote_rx_intent_req, .rx_cmd_rx_intent_req_ack = glink_core_rx_cmd_rx_intent_req_ack, .rx_cmd_tx_done = glink_core_rx_cmd_tx_done, diff --git a/drivers/soc/qcom/glink_core_if.h b/drivers/soc/qcom/glink_core_if.h index 93c59d9c4aa1..14113305a50e 100644 --- a/drivers/soc/qcom/glink_core_if.h +++ b/drivers/soc/qcom/glink_core_if.h @@ -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 @@ -64,6 +64,7 @@ struct glink_core_version { * iovec: Pointer to vector buffer if the transport passes a vector buffer * vprovider: Virtual address-space buffer provider for a vector buffer * pprovider: Physical address-space buffer provider for a vector buffer + * cookie: Private transport specific cookie * pkt_priv: G-Link core owned packet-private data * list: G-Link core owned list node * bounce_buf: Pointer to the temporary/internal bounce buffer @@ -78,6 +79,7 @@ struct glink_core_rx_intent { void *iovec; void * (*vprovider)(void *iovec, size_t offset, size_t *size); void * (*pprovider)(void *iovec, size_t offset, size_t *size); + void *cookie; /* G-Link-Core-owned elements - please ignore */ struct list_head list; @@ -151,6 +153,9 @@ struct glink_core_if { struct glink_core_rx_intent *intent_ptr, bool complete); void (*rx_cmd_remote_rx_intent_put)(struct glink_transport_if *if_ptr, uint32_t rcid, uint32_t riid, size_t size); + void (*rx_cmd_remote_rx_intent_put_cookie)( + struct glink_transport_if *if_ptr, uint32_t rcid, + uint32_t riid, size_t size, void *cookie); void (*rx_cmd_tx_done)(struct glink_transport_if *if_ptr, uint32_t rcid, uint32_t riid, bool reuse); void (*rx_cmd_remote_rx_intent_req)(struct glink_transport_if *if_ptr, diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c new file mode 100644 index 000000000000..6c91ac54821d --- /dev/null +++ b/drivers/soc/qcom/glink_spi_xprt.c @@ -0,0 +1,2192 @@ +/* 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/delay.h> +#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/printk.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> +#include <linux/srcu.h> +#include <linux/wait.h> +#include <linux/component.h> +#include <soc/qcom/tracer_pkt.h> +#include <sound/wcd-dsp-mgr.h> +#include <sound/wcd-spi.h> +#include "glink_core_if.h" +#include "glink_private.h" +#include "glink_xprt_if.h" + +#define XPRT_NAME "spi" +#define FIFO_ALIGNMENT 16 +#define FIFO_FULL_RESERVE 8 +#define TX_BLOCKED_CMD_RESERVE 16 +#define TRACER_PKT_FEATURE BIT(2) +#define DEFAULT_FIFO_SIZE 1024 +#define SHORT_PKT_SIZE 16 +#define XPRT_ALIGNMENT 4 + +#define MAX_INACTIVE_CYCLES 50 +#define POLL_INTERVAL_US 500 + +#define ACTIVE_TX BIT(0) +#define ACTIVE_RX BIT(1) + +#define ID_MASK 0xFFFFFF +/** + * enum command_types - definition of the types of commands sent/received + * @VERSION_CMD: Version and feature set supported + * @VERSION_ACK_CMD: Response for @VERSION_CMD + * @OPEN_CMD: Open a channel + * @CLOSE_CMD: Close a channel + * @OPEN_ACK_CMD: Response to @OPEN_CMD + * @CLOSE_ACK_CMD: Response for @CLOSE_CMD + * @RX_INTENT_CMD: RX intent for a channel is queued + * @RX_DONE_CMD: Use of RX intent for a channel is complete + * @RX_DONE_W_REUSE_CMD: Same as @RX_DONE but also reuse the used intent + * @RX_INTENT_REQ_CMD: Request to have RX intent queued + * @RX_INTENT_REQ_ACK_CMD: Response for @RX_INTENT_REQ_CMD + * @TX_DATA_CMD: Start of a data transfer + * @TX_DATA_CONT_CMD: Continuation or end of a data transfer + * @READ_NOTIF_CMD: Request for a notification when this cmd is read + * @SIGNALS_CMD: Sideband signals + * @TRACER_PKT_CMD: Start of a Tracer Packet Command + * @TRACER_PKT_CONT_CMD: Continuation or end of a Tracer Packet Command + * @TX_SHORT_DATA_CMD: Transmit short packets + */ +enum command_types { + VERSION_CMD, + VERSION_ACK_CMD, + OPEN_CMD, + CLOSE_CMD, + OPEN_ACK_CMD, + CLOSE_ACK_CMD, + RX_INTENT_CMD, + RX_DONE_CMD, + RX_DONE_W_REUSE_CMD, + RX_INTENT_REQ_CMD, + RX_INTENT_REQ_ACK_CMD, + TX_DATA_CMD, + TX_DATA_CONT_CMD, + READ_NOTIF_CMD, + SIGNALS_CMD, + TRACER_PKT_CMD, + TRACER_PKT_CONT_CMD, + TX_SHORT_DATA_CMD, +}; + +/** + * struct glink_cmpnt - Component to cache WDSP component and its operations + * @master_dev: Device structure corresponding to WDSP device. + * @master_ops: Operations supported by the WDSP device. + */ +struct glink_cmpnt { + struct device *master_dev; + struct wdsp_mgr_ops *master_ops; +}; + +/** + * struct edge_info - local information for managing a single complete edge + * @xprt_if: The transport interface registered with the + * glink core associated with this edge. + * @xprt_cfg: The transport configuration for the glink core + * assocaited with this edge. + * @subsys_name: Name of the remote subsystem in the edge. + * @spi_dev: Pointer to the connectingSPI Device. + * @fifo_size: Size of the FIFO at the remote end. + * @tx_fifo_start: Base Address of the TX FIFO. + * @tx_fifo_end: End Address of the TX FIFO. + * @rx_fifo_start: Base Address of the RX FIFO. + * @rx_fifo_end: End Address of the RX FIFO. + * @tx_fifo_read_reg_addr: Address of the TX FIFO Read Index Register. + * @tx_fifo_write_reg_addr: Address of the TX FIFO Write Index Register. + * @rx_fifo_read_reg_addr: Address of the RX FIFO Read Index Register. + * @rx_fifo_write_reg_addr: Address of the RX FIFO Write Index Register. + * @kwork: Work to be executed when receiving data. + * @kworker: Handle to the entity processing @kwork. + * @task: Handle to the task context that runs @kworker. + * @use_ref: Active users of this transport grab a + * reference. Used for SSR synchronization. + * @in_ssr: Signals if this transport is in ssr. + * @write_lock: Lock to serialize write/tx operation. + * @tx_blocked_queue: Queue of entities waiting for the remote side to + * signal the resumption of TX. + * @tx_resume_needed: A tx resume signal needs to be sent to the glink + * core. + * @tx_blocked_signal_sent: Flag to indicate the flush signal has already + * been sent, and a response is pending from the + * remote side. Protected by @write_lock. + * @num_pw_states: Size of @ramp_time_us. + * @ramp_time_us: Array of ramp times in microseconds where array + * index position represents a power state. + * @activity_flag: Flag indicating active TX and RX. + * @activity_lock: Lock to synchronize access to activity flag. + * @cmpnt: Component to interface with the remote device. + */ +struct edge_info { + struct list_head list; + struct glink_transport_if xprt_if; + struct glink_core_transport_cfg xprt_cfg; + char subsys_name[GLINK_NAME_SIZE]; + struct spi_device *spi_dev; + + uint32_t fifo_size; + uint32_t tx_fifo_start; + uint32_t tx_fifo_end; + uint32_t rx_fifo_start; + uint32_t rx_fifo_end; + unsigned int tx_fifo_read_reg_addr; + unsigned int tx_fifo_write_reg_addr; + unsigned int rx_fifo_read_reg_addr; + unsigned int rx_fifo_write_reg_addr; + + struct kthread_work kwork; + struct kthread_worker kworker; + struct task_struct *task; + struct srcu_struct use_ref; + bool in_ssr; + struct mutex write_lock; + wait_queue_head_t tx_blocked_queue; + bool tx_resume_needed; + bool tx_blocked_signal_sent; + + uint32_t num_pw_states; + unsigned long *ramp_time_us; + + uint32_t activity_flag; + spinlock_t activity_lock; + + struct glink_cmpnt cmpnt; +}; + +static uint32_t negotiate_features_v1(struct glink_transport_if *if_ptr, + const struct glink_core_version *version, + uint32_t features); +static DEFINE_SPINLOCK(edge_infos_lock); +static LIST_HEAD(edge_infos); +static struct glink_core_version versions[] = { + {1, TRACER_PKT_FEATURE, negotiate_features_v1}, +}; + +/** + * negotiate_features_v1() - determine what features of a version can be used + * @if_ptr: The transport for which features are negotiated for. + * @version: The version negotiated. + * @features: The set of requested features. + * + * Return: What set of the requested features can be supported. + */ +static uint32_t negotiate_features_v1(struct glink_transport_if *if_ptr, + const struct glink_core_version *version, + uint32_t features) +{ + return features & version->features; +} + +/** + * wdsp_suspend() - Vote for the WDSP device suspend + * @cmpnt: Component to identify the WDSP device. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int wdsp_suspend(struct glink_cmpnt *cmpnt) +{ + if (cmpnt && cmpnt->master_dev && + cmpnt->master_ops && cmpnt->master_ops->suspend) + return cmpnt->master_ops->suspend(cmpnt->master_dev); + else + return -EINVAL; +} + +/** + * wdsp_resume() - Vote for the WDSP device resume + * @cmpnt: Component to identify the WDSP device. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int wdsp_resume(struct glink_cmpnt *cmpnt) +{ + if (cmpnt && cmpnt->master_dev && + cmpnt->master_ops && cmpnt->master_ops->resume) + return cmpnt->master_ops->resume(cmpnt->master_dev); + else + return -EINVAL; +} + +/** + * glink_spi_xprt_set_poll_mode() - Set the transport to polling mode + * @einfo: Edge information corresponding to the transport. + * + * This helper function indicates the start of RX polling. This will + * prevent the system from suspending and keeps polling for RX for a + * pre-defined duration. + */ +static void glink_spi_xprt_set_poll_mode(struct edge_info *einfo) +{ + unsigned long flags; + + spin_lock_irqsave(&einfo->activity_lock, flags); + einfo->activity_flag |= ACTIVE_RX; + spin_unlock_irqrestore(&einfo->activity_lock, flags); + if (!strcmp(einfo->xprt_cfg.edge, "wdsp")) + wdsp_resume(&einfo->cmpnt); +} + +/** + * glink_spi_xprt_set_irq_mode() - Set the transport to IRQ mode + * @einfo: Edge information corresponding to the transport. + * + * This helper indicates the end of RX polling. This will allow the + * system to suspend and new RX data can be handled only through an IRQ. + */ +static void glink_spi_xprt_set_irq_mode(struct edge_info *einfo) +{ + unsigned long flags; + + spin_lock_irqsave(&einfo->activity_lock, flags); + einfo->activity_flag &= ~ACTIVE_RX; + spin_unlock_irqrestore(&einfo->activity_lock, flags); +} + +/** + * glink_spi_xprt_rx_data() - Receive data over SPI bus + * @einfo: Edge from which the data has to be received. + * @src: Source Address of the RX data. + * @dst: Address of the destination RX buffer. + * @size: Size of the RX data. + * + * This function is used to receive data or command as a byte stream from + * the remote subsystem over the SPI bus. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_xprt_rx_data(struct edge_info *einfo, void *src, + void *dst, uint32_t size) +{ + struct wcd_spi_msg spi_msg; + + memset(&spi_msg, 0, sizeof(spi_msg)); + spi_msg.data = dst; + spi_msg.remote_addr = (uint32_t)(size_t)src; + spi_msg.len = (size_t)size; + return wcd_spi_data_read(einfo->spi_dev, &spi_msg); +} + +/** + * glink_spi_xprt_tx_data() - Transmit data over SPI bus + * @einfo: Edge from which the data has to be received. + * @src: Address of the TX buffer. + * @dst: Destination Address of the TX Date. + * @size: Size of the TX data. + * + * This function is used to transmit data or command as a byte stream to + * the remote subsystem over the SPI bus. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_xprt_tx_data(struct edge_info *einfo, void *src, + void *dst, uint32_t size) +{ + struct wcd_spi_msg spi_msg; + + memset(&spi_msg, 0, sizeof(spi_msg)); + spi_msg.data = src; + spi_msg.remote_addr = (uint32_t)(size_t)dst; + spi_msg.len = (size_t)size; + return wcd_spi_data_write(einfo->spi_dev, &spi_msg); +} + +/** + * glink_spi_xprt_reg_read() - Read the TX/RX FIFO Read/Write Index registers + * @einfo: Edge from which the registers have to be read. + * @reg_addr: Address of the register to be read. + * @data: Buffer into which the register data has to be read. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_xprt_reg_read(struct edge_info *einfo, u32 reg_addr, + uint32_t *data) +{ + int rc; + + rc = glink_spi_xprt_rx_data(einfo, (void *)(unsigned long)reg_addr, + data, sizeof(*data)); + if (!rc) + *data = *data & ID_MASK; + return rc; +} + +/** + * glink_spi_xprt_reg_write() - Write the TX/RX FIFO Read/Write Index registers + * @einfo: Edge to which the registers have to be written. + * @reg_addr: Address of the registers to be written. + * @data: Data to be written to the registers. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_xprt_reg_write(struct edge_info *einfo, u32 reg_addr, + uint32_t data) +{ + return glink_spi_xprt_tx_data(einfo, &data, + (void *)(unsigned long)reg_addr, sizeof(data)); +} + +/** + * glink_spi_xprt_write_avail() - Available Write Space in the remote side + * @einfo: Edge information corresponding to the remote side. + * + * This function reads the TX FIFO Read & Write Index registers from the + * remote subsystem and calculate the available write space. + * + * Return: 0 on error, available write space on success. + */ +static int glink_spi_xprt_write_avail(struct edge_info *einfo) +{ + uint32_t read_id; + uint32_t write_id; + int write_avail; + int ret; + + ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_read_reg_addr, + &read_id); + if (ret < 0) { + pr_err("%s: Error %d reading %s tx_fifo_read_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->tx_fifo_read_reg_addr); + return 0; + } + + ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr, + &write_id); + if (ret < 0) { + pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->tx_fifo_write_reg_addr); + return 0; + } + + if (!read_id || !write_id) + return 0; + + if (unlikely(!einfo->tx_fifo_start)) + einfo->tx_fifo_start = write_id; + + if (read_id > write_id) + write_avail = read_id - write_id; + else + write_avail = einfo->fifo_size - (write_id - read_id); + + if (write_avail < FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE) + write_avail = 0; + else + write_avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE; + + return write_avail; +} + +/** + * glink_spi_xprt_read_avail() - Available Read Data from the remote side + * @einfo: Edge information corresponding to the remote side. + * + * This function reads the RX FIFO Read & Write Index registers from the + * remote subsystem and calculate the available read data size. + * + * Return: 0 on error, available read data on success. + */ +static int glink_spi_xprt_read_avail(struct edge_info *einfo) +{ + uint32_t read_id; + uint32_t write_id; + int read_avail; + int ret; + + ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr, + &read_id); + if (ret < 0) { + pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->rx_fifo_read_reg_addr); + return 0; + } + + ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_write_reg_addr, + &write_id); + if (ret < 0) { + pr_err("%s: Error %d reading %s rx_fifo_write_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->rx_fifo_write_reg_addr); + return 0; + } + + if (!read_id || !write_id) + return 0; + + if (unlikely(!einfo->rx_fifo_start)) + einfo->rx_fifo_start = read_id; + + if (read_id <= write_id) + read_avail = write_id - read_id; + else + read_avail = einfo->fifo_size - (read_id - write_id); + return read_avail; +} + +/** + * glink_spi_xprt_rx_cmd() - Receive G-Link commands + * @einfo: Edge information corresponding to the remote side. + * @dst: Destination buffer where the commands have to be read into. + * @size: Size of the data to be read. + * + * This function is used to receive the commands from the RX FIFO. This + * function updates the RX FIFO Read Index after reading the data. + * + * Return: 0 on success, standard Linux error codes on error. + */ +static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst, + uint32_t size) +{ + uint32_t read_id; + uint32_t size_to_read = size; + uint32_t offset = 0; + int ret; + + ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr, + &read_id); + if (ret < 0) { + pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->rx_fifo_read_reg_addr); + return ret; + } + + do { + if ((read_id + size_to_read) >= + (einfo->rx_fifo_start + einfo->fifo_size)) + size_to_read = einfo->rx_fifo_start + einfo->fifo_size + - read_id; + ret = glink_spi_xprt_rx_data(einfo, (void *)(size_t)read_id, + dst + offset, size_to_read); + if (ret < 0) { + pr_err("%s: Error %d reading data\n", __func__, ret); + return ret; + } + read_id += size_to_read; + offset += size_to_read; + if (read_id >= (einfo->rx_fifo_start + einfo->fifo_size)) + read_id = einfo->rx_fifo_start; + size_to_read = size - offset; + } while (size_to_read); + + ret = glink_spi_xprt_reg_write(einfo, einfo->rx_fifo_read_reg_addr, + read_id); + if (ret < 0) + pr_err("%s: Error %d writing %s rx_fifo_read_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->rx_fifo_read_reg_addr); + return ret; +} + +/** + * glink_spi_xprt_tx_cmd_safe() - Transmit G-Link commands + * @einfo: Edge information corresponding to the remote subsystem. + * @src: Source buffer containing the G-Link command. + * @size: Size of the command to transmit. + * + * This function is used to transmit the G-Link commands. This function + * must be called with einfo->write_lock locked. + * + * Return: 0 on success, standard Linux error codes on error. + */ +static int glink_spi_xprt_tx_cmd_safe(struct edge_info *einfo, void *src, + uint32_t size) +{ + uint32_t write_id; + uint32_t size_to_write = size; + uint32_t offset = 0; + int ret; + + ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr, + &write_id); + if (ret < 0) { + pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->tx_fifo_write_reg_addr); + return ret; + } + + do { + if ((write_id + size_to_write) >= + (einfo->tx_fifo_start + einfo->fifo_size)) + size_to_write = einfo->tx_fifo_start + einfo->fifo_size + - write_id; + ret = glink_spi_xprt_tx_data(einfo, src + offset, + (void *)(size_t)write_id, size_to_write); + if (ret < 0) { + pr_err("%s: Error %d writing data\n", __func__, ret); + return ret; + } + write_id += size_to_write; + offset += size_to_write; + if (write_id >= (einfo->tx_fifo_start + einfo->fifo_size)) + write_id = einfo->tx_fifo_start; + size_to_write = size - offset; + } while (size_to_write); + + ret = glink_spi_xprt_reg_write(einfo, einfo->tx_fifo_write_reg_addr, + write_id); + if (ret < 0) + pr_err("%s: Error %d writing %s tx_fifo_write_reg_addr %d\n", + __func__, ret, einfo->xprt_cfg.edge, + einfo->tx_fifo_write_reg_addr); + return ret; +} + +/** + * send_tx_blocked_signal() - Send flow control request message + * @einfo: Edge information corresponding to the remote subsystem. + * + * This function is used to send a message to the remote subsystem indicating + * that the local subsystem is waiting for the write space. The remote + * subsystem on receiving this message will send a resume tx message. + */ +static void send_tx_blocked_signal(struct edge_info *einfo) +{ + struct read_notif_request { + uint16_t cmd; + uint16_t reserved; + uint32_t reserved2; + uint64_t reserved3; + }; + struct read_notif_request read_notif_req = {0}; + + read_notif_req.cmd = READ_NOTIF_CMD; + + if (!einfo->tx_blocked_signal_sent) { + einfo->tx_blocked_signal_sent = true; + glink_spi_xprt_tx_cmd_safe(einfo, &read_notif_req, + sizeof(read_notif_req)); + } +} + +/** + * glink_spi_xprt_tx_cmd() - Transmit G-Link commands + * @einfo: Edge information corresponding to the remote subsystem. + * @src: Source buffer containing the G-Link command. + * @size: Size of the command to transmit. + * + * This function is used to transmit the G-Link commands. This function + * might sleep if the space is not available to transmit the command. + * + * Return: 0 on success, standard Linux error codes on error. + */ +static int glink_spi_xprt_tx_cmd(struct edge_info *einfo, void *src, + uint32_t size) +{ + int ret; + DEFINE_WAIT(wait); + + mutex_lock(&einfo->write_lock); + while (glink_spi_xprt_write_avail(einfo) < size) { + send_tx_blocked_signal(einfo); + prepare_to_wait(&einfo->tx_blocked_queue, &wait, + TASK_UNINTERRUPTIBLE); + if (glink_spi_xprt_write_avail(einfo) < size && + !einfo->in_ssr) { + mutex_unlock(&einfo->write_lock); + schedule(); + mutex_lock(&einfo->write_lock); + } + finish_wait(&einfo->tx_blocked_queue, &wait); + if (einfo->in_ssr) { + mutex_unlock(&einfo->write_lock); + return -EFAULT; + } + } + ret = glink_spi_xprt_tx_cmd_safe(einfo, src, size); + mutex_unlock(&einfo->write_lock); + return ret; +} + +/** + * process_rx_data() - process received data from an edge + * @einfo: The edge the data is received on. + * @cmd_id: ID to specify the type of data. + * @rcid: The remote channel id associated with the data. + * @intend_id: The intent the data should be put in. + * @src: Address of the source buffer from which the data + * is read. + * @frag_size: Size of the data fragment to read. + * @size_remaining: Size of data left to be read in this packet. + */ +static void process_rx_data(struct edge_info *einfo, uint16_t cmd_id, + uint32_t rcid, uint32_t intent_id, void *src, + uint32_t frag_size, uint32_t size_remaining) +{ + struct glink_core_rx_intent *intent; + int rc = 0; + + intent = einfo->xprt_if.glink_core_if_ptr->rx_get_pkt_ctx( + &einfo->xprt_if, rcid, intent_id); + if (intent == NULL) { + GLINK_ERR("%s: no intent for ch %d liid %d\n", __func__, rcid, + intent_id); + return; + } else if (intent->data == NULL) { + GLINK_ERR("%s: intent for ch %d liid %d has no data buff\n", + __func__, rcid, intent_id); + return; + } else if (intent->intent_size - intent->write_offset < frag_size || + intent->write_offset + size_remaining > intent->intent_size) { + GLINK_ERR("%s: rx data size:%d and remaining:%d %s %d %s:%d\n", + __func__, frag_size, size_remaining, + "will overflow ch", rcid, "intent", intent_id); + return; + } + + if (cmd_id == TX_SHORT_DATA_CMD) + memcpy(intent->data + intent->write_offset, src, frag_size); + else + rc = glink_spi_xprt_rx_data(einfo, src, + intent->data + intent->write_offset, frag_size); + if (rc < 0) { + GLINK_ERR("%s: Error %d receiving data %d:%d:%d:%d\n", + __func__, rc, rcid, intent_id, frag_size, + size_remaining); + size_remaining += frag_size; + } else { + intent->write_offset += frag_size; + intent->pkt_size += frag_size; + + if (unlikely((cmd_id == TRACER_PKT_CMD || + cmd_id == TRACER_PKT_CONT_CMD) && !size_remaining)) { + tracer_pkt_log_event(intent->data, GLINK_XPRT_RX); + intent->tracer_pkt = true; + } + } + einfo->xprt_if.glink_core_if_ptr->rx_put_pkt_ctx(&einfo->xprt_if, + rcid, intent, size_remaining ? false : true); +} + +/** + * process_rx_cmd() - Process incoming G-Link commands + * @einfo: Edge information corresponding to the remote subsystem. + * @rx_data: Buffer which contains the G-Link commands to be processed. + * @rx_size: Size of the buffer containing the series of G-Link commands. + * + * This function is used to parse and process a series of G-Link commands + * received in a buffer. + */ +static void process_rx_cmd(struct edge_info *einfo, + void *rx_data, int rx_size) +{ + struct command { + uint16_t id; + uint16_t param1; + uint32_t param2; + uint32_t param3; + uint32_t param4; + }; + struct intent_desc { + uint32_t size; + uint32_t id; + uint64_t addr; + }; + struct rx_desc { + uint32_t size; + uint32_t size_left; + uint64_t addr; + }; + struct rx_short_data_desc { + unsigned char data[SHORT_PKT_SIZE]; + }; + struct command *cmd; + struct intent_desc *intents; + struct rx_desc *rx_descp; + struct rx_short_data_desc *rx_sd_descp; + int offset = 0; + int rcu_id; + uint16_t rcid; + uint16_t name_len; + uint16_t prio; + char *name; + bool granted; + int i; + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + + while (offset < rx_size) { + cmd = (struct command *)(rx_data + offset); + offset += sizeof(*cmd); + switch (cmd->id) { + case VERSION_CMD: + if (cmd->param3) + einfo->fifo_size = cmd->param3; + einfo->xprt_if.glink_core_if_ptr->rx_cmd_version( + &einfo->xprt_if, cmd->param1, cmd->param2); + break; + + case VERSION_ACK_CMD: + einfo->xprt_if.glink_core_if_ptr->rx_cmd_version_ack( + &einfo->xprt_if, cmd->param1, cmd->param2); + break; + + case OPEN_CMD: + rcid = cmd->param1; + name_len = (uint16_t)(cmd->param2 & 0xFFFF); + prio = (uint16_t)((cmd->param2 & 0xFFFF0000) >> 16); + name = (char *)(rx_data + offset); + offset += ALIGN(name_len, FIFO_ALIGNMENT); + einfo->xprt_if.glink_core_if_ptr->rx_cmd_ch_remote_open( + &einfo->xprt_if, rcid, name, prio); + break; + + case CLOSE_CMD: + einfo->xprt_if.glink_core_if_ptr-> + rx_cmd_ch_remote_close( + &einfo->xprt_if, cmd->param1); + break; + + case OPEN_ACK_CMD: + prio = (uint16_t)(cmd->param2 & 0xFFFF); + einfo->xprt_if.glink_core_if_ptr->rx_cmd_ch_open_ack( + &einfo->xprt_if, cmd->param1, prio); + break; + + case CLOSE_ACK_CMD: + einfo->xprt_if.glink_core_if_ptr->rx_cmd_ch_close_ack( + &einfo->xprt_if, cmd->param1); + break; + + case RX_INTENT_CMD: + for (i = 0; i < cmd->param2; i++) { + intents = (struct intent_desc *) + (rx_data + offset); + offset += sizeof(*intents); + einfo->xprt_if.glink_core_if_ptr-> + rx_cmd_remote_rx_intent_put_cookie( + &einfo->xprt_if, cmd->param1, + intents->id, intents->size, + (void *)(intents->addr)); + } + break; + + case RX_DONE_CMD: + einfo->xprt_if.glink_core_if_ptr->rx_cmd_tx_done( + &einfo->xprt_if, cmd->param1, cmd->param2, + false); + break; + + case RX_INTENT_REQ_CMD: + einfo->xprt_if.glink_core_if_ptr-> + rx_cmd_remote_rx_intent_req( + &einfo->xprt_if, cmd->param1, + cmd->param2); + break; + + case RX_INTENT_REQ_ACK_CMD: + granted = cmd->param2 == 1 ? true : false; + einfo->xprt_if.glink_core_if_ptr-> + rx_cmd_rx_intent_req_ack(&einfo->xprt_if, + cmd->param1, granted); + break; + + case TX_DATA_CMD: + case TX_DATA_CONT_CMD: + case TRACER_PKT_CMD: + case TRACER_PKT_CONT_CMD: + rx_descp = (struct rx_desc *)(rx_data + offset); + offset += sizeof(*rx_descp); + process_rx_data(einfo, cmd->id, cmd->param1, + cmd->param2, (void *)rx_descp->addr, + rx_descp->size, rx_descp->size_left); + break; + + case TX_SHORT_DATA_CMD: + rx_sd_descp = (struct rx_short_data_desc *) + (rx_data + offset); + offset += sizeof(*rx_sd_descp); + process_rx_data(einfo, cmd->id, cmd->param1, + cmd->param2, (void *)rx_sd_descp->data, + cmd->param3, cmd->param4); + break; + + case READ_NOTIF_CMD: + break; + + case SIGNALS_CMD: + einfo->xprt_if.glink_core_if_ptr->rx_cmd_remote_sigs( + &einfo->xprt_if, cmd->param1, cmd->param2); + break; + + case RX_DONE_W_REUSE_CMD: + einfo->xprt_if.glink_core_if_ptr->rx_cmd_tx_done( + &einfo->xprt_if, cmd->param1, + cmd->param2, true); + break; + + default: + pr_err("Unrecognized command: %d\n", cmd->id); + break; + } + } + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** + * __rx_worker() - Receive commands on a specific edge + * @einfo: Edge to process commands on. + * + * This function checks the size of data to be received, allocates the + * buffer for that data and reads the data from the remote subsytem + * into that buffer. This function then calls the process_rx_cmd() to + * parse the received G-Link command sequence. This function will also + * poll for the data for a predefined duration for performance reasons. + */ +static void __rx_worker(struct edge_info *einfo) +{ + uint32_t inactive_cycles = 0; + int rx_avail, rc; + void *rx_data; + int rcu_id; + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (unlikely(!einfo->rx_fifo_start)) { + rx_avail = glink_spi_xprt_read_avail(einfo); + if (!rx_avail) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + einfo->in_ssr = false; + einfo->xprt_if.glink_core_if_ptr->link_up(&einfo->xprt_if); + } + + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + + glink_spi_xprt_set_poll_mode(einfo); + while (inactive_cycles < MAX_INACTIVE_CYCLES) { + if (einfo->tx_resume_needed && + glink_spi_xprt_write_avail(einfo)) { + einfo->tx_resume_needed = false; + einfo->xprt_if.glink_core_if_ptr->tx_resume( + &einfo->xprt_if); + } + mutex_lock(&einfo->write_lock); + if (einfo->tx_blocked_signal_sent) { + wake_up_all(&einfo->tx_blocked_queue); + einfo->tx_blocked_signal_sent = false; + } + mutex_unlock(&einfo->write_lock); + + rx_avail = glink_spi_xprt_read_avail(einfo); + if (!rx_avail) { + usleep_range(POLL_INTERVAL_US, POLL_INTERVAL_US + 50); + inactive_cycles++; + continue; + } + inactive_cycles = 0; + + rx_data = kzalloc(rx_avail, GFP_KERNEL); + if (!rx_data) + break; + + rc = glink_spi_xprt_rx_cmd(einfo, rx_data, rx_avail); + if (rc < 0) { + GLINK_ERR("%s: Error %d receiving data\n", + __func__, rc); + kfree(rx_data); + break; + } + process_rx_cmd(einfo, rx_data, rx_avail); + kfree(rx_data); + } + glink_spi_xprt_set_irq_mode(einfo); + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** + * rx_worker() - Worker function to process received commands + * @work: kwork associated with the edge to process commands on. + */ +static void rx_worker(struct kthread_work *work) +{ + struct edge_info *einfo; + + einfo = container_of(work, struct edge_info, kwork); + __rx_worker(einfo); +}; + +/** + * tx_cmd_version() - Convert a version cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @version: The version number to encode. + * @features: The features information to encode. + */ +static void tx_cmd_version(struct glink_transport_if *if_ptr, uint32_t version, + uint32_t features) +{ + struct command { + uint16_t id; + uint16_t version; + uint32_t features; + uint32_t fifo_size; + uint32_t reserved; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + + cmd.id = VERSION_CMD; + cmd.version = version; + cmd.features = features; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** + * tx_cmd_version_ack() - Convert a version ack cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @version: The version number to encode. + * @features: The features information to encode. + */ +static void tx_cmd_version_ack(struct glink_transport_if *if_ptr, + uint32_t version, + uint32_t features) +{ + struct command { + uint16_t id; + uint16_t version; + uint32_t features; + uint32_t fifo_size; + uint32_t reserved; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + + cmd.id = VERSION_ACK_CMD; + cmd.version = version; + cmd.features = features; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** + * set_version() - Activate a negotiated version and feature set + * @if_ptr: The transport to configure. + * @version: The version to use. + * @features: The features to use. + * + * Return: The supported capabilities of the transport. + */ +static uint32_t set_version(struct glink_transport_if *if_ptr, uint32_t version, + uint32_t features) +{ + struct edge_info *einfo; + uint32_t ret; + int rcu_id; + + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return 0; + } + + ret = GCAP_SIGNALS; + if (features & TRACER_PKT_FEATURE) + ret |= GCAP_TRACER_PKT; + + srcu_read_unlock(&einfo->use_ref, rcu_id); + return ret; +} + +/** + * tx_cmd_ch_open() - Convert a channel open cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @name: The channel name to encode. + * @req_xprt: The transport the core would like to migrate this channel to. + * + * Return: 0 on success or standard Linux error code. + */ +static int tx_cmd_ch_open(struct glink_transport_if *if_ptr, uint32_t lcid, + const char *name, uint16_t req_xprt) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint16_t length; + uint16_t req_xprt; + uint64_t reserved; + }; + struct command cmd; + struct edge_info *einfo; + uint32_t buf_size; + void *buf; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + cmd.id = OPEN_CMD; + cmd.lcid = lcid; + cmd.length = (uint16_t)(strlen(name) + 1); + cmd.req_xprt = req_xprt; + + buf_size = ALIGN(sizeof(cmd) + cmd.length, FIFO_ALIGNMENT); + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -ENOMEM; + } + + memcpy(buf, &cmd, sizeof(cmd)); + memcpy(buf + sizeof(cmd), name, cmd.length); + + glink_spi_xprt_tx_cmd(einfo, buf, buf_size); + + kfree(buf); + srcu_read_unlock(&einfo->use_ref, rcu_id); + return 0; +} + +/** + * tx_cmd_ch_close() - Convert a channel close cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int tx_cmd_ch_close(struct glink_transport_if *if_ptr, uint32_t lcid) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t reserved1; + uint64_t reserved2; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + cmd.id = CLOSE_CMD; + cmd.lcid = lcid; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + + srcu_read_unlock(&einfo->use_ref, rcu_id); + return 0; +} + +/** + * tx_cmd_ch_remote_open_ack() - Convert a channel open ack cmd to wire format + * and transmit + * @if_ptr: The transport to transmit on. + * @rcid: The remote channel id to encode. + * @xprt_resp: The response to a transport migration request. + */ +static void tx_cmd_ch_remote_open_ack(struct glink_transport_if *if_ptr, + uint32_t rcid, uint16_t xprt_resp) +{ + struct command { + uint16_t id; + uint16_t rcid; + uint16_t reserved1; + uint16_t xprt_resp; + uint64_t reserved2; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + + cmd.id = OPEN_ACK_CMD; + cmd.rcid = rcid; + cmd.xprt_resp = xprt_resp; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** + * tx_cmd_ch_remote_close_ack() - Convert a channel close ack cmd to wire format + * and transmit + * @if_ptr: The transport to transmit on. + * @rcid: The remote channel id to encode. + */ +static void tx_cmd_ch_remote_close_ack(struct glink_transport_if *if_ptr, + uint32_t rcid) +{ + struct command { + uint16_t id; + uint16_t rcid; + uint32_t reserved1; + uint64_t reserved2; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + + cmd.id = CLOSE_ACK_CMD; + cmd.rcid = rcid; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** + * ssr() - Process a subsystem restart notification of a transport + * @if_ptr: The transport to restart + * + * Return: 0 on success or standard Linux error code. + */ +static int ssr(struct glink_transport_if *if_ptr) +{ + struct edge_info *einfo; + + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + einfo->in_ssr = true; + wake_up_all(&einfo->tx_blocked_queue); + + synchronize_srcu(&einfo->use_ref); + einfo->tx_resume_needed = false; + einfo->tx_blocked_signal_sent = false; + einfo->tx_fifo_start = 0; + einfo->rx_fifo_start = 0; + einfo->fifo_size = DEFAULT_FIFO_SIZE; + einfo->xprt_if.glink_core_if_ptr->link_down(&einfo->xprt_if); + + return 0; +} + +/** + * allocate_rx_intent() - Allocate/reserve space for RX Intent + * @if_ptr: The transport the intent is associated with. + * @size: size of intent. + * @intent: Pointer to the intent structure. + * + * Assign "data" with the buffer created, since the transport creates + * a linear buffer and "iovec" with the "intent" itself, so that + * the data can be passed to a client that receives only vector buffer. + * Note that returning NULL for the pointer is valid (it means that space has + * been reserved, but the actual pointer will be provided later). + * + * Return: 0 on success or standard Linux error code. + */ +static int allocate_rx_intent(struct glink_transport_if *if_ptr, size_t size, + struct glink_core_rx_intent *intent) +{ + void *t; + + t = kzalloc(size, GFP_KERNEL); + if (!t) + return -ENOMEM; + + intent->data = t; + intent->iovec = (void *)intent; + intent->vprovider = rx_linear_vbuf_provider; + intent->pprovider = NULL; + return 0; +} + +/** + * deallocate_rx_intent() - Deallocate space created for RX Intent + * @if_ptr: The transport the intent is associated with. + * @intent: Pointer to the intent structure. + * + * Return: 0 on success or standard Linux error code. + */ +static int deallocate_rx_intent(struct glink_transport_if *if_ptr, + struct glink_core_rx_intent *intent) +{ + if (!intent || !intent->data) + return -EINVAL; + + kfree(intent->data); + intent->data = NULL; + intent->iovec = NULL; + intent->vprovider = NULL; + return 0; +} + +/** + * tx_cmd_local_rx_intent() - Convert an rx intent cmd to wire format and + * transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @size: The intent size to encode. + * @liid: The local intent id to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int tx_cmd_local_rx_intent(struct glink_transport_if *if_ptr, + uint32_t lcid, size_t size, uint32_t liid) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t count; + uint64_t reserved; + uint32_t size; + uint32_t liid; + uint64_t addr; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + if (size > UINT_MAX) { + pr_err("%s: size %zu is too large to encode\n", __func__, size); + return -EMSGSIZE; + } + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + cmd.id = RX_INTENT_CMD; + cmd.lcid = lcid; + cmd.count = 1; + cmd.size = size; + cmd.liid = liid; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + + srcu_read_unlock(&einfo->use_ref, rcu_id); + return 0; +} + +/** + * tx_cmd_local_rx_done() - Convert an rx done cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @liid: The local intent id to encode. + * @reuse: Reuse the consumed intent. + */ +static void tx_cmd_local_rx_done(struct glink_transport_if *if_ptr, + uint32_t lcid, uint32_t liid, bool reuse) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t liid; + uint64_t reserved; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + + cmd.id = reuse ? RX_DONE_W_REUSE_CMD : RX_DONE_CMD; + cmd.lcid = lcid; + cmd.liid = liid; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + srcu_read_unlock(&einfo->use_ref, rcu_id); +} + +/** + * tx_cmd_rx_intent_req() - Convert an rx intent request cmd to wire format and + * transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @size: The requested intent size to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int tx_cmd_rx_intent_req(struct glink_transport_if *if_ptr, + uint32_t lcid, size_t size) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t size; + uint64_t reserved; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + if (size > UINT_MAX) { + pr_err("%s: size %zu is too large to encode\n", __func__, size); + return -EMSGSIZE; + } + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + cmd.id = RX_INTENT_REQ_CMD, + cmd.lcid = lcid; + cmd.size = size; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + + srcu_read_unlock(&einfo->use_ref, rcu_id); + return 0; +} + +/** + * tx_cmd_rx_intent_req_ack() - Convert an rx intent request ack cmd to wire + * format and transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @granted: The request response to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int tx_cmd_remote_rx_intent_req_ack(struct glink_transport_if *if_ptr, + uint32_t lcid, bool granted) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t response; + uint64_t reserved; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + cmd.id = RX_INTENT_REQ_ACK_CMD, + cmd.lcid = lcid; + if (granted) + cmd.response = 1; + else + cmd.response = 0; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + + srcu_read_unlock(&einfo->use_ref, rcu_id); + return 0; +} + +/** + * tx_cmd_set_sigs() - Convert a signals ack cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int tx_cmd_set_sigs(struct glink_transport_if *if_ptr, uint32_t lcid, + uint32_t sigs) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t sigs; + uint64_t reserved; + }; + struct command cmd; + struct edge_info *einfo; + int rcu_id; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + cmd.id = SIGNALS_CMD, + cmd.lcid = lcid; + cmd.sigs = sigs; + + glink_spi_xprt_tx_cmd(einfo, &cmd, sizeof(cmd)); + + srcu_read_unlock(&einfo->use_ref, rcu_id); + return 0; +} + +/** + * tx_data() - convert a data/tracer_pkt to wire format and transmit + * @if_ptr: The transport to transmit on. + * @cmd_id: The command ID to transmit. + * @lcid: The local channel id to encode. + * @pctx: The data to encode. + * + * Return: Number of bytes written or standard Linux error code. + */ +static int tx_data(struct glink_transport_if *if_ptr, uint16_t cmd_id, + uint32_t lcid, struct glink_core_tx_pkt *pctx) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t riid; + uint64_t reserved; + uint32_t size; + uint32_t size_left; + uint64_t addr; + }; + struct command cmd; + struct edge_info *einfo; + uint32_t size; + void *data_start, *dst = NULL; + size_t tx_size = 0; + int rcu_id; + + if (pctx->size < pctx->size_remaining) { + GLINK_ERR("%s: size remaining exceeds size. Resetting.\n", + __func__); + pctx->size_remaining = pctx->size; + } + if (!pctx->size_remaining) + return 0; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + if (cmd_id == TX_DATA_CMD) { + if (pctx->size_remaining == pctx->size) + cmd.id = TX_DATA_CMD; + else + cmd.id = TX_DATA_CONT_CMD; + } else { + if (pctx->size_remaining == pctx->size) + cmd.id = TRACER_PKT_CMD; + else + cmd.id = TRACER_PKT_CONT_CMD; + } + cmd.lcid = lcid; + cmd.riid = pctx->riid; + data_start = get_tx_vaddr(pctx, pctx->size - pctx->size_remaining, + &tx_size); + if (unlikely(!data_start)) { + GLINK_ERR("%s: invalid data_start\n", __func__); + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EINVAL; + } + if (tx_size & (XPRT_ALIGNMENT - 1)) + tx_size = ALIGN(tx_size - SHORT_PKT_SIZE, XPRT_ALIGNMENT); + if (likely(pctx->cookie)) + dst = pctx->cookie + (pctx->size - pctx->size_remaining); + + mutex_lock(&einfo->write_lock); + size = glink_spi_xprt_write_avail(einfo); + /* Need enough space to write the command */ + if (size <= sizeof(cmd)) { + einfo->tx_resume_needed = true; + mutex_unlock(&einfo->write_lock); + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EAGAIN; + } + cmd.addr = 0; + cmd.size = tx_size; + pctx->size_remaining -= tx_size; + cmd.size_left = pctx->size_remaining; + if (cmd.id == TRACER_PKT_CMD) + tracer_pkt_log_event((void *)(pctx->data), GLINK_XPRT_TX); + + if (!strcmp(einfo->xprt_cfg.edge, "wdsp")) + wdsp_resume(&einfo->cmpnt); + glink_spi_xprt_tx_data(einfo, data_start, dst, tx_size); + glink_spi_xprt_tx_cmd_safe(einfo, &cmd, sizeof(cmd)); + GLINK_DBG("%s %s: lcid[%u] riid[%u] cmd[%d], size[%d], size_left[%d]\n", + "<SPI>", __func__, cmd.lcid, cmd.riid, cmd.id, cmd.size, + cmd.size_left); + mutex_unlock(&einfo->write_lock); + srcu_read_unlock(&einfo->use_ref, rcu_id); + return cmd.size; +} + +/** + * tx_short_data() - Tansmit a short packet in band along with command + * @if_ptr: The transport to transmit on. + * @cmd_id: The command ID to transmit. + * @lcid: The local channel id to encode. + * @pctx: The data to encode. + * + * Return: Number of bytes written or standard Linux error code. + */ +static int tx_short_data(struct glink_transport_if *if_ptr, + uint32_t lcid, struct glink_core_tx_pkt *pctx) +{ + struct command { + uint16_t id; + uint16_t lcid; + uint32_t riid; + uint32_t size; + uint32_t size_left; + unsigned char data[SHORT_PKT_SIZE]; + }; + struct command cmd; + struct edge_info *einfo; + uint32_t size; + void *data_start; + size_t tx_size = 0; + int rcu_id; + + if (pctx->size < pctx->size_remaining) { + GLINK_ERR("%s: size remaining exceeds size. Resetting.\n", + __func__); + pctx->size_remaining = pctx->size; + } + if (!pctx->size_remaining) + return 0; + + memset(&cmd, 0, sizeof(cmd)); + einfo = container_of(if_ptr, struct edge_info, xprt_if); + + rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EFAULT; + } + + cmd.id = TX_SHORT_DATA_CMD; + cmd.lcid = lcid; + cmd.riid = pctx->riid; + data_start = get_tx_vaddr(pctx, pctx->size - pctx->size_remaining, + &tx_size); + if (unlikely(!data_start || tx_size > SHORT_PKT_SIZE)) { + GLINK_ERR("%s: invalid data_start %p or tx_size %zu\n", + __func__, data_start, tx_size); + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EINVAL; + } + + mutex_lock(&einfo->write_lock); + size = glink_spi_xprt_write_avail(einfo); + /* Need enough space to write the command */ + if (size <= sizeof(cmd)) { + einfo->tx_resume_needed = true; + mutex_unlock(&einfo->write_lock); + srcu_read_unlock(&einfo->use_ref, rcu_id); + return -EAGAIN; + } + cmd.size = tx_size; + pctx->size_remaining -= tx_size; + cmd.size_left = pctx->size_remaining; + memcpy(cmd.data, data_start, tx_size); + if (!strcmp(einfo->xprt_cfg.edge, "wdsp")) + wdsp_resume(&einfo->cmpnt); + glink_spi_xprt_tx_cmd_safe(einfo, &cmd, sizeof(cmd)); + GLINK_DBG("%s %s: lcid[%u] riid[%u] cmd[%d], size[%d], size_left[%d]\n", + "<SPI>", __func__, cmd.lcid, cmd.riid, cmd.id, cmd.size, + cmd.size_left); + mutex_unlock(&einfo->write_lock); + srcu_read_unlock(&einfo->use_ref, rcu_id); + return cmd.size; +} + +/** + * tx() - convert a data transmit cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @pctx: The data to encode. + * + * Return: Number of bytes written or standard Linux error code. + */ +static int tx(struct glink_transport_if *if_ptr, uint32_t lcid, + struct glink_core_tx_pkt *pctx) +{ + if (pctx->size_remaining <= SHORT_PKT_SIZE) + return tx_short_data(if_ptr, lcid, pctx); + return tx_data(if_ptr, TX_DATA_CMD, lcid, pctx); +} + +/** + * tx_cmd_tracer_pkt() - convert a tracer packet cmd to wire format and transmit + * @if_ptr: The transport to transmit on. + * @lcid: The local channel id to encode. + * @pctx: The data to encode. + * + * Return: Number of bytes written or standard Linux error code. + */ +static int tx_cmd_tracer_pkt(struct glink_transport_if *if_ptr, uint32_t lcid, + struct glink_core_tx_pkt *pctx) +{ + return tx_data(if_ptr, TRACER_PKT_CMD, lcid, pctx); +} + +/** + * int wait_link_down() - Check status of read/write indices + * @if_ptr: The transport to check + * + * Return: 1 if indices are all zero, 0 otherwise + */ +static int wait_link_down(struct glink_transport_if *if_ptr) +{ + return 0; +} + +/** + * get_power_vote_ramp_time() - Get the ramp time required for the power + * votes to be applied + * @if_ptr: The transport interface on which power voting is requested. + * @state: The power state for which ramp time is required. + * + * Return: The ramp time specific to the power state, standard error otherwise. + */ +static unsigned long get_power_vote_ramp_time( + struct glink_transport_if *if_ptr, uint32_t state) +{ + return 0; +} + +/** + * power_vote() - Update the power votes to meet qos requirement + * @if_ptr: The transport interface on which power voting is requested. + * @state: The power state for which the voting should be done. + * + * Return: 0 on Success, standard error otherwise. + */ +static int power_vote(struct glink_transport_if *if_ptr, uint32_t state) +{ + unsigned long flags; + struct edge_info *einfo; + + einfo = container_of(if_ptr, struct edge_info, xprt_if); + spin_lock_irqsave(&einfo->activity_lock, flags); + einfo->activity_flag |= ACTIVE_TX; + spin_unlock_irqrestore(&einfo->activity_lock, flags); + return 0; +} + +/** + * power_unvote() - Remove the all the power votes + * @if_ptr: The transport interface on which power voting is requested. + * + * Return: 0 on Success, standard error otherwise. + */ +static int power_unvote(struct glink_transport_if *if_ptr) +{ + unsigned long flags; + struct edge_info *einfo; + + einfo = container_of(if_ptr, struct edge_info, xprt_if); + spin_lock_irqsave(&einfo->activity_lock, flags); + einfo->activity_flag &= ~ACTIVE_TX; + spin_unlock_irqrestore(&einfo->activity_lock, flags); + return 0; +} + +static int glink_wdsp_cmpnt_init(struct device *dev, void *priv_data) +{ + return 0; +} + +static int glink_wdsp_cmpnt_deinit(struct device *dev, void *priv_data) +{ + return 0; +} + +static int glink_wdsp_cmpnt_event_handler(struct device *dev, + void *priv_data, enum wdsp_event_type event, void *data) +{ + struct edge_info *einfo = dev_get_drvdata(dev); + struct glink_cmpnt *cmpnt = &einfo->cmpnt; + struct device *sdev; + struct spi_device *spi_dev; + + switch (event) { + case WDSP_EVENT_PRE_BOOTUP: + if (cmpnt && cmpnt->master_dev && + cmpnt->master_ops && + cmpnt->master_ops->get_dev_for_cmpnt) + sdev = cmpnt->master_ops->get_dev_for_cmpnt( + cmpnt->master_dev, WDSP_CMPNT_TRANSPORT); + else + sdev = NULL; + + if (!sdev) { + dev_err(dev, "%s: Failed to get transport device\n", + __func__); + break; + } + + spi_dev = to_spi_device(sdev); + einfo->spi_dev = spi_dev; + break; + case WDSP_EVENT_IPC1_INTR: + queue_kthread_work(&einfo->kworker, &einfo->kwork); + break; + default: + pr_debug("%s: unhandled event %d", __func__, event); + break; + } + + return 0; +} + +/* glink_wdsp_cmpnt_ops - Callback operations registered wtih WDSP framework */ +static struct wdsp_cmpnt_ops glink_wdsp_cmpnt_ops = { + .init = glink_wdsp_cmpnt_init, + .deinit = glink_wdsp_cmpnt_deinit, + .event_handler = glink_wdsp_cmpnt_event_handler, +}; + +static int glink_component_bind(struct device *dev, struct device *master, + void *data) +{ + struct edge_info *einfo = dev_get_drvdata(dev); + struct glink_cmpnt *cmpnt = &einfo->cmpnt; + int ret = 0; + + cmpnt->master_dev = master; + cmpnt->master_ops = data; + + if (cmpnt->master_ops && cmpnt->master_ops->register_cmpnt_ops) + ret = cmpnt->master_ops->register_cmpnt_ops(master, dev, einfo, + &glink_wdsp_cmpnt_ops); + else + ret = -EINVAL; + + if (ret) + dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n", + __func__, ret); + return ret; +} + +static void glink_component_unbind(struct device *dev, struct device *master, + void *data) +{ + struct edge_info *einfo = dev_get_drvdata(dev); + struct glink_cmpnt *cmpnt = &einfo->cmpnt; + + cmpnt->master_dev = NULL; + cmpnt->master_ops = NULL; +} + +static const struct component_ops glink_component_ops = { + .bind = glink_component_bind, + .unbind = glink_component_unbind, +}; + +/** + * init_xprt_if() - Initialize the xprt_if for an edge + * @einfo: The edge to initialize. + */ +static void init_xprt_if(struct edge_info *einfo) +{ + einfo->xprt_if.tx_cmd_version = tx_cmd_version; + einfo->xprt_if.tx_cmd_version_ack = tx_cmd_version_ack; + einfo->xprt_if.set_version = set_version; + einfo->xprt_if.tx_cmd_ch_open = tx_cmd_ch_open; + einfo->xprt_if.tx_cmd_ch_close = tx_cmd_ch_close; + einfo->xprt_if.tx_cmd_ch_remote_open_ack = tx_cmd_ch_remote_open_ack; + einfo->xprt_if.tx_cmd_ch_remote_close_ack = tx_cmd_ch_remote_close_ack; + einfo->xprt_if.ssr = ssr; + einfo->xprt_if.allocate_rx_intent = allocate_rx_intent; + einfo->xprt_if.deallocate_rx_intent = deallocate_rx_intent; + einfo->xprt_if.tx_cmd_local_rx_intent = tx_cmd_local_rx_intent; + einfo->xprt_if.tx_cmd_local_rx_done = tx_cmd_local_rx_done; + einfo->xprt_if.tx = tx; + einfo->xprt_if.tx_cmd_rx_intent_req = tx_cmd_rx_intent_req; + einfo->xprt_if.tx_cmd_remote_rx_intent_req_ack = + tx_cmd_remote_rx_intent_req_ack; + einfo->xprt_if.tx_cmd_set_sigs = tx_cmd_set_sigs; + einfo->xprt_if.wait_link_down = wait_link_down; + einfo->xprt_if.tx_cmd_tracer_pkt = tx_cmd_tracer_pkt; + einfo->xprt_if.get_power_vote_ramp_time = get_power_vote_ramp_time; + einfo->xprt_if.power_vote = power_vote; + einfo->xprt_if.power_unvote = power_unvote; +} + +/** + * init_xprt_cfg() - Initialize the xprt_cfg for an edge + * @einfo: The edge to initialize. + * @name: The name of the remote side this edge communicates to. + */ +static void init_xprt_cfg(struct edge_info *einfo, const char *name) +{ + einfo->xprt_cfg.name = XPRT_NAME; + einfo->xprt_cfg.edge = name; + einfo->xprt_cfg.versions = versions; + einfo->xprt_cfg.versions_entries = ARRAY_SIZE(versions); + einfo->xprt_cfg.max_cid = SZ_64K; + einfo->xprt_cfg.max_iid = SZ_2G; +} + +/** + * parse_qos_dt_params() - Parse the power states from DT + * @dev: Reference to the platform device for a specific edge. + * @einfo: Edge information for the edge probe function is called. + * + * Return: 0 on success, standard error code otherwise. + */ +static int parse_qos_dt_params(struct device_node *node, + struct edge_info *einfo) +{ + int rc; + int i; + char *key; + uint32_t *arr32; + uint32_t num_states; + + key = "qcom,ramp-time"; + if (!of_find_property(node, key, &num_states)) + return -ENODEV; + + num_states /= sizeof(uint32_t); + + einfo->num_pw_states = num_states; + + arr32 = kmalloc_array(num_states, sizeof(uint32_t), GFP_KERNEL); + if (!arr32) + return -ENOMEM; + + einfo->ramp_time_us = kmalloc_array(num_states, sizeof(unsigned long), + GFP_KERNEL); + if (!einfo->ramp_time_us) { + rc = -ENOMEM; + goto mem_alloc_fail; + } + + rc = of_property_read_u32_array(node, key, arr32, num_states); + if (rc) { + rc = -ENODEV; + goto invalid_key; + } + for (i = 0; i < num_states; i++) + einfo->ramp_time_us[i] = arr32[i]; + + kfree(arr32); + return 0; + +invalid_key: + kfree(einfo->ramp_time_us); +mem_alloc_fail: + kfree(arr32); + return rc; +} + +/** + * parse_qos_dt_params() - Parse any remote FIFO configuration + * @node: Reference to the platform device for a specific edge. + * @einfo: Edge information for the edge probe function is called. + * + * Return: 0 on success, standard error code otherwise. + */ +static int parse_remote_fifo_cfg(struct device_node *node, + struct edge_info *einfo) +{ + int rc; + char *key; + + key = "qcom,out-read-idx-reg"; + rc = of_property_read_u32(node, key, &einfo->tx_fifo_read_reg_addr); + if (rc) + goto key_error; + + key = "qcom,out-write-idx-reg"; + rc = of_property_read_u32(node, key, &einfo->tx_fifo_write_reg_addr); + if (rc) + goto key_error; + + key = "qcom,in-read-idx-reg"; + rc = of_property_read_u32(node, key, &einfo->rx_fifo_read_reg_addr); + if (rc) + goto key_error; + + key = "qcom,in-write-idx-reg"; + rc = of_property_read_u32(node, key, &einfo->rx_fifo_write_reg_addr); + if (rc) + goto key_error; + return 0; + +key_error: + pr_err("%s: Error %d parsing key %s\n", __func__, rc, key); + return rc; +} + +static int glink_spi_probe(struct platform_device *pdev) +{ + struct device_node *node; + struct device_node *phandle_node; + struct edge_info *einfo; + int rc; + char *key; + const char *subsys_name; + unsigned long flags; + + node = pdev->dev.of_node; + + einfo = kzalloc(sizeof(*einfo), GFP_KERNEL); + if (!einfo) { + rc = -ENOMEM; + goto edge_info_alloc_fail; + } + + key = "label"; + subsys_name = of_get_property(node, key, NULL); + if (!subsys_name) { + pr_err("%s: missing key %s\n", __func__, key); + rc = -ENODEV; + goto missing_key; + } + strlcpy(einfo->subsys_name, subsys_name, sizeof(einfo->subsys_name)); + + init_xprt_cfg(einfo, subsys_name); + init_xprt_if(einfo); + + einfo->in_ssr = true; + einfo->fifo_size = DEFAULT_FIFO_SIZE; + init_kthread_work(&einfo->kwork, rx_worker); + init_kthread_worker(&einfo->kworker); + init_srcu_struct(&einfo->use_ref); + mutex_init(&einfo->write_lock); + init_waitqueue_head(&einfo->tx_blocked_queue); + spin_lock_init(&einfo->activity_lock); + + spin_lock_irqsave(&edge_infos_lock, flags); + list_add_tail(&einfo->list, &edge_infos); + spin_unlock_irqrestore(&edge_infos_lock, flags); + + einfo->task = kthread_run(kthread_worker_fn, &einfo->kworker, + "spi_%s", subsys_name); + if (IS_ERR(einfo->task)) { + rc = PTR_ERR(einfo->task); + pr_err("%s: kthread run failed %d\n", __func__, rc); + goto kthread_fail; + } + + key = "qcom,remote-fifo-config"; + phandle_node = of_parse_phandle(node, key, 0); + if (phandle_node) + parse_remote_fifo_cfg(phandle_node, einfo); + + key = "qcom,qos-config"; + phandle_node = of_parse_phandle(node, key, 0); + if (phandle_node && !(of_get_glink_core_qos_cfg(phandle_node, + &einfo->xprt_cfg))) + parse_qos_dt_params(node, einfo); + + rc = glink_core_register_transport(&einfo->xprt_if, &einfo->xprt_cfg); + if (rc == -EPROBE_DEFER) + goto reg_xprt_fail; + if (rc) { + pr_err("%s: glink core register transport failed: %d\n", + __func__, rc); + goto reg_xprt_fail; + } + + dev_set_drvdata(&pdev->dev, einfo); + if (!strcmp(einfo->xprt_cfg.edge, "wdsp")) { + rc = component_add(&pdev->dev, &glink_component_ops); + if (rc) { + pr_err("%s: component_add failed, err = %d\n", + __func__, rc); + rc = -ENODEV; + goto reg_cmpnt_fail; + } + } + return 0; + +reg_cmpnt_fail: + dev_set_drvdata(&pdev->dev, NULL); + glink_core_unregister_transport(&einfo->xprt_if); +reg_xprt_fail: + flush_kthread_worker(&einfo->kworker); + kthread_stop(einfo->task); + einfo->task = NULL; +kthread_fail: + spin_lock_irqsave(&edge_infos_lock, flags); + list_del(&einfo->list); + spin_unlock_irqrestore(&edge_infos_lock, flags); +missing_key: + kfree(einfo); +edge_info_alloc_fail: + return rc; +} + +static int glink_spi_remove(struct platform_device *pdev) +{ + struct edge_info *einfo; + unsigned long flags; + + einfo = (struct edge_info *)dev_get_drvdata(&pdev->dev); + glink_core_unregister_transport(&einfo->xprt_if); + flush_kthread_worker(&einfo->kworker); + kthread_stop(einfo->task); + einfo->task = NULL; + spin_lock_irqsave(&edge_infos_lock, flags); + list_del(&einfo->list); + spin_unlock_irqrestore(&edge_infos_lock, flags); + kfree(einfo); + return 0; +} + +static int glink_spi_resume(struct platform_device *pdev) +{ + return 0; +} + +static int glink_spi_suspend(struct platform_device *pdev, + pm_message_t state) +{ + unsigned long flags; + struct edge_info *einfo; + bool suspend; + int rc = -EBUSY; + + einfo = (struct edge_info *)dev_get_drvdata(&pdev->dev); + if (strcmp(einfo->xprt_cfg.edge, "wdsp")) + return 0; + + spin_lock_irqsave(&einfo->activity_lock, flags); + suspend = !(einfo->activity_flag); + spin_unlock_irqrestore(&einfo->activity_lock, flags); + if (suspend) + rc = wdsp_suspend(&einfo->cmpnt); + if (rc < 0) + pr_err("%s: Could not suspend activity_flag %d, rc %d\n", + __func__, einfo->activity_flag, rc); + return rc; +} + +static const struct of_device_id spi_match_table[] = { + { .compatible = "qcom,glink-spi-xprt" }, + {}, +}; + +static struct platform_driver glink_spi_driver = { + .probe = glink_spi_probe, + .remove = glink_spi_remove, + .resume = glink_spi_resume, + .suspend = glink_spi_suspend, + .driver = { + .name = "msm_glink_spi_xprt", + .owner = THIS_MODULE, + .of_match_table = spi_match_table, + }, +}; + +static int __init glink_spi_xprt_init(void) +{ + int rc; + + rc = platform_driver_register(&glink_spi_driver); + if (rc) + pr_err("%s: glink_spi register failed %d\n", __func__, rc); + + return rc; +} +module_init(glink_spi_xprt_init); + +static void __exit glink_spi_xprt_exit(void) +{ + platform_driver_unregister(&glink_spi_driver); +} +module_exit(glink_spi_xprt_exit); + +MODULE_DESCRIPTION("MSM G-Link SPI Transport"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/glink_xprt_if.h b/drivers/soc/qcom/glink_xprt_if.h index 6242e867fe72..f4d5a3b303db 100644 --- a/drivers/soc/qcom/glink_xprt_if.h +++ b/drivers/soc/qcom/glink_xprt_if.h @@ -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 @@ -28,6 +28,7 @@ enum buf_type { enum xprt_ids { SMEM_XPRT_ID = 100, + SPIV2_XPRT_ID = SMEM_XPRT_ID, SMD_TRANS_XPRT_ID = 200, LLOOP_XPRT_ID = 300, MOCK_XPRT_HIGH_ID = 390, @@ -56,6 +57,7 @@ enum xprt_ids { * @iovec: Pointer to the vector buffer packet. * @vprovider: Packet-specific virtual buffer provider function. * @pprovider: Packet-specific physical buffer provider function. + * @cookie: Transport-specific cookie * @pkt_ref: Active references to the packet. */ struct glink_core_tx_pkt { @@ -73,6 +75,7 @@ struct glink_core_tx_pkt { void *iovec; void * (*vprovider)(void *iovec, size_t offset, size_t *size); void * (*pprovider)(void *iovec, size_t offset, size_t *size); + void *cookie; struct rwref_lock pkt_ref; }; diff --git a/drivers/soc/qcom/irq-helper.c b/drivers/soc/qcom/irq-helper.c index 270a1ba9ba19..2bb71464d165 100644 --- a/drivers/soc/qcom/irq-helper.c +++ b/drivers/soc/qcom/irq-helper.c @@ -18,6 +18,7 @@ #include <linux/kobject.h> #include <linux/spinlock.h> #include <linux/slab.h> +#include <soc/qcom/irq-helper.h> struct irq_helper { bool enable; @@ -161,7 +162,7 @@ static int __init irq_helper_init(void) irq_h->enable = true; return 0; out_put_kobj: - koject_put(&irq_h->kobj); + kobject_put(&irq_h->kobj); out_free_irq: kfree(irq_h); return ret; diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index b055234326b6..eaeb8d4776fe 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -813,15 +813,19 @@ int pil_boot(struct pil_desc *desc) } if (desc->subsys_vmid > 0) { - /* Make sure the memory is actually assigned to Linux. In the - * case where the shutdown sequence is not able to immediately - * assign the memory back to Linux, we need to do this here. */ - ret = pil_assign_mem_to_linux(desc, priv->region_start, + /** + * In case of modem ssr, we need to assign memory back to linux. + * This is not true after cold boot since linux already owns it. + * Also for secure boot devices, modem memory has to be released + * after MBA is booted + */ + if (desc->modem_ssr) { + ret = pil_assign_mem_to_linux(desc, priv->region_start, (priv->region_end - priv->region_start)); - if (ret) - pil_err(desc, "Failed to assign to linux, ret - %d\n", + if (ret) + pil_err(desc, "Failed to assign to linux, ret- %d\n", ret); - + } ret = pil_assign_mem_to_subsys_and_linux(desc, priv->region_start, (priv->region_end - priv->region_start)); @@ -857,6 +861,7 @@ int pil_boot(struct pil_desc *desc) goto err_auth_and_reset; } pil_info(desc, "Brought out of reset\n"); + desc->modem_ssr = false; err_auth_and_reset: if (ret && desc->subsys_vmid > 0) { pil_assign_mem_to_linux(desc, priv->region_start, @@ -917,6 +922,7 @@ void pil_shutdown(struct pil_desc *desc) pil_proxy_unvote(desc, 1); else flush_delayed_work(&priv->proxy); + desc->modem_ssr = true; } EXPORT_SYMBOL(pil_shutdown); diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h index c3689faf0034..802abe26a960 100644 --- a/drivers/soc/qcom/peripheral-loader.h +++ b/drivers/soc/qcom/peripheral-loader.h @@ -36,6 +36,7 @@ struct pil_priv; * @unmap_fw_mem: Custom function used to undo mapping by map_fw_mem. * This defaults to iounmap if not specified. * @shutdown_fail: Set if PIL op for shutting down subsystem fails. + * @modem_ssr: true if modem is restarting, false if booting for first time. * @subsys_vmid: memprot id for the subsystem. */ struct pil_desc { @@ -54,6 +55,7 @@ struct pil_desc { void (*unmap_fw_mem)(void *virt, size_t size, void *data); void *map_data; bool shutdown_fail; + bool modem_ssr; u32 subsys_vmid; }; diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c index af9cd189cf6d..31a5ae89174e 100644 --- a/drivers/soc/qcom/pil-q6v5-mss.c +++ b/drivers/soc/qcom/pil-q6v5-mss.c @@ -214,6 +214,7 @@ static int pil_subsys_init(struct modem_data *drv, drv->subsys_desc.stop_ack_handler = modem_stop_ack_intr_handler; drv->subsys_desc.wdog_bite_handler = modem_wdog_bite_intr_handler; + drv->q6->desc.modem_ssr = false; drv->subsys = subsys_register(&drv->subsys_desc); if (IS_ERR(drv->subsys)) { ret = PTR_ERR(drv->subsys); 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/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/configfs.c b/drivers/usb/gadget/configfs.c index 3639890c0dc7..5db4fe9e3cdf 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1738,7 +1738,10 @@ void unregister_gadget_item(struct config_item *item) { struct gadget_info *gi = to_gadget_info(item); + /* to protect race with gadget_dev_desc_UDC_store*/ + mutex_lock(&gi->lock); unregister_gadget(gi); + mutex_unlock(&gi->lock); } EXPORT_SYMBOL_GPL(unregister_gadget_item); 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/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 48f987d77e91..c5fd3ce3ed9a 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -24,6 +24,7 @@ #include <linux/hid.h> #include <linux/module.h> #include <linux/uio.h> +#include <linux/ipc_logging.h> #include <asm/unaligned.h> #include <linux/usb/composite.h> @@ -41,6 +42,15 @@ #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ +#define NUM_PAGES 10 /* # of pages for ipc logging */ + +static void *ffs_ipc_log; +#define ffs_log(fmt, ...) do { \ + ipc_log_string(ffs_ipc_log, "%s: " fmt, __func__, \ + ##__VA_ARGS__); \ + pr_debug(fmt, ##__VA_ARGS__); \ +} while (0) + /* Reference counter handling */ static void ffs_data_get(struct ffs_data *ffs); static void ffs_data_put(struct ffs_data *ffs); @@ -214,6 +224,9 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) spin_unlock_irq(&ffs->ev.waitq.lock); + ffs_log("enter: state %d setup_state %d flags %lu", ffs->state, + ffs->setup_state, ffs->flags); + req->buf = data; req->length = len; @@ -238,11 +251,18 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) } ffs->setup_state = FFS_NO_SETUP; + + ffs_log("exit: state %d setup_state %d flags %lu", ffs->state, + ffs->setup_state, ffs->flags); + return req->status ? req->status : req->actual; } static int __ffs_ep0_stall(struct ffs_data *ffs) { + ffs_log("state %d setup_state %d flags %lu can_stall %d", ffs->state, + ffs->setup_state, ffs->flags, ffs->ev.can_stall); + if (ffs->ev.can_stall) { pr_vdebug("ep0 stall\n"); usb_ep_set_halt(ffs->gadget->ep0); @@ -263,6 +283,9 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ENTER(); + ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, + ffs->state, ffs->setup_state, ffs->flags); + /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -391,6 +414,9 @@ done_spin: break; } + ffs_log("exit:ret %zu state %d setup_state %d flags %lu", ret, + ffs->state, ffs->setup_state, ffs->flags); + mutex_unlock(&ffs->mutex); return ret; } @@ -424,6 +450,10 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, ffs->ev.count * sizeof *ffs->ev.types); spin_unlock_irq(&ffs->ev.waitq.lock); + + ffs_log("state %d setup_state %d flags %lu #evt %zu", ffs->state, + ffs->setup_state, ffs->flags, n); + mutex_unlock(&ffs->mutex); return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size; @@ -439,6 +469,9 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, ENTER(); + ffs_log("enter:len %zu state %d setup_state %d flags %lu", len, + ffs->state, ffs->setup_state, ffs->flags); + /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -527,8 +560,12 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, spin_unlock_irq(&ffs->ev.waitq.lock); done_mutex: + ffs_log("exit:ret %d state %d setup_state %d flags %lu", ret, + ffs->state, ffs->setup_state, ffs->flags); + mutex_unlock(&ffs->mutex); kfree(data); + return ret; } @@ -538,6 +575,9 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) ENTER(); + ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, + ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + if (unlikely(ffs->state == FFS_CLOSING)) return -EBUSY; @@ -557,6 +597,9 @@ static int ffs_ep0_release(struct inode *inode, struct file *file) ENTER(); + ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, + ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + ffs_data_closed(ffs); return 0; @@ -570,6 +613,9 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) ENTER(); + ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, + ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + if (code == FUNCTIONFS_INTERFACE_REVMAP) { struct ffs_function *func = ffs->func; ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; @@ -588,6 +634,9 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) unsigned int mask = POLLWRNORM; int ret; + ffs_log("enter:state %d setup_state %d flags %lu opened %d", ffs->state, + ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + poll_wait(file, &ffs->ev.waitq, wait); ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); @@ -618,6 +667,8 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) break; } + ffs_log("exit: mask %u", mask); + mutex_unlock(&ffs->mutex); return mask; @@ -648,6 +699,7 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) ep->status = req->status ? req->status : req->actual; /* Set is_busy false to indicate completion of last request */ ep->is_busy = false; + ffs_log("ep status %d for req %p", ep->status, req); complete(req->context); } } @@ -659,6 +711,8 @@ static void ffs_user_copy_worker(struct work_struct *work) int ret = io_data->req->status ? io_data->req->status : io_data->req->actual; + ffs_log("enter: ret %d", ret); + if (io_data->read && ret > 0) { use_mm(io_data->mm); ret = copy_to_iter(io_data->buf, ret, &io_data->data); @@ -680,6 +734,8 @@ static void ffs_user_copy_worker(struct work_struct *work) kfree(io_data->to_free); kfree(io_data->buf); kfree(io_data); + + ffs_log("exit"); } static void ffs_epfile_async_io_complete(struct usb_ep *_ep, @@ -689,8 +745,12 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, ENTER(); + ffs_log("enter"); + INIT_WORK(&io_data->work, ffs_user_copy_worker); schedule_work(&io_data->work); + + ffs_log("exit"); } static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) @@ -701,6 +761,9 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ssize_t ret, data_len = -EINVAL; int halt; + ffs_log("enter: epfile name %s epfile err %d", epfile->name, + atomic_read(&epfile->error)); + smp_mb__before_atomic(); if (atomic_read(&epfile->error)) return -ENODEV; @@ -927,6 +990,9 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) } mutex_unlock(&epfile->mutex); + + ffs_log("exit:ret %zu", ret); + return ret; error_lock: @@ -934,6 +1000,9 @@ error_lock: mutex_unlock(&epfile->mutex); error: kfree(data); + + ffs_log("exit: ret %zu", ret); + return ret; } @@ -944,6 +1013,9 @@ ffs_epfile_open(struct inode *inode, struct file *file) ENTER(); + ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, + epfile->ffs->setup_state, epfile->ffs->flags); + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -962,6 +1034,9 @@ ffs_epfile_open(struct inode *inode, struct file *file) smp_mb__before_atomic(); atomic_set(&epfile->error, 0); + ffs_log("exit:state %d setup_state %d flag %lu", epfile->ffs->state, + epfile->ffs->setup_state, epfile->ffs->flags); + return 0; } @@ -973,6 +1048,9 @@ static int ffs_aio_cancel(struct kiocb *kiocb) ENTER(); + ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, + epfile->ffs->setup_state, epfile->ffs->flags); + spin_lock_irq(&epfile->ffs->eps_lock); if (likely(io_data && io_data->ep && io_data->req)) @@ -982,6 +1060,8 @@ static int ffs_aio_cancel(struct kiocb *kiocb) spin_unlock_irq(&epfile->ffs->eps_lock); + ffs_log("exit: value %d", value); + return value; } @@ -992,6 +1072,8 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) ENTER(); + ffs_log("enter"); + if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) @@ -1018,6 +1100,9 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) kfree(p); else *from = p->data; + + ffs_log("exit"); + return res; } @@ -1028,6 +1113,8 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) ENTER(); + ffs_log("enter"); + if (!is_sync_kiocb(kiocb)) { p = kmalloc(sizeof(io_data), GFP_KERNEL); if (unlikely(!p)) @@ -1066,6 +1153,9 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) } else { *to = p->data; } + + ffs_log("enter"); + return res; } @@ -1076,12 +1166,17 @@ ffs_epfile_release(struct inode *inode, struct file *file) ENTER(); + ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, + epfile->ffs->setup_state, epfile->ffs->flags); + smp_mb__before_atomic(); atomic_set(&epfile->opened, 0); atomic_set(&epfile->error, 1); ffs_data_closed(epfile->ffs); file->private_data = NULL; + ffs_log("exit"); + return 0; } @@ -1093,6 +1188,9 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, ENTER(); + ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, + epfile->ffs->setup_state, epfile->ffs->flags); + if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1143,6 +1241,8 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, } spin_unlock_irq(&epfile->ffs->eps_lock); + ffs_log("exit:ret %d", ret); + return ret; } @@ -1174,6 +1274,8 @@ ffs_sb_make_inode(struct super_block *sb, void *data, ENTER(); + ffs_log("enter"); + inode = new_inode(sb); if (likely(inode)) { @@ -1193,6 +1295,8 @@ ffs_sb_make_inode(struct super_block *sb, void *data, inode->i_op = iops; } + ffs_log("exit"); + return inode; } @@ -1207,6 +1311,8 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb, ENTER(); + ffs_log("enter"); + dentry = d_alloc_name(sb->s_root, name); if (unlikely(!dentry)) return NULL; @@ -1218,6 +1324,9 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb, } d_add(dentry, inode); + + ffs_log("exit"); + return dentry; } @@ -1243,6 +1352,8 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) ENTER(); + ffs_log("enter"); + ffs->sb = sb; data->ffs_data = NULL; sb->s_fs_info = ffs; @@ -1267,6 +1378,8 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) &ffs_ep0_operations))) return -ENOMEM; + ffs_log("exit"); + return 0; } @@ -1274,6 +1387,8 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) { ENTER(); + ffs_log("enter"); + if (!opts || !*opts) return 0; @@ -1356,6 +1471,8 @@ invalid: opts = comma + 1; } + ffs_log("exit"); + return 0; } @@ -1381,6 +1498,8 @@ ffs_fs_mount(struct file_system_type *t, int flags, ENTER(); + ffs_log("enter"); + ret = ffs_fs_parse_opts(&data, opts); if (unlikely(ret < 0)) return ERR_PTR(ret); @@ -1410,6 +1529,9 @@ ffs_fs_mount(struct file_system_type *t, int flags, ffs_release_dev(data.ffs_data); ffs_data_put(data.ffs_data); } + + ffs_log("exit"); + return rv; } @@ -1418,12 +1540,16 @@ ffs_fs_kill_sb(struct super_block *sb) { ENTER(); + ffs_log("enter"); + kill_litter_super(sb); if (sb->s_fs_info) { ffs_release_dev(sb->s_fs_info); ffs_data_closed(sb->s_fs_info); ffs_data_put(sb->s_fs_info); } + + ffs_log("exit"); } static struct file_system_type ffs_fs_type = { @@ -1449,6 +1575,8 @@ static int functionfs_init(void) else pr_err("failed registering file system (%d)\n", ret); + ffs_ipc_log = ipc_log_context_create(NUM_PAGES, "f_fs", 0); + return ret; } @@ -1470,14 +1598,21 @@ static void ffs_data_get(struct ffs_data *ffs) { ENTER(); + ffs_log("enter"); + smp_mb__before_atomic(); atomic_inc(&ffs->ref); + + ffs_log("exit"); } static void ffs_data_opened(struct ffs_data *ffs) { ENTER(); + ffs_log("enter: state %d setup_state %d flag %lu opened %d", ffs->state, + ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + smp_mb__before_atomic(); atomic_inc(&ffs->ref); if (atomic_add_return(1, &ffs->opened) == 1 && @@ -1485,12 +1620,17 @@ static void ffs_data_opened(struct ffs_data *ffs) ffs->state = FFS_CLOSING; ffs_data_reset(ffs); } + + ffs_log("exit: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); } static void ffs_data_put(struct ffs_data *ffs) { ENTER(); + ffs_log("enter"); + smp_mb__before_atomic(); if (unlikely(atomic_dec_and_test(&ffs->ref))) { pr_info("%s(): freeing\n", __func__); @@ -1500,12 +1640,17 @@ static void ffs_data_put(struct ffs_data *ffs) kfree(ffs->dev_name); kfree(ffs); } + + ffs_log("exit"); } static void ffs_data_closed(struct ffs_data *ffs) { ENTER(); + ffs_log("enter: state %d setup_state %d flag %lu opened %d", ffs->state, + ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); + smp_mb__before_atomic(); if (atomic_dec_and_test(&ffs->opened)) { if (ffs->no_disconnect) { @@ -1529,6 +1674,9 @@ static void ffs_data_closed(struct ffs_data *ffs) ffs_data_reset(ffs); } + ffs_log("exit: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + ffs_data_put(ffs); } @@ -1540,6 +1688,8 @@ static struct ffs_data *ffs_data_new(void) ENTER(); + ffs_log("enter"); + atomic_set(&ffs->ref, 1); atomic_set(&ffs->opened, 0); ffs->state = FFS_READ_DESCRIPTORS; @@ -1553,6 +1703,8 @@ static struct ffs_data *ffs_data_new(void) /* XXX REVISIT need to update it in some places, or do we? */ ffs->ev.can_stall = 1; + ffs_log("exit"); + return ffs; } @@ -1560,6 +1712,9 @@ static void ffs_data_clear(struct ffs_data *ffs) { ENTER(); + ffs_log("enter: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + pr_debug("%s: ffs->gadget= %p, ffs->flags= %lu\n", __func__, ffs->gadget, ffs->flags); ffs_closed(ffs); @@ -1578,12 +1733,18 @@ static void ffs_data_clear(struct ffs_data *ffs) kfree(ffs->raw_descs_data); kfree(ffs->raw_strings); kfree(ffs->stringtabs); + + ffs_log("exit: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); } static void ffs_data_reset(struct ffs_data *ffs) { ENTER(); + ffs_log("enter: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + ffs_data_clear(ffs); ffs->epfiles = NULL; @@ -1606,6 +1767,9 @@ static void ffs_data_reset(struct ffs_data *ffs) ffs->state = FFS_READ_DESCRIPTORS; ffs->setup_state = FFS_NO_SETUP; ffs->flags = 0; + + ffs_log("exit: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); } @@ -1616,6 +1780,9 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) ENTER(); + ffs_log("enter: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + if (WARN_ON(ffs->state != FFS_ACTIVE || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) return -EBADFD; @@ -1641,6 +1808,10 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) } ffs->gadget = cdev->gadget; + + ffs_log("exit: state %d setup_state %d flag %lu gadget %p\n", + ffs->state, ffs->setup_state, ffs->flags, ffs->gadget); + ffs_data_get(ffs); return 0; } @@ -1654,6 +1825,8 @@ static void functionfs_unbind(struct ffs_data *ffs) ffs->ep0req = NULL; ffs->gadget = NULL; clear_bit(FFS_FL_BOUND, &ffs->flags); + ffs_log("state %d setup_state %d flag %lu gadget %p\n", + ffs->state, ffs->setup_state, ffs->flags, ffs->gadget); ffs_data_put(ffs); } } @@ -1665,6 +1838,9 @@ static int ffs_epfiles_create(struct ffs_data *ffs) ENTER(); + ffs_log("enter: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + count = ffs->eps_count; epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); if (!epfiles) @@ -1690,6 +1866,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs) } ffs->epfiles = epfiles; + + ffs_log("exit: epfile name %s state %d setup_state %d flag %lu", + epfile->name, ffs->state, ffs->setup_state, ffs->flags); + return 0; } @@ -1699,6 +1879,8 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) ENTER(); + ffs_log("enter: epfilename %s", epfile->name); + for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex) || waitqueue_active(&epfile->wait)); @@ -1710,6 +1892,8 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) } kfree(epfiles); + + ffs_log("exit"); } static void ffs_func_eps_disable(struct ffs_function *func) @@ -1719,6 +1903,9 @@ static void ffs_func_eps_disable(struct ffs_function *func) unsigned count = func->ffs->eps_count; unsigned long flags; + ffs_log("enter: state %d setup_state %d flag %lu", func->ffs->state, + func->ffs->setup_state, func->ffs->flags); + spin_lock_irqsave(&func->ffs->eps_lock, flags); do { @@ -1738,6 +1925,8 @@ static void ffs_func_eps_disable(struct ffs_function *func) } } while (--count); spin_unlock_irqrestore(&func->ffs->eps_lock, flags); + + ffs_log("exit"); } static int ffs_func_eps_enable(struct ffs_function *func) @@ -1749,6 +1938,9 @@ static int ffs_func_eps_enable(struct ffs_function *func) unsigned long flags; int ret = 0; + ffs_log("enter: state %d setup_state %d flag %lu", func->ffs->state, + func->ffs->setup_state, func->ffs->flags); + spin_lock_irqsave(&func->ffs->eps_lock, flags); do { struct usb_endpoint_descriptor *ds; @@ -1786,6 +1978,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) epfile->ep = ep; epfile->in = usb_endpoint_dir_in(ds); epfile->isoc = usb_endpoint_xfer_isoc(ds); + ffs_log("usb_ep_enable %s", ep->ep->name); } else { break; } @@ -1797,6 +1990,8 @@ static int ffs_func_eps_enable(struct ffs_function *func) } while (--count); spin_unlock_irqrestore(&func->ffs->eps_lock, flags); + ffs_log("exit: ret %d", ret); + return ret; } @@ -1837,6 +2032,8 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, ENTER(); + ffs_log("enter: len %u", len); + /* At least two bytes are required: length and type */ if (len < 2) { pr_vdebug("descriptor too short\n"); @@ -1953,6 +2150,8 @@ inv_length: #undef __entity_check_STRING #undef __entity_check_ENDPOINT + ffs_log("exit: desc type %d length %d", _ds->bDescriptorType, length); + return length; } @@ -1964,6 +2163,8 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, ENTER(); + ffs_log("enter: len %u", len); + for (;;) { int ret; @@ -1991,6 +2192,8 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, data += ret; ++num; } + + ffs_log("exit: len %u", len); } static int __ffs_data_do_entity(enum ffs_entity_type type, @@ -2002,6 +2205,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, ENTER(); + ffs_log("enter: type %u", type); + switch (type) { case FFS_DESCRIPTOR: break; @@ -2040,6 +2245,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, break; } + ffs_log("exit"); + return 0; } @@ -2049,6 +2256,8 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, u16 bcd_version = le16_to_cpu(desc->bcdVersion); u16 w_index = le16_to_cpu(desc->wIndex); + ffs_log("enter"); + if (bcd_version != 1) { pr_vdebug("unsupported os descriptors version: %d", bcd_version); @@ -2066,6 +2275,8 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, return -EINVAL; } + ffs_log("exit: size of desc %lu", sizeof(*desc)); + return sizeof(*desc); } @@ -2085,6 +2296,8 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len, ENTER(); + ffs_log("enter: len %u os desc type %d", len, type); + /* loop over all ext compat/ext prop descriptors */ while (feature_count--) { ret = entity(type, h, data, len, priv); @@ -2095,6 +2308,9 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len, data += ret; len -= ret; } + + ffs_log("exit"); + return _len - len; } @@ -2108,6 +2324,8 @@ static int __must_check ffs_do_os_descs(unsigned count, ENTER(); + ffs_log("enter: len %u", len); + for (num = 0; num < count; ++num) { int ret; enum ffs_os_desc_type type; @@ -2157,6 +2375,9 @@ static int __must_check ffs_do_os_descs(unsigned count, len -= ret; data += ret; } + + ffs_log("exit"); + return _len - len; } @@ -2172,6 +2393,8 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, ENTER(); + ffs_log("enter: len %u", len); + switch (type) { case FFS_OS_DESC_EXT_COMPAT: { struct usb_ext_compat_desc *d = data; @@ -2226,6 +2449,9 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, pr_vdebug("unknown descriptor: %d\n", type); return -EINVAL; } + + ffs_log("exit"); + return length; } @@ -2239,6 +2465,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, ENTER(); + ffs_log("enter: len %zu", len); + if (get_unaligned_le32(data + 4) != len) goto error; @@ -2349,10 +2577,13 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, ffs->ss_descs_count = counts[2]; ffs->ms_os_descs_count = os_descs_count; + ffs_log("exit"); + return 0; error: kfree(_data); + ffs_log("exit: ret %d", ret); return ret; } @@ -2366,6 +2597,8 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, ENTER(); + ffs_log("enter: len %zu", len); + if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || get_unaligned_le32(data + 4) != len)) goto error; @@ -2480,12 +2713,14 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, ffs->stringtabs = stringtabs; ffs->raw_strings = _data; + ffs_log("exit"); return 0; error_free: kfree(stringtabs); error: kfree(_data); + ffs_log("exit: -EINVAL"); return -EINVAL; } @@ -2498,6 +2733,9 @@ static void __ffs_event_add(struct ffs_data *ffs, enum usb_functionfs_event_type rem_type1, rem_type2 = type; int neg = 0; + ffs_log("enter: type %d state %d setup_state %d flag %lu", type, + ffs->state, ffs->setup_state, ffs->flags); + /* * Abort any unhandled setup * @@ -2557,6 +2795,9 @@ static void __ffs_event_add(struct ffs_data *ffs, wake_up_locked(&ffs->ev.waitq); if (ffs->ffs_eventfd) eventfd_signal(ffs->ffs_eventfd, 1); + + ffs_log("exit: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); } static void ffs_event_add(struct ffs_data *ffs, @@ -2591,6 +2832,8 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, int idx; static const char *speed_names[] = { "full", "high", "super" }; + ffs_log("enter"); + if (type != FFS_DESCRIPTOR) return 0; @@ -2666,6 +2909,8 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, } ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); + ffs_log("exit"); + return 0; } @@ -2677,6 +2922,8 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, unsigned idx; u8 newValue; + ffs_log("enter: type %d", type); + switch (type) { default: case FFS_DESCRIPTOR: @@ -2721,6 +2968,9 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, pr_vdebug("%02x -> %02x\n", *valuep, newValue); *valuep = newValue; + + ffs_log("exit: newValue %d", newValue); + return 0; } @@ -2731,6 +2981,8 @@ static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type, struct ffs_function *func = priv; u8 length = 0; + ffs_log("enter: type %d", type); + switch (type) { case FFS_OS_DESC_EXT_COMPAT: { struct usb_ext_compat_desc *desc = data; @@ -2800,6 +3052,8 @@ static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type, pr_vdebug("unknown descriptor: %d\n", type); } + ffs_log("exit"); + return length; } @@ -2813,6 +3067,8 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, ENTER(); + ffs_log("enter"); + /* * Legacy gadget triggers binding in functionfs_ready_callback, * which already uses locking; taking the same lock here would @@ -2847,6 +3103,8 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, ffs_opts->refcnt++; func->function.strings = func->ffs->stringtabs; + ffs_log("exit"); + return ffs_opts; } @@ -2889,6 +3147,9 @@ static int _ffs_func_bind(struct usb_configuration *c, ENTER(); + ffs_log("enter: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + /* Has descriptors only for speeds gadget does not support */ if (unlikely(!(full | high | super))) return -ENOTSUPP; @@ -3006,10 +3267,15 @@ static int _ffs_func_bind(struct usb_configuration *c, /* And we're done */ ffs_event_add(ffs, FUNCTIONFS_BIND); + + ffs_log("exit: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + return 0; error: /* XXX Do we need to release all claimed endpoints here? */ + ffs_log("exit: ret %d", ret); return ret; } @@ -3020,6 +3286,8 @@ static int ffs_func_bind(struct usb_configuration *c, struct ffs_function *func = ffs_func_from_usb(f); int ret; + ffs_log("enter"); + if (IS_ERR(ffs_opts)) return PTR_ERR(ffs_opts); @@ -3027,6 +3295,8 @@ static int ffs_func_bind(struct usb_configuration *c, if (ret && !--ffs_opts->refcnt) functionfs_unbind(func->ffs); + ffs_log("exit: ret %d", ret); + return ret; } @@ -3037,7 +3307,12 @@ static void ffs_reset_work(struct work_struct *work) { struct ffs_data *ffs = container_of(work, struct ffs_data, reset_work); + + ffs_log("enter"); + ffs_data_reset(ffs); + + ffs_log("exit"); } static int ffs_func_set_alt(struct usb_function *f, @@ -3047,6 +3322,8 @@ static int ffs_func_set_alt(struct usb_function *f, struct ffs_data *ffs = func->ffs; int ret = 0, intf; + ffs_log("enter"); + if (alt != (unsigned)-1) { intf = ffs_func_revmap_intf(func, interface); if (unlikely(intf < 0)) @@ -3082,6 +3359,8 @@ static int ffs_func_set_alt(struct usb_function *f, usb_gadget_autopm_get_async(ffs->gadget); } + ffs_log("exit: ret %d", ret); + return ret; } @@ -3090,9 +3369,13 @@ static void ffs_func_disable(struct usb_function *f) struct ffs_function *func = ffs_func_from_usb(f); struct ffs_data *ffs = func->ffs; + ffs_log("enter"); + ffs_func_set_alt(f, 0, (unsigned)-1); /* matching put to allow LPM on disconnect */ usb_gadget_autopm_put_async(ffs->gadget); + + ffs_log("exit"); } static int ffs_func_setup(struct usb_function *f, @@ -3105,6 +3388,8 @@ static int ffs_func_setup(struct usb_function *f, ENTER(); + ffs_log("enter"); + pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); @@ -3148,19 +3433,31 @@ static int ffs_func_setup(struct usb_function *f, __ffs_event_add(ffs, FUNCTIONFS_SETUP); spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); + ffs_log("exit"); + return 0; } static void ffs_func_suspend(struct usb_function *f) { ENTER(); + + ffs_log("enter"); + ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); + + ffs_log("exit"); } static void ffs_func_resume(struct usb_function *f) { ENTER(); + + ffs_log("enter"); + ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); + + ffs_log("exit"); } @@ -3177,11 +3474,15 @@ static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) short *nums = func->interfaces_nums; unsigned count = func->ffs->interfaces_count; + ffs_log("enter"); + for (; count; --count, ++nums) { if (*nums >= 0 && *nums == intf) return nums - func->interfaces_nums; } + ffs_log("exit"); + return -EDOM; } @@ -3194,6 +3495,8 @@ static struct ffs_dev *_ffs_do_find_dev(const char *name) { struct ffs_dev *dev; + ffs_log("enter"); + list_for_each_entry(dev, &ffs_devices, entry) { if (!dev->name || !name) continue; @@ -3201,6 +3504,8 @@ static struct ffs_dev *_ffs_do_find_dev(const char *name) return dev; } + ffs_log("exit"); + return NULL; } @@ -3211,12 +3516,16 @@ static struct ffs_dev *_ffs_get_single_dev(void) { struct ffs_dev *dev; + ffs_log("enter"); + if (list_is_singular(&ffs_devices)) { dev = list_first_entry(&ffs_devices, struct ffs_dev, entry); if (dev->single) return dev; } + ffs_log("exit"); + return NULL; } @@ -3227,11 +3536,17 @@ static struct ffs_dev *_ffs_find_dev(const char *name) { struct ffs_dev *dev; + ffs_log("enter"); + dev = _ffs_get_single_dev(); if (dev) return dev; - return _ffs_do_find_dev(name); + dev = _ffs_do_find_dev(name); + + ffs_log("exit"); + + return dev; } /* Configfs support *********************************************************/ @@ -3353,6 +3668,10 @@ static void ffs_func_unbind(struct usb_configuration *c, unsigned long flags; ENTER(); + + ffs_log("enter: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); + if (ffs->func == func) { ffs_func_eps_disable(func); ffs->func = NULL; @@ -3383,6 +3702,9 @@ static void ffs_func_unbind(struct usb_configuration *c, func->interfaces_nums = NULL; ffs_event_add(ffs, FUNCTIONFS_UNBIND); + + ffs_log("exit: state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); } static struct usb_function *ffs_alloc(struct usb_function_instance *fi) @@ -3445,12 +3767,16 @@ static int _ffs_name_dev(struct ffs_dev *dev, const char *name) { struct ffs_dev *existing; + ffs_log("enter"); + existing = _ffs_do_find_dev(name); if (existing) return -EBUSY; dev->name = name; + ffs_log("exit"); + return 0; } @@ -3461,10 +3787,14 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) { int ret; + ffs_log("enter"); + ffs_dev_lock(); ret = _ffs_name_dev(dev, name); ffs_dev_unlock(); + ffs_log("exit"); + return ret; } EXPORT_SYMBOL_GPL(ffs_name_dev); @@ -3473,6 +3803,8 @@ int ffs_single_dev(struct ffs_dev *dev) { int ret; + ffs_log("enter"); + ret = 0; ffs_dev_lock(); @@ -3482,6 +3814,9 @@ int ffs_single_dev(struct ffs_dev *dev) dev->single = true; ffs_dev_unlock(); + + ffs_log("exit"); + return ret; } EXPORT_SYMBOL_GPL(ffs_single_dev); @@ -3491,12 +3826,17 @@ EXPORT_SYMBOL_GPL(ffs_single_dev); */ static void _ffs_free_dev(struct ffs_dev *dev) { + + ffs_log("enter"); + list_del(&dev->entry); if (dev->name_allocated) kfree(dev->name); kfree(dev); if (list_empty(&ffs_devices)) functionfs_cleanup(); + + ffs_log("exit"); } static void *ffs_acquire_dev(const char *dev_name) @@ -3504,6 +3844,9 @@ static void *ffs_acquire_dev(const char *dev_name) struct ffs_dev *ffs_dev; ENTER(); + + ffs_log("enter"); + ffs_dev_lock(); ffs_dev = _ffs_find_dev(dev_name); @@ -3518,6 +3861,9 @@ static void *ffs_acquire_dev(const char *dev_name) ffs_dev->mounted = true; ffs_dev_unlock(); + + ffs_log("exit"); + return ffs_dev; } @@ -3526,6 +3872,9 @@ static void ffs_release_dev(struct ffs_data *ffs_data) struct ffs_dev *ffs_dev; ENTER(); + + ffs_log("enter"); + ffs_dev_lock(); ffs_dev = ffs_data->private_data; @@ -3537,6 +3886,8 @@ static void ffs_release_dev(struct ffs_data *ffs_data) } ffs_dev_unlock(); + + ffs_log("exit"); } static int ffs_ready(struct ffs_data *ffs) @@ -3545,6 +3896,9 @@ static int ffs_ready(struct ffs_data *ffs) int ret = 0; ENTER(); + + ffs_log("enter"); + ffs_dev_lock(); ffs_obj = ffs->private_data; @@ -3569,6 +3923,9 @@ static int ffs_ready(struct ffs_data *ffs) set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags); done: ffs_dev_unlock(); + + ffs_log("exit"); + return ret; } @@ -3578,11 +3935,16 @@ static void ffs_closed(struct ffs_data *ffs) struct f_fs_opts *opts; ENTER(); + + ffs_log("enter"); + ffs_dev_lock(); ffs_obj = ffs->private_data; - if (!ffs_obj) + if (!ffs_obj) { + ffs_dev_unlock(); goto done; + } ffs_obj->desc_ready = false; @@ -3590,20 +3952,29 @@ static void ffs_closed(struct ffs_data *ffs) ffs_obj->ffs_closed_callback) ffs_obj->ffs_closed_callback(ffs); - if (ffs_obj->opts) + if (ffs_obj->opts) { opts = ffs_obj->opts; - else + } else { + ffs_dev_unlock(); goto done; + } smp_mb__before_atomic(); if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent - || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount)) + || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount)) { + ffs_dev_unlock(); goto done; + } + + ffs_dev_unlock(); - unregister_gadget_item(ffs_obj->opts-> + if (test_bit(FFS_FL_BOUND, &ffs->flags)) { + unregister_gadget_item(opts-> func_inst.group.cg_item.ci_parent->ci_parent); + ffs_log("unreg gadget done"); + } done: - ffs_dev_unlock(); + ffs_log("exit"); } /* Misc helper functions ****************************************************/ diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 5612645d7237..a629723d19cb 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -39,6 +39,8 @@ static struct workqueue_struct *ipa_usb_wq; static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi, enum gsi_ctrl_notify_state); +static int gsi_alloc_trb_buffer(struct f_gsi *gsi); +static void gsi_free_trb_buffer(struct f_gsi *gsi); void post_event(struct gsi_data_port *port, u8 event) { @@ -474,6 +476,9 @@ static void ipa_disconnect_work_handler(struct gsi_data_port *d_port) if (gsi->d_port.out_ep) usb_gsi_ep_op(gsi->d_port.out_ep, NULL, GSI_EP_OP_FREE_TRBS); + + /* free buffers allocated with each TRB */ + gsi_free_trb_buffer(gsi); } static int ipa_suspend_work_handler(struct gsi_data_port *d_port) @@ -547,6 +552,7 @@ static void ipa_work_handler(struct work_struct *w) struct usb_gadget *gadget = d_port->gadget; struct device *dev; struct device *gad_dev; + struct f_gsi *gsi; event = read_event(d_port); @@ -566,31 +572,27 @@ static void ipa_work_handler(struct work_struct *w) return; } + gsi = d_port_to_gsi(d_port); + switch (d_port->sm_state) { case STATE_UNINITIALIZED: break; case STATE_INITIALIZED: if (event == EVT_CONNECT_IN_PROGRESS) { + usb_gadget_autopm_get(d_port->gadget); + log_event_dbg("%s: get = %d", __func__, + atomic_read(&gad_dev->power.usage_count)); + /* allocate buffers used with each TRB */ + ret = gsi_alloc_trb_buffer(gsi); + if (ret) { + log_event_err("%s: gsi_alloc_trb_failed\n", + __func__); + break; + } ipa_connect_channels(d_port); d_port->sm_state = STATE_CONNECT_IN_PROGRESS; log_event_dbg("%s: ST_INIT_EVT_CONN_IN_PROG", __func__); - } else if (event == EVT_HOST_READY) { - /* - * When in a composition such as RNDIS + ADB, - * RNDIS host sends a GEN_CURRENT_PACKET_FILTER msg - * to enable/disable flow control eg. during RNDIS - * adaptor disable/enable from device manager. - * In the case of the msg to disable flow control, - * connect IPA channels and enable data path. - * EVT_HOST_READY is posted to the state machine - * in the handler for this msg. - */ - ipa_connect_channels(d_port); - ipa_data_path_enable(d_port); - d_port->sm_state = STATE_CONNECTED; - log_event_dbg("%s: ST_INIT_EVT_HOST_READY", - __func__); } break; case STATE_CONNECT_IN_PROGRESS: @@ -648,6 +650,7 @@ static void ipa_work_handler(struct work_struct *w) &gad_dev->power.usage_count)); } else if (event == EVT_SUSPEND) { if (peek_event(d_port) == EVT_DISCONNECTED) { + read_event(d_port); ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; usb_gadget_autopm_put_async(d_port->gadget); @@ -718,19 +721,12 @@ static void ipa_work_handler(struct work_struct *w) case STATE_SUSPENDED: if (event == EVT_RESUMED) { + usb_gadget_autopm_get(d_port->gadget); + log_event_dbg("%s: ST_SUS_EVT_RES", __func__); + log_event_dbg("%s: get = %d", __func__, + atomic_read(&gad_dev->power.usage_count)); ipa_resume_work_handler(d_port); d_port->sm_state = STATE_CONNECTED; - /* - * Increment usage count here to disallow gadget - * parent suspend. This counter will decrement - * after IPA handshake is done in disconnect work - * (due to cable disconnect) or in suspended state. - */ - usb_gadget_autopm_get_noresume(d_port->gadget); - log_event_dbg("%s: ST_SUS_EVT_RES", __func__); - log_event_dbg("%s: get_nores2 = %d", __func__, - atomic_read( - &gad_dev->power.usage_count)); } else if (event == EVT_DISCONNECTED) { ipa_disconnect_work_handler(d_port); d_port->sm_state = STATE_INITIALIZED; @@ -1714,6 +1710,92 @@ static int gsi_get_alt(struct usb_function *f, unsigned intf) return -EINVAL; } +static int gsi_alloc_trb_buffer(struct f_gsi *gsi) +{ + u32 len_in = 0, len_out = 0; + int ret = 0; + + log_event_dbg("allocate trb's buffer\n"); + + if (gsi->d_port.in_ep && !gsi->d_port.in_request.buf_base_addr) { + log_event_dbg("IN: num_bufs:=%zu, buf_len=%zu\n", + gsi->d_port.in_request.num_bufs, + gsi->d_port.in_request.buf_len); + + len_in = gsi->d_port.in_request.buf_len * + gsi->d_port.in_request.num_bufs; + gsi->d_port.in_request.buf_base_addr = + dma_zalloc_coherent(gsi->d_port.gadget->dev.parent, + len_in, &gsi->d_port.in_request.dma, GFP_KERNEL); + if (!gsi->d_port.in_request.buf_base_addr) { + dev_err(&gsi->d_port.gadget->dev, + "IN buf_base_addr allocate failed %s\n", + gsi->function.name); + ret = -ENOMEM; + goto fail1; + } + } + + if (gsi->d_port.out_ep && !gsi->d_port.out_request.buf_base_addr) { + log_event_dbg("OUT: num_bufs:=%zu, buf_len=%zu\n", + gsi->d_port.out_request.num_bufs, + gsi->d_port.out_request.buf_len); + + len_out = gsi->d_port.out_request.buf_len * + gsi->d_port.out_request.num_bufs; + gsi->d_port.out_request.buf_base_addr = + dma_zalloc_coherent(gsi->d_port.gadget->dev.parent, + len_out, &gsi->d_port.out_request.dma, GFP_KERNEL); + if (!gsi->d_port.out_request.buf_base_addr) { + dev_err(&gsi->d_port.gadget->dev, + "OUT buf_base_addr allocate failed %s\n", + gsi->function.name); + ret = -ENOMEM; + goto fail; + } + } + + log_event_dbg("finished allocating trb's buffer\n"); + return ret; + +fail: + if (len_in && gsi->d_port.in_request.buf_base_addr) { + dma_free_coherent(gsi->d_port.gadget->dev.parent, len_in, + gsi->d_port.in_request.buf_base_addr, + gsi->d_port.in_request.dma); + gsi->d_port.in_request.buf_base_addr = NULL; + } +fail1: + return ret; +} + +static void gsi_free_trb_buffer(struct f_gsi *gsi) +{ + u32 len; + + log_event_dbg("freeing trb's buffer\n"); + + if (gsi->d_port.out_ep && + gsi->d_port.out_request.buf_base_addr) { + len = gsi->d_port.out_request.buf_len * + gsi->d_port.out_request.num_bufs; + dma_free_coherent(gsi->d_port.gadget->dev.parent, len, + gsi->d_port.out_request.buf_base_addr, + gsi->d_port.out_request.dma); + gsi->d_port.out_request.buf_base_addr = NULL; + } + + if (gsi->d_port.in_ep && + gsi->d_port.in_request.buf_base_addr) { + len = gsi->d_port.in_request.buf_len * + gsi->d_port.in_request.num_bufs; + dma_free_coherent(gsi->d_port.gadget->dev.parent, len, + gsi->d_port.in_request.buf_base_addr, + gsi->d_port.in_request.dma); + gsi->d_port.in_request.buf_base_addr = NULL; + } +} + static int gsi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct f_gsi *gsi = func_to_gsi(f); @@ -1827,14 +1909,14 @@ static int gsi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (gsi->prot_id == IPA_USB_ECM) gsi->d_port.cdc_filter = DEFAULT_FILTER; + post_event(&gsi->d_port, EVT_CONNECT_IN_PROGRESS); /* - * Increment usage count upon cable connect. Decrement - * after IPA disconnect is done in disconnect work - * (due to cable disconnect) or in suspend work. + * For RNDIS the event is posted from the flow control + * handler which is invoked when the host sends the + * GEN_CURRENT_PACKET_FILTER message. */ - usb_gadget_autopm_get_noresume(gsi->d_port.gadget); - - post_event(&gsi->d_port, EVT_CONNECT_IN_PROGRESS); + if (gsi->prot_id != IPA_USB_RNDIS) + post_event(&gsi->d_port, EVT_HOST_READY); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); } @@ -2042,7 +2124,6 @@ static int gsi_update_function_bind_params(struct f_gsi *gsi, struct usb_ep *ep; struct usb_cdc_notification *event; struct usb_function *f = &gsi->function; - u32 len = 0; int status; /* maybe allocate device-global string IDs */ @@ -2162,37 +2243,9 @@ skip_string_id_alloc: gsi->d_port.in_request.buf_len = info->in_req_buf_len; gsi->d_port.in_request.num_bufs = info->in_req_num_buf; - len = gsi->d_port.in_request.buf_len * gsi->d_port.in_request.num_bufs; - dev_dbg(&cdev->gadget->dev, "%zu %zu\n", gsi->d_port.in_request.buf_len, - gsi->d_port.in_request.num_bufs); - gsi->d_port.in_request.buf_base_addr = - dma_zalloc_coherent(cdev->gadget->dev.parent, len, - &gsi->d_port.in_request.dma, GFP_KERNEL); - if (!gsi->d_port.in_request.buf_base_addr) { - dev_err(&cdev->gadget->dev, - "IN buf_base_addr allocate failed %s\n", - gsi->function.name); - goto fail; - } - if (gsi->d_port.out_ep) { gsi->d_port.out_request.buf_len = info->out_req_buf_len; gsi->d_port.out_request.num_bufs = info->out_req_num_buf; - len = - gsi->d_port.out_request.buf_len * - gsi->d_port.out_request.num_bufs; - dev_dbg(&cdev->gadget->dev, "%zu %zu\n", - gsi->d_port.out_request.buf_len, - gsi->d_port.out_request.num_bufs); - gsi->d_port.out_request.buf_base_addr = - dma_zalloc_coherent(cdev->gadget->dev.parent, len, - &gsi->d_port.out_request.dma, GFP_KERNEL); - if (!gsi->d_port.out_request.buf_base_addr) { - dev_err(&cdev->gadget->dev, - "OUT buf_base_addr allocate failed %s\n", - gsi->function.name); - goto fail; - } } /* Initialize event queue */ @@ -2263,14 +2316,6 @@ fail: gsi->d_port.out_ep->driver_data = NULL; if (gsi->d_port.in_ep && gsi->d_port.in_ep->desc) gsi->d_port.in_ep->driver_data = NULL; - if (len && gsi->d_port.in_request.buf_base_addr) - dma_free_coherent(cdev->gadget->dev.parent, len, - gsi->d_port.in_request.buf_base_addr, - gsi->d_port.in_request.dma); - if (len && gsi->d_port.out_request.buf_base_addr) - dma_free_coherent(cdev->gadget->dev.parent, len, - gsi->d_port.out_request.buf_base_addr, - gsi->d_port.out_request.dma); log_event_err("%s: bind failed for %s", __func__, f->name); return -ENOMEM; } @@ -2564,8 +2609,6 @@ fail: static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_gsi *gsi = func_to_gsi(f); - struct usb_composite_dev *cdev = c->cdev; - u32 len; /* * Use drain_workqueue to accomplish below conditions: @@ -2600,19 +2643,7 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) if (gsi->c_port.notify) { kfree(gsi->c_port.notify_req->buf); usb_ep_free_request(gsi->c_port.notify, gsi->c_port.notify_req); - - len = - gsi->d_port.out_request.buf_len * - gsi->d_port.out_request.num_bufs; - dma_free_coherent(&cdev->gadget->dev, len, - gsi->d_port.out_request.buf_base_addr, - gsi->d_port.out_request.dma); } - - len = gsi->d_port.in_request.buf_len * gsi->d_port.in_request.num_bufs; - dma_free_coherent(&cdev->gadget->dev, len, - gsi->d_port.in_request.buf_base_addr, - gsi->d_port.in_request.dma); } 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/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index dd8149ef097d..f8121eb4f63a 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -799,7 +799,7 @@ static int qusb_phy_probe(struct platform_device *pdev) } of_property_read_u32_array(dev->of_node, - "qcom,qemu-init-seq", + "qcom,emu-init-seq", qphy->emu_init_seq, qphy->emu_init_seq_len); } else { diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index 325f5fcf161b..5ec08098d197 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -878,7 +878,7 @@ static int qusb_phy_probe(struct platform_device *pdev) } of_property_read_u32_array(dev->of_node, - "qcom,qemu-init-seq", + "qcom,emu-init-seq", qphy->emu_init_seq, qphy->emu_init_seq_len); } else { 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_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index eefea9f117c0..0ac5ef4f750c 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -33,6 +33,7 @@ #include "mdss.h" #include "mdss_dp.h" #include "mdss_dp_util.h" +#include "mdss_hdmi_panel.h" #include "mdss_debug.h" #define RGB_COMPONENTS 3 @@ -863,7 +864,7 @@ int mdss_dp_wait4train(struct mdss_dp_drv_pdata *dp_drv) #define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_640x480p60_4_3 -static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv) +static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) { struct mdss_panel_info *pinfo; struct msm_hdmi_mode_timing_info timing = {0}; @@ -875,8 +876,7 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv) } dp_drv->ds_data.ds_registered = false; - ret = hdmi_get_supported_mode(&timing, &dp_drv->ds_data, - DEFAULT_VIDEO_RESOLUTION); + ret = hdmi_get_supported_mode(&timing, &dp_drv->ds_data, vic); pinfo = &dp_drv->panel_data.panel_info; if (ret || !timing.supported || !pinfo) { @@ -884,6 +884,7 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv) return -EINVAL; } + dp_drv->vic = vic; pinfo->xres = timing.active_h; pinfo->yres = timing.active_v; pinfo->clk_rate = timing.pixel_freq * 1000; @@ -895,7 +896,7 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv) pinfo->lcdc.v_front_porch = timing.front_porch_v; pinfo->lcdc.v_pulse_width = timing.pulse_width_v; - pinfo->type = EDP_PANEL; + pinfo->type = DP_PANEL; pinfo->pdest = DISPLAY_4; pinfo->wait_cycle = 0; pinfo->bpp = 24; @@ -904,6 +905,10 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv) pinfo->lcdc.border_clr = 0; /* blk */ pinfo->lcdc.underflow_clr = 0xff; /* blue */ pinfo->lcdc.hsync_skew = 0; + pinfo->is_pluggable = true; + + pr_debug("update res. vic= %d, pclk_rate = %llu\n", + dp_drv->vic, pinfo->clk_rate); return 0; } /* dp_init_panel_info */ @@ -963,6 +968,9 @@ int mdss_dp_on(struct mdss_panel_data *pdata) } + if (dp_drv->new_vic && (dp_drv->new_vic != dp_drv->vic)) + dp_init_panel_info(dp_drv, dp_drv->new_vic); + mdss_dp_phy_aux_setup(&dp_drv->phy_io); mdss_dp_irq_enable(dp_drv); @@ -1072,6 +1080,44 @@ int mdss_dp_off(struct mdss_panel_data *pdata) return 0; } +static void mdss_dp_send_cable_notification( + struct mdss_dp_drv_pdata *dp, int val) +{ + int state = 0; + + if (!dp) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + state = dp->sdev.state; + + switch_set_state(&dp->sdev, val); + + DEV_INFO("%s: cable state %s %d\n", __func__, + dp->sdev.state == state ? + "is same" : "switched to", + dp->sdev.state); +} + +static int mdss_dp_register_switch_event(struct mdss_dp_drv_pdata *dp) +{ + int rc = -EINVAL; + + if (!dp) { + DEV_ERR("%s: invalid input\n", __func__); + goto end; + } + + dp->sdev.name = "hdmi"; + rc = switch_dev_register(&dp->sdev); + if (rc) { + DEV_ERR("%s: display switch registration failed\n", __func__); + goto end; + } +end: + return rc; +} + static int mdss_dp_edid_init(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; @@ -1097,9 +1143,6 @@ static int mdss_dp_edid_init(struct mdss_panel_data *pdata) return -ENODEV; } - edid_init_data.buf = edid_init_data.buf; - edid_init_data.buf_size = edid_init_data.buf_size; - /* Use the existing EDID buffer for 1080p */ memcpy(edid_init_data.buf, edid_buf1, sizeof(edid_buf1)); dp_drv->panel_data.panel_info.edid_data = edid_data; @@ -1152,6 +1195,8 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) goto edid_parser_error; } + mdss_dp_send_cable_notification(dp_drv, true); + return ret; edid_parser_error: @@ -1162,6 +1207,44 @@ vreg_error: return ret; } +static int mdss_dp_check_params(struct mdss_dp_drv_pdata *dp, void *arg) +{ + struct mdss_panel_info *var_pinfo, *pinfo; + int rc = 0; + int new_vic = -1; + + if (!dp || !arg) + return 0; + + pinfo = &dp->panel_data.panel_info; + var_pinfo = (struct mdss_panel_info *)arg; + + pr_debug("reconfig xres: %d yres: %d, current xres: %d yres: %d\n", + var_pinfo->xres, var_pinfo->yres, + pinfo->xres, pinfo->yres); + + new_vic = hdmi_panel_get_vic(var_pinfo, &dp->ds_data); + + if ((new_vic < 0) || (new_vic > HDMI_VFRMT_MAX)) { + DEV_ERR("%s: invalid or not supported vic\n", __func__); + goto end; + } + + /* + * return value of 1 lets mdss know that panel + * needs a reconfig due to new resolution and + * it will issue close and open subsequently. + */ + if (new_vic != dp->vic) { + rc = 1; + DEV_ERR("%s: res change %d ==> %d\n", __func__, + dp->vic, new_vic); + } + dp->new_vic = new_vic; +end: + return rc; +} + static int mdss_dp_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -1194,9 +1277,13 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, dp->kobj = &fbi->dev->kobj; dp->fb_node = fbi->node; mdss_dp_edid_init(pdata); + mdss_dp_register_switch_event(dp); + break; + case MDSS_EVENT_CHECK_PARAMS: + rc = mdss_dp_check_params(dp, arg); break; default: - pr_debug("%s: unhandled event=%d\n", __func__, event); + pr_debug("unhandled event=%d\n", event); break; } return rc; @@ -1220,7 +1307,7 @@ static int mdss_dp_device_register(struct mdss_dp_drv_pdata *dp_drv) { int ret; - ret = dp_init_panel_info(dp_drv); + ret = dp_init_panel_info(dp_drv, DEFAULT_VIDEO_RESOLUTION); if (ret) { DEV_ERR("%s: dp_init_panel_info failed\n", __func__); return ret; @@ -1493,6 +1580,7 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr) mutex_lock(&dp_drv->pd_msg_mutex); dp_drv->cable_connected = false; mutex_unlock(&dp_drv->pd_msg_mutex); + mdss_dp_send_cable_notification(dp_drv, false); } static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index 10fcdec49515..03646cd7cc65 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -21,6 +21,7 @@ #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/usb/usbpd.h> +#include <linux/switch.h> #include "mdss_hdmi_util.h" #include "mdss_hdmi_edid.h" @@ -430,8 +431,11 @@ struct mdss_dp_drv_pdata { spinlock_t event_lock; spinlock_t lock; struct hdmi_util_ds_data ds_data; + struct switch_dev sdev; struct kobject *kobj; u32 max_pclk_khz; + u32 vic; + u32 new_vic; int fb_node; }; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 2e54f335e948..4bd705bdc05f 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -389,8 +389,10 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) } gpio_set_value((ctrl_pdata->rst_gpio), 0); gpio_free(ctrl_pdata->rst_gpio); - if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) + if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) { + gpio_set_value(ctrl_pdata->lcd_mode_sel_gpio, 0); gpio_free(ctrl_pdata->lcd_mode_sel_gpio); + } } exit: diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 99a924c38d65..b2c0c78d3f2b 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -331,8 +331,8 @@ static ssize_t mdss_fb_get_type(struct device *dev, case WRITEBACK_PANEL: ret = snprintf(buf, PAGE_SIZE, "writeback panel\n"); break; - case EDP_PANEL: - ret = snprintf(buf, PAGE_SIZE, "edp panel\n"); + case DP_PANEL: + ret = snprintf(buf, PAGE_SIZE, "dp panel\n"); break; default: ret = snprintf(buf, PAGE_SIZE, "unknown panel\n"); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c index b4d3dad50d45..0335bf900866 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c @@ -150,7 +150,7 @@ enum hdmi_scaling_info { HDMI_SCALING_HORZ_VERT, }; -static int hdmi_panel_get_vic(struct mdss_panel_info *pinfo, +int hdmi_panel_get_vic(struct mdss_panel_info *pinfo, struct hdmi_util_ds_data *ds_data) { int new_vic = -1; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.h b/drivers/video/fbdev/msm/mdss_hdmi_panel.h index 24d3b9b52798..e5cc1486f222 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_panel.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.h @@ -104,4 +104,7 @@ void *hdmi_panel_init(struct hdmi_panel_init_data *data); */ void hdmi_panel_deinit(void *input); +int hdmi_panel_get_vic(struct mdss_panel_info *pinfo, + struct hdmi_util_ds_data *ds_data); + #endif /* __MDSS_HDMI_PANEL_H__ */ 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_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 1a0ba8f0e2a7..2218e9c4ac81 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -2668,7 +2668,7 @@ int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff) { switch (ctl->panel_data->panel_info.type) { case MIPI_VIDEO_PANEL: - case EDP_PANEL: + case DP_PANEL: case DTV_PANEL: return mdss_mdp_video_reconfigure_splash_done(ctl, handoff); case MIPI_CMD_PANEL: @@ -3686,7 +3686,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata, ctl->disable_prefill = false; switch (pdata->panel_info.type) { - case EDP_PANEL: + case DP_PANEL: ctl->is_video_mode = true; ctl->intf_num = MDSS_MDP_INTF0; ctl->intf_type = MDSS_INTF_EDP; 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..5a65451dc127 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)); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 7a49f37660dd..bde137269422 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -51,7 +51,7 @@ struct panel_id { #define MIPI_CMD_PANEL 9 /* MIPI */ #define WRITEBACK_PANEL 10 /* Wifi display */ #define LVDS_PANEL 11 /* LVDS */ -#define EDP_PANEL 12 /* LVDS */ +#define DP_PANEL 12 /* LVDS */ #define DSC_PPS_LEN 128 @@ -61,7 +61,7 @@ static inline const char *mdss_panel2str(u32 panel) #define PANEL_NAME(n) [n ## _PANEL] = __stringify(n) PANEL_NAME(MIPI_VIDEO), PANEL_NAME(MIPI_CMD), - PANEL_NAME(EDP), + PANEL_NAME(DP), PANEL_NAME(HDMI), PANEL_NAME(DTV), PANEL_NAME(WRITEBACK), @@ -811,7 +811,7 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info) case MIPI_CMD_PANEL: frame_rate = panel_info->mipi.frame_rate; break; - case EDP_PANEL: + case DP_PANEL: frame_rate = panel_info->edp.frame_rate; break; case WRITEBACK_PANEL: 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/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h index 52277f26b5a4..7bf2bff2f173 100755 --- a/include/linux/mfd/wcd9xxx/pdata.h +++ b/include/linux/mfd/wcd9xxx/pdata.h @@ -189,6 +189,7 @@ struct wcd9xxx_pdata { u32 mclk_rate; u32 dmic_sample_rate; u32 mad_dmic_sample_rate; + u32 ecpp_dmic_sample_rate; u32 dmic_clk_drv; u16 use_pinctrl; }; 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/soc/qcom/irq-helper.h b/include/soc/qcom/irq-helper.h new file mode 100644 index 000000000000..d992fb6f470a --- /dev/null +++ b/include/soc/qcom/irq-helper.h @@ -0,0 +1,20 @@ +/* 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 __SOC_QCOM_IRQ_HELPER_H +#define __SOC_QCOM_IRQ_HELPER_H + +int irq_blacklist_on(void); +int irq_blacklist_off(void); + +#endif + 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/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 2cf0469712b6..643c68f4c449 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -815,6 +815,12 @@ enum v4l2_mpeg_vidc_extradata { #define V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO \ V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO = 28, +#define V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY \ + V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY + V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY = 29, +#define V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE \ + V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE + V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE = 30, }; #define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE + 26) @@ -1176,6 +1182,23 @@ enum v4l2_mpeg_vidc_video_h264_transform_8x8 { V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE = 1, }; +#define V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 94) + +#define V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 95) + +enum v4l2_cid_mpeg_vidc_video_full_range { + V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_DISABLE = 0, + V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE_ENABLE = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 96) + +#define V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 97) + /* Camera class control IDs */ #define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) diff --git a/include/uapi/media/msm_vidc.h b/include/uapi/media/msm_vidc.h index 45cc81aaaf17..b259bdef8a93 100644 --- a/include/uapi/media/msm_vidc.h +++ b/include/uapi/media/msm_vidc.h @@ -55,6 +55,18 @@ struct msm_vidc_mpeg2_seqdisp_payload { unsigned int disp_height; }; +struct msm_vidc_vc1_seqdisp_payload { + unsigned int prog_seg_format; + unsigned int uv_sampl_fmt; + unsigned int color_format; + unsigned int color_primaries; + unsigned int transfer_char; + unsigned int matrix_coeffs; + unsigned int aspect_ratio; + unsigned int aspect_horiz; + unsigned int aspect_vert; +}; + struct msm_vidc_input_crop_payload { unsigned int size; unsigned int version; @@ -154,6 +166,13 @@ struct msm_vidc_yuv_stats_payload { unsigned int frame_difference; }; +struct msm_vidc_vpx_colorspace_payload { + unsigned int color_space; + unsigned int yuv_range_flag; + unsigned int sumsampling_x; + unsigned int sumsampling_y; +}; + struct msm_vidc_roi_qp_payload { int upper_qp_offset; int lower_qp_offset; @@ -176,6 +195,23 @@ struct msm_vidc_content_light_level_sei_payload { unsigned int nMaxPicAverageLight; }; +struct msm_vidc_vui_display_info_payload { + unsigned int video_signal_present_flag; + unsigned int video_format; + unsigned int bit_depth_y; + unsigned int bit_depth_c; + unsigned int video_full_range_flag; + unsigned int color_description_present_flag; + unsigned int color_primaries; + unsigned int transfer_characteristics; + unsigned int matrix_coefficients; + unsigned int chroma_location_info_present_flag; + unsigned int chroma_format_idc; + unsigned int separate_color_plane_flag; + unsigned int chroma_sample_loc_type_top_field; + unsigned int chroma_sample_loc_type_bottom_field; +}; + enum msm_vidc_extradata_type { MSM_VIDC_EXTRADATA_NONE = 0x00000000, MSM_VIDC_EXTRADATA_MB_QUANTIZATION = 0x00000001, @@ -207,6 +243,9 @@ enum msm_vidc_extradata_type { MSM_VIDC_EXTRADATA_OUTPUT_CROP MSM_VIDC_EXTRADATA_OUTPUT_CROP = 0x0700000F, MSM_VIDC_EXTRADATA_DIGITAL_ZOOM = 0x07000010, +#define MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO \ + MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO + MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO = 0x070000011, MSM_VIDC_EXTRADATA_MULTISLICE_INFO = 0x7F100000, MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB = 0x7F100001, MSM_VIDC_EXTRADATA_INDEX = 0x7F100002, @@ -214,6 +253,9 @@ enum msm_vidc_extradata_type { MSM_VIDC_EXTRADATA_METADATA_LTR = 0x7F100004, MSM_VIDC_EXTRADATA_METADATA_FILLER = 0x7FE00002, MSM_VIDC_EXTRADATA_METADATA_MBI = 0x7F100005, +#define MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO \ + MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO + MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO = 0x7F100006, MSM_VIDC_EXTRADATA_YUVSTATS_INFO = 0x7F100007, }; enum msm_vidc_interlace_type { @@ -243,12 +285,90 @@ enum msm_vidc_userdata_type { MSM_VIDC_USERDATA_TYPE_BOTTOM_FIELD = 0x3, }; +/* See colour_primaries of ISO/IEC 14496 for significance */ +enum msm_vidc_h264_color_primaries_values { + MSM_VIDC_RESERVED_1 = 0, + MSM_VIDC_BT709_5 = 1, + MSM_VIDC_UNSPECIFIED = 2, + MSM_VIDC_RESERVED_2 = 3, + MSM_VIDC_BT470_6_M = 4, + MSM_VIDC_BT601_6_625 = 5, + MSM_VIDC_BT470_6_BG = MSM_VIDC_BT601_6_625, + MSM_VIDC_BT601_6_525 = 6, + MSM_VIDC_SMPTE_240M = 7, + MSM_VIDC_GENERIC_FILM = 8, + MSM_VIDC_BT2020 = 9, +}; + +enum msm_vidc_vp9_color_primaries_values { + MSM_VIDC_CS_UNKNOWN, + MSM_VIDC_CS_BT_601, + MSM_VIDC_CS_BT_709, + MSM_VIDC_CS_SMPTE_170, + MSM_VIDC_CS_SMPTE_240, + MSM_VIDC_CS_BT_2020, + MSM_VIDC_CS_RESERVED, + MSM_VIDC_CS_RGB, +}; + +enum msm_vidc_h264_matrix_coeff_values { + MSM_VIDC_MATRIX_RGB = 0, + MSM_VIDC_MATRIX_BT_709_5 = 1, + MSM_VIDC_MATRIX_UNSPECIFIED = 2, + MSM_VIDC_MATRIX_RESERVED = 3, + MSM_VIDC_MATRIX_FCC_47 = 4, + MSM_VIDC_MATRIX_601_6_625 = 5, + MSM_VIDC_MATRIX_BT470_BG = MSM_VIDC_MATRIX_601_6_625, + MSM_VIDC_MATRIX_601_6_525 = 6, + MSM_VIDC_MATRIX_SMPTE_170M = MSM_VIDC_MATRIX_601_6_525, + MSM_VIDC_MATRIX_SMPTE_240M = 7, + MSM_VIDC_MATRIX_Y_CG_CO = 8, + MSM_VIDC_MATRIX_BT_2020 = 9, + MSM_VIDC_MATRIX_BT_2020_CONST = 10, +}; + +enum msm_vidc_h264_transfer_chars_values { + MSM_VIDC_TRANSFER_RESERVED_1 = 0, + MSM_VIDC_TRANSFER_BT709_5 = 1, + MSM_VIDC_TRANSFER_UNSPECIFIED = 2, + MSM_VIDC_TRANSFER_RESERVED_2 = 3, + MSM_VIDC_TRANSFER_BT_470_6_M = 4, + MSM_VIDC_TRANSFER_BT_470_6_BG = 5, + MSM_VIDC_TRANSFER_601_6_625 = 6, + MSM_VIDC_TRANSFER_601_6_525 = MSM_VIDC_TRANSFER_601_6_625, + MSM_VIDC_TRANSFER_SMPTE_240M = 7, + MSM_VIDC_TRANSFER_LINEAR = 8, + MSM_VIDC_TRANSFER_LOG_100_1 = 9, + MSM_VIDC_TRANSFER_LOG_100_SQRT10_1 = 10, + MSM_VIDC_TRANSFER_IEC_61966 = 11, + MSM_VIDC_TRANSFER_BT_1361 = 12, + MSM_VIDC_TRANSFER_SRGB = 13, + MSM_VIDC_TRANSFER_BT_2020_10 = 14, + MSM_VIDC_TRANSFER_BT_2020_12 = 15, +}; + enum msm_vidc_pixel_depth { MSM_VIDC_BIT_DEPTH_8, MSM_VIDC_BIT_DEPTH_10, MSM_VIDC_BIT_DEPTH_UNSUPPORTED = 0XFFFFFFFF, }; +enum msm_vidc_video_format { + MSM_VIDC_COMPONENT, + MSM_VIDC_PAL, + MSM_VIDC_NTSC, + MSM_VIDC_SECAM, + MSM_VIDC_MAC, + MSM_VIDC_UNSPECIFIED_FORMAT, + MSM_VIDC_RESERVED_1_FORMAT, + MSM_VIDC_RESERVED_2_FORMAT, +}; + +enum msm_vidc_color_desc_flag { + MSM_VIDC_COLOR_DESC_NOT_PRESENT, + MSM_VIDC_COLOR_DESC_PRESENT, +}; + /*enum msm_vidc_pic_struct */ #define MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED 0x0 #define MSM_VIDC_PIC_STRUCT_PROGRESSIVE 0x1 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 0af7314f1b7b..11993bb9a639 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5820,6 +5820,18 @@ static u32 tasha_get_dmic_sample_rate(struct snd_soc_codec *codec, tx_stream_fs = snd_soc_read(codec, tx_fs_reg) & 0x0F; dmic_fs = tx_stream_fs <= 4 ? WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ : WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ; + + /* + * Check for ECPP path selection and DEC1 not connected to + * any other audio path to apply ECPP DMIC sample rate + */ + if ((adc_mux_index == 1) && + ((snd_soc_read(codec, WCD9335_CPE_SS_US_EC_MUX_CFG) + & 0x0F) == 0x0A) && + ((snd_soc_read(codec, WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0) + & 0x0C) == 0x00)) { + dmic_fs = pdata->ecpp_dmic_sample_rate; + } } else { dmic_fs = pdata->dmic_sample_rate; } @@ -12476,6 +12488,17 @@ static int tasha_handle_pdata(struct tasha_priv *tasha, */ pdata->mad_dmic_sample_rate = pdata->dmic_sample_rate; } + if (pdata->ecpp_dmic_sample_rate == + WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED) { + dev_info(codec->dev, + "%s: ecpp_dmic_rate invalid default = %d\n", + __func__, def_dmic_rate); + /* + * use dmic_sample_rate as the default for ECPP DMIC + * if ecpp dmic sample rate is undefined + */ + pdata->ecpp_dmic_sample_rate = pdata->dmic_sample_rate; + } if (pdata->dmic_clk_drv == WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED) { diff --git a/sound/soc/msm/msm-cpe-lsm.c b/sound/soc/msm/msm-cpe-lsm.c index 45eed236c5c9..8270cfb98de8 100644 --- a/sound/soc/msm/msm-cpe-lsm.c +++ b/sound/soc/msm/msm-cpe-lsm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 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 @@ -1208,6 +1208,7 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: No memory for sound model\n", __func__); kfree(session->conf_levels); + session->conf_levels = NULL; return -ENOMEM; } session->snd_model_size = snd_model.data_size; @@ -1219,6 +1220,8 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, __func__); kfree(session->conf_levels); kfree(session->snd_model_data); + session->conf_levels = NULL; + session->snd_model_data = NULL; return -EFAULT; } @@ -1230,6 +1233,8 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, __func__, rc); kfree(session->snd_model_data); kfree(session->conf_levels); + session->snd_model_data = NULL; + session->conf_levels = NULL; return rc; } @@ -1243,6 +1248,8 @@ static int msm_cpe_lsm_ioctl_shared(struct snd_pcm_substream *substream, lsm_ops->lsm_shmem_dealloc(cpe->core_handle, session); kfree(session->snd_model_data); kfree(session->conf_levels); + session->snd_model_data = NULL; + session->conf_levels = NULL; return rc; } 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-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c index f577637ee2b2..26528e6a2bb8 100644 --- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c @@ -1070,6 +1070,7 @@ static int msm_compr_ioctl_shared(struct snd_pcm_substream *substream, __func__, ddp->params_length); return -EINVAL; } + params_length = ddp->params_length*sizeof(int); if (params_length > MAX_AC3_PARAM_SIZE) { /*MAX is 36*sizeof(int) this should not happen*/ pr_err("%s: params_length(%d) is greater than %zd\n", 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-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c index 2d8177c9712d..7c56f4ad8884 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-slim.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c @@ -1,5 +1,5 @@ /* - * 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 @@ -467,7 +467,9 @@ static void msm_dai_slim_remove_dai_data( dai_data_t = &drv_data->slim_dai_data[i]; kfree(dai_data_t->chan_h); + dai_data_t->chan_h = NULL; kfree(dai_data_t->sh_ch); + dai_data_t->sh_ch = NULL; } } 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 8efa04c3807e..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) { @@ -3312,7 +3477,7 @@ int afe_loopback(u16 enable, u16 rx_port, u16 tx_port) sizeof(struct afe_port_param_data_v2); lb_cmd.dst_port_id = rx_port; - lb_cmd.routing_mode = LB_MODE_EC_REF_VOICE_AUDIO; + lb_cmd.routing_mode = LB_MODE_DEFAULT; lb_cmd.enable = (enable ? 1 : 0); lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG; diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c index d0250535c69b..2bf0c490e834 100644 --- a/sound/soc/msm/qdsp6v2/q6lsm.c +++ b/sound/soc/msm/qdsp6v2/q6lsm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, 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 @@ -348,6 +348,7 @@ void q6lsm_client_free(struct lsm_client *client) q6lsm_mmap_apr_dereg(); mutex_destroy(&client->cmd_lock); kfree(client); + client = NULL; } /* |
