diff options
77 files changed, 8086 insertions, 2666 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/sound/wcd_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt index d585595f21c6..e37e7c2bea3c 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 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/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-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.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index c9a2abf0d5b5..4e98a844d059 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"; @@ -2918,6 +2947,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/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index f9d9a882db1f..3a9fcfc95d00 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -419,6 +419,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 +482,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 +497,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 +520,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..a3bad54c0b5b 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -421,6 +421,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 +495,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 +512,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 +541,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/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/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/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_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/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/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/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_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_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_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/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/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/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/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/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-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/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index 8efa04c3807e..b76cb7f4b210 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -3312,7 +3312,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; } /* |
