summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/clk-qpnp-div.txt52
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dp.txt2
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-mdp.txt3
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-pll.txt2
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio_keys.txt49
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt54
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt30
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt6
-rw-r--r--Documentation/devicetree/bindings/regulator/cpr3-regulator.txt9
-rw-r--r--Documentation/devicetree/bindings/regulator/cpr4-mmss-ldo-regulator.txt5
-rw-r--r--Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt3
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,cx_ipeak.txt22
-rw-r--r--arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts8
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8998.dtsi83
-rw-r--r--arch/arm/boot/dts/qcom/msm-smb138x.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-cdp.dtsi35
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-gpu.dtsi271
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi66
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi47
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss.dtsi488
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mtp.dtsi35
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-qrd.dtsi80
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-regulator.dtsi203
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi207
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-common.dtsi47
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-coresight.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mtp.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-regulator.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi47
-rw-r--r--arch/arm/configs/msmcortex_defconfig1
-rw-r--r--arch/arm/configs/sdm660-perf_defconfig6
-rw-r--r--arch/arm/configs/sdm660_defconfig10
-rw-r--r--arch/arm/include/asm/cacheflush.h3
-rw-r--r--arch/arm/include/asm/device.h2
-rw-r--r--arch/arm/include/asm/dma-iommu.h3
-rw-r--r--arch/arm/include/asm/dma-mapping.h7
-rw-r--r--arch/arm/include/asm/glue-cache.h6
-rw-r--r--arch/arm/mm/dma-mapping.c26
-rw-r--r--arch/arm/mm/dma.h3
-rw-r--r--arch/arm64/Kconfig5
-rw-r--r--arch/arm64/configs/msm-perf_defconfig6
-rw-r--r--arch/arm64/configs/msm_defconfig5
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig1
-rw-r--r--arch/arm64/configs/msmcortex_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig709
-rw-r--r--arch/arm64/configs/sdm660_defconfig1
-rw-r--r--arch/arm64/kernel/entry.S3
-rw-r--r--arch/arm64/kernel/process.c2
-rw-r--r--arch/arm64/mm/dma-mapping.c10
-rw-r--r--arch/arm64/mm/fault.c22
-rw-r--r--drivers/base/cpu.c30
-rw-r--r--drivers/base/firmware_class.c3
-rw-r--r--drivers/base/regmap/Kconfig5
-rw-r--r--drivers/char/adsprpc.c1
-rw-r--r--drivers/clk/clk.c3
-rw-r--r--drivers/clk/clk.h1
-rw-r--r--drivers/clk/qcom/Kconfig9
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c26
-rw-r--r--drivers/clk/qcom/clk-branch.c18
-rw-r--r--drivers/clk/qcom/clk-qpnp-div.c440
-rw-r--r--drivers/clk/qcom/clk-rcg2.c41
-rw-r--r--drivers/clk/qcom/common.h17
-rw-r--r--drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c1
-rw-r--r--drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c47
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.c5
-rw-r--r--drivers/clk/qcom/mdss/mdss-pll.h1
-rw-r--r--drivers/clk/qcom/mmcc-msm8996.c729
-rw-r--r--drivers/crypto/msm/ice.c13
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c28
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_sspp.h12
-rw-r--r--drivers/gpu/drm/msm/sde/sde_plane.c71
-rw-r--r--drivers/gpu/msm/kgsl.c7
-rw-r--r--drivers/input/keyboard/gpio_keys.c90
-rw-r--r--drivers/input/touchscreen/Kconfig11
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/gt9xx/goodix_tool.c8
-rw-r--r--drivers/input/touchscreen/st/Kconfig9
-rw-r--r--drivers/input/touchscreen/st/Makefile5
-rw-r--r--drivers/input/touchscreen/st/fts.c2354
-rw-r--r--drivers/input/touchscreen/st/fts.h249
-rw-r--r--drivers/input/touchscreen/st/fts_driver_test.c871
-rw-r--r--drivers/input/touchscreen/st/fts_fw.h10
-rw-r--r--drivers/input/touchscreen/st/fts_gui.c359
-rw-r--r--drivers/input/touchscreen/st/fts_lib/Makefile7
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCompensation.c591
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCompensation.h146
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c43
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h34
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsError.c105
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsError.h75
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFlash.c1071
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFlash.h79
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFrame.c569
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFrame.h49
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsGesture.c393
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsGesture.h74
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsHardware.h177
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsIO.c403
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsIO.h35
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsSoftware.h131
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTest.c2324
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTest.h158
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTime.c84
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTime.h29
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTool.c706
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTool.h64
-rw-r--r--drivers/input/touchscreen/st/fts_limits.h10
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c6
-rw-r--r--drivers/iommu/dma-mapping-fast.c19
-rw-r--r--drivers/iommu/io-pgtable-fast.c59
-rw-r--r--drivers/iommu/iommu-debug.c38
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c2
-rw-r--r--drivers/leds/leds-qpnp-flash.c78
-rw-r--r--drivers/media/dvb-core/dvb_demux.c91
-rw-r--r--drivers/media/dvb-core/dvb_demux.h25
-rw-r--r--drivers/media/platform/msm/broadcast/tspp.c166
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c40
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c16
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c8
-rw-r--r--drivers/media/platform/msm/dvb/adapter/Makefile1
-rw-r--r--drivers/media/platform/msm/dvb/demux/Kconfig8
-rw-r--r--drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c1720
-rw-r--r--drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h108
-rw-r--r--drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c28
-rw-r--r--drivers/media/platform/msm/dvb/include/mpq_adapter.h29
-rw-r--r--drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h36
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_base.c39
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_base.h12
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c19
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h30
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h4
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c73
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c4
-rw-r--r--drivers/media/platform/msm/vidc/msm_smem.c22
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c64
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c166
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c13
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c26
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c6
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_internal.h6
-rw-r--r--drivers/misc/qseecom.c8
-rw-r--r--drivers/net/ethernet/msm/msm_rmnet_mhi.c1
-rw-r--r--drivers/net/ethernet/msm/rndis_ipa.c63
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c8
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h7
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c85
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c78
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h226
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c90
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.c7
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c21
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c36
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h27
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c66
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h23
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c56
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.h1
-rw-r--r--drivers/platform/msm/ipa/ipa_api.c5
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c2
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_utils.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c34
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_client.c30
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c149
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_flt.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h1
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c18
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c210
-rw-r--r--drivers/platform/msm/mhi/mhi_ring_ops.c6
-rw-r--r--drivers/platform/msm/mhi/mhi_ssr.c4
-rw-r--r--drivers/platform/msm/mhi/mhi_sys.c4
-rw-r--r--drivers/platform/msm/mhi_uci/mhi_uci.c22
-rw-r--r--drivers/power/power_supply_sysfs.c13
-rw-r--r--drivers/power/supply/qcom/battery.c69
-rw-r--r--drivers/power/supply/qcom/fg-core.h18
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c141
-rw-r--r--drivers/power/supply/qcom/qpnp-fg.c32
-rw-r--r--drivers/power/supply/qcom/qpnp-qnovo.c84
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c145
-rw-r--r--drivers/power/supply/qcom/smb-lib.c572
-rw-r--r--drivers/power/supply/qcom/smb-lib.h73
-rw-r--r--drivers/power/supply/qcom/smb-reg.h1
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c112
-rw-r--r--drivers/power/supply/qcom/storm-watch.c11
-rw-r--r--drivers/power/supply/qcom/storm-watch.h16
-rw-r--r--drivers/regulator/cpr3-regulator.c11
-rw-r--r--drivers/regulator/cpr3-regulator.h7
-rw-r--r--drivers/regulator/cpr3-util.c8
-rw-r--r--drivers/regulator/cpr4-mmss-ldo-regulator.c4
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c243
-rw-r--r--drivers/scsi/ufs/ufshcd.c34
-rw-r--r--drivers/soc/qcom/Kconfig9
-rw-r--r--drivers/soc/qcom/Makefile3
-rw-r--r--drivers/soc/qcom/cx_ipeak.c202
-rw-r--r--drivers/soc/qcom/glink_spi_xprt.c4
-rw-r--r--drivers/soc/qcom/icnss.c43
-rw-r--r--drivers/soc/qcom/peripheral-loader.c31
-rw-r--r--drivers/soc/qcom/qbt1000.c51
-rw-r--r--drivers/soc/qcom/qdsp6v2/voice_svc.c26
-rw-r--r--drivers/soc/qcom/rpm_rail_stats.c329
-rw-r--r--drivers/soc/qcom/spcom.c71
-rw-r--r--drivers/soc/qcom/spss_utils.c22
-rw-r--r--drivers/spi/spi_qsd.c3
-rw-r--r--drivers/spi/spi_qsd.h7
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--drivers/usb/gadget/function/f_qc_rndis.c2
-rw-r--r--drivers/usb/gadget/function/rndis.c1
-rw-r--r--drivers/usb/gadget/function/u_data_ipa.c31
-rw-r--r--drivers/usb/pd/policy_engine.c88
-rw-r--r--drivers/usb/phy/phy-msm-qusb.c11
-rw-r--r--drivers/video/fbdev/msm/mdss.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_debug.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c11
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c14
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c29
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.h30
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c29
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c22
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c7
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_rotator.c8
-rw-r--r--drivers/video/fbdev/msm/mdss_smmu.c3
-rw-r--r--fs/fuse/dev.c4
-rw-r--r--include/dt-bindings/clock/qcom,mmcc-msm8996.h485
-rw-r--r--include/linux/mdss_smmu_ext.h4
-rw-r--r--include/linux/power_supply.h8
-rw-r--r--include/linux/qcom_tspp.h11
-rw-r--r--include/soc/qcom/cx_ipeak.h46
-rw-r--r--include/soc/qcom/qseecomi.h5
-rw-r--r--include/sound/apr_audio-v2.h185
-rw-r--r--include/sound/q6afe-v2.h4
-rw-r--r--include/sound/q6asm-v2.h6
-rw-r--r--include/trace/events/power.h2
-rw-r--r--include/uapi/linux/dvb/dmx.h3
-rw-r--r--include/uapi/linux/msm_ipa.h4
-rw-r--r--include/uapi/linux/msm_mdp.h1
-rw-r--r--include/uapi/linux/msm_mdp_ext.h94
-rw-r--r--kernel/power/qos.c6
-rw-r--r--kernel/sched/core_ctl.c19
-rw-r--r--kernel/sched/fair.c54
-rw-r--r--kernel/sched/hmp.c6
-rw-r--r--net/core/skbuff.c6
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c56
-rw-r--r--sound/soc/msm/msm8998.c326
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c63
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c630
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c131
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c197
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h4
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c114
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c181
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c86
265 files changed, 22489 insertions, 2820 deletions
diff --git a/Documentation/devicetree/bindings/clock/clk-qpnp-div.txt b/Documentation/devicetree/bindings/clock/clk-qpnp-div.txt
new file mode 100644
index 000000000000..03b7b70d7f7e
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-qpnp-div.txt
@@ -0,0 +1,52 @@
+Qualcomm Technologies, Inc. QPNP clock divider (clkdiv)
+
+clkdiv configures the clock frequency of a set of outputs on the PMIC.
+These clocks are typically wired through alternate functions on
+gpio pins.
+
+=======================
+Supported Properties
+=======================
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: should be "qcom,qpnp-clkdiv".
+
+- reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Addresses and sizes for the memory of this CLKDIV
+ peripheral.
+
+- qcom,cxo-freq
+ Usage: required
+ Value type: <u32>
+ Definition: The frequency of the crystal oscillator (CXO) clock in Hz.
+
+- qcom,clkdiv-id
+ Usage: required
+ Value type: <u32>
+ Definition: Integer value specifies the hardware identifier of this
+ CLKDIV peripheral.
+
+- qcom,clkdiv-init-freq
+ Usage: optional
+ Value type: <u32>
+ Definition: Initial output frequency in Hz to configure for the CLKDIV
+ peripheral. The initial frequency value should be less than
+ or equal to CXO clock frequency and greater than or equal to
+ CXO_freq/64.
+
+=======
+Example
+=======
+
+qcom,clkdiv@5b00 {
+ compatible = "qcom,qpnp-clkdiv";
+ reg = <0x5b00 0x100>;
+
+ qcom,cxo-freq = <19200000>;
+ qcom,clkdiv-id = <1>;
+ qcom,clkdiv-init-freq = <9600000>;
+};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dp.txt b/Documentation/devicetree/bindings/fb/mdss-dp.txt
index 7bf7b9bacb60..aa227c2628da 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dp.txt
@@ -54,6 +54,7 @@ Optional properties:
device node. Refer to pinctrl-bindings.txt
- qcom,logical2physical-lane-map: An array that specifies the DP logical to physical lane map setting.
- qcom,phy-register-offset: An integer specifying the offset value of DP PHY register space.
+- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port.
Example:
mdss_dp_ctrl: qcom,dp_ctrl@c990000 {
@@ -89,6 +90,7 @@ Example:
qcom,aux-cfg-settings = [00 13 00 10 0a 26 0a 03 8b 03];
qcom,logical2physical-lane-map = [02 03 01 00];
qcom,phy-register-offset = <0x4>;
+ qcom,max-pclk-frequency-khz = <593470>;
qcom,core-supply-entries {
#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 7a98e4e8fdd2..0ab4d53f2663 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -92,6 +92,8 @@ Required properties
active in MDP for this configuration. Meant for
hardware that has hw cursors support as a
source pipe.
+- qcom,mdss-rot-xin-id: Array of VBIF clients ids (xins) corresponding
+ to the respective rotator pipes.
- qcom,mdss-pipe-cursor-xin-id: Array of VBIF clients ids (xins) corresponding
to the respective cursor pipes. Number of xin ids
defined should match the number of offsets
@@ -754,6 +756,7 @@ Example:
qcom,mdss-pipe-rgb-xin-id = <1 5 9>;
qcom,mdss-pipe-dma-xin-id = <2 10>;
qcom,mdss-pipe-cursor-xin-id = <7 7>;
+ qcom,mdss-rot-xin-id = <14 15>;
qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>,
<0x3B4 0 0>,
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index b9d4ebfb79e3..c3a1567340a8 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -16,7 +16,7 @@ Required properties:
"qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8",
"qcom,mdss_dsi_pll_8998", "qcom,mdss_dp_pll_8998",
"qcom,mdss_hdmi_pll_8998", "qcom,mdss_dsi_pll_sdm660",
- "qcom,mdss_dp_pll_sdm660"
+ "qcom,mdss_dp_pll_sdm660", "qcom,mdss_dsi_pll_sdm630"
- cell-index: Specifies the controller used
- reg: offset and length of the register set for the device.
- reg-names : names to refer to register sets related to this device
diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
new file mode 100644
index 000000000000..0a9b31a946ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
@@ -0,0 +1,49 @@
+Device-Tree bindings for input/gpio_keys.c keyboard driver
+
+Required properties:
+ - compatible = "gpio-keys";
+
+Optional properties:
+ - input-name: input name of the device.
+ - autorepeat: Boolean, Enable auto repeat feature of Linux input subsystem.
+ - pinctrl-names : This should be defined if a target uses pinctrl framework.
+ See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+ It should specify the names of the configs that pinctrl can install in drive.
+
+ Following are the pinctrl configs that can be installed:
+ "gpio_ts_active" : Active configuration of pins, this should specify active
+ config defined in pin groups of interrupt and reset gpio.
+ "gpio_ts_suspend" : Disabled configuration of pins, this should specify sleep
+ config defined in pin groups of interrupt and reset gpio.
+
+Each button (key) is represented as a sub-node of "gpio-keys":
+Subnode properties:
+
+ - gpios: OF device-tree gpio specification.
+ - label: Descriptive name of the key.
+ - linux,code: Keycode to emit.
+
+Optional subnode-properties:
+ - linux,input-type: Specify event type this button/key generates.
+ If not specified defaults to <1> == EV_KEY.
+ - debounce-interval: Debouncing interval time in milliseconds.
+ If not specified defaults to 5.
+ - gpio-key,wakeup: Boolean, button can wake-up the system.
+
+Example nodes:
+
+gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ autorepeat;
+ input-name = "gpio-keys";
+ pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+ pinctrl-0 = <&gpio_key_active>;
+ pinctrl-1 = <&gpio_key_suspend>;
+ button@21 {
+ label = "GPIO Key UP";
+ linux,code = <103>;
+ gpios = <&gpio1 0 1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt b/Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt
new file mode 100644
index 000000000000..7799392700a7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt
@@ -0,0 +1,54 @@
+STMicroelectronics touch controller
+
+The STMicroelectronics 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 "st,fts".
+ - 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-supply : Power source required to power up i2c bus.
+ - st,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.
+ - st,reset-gpio : reset gpio to control the reset of chip.
+ - 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.
+ - st,regulator_avdd : name of Power supply needed to power up the device.
+ - st,regulator_dvdd : name of Power source required to power up i2c bus.
+Optional properties:
+
+
+Example:
+ i2c@78b9000 { /* BLSP1 QUP5 */
+ st_fts@49 {
+ compatible = "st,fts";
+ reg = <0x49>;
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <13 0x2008>;
+ vdd-supply = <&pm8916_l17>;
+ vcc-supply = <&pm8916_l6>;
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ st,irq-gpio = <&msm_gpio 13 0x00000001>;
+ st,reset-gpio = <&msm_gpio 12 0x0>;
+ st,regulator_dvdd = "vdd";
+ st,regulator_avdd = "avdd";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index 8adfeebb1580..af80de7f5f1f 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -215,6 +215,12 @@ First Level Node - FG Gen3 device
capacity learning cycle. If this is not specified, then
the default value is 0. Unit is in decipercentage.
+- qcom,battery-thermal-coefficients
+ Usage: optional
+ Value type: <u8>
+ Definition: Byte array of battery thermal coefficients.
+ This should be exactly 3 bytes in length.
+
- qcom,fg-jeita-hyst-temp
Usage: optional
Value type: <u32>
@@ -320,6 +326,27 @@ First Level Node - FG Gen3 device
to be configured in conjunction with the charger side
configuration for proper functionality.
+- qcom,slope-limit-temp-threshold
+ Usage: optional
+ Value type: <u32>
+ Definition: Battery temperature threshold to decide when slope limit
+ coefficients should be applied along with charging status.
+ Unit is in decidegC.
+
+- qcom,slope-limit-coeffs
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: A list of integers which holds the slope limit coefficients
+ in the following order. Allowed size is 4. Possible values
+ are from 0 to 31. Unit is in decipercentage.
+ Element 0 - Low temperature discharging
+ Element 1 - Low temperature charging
+ Element 2 - High temperature discharging
+ Element 3 - High temperature charging
+ These coefficients have to be specified along with the
+ property "qcom,slope-limit-temp-threshold" to make dynamic
+ slope limit adjustment functional.
+
==========================================================
Second Level Nodes - Peripherals managed by FG Gen3 driver
==========================================================
@@ -354,6 +381,9 @@ pmi8998_fg: qpnp,fg {
qcom,ki-coeff-soc-dischg = <30 60 90>;
qcom,ki-coeff-med-dischg = <800 1000 1400>;
qcom,ki-coeff-hi-dischg = <1200 1500 2100>;
+ qcom,slope-limit-temp-threshold = <100>;
+ qcom,slope-limit-coeffs = <10 11 12 13>;
+ qcom,battery-thermal-coefficients = [9d 50 ff];
status = "okay";
qcom,fg-batt-soc@4000 {
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index eabdc6a75fbe..5a2c3ecd3d1e 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -163,6 +163,12 @@ Charger specific properties:
Definition: Boolean flag which indicates that the platform only support
micro usb port.
+- qcom,suspend-input-on-debug-batt
+ Usage: optional
+ Value type: <empty>
+ Definition: Boolean flag which when present enables intput suspend for
+ debug battery.
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
index af53e59cd87f..37e8391259c6 100644
--- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
@@ -209,6 +209,15 @@ Platform independent properties:
as the corresponding addresses are specified in
the qcom,cpr-panic-reg-addr-list property.
+- qcom,cpr-reset-step-quot-loop-en
+ Usage: optional; only meaningful for CPR4 and CPRh controllers
+ Value type: <empty>
+ Definition: Boolean value which indicates that the CPR controller should
+ be configured to reset step_quot on each loop_en = 0
+ transition. This configuration allows the CPR controller to
+ first use the default step_quot and then later switch to the
+ run-time calibrated step_quot.
+
=================================================
Second Level Nodes - CPR Threads for a Controller
=================================================
diff --git a/Documentation/devicetree/bindings/regulator/cpr4-mmss-ldo-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr4-mmss-ldo-regulator.txt
index 851528517f4c..4af9cd38d77d 100644
--- a/Documentation/devicetree/bindings/regulator/cpr4-mmss-ldo-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr4-mmss-ldo-regulator.txt
@@ -28,7 +28,8 @@ MMSS LDO specific properties:
Usage: required
Value type: <string>
Definition: should be the following:
- "qcom,cpr4-sdm660-mmss-ldo-regulator".
+ "qcom,cpr4-sdm660-mmss-ldo-regulator" for SDM660,
+ "qcom,cpr4-sdm630-mmss-ldo-regulator" for SDM630.
- clocks
Usage: required
@@ -71,7 +72,7 @@ MMSS specific properties:
Usage: required
Value type: <u32>
Definition: Specifies the number of fuse corners. This value must be 6
- for sdm660 GFX LDO. These fuse corners are: MinSVS,
+ for sdm660/sdm630 GFX LDO. These fuse corners are: MinSVS,
LowSVS, SVS, SVSP, NOM and NOMP. The open-loop voltage fuses
are allocated for LowSVS, SVS, NOM and NOMP corners. The
open-loop voltages for MinSVS and SVSP are derived by
diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
index ff800352cc05..446046ced77e 100644
--- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
@@ -34,7 +34,8 @@ KBSS specific properties:
"qcom,cprh-msm8998-v1-kbss-regulator",
"qcom,cprh-msm8998-v2-kbss-regulator",
"qcom,cprh-msm8998-kbss-regulator",
- "qcom,cprh-sdm660-kbss-regulator".
+ "qcom,cprh-sdm660-kbss-regulator",
+ "qcom,cprh-sdm630-kbss-regulator".
If the SoC revision is not specified, then it is assumed to
be the most recent revision of MSM8998, i.e. v2.
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,cx_ipeak.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,cx_ipeak.txt
new file mode 100644
index 000000000000..d5fb03cc9318
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,cx_ipeak.txt
@@ -0,0 +1,22 @@
+* Cx iPeak driver to handle requests from various multimedia clients.
+
+Cx ipeak HW module is used to limit the current drawn by various subsystem
+blocks on Cx power rail. Each client needs to set their
+bit in tcsr register if it is going to cross its own threshold. If all
+clients are going to cross their thresholds then Cx ipeak hw module will raise
+an interrupt to cDSP block to throttle cDSP's fmax.
+
+Required properties:
+
+- compatible : name of the component used for driver matching, should be
+ "qcom,cx-ipeak-sdm660"
+
+- reg : physical base address and length of the register set(s), SRAM and XPU
+ of the component.
+
+Example:
+
+ cx_ipeak_lm: cx_ipeak@1fe5040 {
+ compatible = "qcom,cx-ipeak-sdm660";
+ reg = <0x01fe5040 0x28>;
+ };
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
index f84708d73bd8..daf43d49e079 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
+++ b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
@@ -21,10 +21,6 @@
qcom,board-id = <8 1>;
};
-&pil_modem {
- status = "disabled";
-};
-
&msm_ath10k_wlan {
status = "ok";
};
@@ -78,3 +74,7 @@
status = "ok";
};
+
+&tspp {
+ qcom,lpass-timer-tts = <1>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index ca5b22cd34ee..131ad649ef8b 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -607,6 +607,8 @@
qcom,lra-high-z = "opt1";
qcom,lra-auto-res-mode = "qwd";
qcom,lra-res-cal-period = <4>;
+ qcom,correct-lra-drive-freq;
+ qcom,misc-trim-error-rc19p2-clk-reg-present;
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
index 72f9f9ea9b2d..c21c136907d4 100644
--- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
@@ -164,11 +164,12 @@
qcom,chgr@1000 {
reg = <0x1000 0x100>;
- interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>,
- <0x2 0x10 0x1 IRQ_TYPE_NONE>,
- <0x2 0x10 0x2 IRQ_TYPE_NONE>,
- <0x2 0x10 0x3 IRQ_TYPE_NONE>,
- <0x2 0x10 0x4 IRQ_TYPE_NONE>;
+ interrupts =
+ <0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "chg-error",
"chg-state-change",
@@ -179,10 +180,10 @@
qcom,otg@1100 {
reg = <0x1100 0x100>;
- interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>,
- <0x2 0x11 0x1 IRQ_TYPE_NONE>,
- <0x2 0x11 0x2 IRQ_TYPE_NONE>,
- <0x2 0x11 0x3 IRQ_TYPE_NONE>;
+ interrupts = <0x2 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "otg-fail",
"otg-overcurrent",
@@ -192,12 +193,13 @@
qcom,bat-if@1200 {
reg = <0x1200 0x100>;
- interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>,
- <0x2 0x12 0x1 IRQ_TYPE_NONE>,
- <0x2 0x12 0x2 IRQ_TYPE_NONE>,
- <0x2 0x12 0x3 IRQ_TYPE_NONE>,
- <0x2 0x12 0x4 IRQ_TYPE_NONE>,
- <0x2 0x12 0x5 IRQ_TYPE_NONE>;
+ interrupts =
+ <0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "bat-temp",
"bat-ocp",
@@ -209,14 +211,15 @@
qcom,usb-chgpth@1300 {
reg = <0x1300 0x100>;
- interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>,
- <0x2 0x13 0x1 IRQ_TYPE_NONE>,
- <0x2 0x13 0x2 IRQ_TYPE_NONE>,
- <0x2 0x13 0x3 IRQ_TYPE_NONE>,
- <0x2 0x13 0x4 IRQ_TYPE_NONE>,
- <0x2 0x13 0x5 IRQ_TYPE_NONE>,
- <0x2 0x13 0x6 IRQ_TYPE_NONE>,
- <0x2 0x13 0x7 IRQ_TYPE_NONE>;
+ interrupts =
+ <0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "usbin-collapse",
"usbin-lt-3p6v",
@@ -230,13 +233,14 @@
qcom,dc-chgpth@1400 {
reg = <0x1400 0x100>;
- interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>,
- <0x2 0x14 0x1 IRQ_TYPE_NONE>,
- <0x2 0x14 0x2 IRQ_TYPE_NONE>,
- <0x2 0x14 0x3 IRQ_TYPE_NONE>,
- <0x2 0x14 0x4 IRQ_TYPE_NONE>,
- <0x2 0x14 0x5 IRQ_TYPE_NONE>,
- <0x2 0x14 0x6 IRQ_TYPE_NONE>;
+ interrupts =
+ <0x2 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "dcin-collapse",
"dcin-lt-3p6v",
@@ -249,14 +253,15 @@
qcom,chgr-misc@1600 {
reg = <0x1600 0x100>;
- interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>,
- <0x2 0x16 0x1 IRQ_TYPE_NONE>,
- <0x2 0x16 0x2 IRQ_TYPE_NONE>,
- <0x2 0x16 0x3 IRQ_TYPE_NONE>,
- <0x2 0x16 0x4 IRQ_TYPE_NONE>,
- <0x2 0x16 0x5 IRQ_TYPE_NONE>,
- <0x2 0x16 0x6 IRQ_TYPE_NONE>,
- <0x2 0x16 0x7 IRQ_TYPE_NONE>;
+ interrupts =
+ <0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+ <0x2 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "wdog-snarl",
"wdog-bark",
@@ -641,6 +646,8 @@
qcom,lra-high-z = "opt1";
qcom,lra-auto-res-mode = "qwd";
qcom,lra-res-cal-period = <4>;
+ qcom,correct-lra-drive-freq;
+ qcom,misc-trim-error-rc19p2-clk-reg-present;
};
flash_led: qcom,leds@d300 {
diff --git a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
index 138fa2b57248..8edc1fc61830 100644
--- a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
@@ -108,6 +108,12 @@
"connector_temp_thr3",
"charger_temp_max";
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "chg-state-change";
+ };
+
qcom,chgr-misc@1600 {
reg = <0x1600 0x100>;
interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
index 7dfcd34c2743..24186aca22be 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
@@ -45,6 +45,7 @@
/* VBIF QoS remapper settings*/
qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>;
+ qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>;
qcom,vbif-settings = <0x00ac 0x00000040>,
<0x00d0 0x00001010>; /* v1 only */
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index 8acbb6600415..697b049235bd 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -1750,7 +1750,7 @@
tx-fifo-resize;
snps,nominal-elastic-buffer;
snps,disable-clk-gating;
- snps,hird_thresh = <0x10>;
+ snps,hird-threshold = /bits/ 8 <0x10>;
snps,num-gsi-evt-buffs = <0x3>;
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi
index af288ff26d06..d223197ad878 100644
--- a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi
@@ -101,3 +101,38 @@
status = "ok";
};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_nt35695b_truly_fhd_video>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 53 0>;
+ qcom,platform-te-gpio = <&tlmm 59 0>;
+};
+
+&pm660l_wled {
+ qcom,led-strings-list = [01 02];
+};
+
+&dsi_nt35695b_truly_fhd_video {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_nt35695b_truly_fhd_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
new file mode 100644
index 000000000000..eec0862e5ee3
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
@@ -0,0 +1,271 @@
+/* Copyright (c) 2017, 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.
+ */
+
+&soc {
+ pil_gpu: qcom,kgsl-hyp {
+ compatible = "qcom,pil-tz-generic";
+ qcom,pas-id = <13>;
+ qcom,firmware-name = "a508_zap";
+ };
+
+ msm_bus: qcom,kgsl-busmon{
+ label = "kgsl-busmon";
+ compatible = "qcom,kgsl-busmon";
+ };
+
+ gpubw: qcom,gpubw {
+ compatible = "qcom,devbw";
+ governor = "bw_vbif";
+ qcom,src-dst-ports = <26 512>;
+ /*
+ * active-only flag is used while registering the bus
+ * governor. It helps release the bus vote when the CPU
+ * subsystem is inactive
+ */
+ qcom,active-only;
+ /*
+ * IB votes in MBPS, derived using below formula
+ * IB = (DDR frequency * DDR bus width in Bytes * Dual rate)
+ * Note: IB vote is per DDR channel vote
+ */
+ qcom,bw-tbl =
+ < 0 /* off */ >,
+ < 381 /* 100 MHz */ >,
+ < 572 /* 150 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1571 /* 412 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5161 /* 1353 MHz */ >;
+ };
+
+ msm_gpu: qcom,kgsl-3d0@5000000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ status = "ok";
+ reg = <0x5000000 0x40000>;
+ reg-names = "kgsl_3d0_reg_memory";
+ interrupts = <0 300 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x05000800>;
+
+ qcom,initial-pwrlevel = <5>;
+
+ /* <HZ/12> */
+ qcom,idle-timeout = <80>;
+
+ qcom,highest-bank-bit = <14>;
+
+ /* size in bytes */
+ qcom,snapshot-size = <1048576>;
+
+ clocks = <&clock_gfx GPUCC_GFX3D_CLK>,
+ <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+ <&clock_gfx GPUCC_RBBMTIMER_CLK>,
+ <&clock_gcc GCC_GPU_BIMC_GFX_CLK>,
+ <&clock_gcc GCC_BIMC_GFX_CLK>,
+ <&clock_gpu GPUCC_RBCPR_CLK>;
+
+ clock-names = "core_clk", "iface_clk", "rbbmtimer_clk",
+ "mem_clk", "alt_mem_iface_clk", "rbcpr_clk";
+
+ /* Bus Scale Settings */
+ qcom,gpubw-dev = <&gpubw>;
+ qcom,bus-control;
+ /* GPU to BIMC bus width, VBIF data transfer in 1 cycle */
+ qcom,bus-width = <32>;
+ qcom,msm-bus,name = "grp3d";
+ qcom,msm-bus,num-cases = <14>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>,
+ <26 512 0 400000>, /* 1 bus=100 */
+ <26 512 0 600000>, /* 2 bus=150 */
+ <26 512 0 800000>, /* 3 bus=200 */
+ <26 512 0 1200000>, /* 4 bus=300 */
+ <26 512 0 1648000>, /* 5 bus=412 */
+ <26 512 0 2188000>, /* 6 bus=547 */
+ <26 512 0 2724000>, /* 7 bus=681 */
+ <26 512 0 3072000>, /* 8 bus=768 */
+ <26 512 0 4068000>, /* 9 bus=1017 */
+ <26 512 0 5184000>, /* 10 bus=1296 */
+ <26 512 0 5412000>; /* 11 bus=1353 */
+
+ /* GDSC regulator names */
+ regulator-names = "vddcx", "vdd";
+ /* GDSC oxili regulators */
+ vddcx-supply = <&gdsc_gpu_cx>;
+ vdd-supply = <&gdsc_gpu_gx>;
+
+ /* CPU latency parameter */
+ qcom,pm-qos-active-latency = <349>;
+ qcom,pm-qos-wakeup-latency = <349>;
+
+ /* Quirks */
+ qcom,gpu-quirk-dp2clockgating-disable;
+ qcom,gpu-quirk-lmloadkill-disable;
+
+ /* Enable context aware freq. scaling */
+ qcom,enable-ca-jump;
+
+ /* Context aware jump busy penalty in us */
+ qcom,ca-busy-penalty = <12000>;
+
+ /* Context aware jump target power level */
+ qcom,ca-target-pwrlevel = <4>;
+
+ /* GPU Mempools */
+ qcom,gpu-mempools {
+ #address-cells= <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-mempools";
+
+ qcom,mempool-max-pages = <32768>;
+
+ /* 4K Page Pool configuration */
+ qcom,gpu-mempool@0 {
+ reg = <0>;
+ qcom,mempool-page-size = <4096>;
+ };
+ /* 64K Page Pool configuration */
+ qcom,gpu-mempool@1 {
+ reg = <1>;
+ qcom,mempool-page-size = <65536>;
+ };
+ };
+
+ /* Power levels */
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <775000000>;
+ qcom,bus-freq = <11>;
+ qcom,bus-min = <10>;
+ qcom,bus-max = <11>;
+ };
+
+ /* TURBO */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <700000000>;
+ qcom,bus-freq = <10>;
+ qcom,bus-min = <9>;
+ qcom,bus-max = <11>;
+ };
+
+ /* NOM_L1 */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <647000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <8>;
+ qcom,bus-max = <9>;
+ };
+
+ /* NOM */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <588000000>;
+ qcom,bus-freq = <9>;
+ qcom,bus-min = <7>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS_L1 */
+ qcom,gpu-pwrlevel@4 {
+ reg = <4>;
+ qcom,gpu-freq = <465000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <9>;
+ };
+
+ /* SVS */
+ qcom,gpu-pwrlevel@5 {
+ reg = <5>;
+ qcom,gpu-freq = <370000000>;
+ qcom,bus-freq = <5>;
+ qcom,bus-min = <4>;
+ qcom,bus-max = <7>;
+ };
+
+ /* Low SVS */
+ qcom,gpu-pwrlevel@6 {
+ reg = <6>;
+ qcom,gpu-freq = <240000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ /* Min SVS */
+ qcom,gpu-pwrlevel@7 {
+ reg = <7>;
+ qcom,gpu-freq = <160000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <2>;
+ qcom,bus-max = <4>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@8 {
+ reg = <8>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
+ };
+ };
+
+ kgsl_msm_iommu: qcom,kgsl-iommu {
+ compatible = "qcom,kgsl-smmu-v2";
+
+ reg = <0x05040000 0x10000>;
+ qcom,protect = <0x40000 0x10000>;
+ qcom,micro-mmu-control = <0x6000>;
+
+ clocks = <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+ <&clock_gcc GCC_GPU_BIMC_GFX_CLK>,
+ <&clock_gcc GCC_BIMC_GFX_CLK>;
+
+ clock-names = "iface_clk", "mem_clk", "alt_mem_iface_clk";
+
+ qcom,secure_align_mask = <0xfff>;
+ qcom,retention;
+ qcom,hyp_secure_alloc;
+
+ gfx3d_user: gfx3d_user {
+ compatible = "qcom,smmu-kgsl-cb";
+ label = "gfx3d_user";
+ iommus = <&kgsl_smmu 0>;
+ qcom,gpu-offset = <0x48000>;
+ };
+
+ gfx3d_secure: gfx3d_secure {
+ compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 2>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
new file mode 100644
index 000000000000..a07118486322
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
@@ -0,0 +1,66 @@
+/* Copyright (c) 2017, 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 "dsi-panel-sim-video.dtsi"
+#include "dsi-panel-nt35695b-truly-fhd-video.dtsi"
+#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi"
+
+&soc {
+ dsi_panel_pwr_supply: dsi_panel_pwr_supply {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "wqhd-vddio";
+ qcom,supply-min-voltage = <1880000>;
+ qcom,supply-max-voltage = <1950000>;
+ qcom,supply-enable-load = <32000>;
+ qcom,supply-disable-load = <80>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <10>;
+ };
+ };
+};
+
+&dsi_nt35695b_truly_fhd_video {
+ qcom,mdss-dsi-panel-timings-phy-v2 = [24 1e 08 09 05 03 04 a0
+ 24 1e 08 09 05 03 04 a0
+ 24 1e 08 09 05 03 04 a0
+ 24 1e 08 09 05 03 04 a0
+ 24 1a 08 09 05 03 04 a0];
+};
+
+&dsi_nt35695b_truly_fhd_cmd {
+ qcom,mdss-dsi-panel-timings-phy-v2 = [24 1e 08 09 05 03 04 a0
+ 24 1e 08 09 05 03 04 a0
+ 24 1e 08 09 05 03 04 a0
+ 24 1e 08 09 05 03 04 a0
+ 24 1a 08 09 05 03 04 a0];
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi
new file mode 100644
index 000000000000..82acdec92431
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi
@@ -0,0 +1,47 @@
+/* Copyright (c) 2017, 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.
+ */
+
+&soc {
+ mdss_dsi0_pll: qcom,mdss_dsi_pll@c994400 {
+ compatible = "qcom,mdss_dsi_pll_sdm630";
+ status = "ok";
+ label = "MDSS DSI 0 PLL";
+ cell-index = <0>;
+ #clock-cells = <1>;
+
+ reg = <0xc994400 0x588>,
+ <0xc8c2300 0x8>;
+ reg-names = "pll_base", "gdsc_base";
+
+ gdsc-supply = <&gdsc_mdss>;
+
+ clocks = <&clock_mmss MMSS_MDSS_AHB_CLK>;
+ clock-names = "iface_clk";
+ clock-rate = <0>;
+ qcom,dsi-pll-ssc-en;
+ qcom,dsi-pll-ssc-mode = "down-spread";
+
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
new file mode 100644
index 000000000000..d7a0c33019f2
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
@@ -0,0 +1,488 @@
+/* Copyright (c) 2017, 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 <dt-bindings/clock/mdss-pll-clk.h>
+
+&soc {
+ mdss_mdp: qcom,mdss_mdp@c900000 {
+ compatible = "qcom,mdss_mdp";
+ status = "ok";
+ reg = <0x0c900000 0x90000>,
+ <0x0c9b0000 0x1040>;
+ reg-names = "mdp_phys", "vbif_phys";
+ interrupts = <0 83 0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ vdd-supply = <&gdsc_mdss>;
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_mdp";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>, <23 512 0 0>,
+ <22 512 0 6400000>, <23 512 0 6400000>,
+ <22 512 0 6400000>, <23 512 0 6400000>;
+
+ /* Fudge factors */
+ qcom,mdss-ab-factor = <1 1>; /* 1 time */
+ qcom,mdss-ib-factor = <1 1>; /* 1 time */
+ qcom,mdss-clk-factor = <105 100>; /* 1.05 times */
+
+ qcom,max-mixer-width = <2560>;
+ qcom,max-pipe-width = <2560>;
+
+ qcom,max-dest-scaler-input-width = <2048>;
+ qcom,max-dest-scaler-output-width = <2560>;
+
+ /* VBIF QoS remapper settings*/
+ qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>;
+ qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>;
+ qcom,vbif-settings = <0x00ac 0x00008040>,
+ <0x00d0 0x00002828>;
+
+ qcom,mdss-has-panic-ctrl;
+ qcom,mdss-per-pipe-panic-luts = <0x000f>,
+ <0xffff>,
+ <0xfffc>,
+ <0xff00>;
+
+ qcom,mdss-mdp-reg-offset = <0x00001000>;
+ qcom,max-bandwidth-low-kbps = <4100000>;
+ qcom,max-bandwidth-high-kbps = <4100000>;
+ qcom,max-bandwidth-per-pipe-kbps = <1 3200000>, /* Default */
+ <2 2400000>; /* Camera */
+ qcom,max-clk-rate = <412500000>;
+ qcom,mdss-default-ot-rd-limit = <32>;
+ qcom,mdss-default-ot-wr-limit = <40>;
+ qcom,mdss-dram-channels = <2>;
+
+ /* Bandwidth limit settings */
+ qcom,max-bw-settings = <1 4100000>, /* Default */
+ <2 3000000>; /* Camera */
+
+ qcom,mdss-pipe-vig-off = <0x00005000>;
+ qcom,mdss-pipe-dma-off = <0x00025000 0x00027000 0x00029000>;
+ qcom,mdss-pipe-cursor-off = <0x00035000>;
+
+ qcom,mdss-pipe-vig-xin-id = <0>;
+ qcom,mdss-pipe-dma-xin-id = <1 5 9>;
+ qcom,mdss-pipe-cursor-xin-id = <2>;
+
+ /*
+ * These Offsets are relative to
+ * "mdp_phys + mdp-reg-offset" address
+ */
+ qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x2ac 0 0>;
+ qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2ac 8 12>,
+ <0x2b4 8 12>,
+ <0x2c4 8 12>;
+ qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3a8 16 15>;
+
+ qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400
+ 0x00002600 0x00002800>;
+ qcom,mdss-mixer-intf-off = <0x00045000 0x00047000>;
+ qcom,mdss-dspp-off = <0x00055000>;
+ qcom,mdss-wb-off = <0x00066000>;
+ qcom,mdss-intf-off = <0x0006b000 0x0006b800>;
+ qcom,mdss-pingpong-off = <0x00071000 0x00072000>;
+ qcom,mdss-slave-pingpong-off = <0x00073000>;
+ qcom,mdss-ppb-ctl-off = <0x00000330 0x00000338 0x00000370
+ 0x00000374> ;
+ qcom,mdss-ppb-cfg-off = <0x00000334 0x0000033C>;
+ qcom,mdss-has-pingpong-split;
+ qcom,mdss-has-separate-rotator;
+
+ qcom,mdss-ad-off = <0x0079000 0x00079800>;
+ qcom,mdss-cdm-off = <0x0007a200>;
+ qcom,mdss-wfd-mode = "intf";
+ qcom,mdss-has-source-split;
+ qcom,mdss-highest-bank-bit = <0x1>;
+ qcom,mdss-has-decimation;
+ qcom,mdss-idle-power-collapse-enabled;
+ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_AXI_CLK>,
+ <&clock_mmss MDP_CLK_SRC>,
+ <&clock_mmss MMSS_MDSS_MDP_CLK>,
+ <&clock_mmss MMSS_MDSS_VSYNC_CLK>,
+ <&clock_mmss MDP_CLK_SRC>;
+ clock-names = "mnoc_clk", "iface_clk", "bus_clk",
+ "core_clk_src", "core_clk", "vsync_clk",
+ "lut_clk";
+
+ qcom,mdp-settings = <0x01190 0x00000000>,
+ <0x012ac 0xc0000ccc>,
+ <0x012b4 0xc0000ccc>,
+ <0x012bc 0x00cccccc>,
+ <0x012c4 0x0000cccc>,
+ <0x013a8 0x0cccc0c0>,
+ <0x013b0 0xccccc0c0>,
+ <0x013b8 0xcccc0000>,
+ <0x013d0 0x00cc0000>,
+ <0x0506c 0x00000000>,
+ <0x0706c 0x00000000>,
+ <0x0906c 0x00000000>,
+ <0x0b06c 0x00000000>,
+ <0x1506c 0x00000000>,
+ <0x1706c 0x00000000>,
+ <0x1906c 0x00000000>,
+ <0x1b06c 0x00000000>,
+ <0x2506c 0x00000000>,
+ <0x2706c 0x00000000>;
+
+ qcom,regs-dump-mdp = <0x01000 0x01458>,
+ <0x02000 0x02094>,
+ <0x02200 0x02294>,
+ <0x02400 0x02494>,
+ <0x02600 0x02694>,
+ <0x02800 0x02894>,
+ <0x05000 0x05154>,
+ <0x05a00 0x05b00>,
+ <0x25000 0x25184>,
+ <0x27000 0x27184>,
+ <0x29000 0x29184>,
+ <0x35000 0x35150>,
+ <0x45000 0x452bc>,
+ <0x47000 0x472bc>,
+ <0x55000 0x5522c>,
+ <0x66000 0x662c0>,
+ <0x6b000 0x6b268>,
+ <0x6b800 0x6ba68>,
+ <0x71000 0x710d4>,
+ <0x72000 0x720d4>;
+
+ qcom,regs-dump-names-mdp = "MDP",
+ "CTL_0", "CTL_1", "CTL_2", "CTL_3", "CTL_4",
+ "VIG0_SSPP", "VIG0",
+ "DMA0_SSPP", "DMA1_SSPP","DMA2_SSPP",
+ "CURSOR0_SSPP",
+ "LAYER_0", "LAYER_2",
+ "DSPP_0",
+ "WB_2",
+ "INTF_0", "INTF_1",
+ "PP_0", "PP_2";
+
+ /* buffer parameters to calculate prefill bandwidth */
+ qcom,mdss-prefill-outstanding-buffer-bytes = <0>;
+ qcom,mdss-prefill-y-buffer-bytes = <0>;
+ qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>;
+ qcom,mdss-prefill-scaler-buffer-lines-caf = <4>;
+ qcom,mdss-prefill-post-scaler-buffer-pixels = <2560>;
+ qcom,mdss-prefill-pingpong-buffer-pixels = <5120>;
+
+ qcom,mdss-pp-offsets {
+ qcom,mdss-sspp-mdss-igc-lut-off = <0x2000>;
+ qcom,mdss-sspp-vig-pcc-off = <0x1b00>;
+ qcom,mdss-sspp-rgb-pcc-off = <0x380>;
+ qcom,mdss-sspp-dma-pcc-off = <0x380>;
+ qcom,mdss-lm-pgc-off = <0x3c0>;
+ qcom,mdss-dspp-gamut-off = <0x1600>;
+ qcom,mdss-dspp-pcc-off = <0x1700>;
+ qcom,mdss-dspp-pgc-off = <0x17c0>;
+ };
+
+ qcom,mdss-scaler-offsets {
+ qcom,mdss-vig-scaler-off = <0xa00>;
+ qcom,mdss-vig-scaler-lut-off = <0xb00>;
+ qcom,mdss-has-dest-scaler;
+ qcom,mdss-dest-block-off = <0x00061000>;
+ qcom,mdss-dest-scaler-off = <0x800 0x1000>;
+ qcom,mdss-dest-scaler-lut-off = <0x900 0x1100>;
+ };
+
+ smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb {
+ compatible = "qcom,smmu_mdp_unsec";
+ iommus = <&mmss_bimc_smmu 0>;
+ gdsc-mmagic-mdss-supply = <&gdsc_bimc_smmu>;
+ clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>,
+ <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>;
+ clock-names = "mmss_noc_axi_clk",
+ "mmss_noc_ahb_clk",
+ "mmss_smmu_ahb_clk",
+ "mmss_smmu_axi_clk";
+ };
+
+ smmu_mdp_sec: qcom,smmu_mdp_sec_cb {
+ compatible = "qcom,smmu_mdp_sec";
+ iommus = <&mmss_bimc_smmu 1>;
+ gdsc-mmagic-mdss-supply = <&gdsc_bimc_smmu>;
+ clocks = <&clock_rpmcc MMSSNOC_AXI_CLK>,
+ <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>;
+ clock-names = "mmss_noc_axi_clk",
+ "mmss_noc_ahb_clk",
+ "mmss_smmu_ahb_clk",
+ "mmss_smmu_axi_clk";
+ };
+
+ mdss_fb0: qcom,mdss_fb_primary {
+ cell-index = <0>;
+ compatible = "qcom,mdss-fb";
+ };
+
+ mdss_fb1: qcom,mdss_fb_wfd {
+ cell-index = <1>;
+ compatible = "qcom,mdss-fb";
+ };
+
+ mdss_fb2: qcom,mdss_fb_dp {
+ cell-index = <2>;
+ compatible = "qcom,mdss-fb";
+ qcom,mdss-intf = <&mdss_dp_ctrl>;
+ };
+ };
+
+ mdss_dsi: qcom,mdss_dsi@0 {
+ compatible = "qcom,mdss-dsi";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ gdsc-supply = <&gdsc_mdss>;
+ vdda-1p2-supply = <&pm660_l1>;
+ vdda-0p9-supply = <&pm660l_l1>;
+ ranges = <0xc994000 0xc994000 0x400
+ 0xc994400 0xc994400 0x588
+ 0xc828000 0xc828000 0xac>;
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_dsi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>,
+ <22 512 0 1000>;
+
+ qcom,mmss-ulp-clamp-ctrl-offset = <0x14>;
+
+ clocks = <&clock_mmss MMSS_MDSS_MDP_CLK>,
+ <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_AXI_CLK>,
+ <&clock_mmss MMSS_MISC_AHB_CLK>,
+ <&mdss_dsi0_pll BYTE0_MUX_CLK>,
+ <&mdss_dsi0_pll PIX0_MUX_CLK>;
+ clock-names = "mdp_core_clk",
+ "mnoc_clk", "iface_clk",
+ "bus_clk", "core_mmss_clk",
+ "ext_byte0_clk","ext_pixel0_clk";
+
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1250000>;
+ qcom,supply-enable-load = <12560>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <925000>;
+ qcom,supply-enable-load = <73400>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+
+ mdss_dsi0: qcom,mdss_dsi_ctrl0@c994000 {
+ compatible = "qcom,mdss-dsi-ctrl";
+ label = "MDSS DSI CTRL->0";
+ cell-index = <0>;
+ reg = <0xc994000 0x400>,
+ <0xc994400 0x588>,
+ <0xc828000 0xac>;
+ reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys";
+
+ qcom,timing-db-mode;
+ wqhd-vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+ qcom,mdss-mdp = <&mdss_mdp>;
+ qcom,mdss-fb-map = <&mdss_fb0>;
+
+ clocks = <&clock_mmss MMSS_MDSS_BYTE0_CLK>,
+ <&clock_mmss MMSS_MDSS_PCLK0_CLK>,
+ <&clock_mmss MMSS_MDSS_ESC0_CLK>,
+ <&clock_mmss BYTE0_CLK_SRC>,
+ <&clock_mmss PCLK0_CLK_SRC>,
+ <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>;
+ clock-names = "byte_clk", "pixel_clk", "core_clk",
+ "byte_clk_rcg", "pixel_clk_rcg",
+ "byte_intf_clk";
+
+ qcom,platform-strength-ctrl = [ff 06
+ ff 06
+ ff 06
+ ff 06
+ ff 00];
+ qcom,platform-regulator-settings = [1d
+ 1d 1d 1d 1d];
+ qcom,platform-lane-config = [00 00 10 0f
+ 00 00 10 0f
+ 00 00 10 0f
+ 00 00 10 0f
+ 00 00 10 8f];
+ };
+ };
+
+ qcom,mdss_wb_panel {
+ compatible = "qcom,mdss_wb";
+ qcom,mdss_pan_res = <640 480>;
+ qcom,mdss_pan_bpp = <24>;
+ qcom,mdss-fb-map = <&mdss_fb1>;
+ };
+
+ msm_ext_disp: qcom,msm_ext_disp {
+ status = "disabled";
+ compatible = "qcom,msm-ext-disp";
+
+ ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ qcom,msm_ext_disp = <&msm_ext_disp>;
+ };
+ };
+
+ mdss_dp_ctrl: qcom,dp_ctrl@c990000 {
+ status = "disabled";
+ cell-index = <0>;
+ compatible = "qcom,mdss-dp";
+ qcom,mdss-fb-map = <&mdss_fb2>;
+
+ gdsc-supply = <&gdsc_mdss>;
+ vdda-1p2-supply = <&pm660_l1>;
+ vdda-0p9-supply = <&pm660l_l1>;
+
+ reg = <0xc990000 0xa84>,
+ <0xc011000 0x910>,
+ <0x1fcb200 0x050>,
+ <0xc8c2200 0x1a0>,
+ <0x780000 0x621c>,
+ <0xc9e1000 0x02c>;
+ reg-names = "dp_ctrl", "dp_phy", "tcsr_regs", "dp_mmss_cc",
+ "qfprom_physical","hdcp_physical";
+
+ qcom,msm_ext_disp = <&msm_ext_disp>;
+
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1250000>;
+ qcom,supply-enable-load = <12560>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <925000>;
+ qcom,supply-enable-load = <73400>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+ };
+
+ mdss_rotator: qcom,mdss_rotator {
+ compatible = "qcom,sde_rotator";
+ reg = <0x0c900000 0xab100>,
+ <0x0c9b0000 0x1040>;
+ reg-names = "mdp_phys",
+ "rot_vbif_phys";
+
+ qcom,mdss-rot-mode = <1>;
+ qcom,mdss-highest-bank-bit = <0x1>;
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_rotator";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <22 512 0 0>,
+ <22 512 0 6400000>,
+ <22 512 0 6400000>;
+
+ rot-vdd-supply = <&gdsc_mdss>;
+ qcom,supply-names = "rot-vdd";
+
+ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_AHB_CLK>,
+ <&clock_mmss ROT_CLK_SRC>,
+ <&clock_mmss MMSS_MDSS_ROT_CLK>,
+ <&clock_mmss MMSS_MDSS_AXI_CLK>;
+ clock-names = "mnoc_clk",
+ "iface_clk", "rot_core_clk",
+ "rot_clk", "axi_clk";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <2 0>;
+
+ /* VBIF QoS remapper settings*/
+ qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>;
+ qcom,mdss-rot-xin-id = <14 15>;
+
+ qcom,mdss-default-ot-rd-limit = <32>;
+ qcom,mdss-default-ot-wr-limit = <40>;
+ };
+};
+
+#include "sdm630-mdss-panels.dtsi"
diff --git a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi
index a47f8419f41a..cdcea7654e3e 100644
--- a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi
@@ -110,3 +110,38 @@
status = "ok";
};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_nt35695b_truly_fhd_video>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 53 0>;
+ qcom,platform-te-gpio = <&tlmm 59 0>;
+};
+
+&pm660l_wled {
+ qcom,led-strings-list = [01 02];
+};
+
+&dsi_nt35695b_truly_fhd_video {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&dsi_nt35695b_truly_fhd_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
index 6779d80d76cf..59afb993fb83 100644
--- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
@@ -20,5 +20,85 @@
pinctrl-0 = <&uart_console_active>;
};
+&ufsphy1 {
+ vdda-phy-supply = <&pm660l_l1>;
+ vdda-pll-supply = <&pm660_l10>;
+ vddp-ref-clk-supply = <&pm660_l1>;
+ vdda-phy-max-microamp = <51400>;
+ vdda-pll-max-microamp = <14200>;
+ vddp-ref-clk-max-microamp = <100>;
+ vddp-ref-clk-always-on;
+ status = "ok";
+};
+
+&ufs1 {
+ vdd-hba-supply = <&gdsc_ufs>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm660l_l4>;
+ vccq2-supply = <&pm660_l8>;
+ vcc-max-microamp = <500000>;
+ vccq2-max-microamp = <600000>;
+ status = "ok";
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm660l_l4>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm660_l8>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm660l_l5>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm660l_l2>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 0 125 0
+ 1 &intc 0 0 221 0
+ 2 &tlmm 54 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&tlmm 54 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
&soc {
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
index c824ed12b3e7..13cf99ef0b40 100644
--- a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
@@ -633,4 +633,207 @@
};
};
};
+
+ /* APC0 CPR Controller node for Silver cluster */
+ apc0_cpr: cprh-ctrl@179c8000 {
+ compatible = "qcom,cprh-sdm630-kbss-regulator";
+ reg = <0x179c8000 0x4000>, <0x00784000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base";
+ clocks = <&clock_gcc GCC_HMSS_RBCPR_CLK>;
+ clock-names = "core_clk";
+ qcom,cpr-ctrl-name = "apc0";
+ qcom,cpr-controller-id = <0>;
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ qcom,cpr-up-down-delay-time = <3000>;
+ qcom,cpr-step-quot-init-min = <12>;
+ qcom,cpr-step-quot-init-max = <14>;
+ qcom,cpr-count-mode = <0>; /* All at once */
+ qcom,cpr-count-repeat = <14>;
+ qcom,cpr-down-error-step-limit = <1>;
+ qcom,cpr-up-error-step-limit = <1>;
+ qcom,cpr-corner-switch-delay-time = <1042>;
+ qcom,cpr-voltage-settling-time = <1760>;
+
+ qcom,apm-threshold-voltage = <872000>;
+ qcom,apm-crossover-voltage = <872000>;
+ qcom,apm-hysteresis-voltage = <20000>;
+ qcom,voltage-step = <4000>;
+ qcom,voltage-base = <400000>;
+ qcom,cpr-saw-use-unit-mV;
+
+ qcom,cpr-panic-reg-addr-list =
+ <0x179cbaa4 0x17912c18>;
+ qcom,cpr-panic-reg-name-list =
+ "PWR_CPRH_STATUS", "APCLUS0_L2_SAW4_PMIC_STS";
+
+ thread@0 {
+ qcom,cpr-thread-id = <0>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <2>;
+
+ apc0_pwrcl_vreg: regulator {
+ regulator-name = "apc0_pwrcl_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <8>;
+
+ qcom,cpr-fuse-corners = <4>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <8 8 8>;
+ qcom,cpr-corners = <8>;
+ qcom,cpr-corner-fmax-map = <2 4 5 8>;
+
+ qcom,cpr-voltage-ceiling =
+ <724000 724000 724000 788000 868000
+ 924000 988000 1068000>;
+
+ qcom,cpr-voltage-floor =
+ <588000 588000 596000 652000 712000
+ 744000 784000 844000>;
+
+ qcom,corner-frequencies =
+ <300000000 614400000 883200000
+ 1094400000 1382400000 1536000000
+ 1728000000 1843200000>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+ };
+ };
+ };
+
+ /* APC1 CPR Controller node for Gold cluster */
+ apc1_cpr: cprh-ctrl@179c4000 {
+ compatible = "qcom,cprh-sdm630-kbss-regulator";
+ reg = <0x179c4000 0x4000>, <0x00784000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base";
+ clocks = <&clock_gcc GCC_HMSS_RBCPR_CLK>;
+ clock-names = "core_clk";
+ qcom,cpr-ctrl-name = "apc1";
+ qcom,cpr-controller-id = <1>;
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ qcom,cpr-up-down-delay-time = <3000>;
+ qcom,cpr-step-quot-init-min = <12>;
+ qcom,cpr-step-quot-init-max = <14>;
+ qcom,cpr-count-mode = <0>; /* All at once */
+ qcom,cpr-count-repeat = <14>;
+ qcom,cpr-down-error-step-limit = <1>;
+ qcom,cpr-up-error-step-limit = <1>;
+ qcom,cpr-corner-switch-delay-time = <1042>;
+ qcom,cpr-voltage-settling-time = <1760>;
+
+ qcom,apm-threshold-voltage = <872000>;
+ qcom,apm-crossover-voltage = <872000>;
+ qcom,apm-hysteresis-voltage = <20000>;
+ qcom,voltage-step = <4000>;
+ qcom,voltage-base = <400000>;
+ qcom,cpr-saw-use-unit-mV;
+
+ qcom,cpr-panic-reg-addr-list =
+ <0x179c7aa4 0x17812c18>;
+ qcom,cpr-panic-reg-name-list =
+ "PERF_CPRH_STATUS", "APCLUS1_L2_SAW4_PMIC_STS";
+
+ thread@0 {
+ qcom,cpr-thread-id = <0>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <2>;
+
+ apc1_perfcl_vreg: regulator {
+ regulator-name = "apc1_perfcl_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <11>;
+
+ qcom,cpr-fuse-corners = <4>;
+ qcom,cpr-fuse-combos = <24>;
+ qcom,cpr-speed-bins = <3>;
+ qcom,cpr-speed-bin-corners = <10 10 11>;
+ qcom,cpr-corners =
+ /* Speed bin 0 */
+ <10 10 10 10 10 10 10 10>,
+
+ /* Speed bin 1 */
+ <10 10 10 10 10 10 10 10>,
+
+ /* Speed bin 2 */
+ <11 11 11 11 11 11 11 11>;
+
+ qcom,cpr-corner-fmax-map =
+ /* Speed bin 0 */
+ <2 4 6 10>,
+
+ /* Speed bin 1 */
+ <2 4 6 10>,
+
+ /* Speed bin 2 */
+ <2 4 6 11>;
+
+ qcom,cpr-voltage-ceiling =
+ /* Speed bin 0 */
+ <724000 724000 724000 788000
+ 868000 868000 924000 988000
+ 988000 1068000>,
+
+ /* Speed bin 1 */
+ <724000 724000 724000 788000
+ 868000 868000 924000 988000
+ 988000 1068000>,
+
+ /* Speed bin 2 */
+ <724000 724000 724000 788000
+ 868000 868000 924000 988000
+ 988000 1068000 1140000>;
+
+ qcom,cpr-voltage-floor =
+ /* Speed bin 0 */
+ <588000 588000 596000 652000
+ 712000 712000 744000 784000
+ 784000 844000>,
+
+ /* Speed bin 1 */
+ <588000 588000 596000 652000
+ 712000 712000 744000 784000
+ 784000 844000>,
+
+ /* Speed bin 2 */
+ <588000 588000 596000 652000
+ 712000 712000 744000 784000
+ 784000 844000 900000>;
+
+ qcom,corner-frequencies =
+ /* Speed bin 0 */
+ <300000000 787200000 1113600000
+ 1344000000 1516800000 1670400000
+ 1881600000 2016000000 2150400000
+ 2380800000>,
+
+ /* Speed bin 1 */
+ <300000000 787200000 1113600000
+ 1344000000 1516800000 1670400000
+ 1881600000 2016000000 2150400000
+ 2208000000>,
+
+ /* Speed bin 2 */
+ <300000000 787200000 1113600000
+ 1344000000 1516800000 1670400000
+ 1881600000 2016000000 2150400000
+ 2208000000 2515200000>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+ };
+ };
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index 6c54e8d9d14b..206628149f7d 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -712,6 +712,7 @@
qcom,synchronous-cluster-map = <0 4 &CPU4 &CPU5 &CPU6 &CPU7>,
<1 4 &CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,cxip-lm-enable = <0>;
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
@@ -1017,6 +1018,158 @@
#clock-cells = <1>;
};
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "performance";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 572 /* 150 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1571 /* 412 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5163 /* 1353 MHz */ >;
+ };
+
+ bwmon: qcom,cpu-bwmon {
+ compatible = "qcom,bimc-bwmon4";
+ reg = <0x01008000 0x300>, <0x01001000 0x200>;
+ reg-names = "base", "global_base";
+ interrupts = <0 183 4>;
+ qcom,mport = <0>;
+ qcom,hw-timer-hz = <19200000>;
+ qcom,target-dev = <&cpubw>;
+ };
+
+ mincpubw: qcom,mincpubw {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 572 /* 150 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1571 /* 412 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5163 /* 1353 MHz */ >;
+ };
+
+ memlat_cpu0: qcom,memlat-cpu0 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 572 /* 150 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1571 /* 412 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5163 /* 1353 MHz */ >;
+ };
+
+ memlat_cpu4: qcom,memlat-cpu4 {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 381 /* 100 MHz */ >,
+ < 572 /* 150 MHz */ >,
+ < 762 /* 200 MHz */ >,
+ < 1144 /* 300 MHz */ >,
+ < 1571 /* 412 MHz */ >,
+ < 2086 /* 547 MHz */ >,
+ < 2597 /* 681 MHz */ >,
+ < 2929 /* 768 MHz */ >,
+ < 3879 /* 1017 MHz */ >,
+ < 4943 /* 1296 MHz */ >,
+ < 5163 /* 1353 MHz */ >;
+ };
+
+ devfreq_memlat_0: qcom,arm-memlat-mon-0 {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ qcom,target-dev = <&memlat_cpu0>;
+ qcom,core-dev-table =
+ < 787200 762 >,
+ < 1344000 2086 >,
+ < 1670400 2929 >,
+ < 2150400 3879 >,
+ < 2380800 4943 >;
+ };
+
+ devfreq_memlat_4: qcom,arm-memlat-mon-4 {
+ compatible = "qcom,arm-memlat-mon";
+ qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>;
+ qcom,target-dev = <&memlat_cpu4>;
+ qcom,core-dev-table =
+ < 614400 762 >,
+ < 1536000 2929 >,
+ < 1728000 3879 >;
+ };
+
+ devfreq_cpufreq: devfreq-cpufreq {
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map-0 =
+ < 787200 762 >,
+ < 1344000 1571 >,
+ < 1881600 2929 >,
+ < 2380800 3879 >;
+ cpu-to-dev-map-4 =
+ < 614400 762 >,
+ < 1536000 1571 >,
+ < 1728000 3879 >;
+ };
+ };
+
+ msm_cpufreq: qcom,msm-cpufreq {
+ compatible = "qcom,msm-cpufreq";
+ clock-names = "cpu0_clk", "cpu4_clk";
+ clocks = <&clock_cpu PWRCL_CLK>,
+ <&clock_cpu PERFCL_CLK>;
+
+ qcom,governor-per-policy;
+
+ qcom,cpufreq-table-0 =
+ < 787200 >,
+ < 1113600 >,
+ < 1344000 >,
+ < 1670400 >,
+ < 1881600 >,
+ < 2150400 >,
+ < 2380800 >,
+ < 2515000 >;
+
+ qcom,cpufreq-table-4 =
+ < 614400 >,
+ < 883200 >,
+ < 1094400 >,
+ < 1382400 >,
+ < 1536000 >,
+ < 1728000 >,
+ < 1843200 >,
+ < 2000000 >;
+ };
+
ipa_hw: qcom,ipa@14780000 {
compatible = "qcom,ipa";
reg = <0x14780000 0x4effc>, <0x14784000 0x26934>;
@@ -1111,8 +1264,8 @@
< 883200000 0x0404002e 0x04250025 0x1 3 >,
< 1094400000 0x04040039 0x052e002e 0x2 4 >,
< 1382400000 0x04040048 0x07390039 0x2 5 >,
- < 1536000000 0x04040050 0x08400040 0x3 6 >,
- < 1728000000 0x0404005a 0x09480048 0x3 7 >,
+ < 1536000000 0x04040050 0x08400040 0x2 6 >,
+ < 1728000000 0x0404005a 0x09480048 0x2 7 >,
< 1843200000 0x04040060 0x094c004c 0x3 8 >;
qcom,perfcl-speedbin0-v0 =
@@ -1122,9 +1275,9 @@
< 1344000000 0x04040046 0x07380038 0x2 4 >,
< 1516800000 0x0404004f 0x073f003f 0x2 5 >,
< 1670400000 0x04040057 0x08450045 0x2 6 >,
- < 1881600000 0x04040062 0x094e004e 0x3 7 >,
- < 2016000000 0x04040069 0x0a540054 0x3 8 >,
- < 2150400000 0x04040070 0x0b590059 0x3 9 >,
+ < 1881600000 0x04040062 0x094e004e 0x2 7 >,
+ < 2016000000 0x04040069 0x0a540054 0x2 8 >,
+ < 2150400000 0x04040070 0x0b590059 0x2 9 >,
< 2380800000 0x0404007c 0x0c630063 0x3 10 >;
qcom,perfcl-speedbin1-v0 =
@@ -1134,9 +1287,9 @@
< 1344000000 0x04040046 0x07380038 0x2 4 >,
< 1516800000 0x0404004f 0x073f003f 0x2 5 >,
< 1670400000 0x04040057 0x08450045 0x2 6 >,
- < 1881600000 0x04040062 0x094e004e 0x3 7 >,
- < 2016000000 0x04040069 0x0a540054 0x3 8 >,
- < 2150400000 0x04040070 0x0b590059 0x3 8 >,
+ < 1881600000 0x04040062 0x094e004e 0x2 7 >,
+ < 2016000000 0x04040069 0x0a540054 0x2 8 >,
+ < 2150400000 0x04040070 0x0b590059 0x2 8 >,
< 2208000000 0x04040073 0x0b5c005c 0x3 10 >;
qcom,perfcl-speedbin2-v0 =
@@ -1146,9 +1299,9 @@
< 1344000000 0x04040046 0x07380038 0x2 4 >,
< 1516800000 0x0404004f 0x073f003f 0x2 5 >,
< 1670400000 0x04040057 0x08450045 0x2 6 >,
- < 1881600000 0x04040062 0x094e004e 0x3 7 >,
- < 2016000000 0x04040069 0x0a540054 0x3 8 >,
- < 2150400000 0x04040070 0x0b590059 0x3 9 >,
+ < 1881600000 0x04040062 0x094e004e 0x2 7 >,
+ < 2016000000 0x04040069 0x0a540054 0x2 8 >,
+ < 2150400000 0x04040070 0x0b590059 0x2 9 >,
< 2380800000 0x0404007c 0x0c630063 0x3 10 >,
< 2515200000 0x04040083 0x0d680068 0x3 11 >;
@@ -1246,7 +1399,7 @@
dcc: dcc@10b3000 {
compatible = "qcom,dcc";
reg = <0x10b3000 0x1000>,
- <0x10b4000 0x800>;
+ <0x10b4000 0x2000>;
reg-names = "dcc-base", "dcc-ram-base";
clocks = <&clock_gcc GCC_DCC_AHB_CLK>;
@@ -1912,9 +2065,12 @@
#include "msm-arm-smmu-630.dtsi"
#include "msm-audio.dtsi"
#include "sdm660-audio.dtsi"
+#include "sdm630-gpu.dtsi"
#include "sdm660-camera.dtsi"
#include "sdm630-pm.dtsi"
#include "sdm660-vidc.dtsi"
+#include "sdm630-mdss.dtsi"
+#include "sdm630-mdss-pll.dtsi"
&gdsc_usb30 {
status = "ok";
@@ -1986,3 +2142,30 @@
&blsp2_uart1_hs {
status = "ok";
};
+
+&soc {
+ gpio_keys {
+ status = "okay";
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+ pinctrl-0 = <&gpio_key_active>;
+ pinctrl-1 = <&gpio_key_suspend>;
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&tlmm 64 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 113 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
index 5a0997faf133..05b7973f2457 100644
--- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
@@ -25,12 +25,58 @@
status = "disabled";
};
+ ufs_ice: ufsice@1db0000 {
+ compatible = "qcom,ice";
+ reg = <0x1db0000 0x8000>;
+ qcom,enable-ice-clk;
+ clock-names = "ufs_core_clk", "bus_clk",
+ "iface_clk", "ice_core_clk";
+ clocks = <&clock_gcc GCC_UFS_AXI_CLK>,
+ <&clock_gcc GCC_UFS_CLKREF_CLK>,
+ <&clock_gcc GCC_UFS_AHB_CLK>,
+ <&clock_gcc GCC_UFS_ICE_CORE_CLK>;
+ qcom,op-freq-hz = <0>, <0>, <0>, <300000000>;
+ vdd-hba-supply = <&gdsc_ufs>;
+ qcom,msm-bus,name = "ufs_ice_noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 650 0 0>, /* No vote */
+ <1 650 1000 0>; /* Max. bandwidth */
+ qcom,bus-vector-names = "MIN",
+ "MAX";
+ qcom,instance-type = "ufs";
+ };
+
+ sdcc1_ice: sdcc1ice@c0c8000 {
+ compatible = "qcom,ice";
+ reg = <0xc0c8000 0x8000>;
+ qcom,enable-ice-clk;
+ clock-names = "ice_core_clk_src", "ice_core_clk",
+ "bus_clk", "iface_clk";
+ clocks = <&clock_gcc SDCC1_ICE_CORE_CLK_SRC>,
+ <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>,
+ <&clock_gcc GCC_SDCC1_APPS_CLK>,
+ <&clock_gcc GCC_SDCC1_AHB_CLK>;
+ qcom,op-freq-hz = <300000000>, <0>, <0>, <0>;
+ qcom,msm-bus,name = "sdcc_ice_noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <78 512 0 0>, /* No vote */
+ <78 512 1000 0>; /* Max. bandwidth */
+ qcom,bus-vector-names = "MIN",
+ "MAX";
+ qcom,instance-type = "sdcc";
+ };
+
ufs1: ufshc@1da4000 {
compatible = "qcom,ufshc";
reg = <0x1da4000 0x3000>;
interrupts = <0 265 0>;
phys = <&ufsphy1>;
phy-names = "ufsphy";
+ ufs-qcom-crypto = <&ufs_ice>;
clock-names =
"core_clk",
@@ -415,6 +461,7 @@
qcom,bus-width = <8>;
qcom,large-address-bus;
+ sdhc-msm-crypto = <&sdcc1_ice>;
qcom,devfreq,freq-table = <50000000 200000000>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi
index 431da5036a4b..dce86a7ceec3 100644
--- a/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi
@@ -25,6 +25,7 @@
arm,buffer-size = <0x400000>;
arm,sg-enable;
+ arm,default-sink;
coresight-ctis = <&cti0 &cti8>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
index ec79dd63e4d2..7f82a00e9f19 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
@@ -494,7 +494,7 @@
qcom,aux-cfg-settings = [00 13 00 00 0a 28 0a 03 b7 03];
qcom,logical2physical-lane-map = [00 01 02 03];
qcom,phy-register-offset = <0x4>;
- qcom,max-pclk-frequency-khz = <593470>;
+ qcom,max-pclk-frequency-khz = <300000>;
qcom,core-supply-entries {
#address-cells = <1>;
@@ -575,6 +575,7 @@
/* VBIF QoS remapper settings*/
qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>;
+ qcom,mdss-rot-xin-id = <14 15>;
qcom,mdss-default-ot-rd-limit = <32>;
qcom,mdss-default-ot-wr-limit = <40>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi
index 150b88c10646..23514467ba73 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi
@@ -242,3 +242,15 @@
&pm660_fg {
qcom,battery-data = <&mtp_batterydata>;
};
+
+&i2c_2 {
+ status = "ok";
+ smb1351-charger@1d {
+ compatible = "qcom,smb1351-charger";
+ reg = <0x1d>;
+ qcom,parallel-charger;
+ qcom,float-voltage-mv = <4400>;
+ qcom,recharge-mv = <100>;
+ qcom,parallel-en-pin-polarity = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
index f0d13b3455ab..49b58c8be8d5 100644
--- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
@@ -110,16 +110,6 @@
};
&pm660_gpios {
- /* GPIO 11 for home key */
- gpio@ca00 {
- status = "ok";
- qcom,mode = <0>;
- qcom,pull = <0>;
- qcom,vin-sel = <0>;
- qcom,src-sel = <0>;
- qcom,out-strength = <1>;
- };
-
/* GPIO 4 (NFC_CLK_REQ) */
gpio@c300 {
qcom,mode = <0>;
@@ -210,16 +200,6 @@
gpio-key,wakeup;
debounce-interval = <15>;
};
-
- home {
- label = "home";
- gpios = <&pm660_gpios 11 0x1>;
- linux,input-type = <1>;
- linux,code = <102>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
};
hbtp {
diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
index 0826f94a2296..44796eeb7059 100644
--- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
@@ -547,6 +547,7 @@
qcom,cpr-step-quot-init-max = <14>;
qcom,cpr-count-mode = <0>; /* All at once */
qcom,cpr-count-repeat = <14>;
+ qcom,cpr-reset-step-quot-loop-en;
vdd-supply = <&gfx_stub_vreg>;
mem-acc-supply = <&gfx_mem_acc_vreg>;
@@ -664,6 +665,7 @@
qcom,voltage-step = <4000>;
qcom,voltage-base = <400000>;
qcom,cpr-saw-use-unit-mV;
+ qcom,cpr-reset-step-quot-loop-en;
qcom,cpr-panic-reg-addr-list =
<0x179cbaa4 0x17912c18>;
@@ -738,6 +740,7 @@
qcom,voltage-step = <4000>;
qcom,voltage-base = <400000>;
qcom,cpr-saw-use-unit-mV;
+ qcom,cpr-reset-step-quot-loop-en;
qcom,cpr-panic-reg-addr-list =
<0x179c7aa4 0x17812c18>;
diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi
index 6077699ebea9..8633d89821ec 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -1307,51 +1307,6 @@
< 2457600 >;
};
- ufs_ice: ufsice@1db0000 {
- compatible = "qcom,ice";
- reg = <0x1db0000 0x8000>;
- qcom,enable-ice-clk;
- clock-names = "ufs_core_clk", "bus_clk",
- "iface_clk", "ice_core_clk";
- clocks = <&clock_gcc GCC_UFS_AXI_CLK>,
- <&clock_gcc GCC_UFS_CLKREF_CLK>,
- <&clock_gcc GCC_UFS_AHB_CLK>,
- <&clock_gcc GCC_UFS_ICE_CORE_CLK>;
- qcom,op-freq-hz = <0>, <0>, <0>, <300000000>;
- vdd-hba-supply = <&gdsc_ufs>;
- qcom,msm-bus,name = "ufs_ice_noc";
- qcom,msm-bus,num-cases = <2>;
- qcom,msm-bus,num-paths = <1>;
- qcom,msm-bus,vectors-KBps =
- <1 650 0 0>, /* No vote */
- <1 650 1000 0>; /* Max. bandwidth */
- qcom,bus-vector-names = "MIN",
- "MAX";
- qcom,instance-type = "ufs";
- };
-
- sdcc1_ice: sdcc1ice@c0c8000 {
- compatible = "qcom,ice";
- reg = <0xc0c8000 0x8000>;
- qcom,enable-ice-clk;
- clock-names = "ice_core_clk_src", "ice_core_clk",
- "bus_clk", "iface_clk";
- clocks = <&clock_gcc SDCC1_ICE_CORE_CLK_SRC>,
- <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>,
- <&clock_gcc GCC_SDCC1_APPS_CLK>,
- <&clock_gcc GCC_SDCC1_AHB_CLK>;
- qcom,op-freq-hz = <300000000>, <0>, <0>, <0>;
- qcom,msm-bus,name = "sdcc_ice_noc";
- qcom,msm-bus,num-cases = <2>;
- qcom,msm-bus,num-paths = <1>;
- qcom,msm-bus,vectors-KBps =
- <78 512 0 0>, /* No vote */
- <78 512 1000 0>; /* Max. bandwidth */
- qcom,bus-vector-names = "MIN",
- "MAX";
- qcom,instance-type = "sdcc";
- };
-
sdhc_1: sdhci@c0c4000 {
compatible = "qcom,sdhci-msm-v5";
reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>;
@@ -1614,7 +1569,7 @@
dcc: dcc@10b3000 {
compatible = "qcom,dcc";
reg = <0x10b3000 0x1000>,
- <0x10b4000 0x800>;
+ <0x10b4000 0x2000>;
reg-names = "dcc-base", "dcc-ram-base";
clocks = <&clock_gcc GCC_DCC_AHB_CLK>;
diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig
index 2cfe647855c3..1658cc992ee6 100644
--- a/arch/arm/configs/msmcortex_defconfig
+++ b/arch/arm/configs/msmcortex_defconfig
@@ -217,6 +217,7 @@ CONFIG_NFC_NQ=y
CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=40
CONFIG_ZRAM=y
diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig
index dcf4f6fa0031..7df369de029a 100644
--- a/arch/arm/configs/sdm660-perf_defconfig
+++ b/arch/arm/configs/sdm660-perf_defconfig
@@ -327,12 +327,14 @@ CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG_GEN3=y
CONFIG_SMB1351_USB_CHARGER=y
CONFIG_MSM_BCL_CTL=y
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_BATTERY_BCL=y
CONFIG_QPNP_SMB2=y
CONFIG_SMB138X_CHARGER=y
+CONFIG_QPNP_QNOVO=y
CONFIG_APSS_CORE_EA=y
CONFIG_MSM_APM=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -376,6 +378,9 @@ CONFIG_USB_VIDEO_CLASS=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA=y
CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_VMEM=y
+CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_DVB_MPQ=m
CONFIG_DVB_MPQ_DEMUX=m
@@ -496,6 +501,7 @@ CONFIG_MSM_MMCC_660=y
CONFIG_CLOCK_CPU_OSM=y
CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig
index 633b9ad305bc..3a757a7dc7b5 100644
--- a/arch/arm/configs/sdm660_defconfig
+++ b/arch/arm/configs/sdm660_defconfig
@@ -324,12 +324,14 @@ CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG_GEN3=y
CONFIG_SMB1351_USB_CHARGER=y
CONFIG_MSM_BCL_CTL=y
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_BATTERY_BCL=y
CONFIG_QPNP_SMB2=y
CONFIG_SMB138X_CHARGER=y
+CONFIG_QPNP_QNOVO=y
CONFIG_APSS_CORE_EA=y
CONFIG_MSM_APM=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
@@ -374,8 +376,9 @@ CONFIG_USB_VIDEO_CLASS=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA=y
CONFIG_MSM_CAMERA_DEBUG=y
-CONFIG_MSM_VIDC_V4L2=m
-CONFIG_MSM_VIDC_GOVERNORS=m
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_VMEM=y
+CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
CONFIG_DVB_MPQ=m
@@ -444,6 +447,7 @@ CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_RING_BUFFER=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_CLKGATE=y
CONFIG_MMC_BLOCK_MINORS=32
@@ -496,6 +500,8 @@ CONFIG_MSM_MMCC_660=y
CONFIG_CLOCK_CPU_OSM=y
CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 2e2d1657e604..012a3aafcf33 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -178,6 +178,9 @@ extern void __cpuc_flush_dcache_area(void *, size_t);
* is visible to DMA, or data written by DMA to system memory is
* visible to the CPU.
*/
+extern void __dma_map_area(const void *, size_t, int);
+extern void __dma_unmap_area(const void *, size_t, int);
+
extern void dmac_inv_range(const void *, const void *);
extern void dmac_clean_range(const void *, const void *);
extern void dmac_flush_range(const void *, const void *);
diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h
index 4111592f0130..d8a572f9c187 100644
--- a/arch/arm/include/asm/device.h
+++ b/arch/arm/include/asm/device.h
@@ -7,7 +7,7 @@
#define ASMARM_DEVICE_H
struct dev_archdata {
- struct dma_map_ops *dma_ops;
+ const struct dma_map_ops *dma_ops;
#ifdef CONFIG_DMABOUNCE
struct dmabounce_device_info *dmabounce;
#endif
diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index b4e74af0abb7..74643f5b41c4 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -8,6 +8,7 @@
#include <linux/dma-debug.h>
#include <linux/kmemcheck.h>
#include <linux/kref.h>
+#include <linux/dma-mapping-fast.h>
struct dma_iommu_mapping {
/* iommu specific data */
@@ -22,6 +23,8 @@ struct dma_iommu_mapping {
spinlock_t lock;
struct kref kref;
+
+ struct dma_fast_smmu_mapping *fast;
};
#ifdef CONFIG_ARM_DMA_USE_IOMMU
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index ccb3aa64640d..05ff03aead43 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -17,14 +17,14 @@
extern struct dma_map_ops arm_dma_ops;
extern struct dma_map_ops arm_coherent_dma_ops;
-static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
+static inline const struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
if (dev && dev->archdata.dma_ops)
return dev->archdata.dma_ops;
return &arm_dma_ops;
}
-static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+static inline const struct dma_map_ops *get_dma_ops(struct device *dev)
{
if (xen_initial_domain())
return xen_dma_ops;
@@ -32,7 +32,8 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
return __generic_dma_ops(dev);
}
-static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
+static inline void set_dma_ops(struct device *dev,
+ const struct dma_map_ops *ops)
{
BUG_ON(!dev);
dev->archdata.dma_ops = ops;
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index 1f442995cdbf..7a4893e61866 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -161,6 +161,12 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
#define dmac_inv_range __glue(_CACHE, _dma_inv_range)
#define dmac_clean_range __glue(_CACHE, _dma_clean_range)
+#define dmac_map_area __glue(_CACHE, _dma_map_area)
+#define dmac_unmap_area __glue(_CACHE, _dma_unmap_area)
+
+#define __dma_map_area dmac_map_area
+#define __dma_unmap_area dmac_unmap_area
+#define __dma_flush_range dmac_flush_range
#endif
#endif
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 330061d3d081..b58d8e0d9ed1 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -29,6 +29,7 @@
#include <linux/sizes.h>
#include <linux/cma.h>
#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/dma-mapping-fast.h>
#include <asm/memory.h>
#include <asm/highmem.h>
@@ -1019,7 +1020,7 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, struct dma_attrs *attrs)
{
- struct dma_map_ops *ops = get_dma_ops(dev);
+ const struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i, j;
@@ -1053,7 +1054,7 @@ int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, struct dma_attrs *attrs)
{
- struct dma_map_ops *ops = get_dma_ops(dev);
+ const struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i;
@@ -1072,7 +1073,7 @@ void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
- struct dma_map_ops *ops = get_dma_ops(dev);
+ const struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i;
@@ -1091,7 +1092,7 @@ void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
- struct dma_map_ops *ops = get_dma_ops(dev);
+ const struct dma_map_ops *ops = get_dma_ops(dev);
struct scatterlist *s;
int i;
@@ -1988,7 +1989,7 @@ static void arm_iommu_sync_single_for_device(struct device *dev,
__dma_page_cpu_to_dev(page, offset, size, dir);
}
-struct dma_map_ops iommu_ops = {
+const struct dma_map_ops iommu_ops = {
.alloc = arm_iommu_alloc_attrs,
.free = arm_iommu_free_attrs,
.mmap = arm_iommu_mmap_attrs,
@@ -2007,7 +2008,7 @@ struct dma_map_ops iommu_ops = {
.set_dma_mask = arm_dma_set_mask,
};
-struct dma_map_ops iommu_coherent_ops = {
+const struct dma_map_ops iommu_coherent_ops = {
.alloc = arm_iommu_alloc_attrs,
.free = arm_iommu_free_attrs,
.mmap = arm_iommu_mmap_attrs,
@@ -2166,6 +2167,11 @@ int arm_iommu_attach_device(struct device *dev,
{
int err;
int s1_bypass = 0;
+ int is_fast = 0;
+
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
+ if (is_fast)
+ return fast_smmu_attach_device(dev, mapping);
err = __arm_iommu_attach_device(dev, mapping);
if (err)
@@ -2182,6 +2188,7 @@ EXPORT_SYMBOL_GPL(arm_iommu_attach_device);
static void __arm_iommu_detach_device(struct device *dev)
{
struct dma_iommu_mapping *mapping;
+ int is_fast;
mapping = to_dma_iommu_mapping(dev);
if (!mapping) {
@@ -2191,6 +2198,9 @@ static void __arm_iommu_detach_device(struct device *dev)
if (msm_dma_unmap_all_for_dev(dev))
dev_warn(dev, "IOMMU detach with outstanding mappings\n");
+ iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_FAST, &is_fast);
+ if (is_fast)
+ return fast_smmu_detach_device(dev, mapping);
iommu_detach_device(mapping->domain, dev);
kref_put(&mapping->kref, release_iommu_mapping);
@@ -2226,7 +2236,7 @@ void arm_iommu_detach_device(struct device *dev)
}
EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
-static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
+static const struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
{
return coherent ? &iommu_coherent_ops : &iommu_ops;
}
@@ -2289,7 +2299,7 @@ static struct dma_map_ops *arm_get_dma_map_ops(bool coherent)
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
struct iommu_ops *iommu, bool coherent)
{
- struct dma_map_ops *dma_ops;
+ const struct dma_map_ops *dma_ops;
dev->archdata.dma_coherent = coherent;
if (arm_setup_iommu_dma_ops(dev, dma_base, size, iommu))
diff --git a/arch/arm/mm/dma.h b/arch/arm/mm/dma.h
index 70ea6852f94e..29c54f7d81f3 100644
--- a/arch/arm/mm/dma.h
+++ b/arch/arm/mm/dma.h
@@ -4,9 +4,6 @@
#include <asm/glue-cache.h>
#ifndef MULTI_CACHE
-#define dmac_map_area __glue(_CACHE,_dma_map_area)
-#define dmac_unmap_area __glue(_CACHE,_dma_unmap_area)
-
/*
* These are private to the dma-mapping API. Do not use directly.
* Their sole purpose is to ensure that data held in the cache
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8ac5ba251136..f8d50d8c5379 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -620,6 +620,11 @@ config ARCH_NR_GPIO
If unsure, leave the default value.
+config QCOM_TLB_EL2_HANDLER
+ bool "Raise TLB conflict exception to EL2"
+ help
+ This option enables TLB conflict to be handled
+ by EL2.
source kernel/Kconfig.preempt
source kernel/Kconfig.hz
diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index f184c571331a..03c5bc89b6f5 100644
--- a/arch/arm64/configs/msm-perf_defconfig
+++ b/arch/arm64/configs/msm-perf_defconfig
@@ -345,6 +345,7 @@ CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_WCD9335_CODEC=y
+CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_RPM_SMD=y
CONFIG_REGULATOR_QPNP=y
@@ -394,7 +395,7 @@ CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_QCOM_KGSL=y
-CONFIG_DRM=y
+CONFIG_FB=y
CONFIG_FB_MSM=y
CONFIG_FB_MSM_MDSS=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
@@ -518,6 +519,7 @@ CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y
CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SPM=y
+CONFIG_QCOM_SCM=y
CONFIG_QCOM_SCM_XPU=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
@@ -550,6 +552,7 @@ CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
CONFIG_SENSORS_SSC=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
@@ -561,6 +564,7 @@ CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_ECRYPT_FS=y
CONFIG_ECRYPT_FS_MESSAGING=y
diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig
index a7d2b895e08c..b4ddd9a2bed5 100644
--- a/arch/arm64/configs/msm_defconfig
+++ b/arch/arm64/configs/msm_defconfig
@@ -332,6 +332,7 @@ CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_WCD9335_CODEC=y
+CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_RPM_SMD=y
CONFIG_REGULATOR_QPNP=y
@@ -382,7 +383,7 @@ CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_QCOM_KGSL=y
-CONFIG_DRM=y
+CONFIG_FB=y
CONFIG_FB_MSM=y
CONFIG_FB_MSM_MDSS=y
CONFIG_FB_MSM_MDSS_WRITEBACK=y
@@ -519,6 +520,7 @@ CONFIG_MSM_IPC_ROUTER_MHI_XPRT=y
CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SPM=y
+CONFIG_QCOM_SCM=y
CONFIG_QCOM_SCM_XPU=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
@@ -568,6 +570,7 @@ CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_ECRYPT_FS=y
CONFIG_ECRYPT_FS_MESSAGING=y
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 1498b51b8080..f64ca9a07c6e 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -52,6 +52,7 @@ CONFIG_PCI=y
CONFIG_PCI_MSM=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
+CONFIG_QCOM_TLB_EL2_HANDLER=y
CONFIG_PREEMPT=y
CONFIG_HZ_100=y
CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index 31c30dcac64e..f08cd3b27c81 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -53,12 +53,14 @@ CONFIG_PCI=y
CONFIG_PCI_MSM=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
+CONFIG_QCOM_TLB_EL2_HANDLER=y
CONFIG_PREEMPT=y
CONFIG_HZ_100=y
CONFIG_CLEANCACHE=y
CONFIG_CMA=y
CONFIG_CMA_DEBUGFS=y
CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
@@ -546,7 +548,6 @@ CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_IRQ_HELPER=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_ICNSS=y
-CONFIG_ICNSS_DEBUG=y
CONFIG_MSM_GLADIATOR_ERP_V2=y
CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
new file mode 100644
index 000000000000..967edf184f1b
--- /dev/null
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -0,0 +1,709 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_SCHED_HMP_CSTATE_AWARE=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_AIO is not set
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8998=y
+CONFIG_ARCH_MSMHAMSTER=y
+CONFIG_PCI=y
+CONFIG_PCI_MSM=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_HZ_100=y
+CONFIG_CLEANCACHE=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_SOCKEV_NLMCAST=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_BTFM_SLIM=y
+CONFIG_BTFM_SLIM_WCN3990=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+# CONFIG_CFG80211_CRDA_SUPPORT is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=m
+CONFIG_MAC80211_MESH=y
+CONFIG_MAC80211_LEDS=y
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_HDCP_QSEECOM=y
+CONFIG_UID_CPUTIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_DM_ANDROID_VERITY=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_RNDIS_IPA=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_USB_USBNET=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_ATH_CARDS=y
+CONFIG_WIL6210=m
+CONFIG_ATH10K=m
+CONFIG_ATH10K_TARGET_SNOC=m
+CONFIG_ATH10K_SNOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y
+CONFIG_SECURE_TOUCH=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SOUNDWIRE=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_PINCTRL_MSM8998=y
+CONFIG_PINCTRL_SDM660=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG_GEN3=y
+CONFIG_MSM_BCL_CTL=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_BATTERY_BCL=y
+CONFIG_QPNP_SMB2=y
+CONFIG_SMB138X_CHARGER=y
+CONFIG_QPNP_QNOVO=y
+CONFIG_MSM_PM=y
+CONFIG_APSS_CORE_EA=y
+CONFIG_MSM_APM=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_CPU_THERMAL=y
+CONFIG_LIMITS_MONITOR=y
+CONFIG_LIMITS_LITE_HW=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_QCOM_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_MFD_I2C_PMIC=y
+CONFIG_WCD9335_CODEC=y
+CONFIG_WCD934X_CODEC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_CPR3_HMSS=y
+CONFIG_REGULATOR_CPR3_MMSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_ADV_DEBUG=y
+CONFIG_VIDEO_FIXED_MINOR_RANGES=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA=y
+CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_MSMB_CAMERA_DEBUG=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI20_HEADER=y
+CONFIG_MSM_CSI22_HEADER=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSI31_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_EEPROM=y
+CONFIG_MSM_ISPIF=y
+CONFIG_IMX134=y
+CONFIG_IMX132=y
+CONFIG_OV9724=y
+CONFIG_OV5648=y
+CONFIG_GC0339=y
+CONFIG_OV8825=y
+CONFIG_OV8865=y
+CONFIG_s5k4e1=y
+CONFIG_OV12830=y
+CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
+CONFIG_MSMB_JPEG=y
+CONFIG_MSM_FD=y
+CONFIG_MSM_JPEGDMA=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_VMEM=y
+CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
+CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y
+CONFIG_TSPP=m
+CONFIG_QCOM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_DP_PANEL=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_AUDIO_QMI=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8998=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_PLANTRONICS=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_ISP1760_HOST_ROLE=y
+CONFIG_USB_PD_POLICY=y
+CONFIG_QPNP_USB_PDPHY=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_OTG_WAKELOCK=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+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
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_SWITCH=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_CORTEX_ARM64=y
+CONFIG_EDAC_CORTEX_ARM64_PANIC_ON_UE=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_QPNP_REVID=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_GPIO_USB_DETECT=y
+CONFIG_SEEMP_CORE=y
+CONFIG_USB_BAM=y
+CONFIG_MSM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_TIMER_LEAP=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_COMMON_LOG=y
+CONFIG_MSM_SMEM=y
+CONFIG_QPNP_HAPTIC=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+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_SPSS_UTILS=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_QCOM_DCC=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+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_ICNSS_DEBUG=y
+CONFIG_MSM_GLADIATOR_ERP_V2=y
+CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
+CONFIG_MSM_GLADIATOR_HANG_DETECT=y
+CONFIG_MSM_CORE_HANG_DETECT=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_CPUSS_DUMP=y
+CONFIG_MSM_ADSP_LOADER=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_TRACER_PKT=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_MPM_OF=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
+CONFIG_QCOM_REMOTEQDSS=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_QSEE_IPC_IRQ_BRIDGE=y
+CONFIG_QCOM_SMCINVOKE=y
+CONFIG_QCOM_EARLY_RANDOM=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
+CONFIG_EXTCON=y
+CONFIG_IIO=y
+CONFIG_QCOM_RRADC=y
+CONFIG_QCOM_TADC=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_PHY_XGENE=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder"
+CONFIG_MSM_TZ_LOG=y
+CONFIG_SENSORS_SSC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_EFIVAR_FS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_PAGE_OWNER=y
+CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
+CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_UFS_FAULT_INJECTION=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_MEMTEST=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_ARM64_PTDUMP=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_DEBUG_RODATA=y
+CONFIG_FREE_PAGES_RDONLY=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SOURCE_ETM4X=y
+CONFIG_CORESIGHT_REMOTE_ETM=y
+CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_QPDI=y
+CONFIG_CORESIGHT_SOURCE_DUMMY=y
+CONFIG_PFK=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_CRYPTO_CRC32_ARM64=y
+CONFIG_XZ_DEC=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index ef8bac8e2947..af8902054b8a 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -59,6 +59,7 @@ CONFIG_CLEANCACHE=y
CONFIG_CMA=y
CONFIG_CMA_DEBUGFS=y
CONFIG_ZSMALLOC=y
+CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y
CONFIG_PROCESS_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_ARMV8_DEPRECATED=y
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index cab1821db191..d311c635a00e 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -347,6 +347,9 @@ ENDPROC(el1_error_invalid)
*/
.align 6
el1_sync:
+#ifdef CONFIG_TLB_EL2_HANDLER
+ smc #0xffff
+#endif
kernel_entry 1
mrs x1, esr_el1 // read the syndrome register
lsr x24, x1, #ESR_ELx_EC_SHIFT // exception class
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 8202bd87f3f8..5a09efa75722 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -188,7 +188,7 @@ static void show_data(unsigned long addr, int nbytes, const char *name)
* don't attempt to dump non-kernel addresses or
* values that are probably just small negative numbers
*/
- if (addr < PAGE_OFFSET || addr > -256UL)
+ if (addr < KIMAGE_VADDR || addr > -256UL)
return;
printk("\n%s: %#lx:\n", name, addr);
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 2d3f1ab33f70..45c365290553 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1927,7 +1927,11 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
if (!mapping)
goto err;
- mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL | __GFP_NOWARN |
+ __GFP_NORETRY);
+ if (!mapping->bitmap)
+ mapping->bitmap = vzalloc(bitmap_size);
+
if (!mapping->bitmap)
goto err2;
@@ -1942,7 +1946,7 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
kref_init(&mapping->kref);
return mapping;
err3:
- kfree(mapping->bitmap);
+ kvfree(mapping->bitmap);
err2:
kfree(mapping);
err:
@@ -1956,7 +1960,7 @@ static void release_iommu_mapping(struct kref *kref)
container_of(kref, struct dma_iommu_mapping, kref);
iommu_domain_free(mapping->domain);
- kfree(mapping->bitmap);
+ kvfree(mapping->bitmap);
kfree(mapping);
}
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index eacaee18645b..a65dec4b001b 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -410,23 +410,19 @@ no_context:
return 0;
}
+/*
+ * TLB conflict is already handled in EL2. This rourtine should return zero
+ * so that, do_mem_abort would not crash kernel thinking TLB conflict not
+ * handled.
+*/
+#ifdef QCOM_TLB_EL2_HANDLER
static int do_tlb_conf_fault(unsigned long addr,
unsigned int esr,
struct pt_regs *regs)
{
-#define SCM_TLB_CONFLICT_CMD 0x1B
- struct scm_desc desc = {
- .args[0] = addr,
- .arginfo = SCM_ARGS(1),
- };
-
- if (scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP, SCM_TLB_CONFLICT_CMD),
- &desc))
- return 1;
-
return 0;
}
-
+#endif
/*
* First Level Translation Fault Handler
*
@@ -518,7 +514,11 @@ static struct fault_info {
{ do_bad, SIGBUS, 0, "unknown 45" },
{ do_bad, SIGBUS, 0, "unknown 46" },
{ do_bad, SIGBUS, 0, "unknown 47" },
+#ifdef QCOM_TLB_EL2_HANDLER
{ do_tlb_conf_fault, SIGBUS, 0, "TLB conflict abort" },
+#else
+ { do_bad, SIGBUS, 0, "TLB conflict abort" },
+#endif
{ do_bad, SIGBUS, 0, "unknown 49" },
{ do_bad, SIGBUS, 0, "unknown 50" },
{ do_bad, SIGBUS, 0, "unknown 51" },
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 118a4f245ad1..8882f0bc94a5 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -182,8 +182,8 @@ static struct attribute_group crash_note_cpu_attr_group = {
#ifdef CONFIG_HOTPLUG_CPU
-static ssize_t show_cpu_isolated(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t isolate_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct cpu *cpu = container_of(dev, struct cpu, dev);
ssize_t rc;
@@ -195,31 +195,7 @@ static ssize_t show_cpu_isolated(struct device *dev,
return rc;
}
-static ssize_t __ref store_cpu_isolated(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- int err;
- int cpuid = cpu->dev.id;
- unsigned int isolated;
-
- err = kstrtouint(strstrip((char *)buf), 0, &isolated);
- if (err)
- return err;
-
- if (isolated > 1)
- return -EINVAL;
-
- if (isolated)
- sched_isolate_cpu(cpuid);
- else
- sched_unisolate_cpu(cpuid);
-
- return count;
-}
-
-static DEVICE_ATTR(isolate, 0644, show_cpu_isolated, store_cpu_isolated);
+static DEVICE_ATTR_RO(isolate);
static struct attribute *cpu_isolated_attrs[] = {
&dev_attr_isolate.attr,
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 152c81ca50ea..87a48268b663 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -840,7 +840,8 @@ static ssize_t firmware_direct_write(struct file *filp, struct kobject *kobj,
mutex_lock(&fw_lock);
fw = fw_priv->fw;
- if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->buf->status)) {
+ if (!fw || !fw_priv->buf ||
+ test_bit(FW_STATUS_DONE, &fw_priv->buf->status)) {
retval = -ENODEV;
goto out;
}
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 5b83a06ee1a9..45fc564bf949 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -36,3 +36,8 @@ config REGMAP_SWR
config REGMAP_ALLOW_WRITE_DEBUGFS
depends on REGMAP && DEBUG_FS
bool "Allow REGMAP debugfs write"
+ default n
+ help
+ Say 'y' here to allow the regmap debugfs write. Regmap debugfs write
+ could be risky when accessing some essential hardwares, so it is not
+ recommended to enable this option on any production device.
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 0345e977a2d4..88bd6afdeea5 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1981,6 +1981,7 @@ static int fastrpc_session_alloc_locked(struct fastrpc_channel_ctx *chan,
if (err)
goto bail;
chan->session[0].dev = me->dev;
+ chan->session[0].smmu.dev = me->dev;
}
*session = &chan->session[idx];
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 4f1ba98a2b2c..e8e48015d3af 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2649,7 +2649,7 @@ static const struct file_operations clk_enabled_list_fops = {
.release = seq_release,
};
-static void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
+void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
{
if (IS_ERR_OR_NULL(clk))
return;
@@ -2663,6 +2663,7 @@ static void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
clk->ops->list_registers(f, clk->hw);
}
+EXPORT_SYMBOL(clk_debug_print_hw);
static int print_hw_show(struct seq_file *m, void *unused)
{
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index c95a327a9301..25bf4bc85f5c 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -25,6 +25,7 @@ void __clk_free_clk(struct clk *clk);
void clock_debug_print_enabled(void);
int clk_register_debug(struct clk_hw *hw, struct dentry *dentry);
void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
+void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f);
#else
/* All these casts to avoid ifdefs in clkdev... */
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 5a6b62892328..59da00fa7a13 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -231,4 +231,13 @@ config CLOCK_CPU_OSM
existence of multiple OSM domains.
Say Y if you want to support osm clocks.
+config CLOCK_QPNP_DIV
+ tristate "QPNP PMIC clkdiv driver"
+ depends on COMMON_CLK_QCOM && SPMI
+ help
+ This driver supports the clkdiv functionality on the Qualcomm
+ Technologies, Inc. QPNP PMIC. It configures the frequency of
+ clkdiv outputs on the PMIC. These clocks are typically wired
+ through alternate functions on gpio pins.
+
source "drivers/clk/qcom/mdss/Kconfig"
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 481cda67974b..317091a8003d 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -38,5 +38,6 @@ obj-$(CONFIG_QCOM_A53) += clk-a53.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
obj-$(CONFIG_CLOCK_CPU_OSM) += clk-cpu-osm.o
+obj-$(CONFIG_CLOCK_QPNP_DIV) += clk-qpnp-div.o
obj-y += mdss/
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 375f1420f3bb..e6054444599c 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -16,8 +16,10 @@
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include "clk-alpha-pll.h"
+#include "common.h"
#define PLL_MODE 0x00
#define PLL_OUTCTRL BIT(0)
@@ -74,13 +76,17 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
u32 val, off;
int count;
int ret;
- const char *name = clk_hw_get_name(&pll->clkr.hw);
+ u64 time;
+ struct clk_hw *hw = &pll->clkr.hw;
+ const char *name = clk_hw_get_name(hw);
off = pll->offset;
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
if (ret)
return ret;
+ time = sched_clock();
+
for (count = 100; count > 0; count--) {
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
if (ret)
@@ -93,7 +99,13 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
udelay(1);
}
- WARN(1, "%s failed to %s!\n", name, action);
+ time = sched_clock() - time;
+
+ pr_err("PLL lock bit detection total wait time: %lld ns", time);
+
+ WARN_CLK(hw->core, name, 1, "failed to %s!\n", action);
+
+
return -ETIMEDOUT;
}
@@ -589,7 +601,11 @@ static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
{"PLL_ALPHA_VAL", 0x8},
{"PLL_ALPHA_VAL_U", 0xC},
{"PLL_USER_CTL", 0x10},
+ {"PLL_USER_CTL_U", 0x14},
{"PLL_CONFIG_CTL", 0x18},
+ {"PLL_TEST_CTL", 0x1c},
+ {"PLL_TEST_CTL_U", 0x20},
+ {"PLL_STATUS", 0x24},
};
static struct clk_register_data data1[] = {
@@ -601,7 +617,8 @@ static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
for (i = 0; i < size; i++) {
regmap_read(pll->clkr.regmap, pll->offset + data[i].offset,
&val);
- seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
+ data[i].name, val);
}
regmap_read(pll->clkr.regmap, pll->offset + data[0].offset, &val);
@@ -609,7 +626,8 @@ static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
if (val & PLL_FSM_ENA) {
regmap_read(pll->clkr.regmap, pll->clkr.enable_reg +
data1[0].offset, &val);
- seq_printf(f, "%20s: 0x%.8x\n", data1[0].name, val);
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
+ data1[0].name, val);
}
}
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index bfaf4482d668..ca6010db8d78 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -22,6 +22,7 @@
#include "clk-branch.h"
#include "clk-regmap.h"
+#include "common.h"
static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
{
@@ -77,7 +78,8 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
bool (check_halt)(const struct clk_branch *, bool))
{
bool voted = br->halt_check & BRANCH_VOTED;
- const char *name = clk_hw_get_name(&br->clkr.hw);
+ const struct clk_hw *hw = &br->clkr.hw;
+ const char *name = clk_hw_get_name(hw);
/* Skip checking halt bit if the clock is in hardware gated mode */
if (clk_branch_in_hwcg_mode(br))
@@ -104,8 +106,10 @@ static int clk_branch_wait(const struct clk_branch *br, bool enabling,
return 0;
udelay(1);
}
- WARN(1, "%s status stuck at 'o%s'", name,
- enabling ? "ff" : "n");
+
+ WARN_CLK(hw->core, name, 1, "status stuck at 'o%s'",
+ enabling ? "ff" : "n");
+
return -EBUSY;
}
return 0;
@@ -212,7 +216,8 @@ static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw)
for (i = 0; i < size; i++) {
regmap_read(br->clkr.regmap, br->halt_reg + data[i].offset,
&val);
- seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
+ data[i].name, val);
}
if ((br->halt_check & BRANCH_HALT_VOTED) &&
@@ -222,7 +227,7 @@ static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw)
for (i = 0; i < size; i++) {
regmap_read(br->clkr.regmap, rclk->enable_reg +
data1[i].offset, &val);
- seq_printf(f, "%20s: 0x%.8x\n",
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
data1[i].name, val);
}
}
@@ -360,7 +365,8 @@ static void clk_gate2_list_registers(struct seq_file *f, struct clk_hw *hw)
for (i = 0; i < size; i++) {
regmap_read(gt->clkr.regmap, gt->clkr.enable_reg +
data[i].offset, &val);
- seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
+ data[i].name, val);
}
}
diff --git a/drivers/clk/qcom/clk-qpnp-div.c b/drivers/clk/qcom/clk-qpnp-div.c
new file mode 100644
index 000000000000..460541c3da2b
--- /dev/null
+++ b/drivers/clk/qcom/clk-qpnp-div.c
@@ -0,0 +1,440 @@
+/* Copyright (c) 2017, 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/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define Q_REG_DIV_CTL1 0x43
+#define Q_DIV_CTL1_DIV_FACTOR_MASK GENMASK(2, 0)
+
+#define Q_REG_EN_CTL 0x46
+#define Q_REG_EN_MASK BIT(7)
+#define Q_SET_EN BIT(7)
+
+#define Q_CXO_PERIOD_NS(cxo_clk) (NSEC_PER_SEC / cxo_clk)
+#define Q_DIV_PERIOD_NS(cxo_clk, div) (NSEC_PER_SEC / (cxo_clk / div))
+#define Q_ENABLE_DELAY_NS(cxo_clk, div) (2 * Q_CXO_PERIOD_NS(cxo_clk) + \
+ (3 * Q_DIV_PERIOD_NS(cxo_clk, div)))
+#define Q_DISABLE_DELAY_NS(cxo_clk, div) \
+ (3 * Q_DIV_PERIOD_NS(cxo_clk, div))
+
+#define CLK_QPNP_DIV_OFFSET 1
+
+enum q_clk_div_factor {
+ Q_CLKDIV_XO_DIV_1_0 = 0,
+ Q_CLKDIV_XO_DIV_1,
+ Q_CLKDIV_XO_DIV_2,
+ Q_CLKDIV_XO_DIV_4,
+ Q_CLKDIV_XO_DIV_8,
+ Q_CLKDIV_XO_DIV_16,
+ Q_CLKDIV_XO_DIV_32,
+ Q_CLKDIV_XO_DIV_64,
+ Q_CLKDIV_MAX_ALLOWED,
+};
+
+enum q_clkdiv_state {
+ DISABLE = false,
+ ENABLE = true,
+};
+
+struct q_clkdiv {
+ struct regmap *regmap;
+ struct device *dev;
+
+ u16 base;
+ spinlock_t lock;
+
+ /* clock properties */
+ struct clk_hw hw;
+ unsigned int cxo_hz;
+ enum q_clk_div_factor div_factor;
+ bool enabled;
+};
+
+static inline struct q_clkdiv *to_clkdiv(struct clk_hw *_hw)
+{
+ return container_of(_hw, struct q_clkdiv, hw);
+}
+
+static inline unsigned int div_factor_to_div(unsigned int div_factor)
+{
+ if (div_factor == Q_CLKDIV_XO_DIV_1_0)
+ return 1;
+ return 1 << (div_factor - CLK_QPNP_DIV_OFFSET);
+}
+
+static inline unsigned int div_to_div_factor(unsigned int div)
+{
+ return ilog2(div) + CLK_QPNP_DIV_OFFSET;
+}
+
+static int qpnp_clkdiv_masked_write(struct q_clkdiv *q_clkdiv, u16 offset,
+ u8 mask, u8 val)
+{
+ int rc;
+
+ rc = regmap_update_bits(q_clkdiv->regmap, q_clkdiv->base + offset, mask,
+ val);
+ if (rc)
+ dev_err(q_clkdiv->dev,
+ "Unable to regmap_update_bits to addr=%hx, rc(%d)\n",
+ q_clkdiv->base + offset, rc);
+ return rc;
+}
+
+static int qpnp_clkdiv_set_enable_state(struct q_clkdiv *q_clkdiv,
+ enum q_clkdiv_state enable_state)
+{
+ int rc;
+
+ rc = qpnp_clkdiv_masked_write(q_clkdiv, Q_REG_EN_CTL, Q_REG_EN_MASK,
+ (enable_state == ENABLE) ? Q_SET_EN : 0);
+ if (rc)
+ return rc;
+
+ if (enable_state == ENABLE)
+ ndelay(Q_ENABLE_DELAY_NS(q_clkdiv->cxo_hz,
+ div_factor_to_div(q_clkdiv->div_factor)));
+ else
+ ndelay(Q_DISABLE_DELAY_NS(q_clkdiv->cxo_hz,
+ div_factor_to_div(q_clkdiv->div_factor)));
+
+ return rc;
+}
+
+static int qpnp_clkdiv_config_freq_div(struct q_clkdiv *q_clkdiv,
+ unsigned int div)
+{
+ unsigned int div_factor;
+ int rc;
+
+ div_factor = div_to_div_factor(div);
+ if (div_factor <= 0 || div_factor >= Q_CLKDIV_MAX_ALLOWED)
+ return -EINVAL;
+
+ if (q_clkdiv->enabled) {
+ rc = qpnp_clkdiv_set_enable_state(q_clkdiv, DISABLE);
+ if (rc) {
+ dev_err(q_clkdiv->dev, "unable to disable clock, rc = %d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ rc = qpnp_clkdiv_masked_write(q_clkdiv, Q_REG_DIV_CTL1,
+ Q_DIV_CTL1_DIV_FACTOR_MASK, div_factor);
+ if (rc) {
+ dev_err(q_clkdiv->dev, "config divider failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ q_clkdiv->div_factor = div_factor;
+
+ if (q_clkdiv->enabled) {
+ rc = qpnp_clkdiv_set_enable_state(q_clkdiv, ENABLE);
+ if (rc)
+ dev_err(q_clkdiv->dev, "unable to re-enable clock, rc = %d\n",
+ rc);
+ }
+
+ return rc;
+}
+
+static int clk_qpnp_div_enable(struct clk_hw *hw)
+{
+ struct q_clkdiv *q_clkdiv = to_clkdiv(hw);
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&q_clkdiv->lock, flags);
+
+ rc = qpnp_clkdiv_set_enable_state(q_clkdiv, ENABLE);
+ if (rc) {
+ dev_err(q_clkdiv->dev, "clk enable failed, rc=%d\n", rc);
+ goto fail;
+ }
+
+ q_clkdiv->enabled = true;
+
+fail:
+ spin_unlock_irqrestore(&q_clkdiv->lock, flags);
+ return rc;
+}
+
+static void clk_qpnp_div_disable(struct clk_hw *hw)
+{
+ struct q_clkdiv *q_clkdiv = to_clkdiv(hw);
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&q_clkdiv->lock, flags);
+
+ rc = qpnp_clkdiv_set_enable_state(q_clkdiv, DISABLE);
+ if (rc) {
+ dev_err(q_clkdiv->dev, "clk disable failed, rc=%d\n", rc);
+ goto fail;
+ }
+
+ q_clkdiv->enabled = false;
+
+fail:
+ spin_unlock_irqrestore(&q_clkdiv->lock, flags);
+}
+
+static long clk_qpnp_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct q_clkdiv *q_clkdiv = to_clkdiv(hw);
+ unsigned long flags, new_rate;
+ unsigned int div, div_factor;
+
+ spin_lock_irqsave(&q_clkdiv->lock, flags);
+ if (rate <= 0 || rate > q_clkdiv->cxo_hz) {
+ dev_err(q_clkdiv->dev, "invalid rate requested, rate = %lu\n",
+ rate);
+ spin_unlock_irqrestore(&q_clkdiv->lock, flags);
+ return -EINVAL;
+ }
+
+ div = DIV_ROUND_UP(q_clkdiv->cxo_hz, rate);
+ div_factor = div_to_div_factor(div);
+ if (div_factor >= Q_CLKDIV_MAX_ALLOWED)
+ div_factor = Q_CLKDIV_MAX_ALLOWED - 1;
+ new_rate = q_clkdiv->cxo_hz / div_factor_to_div(div_factor);
+
+ spin_unlock_irqrestore(&q_clkdiv->lock, flags);
+ return new_rate;
+}
+
+static unsigned long clk_qpnp_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct q_clkdiv *q_clkdiv = to_clkdiv(hw);
+ unsigned long rate, flags;
+
+ spin_lock_irqsave(&q_clkdiv->lock, flags);
+
+ rate = q_clkdiv->cxo_hz / div_factor_to_div(q_clkdiv->div_factor);
+
+ spin_unlock_irqrestore(&q_clkdiv->lock, flags);
+ return rate;
+}
+
+static int clk_qpnp_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct q_clkdiv *q_clkdiv = to_clkdiv(hw);
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&q_clkdiv->lock, flags);
+ if (rate <= 0 || rate > q_clkdiv->cxo_hz) {
+ dev_err(q_clkdiv->dev, "invalid rate requested, rate = %lu\n",
+ rate);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ rc = qpnp_clkdiv_config_freq_div(q_clkdiv, q_clkdiv->cxo_hz / rate);
+ if (rc)
+ dev_err(q_clkdiv->dev, "clkdiv set rate(%lu) failed, rc = %d\n",
+ rate, rc);
+
+fail:
+ spin_unlock_irqrestore(&q_clkdiv->lock, flags);
+ return rc;
+}
+
+static long clk_qpnp_div_list_rate(struct clk_hw *hw, unsigned n,
+ unsigned long rate_max)
+{
+ struct q_clkdiv *q_clkdiv = to_clkdiv(hw);
+ unsigned int div_factor;
+ long rate;
+
+ if (n >= Q_CLKDIV_MAX_ALLOWED - CLK_QPNP_DIV_OFFSET)
+ return 0;
+
+ div_factor = Q_CLKDIV_MAX_ALLOWED - 1 - n;
+ rate = q_clkdiv->cxo_hz / div_factor_to_div(div_factor);
+
+ return rate <= rate_max ? rate : 0;
+}
+
+const struct clk_ops clk_qpnp_div_ops = {
+ .enable = clk_qpnp_div_enable,
+ .disable = clk_qpnp_div_disable,
+ .set_rate = clk_qpnp_div_set_rate,
+ .recalc_rate = clk_qpnp_div_recalc_rate,
+ .round_rate = clk_qpnp_div_round_rate,
+ .list_rate = clk_qpnp_div_list_rate,
+};
+
+#define QPNP_CLKDIV_MAX_NAME_LEN 16
+
+static int qpnp_clkdiv_probe(struct platform_device *pdev)
+{
+ struct q_clkdiv *q_clkdiv;
+ struct device *dev = &pdev->dev;
+ struct device_node *of_node = dev->of_node;
+ struct clk_init_data *init;
+ struct clk_onecell_data *clk_data;
+ struct clk *clk;
+ unsigned int base, div, init_freq;
+ int rc = 0, id;
+ char *clk_name;
+
+ q_clkdiv = devm_kzalloc(dev, sizeof(*q_clkdiv), GFP_KERNEL);
+ if (!q_clkdiv)
+ return -ENOMEM;
+
+ q_clkdiv->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!q_clkdiv->regmap) {
+ dev_err(dev, "Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+ q_clkdiv->dev = dev;
+
+ rc = of_property_read_u32(of_node, "reg", &base);
+ if (rc < 0) {
+ dev_err(dev, "Couldn't find reg in node = %s, rc = %d\n",
+ of_node->full_name, rc);
+ return rc;
+ }
+ q_clkdiv->base = base;
+
+ /* init clock properties */
+ rc = of_property_read_u32(of_node, "qcom,cxo-freq", &q_clkdiv->cxo_hz);
+ if (rc) {
+ dev_err(dev, "unable to get qcom,cxo-freq property, rc = %d\n",
+ rc);
+ return rc;
+ }
+
+ q_clkdiv->div_factor = Q_CLKDIV_XO_DIV_1_0;
+ rc = of_property_read_u32(of_node, "qcom,clkdiv-init-freq", &init_freq);
+ if (rc) {
+ if (rc != -EINVAL) {
+ dev_err(dev, "Unable to read initial frequency value, rc=%d\n",
+ rc);
+ return rc;
+ }
+ } else {
+ if (init_freq <= 0 || init_freq > q_clkdiv->cxo_hz) {
+ dev_err(dev, "invalid initial frequency specified, rate = %u\n",
+ init_freq);
+ return -EINVAL;
+ }
+
+ div = DIV_ROUND_UP(q_clkdiv->cxo_hz, init_freq);
+ q_clkdiv->div_factor = div_to_div_factor(div);
+ if (q_clkdiv->div_factor >= Q_CLKDIV_MAX_ALLOWED)
+ q_clkdiv->div_factor = Q_CLKDIV_MAX_ALLOWED - 1;
+ rc = qpnp_clkdiv_config_freq_div(q_clkdiv,
+ div_factor_to_div(q_clkdiv->div_factor));
+ if (rc) {
+ dev_err(dev, "Config initial frequency failed, rc = %d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL);
+ if (!init)
+ return -ENOMEM;
+
+ rc = of_property_read_u32(of_node, "qcom,clkdiv-id", &id);
+ if (rc) {
+ dev_err(dev, "Unable to read clkdiv node id, rc = %d\n", rc);
+ return rc;
+ }
+
+ clk_name = devm_kcalloc(dev, QPNP_CLKDIV_MAX_NAME_LEN,
+ sizeof(*clk_name), GFP_KERNEL);
+ if (!clk_name)
+ return -ENOMEM;
+ snprintf(clk_name, QPNP_CLKDIV_MAX_NAME_LEN, "qpnp_clkdiv_%d", id);
+
+ init->name = clk_name;
+ init->ops = &clk_qpnp_div_ops;
+ q_clkdiv->hw.init = init;
+ spin_lock_init(&q_clkdiv->lock);
+
+ clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clks = devm_kzalloc(dev, sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ clk = devm_clk_register(dev, &q_clkdiv->hw);
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Unable to register qpnp div clock\n");
+ return PTR_ERR(clk);
+ }
+
+ clk_data->clk_num = 1;
+ clk_data->clks[0] = clk;
+
+ rc = of_clk_add_provider(of_node, of_clk_src_onecell_get, clk_data);
+ if (rc) {
+ dev_err(dev, "Unable to register qpnp div clock provider, rc = %d\n",
+ rc);
+ return rc;
+ }
+
+ dev_set_drvdata(dev, q_clkdiv);
+ dev_info(dev, "Registered %s successfully\n", clk_name);
+
+ return rc;
+}
+
+static const struct of_device_id qpnp_clkdiv_match_table[] = {
+ { .compatible = "qcom,qpnp-clkdiv",
+ },
+ {}
+};
+
+static struct platform_driver qpnp_clkdiv_driver = {
+ .driver = {
+ .name = "qcom,qpnp-clkdiv",
+ .of_match_table = qpnp_clkdiv_match_table,
+ },
+ .probe = qpnp_clkdiv_probe,
+};
+
+static int __init qpnp_clkdiv_init(void)
+{
+ return platform_driver_register(&qpnp_clkdiv_driver);
+}
+module_init(qpnp_clkdiv_init);
+
+static void __exit qpnp_clkdiv_exit(void)
+{
+ return platform_driver_unregister(&qpnp_clkdiv_driver);
+}
+module_exit(qpnp_clkdiv_exit);
+
+MODULE_DESCRIPTION("QPNP PMIC clkdiv driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 6e6adbff4676..a07deb902577 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -122,7 +122,7 @@ err:
return 0;
}
-static int update_config(struct clk_rcg2 *rcg)
+static int update_config(struct clk_rcg2 *rcg, u32 cfg)
{
int count, ret;
u32 cmd;
@@ -144,7 +144,11 @@ static int update_config(struct clk_rcg2 *rcg)
udelay(1);
}
- WARN(1, "%s: rcg didn't update its configuration.", name);
+ pr_err("CFG_RCGR old frequency configuration 0x%x !\n", cfg);
+
+ WARN_CLK(hw->core, name, count == 0,
+ "rcg didn't update its configuration.");
+
return 0;
}
@@ -153,13 +157,17 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
int ret;
u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
+ u32 old_cfg;
+
+ /* Read back the old configuration */
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &old_cfg);
ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
CFG_SRC_SEL_MASK, cfg);
if (ret)
return ret;
- return update_config(rcg);
+ return update_config(rcg, old_cfg);
}
static void clk_rcg_clear_force_enable(struct clk_hw *hw)
@@ -297,13 +305,16 @@ static int clk_rcg2_determine_rate(struct clk_hw *hw,
static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
{
- u32 cfg, mask;
+ u32 cfg, mask, old_cfg;
struct clk_hw *hw = &rcg->clkr.hw;
int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
if (index < 0)
return index;
+ /* Read back the old configuration */
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &old_cfg);
+
if (rcg->mnd_width && f->n) {
mask = BIT(rcg->mnd_width) - 1;
ret = regmap_update_bits(rcg->clkr.regmap,
@@ -333,7 +344,7 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
if (ret)
return ret;
- return update_config(rcg);
+ return update_config(rcg, old_cfg);
}
static void clk_rcg2_list_registers(struct seq_file *f, struct clk_hw *hw)
@@ -359,14 +370,16 @@ static void clk_rcg2_list_registers(struct seq_file *f, struct clk_hw *hw)
for (i = 0; i < size; i++) {
regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr +
data1[i].offset), &val);
- seq_printf(f, "%20s: 0x%.8x\n", data1[i].name, val);
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
+ data1[i].name, val);
}
} else {
size = ARRAY_SIZE(data);
for (i = 0; i < size; i++) {
regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr +
data[i].offset), &val);
- seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val);
+ clock_debug_output(f, false, "%20s: 0x%.8x\n",
+ data[i].name, val);
}
}
}
@@ -1186,16 +1199,19 @@ static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 cfg;
+ u32 cfg, old_cfg;
int ret;
+ /* Read back the old configuration */
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &old_cfg);
+
/* Just mux it, we don't use the division or m/n hardware */
cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
if (ret)
return ret;
- return update_config(rcg);
+ return update_config(rcg, old_cfg);
}
static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -1271,9 +1287,12 @@ static int clk_gfx3d_src_set_rate_and_parent(struct clk_hw *hw,
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
const struct freq_tbl *f;
- u32 cfg;
+ u32 cfg, old_cfg;
int ret;
+ /* Read back the old configuration */
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &old_cfg);
+
cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
f = qcom_find_freq(rcg->freq_tbl, rate);
@@ -1287,7 +1306,7 @@ static int clk_gfx3d_src_set_rate_and_parent(struct clk_hw *hw,
if (ret)
return ret;
- return update_config(rcg);
+ return update_config(rcg, old_cfg);
}
const struct clk_ops clk_gfx3d_src_ops = {
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 06ec0bb0bc29..95408a47fef0 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -13,6 +13,8 @@
#ifndef __QCOM_CLK_COMMON_H__
#define __QCOM_CLK_COMMON_H__
+#include "../clk.h"
+
struct platform_device;
struct regmap_config;
struct clk_regmap;
@@ -153,4 +155,19 @@ struct clk_debug_mux {
extern const struct clk_ops clk_debug_mux_ops;
+#define WARN_CLK(core, name, cond, fmt, ...) do { \
+ clk_debug_print_hw(core, NULL); \
+ WARN(cond, "%s: " fmt, name, ##__VA_ARGS__); \
+} while (0)
+
+#define clock_debug_output(m, c, fmt, ...) \
+do { \
+ if (m) \
+ seq_printf(m, fmt, ##__VA_ARGS__); \
+ else if (c) \
+ pr_cont(fmt, ##__VA_ARGS__); \
+ else \
+ pr_info(fmt, ##__VA_ARGS__); \
+} while (0)
+
#endif
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c
index 0965d5590a28..f0d4e1ff52be 100644
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm-util.c
@@ -600,6 +600,7 @@ unsigned long dp_vco_recalc_rate_14nm(struct clk_hw *hw,
mdss_pll_resource_enable(dp_res, false);
+ dp_res->vco_cached_rate = vco->rate = vco_rate;
return (unsigned long)vco_rate;
}
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c
index ffe8286cfaaa..d74584850259 100644
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c
@@ -62,6 +62,7 @@ v----------+----------v | divsel_two | | divsel_four |
#include "mdss-dp-pll-14nm.h"
static struct dp_pll_db dp_pdb;
+static struct clk_ops mux_clk_ops;
static struct regmap_config dp_pll_14nm_cfg = {
.reg_bits = 32,
@@ -137,6 +138,47 @@ static struct clk_fixed_factor dp_vco_divsel_four_clk_src = {
},
};
+static int clk_mux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ int ret = 0;
+
+ ret = __clk_mux_determine_rate_closest(hw, req);
+ if (ret)
+ return ret;
+
+ /* Set the new parent of mux if there is a new valid parent */
+ if (hw->clk && req->best_parent_hw->clk)
+ clk_set_parent(hw->clk, req->best_parent_hw->clk);
+
+ return 0;
+}
+
+
+static unsigned long mux_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk *div_clk = NULL, *vco_clk = NULL;
+ struct dp_pll_vco_clk *vco = NULL;
+
+ div_clk = clk_get_parent(hw->clk);
+ if (!div_clk)
+ return 0;
+
+ vco_clk = clk_get_parent(div_clk);
+ if (!vco_clk)
+ return 0;
+
+ vco = to_dp_vco_hw(__clk_get_hw(vco_clk));
+ if (!vco)
+ return 0;
+
+ if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000)
+ return (vco->rate / 4);
+ else
+ return (vco->rate / 2);
+}
+
static struct clk_regmap_mux dp_vco_divided_clk_src_mux = {
.reg = 0x64,
.shift = 0,
@@ -149,7 +191,7 @@ static struct clk_regmap_mux dp_vco_divided_clk_src_mux = {
(const char *[]){"dp_vco_divsel_two_clk_src",
"dp_vco_divsel_four_clk_src"},
.num_parents = 2,
- .ops = &clk_regmap_mux_closest_ops,
+ .ops = &mux_clk_ops,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
},
},
@@ -202,6 +244,9 @@ int dp_pll_clock_register_14nm(struct platform_device *pdev,
regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops,
pll_res, &dp_pll_14nm_cfg);
dp_vco_divided_clk_src_mux.clkr.regmap = regmap;
+ mux_clk_ops = clk_regmap_mux_closest_ops;
+ mux_clk_ops.determine_rate = clk_mux_determine_rate;
+ mux_clk_ops.recalc_rate = mux_recalc_rate;
dp_vco_clk.priv = pll_res;
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 2f3a020a761a..833bb4a17b6a 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -138,6 +138,10 @@ static int mdss_pll_resource_parse(struct platform_device *pdev,
pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
pll_res->target_id = MDSS_PLL_TARGET_SDM660;
pll_res->revision = 2;
+ } else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_sdm630")) {
+ pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
+ pll_res->target_id = MDSS_PLL_TARGET_SDM630;
+ pll_res->revision = 2;
} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8998")) {
pll_res->pll_interface_type = MDSS_DSI_PLL_8998;
} else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_8998")) {
@@ -391,6 +395,7 @@ static const struct of_device_id mdss_pll_dt_match[] = {
{.compatible = "qcom,mdss_hdmi_pll_8998"},
{.compatible = "qcom,mdss_dsi_pll_sdm660"},
{.compatible = "qcom,mdss_dp_pll_sdm660"},
+ {.compatible = "qcom,mdss_dsi_pll_sdm630"},
{}
};
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 9cf785d43504..cb6918127041 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -53,6 +53,7 @@ enum {
enum {
MDSS_PLL_TARGET_8996,
MDSS_PLL_TARGET_SDM660,
+ MDSS_PLL_TARGET_SDM630,
};
#define DFPS_MAX_NUM_OF_FRAME_RATES 20
diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c
index 2af5c1a1d7ca..51faccc7c26c 100644
--- a/drivers/clk/qcom/mmcc-msm8996.c
+++ b/drivers/clk/qcom/mmcc-msm8996.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,11 +31,25 @@
#include "clk-alpha-pll.h"
#include "clk-rcg.h"
#include "clk-branch.h"
+#include "clk-voter.h"
#include "reset.h"
#include "gdsc.h"
+#include "vdd-level-8996.h"
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+
+static int vdd_mmpll4_levels[] = {
+ RPM_REGULATOR_CORNER_NONE, 0,
+ RPM_REGULATOR_CORNER_SVS_KRAIT, 1800000,
+ RPM_REGULATOR_CORNER_SVS_SOC, 1800000,
+ RPM_REGULATOR_CORNER_NORMAL, 1800000,
+ RPM_REGULATOR_CORNER_SUPER_TURBO, 1800000,
+};
+
+static DEFINE_VDD_REGULATORS(vdd_mmpll4, VDD_DIG_NUM, 2, vdd_mmpll4_levels);
+
enum {
P_XO,
P_MMPLL0,
@@ -73,8 +87,8 @@ static const struct parent_map mmss_xo_dsi0pll_dsi1pll_map[] = {
static const char * const mmss_xo_dsi0pll_dsi1pll[] = {
"xo",
- "dsi0pll",
- "dsi1pll"
+ "dsi0pll_pixel_clk_mux",
+ "dsi1pll_pixel_clk_mux"
};
static const struct parent_map mmss_xo_gpll0_gpll0_div_map[] = {
@@ -97,8 +111,8 @@ static const struct parent_map mmss_xo_dsibyte_map[] = {
static const char * const mmss_xo_dsibyte[] = {
"xo",
- "dsi0pllbyte",
- "dsi1pllbyte"
+ "dsi0pll_byte_clk_mux",
+ "dsi1pll_byte_clk_mux"
};
static const struct parent_map mmss_xo_mmpll0_gpll0_gpll0_div_map[] = {
@@ -265,6 +279,18 @@ static struct pll_vco mmpll_t_vco[] = {
{ 500000000, 1500000000, 0 },
};
+/* Initial configuration for 800MHz rate */
+static const struct pll_config mmpll0_config = {
+ .l = 0x29,
+ .config_ctl_val = 0x4001051b,
+ .alpha = 0xaaaaab00,
+ .alpha_u = 0xaa,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll0_early = {
.offset = 0x0,
.vco_table = mmpll_p_vco,
@@ -277,6 +303,7 @@ static struct clk_alpha_pll mmpll0_early = {
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 400000000, NOMINAL, 800000000),
},
},
};
@@ -293,6 +320,18 @@ static struct clk_alpha_pll_postdiv mmpll0 = {
},
};
+/* Initial configuration for 810MHz rate */
+static const struct pll_config mmpll1_config = {
+ .l = 0x2a,
+ .config_ctl_val = 0x4001051b,
+ .alpha = 0x00,
+ .alpha_u = 0x30,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll1_early = {
.offset = 0x30,
.vco_table = mmpll_p_vco,
@@ -305,6 +344,7 @@ static struct clk_alpha_pll mmpll1_early = {
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 405000000, NOMINAL, 810000000),
}
},
};
@@ -321,6 +361,18 @@ static struct clk_alpha_pll_postdiv mmpll1 = {
},
};
+/* Initial configuration for 400MHz rate */
+static const struct pll_config mmpll2_config = {
+ .l = 0x14,
+ .config_ctl_val = 0x4001051b,
+ .alpha = 0x55555600,
+ .alpha_u = 0xd5,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll2_early = {
.offset = 0x4100,
.vco_table = mmpll_gfx_vco,
@@ -330,6 +382,7 @@ static struct clk_alpha_pll mmpll2_early = {
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 1000000000),
},
};
@@ -345,6 +398,18 @@ static struct clk_alpha_pll_postdiv mmpll2 = {
},
};
+/* Initial configuration for 1040MHz rate */
+static const struct pll_config mmpll3_config = {
+ .l = 0x36,
+ .config_ctl_val = 0x4001051b,
+ .alpha = 0xaaaaab00,
+ .alpha_u = 0x2a,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x1 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll3_early = {
.offset = 0x60,
.vco_table = mmpll_p_vco,
@@ -354,6 +419,7 @@ static struct clk_alpha_pll mmpll3_early = {
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 520000000, NOMINAL, 1040000000),
},
};
@@ -369,6 +435,18 @@ static struct clk_alpha_pll_postdiv mmpll3 = {
},
};
+/* Initial configuration for 960MHz rate */
+static const struct pll_config mmpll4_config = {
+ .l = 0x32,
+ .config_ctl_val = 0x4289,
+ .alpha = 0x00,
+ .alpha_u = 0x00,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x0 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll4_early = {
.offset = 0x90,
.vco_table = mmpll_t_vco,
@@ -378,6 +456,7 @@ static struct clk_alpha_pll mmpll4_early = {
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 480000000, NOMINAL, 960000000),
},
};
@@ -393,6 +472,18 @@ static struct clk_alpha_pll_postdiv mmpll4 = {
},
};
+/* Initial configuration for 825MHz rate */
+static const struct pll_config mmpll5_config = {
+ .l = 0x2a,
+ .config_ctl_val = 0x4001051b,
+ .alpha = 0x00,
+ .alpha_u = 0xf8,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll5_early = {
.offset = 0xc0,
.vco_table = mmpll_p_vco,
@@ -402,6 +493,7 @@ static struct clk_alpha_pll mmpll5_early = {
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 412500000, LOW, 825000000),
},
};
@@ -417,6 +509,18 @@ static struct clk_alpha_pll_postdiv mmpll5 = {
},
};
+/* Initial configuration for 532MHz rate */
+static const struct pll_config mmpll8_config = {
+ .l = 0x1b,
+ .config_ctl_val = 0x4001051b,
+ .alpha = 0x55555600,
+ .alpha_u = 0xb5,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll8_early = {
.offset = 0x4130,
.vco_table = mmpll_gfx_vco,
@@ -426,6 +530,7 @@ static struct clk_alpha_pll mmpll8_early = {
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 1000000000),
},
};
@@ -441,15 +546,30 @@ static struct clk_alpha_pll_postdiv mmpll8 = {
},
};
+/* Initial configuration for 1248MHz rate */
+static const struct pll_config mmpll9_config = {
+ .l = 0x41,
+ .config_ctl_val = 0x4289,
+ .alpha = 0x00,
+ .alpha_u = 0x00,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x0 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
static struct clk_alpha_pll mmpll9_early = {
.offset = 0x4200,
.vco_table = mmpll_t_vco,
.num_vco = ARRAY_SIZE(mmpll_t_vco),
+ .flags = SUPPORTS_DYNAMIC_UPDATE,
+ .min_supported_freq = 1248000000,
.clkr.hw.init = &(struct clk_init_data){
.name = "mmpll9_early",
.parent_names = (const char *[]){ "xo" },
.num_parents = 1,
.ops = &clk_alpha_pll_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 652000000, NOMINAL, 1305600000),
},
};
@@ -482,6 +602,7 @@ static struct clk_rcg2 ahb_clk_src = {
.parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
.num_parents = 4,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 40000000, NOMINAL, 80000000),
},
};
@@ -489,26 +610,13 @@ static const struct freq_tbl ftbl_axi_clk_src[] = {
F(19200000, P_XO, 1, 0, 0),
F(75000000, P_GPLL0_DIV, 4, 0, 0),
F(100000000, P_GPLL0, 6, 0, 0),
- F(171430000, P_GPLL0, 3.5, 0, 0),
+ F(171428571, P_GPLL0, 3.5, 0, 0),
F(200000000, P_GPLL0, 3, 0, 0),
F(320000000, P_MMPLL0, 2.5, 0, 0),
- F(400000000, P_MMPLL0, 2, 0, 0),
+ F(405000000, P_MMPLL1, 2, 0, 0),
{ }
};
-static struct clk_rcg2 axi_clk_src = {
- .cmd_rcgr = 0x5040,
- .hid_width = 5,
- .parent_map = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div_map,
- .freq_tbl = ftbl_axi_clk_src,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "axi_clk_src",
- .parent_names = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div,
- .num_parents = 5,
- .ops = &clk_rcg2_ops,
- },
-};
-
static struct clk_rcg2 maxi_clk_src = {
.cmd_rcgr = 0x5090,
.hid_width = 5,
@@ -519,6 +627,8 @@ static struct clk_rcg2 maxi_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 171430000,
+ NOMINAL, 320000000, HIGH, 405000000),
},
};
@@ -526,11 +636,13 @@ static struct clk_rcg2 gfx3d_clk_src = {
.cmd_rcgr = 0x4000,
.hid_width = 5,
.parent_map = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_map,
+ .flags = FORCE_ENABLE_RCGR,
.clkr.hw.init = &(struct clk_init_data){
.name = "gfx3d_clk_src",
.parent_names = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0,
.num_parents = 6,
.ops = &clk_gfx3d_ops,
+ .vdd_class = &vdd_gfx,
.flags = CLK_SET_RATE_PARENT,
},
};
@@ -550,18 +662,7 @@ static struct clk_rcg2 rbbmtimer_clk_src = {
.parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
.num_parents = 4,
.ops = &clk_rcg2_ops,
- },
-};
-
-static struct clk_rcg2 isense_clk_src = {
- .cmd_rcgr = 0x4010,
- .hid_width = 5,
- .parent_map = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div_map,
- .clkr.hw.init = &(struct clk_init_data){
- .name = "isense_clk_src",
- .parent_names = mmss_xo_mmpll0_mmpll9_mmpll2_mmpll8_gpll0_gpll0_div,
- .num_parents = 7,
- .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
},
};
@@ -580,7 +681,9 @@ static struct clk_rcg2 rbcpr_clk_src = {
.name = "rbcpr_clk_src",
.parent_names = mmss_xo_mmpll0_gpll0_gpll0_div,
.num_parents = 4,
+ .flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(LOWER, 19200000, NOMINAL, 50000000),
},
};
@@ -603,6 +706,8 @@ static struct clk_rcg2 video_core_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 150000000,
+ NOMINAL, 346666667, HIGH, 520000000),
},
};
@@ -617,6 +722,8 @@ static struct clk_rcg2 video_subcore0_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 150000000,
+ NOMINAL, 346666667, HIGH, 520000000),
},
};
@@ -631,6 +738,8 @@ static struct clk_rcg2 video_subcore1_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll3_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 150000000,
+ NOMINAL, 346666667, HIGH, 520000000),
},
};
@@ -645,6 +754,8 @@ static struct clk_rcg2 pclk0_clk_src = {
.num_parents = 3,
.ops = &clk_pixel_ops,
.flags = CLK_SET_RATE_PARENT,
+ VDD_DIG_FMAX_MAP3(LOWER, 175000000, LOW, 280000000,
+ NOMINAL, 350000000),
},
};
@@ -659,6 +770,8 @@ static struct clk_rcg2 pclk1_clk_src = {
.num_parents = 3,
.ops = &clk_pixel_ops,
.flags = CLK_SET_RATE_PARENT,
+ VDD_DIG_FMAX_MAP3(LOWER, 175000000, LOW, 280000000,
+ NOMINAL, 350000000),
},
};
@@ -685,6 +798,8 @@ static struct clk_rcg2 mdp_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll5_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 171430000, LOW, 275000000,
+ NOMINAL, 330000000, HIGH, 412500000),
},
};
@@ -704,6 +819,8 @@ static struct clk_rcg2 extpclk_clk_src = {
.num_parents = 2,
.ops = &clk_byte_ops,
.flags = CLK_SET_RATE_PARENT,
+ VDD_DIG_FMAX_MAP3(LOWER, 150000000, LOW, 300000000,
+ NOMINAL, 600000000),
},
};
@@ -722,6 +839,7 @@ static struct clk_rcg2 vsync_clk_src = {
.parent_names = mmss_xo_gpll0_gpll0_div,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
},
};
@@ -740,6 +858,7 @@ static struct clk_rcg2 hdmi_clk_src = {
.parent_names = mmss_xo_gpll0_gpll0_div,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
},
};
@@ -753,6 +872,8 @@ static struct clk_rcg2 byte0_clk_src = {
.num_parents = 3,
.ops = &clk_byte2_ops,
.flags = CLK_SET_RATE_PARENT,
+ VDD_DIG_FMAX_MAP3(LOWER, 131250000, LOW, 210000000,
+ NOMINAL, 262500000),
},
};
@@ -766,6 +887,8 @@ static struct clk_rcg2 byte1_clk_src = {
.num_parents = 3,
.ops = &clk_byte2_ops,
.flags = CLK_SET_RATE_PARENT,
+ VDD_DIG_FMAX_MAP3(LOWER, 131250000, LOW, 210000000,
+ NOMINAL, 262500000),
},
};
@@ -784,6 +907,7 @@ static struct clk_rcg2 esc0_clk_src = {
.parent_names = mmss_xo_dsibyte,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
},
};
@@ -797,6 +921,7 @@ static struct clk_rcg2 esc1_clk_src = {
.parent_names = mmss_xo_dsibyte,
.num_parents = 3,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(LOWER, 19200000),
},
};
@@ -821,6 +946,8 @@ static struct clk_rcg2 camss_gp0_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
},
};
@@ -835,6 +962,8 @@ static struct clk_rcg2 camss_gp1_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000,
+ NOMINAL, 200000000),
},
};
@@ -863,6 +992,8 @@ static struct clk_rcg2 mclk0_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667,
+ NOMINAL, 68570000),
},
};
@@ -877,6 +1008,8 @@ static struct clk_rcg2 mclk1_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667,
+ NOMINAL, 68570000),
},
};
@@ -891,6 +1024,8 @@ static struct clk_rcg2 mclk2_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667,
+ NOMINAL, 68570000),
},
};
@@ -905,6 +1040,8 @@ static struct clk_rcg2 mclk3_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667,
+ NOMINAL, 68570000),
},
};
@@ -927,6 +1064,8 @@ static struct clk_rcg2 cci_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 50000000,
+ NOMINAL, 100000000),
},
};
@@ -947,6 +1086,8 @@ static struct clk_rcg2 csi0phytimer_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 266666667),
},
};
@@ -960,6 +1101,8 @@ static struct clk_rcg2 csi1phytimer_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 266666667),
},
};
@@ -973,6 +1116,8 @@ static struct clk_rcg2 csi2phytimer_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 266666667),
},
};
@@ -994,6 +1139,8 @@ static struct clk_rcg2 csiphy0_3p_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 320000000, HIGH, 384000000),
},
};
@@ -1007,6 +1154,8 @@ static struct clk_rcg2 csiphy1_3p_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 320000000, HIGH, 384000000),
},
};
@@ -1020,6 +1169,8 @@ static struct clk_rcg2 csiphy2_3p_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 320000000, HIGH, 384000000),
},
};
@@ -1043,6 +1194,8 @@ static struct clk_rcg2 jpeg0_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 150000000,
+ NOMINAL, 320000000, HIGH, 480000000),
},
};
@@ -1065,6 +1218,8 @@ static struct clk_rcg2 jpeg2_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 150000000,
+ NOMINAL, 266666667, HIGH, 320000000),
},
};
@@ -1078,6 +1233,8 @@ static struct clk_rcg2 jpeg_dma_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 150000000,
+ NOMINAL, 320000000, HIGH, 480000000),
},
};
@@ -1101,6 +1258,8 @@ static struct clk_rcg2 vfe0_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 300000000,
+ NOMINAL, 480000000, HIGH, 600000000),
},
};
@@ -1114,6 +1273,8 @@ static struct clk_rcg2 vfe1_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 300000000,
+ NOMINAL, 480000000, HIGH, 600000000),
},
};
@@ -1136,6 +1297,8 @@ static struct clk_rcg2 cpp_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 480000000, HIGH, 640000000),
},
};
@@ -1143,6 +1306,7 @@ static const struct freq_tbl ftbl_csi0_clk_src[] = {
F(100000000, P_GPLL0_DIV, 3, 0, 0),
F(200000000, P_GPLL0, 3, 0, 0),
F(266666667, P_MMPLL0, 3, 0, 0),
+ F(320000000, P_MMPLL4, 3, 0, 0),
F(480000000, P_MMPLL4, 2, 0, 0),
F(600000000, P_GPLL0, 1, 0, 0),
{ }
@@ -1158,6 +1322,8 @@ static struct clk_rcg2 csi0_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 480000000, HIGH, 600000000),
},
};
@@ -1171,6 +1337,8 @@ static struct clk_rcg2 csi1_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 480000000, HIGH, 600000000),
},
};
@@ -1184,6 +1352,8 @@ static struct clk_rcg2 csi2_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 480000000, HIGH, 600000000),
},
};
@@ -1197,6 +1367,8 @@ static struct clk_rcg2 csi3_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll1_mmpll4_mmpll3_gpll0_gpll0_div,
.num_parents = 7,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 480000000, HIGH, 600000000),
},
};
@@ -1217,11 +1389,14 @@ static struct clk_rcg2 fd_core_clk_src = {
.parent_names = mmss_xo_mmpll0_mmpll4_gpll0_gpll0_div,
.num_parents = 5,
.ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000,
+ NOMINAL, 400000000),
},
};
static struct clk_branch mmss_mmagic_ahb_clk = {
.halt_reg = 0x5024,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x5024,
.enable_mask = BIT(0),
@@ -1229,7 +1404,6 @@ static struct clk_branch mmss_mmagic_ahb_clk = {
.name = "mmss_mmagic_ahb_clk",
.parent_names = (const char *[]){ "ahb_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
.ops = &clk_branch2_ops,
},
},
@@ -1237,14 +1411,16 @@ static struct clk_branch mmss_mmagic_ahb_clk = {
static struct clk_branch mmss_mmagic_cfg_ahb_clk = {
.halt_reg = 0x5054,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x5054,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_mmagic_cfg_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1257,9 +1433,10 @@ static struct clk_branch mmss_misc_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_misc_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1279,21 +1456,6 @@ static struct clk_branch mmss_misc_cxo_clk = {
},
};
-static struct clk_branch mmss_mmagic_axi_clk = {
- .halt_reg = 0x506c,
- .clkr = {
- .enable_reg = 0x506c,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmss_mmagic_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch mmss_mmagic_maxi_clk = {
.halt_reg = 0x5074,
.clkr = {
@@ -1316,9 +1478,6 @@ static struct clk_branch mmagic_camss_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmagic_camss_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1331,9 +1490,6 @@ static struct clk_branch mmagic_camss_noc_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmagic_camss_noc_cfg_ahb_clk",
- .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1341,14 +1497,16 @@ static struct clk_branch mmagic_camss_noc_cfg_ahb_clk = {
static struct clk_branch smmu_vfe_ahb_clk = {
.halt_reg = 0x3c04,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x3c04,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_vfe_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1356,14 +1514,12 @@ static struct clk_branch smmu_vfe_ahb_clk = {
static struct clk_branch smmu_vfe_axi_clk = {
.halt_reg = 0x3c08,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x3c08,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_vfe_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1371,14 +1527,16 @@ static struct clk_branch smmu_vfe_axi_clk = {
static struct clk_branch smmu_cpp_ahb_clk = {
.halt_reg = 0x3c14,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x3c14,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_cpp_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1386,14 +1544,12 @@ static struct clk_branch smmu_cpp_ahb_clk = {
static struct clk_branch smmu_cpp_axi_clk = {
.halt_reg = 0x3c18,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x3c18,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_cpp_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1401,14 +1557,16 @@ static struct clk_branch smmu_cpp_axi_clk = {
static struct clk_branch smmu_jpeg_ahb_clk = {
.halt_reg = 0x3c24,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x3c24,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_jpeg_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1416,14 +1574,12 @@ static struct clk_branch smmu_jpeg_ahb_clk = {
static struct clk_branch smmu_jpeg_axi_clk = {
.halt_reg = 0x3c28,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x3c28,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_jpeg_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1436,9 +1592,7 @@ static struct clk_branch mmagic_mdss_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmagic_mdss_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
@@ -1451,9 +1605,7 @@ static struct clk_branch mmagic_mdss_noc_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmagic_mdss_noc_cfg_ahb_clk",
- .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
@@ -1461,14 +1613,16 @@ static struct clk_branch mmagic_mdss_noc_cfg_ahb_clk = {
static struct clk_branch smmu_rot_ahb_clk = {
.halt_reg = 0x2444,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x2444,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_rot_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1476,14 +1630,12 @@ static struct clk_branch smmu_rot_ahb_clk = {
static struct clk_branch smmu_rot_axi_clk = {
.halt_reg = 0x2448,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x2448,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_rot_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1491,14 +1643,17 @@ static struct clk_branch smmu_rot_axi_clk = {
static struct clk_branch smmu_mdp_ahb_clk = {
.halt_reg = 0x2454,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x2454,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_mdp_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
+ .flags = CLK_ENABLE_HAND_OFF,
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1506,14 +1661,13 @@ static struct clk_branch smmu_mdp_ahb_clk = {
static struct clk_branch smmu_mdp_axi_clk = {
.halt_reg = 0x2458,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x2458,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_mdp_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
@@ -1526,9 +1680,6 @@ static struct clk_branch mmagic_video_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmagic_video_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1541,9 +1692,6 @@ static struct clk_branch mmagic_video_noc_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmagic_video_noc_cfg_ahb_clk",
- .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1551,14 +1699,16 @@ static struct clk_branch mmagic_video_noc_cfg_ahb_clk = {
static struct clk_branch smmu_video_ahb_clk = {
.halt_reg = 0x1174,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x1174,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_video_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1566,29 +1716,12 @@ static struct clk_branch smmu_video_ahb_clk = {
static struct clk_branch smmu_video_axi_clk = {
.halt_reg = 0x1178,
+ .halt_check = BRANCH_VOTED,
.clkr = {
.enable_reg = 0x1178,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "smmu_video_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch mmagic_bimc_axi_clk = {
- .halt_reg = 0x5294,
- .clkr = {
- .enable_reg = 0x5294,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "mmagic_bimc_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1601,9 +1734,6 @@ static struct clk_branch mmagic_bimc_noc_cfg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmagic_bimc_noc_cfg_ahb_clk",
- .parent_names = (const char *[]){ "gcc_mmss_noc_cfg_ahb_clk" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1678,7 +1808,6 @@ static struct clk_branch vmem_maxi_clk = {
.name = "vmem_maxi_clk",
.parent_names = (const char *[]){ "maxi_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1691,9 +1820,10 @@ static struct clk_branch vmem_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "vmem_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1721,9 +1851,10 @@ static struct clk_branch mmss_rbcpr_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mmss_rbcpr_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1751,9 +1882,6 @@ static struct clk_branch video_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "video_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1768,7 +1896,6 @@ static struct clk_branch video_maxi_clk = {
.name = "video_maxi_clk",
.parent_names = (const char *[]){ "maxi_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1781,9 +1908,10 @@ static struct clk_branch video_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "video_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1826,9 +1954,11 @@ static struct clk_branch mdss_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
+ .flags = CLK_ENABLE_HAND_OFF,
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1843,7 +1973,6 @@ static struct clk_branch mdss_hdmi_ahb_clk = {
.name = "mdss_hdmi_ahb_clk",
.parent_names = (const char *[]){ "ahb_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1856,9 +1985,6 @@ static struct clk_branch mdss_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "mdss_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -1903,12 +2029,15 @@ static struct clk_branch mdss_mdp_clk = {
.name = "mdss_mdp_clk",
.parent_names = (const char *[]){ "mdp_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_ENABLE_HAND_OFF,
.ops = &clk_branch2_ops,
},
},
};
+static DEFINE_CLK_VOTER(mdss_mdp_vote_clk, mdss_mdp_clk, 0);
+static DEFINE_CLK_VOTER(mdss_rotator_vote_clk, mdss_mdp_clk, 0);
+
static struct clk_branch mdss_extpclk_clk = {
.halt_reg = 0x2324,
.clkr = {
@@ -2021,9 +2150,6 @@ static struct clk_branch camss_top_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_top_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2036,9 +2162,10 @@ static struct clk_branch camss_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
+ .parent_names = (const char *[]){
+ "mmss_mmagic_ahb_clk"
+ },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2051,9 +2178,6 @@ static struct clk_branch camss_micro_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_micro_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2171,9 +2295,6 @@ static struct clk_branch camss_cci_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_cci_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2321,9 +2442,6 @@ static struct clk_branch camss_jpeg_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_jpeg_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2336,9 +2454,6 @@ static struct clk_branch camss_jpeg_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_jpeg_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2351,9 +2466,6 @@ static struct clk_branch camss_vfe_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2366,9 +2478,6 @@ static struct clk_branch camss_vfe_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2398,7 +2507,6 @@ static struct clk_branch camss_vfe0_stream_clk = {
.name = "camss_vfe0_stream_clk",
.parent_names = (const char *[]){ "vfe0_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2411,9 +2519,6 @@ static struct clk_branch camss_vfe0_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe0_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2443,7 +2548,6 @@ static struct clk_branch camss_vfe1_stream_clk = {
.name = "camss_vfe1_stream_clk",
.parent_names = (const char *[]){ "vfe1_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2456,9 +2560,6 @@ static struct clk_branch camss_vfe1_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_vfe1_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2473,7 +2574,6 @@ static struct clk_branch camss_csi_vfe0_clk = {
.name = "camss_csi_vfe0_clk",
.parent_names = (const char *[]){ "vfe0_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2488,7 +2588,6 @@ static struct clk_branch camss_csi_vfe1_clk = {
.name = "camss_csi_vfe1_clk",
.parent_names = (const char *[]){ "vfe1_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2501,9 +2600,6 @@ static struct clk_branch camss_cpp_vbif_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_cpp_vbif_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2516,9 +2612,6 @@ static struct clk_branch camss_cpp_axi_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_cpp_axi_clk",
- .parent_names = (const char *[]){ "axi_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2546,9 +2639,6 @@ static struct clk_branch camss_cpp_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_cpp_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2576,9 +2666,6 @@ static struct clk_branch camss_csi0_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi0_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2593,7 +2680,6 @@ static struct clk_branch camss_csi0phy_clk = {
.name = "camss_csi0phy_clk",
.parent_names = (const char *[]){ "csi0_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2608,7 +2694,6 @@ static struct clk_branch camss_csi0rdi_clk = {
.name = "camss_csi0rdi_clk",
.parent_names = (const char *[]){ "csi0_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2623,7 +2708,6 @@ static struct clk_branch camss_csi0pix_clk = {
.name = "camss_csi0pix_clk",
.parent_names = (const char *[]){ "csi0_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2651,9 +2735,6 @@ static struct clk_branch camss_csi1_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi1_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2668,7 +2749,6 @@ static struct clk_branch camss_csi1phy_clk = {
.name = "camss_csi1phy_clk",
.parent_names = (const char *[]){ "csi1_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2683,7 +2763,6 @@ static struct clk_branch camss_csi1rdi_clk = {
.name = "camss_csi1rdi_clk",
.parent_names = (const char *[]){ "csi1_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2698,7 +2777,6 @@ static struct clk_branch camss_csi1pix_clk = {
.name = "camss_csi1pix_clk",
.parent_names = (const char *[]){ "csi1_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2726,9 +2804,6 @@ static struct clk_branch camss_csi2_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi2_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2743,7 +2818,6 @@ static struct clk_branch camss_csi2phy_clk = {
.name = "camss_csi2phy_clk",
.parent_names = (const char *[]){ "csi2_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2758,7 +2832,6 @@ static struct clk_branch camss_csi2rdi_clk = {
.name = "camss_csi2rdi_clk",
.parent_names = (const char *[]){ "csi2_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2773,7 +2846,6 @@ static struct clk_branch camss_csi2pix_clk = {
.name = "camss_csi2pix_clk",
.parent_names = (const char *[]){ "csi2_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2801,9 +2873,6 @@ static struct clk_branch camss_csi3_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_csi3_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2818,7 +2887,6 @@ static struct clk_branch camss_csi3phy_clk = {
.name = "camss_csi3phy_clk",
.parent_names = (const char *[]){ "csi3_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2833,7 +2901,6 @@ static struct clk_branch camss_csi3rdi_clk = {
.name = "camss_csi3rdi_clk",
.parent_names = (const char *[]){ "csi3_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2848,7 +2915,6 @@ static struct clk_branch camss_csi3pix_clk = {
.name = "camss_csi3pix_clk",
.parent_names = (const char *[]){ "csi3_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2861,9 +2927,6 @@ static struct clk_branch camss_ispif_ahb_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "camss_ispif_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
@@ -2893,175 +2956,27 @@ static struct clk_branch fd_core_uar_clk = {
.name = "fd_core_uar_clk",
.parent_names = (const char *[]){ "fd_core_clk_src" },
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch fd_ahb_clk = {
- .halt_reg = 0x3ba74,
+ .halt_reg = 0x3b74,
.clkr = {
- .enable_reg = 0x3ba74,
+ .enable_reg = 0x3b74,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "fd_ahb_clk",
- .parent_names = (const char *[]){ "ahb_clk_src" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_hw *mmcc_msm8996_hws[] = {
- &gpll0_div.hw,
-};
-
-static struct gdsc mmagic_bimc_gdsc = {
- .gdscr = 0x529c,
- .pd = {
- .name = "mmagic_bimc",
- },
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc mmagic_video_gdsc = {
- .gdscr = 0x119c,
- .gds_hw_ctrl = 0x120c,
- .pd = {
- .name = "mmagic_video",
- },
- .pwrsts = PWRSTS_OFF_ON,
- .flags = VOTABLE,
-};
-
-static struct gdsc mmagic_mdss_gdsc = {
- .gdscr = 0x247c,
- .gds_hw_ctrl = 0x2480,
- .pd = {
- .name = "mmagic_mdss",
- },
- .pwrsts = PWRSTS_OFF_ON,
- .flags = VOTABLE,
-};
-
-static struct gdsc mmagic_camss_gdsc = {
- .gdscr = 0x3c4c,
- .gds_hw_ctrl = 0x3c50,
- .pd = {
- .name = "mmagic_camss",
- },
- .pwrsts = PWRSTS_OFF_ON,
- .flags = VOTABLE,
-};
-
-static struct gdsc venus_gdsc = {
- .gdscr = 0x1024,
- .cxcs = (unsigned int []){ 0x1028, 0x1034, 0x1038 },
- .cxc_count = 3,
- .pd = {
- .name = "venus",
- },
- .parent = &mmagic_video_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc venus_core0_gdsc = {
- .gdscr = 0x1040,
- .cxcs = (unsigned int []){ 0x1048 },
- .cxc_count = 1,
- .pd = {
- .name = "venus_core0",
- },
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc venus_core1_gdsc = {
- .gdscr = 0x1044,
- .cxcs = (unsigned int []){ 0x104c },
- .cxc_count = 1,
- .pd = {
- .name = "venus_core1",
- },
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc camss_gdsc = {
- .gdscr = 0x34a0,
- .cxcs = (unsigned int []){ 0x36bc, 0x36c4 },
- .cxc_count = 2,
- .pd = {
- .name = "camss",
- },
- .parent = &mmagic_camss_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc vfe0_gdsc = {
- .gdscr = 0x3664,
- .cxcs = (unsigned int []){ 0x36a8 },
- .cxc_count = 1,
- .pd = {
- .name = "vfe0",
- },
- .parent = &camss_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc vfe1_gdsc = {
- .gdscr = 0x3674,
- .cxcs = (unsigned int []){ 0x36ac },
- .cxc_count = 1,
- .pd = {
- .name = "vfe0",
- },
- .parent = &camss_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc jpeg_gdsc = {
- .gdscr = 0x35a4,
- .cxcs = (unsigned int []){ 0x35a8, 0x35b0, 0x35c0, 0x35b8 },
- .cxc_count = 4,
- .pd = {
- .name = "jpeg",
- },
- .parent = &camss_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc cpp_gdsc = {
- .gdscr = 0x36d4,
- .cxcs = (unsigned int []){ 0x36b0 },
- .cxc_count = 1,
- .pd = {
- .name = "cpp",
- },
- .parent = &camss_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc fd_gdsc = {
- .gdscr = 0x3b64,
- .cxcs = (unsigned int []){ 0x3b68, 0x3b6c },
- .cxc_count = 2,
- .pd = {
- .name = "fd",
- },
- .parent = &camss_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
-};
-
-static struct gdsc mdss_gdsc = {
- .gdscr = 0x2304,
- .cxcs = (unsigned int []){ 0x2310, 0x231c },
- .cxc_count = 2,
- .pd = {
- .name = "mdss",
- },
- .parent = &mmagic_mdss_gdsc.pd,
- .pwrsts = PWRSTS_OFF_ON,
+ [GPLL0_DIV] = &gpll0_div.hw,
+ [MDSS_MDP_VOTE_CLK] = &mdss_mdp_vote_clk.hw,
+ [MDSS_ROTATOR_VOTE_CLK] = &mdss_rotator_vote_clk.hw,
};
static struct clk_regmap *mmcc_msm8996_clocks[] = {
@@ -3082,11 +2997,9 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = {
[MMPLL9_EARLY] = &mmpll9_early.clkr,
[MMPLL9_PLL] = &mmpll9.clkr,
[AHB_CLK_SRC] = &ahb_clk_src.clkr,
- [AXI_CLK_SRC] = &axi_clk_src.clkr,
[MAXI_CLK_SRC] = &maxi_clk_src.clkr,
[GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
[RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
- [ISENSE_CLK_SRC] = &isense_clk_src.clkr,
[RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
[VIDEO_CORE_CLK_SRC] = &video_core_clk_src.clkr,
[VIDEO_SUBCORE0_CLK_SRC] = &video_subcore0_clk_src.clkr,
@@ -3129,7 +3042,6 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = {
[MMSS_MMAGIC_CFG_AHB_CLK] = &mmss_mmagic_cfg_ahb_clk.clkr,
[MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr,
[MMSS_MISC_CXO_CLK] = &mmss_misc_cxo_clk.clkr,
- [MMSS_MMAGIC_AXI_CLK] = &mmss_mmagic_axi_clk.clkr,
[MMSS_MMAGIC_MAXI_CLK] = &mmss_mmagic_maxi_clk.clkr,
[MMAGIC_CAMSS_AXI_CLK] = &mmagic_camss_axi_clk.clkr,
[MMAGIC_CAMSS_NOC_CFG_AHB_CLK] = &mmagic_camss_noc_cfg_ahb_clk.clkr,
@@ -3149,7 +3061,6 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = {
[MMAGIC_VIDEO_NOC_CFG_AHB_CLK] = &mmagic_video_noc_cfg_ahb_clk.clkr,
[SMMU_VIDEO_AHB_CLK] = &smmu_video_ahb_clk.clkr,
[SMMU_VIDEO_AXI_CLK] = &smmu_video_axi_clk.clkr,
- [MMAGIC_BIMC_AXI_CLK] = &mmagic_bimc_axi_clk.clkr,
[MMAGIC_BIMC_NOC_CFG_AHB_CLK] = &mmagic_bimc_noc_cfg_ahb_clk.clkr,
[GPU_GX_GFX3D_CLK] = &gpu_gx_gfx3d_clk.clkr,
[GPU_GX_RBBMTIMER_CLK] = &gpu_gx_rbbmtimer_clk.clkr,
@@ -3240,23 +3151,6 @@ static struct clk_regmap *mmcc_msm8996_clocks[] = {
[FD_AHB_CLK] = &fd_ahb_clk.clkr,
};
-static struct gdsc *mmcc_msm8996_gdscs[] = {
- [MMAGIC_BIMC_GDSC] = &mmagic_bimc_gdsc,
- [MMAGIC_VIDEO_GDSC] = &mmagic_video_gdsc,
- [MMAGIC_MDSS_GDSC] = &mmagic_mdss_gdsc,
- [MMAGIC_CAMSS_GDSC] = &mmagic_camss_gdsc,
- [VENUS_GDSC] = &venus_gdsc,
- [VENUS_CORE0_GDSC] = &venus_core0_gdsc,
- [VENUS_CORE1_GDSC] = &venus_core1_gdsc,
- [CAMSS_GDSC] = &camss_gdsc,
- [VFE0_GDSC] = &vfe0_gdsc,
- [VFE1_GDSC] = &vfe1_gdsc,
- [JPEG_GDSC] = &jpeg_gdsc,
- [CPP_GDSC] = &cpp_gdsc,
- [FD_GDSC] = &fd_gdsc,
- [MDSS_GDSC] = &mdss_gdsc,
-};
-
static const struct qcom_reset_map mmcc_msm8996_resets[] = {
[MMAGICAHB_BCR] = { 0x5020 },
[MMAGIC_CFG_BCR] = { 0x5050 },
@@ -3321,21 +3215,21 @@ static const struct qcom_reset_map mmcc_msm8996_resets[] = {
};
static const struct regmap_config mmcc_msm8996_regmap_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = 0xb008,
- .fast_io = true,
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xb008,
+ .fast_io = true,
};
static const struct qcom_cc_desc mmcc_msm8996_desc = {
.config = &mmcc_msm8996_regmap_config,
.clks = mmcc_msm8996_clocks,
+ .hwclks = mmcc_msm8996_hws,
+ .num_hwclks = ARRAY_SIZE(mmcc_msm8996_hws),
.num_clks = ARRAY_SIZE(mmcc_msm8996_clocks),
.resets = mmcc_msm8996_resets,
.num_resets = ARRAY_SIZE(mmcc_msm8996_resets),
- .gdscs = mmcc_msm8996_gdscs,
- .num_gdscs = ARRAY_SIZE(mmcc_msm8996_gdscs),
};
static const struct of_device_id mmcc_msm8996_match_table[] = {
@@ -3346,10 +3240,9 @@ MODULE_DEVICE_TABLE(of, mmcc_msm8996_match_table);
static int mmcc_msm8996_probe(struct platform_device *pdev)
{
- struct clk *clk;
- struct device *dev = &pdev->dev;
- int i;
struct regmap *regmap;
+ struct regulator *reg;
+ int ret = 0;
regmap = qcom_cc_map(pdev, &mmcc_msm8996_desc);
if (IS_ERR(regmap))
@@ -3360,13 +3253,48 @@ static int mmcc_msm8996_probe(struct platform_device *pdev)
/* Disable the NoC FSM for mmss_mmagic_cfg_ahb_clk */
regmap_update_bits(regmap, 0x5054, BIT(15), 0);
- for (i = 0; i < ARRAY_SIZE(mmcc_msm8996_hws); i++) {
- clk = devm_clk_register(dev, mmcc_msm8996_hws[i]);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ vdd_dig.vdd_uv[1] = RPM_REGULATOR_CORNER_SVS_KRAIT;
+ reg = vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig");
+ if (IS_ERR(reg)) {
+ if (PTR_ERR(reg) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get vdd_dig regulator!");
+ return PTR_ERR(reg);
+ }
+
+ reg = vdd_mmpll4.regulator[0] = devm_regulator_get(&pdev->dev,
+ "mmpll4_dig");
+ if (IS_ERR(reg)) {
+ if (PTR_ERR(reg) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get mmpll4_dig regulator!");
+ return PTR_ERR(reg);
+ }
+
+ reg = vdd_mmpll4.regulator[1] = devm_regulator_get(&pdev->dev,
+ "mmpll4_analog");
+ if (IS_ERR(reg)) {
+ if (PTR_ERR(reg) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get mmpll4_analog regulator!");
+ return PTR_ERR(reg);
+ }
+
+ clk_alpha_pll_configure(&mmpll0_early, regmap, &mmpll0_config);
+ clk_alpha_pll_configure(&mmpll1_early, regmap, &mmpll1_config);
+ clk_alpha_pll_configure(&mmpll2_early, regmap, &mmpll2_config);
+ clk_alpha_pll_configure(&mmpll3_early, regmap, &mmpll3_config);
+ clk_alpha_pll_configure(&mmpll4_early, regmap, &mmpll4_config);
+ clk_alpha_pll_configure(&mmpll5_early, regmap, &mmpll5_config);
+ clk_alpha_pll_configure(&mmpll8_early, regmap, &mmpll8_config);
+ clk_alpha_pll_configure(&mmpll9_early, regmap, &mmpll9_config);
+
+ ret = qcom_cc_really_probe(pdev, &mmcc_msm8996_desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register MMCC clocks\n");
+ return ret;
}
- return qcom_cc_really_probe(pdev, &mmcc_msm8996_desc, regmap);
+ dev_info(&pdev->dev, "Registered MMCC clocks\n");
+
+ return ret;
}
static struct platform_driver mmcc_msm8996_driver = {
@@ -3376,7 +3304,18 @@ static struct platform_driver mmcc_msm8996_driver = {
.of_match_table = mmcc_msm8996_match_table,
},
};
-module_platform_driver(mmcc_msm8996_driver);
+
+static int __init msm_mmcc_8996_init(void)
+{
+ return platform_driver_register(&mmcc_msm8996_driver);
+}
+arch_initcall(msm_mmcc_8996_init);
+
+static void __exit mmcc_msm8996_exit(void)
+{
+ platform_driver_unregister(&mmcc_msm8996_driver);
+}
+module_exit(mmcc_msm8996_exit);
MODULE_DESCRIPTION("QCOM MMCC MSM8996 Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index a5e5ad34db16..ab21334d5813 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -53,6 +53,8 @@
#define QCOM_SDCC_ICE_DEV "icesdcc"
#define QCOM_ICE_TYPE_NAME_LEN 8
#define QCOM_ICE_MAX_BIST_CHECK_COUNT 100
+#define QCOM_ICE_UFS 10
+#define QCOM_ICE_SDCC 20
struct ice_clk_info {
struct list_head list;
@@ -838,7 +840,7 @@ static int qcom_ice_restore_config(void)
return ret;
}
-static int qcom_ice_restore_key_config(void)
+static int qcom_ice_restore_key_config(struct ice_device *ice_dev)
{
struct scm_desc desc = {0};
int ret = -1;
@@ -846,7 +848,12 @@ static int qcom_ice_restore_key_config(void)
/* For ice 3, key configuration needs to be restored in case of reset */
desc.arginfo = TZ_OS_KS_RESTORE_KEY_CONFIG_ID_PARAM_ID;
- desc.args[0] = 10; /* UFS_ICE */
+
+ if (!strcmp(ice_dev->ice_instance_type, "sdcc"))
+ desc.args[0] = QCOM_ICE_SDCC;
+
+ if (!strcmp(ice_dev->ice_instance_type, "ufs"))
+ desc.args[0] = QCOM_ICE_UFS;
ret = scm_call2(TZ_OS_KS_RESTORE_KEY_CONFIG_ID, &desc);
@@ -1135,7 +1142,7 @@ static int qcom_ice_finish_power_collapse(struct ice_device *ice_dev)
* restore it
*/
} else if (ICE_REV(ice_dev->ice_hw_version, MAJOR) > 2) {
- err = qcom_ice_restore_key_config();
+ err = qcom_ice_restore_key_config(ice_dev);
if (err)
goto out;
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 6fa56abf0c78..351985327214 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -97,12 +97,13 @@ static struct page **get_pages(struct drm_gem_object *obj)
msm_obj->pages = p;
- /* For non-cached buffers, ensure the new pages are clean
- * because display controller, GPU, etc. are not coherent:
+ /*
+ * Make sure to flush the CPU cache for newly allocated memory
+ * so we don't get ourselves into trouble with a dirty cache
*/
if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
- dma_map_sg(dev->dev, msm_obj->sgt->sgl,
- msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+ dma_sync_sg_for_device(dev->dev, msm_obj->sgt->sgl,
+ msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
}
return msm_obj->pages;
@@ -113,12 +114,6 @@ static void put_pages(struct drm_gem_object *obj)
struct msm_gem_object *msm_obj = to_msm_bo(obj);
if (msm_obj->pages) {
- /* For non-cached buffers, ensure the new pages are clean
- * because display controller, GPU, etc. are not coherent:
- */
- if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
- dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl,
- msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
sg_free_table(msm_obj->sgt);
kfree(msm_obj->sgt);
@@ -307,9 +302,14 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
DRM_ERROR("Unable to map dma buf\n");
return ret;
}
+ } else {
+ ret = mmu->funcs->map_sg(mmu, msm_obj->sgt,
+ DMA_BIDIRECTIONAL);
}
- msm_obj->domain[id].iova =
- sg_dma_address(msm_obj->sgt->sgl);
+
+ if (!ret)
+ msm_obj->domain[id].iova =
+ sg_dma_address(msm_obj->sgt->sgl);
} else {
WARN_ONCE(1, "physical address being used\n");
msm_obj->domain[id].iova = physaddr(obj);
@@ -535,7 +535,9 @@ void msm_gem_free_object(struct drm_gem_object *obj)
mmu->funcs->unmap_dma_buf(mmu, msm_obj->sgt,
obj->import_attach->dmabuf,
DMA_BIDIRECTIONAL);
- }
+ } else
+ mmu->funcs->unmap_sg(mmu, msm_obj->sgt,
+ DMA_BIDIRECTIONAL);
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 743f5e72d1a8..ceb48282081d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -64,6 +64,18 @@ enum sde_hw_filter {
SDE_SCALE_FILTER_MAX
};
+enum sde_hw_filter_alpa {
+ SDE_SCALE_ALPHA_PIXEL_REP,
+ SDE_SCALE_ALPHA_BIL
+};
+
+enum sde_hw_filter_yuv {
+ SDE_SCALE_2D_4X4,
+ SDE_SCALE_2D_CIR,
+ SDE_SCALE_1D_SEP,
+ SDE_SCALE_BIL
+};
+
struct sde_hw_sharp_cfg {
u32 strength;
u32 edge_thr;
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 3ca74926cfac..b3de45302dea 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -60,6 +60,9 @@
#define SDE_PLANE_DIRTY_SHARPEN 0x4
#define SDE_PLANE_DIRTY_ALL 0xFFFFFFFF
+#define SDE_QSEED3_DEFAULT_PRELOAD_H 0x4
+#define SDE_QSEED3_DEFAULT_PRELOAD_V 0x3
+
/**
* enum sde_plane_qos - Different qos configurations for each pipe
*
@@ -615,6 +618,73 @@ static void _sde_plane_setup_scaler3(struct sde_plane *psde,
const struct sde_format *fmt,
uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
{
+ uint32_t decimated, i;
+
+ if (!psde || !scale_cfg || !fmt || !chroma_subsmpl_h ||
+ !chroma_subsmpl_v) {
+ SDE_ERROR("psde %pK scale_cfg %pK fmt %pK smp_h %d smp_v %d\n"
+ , psde, scale_cfg, fmt, chroma_subsmpl_h,
+ chroma_subsmpl_v);
+ return;
+ }
+
+ memset(scale_cfg, 0, sizeof(*scale_cfg));
+
+ decimated = DECIMATED_DIMENSION(src_w,
+ psde->pipe_cfg.horz_decimation);
+ scale_cfg->phase_step_x[SDE_SSPP_COMP_0] =
+ mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_w);
+ decimated = DECIMATED_DIMENSION(src_h,
+ psde->pipe_cfg.vert_decimation);
+ scale_cfg->phase_step_y[SDE_SSPP_COMP_0] =
+ mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_h);
+
+
+ scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2] =
+ scale_cfg->phase_step_y[SDE_SSPP_COMP_0] / chroma_subsmpl_v;
+ scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2] =
+ scale_cfg->phase_step_x[SDE_SSPP_COMP_0] / chroma_subsmpl_h;
+
+ scale_cfg->phase_step_x[SDE_SSPP_COMP_2] =
+ scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2];
+ scale_cfg->phase_step_y[SDE_SSPP_COMP_2] =
+ scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2];
+
+ scale_cfg->phase_step_x[SDE_SSPP_COMP_3] =
+ scale_cfg->phase_step_x[SDE_SSPP_COMP_0];
+ scale_cfg->phase_step_y[SDE_SSPP_COMP_3] =
+ scale_cfg->phase_step_y[SDE_SSPP_COMP_0];
+
+ for (i = 0; i < SDE_MAX_PLANES; i++) {
+ scale_cfg->src_width[i] = DECIMATED_DIMENSION(src_w,
+ psde->pipe_cfg.horz_decimation);
+ scale_cfg->src_height[i] = DECIMATED_DIMENSION(src_h,
+ psde->pipe_cfg.vert_decimation);
+ if (SDE_FORMAT_IS_YUV(fmt))
+ scale_cfg->src_width[i] &= ~0x1;
+ if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) {
+ scale_cfg->src_width[i] /= chroma_subsmpl_h;
+ scale_cfg->src_height[i] /= chroma_subsmpl_v;
+ }
+ scale_cfg->preload_x[i] = SDE_QSEED3_DEFAULT_PRELOAD_H;
+ scale_cfg->preload_y[i] = SDE_QSEED3_DEFAULT_PRELOAD_V;
+ psde->pixel_ext.num_ext_pxls_top[i] =
+ scale_cfg->src_height[i];
+ psde->pixel_ext.num_ext_pxls_left[i] =
+ scale_cfg->src_width[i];
+ }
+ if (!(SDE_FORMAT_IS_YUV(fmt)) && (src_h == dst_h)
+ && (src_w == dst_w))
+ return;
+
+ scale_cfg->dst_width = dst_w;
+ scale_cfg->dst_height = dst_h;
+ scale_cfg->y_rgb_filter_cfg = SDE_SCALE_BIL;
+ scale_cfg->uv_filter_cfg = SDE_SCALE_BIL;
+ scale_cfg->alpha_filter_cfg = SDE_SCALE_ALPHA_BIL;
+ scale_cfg->lut_flag = 0;
+ scale_cfg->blend_cfg = 1;
+ scale_cfg->enable = 1;
}
/**
@@ -901,6 +971,7 @@ static void _sde_plane_setup_scaler(struct sde_plane *psde,
error = _sde_plane_setup_scaler3_lut(psde, pstate);
if (error || !psde->pixel_ext_usr) {
+ memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
/* calculate default config for QSEED3 */
_sde_plane_setup_scaler3(psde,
psde->pipe_cfg.src_rect.w,
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index bae3884aa277..2b227f2c3a6c 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2017, 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
@@ -3617,6 +3617,9 @@ static inline bool _is_phys_bindable(struct kgsl_mem_entry *phys_entry,
if (!IS_ALIGNED(offset | size, kgsl_memdesc_get_pagesize(memdesc)))
return false;
+ if (offset + size < offset)
+ return false;
+
if (!(flags & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS) &&
offset + size > memdesc->size)
return false;
@@ -3744,7 +3747,7 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
break;
/* Sanity check initial range */
- if (obj.size == 0 ||
+ if (obj.size == 0 || obj.virtoffset + obj.size < obj.size ||
obj.virtoffset + obj.size > virt_entry->memdesc.size ||
!(IS_ALIGNED(obj.virtoffset | obj.size, pg_sz))) {
ret = -EINVAL;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index cbf603ed5916..cf29f2756b84 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -31,6 +31,7 @@
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
+#include <linux/pinctrl/consumer.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
@@ -50,6 +51,7 @@ struct gpio_button_data {
struct gpio_keys_drvdata {
const struct gpio_keys_platform_data *pdata;
+ struct pinctrl *key_pinctrl;
struct input_dev *input;
struct mutex disable_lock;
struct gpio_button_data data[0];
@@ -564,6 +566,41 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
input_sync(input);
}
+static int gpio_keys_pinctrl_configure(struct gpio_keys_drvdata *ddata,
+ bool active)
+{
+ struct pinctrl_state *set_state;
+ int retval;
+
+ if (active) {
+ set_state =
+ pinctrl_lookup_state(ddata->key_pinctrl,
+ "tlmm_gpio_key_active");
+ if (IS_ERR(set_state)) {
+ dev_err(&ddata->input->dev,
+ "cannot get ts pinctrl active state\n");
+ return PTR_ERR(set_state);
+ }
+ } else {
+ set_state =
+ pinctrl_lookup_state(ddata->key_pinctrl,
+ "tlmm_gpio_key_suspend");
+ if (IS_ERR(set_state)) {
+ dev_err(&ddata->input->dev,
+ "cannot get gpiokey pinctrl sleep state\n");
+ return PTR_ERR(set_state);
+ }
+ }
+ retval = pinctrl_select_state(ddata->key_pinctrl, set_state);
+ if (retval) {
+ dev_err(&ddata->input->dev,
+ "cannot set ts pinctrl active state\n");
+ return retval;
+ }
+
+ return 0;
+}
+
static int gpio_keys_open(struct input_dev *input)
{
struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
@@ -708,6 +745,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
size_t size;
int i, error;
int wakeup = 0;
+ struct pinctrl_state *set_state;
if (!pdata) {
pdata = gpio_keys_get_devtree_pdata(dev);
@@ -751,13 +789,31 @@ static int gpio_keys_probe(struct platform_device *pdev)
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
+ /* Get pinctrl if target uses pinctrl */
+ ddata->key_pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(ddata->key_pinctrl)) {
+ if (PTR_ERR(ddata->key_pinctrl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ pr_debug("Target does not use pinctrl\n");
+ ddata->key_pinctrl = NULL;
+ }
+
+ if (ddata->key_pinctrl) {
+ error = gpio_keys_pinctrl_configure(ddata, true);
+ if (error) {
+ dev_err(dev, "cannot set ts pinctrl active state\n");
+ return error;
+ }
+ }
+
for (i = 0; i < pdata->nbuttons; i++) {
const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
error = gpio_keys_setup_key(pdev, input, bdata, button);
if (error)
- return error;
+ goto err_setup_key;
if (button->wakeup)
wakeup = 1;
@@ -767,7 +823,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n",
error);
- return error;
+ goto err_create_sysfs;
}
error = input_register_device(input);
@@ -783,6 +839,18 @@ static int gpio_keys_probe(struct platform_device *pdev)
err_remove_group:
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
+err_create_sysfs:
+err_setup_key:
+ if (ddata->key_pinctrl) {
+ set_state =
+ pinctrl_lookup_state(ddata->key_pinctrl,
+ "tlmm_gpio_key_suspend");
+ if (IS_ERR(set_state))
+ dev_err(dev, "cannot get gpiokey pinctrl sleep state\n");
+ else
+ pinctrl_select_state(ddata->key_pinctrl, set_state);
+ }
+
return error;
}
@@ -800,7 +868,15 @@ static int gpio_keys_suspend(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
- int i;
+ int i, ret;
+
+ if (ddata->key_pinctrl) {
+ ret = gpio_keys_pinctrl_configure(ddata, false);
+ if (ret) {
+ dev_err(dev, "failed to put the pin in suspend state\n");
+ return ret;
+ }
+ }
if (device_may_wakeup(dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
@@ -825,6 +901,14 @@ static int gpio_keys_resume(struct device *dev)
int error = 0;
int i;
+ if (ddata->key_pinctrl) {
+ error = gpio_keys_pinctrl_configure(ddata, true);
+ if (error) {
+ dev_err(dev, "failed to put the pin in resume state\n");
+ return error;
+ }
+ }
+
if (device_may_wakeup(dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 49df5e0afbfb..f13017cd9d46 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1228,4 +1228,15 @@ config TOUCHSCREEN_GT9XX
If unsure, say N.
source "drivers/input/touchscreen/gt9xx/Kconfig"
+
+config TOUCHSCREEN_ST
+ bool "STMicroelectronics Touchscreen Driver"
+ depends on I2C
+ help
+ Say Y here if you have a STMicroelectronics Touchscreen.
+
+ If unsure, say N.
+
+source "drivers/input/touchscreen/st/Kconfig"
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 06953a69123f..7606fe53fcff 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -100,3 +100,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_MSTAR21XX) += msg21xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/
+obj-$(CONFIG_TOUCHSCREEN_ST) += st/
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index 1657f56558ce..ded8c88fdac9 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -1,7 +1,7 @@
/* drivers/input/touchscreen/goodix_tool.c
*
* 2010 - 2012 Goodix Technology.
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, 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
@@ -308,6 +308,7 @@ static ssize_t goodix_tool_write(struct file *filp, const char __user *userbuf,
size_t count, loff_t *ppos)
{
s32 ret = 0;
+ u8 *dataptr = NULL;
mutex_lock(&lock);
ret = copy_from_user(&cmd_head, userbuf, CMD_HEAD_LENGTH);
@@ -463,6 +464,11 @@ static ssize_t goodix_tool_write(struct file *filp, const char __user *userbuf,
ret = CMD_HEAD_LENGTH;
exit:
+ dataptr = cmd_head.data;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.wr = 0xFF;
+ cmd_head.data = dataptr;
+
mutex_unlock(&lock);
return ret;
}
diff --git a/drivers/input/touchscreen/st/Kconfig b/drivers/input/touchscreen/st/Kconfig
new file mode 100644
index 000000000000..817faea01742
--- /dev/null
+++ b/drivers/input/touchscreen/st/Kconfig
@@ -0,0 +1,9 @@
+#
+# STMicroelectronics touchscreen driver configuration
+#
+
+config TOUCHSCREEN_ST_I2C
+ tristate "STMicroelectronics i2c touchscreen"
+ depends on TOUCHSCREEN_ST
+ help
+ This enables support for ST touch panel over I2C based touchscreens.
diff --git a/drivers/input/touchscreen/st/Makefile b/drivers/input/touchscreen/st/Makefile
new file mode 100644
index 000000000000..0aa7b4a364da
--- /dev/null
+++ b/drivers/input/touchscreen/st/Makefile
@@ -0,0 +1,5 @@
+#
+## Makefile for the STMicroelectronics touchscreen driver.
+#
+
+obj-$(CONFIG_TOUCHSCREEN_ST_I2C) += fts.o fts_gui.o fts_driver_test.o fts_lib/
diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c
new file mode 100644
index 000000000000..bbe872001407
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts.c
@@ -0,0 +1,2354 @@
+/*
+ * fts.c
+ *
+ * FTS Capacitive touch screen controller (FingerTipS)
+ *
+ * Copyright (C) 2016, STMicroelectronics Limited.
+ * Authors: AMG(Analog Mems Group)
+ *
+ * marco.cali@st.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/completion.h>
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/notifier.h>
+#include <linux/fb.h>
+
+#ifdef KERNEL_ABOVE_2_6_38
+#include <linux/input/mt.h>
+#endif
+
+#include "fts.h"
+#include "fts_lib/ftsCompensation.h"
+#include "fts_lib/ftsIO.h"
+#include "fts_lib/ftsError.h"
+#include "fts_lib/ftsFlash.h"
+#include "fts_lib/ftsFrame.h"
+#include "fts_lib/ftsGesture.h"
+#include "fts_lib/ftsTest.h"
+#include "fts_lib/ftsTime.h"
+#include "fts_lib/ftsTool.h"
+
+#define LINK_KOBJ_NAME "tp"
+
+/*
+ * Uncomment to use polling mode instead of interrupt mode.
+ *
+ */
+/* #define FTS_USE_POLLING_MODE */
+
+/*
+ * Event installer helpers
+ */
+#define event_id(_e) EVENTID_##_e
+#define handler_name(_h) fts_##_h##_event_handler
+
+#define install_handler(_i, _evt, _hnd) \
+do { \
+ _i->event_dispatch_table[event_id(_evt)] = handler_name(_hnd); \
+} while (0)
+
+/*
+ * Asyncronouns command helper
+ */
+#define WAIT_WITH_TIMEOUT(_info, _timeout, _command) \
+do { \
+ if (wait_for_completion_timeout(&_info->cmd_done, _timeout) == 0) { \
+ dev_warn(_info->dev, "Waiting for %s command: timeout\n", \
+ #_command); \
+ } \
+} while (0)
+
+#ifdef KERNEL_ABOVE_2_6_38
+#define TYPE_B_PROTOCOL
+#endif
+
+#if defined(SCRIPTLESS) || defined(DRIVER_TEST)
+static struct class *fts_cmd_class;
+#endif
+
+extern chipInfo ftsInfo;
+
+unsigned char tune_version_same;
+
+char tag[8] = "[ FTS ]\0";
+
+static u32 *typeOfComand;
+static int numberParameters;
+static int feature_feasibility = ERROR_OP_NOT_ALLOW;
+#ifdef PHONE_GESTURE
+static u8 mask[GESTURE_MASK_SIZE+2];
+#endif
+static void fts_interrupt_enable(struct fts_ts_info *info);
+static int fts_init_hw(struct fts_ts_info *info);
+static int fts_mode_handler(struct fts_ts_info *info, int force);
+static int fts_command(struct fts_ts_info *info, unsigned char cmd);
+
+static int fts_chip_initialization(struct fts_ts_info *info);
+
+void touch_callback(unsigned int status)
+{
+ /* Empty */
+}
+
+unsigned int le_to_uint(const unsigned char *ptr)
+{
+ return (unsigned int) ptr[0] + (unsigned int) ptr[1] * 0x100;
+}
+
+unsigned int be_to_uint(const unsigned char *ptr)
+{
+ return (unsigned int) ptr[1] + (unsigned int) ptr[0] * 0x100;
+}
+
+/* force update firmware*/
+static ssize_t fts_fw_control_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count){
+ int ret, mode;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ /* reading out firmware upgrade mode */
+ sscanf(buf, "%d", &mode);
+#ifdef FTM3_CHIP
+ ret = flashProcedure(PATH_FILE_FW, mode, !mode);
+#else
+ ret = flashProcedure(PATH_FILE_FW, mode, 1);
+#endif
+ info->fwupdate_stat = ret;
+
+ if (ret < OK)
+ logError(1, "%s %s :Unable to upgrade firmware\n", tag, __func__);
+ return count;
+}
+
+static ssize_t fts_sysfs_config_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ int error;
+
+ error = snprintf(buf, TSP_BUF_SIZE, "%x.%x\n", ftsInfo.u16_fwVer, ftsInfo.u16_cfgId);
+ return error;
+}
+
+static ssize_t fts_sysfs_fwupdate_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ /* fwupdate_stat: ERROR code Returned by flashProcedure. */
+ return snprintf(buf, TSP_BUF_SIZE, "%08X\n", info->fwupdate_stat);
+}
+
+static ssize_t fts_fw_test_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+
+ Firmware fw;
+ int ret;
+
+ fw.data = NULL;
+ ret = readFwFile(PATH_FILE_FW, &fw, 0);
+
+ if (ret < OK) {
+ logError(1, "%s: Error during reading FW file! ERROR %08X\n", tag, ret);
+ } else
+ logError(1, "%s: fw_version = %04X, config_version = %04X, size = %d bytes\n",
+ tag, fw.fw_ver, fw.config_id, fw.data_size);
+
+ kfree(fw.data);
+ return 0;
+}
+
+/* TODO: edit this function according to the features policy to allow during the screen on/off */
+int check_feature_feasibility(struct fts_ts_info *info, unsigned int feature)
+{
+ int res = ERROR_OP_NOT_ALLOW;
+
+ if (info->resume_bit == 0) {
+ switch (feature) {
+#ifdef PHONE_GESTURE
+ case FEAT_GESTURE:
+ res = OK;
+ break;
+#endif
+ default:
+ logError(1, "%s %s: Feature not allowed in this operating mode! ERROR %08X\n", tag, __func__, res);
+ break;
+
+ }
+ } else{
+ switch (feature) {
+#ifdef PHONE_GESTURE
+ case FEAT_GESTURE:
+#endif
+ case FEAT_GLOVE:
+ /* glove mode can only activate during sense on */
+ res = OK;
+ break;
+
+ default:
+ logError(1, "%s %s: Feature not allowed in this operating mode! ERROR %08X\n", tag, __func__, res);
+ break;
+
+ }
+ }
+
+ return res;
+
+}
+
+static ssize_t fts_feature_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count) {
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ char *p = (char *)buf;
+ unsigned int temp;
+ int res = OK;
+
+ if ((count + 1) / 3 != 2) {
+ logError(1, "%s fts_feature_enable: Number of parameter wrong! %d > %d\n",
+ tag, (count + 1) / 3, 2);
+ } else{
+ sscanf(p, "%02X ", &temp);
+ p += 3;
+ res = check_feature_feasibility(info, temp);
+ if (res >= OK) {
+ switch (temp) {
+#ifdef PHONE_GESTURE
+ case FEAT_GESTURE:
+ sscanf(p, "%02X ", &info->gesture_enabled);
+ logError(1, "%s fts_feature_enable: Gesture Enabled = %d\n", tag,
+ info->gesture_enabled);
+ break;
+#endif
+ case FEAT_GLOVE:
+ sscanf(p, "%02X ", &info->glove_enabled);
+ logError(1, "%s fts_feature_enable: Glove Enabled = %d\n",
+ tag, info->glove_enabled);
+
+ break;
+
+ default:
+ logError(1, "%s fts_feature_enable: Feature %02X not valid! ERROR %08X\n", tag, temp, ERROR_OP_NOT_ALLOW);
+
+ }
+ feature_feasibility = res;
+ }
+
+ }
+ return count;
+}
+
+static ssize_t fts_feature_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char buff[CMD_STR_LEN] = {0};
+ int size = 6 * 2;
+ u8 *all_strbuff = NULL;
+ int count = 0, res;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ if (feature_feasibility >= OK)
+ res = fts_mode_handler(info, 1);
+ else{
+ res = feature_feasibility;
+ logError(1, "%s %s: Call before echo xx xx > feature_enable with a correct feature! ERROR %08X\n", tag, __func__, res);
+ }
+
+ all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL);
+ if (all_strbuff != NULL) {
+ memset(all_strbuff, 0, size);
+
+ snprintf(buff, sizeof(buff), "%02X", 0xAA);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%08X", res);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", 0xBB);
+ strlcat(all_strbuff, buff, size);
+
+ count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
+ kfree(all_strbuff);
+ } else{
+ logError(1, "%s fts_feature_enable_show: Unable to allocate all_strbuff! ERROR %08X\n", tag, ERROR_ALLOC);
+ }
+
+ feature_feasibility = ERROR_OP_NOT_ALLOW;
+ return count;
+}
+
+#ifdef PHONE_GESTURE
+static ssize_t fts_gesture_mask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ char buff[CMD_STR_LEN] = {0};
+ int size = 6 * 2;
+ u8 *all_strbuff = NULL;
+ int count = 0, res;
+
+ if (mask[0] == 0) {
+ res = ERROR_OP_NOT_ALLOW;
+ logError(1, "%s %s: Call before echo enable/disable xx xx .... > gesture_mask with a correct number of parameters! ERROR %08X\n", tag, __func__, res);
+
+ } else{
+ res = fts_disableInterrupt();
+ if (res >= OK) {
+ if (mask[1] == FEAT_ENABLE)
+ res = enableGesture(&mask[2], mask[0]);
+ else{
+ if (mask[1] == FEAT_DISABLE)
+ res = disableGesture(&mask[2], mask[0]);
+ else
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ if (res < OK) {
+ logError(1, "%s fts_gesture_mask_store: ERROR %08X\n", tag, res);
+ }
+ }
+ res |= fts_enableInterrupt();
+ }
+
+ all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL);
+ if (all_strbuff != NULL) {
+ memset(all_strbuff, 0, size);
+
+ snprintf(buff, sizeof(buff), "%02X", 0xAA);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%08X", res);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", 0xBB);
+ strlcat(all_strbuff, buff, size);
+
+ count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
+ kfree(all_strbuff);
+ } else{
+ logError(1, "%s fts_gesture_mask_show: Unable to allocate all_strbuff! ERROR %08X\n", tag, ERROR_ALLOC);
+ }
+
+ mask[0] = 0;
+ return count;
+}
+
+static ssize_t fts_gesture_mask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ int n;
+ unsigned int temp;
+
+ if ((count + 1) / 3 > GESTURE_MASK_SIZE+1) {
+ logError(1, "%s fts_gesture_mask_store: Number of bytes of parameter wrong! %d > (enable/disable + %d )\n", tag, (count + 1) / 3, GESTURE_MASK_SIZE);
+ mask[0] = 0;
+ } else {
+ mask[0] = ((count + 1) / 3) - 1;
+ for (n = 1; n <= (count + 1) / 3; n++) {
+ sscanf(p, "%02X ", &temp);
+ p += 3;
+ mask[n] = (u8)temp;
+ logError(1, "%s mask[%d] = %02X\n", tag, n, mask[n]);
+
+ }
+
+ }
+
+ return count;
+}
+#endif
+
+/************************ PRODUCTION TEST **********************************/
+static ssize_t stm_fts_cmd_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count) {
+ int n;
+ char *p = (char *) buf;
+
+ typeOfComand = (u32 *) kmalloc(8 * sizeof (u32), GFP_KERNEL);
+ if (typeOfComand == NULL) {
+ logError(1, "%s impossible to allocate typeOfComand!\n", tag);
+ return count;
+ }
+ memset(typeOfComand, 0, 8 * sizeof (u32));
+
+ logError(1, "%s\n", tag);
+ for (n = 0; n < (count + 1) / 3; n++) {
+ sscanf(p, "%02X ", &typeOfComand[n]);
+ p += 3;
+ logError(1, "%s typeOfComand[%d] = %02X\n", tag, n, typeOfComand[n]);
+
+ }
+
+ numberParameters = n;
+ logError(1, "%s Number of Parameters = %d\n", tag, numberParameters);
+ return count;
+}
+
+static ssize_t stm_fts_cmd_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ char buff[CMD_STR_LEN] = {0};
+ int res, j, doClean = 0, count;
+
+ int size = 6 * 2;
+ u8 *all_strbuff = NULL;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ MutualSenseData compData;
+ SelfSenseData comData;
+ MutualSenseFrame frameMS;
+ SelfSenseFrame frameSS;
+
+ /* struct used for defining which test
+ *perform during the production test
+ */
+ TestToDo todoDefault;
+
+ todoDefault.MutualRaw = 1;
+ todoDefault.MutualRawGap = 1;
+ todoDefault.MutualCx1 = 0;
+ todoDefault.MutualCx2 = 1;
+ todoDefault.MutualCx2Adj = 1;
+ todoDefault.MutualCxTotal = 0;
+ todoDefault.MutualCxTotalAdj = 0;
+
+ todoDefault.MutualKeyRaw = 0;
+ todoDefault.MutualKeyCx1 = 0;
+ todoDefault.MutualKeyCx2 = 0;
+ todoDefault.MutualKeyCxTotal = 0;
+
+ todoDefault.SelfForceRaw = 1;
+ todoDefault.SelfForceRawGap = 0;
+ todoDefault.SelfForceIx1 = 0;
+ todoDefault.SelfForceIx2 = 0;
+ todoDefault.SelfForceIx2Adj = 0;
+ todoDefault.SelfForceIxTotal = 1;
+ todoDefault.SelfForceIxTotalAdj = 0;
+ todoDefault.SelfForceCx1 = 0;
+ todoDefault.SelfForceCx2 = 0;
+ todoDefault.SelfForceCx2Adj = 0;
+ todoDefault.SelfForceCxTotal = 0;
+ todoDefault.SelfForceCxTotalAdj = 0;
+
+ todoDefault.SelfSenseRaw = 1;
+ todoDefault.SelfSenseRawGap = 0;
+ todoDefault.SelfSenseIx1 = 0;
+ todoDefault.SelfSenseIx2 = 0;
+ todoDefault.SelfSenseIx2Adj = 0;
+ todoDefault.SelfSenseIxTotal = 1;
+ todoDefault.SelfSenseIxTotalAdj = 0;
+ todoDefault.SelfSenseCx1 = 0;
+ todoDefault.SelfSenseCx2 = 0;
+ todoDefault.SelfSenseCx2Adj = 0;
+ todoDefault.SelfSenseCxTotal = 0;
+ todoDefault.SelfSenseCxTotalAdj = 0;
+
+ if (numberParameters >= 1 && typeOfComand != NULL) {
+ res = fts_disableInterrupt();
+ if (res < 0) {
+ logError(0, "%s fts_disableInterrupt: ERROR %08X\n", tag, res);
+ res = (res | ERROR_DISABLE_INTER);
+ goto END;
+ }
+
+ res = fb_unregister_client(&info->notifier);
+ if (res < 0) {
+ logError(1, "%s ERROR: unregister notifier failed!\n", tag);
+ goto END;
+ }
+
+ switch (typeOfComand[0]) {
+ /*ITO TEST*/
+ case 0x01:
+ res = production_test_ito();
+ break;
+ /*PRODUCTION TEST*/
+ case 0x00:
+ if (ftsInfo.u32_mpPassFlag != INIT_MP) {
+ logError(0, "%s MP Flag not set!\n", tag, res);
+ res = production_test_main(LIMITS_FILE, 1, 1, &todoDefault, INIT_MP);
+ } else{
+ logError(0, "%s MP Flag set!\n", tag, res);
+ res = production_test_main(LIMITS_FILE, 1, 0, &todoDefault, INIT_MP);
+ }
+ break;
+ /*read mutual raw*/
+ case 0x13:
+ logError(0, "%s Get 1 MS Frame\n", tag);
+ /* res = getMSFrame(ADDR_RAW_TOUCH, &frame, 0); */
+ res = getMSFrame2(MS_TOUCH_ACTIVE, &frameMS);
+ if (res < 0) {
+ logError(0, "%s Error while taking the MS frame... ERROR %02X\n", tag, res);
+
+ } else {
+ logError(0, "%s The frame size is %d words\n", tag, res);
+ size = (res * sizeof (short) + 8)*2;
+ /* set res to OK because if getMSFrame is
+ * successful res = number of words read
+ */
+ res = OK;
+ }
+ break;
+ /*read self raw*/
+ case 0x15:
+ logError(0, "%s Get 1 SS Frame\n", tag);
+ res = getSSFrame2(SS_TOUCH, &frameSS);
+
+ if (res < OK) {
+ logError(0, "%s Error while taking the SS frame... ERROR %02X\n", tag, res);
+
+ } else {
+ logError(0, "%s The frame size is %d words\n", tag, res);
+ size = (res * sizeof (short) + 8)*2+1;
+ /* set res to OK because if getMSFrame is
+ * successful res = number of words read
+ */
+ res = OK;
+ }
+
+ break;
+
+ case 0x14: /*read mutual comp data */
+ logError(0, "%s Get MS Compensation Data\n", tag);
+ res = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, &compData);
+
+ if (res < 0) {
+ logError(0, "%s Error reading MS compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s MS Compensation Data Reading Finished!\n", tag);
+ size = ((compData.node_data_size + 9) * sizeof (u8))*2;
+ }
+ break;
+
+ case 0x16: /* read self comp data */
+ logError(0, "%s Get SS Compensation Data...\n", tag);
+ res = readSelfSenseCompensationData(SS_TOUCH, &comData);
+ if (res < 0) {
+ logError(0, "%s Error reading SS compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s SS Compensation Data Reading Finished!\n", tag);
+ size = ((comData.header.force_node + comData.header.sense_node)*2 + 12) * sizeof (u8)*2;
+ }
+ break;
+
+ case 0x03: /* MS Raw DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ms_raw(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0x04: /* MS CX DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ms_cx(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0x05: /* SS RAW DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ss_raw(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0x06: /* SS IX CX DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ss_ix_cx(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0xF0:
+ case 0xF1: /* TOUCH ENABLE/DISABLE */
+ doClean = (int) (typeOfComand[0]&0x01);
+ res = cleanUp(doClean);
+
+ break;
+
+ default:
+ logError(1, "%s COMMAND NOT VALID!! Insert a proper value ...\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ break;
+ }
+
+ doClean = fts_enableInterrupt();
+ if (doClean < 0) {
+ logError(0, "%s fts_enableInterrupt: ERROR %08X\n", tag, (doClean|ERROR_ENABLE_INTER));
+ }
+ } else {
+ logError(1, "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ typeOfComand = NULL;
+
+ }
+
+ if (fb_register_client(&info->notifier) < 0) {
+ logError(1, "%s ERROR: register notifier failed!\n", tag);
+ }
+
+END: /* here start the reporting phase, assembling the data to send in the file node */
+ all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL);
+ memset(all_strbuff, 0, size);
+
+ snprintf(buff, sizeof(buff), "%02X", 0xAA);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%08X", res);
+ strlcat(all_strbuff, buff, size);
+
+ if (res >= OK) {
+ /*all the other cases are already fine printing only the res.*/
+ switch (typeOfComand[0]) {
+ case 0x13:
+ snprintf(buff, sizeof (buff), "%02X", (u8) frameMS.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", (u8) frameMS.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ for (j = 0; j < frameMS.node_data_size; j++) {
+ snprintf(buff, sizeof(buff), "%04X", frameMS.node_data[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(frameMS.node_data);
+ break;
+
+ case 0x15:
+ snprintf(buff, sizeof(buff), "%02X", (u8) frameSS.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", (u8) frameSS.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ /* Copying self raw data Force */
+ for (j = 0; j < frameSS.header.force_node; j++) {
+ snprintf(buff, sizeof(buff), "%04X", frameSS.force_data[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying self raw data Sense */
+ for (j = 0; j < frameSS.header.sense_node; j++) {
+ snprintf(buff, sizeof(buff), "%04X", frameSS.sense_data[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(frameSS.force_data);
+ kfree(frameSS.sense_data);
+ break;
+
+ case 0x14:
+ snprintf(buff, sizeof(buff), "%02X", (u8) compData.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", (u8) compData.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ /* Cpying CX1 value */
+ snprintf(buff, sizeof(buff), "%02X", compData.cx1);
+ strlcat(all_strbuff, buff, size);
+
+ /* Copying CX2 values */
+ for (j = 0; j < compData.node_data_size; j++) {
+ snprintf(buff, sizeof(buff), "%02X", *(compData.node_data + j));
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(compData.node_data);
+ break;
+
+ case 0x16:
+ snprintf(buff, sizeof(buff), "%02X", comData.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", comData.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", comData.f_ix1);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", comData.s_ix1);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", comData.f_cx1);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof(buff), "%02X", comData.s_cx1);
+ strlcat(all_strbuff, buff, size);
+
+ /* Copying IX2 Force */
+ for (j = 0; j < comData.header.force_node; j++) {
+ snprintf(buff, sizeof(buff), "%02X", comData.ix2_fm[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying IX2 Sense */
+ for (j = 0; j < comData.header.sense_node; j++) {
+ snprintf(buff, sizeof(buff), "%02X", comData.ix2_sn[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying CX2 Force */
+ for (j = 0; j < comData.header.force_node; j++) {
+ snprintf(buff, sizeof(buff), "%02X", comData.cx2_fm[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying CX2 Sense */
+ for (j = 0; j < comData.header.sense_node; j++) {
+ snprintf(buff, sizeof(buff), "%02X", comData.cx2_sn[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(comData.ix2_fm);
+ kfree(comData.ix2_sn);
+ kfree(comData.cx2_fm);
+ kfree(comData.cx2_sn);
+ break;
+
+ default:
+ break;
+
+ }
+ }
+
+ snprintf(buff, sizeof(buff), "%02X", 0xBB);
+ strlcat(all_strbuff, buff, size);
+
+ count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
+ numberParameters = 0; /* need to reset the number of parameters
+ * in order to wait the next command, comment
+ *if you want to repeat the last command sent
+ *just doing a cat
+ */
+ /* logError(0,"%s numberParameters = %d\n", tag, numberParameters); */
+ kfree(all_strbuff);
+
+ kfree(typeOfComand);
+ return count;
+
+}
+
+static DEVICE_ATTR(fwupdate, (S_IRUGO | S_IWUSR | S_IWGRP), fts_sysfs_fwupdate_show, fts_fw_control_store);
+static DEVICE_ATTR(appid, (S_IRUGO), fts_sysfs_config_id_show, NULL);
+static DEVICE_ATTR(fw_file_test, (S_IRUGO), fts_fw_test_show, NULL);
+static DEVICE_ATTR(stm_fts_cmd, (S_IRUGO | S_IWUSR | S_IWGRP), stm_fts_cmd_show, stm_fts_cmd_store);
+static DEVICE_ATTR(feature_enable, (S_IRUGO | S_IWUSR | S_IWGRP), fts_feature_enable_show, fts_feature_enable_store);
+#ifdef PHONE_GESTURE
+static DEVICE_ATTR(gesture_mask, (S_IRUGO | S_IWUSR | S_IWGRP), fts_gesture_mask_show, fts_gesture_mask_store);
+#endif
+/* /sys/devices/soc.0/f9928000.i2c/i2c-6/6-0049 */
+static struct attribute *fts_attr_group[] = {
+ &dev_attr_fwupdate.attr,
+ &dev_attr_appid.attr,
+ &dev_attr_fw_file_test.attr,
+ /* &dev_attr_touch_debug.attr, */
+ &dev_attr_stm_fts_cmd.attr,
+ &dev_attr_feature_enable.attr,
+#ifdef PHONE_GESTURE
+ &dev_attr_gesture_mask.attr,
+#endif
+ NULL,
+};
+
+static int fts_command(struct fts_ts_info *info, unsigned char cmd)
+{
+ unsigned char regAdd;
+ int ret;
+
+ regAdd = cmd;
+
+ ret = fts_writeCmd(&regAdd, sizeof (regAdd)); /* 0 = ok */
+
+ logError(0, "%s Issued command 0x%02x, return value %08X\n", cmd, ret);
+
+ return ret;
+}
+
+void fts_input_report_key(struct fts_ts_info *info, int key_code)
+{
+ mutex_lock(&info->input_report_mutex);
+ input_report_key(info->input_dev, key_code, 1);
+ input_sync(info->input_dev);
+ input_report_key(info->input_dev, key_code, 0);
+ input_sync(info->input_dev);
+ mutex_unlock(&info->input_report_mutex);
+}
+
+/*
+ * New Interrupt handle implementation
+ */
+
+static inline unsigned char *fts_next_event(unsigned char *evt)
+{
+ /* Nothing to do with this event, moving to the next one */
+ evt += FIFO_EVENT_SIZE;
+
+ /* the previous one was the last event ? */
+ return (evt[-1] & 0x1F) ? evt : NULL;
+}
+
+/* EventId : 0x00 */
+static unsigned char *fts_nop_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ /* logError(1, "%s %s Doing nothing for event = %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ * tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+ */
+ return fts_next_event(event);
+}
+
+/* EventId : 0x03 */
+static unsigned char *fts_enter_pointer_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ unsigned char touchId, touchcount;
+ int x, y, z;
+
+ if (!info->resume_bit)
+ goto no_report;
+
+ touchId = event[1] & 0x0F;
+ touchcount = (event[1] & 0xF0) >> 4;
+
+ __set_bit(touchId, &info->touch_id);
+
+ x = (event[2] << 4) | (event[4] & 0xF0) >> 4;
+ y = (event[3] << 4) | (event[4] & 0x0F);
+ z = (event[5] & 0x3F);
+
+ if (x == X_AXIS_MAX)
+ x--;
+
+ if (y == Y_AXIS_MAX)
+ y--;
+
+ input_mt_slot(info->input_dev, touchId);
+ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1);
+ logError(0, "%s %s : TouchID = %d,Touchcount = %d\n", tag, __func__, touchId, touchcount);
+ if (touchcount == 1) {
+ input_report_key(info->input_dev, BTN_TOUCH, 1);
+ input_report_key(info->input_dev, BTN_TOOL_FINGER, 1);
+ }
+ /* input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, touchId); */
+ input_report_abs(info->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, z);
+ input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, z);
+ input_report_abs(info->input_dev, ABS_MT_PRESSURE, z);
+ logError(0, "%s %s : Event 0x%02x - ID[%d], (x, y, z) = (%3d, %3d, %3d)\n", tag, __func__, *event, touchId, x, y, z);
+
+no_report:
+ return fts_next_event(event);
+}
+
+/* EventId : 0x04 */
+static unsigned char *fts_leave_pointer_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ unsigned char touchId, touchcount;
+
+ touchId = event[1] & 0x0F;
+ touchcount = (event[1] & 0xF0) >> 4;
+
+ __clear_bit(touchId, &info->touch_id);
+
+ input_mt_slot(info->input_dev, touchId);
+ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0);
+ logError(0, "%s %s : TouchID = %d, Touchcount = %d\n", tag, __func__, touchId, touchcount);
+ if (touchcount == 0) {
+ input_report_key(info->input_dev, BTN_TOUCH, 0);
+ input_report_key(info->input_dev, BTN_TOOL_FINGER, 0);
+ }
+
+ input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, -1);
+ logError(0, "%s %s : Event 0x%02x - release ID[%d]\n", tag, __func__, event[0], touchId);
+
+ return fts_next_event(event);
+}
+
+/* EventId : 0x05 */
+#define fts_motion_pointer_event_handler fts_enter_pointer_event_handler
+
+#ifdef PHONE_KEY
+/* EventId : 0x0E */
+static unsigned char *fts_key_status_event_handler(struct fts_ts_info *info, unsigned char *event)
+{
+ int value;
+ logError(0, "%s %s Received event %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+ /* TODO: the customer should handle the events coming from the keys according his needs (this is an example that report only the single pressure of one key at time) */
+ if (event[2] != 0) { /* event[2] contain the bitmask of the keys that are actually pressed */
+ switch (event[2]) {
+ case KEY1:
+ value = KEY_HOMEPAGE;
+ logError(0, "%s %s: Button HOME !\n", tag, __func__);
+ break;
+
+ case KEY2:
+ value = KEY_BACK;
+ logError(0, "%s %s: Button Back !\n", tag, __func__);
+ break;
+
+ case KEY3:
+ value = KEY_MENU;
+ logError(0, "%s %s: Button Menu !\n", tag, __func__);
+ break;
+
+ default:
+ logError(0, "%s %s: No valid Button ID or more than one key pressed!\n", tag, __func__);
+ goto done;
+ }
+
+ fts_input_report_key(info, value);
+ } else{
+ logError(0, "%s %s: All buttons released!\n", tag, __func__);
+ }
+done:
+ return fts_next_event(event);
+}
+#endif
+
+/* EventId : 0x0F */
+static unsigned char *fts_error_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ int error = 0, i = 0;
+ logError(0, "%s %s Received event 0x%02x 0x%02x\n", tag, __func__, event[0], event[1]);
+
+ switch (event[1]) {
+ case EVENT_TYPE_ESD_ERROR:
+ {
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev, (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ fts_chip_powercycle(info);
+
+ error = fts_system_reset();
+ error |= fts_mode_handler(info, 0);
+ error |= fts_enableInterrupt();
+ if (error < OK) {
+ logError(1, "%s %s Cannot restore the device ERROR %08X\n", tag, __func__, error);
+ }
+ }
+ break;
+ case EVENT_TYPE_WATCHDOG_ERROR: /* watch dog timer */
+ {
+ if (event[2] == 0) {
+ /* before reset clear all slot */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+ error = fts_system_reset();
+ error |= fts_mode_handler(info, 0);
+ error |= fts_enableInterrupt();
+ if (error < OK) {
+ logError(1, "%s %s Cannot reset the device ERROR %08X\n", tag, __func__, error);
+ }
+ }
+ }
+ break;
+
+ }
+ return fts_next_event(event);
+}
+
+/* EventId : 0x10 */
+static unsigned char *fts_controller_ready_event_handler(
+ struct fts_ts_info *info, unsigned char *event) {
+ int error;
+ logError(0, "%s %s Received event 0x%02x\n", tag, __func__, event[0]);
+ info->touch_id = 0;
+ input_sync(info->input_dev);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ error = fts_mode_handler(info, 0);
+ if (error < OK) {
+ logError(1, "%s %s Cannot restore the device status ERROR %08X\n", tag, __func__, error);
+ }
+ return fts_next_event(event);
+}
+
+/* EventId : 0x16 */
+static unsigned char *fts_status_event_handler(
+ struct fts_ts_info *info, unsigned char *event) {
+ /* logError(1, "%s Received event 0x%02x\n", tag, event[0]); */
+
+ switch (event[1]) {
+ case EVENT_TYPE_MS_TUNING_CMPL:
+ case EVENT_TYPE_SS_TUNING_CMPL:
+ case FTS_FORCE_CAL_SELF_MUTUAL:
+ case FTS_FLASH_WRITE_CONFIG:
+ case FTS_FLASH_WRITE_COMP_MEMORY:
+ case FTS_FORCE_CAL_SELF:
+ case FTS_WATER_MODE_ON:
+ case FTS_WATER_MODE_OFF:
+ default:
+ logError(1, "%s %s Received unhandled status event = %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+ break;
+ }
+
+ return fts_next_event(event);
+}
+
+#ifdef PHONE_GESTURE
+static unsigned char *fts_gesture_event_handler(struct fts_ts_info *info, unsigned char *event)
+{
+ unsigned char touchId;
+ int value;
+
+ logError(0, "%s gesture event data: %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+
+ if (event[1] == 0x03) {
+
+ logError(1, "%s %s: Gesture ID %02X enable_status = %02X\n", tag, __func__, event[2], event[3]);
+
+ }
+ if (event[1] == EVENT_TYPE_ENB && event[2] == 0x00) {
+ switch (event[3]) {
+ case GESTURE_ENABLE:
+ logError(1, "%s %s: Gesture Enabled! res = %02X\n", tag, __func__, event[4]);
+ break;
+
+ case GESTURE_DISABLE:
+ logError(1, "%s %s: Gesture Disabled! res = %02X\n", tag, __func__, event[4]);
+ break;
+
+ default:
+ logError(1, "%s %s: Event not Valid!\n", tag, __func__);
+
+ }
+
+ }
+
+ /* always use touchId zero */
+ touchId = 0;
+ __set_bit(touchId, &info->touch_id);
+
+ if (event[0] == EVENTID_GESTURE && (event[1] == EVENT_TYPE_GESTURE_DTC1 || event[1] == EVENT_TYPE_GESTURE_DTC2)) {
+
+ switch (event[2]) {
+ case GES_ID_DBLTAP:
+ value = KEY_WAKEUP;
+ logError(0, "%s %s: double tap !\n", tag, __func__);
+ break;
+
+ case GES_ID_AT:
+ value = KEY_WWW;
+ logError(0, "%s %s: @ !\n", tag, __func__);
+ break;
+
+ case GES_ID_C:
+ value = KEY_C;
+ logError(0, "%s %s: C !\n", tag, __func__);
+ break;
+
+ case GES_ID_E:
+ value = KEY_E;
+ logError(0, "%s %s: e !\n", tag, __func__);
+ break;
+
+ case GES_ID_F:
+ value = KEY_F;
+ logError(0, "%s %s: F !\n", tag, __func__);
+ break;
+
+ case GES_ID_L:
+ value = KEY_L;
+ logError(0, "%s %s: L !\n", tag, __func__);
+ break;
+
+ case GES_ID_M:
+ value = KEY_M;
+ logError(0, "%s %s: M !\n", tag, __func__);
+ break;
+
+ case GES_ID_O:
+ value = KEY_O;
+ logError(0, "%s %s: O !\n", tag, __func__);
+ break;
+
+ case GES_ID_S:
+ value = KEY_S;
+ logError(0, "%s %s: S !\n", tag, __func__);
+ break;
+
+ case GES_ID_V:
+ value = KEY_V;
+ logError(0, "%s %s: V !\n", tag, __func__);
+ break;
+
+ case GES_ID_W:
+ value = KEY_W;
+ logError(0, "%s %s: W !\n", tag, __func__);
+ break;
+
+ case GES_ID_Z:
+ value = KEY_Z;
+ logError(0, "%s %s: Z !\n", tag, __func__);
+ break;
+
+ case GES_ID_HFLIP_L2R:
+ value = KEY_RIGHT;
+ logError(0, "%s %s: -> !\n", tag, __func__);
+ break;
+
+ case GES_ID_HFLIP_R2L:
+ value = KEY_LEFT;
+ logError(0, "%s %s: <- !\n", tag, __func__);
+ break;
+
+ case GES_ID_VFLIP_D2T:
+ value = KEY_UP;
+ logError(0, "%s %s: UP !\n", tag, __func__);
+ break;
+
+ case GES_ID_VFLIP_T2D:
+ value = KEY_DOWN;
+ logError(0, "%s %s: DOWN !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST1:
+ value = KEY_F1;
+ logError(0, "%s %s: F1 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST2:
+ value = KEY_F1;
+ logError(0, "%s %s: F2 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST3:
+ value = KEY_F3;
+ logError(0, "%s %s: F3 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST4:
+ value = KEY_F1;
+ logError(0, "%s %s: F4 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST5:
+ value = KEY_F1;
+ logError(0, "%s %s: F5 !\n", tag, __func__);
+ break;
+
+ case GES_ID_LEFTBRACE:
+ value = KEY_LEFTBRACE;
+ logError(0, "%s %s: < !\n", tag, __func__);
+ break;
+
+ case GES_ID_RIGHTBRACE:
+ value = KEY_RIGHTBRACE;
+ logError(0, "%s %s: > !\n", tag, __func__);
+ break;
+ default:
+ logError(0, "%s %s: No valid GestureID!\n", tag, __func__);
+ goto gesture_done;
+
+ }
+
+ fts_input_report_key(info, value);
+
+ gesture_done:
+ /* Done with gesture event, clear bit. */
+ __clear_bit(touchId, &info->touch_id);
+ }
+
+ return fts_next_event(event);
+}
+#endif
+
+/* EventId : 0x05 */
+#define fts_motion_pointer_event_handler fts_enter_pointer_event_handler
+
+/*
+ * This handler is called each time there is at least
+ * one new event in the FIFO
+ */
+static void fts_event_handler(struct work_struct *work)
+{
+ struct fts_ts_info *info;
+ int error, error1;
+ int left_events;
+ unsigned char regAdd;
+ unsigned char data[FIFO_EVENT_SIZE * (FIFO_DEPTH)] = {0};
+ unsigned char *event = NULL;
+ unsigned char eventId;
+ event_dispatch_handler_t event_handler;
+
+ info = container_of(work, struct fts_ts_info, work);
+ /*
+ * to avoid reading all FIFO, we read the first event and
+ * then check how many events left in the FIFO
+ */
+
+
+ regAdd = FIFO_CMD_READONE;
+ error = fts_readCmd(&regAdd,
+ sizeof (regAdd), data, FIFO_EVENT_SIZE);
+
+ if (!error) {
+
+ left_events = data[7] & 0x1F;
+ if ((left_events > 0) && (left_events < FIFO_DEPTH)) {
+ /*
+ * Read remaining events.
+ */
+ regAdd = FIFO_CMD_READALL;
+
+ error1 = fts_readCmd(&regAdd, sizeof (regAdd),
+ &data[FIFO_EVENT_SIZE],
+ left_events * FIFO_EVENT_SIZE);
+ /*
+ * Got an error reading remaining events,
+ * process at least * the first one that was
+ * reading fine.
+ */
+ if (error1)
+ data[7] &= 0xE0;
+ }
+
+ /* At least one event is available */
+ event = data;
+ do {
+ eventId = *event;
+ event_handler = info->event_dispatch_table[eventId];
+
+ if (eventId < EVENTID_LAST) {
+ event = event_handler(info, (event));
+ } else {
+ event = fts_next_event(event);
+ }
+ input_sync(info->input_dev);
+ } while (event);
+ }
+
+ /*
+ * re-enable interrupts
+ */
+ fts_interrupt_enable(info);
+}
+
+static int cx_crc_check(void)
+{
+ unsigned char regAdd1[3] = {FTS_CMD_HW_REG_R, ADDR_CRC_BYTE0, ADDR_CRC_BYTE1};
+ unsigned char val;
+ unsigned char crc_status;
+ unsigned int error;
+
+ error = fts_readCmd(regAdd1, sizeof (regAdd1), &val, 1);
+ if (error < OK) {
+ logError(1, "%s %s Cannot read crc status ERROR %08X\n", tag, __func__, error);
+ return error;
+ }
+
+ crc_status = val & CRC_MASK;
+ if (crc_status != OK) { /* CRC error if crc_status!= 0 */
+ logError(1, "%s %s CRC ERROR = %X\n", tag, __func__, crc_status);
+ }
+
+ return crc_status; /* return OK if no CRC error, or a number >OK if crc error */
+}
+
+static void fts_fw_update_auto(struct work_struct *work)
+{
+ int retval = 0;
+ int retval1 = 0;
+ int ret;
+ struct fts_ts_info *info;
+ struct delayed_work *fwu_work = container_of(work, struct delayed_work, work);
+ int crc_status = 0;
+ int error = 0;
+ info = container_of(fwu_work, struct fts_ts_info, fwu_work);
+
+ logError(1, "%s Fw Auto Update is starting...\n", tag);
+
+ /* check CRC status */
+ ret = cx_crc_check();
+ if (ret > OK && ftsInfo.u16_fwVer == 0x0000) {
+ logError(1, "%s %s: CRC Error or NO FW!\n", tag, __func__);
+ crc_status = 1;
+ } else {
+ crc_status = 0;
+ logError(1, "%s %s: NO CRC Error or Impossible to read CRC register!\n", tag, __func__);
+ }
+#ifdef FTM3_CHIP
+ retval = flashProcedure(PATH_FILE_FW, crc_status, !crc_status);
+#else
+ retval = flashProcedure(PATH_FILE_FW, crc_status, 1);
+#endif
+ if ((retval & 0xFF000000) == ERROR_FLASH_PROCEDURE) {
+ logError(1, "%s %s: firmware update failed and retry! ERROR %08X\n", tag, __func__, retval);
+ fts_chip_powercycle(info); /* power reset */
+#ifdef FTM3_CHIP
+ retval1 = flashProcedure(PATH_FILE_FW, crc_status, !crc_status);
+#else
+ retval1 = flashProcedure(PATH_FILE_FW, crc_status, 1);
+#endif
+ if ((retval1 & 0xFF000000) == ERROR_FLASH_PROCEDURE) {
+ logError(1, "%s %s: firmware update failed again! ERROR %08X\n", tag, __func__, retval1);
+ logError(1, "%s Fw Auto Update Failed!\n", tag);
+ /* return; */
+ }
+ }
+
+ if ((ftsInfo.u32_mpPassFlag != INIT_MP) && (ftsInfo.u32_mpPassFlag != INIT_FIELD))
+ ret = ERROR_GET_INIT_STATUS;
+ else
+ ret = OK;
+
+ if (ret == ERROR_GET_INIT_STATUS) { /* initialization status not correct or after FW complete update, do initialization. */
+ error = fts_chip_initialization(info);
+ if (error < OK) {
+ logError(1, "%s %s Cannot initialize the chip ERROR %08X\n", tag, __func__, error);
+ }
+ }
+ error = fts_init_hw(info);
+ if (error < OK) {
+ logError(1, "%s Cannot initialize the hardware device ERROR %08X\n", tag, error);
+ }
+
+ logError(1, "%s Fw Auto Update Finished!\n", tag);
+}
+
+static int fts_chip_initialization(struct fts_ts_info *info)
+{
+ int ret2 = 0;
+ int retry;
+ int initretrycnt = 0;
+
+ /* initialization error, retry initialization */
+ for (retry = 0; retry <= INIT_FLAG_CNT; retry++) {
+ ret2 = production_test_initialization();
+ if (ret2 == OK) {
+ ret2 = save_mp_flag(INIT_FIELD);
+ if (ret2 == OK)
+ break;
+ }
+ initretrycnt++;
+ logError(1, "%s initialization cycle count = %04d - ERROR %08X\n", tag, initretrycnt, ret2);
+ fts_chip_powercycle(info);
+ }
+ if (ret2 < OK) { /* initialization error */
+ logError(1, "%s fts initialization failed 3 times\n", tag);
+ }
+
+ return ret2;
+}
+
+#ifdef FTS_USE_POLLING_MODE
+
+static enum hrtimer_restart fts_timer_func(struct hrtimer *timer)
+{
+ struct fts_ts_info *info =
+ container_of(timer, struct fts_ts_info, timer);
+
+ queue_work(info->event_wq, &info->work);
+ return HRTIMER_NORESTART;
+}
+#else
+
+static irqreturn_t fts_interrupt_handler(int irq, void *handle)
+{
+ struct fts_ts_info *info = handle;
+ disable_irq_nosync(info->client->irq);
+ queue_work(info->event_wq, &info->work);
+ return IRQ_HANDLED;
+}
+#endif
+
+static int fts_interrupt_install(struct fts_ts_info *info)
+{
+ int i, error = 0;
+
+ info->event_dispatch_table = kzalloc(
+ sizeof (event_dispatch_handler_t) * EVENTID_LAST, GFP_KERNEL);
+
+ if (!info->event_dispatch_table) {
+ logError(1, "%s OOM allocating event dispatch table\n", tag);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < EVENTID_LAST; i++)
+ info->event_dispatch_table[i] = fts_nop_event_handler;
+
+ install_handler(info, ENTER_POINTER, enter_pointer);
+ install_handler(info, LEAVE_POINTER, leave_pointer);
+ install_handler(info, MOTION_POINTER, motion_pointer);
+ install_handler(info, ERROR_EVENT, error);
+ install_handler(info, CONTROL_READY, controller_ready);
+ install_handler(info, STATUS_UPDATE, status);
+#ifdef PHONE_GESTURE
+ install_handler(info, GESTURE, gesture);
+#endif
+#ifdef PHONE_KEY
+ install_handler(info, KEY_STATUS, key_status);
+#endif
+
+ /* disable interrupts in any case */
+ error = fts_disableInterrupt();
+
+#ifdef FTS_USE_POLLING_MODE
+ logError(1, "%s Polling Mode\n");
+ hrtimer_init(&info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ info->timer.function = fts_timer_func;
+ hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+#else
+ logError(1, "%s Interrupt Mode\n", tag);
+ if (request_irq(info->client->irq, fts_interrupt_handler,
+ IRQF_TRIGGER_LOW, info->client->name,
+ info)) {
+ logError(1, "%s Request irq failed\n", tag);
+ kfree(info->event_dispatch_table);
+ error = -EBUSY;
+ } /*else {
+ error = fts_enableInterrupt();
+ }*/
+#endif
+
+ return error;
+}
+
+static void fts_interrupt_uninstall(struct fts_ts_info *info)
+{
+
+ fts_disableInterrupt();
+
+ kfree(info->event_dispatch_table);
+#ifdef FTS_USE_POLLING_MODE
+ hrtimer_cancel(&info->timer);
+#else
+ free_irq(info->client->irq, info);
+#endif
+}
+
+static void fts_interrupt_enable(struct fts_ts_info *info)
+{
+#ifdef FTS_USE_POLLING_MODE
+ hrtimer_start(&info->timer,
+ ktime_set(0, 10000000), HRTIMER_MODE_REL);
+#else
+ enable_irq(info->client->irq);
+#endif
+}
+
+/*
+static void fts_interrupt_disable(struct fts_ts_info *info)
+{
+#ifdef FTS_USE_POLLING_MODE
+ hrtimer_cancel(&info->timer);
+#else
+ disable_irq(info->client->irq);
+#endif
+}
+*/
+
+static int fts_init(struct fts_ts_info *info)
+{
+ int error;
+
+ error = fts_system_reset();
+ if (error < OK && error != (ERROR_TIMEOUT | ERROR_SYSTEM_RESET_FAIL)) {
+ logError(1, "%s Cannot reset the device! ERROR %08X\n", tag, error);
+ return error;
+ }
+ if (error == (ERROR_TIMEOUT | ERROR_SYSTEM_RESET_FAIL)) {
+ logError(1, "%s Setting default Chip INFO!\n", tag);
+ defaultChipInfo(0);
+ } else {
+ error = readChipInfo(0); /* system reset OK */
+ if (error < OK) {
+ logError(1, "%s Cannot read Chip Info! ERROR %08X\n", tag, error);
+ }
+ }
+
+ error = fts_interrupt_install(info);
+
+ if (error != OK)
+ logError(1, "%s Init (1) error (ERROR = %08X)\n", error);
+
+ return error;
+}
+
+int fts_chip_powercycle(struct fts_ts_info *info)
+{
+ int error, i;
+
+ logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__);
+ if (info->pwr_reg) {
+ error = regulator_disable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable DVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_disable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED)
+ gpio_set_value(info->bdata->reset_gpio, 0);
+
+ msleep(300);
+ if (info->pwr_reg) {
+ error = regulator_enable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_enable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable DVDD regulator\n", tag, __func__);
+ }
+ }
+ msleep(300); /* time needed by the regulators for reaching the regime values */
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) {
+ msleep(10); /* time to wait before bring up the reset gpio after the power up of the regulators */
+ gpio_set_value(info->bdata->reset_gpio, 1);
+ /* msleep(300); */
+ }
+
+ /* before reset clear all slot */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", tag, __func__, error);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ return error;
+}
+
+int fts_chip_powercycle2(struct fts_ts_info *info, unsigned long sleep)
+{
+ int error, i;
+
+ logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__);
+ if (info->pwr_reg) {
+ error = regulator_disable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable DVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_disable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED)
+ gpio_set_value(info->bdata->reset_gpio, 0);
+
+ msleep(sleep);
+ if (info->pwr_reg) {
+ error = regulator_enable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_enable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable DVDD regulator\n", tag, __func__);
+ }
+ }
+ msleep(500); /*time needed by the regulators for reaching the regime values */
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) {
+ msleep(10); /*time to wait before bring up the reset gpio after the power up of the regulators */
+ gpio_set_value(info->bdata->reset_gpio, 1);
+ /* msleep(300); */
+ }
+
+ /* before reset clear all slot */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", tag, __func__, error);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ return error;
+}
+
+static int fts_init_hw(struct fts_ts_info *info)
+{
+ int error = 0;
+
+ error = cleanUp(1);
+ if (error < OK)
+ logError(1, "%s Init (2) error (ERROR = %08X)\n", tag, error);
+
+ info->mode = MODE_NORMAL;
+
+ return error;
+}
+
+ /*
+ * TODO: change this function according with the needs of
+ *customer in temrs of feature to enable/disable
+ */
+static int fts_mode_handler(struct fts_ts_info *info, int force)
+{
+ int res = OK;
+ int ret = OK;
+
+ logError(0, "%s %s: Mode Handler starting...\n", tag, __func__);
+ switch (info->resume_bit) {
+ case 0:/* screen down */
+ logError(0, "%s %s: Screen OFF...\n", tag, __func__);
+#ifdef PHONE_GESTURE
+ if (info->gesture_enabled == 1) {
+ logError(0, "%s %s: enter in gesture mode !\n", tag, __func__);
+ res = enterGestureMode(isSystemResettedDown());
+ if (res >= OK) {
+
+ info->mode = MODE_GESTURE;
+ /* return OK; */
+ } else {
+ logError(1, "%s %s: enterGestureMode failed! ERROR %08X recovery in senseOff...\n", tag, __func__, res);
+ }
+ }
+#endif
+ if (info->mode != MODE_GESTURE || info->gesture_enabled == 0) {
+ logError(0, "%s %s: Sense OFF!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_MT_SENSE_OFF); /* we need to use fts_command for speed reason (no need to check echo in this case and interrupt can be enabled) */
+#ifdef PHONE_KEY
+ logError(0, "%s %s: Key OFF!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_KEY_OFF);
+#endif
+
+ info->mode = MODE_SENSEOFF;
+
+ }
+ setSystemResettedDown(0);
+ break;
+
+ case 1: /* screen up */
+ logError(0, "%s %s: Screen ON...\n", tag, __func__);
+ logError(0, "%s %s: Sense ON!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_MT_SENSE_ON);
+#ifdef PHONE_KEY
+ logError(0, "%s %s: Key ON!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_KEY_ON);
+#endif
+ info->mode = MODE_NORMAL;
+
+ if (info->glove_enabled == FEAT_ENABLE || force == 1) {
+ if (isSystemResettedUp() || force == 1) {
+ logError(0, "%s %s: Glove Mode setting...\n", tag, __func__);
+ ret = featureEnableDisable(info->glove_enabled, FEAT_GLOVE);
+ if (ret < OK) {
+ logError(1, "%s %s: error during setting GLOVE_MODE! ERROR %08X\n", tag, __func__, ret);
+ }
+ res |= ret;
+ }
+ if (ret >= OK && info->glove_enabled == FEAT_ENABLE) {
+ info->mode = MODE_GLOVE;
+ logError(1, "%s %s: GLOVE_MODE Enabled!\n", tag, __func__);
+ } else{
+ logError(1, "%s %s: GLOVE_MODE Disabled!\n", tag, __func__);
+ }
+ }
+
+ setSystemResettedUp(0);
+ break;
+
+ default:
+ logError(1, "%s %s: invalid resume_bit value = %d! ERROR %08X\n", tag, __func__, info->resume_bit, ERROR_OP_NOT_ALLOW);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ logError(0, "%s %s: Mode Handler finished! res = %08X\n", tag, __func__, res);
+ return res;
+
+}
+
+static int fts_fb_state_chg_callback(struct notifier_block *nb, unsigned long val, void *data)
+{
+ struct fts_ts_info *info = container_of(nb, struct fts_ts_info, notifier);
+ struct fb_event *evdata = data;
+ int i;
+ unsigned int blank;
+
+ if (val != FB_EVENT_BLANK)
+ return 0;
+
+ logError(0, "%s %s: fts notifier begin!\n", tag, __func__);
+
+ if (evdata && evdata->data && val == FB_EVENT_BLANK && info) {
+
+ blank = *(int *) (evdata->data);
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ if (info->sensor_sleep)
+ break;
+
+ logError(0, "%s %s: FB_BLANK_POWERDOWN\n", tag, __func__);
+
+ /* Release all slots */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ info->resume_bit = 0;
+
+ fts_mode_handler(info, 0);
+
+ info->sensor_sleep = true;
+
+ fts_disableInterrupt();
+
+ break;
+
+ case FB_BLANK_UNBLANK:
+ if (!info->sensor_sleep)
+ break;
+
+ logError(0, "%s %s: FB_BLANK_UNBLANK\n", tag, __func__);
+
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ info->resume_bit = 1;
+
+ fts_system_reset();
+
+ fts_mode_handler(info, 0);
+
+ info->sensor_sleep = false;
+
+ fts_enableInterrupt();
+ break;
+ default:
+ break;
+
+ }
+ }
+ return NOTIFY_OK;
+
+}
+
+static struct notifier_block fts_noti_block = {
+ .notifier_call = fts_fb_state_chg_callback,
+};
+
+static int fts_get_reg(struct fts_ts_info *rmi4_data,
+ bool get) {
+ int retval;
+ const struct fts_i2c_platform_data *bdata =
+ rmi4_data->bdata;
+
+ if (!get) {
+ retval = 0;
+ goto regulator_put;
+ }
+
+ if ((bdata->pwr_reg_name != NULL) && (*bdata->pwr_reg_name != 0)) {
+ rmi4_data->pwr_reg = regulator_get(rmi4_data->dev,
+ bdata->pwr_reg_name);
+ if (IS_ERR(rmi4_data->pwr_reg)) {
+ logError(1, "%s %s: Failed to get power regulator\n", tag,
+ __func__);
+ retval = PTR_ERR(rmi4_data->pwr_reg);
+ goto regulator_put;
+ }
+ }
+
+ if ((bdata->bus_reg_name != NULL) && (*bdata->bus_reg_name != 0)) {
+ rmi4_data->bus_reg = regulator_get(rmi4_data->dev,
+ bdata->bus_reg_name);
+ if (IS_ERR(rmi4_data->bus_reg)) {
+ logError(1, "%s %s: Failed to get bus pullup regulator\n", tag,
+ __func__);
+ retval = PTR_ERR(rmi4_data->bus_reg);
+ goto regulator_put;
+ }
+ }
+
+ return 0;
+
+regulator_put:
+ if (rmi4_data->pwr_reg) {
+ regulator_put(rmi4_data->pwr_reg);
+ rmi4_data->pwr_reg = NULL;
+ }
+
+ if (rmi4_data->bus_reg) {
+ regulator_put(rmi4_data->bus_reg);
+ rmi4_data->bus_reg = NULL;
+ }
+
+ return retval;
+}
+
+static int fts_enable_reg(struct fts_ts_info *rmi4_data,
+ bool enable) {
+ int retval;
+
+ if (!enable) {
+ retval = 0;
+ goto disable_pwr_reg;
+ }
+
+ if (rmi4_data->bus_reg) {
+ retval = regulator_enable(rmi4_data->bus_reg);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to enable bus regulator\n", tag,
+ __func__);
+ goto exit;
+ }
+ }
+
+ if (rmi4_data->pwr_reg) {
+ retval = regulator_enable(rmi4_data->pwr_reg);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to enable power regulator\n", tag,
+ __func__);
+ goto disable_bus_reg;
+ }
+ }
+
+ return OK;
+
+disable_pwr_reg:
+ if (rmi4_data->pwr_reg)
+ regulator_disable(rmi4_data->pwr_reg);
+
+disable_bus_reg:
+ if (rmi4_data->bus_reg)
+ regulator_disable(rmi4_data->bus_reg);
+
+exit:
+ return retval;
+}
+
+static int fts_gpio_setup(int gpio, bool config, int dir, int state)
+{
+ int retval = 0;
+ unsigned char buf[16];
+
+ if (config) {
+ snprintf(buf, 16, "fts_gpio_%u\n", gpio);
+
+ retval = gpio_request(gpio, buf);
+ if (retval) {
+ logError(1, "%s %s: Failed to get gpio %d (code: %d)", tag,
+ __func__, gpio, retval);
+ return retval;
+ }
+
+ if (dir == 0)
+ retval = gpio_direction_input(gpio);
+ else
+ retval = gpio_direction_output(gpio, state);
+ if (retval) {
+ logError(1, "%s %s: Failed to set gpio %d direction", tag,
+ __func__, gpio);
+ return retval;
+ }
+ } else {
+ gpio_free(gpio);
+ }
+
+ return retval;
+}
+
+static int fts_set_gpio(struct fts_ts_info *rmi4_data)
+{
+ int retval;
+ const struct fts_i2c_platform_data *bdata =
+ rmi4_data->bdata;
+
+ retval = fts_gpio_setup(bdata->irq_gpio, true, 0, 0);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to configure irq GPIO\n", tag, __func__);
+ goto err_gpio_irq;
+ }
+
+ if (bdata->reset_gpio >= 0) {
+ retval = fts_gpio_setup(bdata->reset_gpio, true, 1, 0);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to configure reset GPIO\n", tag, __func__);
+ goto err_gpio_reset;
+ }
+ }
+ if (bdata->reset_gpio >= 0) {
+ gpio_set_value(bdata->reset_gpio, 0);
+ msleep(10);
+ gpio_set_value(bdata->reset_gpio, 1);
+ }
+
+ setResetGpio(bdata->reset_gpio);
+ return OK;
+
+err_gpio_reset:
+ fts_gpio_setup(bdata->irq_gpio, false, 0, 0);
+ setResetGpio(GPIO_NOT_DEFINED);
+err_gpio_irq:
+ return retval;
+}
+
+static int parse_dt(struct device *dev, struct fts_i2c_platform_data *bdata)
+{
+ int retval;
+ const char *name;
+ struct device_node *np = dev->of_node;
+
+ bdata->irq_gpio = of_get_named_gpio_flags(np,
+ "st,irq-gpio", 0, NULL);
+
+ logError(0, "%s irq_gpio = %d\n", tag, bdata->irq_gpio);
+
+ retval = of_property_read_string(np, "st,regulator_dvdd", &name);
+ if (retval == -EINVAL)
+ bdata->pwr_reg_name = NULL;
+ else if (retval < 0)
+ return retval;
+ bdata->pwr_reg_name = name;
+ logError(0, "%s pwr_reg_name = %s\n", tag, name);
+
+ retval = of_property_read_string(np, "st,regulator_avdd", &name);
+ if (retval == -EINVAL)
+ bdata->bus_reg_name = NULL;
+ else if (retval < 0)
+ return retval;
+ bdata->bus_reg_name = name;
+ logError(0, "%s bus_reg_name = %s\n", tag, name);
+
+ if (of_property_read_bool(np, "st, reset-gpio")) {
+ bdata->reset_gpio = of_get_named_gpio_flags(np,
+ "st, reset-gpio", 0, NULL);
+ logError(0, "%s reset_gpio =%d\n", tag, bdata->reset_gpio);
+ } else {
+ bdata->reset_gpio = GPIO_NOT_DEFINED;
+ }
+
+ return OK;
+}
+
+static int fts_probe(struct i2c_client *client,
+ const struct i2c_device_id *idp) {
+ struct fts_ts_info *info = NULL;
+ char fts_ts_phys[64];
+ int error = 0;
+ struct device_node *dp = client->dev.of_node;
+ int retval;
+
+ logError(1, "%s %s: driver probe begin!\n", tag, __func__);
+
+ logError(1, "%s SET I2C Functionality and Dev INFO:\n", tag);
+ openChannel(client);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ logError(1, "%s Unsupported I2C functionality\n", tag);
+ error = -EIO;
+ goto ProbeErrorExit_0;
+ }
+
+ info = kzalloc(sizeof (struct fts_ts_info), GFP_KERNEL);
+ if (!info) {
+ logError(1, "%s Out of memory... Impossible to allocate struct info!\n", tag);
+ error = -ENOMEM;
+ goto ProbeErrorExit_0;
+ }
+
+ info->client = client;
+
+ i2c_set_clientdata(client, info);
+ logError(1, "%s i2c address: %x\n", tag, client->addr);
+ info->dev = &info->client->dev;
+ if (dp) {
+ info->bdata = devm_kzalloc(&client->dev, sizeof (struct fts_i2c_platform_data), GFP_KERNEL);
+ if (!info->bdata) {
+ logError(1, "%s ERROR:info.bdata kzalloc failed\n", tag);
+ goto ProbeErrorExit_1;
+ }
+ parse_dt(&client->dev, info->bdata);
+ }
+
+ logError(1, "%s SET Regulators:\n", tag);
+ retval = fts_get_reg(info, true);
+ if (retval < 0) {
+ logError(1, "%s ERROR: %s: Failed to get regulators\n", tag, __func__);
+ goto ProbeErrorExit_1;
+ }
+
+ retval = fts_enable_reg(info, true);
+ if (retval < 0) {
+ logError(1, "%s %s: ERROR Failed to enable regulators\n", tag, __func__);
+ goto ProbeErrorExit_2;
+ }
+
+ logError(1, "%s SET GPIOS:\n", tag);
+ retval = fts_set_gpio(info);
+ if (retval < 0) {
+ logError(1, "%s %s: ERROR Failed to set up GPIO's\n", tag, __func__);
+ goto ProbeErrorExit_2;
+ }
+ info->client->irq = gpio_to_irq(info->bdata->irq_gpio);
+
+ logError(1, "%s SET Auto Fw Update:\n", tag);
+ info->fwu_workqueue = create_singlethread_workqueue("fts-fwu-queue");
+ if (!info->fwu_workqueue) {
+ logError(1, "%s ERROR: Cannot create fwu work thread\n", tag);
+ goto ProbeErrorExit_3;
+ }
+ INIT_DELAYED_WORK(&info->fwu_work, fts_fw_update_auto);
+
+ logError(1, "%s SET Event Handler:\n", tag);
+ info->event_wq = create_singlethread_workqueue("fts-event-queue");
+ if (!info->event_wq) {
+ logError(1, "%s ERROR: Cannot create work thread\n", tag);
+ error = -ENOMEM;
+ goto ProbeErrorExit_4;
+ }
+
+ INIT_WORK(&info->work, fts_event_handler);
+
+ logError(1, "%s SET Input Device Property:\n", tag);
+ info->dev = &info->client->dev;
+ info->input_dev = input_allocate_device();
+ if (!info->input_dev) {
+ logError(1, "%s ERROR: No such input device defined!\n", tag);
+ error = -ENODEV;
+ goto ProbeErrorExit_5;
+ }
+ info->input_dev->dev.parent = &client->dev;
+ info->input_dev->name = FTS_TS_DRV_NAME;
+ snprintf(fts_ts_phys, sizeof (fts_ts_phys), "%s/input0",
+ info->input_dev->name);
+ info->input_dev->phys = fts_ts_phys;
+ info->input_dev->id.bustype = BUS_I2C;
+ info->input_dev->id.vendor = 0x0001;
+ info->input_dev->id.product = 0x0002;
+ info->input_dev->id.version = 0x0100;
+
+ __set_bit(EV_SYN, info->input_dev->evbit);
+ __set_bit(EV_KEY, info->input_dev->evbit);
+ __set_bit(EV_ABS, info->input_dev->evbit);
+ __set_bit(BTN_TOUCH, info->input_dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, info->input_dev->keybit);
+
+ input_mt_init_slots(info->input_dev, TOUCH_ID_MAX, INPUT_MT_DIRECT);
+
+ /* input_mt_init_slots(info->input_dev, TOUCH_ID_MAX); */
+
+ /* input_set_abs_params(info->input_dev, ABS_MT_TRACKING_ID, 0, FINGER_MAX, 0, 0); */
+ input_set_abs_params(info->input_dev, ABS_MT_POSITION_X,
+ X_AXIS_MIN, X_AXIS_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y,
+ Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR,
+ AREA_MIN, AREA_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR,
+ AREA_MIN, AREA_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_PRESSURE,
+ PRESSURE_MIN, PRESSURE_MAX, 0, 0);
+
+#ifdef PHONE_GESTURE
+ input_set_capability(info->input_dev, EV_KEY, KEY_WAKEUP);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_M);
+ input_set_capability(info->input_dev, EV_KEY, KEY_O);
+ input_set_capability(info->input_dev, EV_KEY, KEY_E);
+ input_set_capability(info->input_dev, EV_KEY, KEY_W);
+ input_set_capability(info->input_dev, EV_KEY, KEY_C);
+ input_set_capability(info->input_dev, EV_KEY, KEY_L);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F);
+ input_set_capability(info->input_dev, EV_KEY, KEY_V);
+ input_set_capability(info->input_dev, EV_KEY, KEY_S);
+ input_set_capability(info->input_dev, EV_KEY, KEY_Z);
+ input_set_capability(info->input_dev, EV_KEY, KEY_WWW);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_LEFT);
+ input_set_capability(info->input_dev, EV_KEY, KEY_RIGHT);
+ input_set_capability(info->input_dev, EV_KEY, KEY_UP);
+ input_set_capability(info->input_dev, EV_KEY, KEY_DOWN);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_F1);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F2);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F3);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F4);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F5);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_LEFTBRACE);
+ input_set_capability(info->input_dev, EV_KEY, KEY_RIGHTBRACE);
+#endif
+
+#ifdef PHONE_KEY
+ /* KEY associated to the touch screen buttons */
+ input_set_capability(info->input_dev, EV_KEY, KEY_HOMEPAGE);
+ input_set_capability(info->input_dev, EV_KEY, KEY_BACK);
+ input_set_capability(info->input_dev, EV_KEY, KEY_MENU);
+#endif
+
+ mutex_init(&(info->input_report_mutex));
+
+ /* register the multi-touch input device */
+ error = input_register_device(info->input_dev);
+ if (error) {
+ logError(1, "%s ERROR: No such input device\n", tag);
+ error = -ENODEV;
+ goto ProbeErrorExit_5_1;
+ }
+
+ /* track slots */
+ info->touch_id = 0;
+
+ /* init hardware device */
+ logError(1, "%s Device Initialization:\n", tag);
+ error = fts_init(info);
+ if (error < OK) {
+ logError(1, "%s Cannot initialize the device ERROR %08X\n", tag, error);
+ error = -ENODEV;
+ goto ProbeErrorExit_6;
+ }
+
+ info->gesture_enabled = 0;
+ info->glove_enabled = 0;
+ info->resume_bit = 1;
+ info->notifier = fts_noti_block;
+ error = fb_register_client(&info->notifier);
+ if (error) {
+ logError(1, "%s ERROR: register notifier failed!\n", tag);
+ goto ProbeErrorExit_6;
+ }
+
+ logError(1, "%s SET Device File Nodes:\n", tag);
+ /* sysfs stuff */
+ info->attrs.attrs = fts_attr_group;
+ error = sysfs_create_group(&client->dev.kobj, &info->attrs);
+ if (error) {
+ logError(1, "%s ERROR: Cannot create sysfs structure!\n", tag);
+ error = -ENODEV;
+ goto ProbeErrorExit_7;
+ }
+
+#ifdef SCRIPTLESS
+ /*I2C cmd*/
+ if (fts_cmd_class == NULL)
+ fts_cmd_class = class_create(THIS_MODULE, FTS_TS_DRV_NAME);
+ info->i2c_cmd_dev = device_create(fts_cmd_class,
+ NULL, DCHIP_ID_0, info, "fts_i2c");
+ if (IS_ERR(info->i2c_cmd_dev)) {
+ logError(1, "%s ERROR: Failed to create device for the sysfs!\n", tag);
+ goto ProbeErrorExit_8;
+ }
+
+ dev_set_drvdata(info->i2c_cmd_dev, info);
+
+ error = sysfs_create_group(&info->i2c_cmd_dev->kobj,
+ &i2c_cmd_attr_group);
+ if (error) {
+ logError(1, "%s ERROR: Failed to create sysfs group!\n", tag);
+ goto ProbeErrorExit_9;
+ }
+
+#endif
+
+#ifdef DRIVER_TEST
+ if (fts_cmd_class == NULL)
+ fts_cmd_class = class_create(THIS_MODULE, FTS_TS_DRV_NAME);
+ info->test_cmd_dev = device_create(fts_cmd_class,
+ NULL, DCHIP_ID_0, info, "fts_driver_test");
+ if (IS_ERR(info->test_cmd_dev)) {
+ logError(1, "%s ERROR: Failed to create device for the sysfs!\n", tag);
+ goto ProbeErrorExit_10;
+ }
+
+ dev_set_drvdata(info->test_cmd_dev, info);
+
+ error = sysfs_create_group(&info->test_cmd_dev->kobj,
+ &test_cmd_attr_group);
+ if (error) {
+ logError(1, "%s ERROR: Failed to create sysfs group!\n", tag);
+ goto ProbeErrorExit_11;
+ }
+
+#endif
+ queue_delayed_work(info->fwu_workqueue, &info->fwu_work, msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
+ logError(1, "%s Probe Finished!\n", tag);
+ return OK;
+
+ /* error exit path */
+#ifdef DRIVER_TEST
+ProbeErrorExit_11:
+#ifndef SCRIPTLESS
+ device_destroy(fts_cmd_class, DCHIP_ID_0);
+#endif
+
+ProbeErrorExit_10:
+#ifndef SCRIPTLESS
+ sysfs_remove_group(&client->dev.kobj, &info->attrs);
+#endif
+#endif
+
+#ifdef SCRIPTLESS
+ProbeErrorExit_9:
+ device_destroy(fts_cmd_class, DCHIP_ID_0);
+
+ProbeErrorExit_8:
+ sysfs_remove_group(&client->dev.kobj, &info->attrs);
+#endif
+
+ProbeErrorExit_7:
+ fb_unregister_client(&info->notifier);
+
+ProbeErrorExit_6:
+ input_unregister_device(info->input_dev);
+
+ProbeErrorExit_5_1:
+ /* intput_free_device(info->input_dev ); */
+
+ ProbeErrorExit_5:
+ destroy_workqueue(info->event_wq);
+
+ProbeErrorExit_4:
+ destroy_workqueue(info->fwu_workqueue);
+
+ProbeErrorExit_3:
+ fts_enable_reg(info, false);
+
+ProbeErrorExit_2:
+ fts_get_reg(info, false);
+
+ProbeErrorExit_1:
+ kfree(info);
+
+ProbeErrorExit_0:
+ logError(1, "%s Probe Failed!\n", tag);
+
+ return error;
+}
+
+static int fts_remove(struct i2c_client *client)
+{
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+#ifdef DRIVER_TEST
+ sysfs_remove_group(&info->test_cmd_dev->kobj,
+ &test_cmd_attr_group);
+#endif
+
+#ifdef SCRIPTLESS
+ /*I2C cmd*/
+ sysfs_remove_group(&info->i2c_cmd_dev->kobj,
+ &i2c_cmd_attr_group);
+
+#endif
+
+#if defined(SCRIPTLESS) || defined(DRIVER_TEST)
+ device_destroy(fts_cmd_class, DCHIP_ID_0);
+#endif
+
+ /* sysfs stuff */
+ sysfs_remove_group(&client->dev.kobj, &info->attrs);
+
+ /* remove interrupt and event handlers */
+ fts_interrupt_uninstall(info);
+
+ fb_unregister_client(&info->notifier);
+
+ /* unregister the device */
+ input_unregister_device(info->input_dev);
+
+ /* intput_free_device(info->input_dev ); */
+
+ /* Empty the FIFO buffer */
+ fts_command(info, FIFO_CMD_FLUSH);
+ /* flushFIFO(); */
+
+ /* Remove the work thread */
+ destroy_workqueue(info->event_wq);
+ destroy_workqueue(info->fwu_workqueue);
+
+ fts_enable_reg(info, false);
+ fts_get_reg(info, false);
+
+ /* free all */
+ kfree(info);
+
+ return OK;
+}
+
+static struct of_device_id fts_of_match_table[] = {
+ {
+ .compatible = "st,fts",
+ },
+ {},
+};
+static const struct i2c_device_id fts_device_id[] = {
+ {FTS_TS_DRV_NAME, 0},
+ {}
+};
+
+static struct i2c_driver fts_i2c_driver = {
+ .driver = {
+ .name = FTS_TS_DRV_NAME,
+ .of_match_table = fts_of_match_table,
+ },
+ .probe = fts_probe,
+ .remove = fts_remove,
+ .id_table = fts_device_id,
+};
+
+static int __init fts_driver_init(void)
+{
+ return i2c_add_driver(&fts_i2c_driver);
+}
+
+static void __exit fts_driver_exit(void)
+{
+ i2c_del_driver(&fts_i2c_driver);
+}
+
+MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver");
+MODULE_AUTHOR("STMicroelectronics, Inc.");
+MODULE_LICENSE("GPL");
+
+late_initcall(fts_driver_init);
+module_exit(fts_driver_exit);
diff --git a/drivers/input/touchscreen/st/fts.h b/drivers/input/touchscreen/st/fts.h
new file mode 100644
index 000000000000..7d72d226349f
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts.h
@@ -0,0 +1,249 @@
+/*
+ * fts.c
+ *
+ * FTS Capacitive touch screen controller (FingerTipS)
+ *
+ * Copyright (C) 2016, STMicroelectronics Limited.
+ * Authors: AMG(Analog Mems Group)
+ *
+ * marco.cali@st.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _LINUX_FTS_I2C_H_
+#define _LINUX_FTS_I2C_H_
+
+#include "fts_lib/ftsSoftware.h"
+#include "fts_lib/ftsHardware.h"
+
+#define FTS_POWER_ON 1
+#define FTS_POWER_OFF 0
+
+/****************** CONFIGURATION SECTION ******************/
+/* #define PHONE_KEY */
+
+/* #define PHONE_GESTURE */
+
+#define SCRIPTLESS
+#ifdef SCRIPTLESS
+#define SCRIPTLESS_DEBUG
+/* uncomment this macro definition to print debug
+* message for script less support
+*/
+#endif
+
+#define DRIVER_TEST
+
+#define FW_H_FILE
+#ifdef FW_H_FILE
+#define FW_SIZE_NAME myArray_size
+#define FW_ARRAY_NAME myArray
+#endif
+
+#define LIMITS_H_FILE
+#ifdef LIMITS_H_FILE
+#define LIMITS_SIZE_NAME myArray2_size
+#define LIMITS_ARRAY_NAME myArray2
+#endif
+
+#define FTS_TS_DRV_NAME "fts"
+#define FTS_TS_DRV_VERSION "4.1.0"
+
+#define X_AXIS_MAX 1440
+#define X_AXIS_MIN 0
+#define Y_AXIS_MAX 2560
+#define Y_AXIS_MIN 0
+
+#define PRESSURE_MIN 0
+#define PRESSURE_MAX 127
+
+#define FINGER_MAX 10
+#define STYLUS_MAX 1
+#define TOUCH_ID_MAX (FINGER_MAX + STYLUS_MAX)
+
+#define AREA_MIN PRESSURE_MIN
+#define AREA_MAX PRESSURE_MAX
+
+/*********************************************************/
+
+/* Flash programming */
+
+#define INIT_FLAG_CNT 3
+
+/* KEYS */
+#define KEY1 0x02
+#define KEY2 0x01
+#define KEY3 0x04
+
+/*
+ * Configuration mode
+ */
+#define MODE_NORMAL 0
+#define MODE_GESTURE 1
+#define MODE_GLOVE 2
+#define MODE_SENSEOFF 3
+
+/*
+ * Status Event Field:
+ * id of command that triggered the event
+ */
+
+#define FTS_FLASH_WRITE_CONFIG 0x03
+#define FTS_FLASH_WRITE_COMP_MEMORY 0x04
+#define FTS_FORCE_CAL_SELF_MUTUAL 0x05
+#define FTS_FORCE_CAL_SELF 0x06
+#define FTS_WATER_MODE_ON 0x07
+#define FTS_WATER_MODE_OFF 0x08
+
+#define EXP_FN_WORK_DELAY_MS 1000
+
+#define CMD_STR_LEN 32
+
+#ifdef SCRIPTLESS
+/*
+ * I2C Command Read/Write Function
+ */
+
+#define CMD_RESULT_STR_LEN 2048
+#endif
+
+#define TSP_BUF_SIZE 4096
+
+struct fts_i2c_platform_data {
+ int (*power)(bool on);
+ int irq_gpio;
+ int reset_gpio;
+ const char *pwr_reg_name;
+ const char *bus_reg_name;
+
+};
+
+/*
+ * Forward declaration
+ */
+struct fts_ts_info;
+extern char tag[8];
+
+/*
+ * Dispatch event handler
+ */
+typedef unsigned char * (*event_dispatch_handler_t)
+(struct fts_ts_info *info, unsigned char *data);
+
+/*
+ * struct fts_ts_info - FTS capacitive touch screen device information
+ * @dev: Pointer to the structure device
+ * @client: I2C client structure
+ * @input_dev Input device structure
+ * @work Work thread
+ * @event_wq Event queue for work thread
+ * @cmd_done Asyncronous command notification
+ * @event_dispatch_table Event dispatch table handlers
+ * @fw_version Firmware version
+ * @attrs SysFS attributes
+ * @mode Device operating mode
+ * @touch_id Bitmask for touch id (mapped to input slots)
+ * @buttons Bitmask for buttons status
+ * @timer Timer when operating in polling mode
+ * @early_suspend Structure for early suspend functions
+ * @power Power on/off routine
+ */
+
+struct fts_ts_info {
+ struct device *dev;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+
+ struct work_struct work;
+ struct workqueue_struct *event_wq;
+
+ struct delayed_work fwu_work;
+ struct workqueue_struct *fwu_workqueue;
+ struct completion cmd_done;
+
+ event_dispatch_handler_t *event_dispatch_table;
+
+ unsigned int fw_version;
+ unsigned int config_id;
+
+ struct attribute_group attrs;
+
+ unsigned int mode;
+ unsigned long touch_id;
+ unsigned int buttons;
+
+#ifdef FTS_USE_POLLING_MODE
+ struct hrtimer timer;
+#endif
+
+#ifdef SCRIPTLESS
+ /*I2C cmd*/
+ struct device *i2c_cmd_dev;
+ char cmd_read_result[CMD_RESULT_STR_LEN];
+ char cmd_wr_result[CMD_RESULT_STR_LEN];
+ char cmd_write_result[20];
+#endif
+
+#ifdef DRIVER_TEST
+ struct device *test_cmd_dev;
+#endif
+
+ int (*power)(bool on);
+
+ struct fts_i2c_platform_data *bdata;
+ struct regulator *pwr_reg;
+ struct regulator *bus_reg;
+
+ bool fw_force;
+ int debug_enable;
+
+ int resume_bit;
+ int fwupdate_stat;
+ int touch_debug;
+
+ struct notifier_block notifier;
+ bool sensor_sleep;
+ bool stay_awake;
+
+ /* input lock */
+ struct mutex input_report_mutex;
+
+ /* switches */
+ int gesture_enabled;
+ int glove_enabled;
+
+};
+
+typedef enum {
+ ERR_ITO_NO_ERR, /* < 0 No ITO Error */
+ ERR_ITO_PANEL_OPEN_FORCE, /* < 1 Panel Open Force */
+ ERR_ITO_PANEL_OPEN_SENSE, /* < 2 Panel Open Sense */
+ ERR_ITO_F2G, /* < 3 Force short to ground */
+ ERR_ITO_S2G, /* < 4 Sense short to ground */
+ ERR_ITO_F2VDD, /* < 5 Force short to VDD */
+ ERR_ITO_S2VDD, /* < 6 Sense short to VDD */
+ ERR_ITO_P2P_FORCE, /* < 7 Pin to Pin short (Force) */
+ ERR_ITO_P2P_SENSE, /* < 8 Pin to Pin short (Sense) */
+} errItoSubTypes_t;
+
+int fts_chip_powercycle(struct fts_ts_info *info);
+int fts_chip_powercycle2(struct fts_ts_info *info, unsigned long sleep);
+int fts_get_fw_version(struct fts_ts_info *info);
+extern unsigned int le_to_uint(const unsigned char *ptr);
+extern unsigned int be_to_uint(const unsigned char *ptr);
+extern int input_register_notifier_client(struct notifier_block *nb);
+extern int input_unregister_notifier_client(struct notifier_block *nb);
+
+#ifdef SCRIPTLESS
+extern struct attribute_group i2c_cmd_attr_group;
+#endif
+
+#ifdef DRIVER_TEST
+extern struct attribute_group test_cmd_attr_group;
+#endif
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_driver_test.c b/drivers/input/touchscreen/st/fts_driver_test.c
new file mode 100644
index 000000000000..5c55d8e4ac88
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_driver_test.c
@@ -0,0 +1,871 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* API used by Driver Test Apk *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/completion.h>
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include "fts.h"
+#include "fts_lib/ftsCompensation.h"
+#include "fts_lib/ftsIO.h"
+#include "fts_lib/ftsError.h"
+#include "fts_lib/ftsFrame.h"
+#include "fts_lib/ftsFlash.h"
+#include "fts_lib/ftsTest.h"
+#include "fts_lib/ftsTime.h"
+#include "fts_lib/ftsTool.h"
+
+#ifdef DRIVER_TEST
+
+#define MAX_PARAMS 10
+
+/* DEFINE COMMANDS TO TEST */
+#define CMD_READ 0x00
+#define CMD_WRITE 0x01
+#define CMD_READU16 0x02
+#define CMD_READB2 0x03
+#define CMD_READB2U16 0x04
+#define CMD_POLLFOREVENT 0x05
+#define CMD_SYSTEMRESET 0x06
+#define CMD_CLEANUP 0x07
+#define CMD_GETFORCELEN 0x08
+#define CMD_GETSENSELEN 0x09
+#define CMD_GETMSFRAME 0x0A
+/* #define CMD_GETMSKEYFRAME 0x0B */
+#define CMD_GETSSFRAME 0x0C
+#define CMD_REQCOMPDATA 0x0D
+#define CMD_READCOMPDATAHEAD 0x0E
+#define CMD_READMSCOMPDATA 0x0F
+#define CMD_READSSCOMPDATA 0x10
+#define CMD_READGNCOMPDATA 0x11
+#define CMD_GETFWVER 0x12
+#define CMD_FLASHSTATUS 0x13
+#define CMD_FLASHUNLOCK 0x14
+#define CMD_READFWFILE 0x15
+#define CMD_FLASHPROCEDURE 0x16
+#define CMD_ITOTEST 0x17
+#define CMD_INITTEST 0x18
+#define CMD_MSRAWTEST 0x19
+#define CMD_MSINITDATATEST 0x1A
+#define CMD_SSRAWTEST 0x1B
+#define CMD_SSINITDATATEST 0x1C
+#define CMD_MAINTEST 0x1D
+#define CMD_POWERCYCLE 0x1E
+#define CMD_FWWRITE 0x1F
+#define CMD_READCHIPINFO 0x20
+#define CMD_REQFRAME 0x21
+
+u32 *functionToTest;
+int numberParam;
+
+static ssize_t stm_driver_test_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count) {
+ int n;
+ char *p = (char *) buf;
+
+ functionToTest = (u32 *) kmalloc(MAX_PARAMS * sizeof (u32), GFP_KERNEL);
+ if (functionToTest == NULL) {
+ logError(1, "%s impossible to allocate functionToTest!\n", tag);
+ return count;
+ }
+ memset(functionToTest, 0, MAX_PARAMS * sizeof (u32));
+
+ for (n = 0; n < (count + 1) / 3 && n < MAX_PARAMS; n++) {
+ sscanf(p, "%02X ", &functionToTest[n]);
+ p += 3;
+ logError(1, "%s functionToTest[%d] = %02X\n", tag, n, functionToTest[n]);
+
+ }
+
+ numberParam = n;
+ logError(1, "%s Number of Parameters = %d\n", tag, numberParam);
+ return count;
+}
+
+static ssize_t stm_driver_test_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ char buff[CMD_STR_LEN] = {0};
+ int res = -1, j, count;
+ /* int res2; */
+ int size = 6 * 2;
+ int temp, i, byteToRead;
+ u8 *readData = NULL;
+ u8 *all_strbuff = NULL;
+ u8 *cmd;
+
+ MutualSenseFrame frameMS;
+ SelfSenseFrame frameSS;
+
+ DataHeader dataHead;
+ MutualSenseData compData;
+ SelfSenseData comData;
+ GeneralData gnData;
+
+ u16 address;
+ u16 fw_version;
+ u16 config_id;
+
+ Firmware fw;
+
+ /* struct used for defining which test perform during the MP test */
+
+ TestToDo todoDefault;
+
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ fw.data = NULL;
+
+ todoDefault.MutualRaw = 1;
+ todoDefault.MutualRawGap = 1;
+ todoDefault.MutualCx1 = 0;
+ todoDefault.MutualCx2 = 1;
+ todoDefault.MutualCx2Adj = 1;
+ todoDefault.MutualCxTotal = 0;
+ todoDefault.MutualCxTotalAdj = 0;
+
+ todoDefault.MutualKeyRaw = 0;
+ todoDefault.MutualKeyCx1 = 0;
+ todoDefault.MutualKeyCx2 = 0;
+ todoDefault.MutualKeyCxTotal = 0;
+
+ todoDefault.SelfForceRaw = 1;
+ todoDefault.SelfForceRawGap = 0;
+ todoDefault.SelfForceIx1 = 0;
+ todoDefault.SelfForceIx2 = 0;
+ todoDefault.SelfForceIx2Adj = 0;
+ todoDefault.SelfForceIxTotal = 1;
+ todoDefault.SelfForceIxTotalAdj = 0;
+ todoDefault.SelfForceCx1 = 0;
+ todoDefault.SelfForceCx2 = 0;
+ todoDefault.SelfForceCx2Adj = 0;
+ todoDefault.SelfForceCxTotal = 0;
+ todoDefault.SelfForceCxTotalAdj = 0;
+
+ todoDefault.SelfSenseRaw = 1;
+ todoDefault.SelfSenseRawGap = 0;
+ todoDefault.SelfSenseIx1 = 0;
+ todoDefault.SelfSenseIx2 = 0;
+ todoDefault.SelfSenseIx2Adj = 0;
+ todoDefault.SelfSenseIxTotal = 1;
+ todoDefault.SelfSenseIxTotalAdj = 0;
+ todoDefault.SelfSenseCx1 = 0;
+ todoDefault.SelfSenseCx2 = 0;
+ todoDefault.SelfSenseCx2Adj = 0;
+ todoDefault.SelfSenseCxTotal = 0;
+ todoDefault.SelfSenseCxTotalAdj = 0;
+
+ if (numberParam >= 1 && functionToTest != NULL) {
+ res = fts_disableInterrupt();
+ if (res < 0) {
+ logError(0, "%s stm_driver_test_show: ERROR %08X\n", tag, res);
+ res = (res | ERROR_DISABLE_INTER);
+ goto END;
+ }
+ switch (functionToTest[0]) {
+ case CMD_READ:
+ if (numberParam >= 4) {
+ temp = (int) functionToTest[1];
+ if (numberParam == 4 + (temp - 1) && temp != 0) {
+ cmd = (u8 *) kmalloc(temp * sizeof (u8), GFP_KERNEL);
+ for (i = 0; i < temp; i++) {
+ cmd[i] = functionToTest[i + 2];
+ }
+ byteToRead = functionToTest[i + 2];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = fts_readCmd(cmd, temp, readData, byteToRead);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_WRITE:
+ if (numberParam >= 3) { /* need to pass: cmdLength cmd[0] cmd[1] … cmd[cmdLength-1] */
+ temp = (int) functionToTest[1];
+ if (numberParam == 3 + (temp - 1) && temp != 0) {
+ cmd = (u8 *) kmalloc(temp * sizeof (u8), GFP_KERNEL);
+ for (i = 0; i < temp; i++) {
+ cmd[i] = functionToTest[i + 2];
+ }
+ res = fts_writeCmd(cmd, temp);
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_FWWRITE:
+ if (numberParam >= 3) { /* need to pass: cmdLength cmd[0] cmd[1] … cmd[cmdLength-1] */
+ temp = (int) functionToTest[1];
+ if (numberParam == 3 + (temp - 1) && temp != 0) {
+ cmd = (u8 *) kmalloc(temp * sizeof (u8), GFP_KERNEL);
+ for (i = 0; i < temp; i++) {
+ cmd[i] = functionToTest[i + 2];
+ }
+ res = fts_writeFwCmd(cmd, temp);
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READU16:
+ if (numberParam == 6) { /* need to pass: cmd addr[0] addr[1] byteToRead hasDummyByte */
+ byteToRead = functionToTest[4];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = readCmdU16((u8) functionToTest[1], (u16) ((((u8) functionToTest[2] & 0x00FF) << 8) + ((u8) functionToTest[3] & 0x00FF)), readData, byteToRead, functionToTest[5]);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READB2:
+ if (numberParam == 4) { /* need to pass: addr[0] addr[1] byteToRead */
+ byteToRead = functionToTest[3];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = readB2((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), readData, byteToRead);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READB2U16:
+ if (numberParam == 4) { /* need to pass: addr[0] addr[1] byteToRead */
+ byteToRead = functionToTest[3];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = readB2U16((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), readData, byteToRead);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_POLLFOREVENT:
+ if (numberParam >= 5) { /* need to pass: eventLength event[0] event[1] event[eventLength-1] timeTowait */
+ temp = (int) functionToTest[1];
+ if (numberParam == 5 + (temp - 1) && temp != 0) {
+ readData = (u8 *) kmalloc(FIFO_EVENT_SIZE * sizeof (u8), GFP_KERNEL);
+ res = pollForEvent((int *) &functionToTest[2], temp, readData, ((functionToTest[temp + 2] & 0x00FF) << 8)+(functionToTest[temp + 3] & 0x00FF));
+ if (res >= OK)
+ res = OK; /* pollForEvent return the number of error found */
+ size += (FIFO_EVENT_SIZE * sizeof (u8))*2;
+ byteToRead = FIFO_EVENT_SIZE;
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_SYSTEMRESET:
+ res = fts_system_reset();
+
+ break;
+
+ case CMD_READCHIPINFO:
+ if (numberParam == 2) { /* need to pass: doRequest */
+ res = readChipInfo(functionToTest[1]);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ break;
+
+ case CMD_CLEANUP: /* TOUCH ENABLE/DISABLE */
+ if (numberParam == 2) { /* need to pass: enableTouch */
+ res = cleanUp(functionToTest[1]);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ break;
+
+ case CMD_GETFORCELEN: /* read number Tx channels */
+ temp = getForceLen();
+ if (temp < OK)
+ res = temp;
+ else {
+ size += (1 * sizeof (u8))*2;
+ res = OK;
+ }
+ break;
+
+ case CMD_GETSENSELEN: /* read number Rx channels */
+ temp = getSenseLen();
+ if (temp < OK)
+ res = temp;
+ else {
+ size += (1 * sizeof (u8))*2;
+ res = OK;
+ }
+ break;
+
+ case CMD_REQFRAME: /* request a frame */
+ if (numberParam == 3) {
+ logError(0, "%s Requesting Frame\n", tag);
+ res = requestFrame((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)));
+
+ if (res < OK) {
+ logError(0, "%s Error requesting frame ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Requesting Frame Finished!\n", tag);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_GETMSFRAME:
+ if (numberParam == 3) {
+ logError(0, "%s Get 1 MS Frame\n", tag);
+ flushFIFO(); /* delete the events related to some touch (allow to call this function while touching the sreen without having a flooding of the FIFO) */
+ res = getMSFrame2((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &frameMS);
+ if (res < 0) {
+ logError(0, "%s Error while taking the MS frame... ERROR %02X\n", tag, res);
+
+ } else {
+ logError(0, "%s The frame size is %d words\n", tag, res);
+ size = (res * sizeof (short) + 8)*2;
+ /* set res to OK because if getMSFrame is
+ successful res = number of words read
+ */
+ res = OK;
+ print_frame_short("MS frame =", array1dTo2d_short(frameMS.node_data, frameMS.node_data_size, frameMS.header.sense_node), frameMS.header.force_node, frameMS.header.sense_node);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ /*read self raw*/
+ case CMD_GETSSFRAME:
+ if (numberParam == 3) {
+ logError(0, "%s Get 1 SS Frame\n", tag);
+ flushFIFO(); /* delete the events related to some touch (allow to call this function while touching the sreen without having a flooding of the FIFO) */
+ res = getSSFrame2((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &frameSS);
+
+ if (res < OK) {
+ logError(0, "%s Error while taking the SS frame... ERROR %02X\n", tag, res);
+
+ } else {
+ logError(0, "%s The frame size is %d words\n", tag, res);
+ size = (res * sizeof (short) + 8)*2+1;
+ /* set res to OK because if getMSFrame is
+ successful res = number of words read
+ */
+ res = OK;
+ print_frame_short("SS force frame =", array1dTo2d_short(frameSS.force_data, frameSS.header.force_node, 1), frameSS.header.force_node, 1);
+ print_frame_short("SS sense frame =", array1dTo2d_short(frameSS.sense_data, frameSS.header.sense_node, frameSS.header.sense_node), 1, frameSS.header.sense_node);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_REQCOMPDATA: /* request comp data */
+ if (numberParam == 3) {
+ logError(0, "%s Requesting Compensation Data\n", tag);
+ res = requestCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)));
+
+ if (res < OK) {
+ logError(0, "%s Error requesting compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Requesting Compensation Data Finished!\n", tag);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READCOMPDATAHEAD: /* read comp data header */
+ if (numberParam == 3) {
+ logError(0, "%s Requesting Compensation Data\n", tag);
+ res = requestCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)));
+ if (res < OK) {
+ logError(0, "%s Error requesting compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Requesting Compensation Data Finished!\n", tag);
+ res = readCompensationDataHeader((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &dataHead, &address);
+ if (res < OK) {
+ logError(0, "%s Read Compensation Data Header ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Read Compensation Data Header OK!\n", tag);
+ size += (2 * sizeof (u8))*2;
+ }
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READMSCOMPDATA: /* read mutual comp data */
+ if (numberParam == 3) {
+ logError(0, "%s Get MS Compensation Data\n", tag);
+ res = readMutualSenseCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &compData);
+
+ if (res < OK) {
+ logError(0, "%s Error reading MS compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s MS Compensation Data Reading Finished!\n", tag);
+ size = ((compData.node_data_size + 9) * sizeof (u8))*2;
+ print_frame_u8("MS Data (Cx2) =", array1dTo2d_u8(compData.node_data, compData.node_data_size, compData.header.sense_node), compData.header.force_node, compData.header.sense_node);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READSSCOMPDATA:
+ if (numberParam == 3) { /* read self comp data */
+ logError(0, "%s Get SS Compensation Data...\n", tag);
+ res = readSelfSenseCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &comData);
+ if (res < OK) {
+ logError(0, "%s Error reading SS compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s SS Compensation Data Reading Finished!\n", tag);
+ size = ((comData.header.force_node + comData.header.sense_node)*2 + 12) * sizeof (u8)*2;
+ print_frame_u8("SS Data Ix2_fm = ", array1dTo2d_u8(comData.ix2_fm, comData.header.force_node, comData.header.force_node), 1, comData.header.force_node);
+ print_frame_u8("SS Data Cx2_fm = ", array1dTo2d_u8(comData.cx2_fm, comData.header.force_node, comData.header.force_node), 1, comData.header.force_node);
+ print_frame_u8("SS Data Ix2_sn = ", array1dTo2d_u8(comData.ix2_sn, comData.header.sense_node, comData.header.sense_node), 1, comData.header.sense_node);
+ print_frame_u8("SS Data Cx2_sn = ", array1dTo2d_u8(comData.cx2_sn, comData.header.sense_node, comData.header.sense_node), 1, comData.header.sense_node);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READGNCOMPDATA:
+ if (numberParam == 3) { /* read self comp data */
+ logError(0, "%s Get General Compensation Data...\n", tag);
+ res = readGeneralCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &gnData);
+ if (res < OK) {
+ logError(0, "%s Error reading General compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s General Compensation Data Reading Finished!\n", tag);
+ size = (14) * sizeof (u8)*2;
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_GETFWVER:
+ res = getFirmwareVersion(&fw_version, &config_id);
+ if (res < OK) {
+ logError(1, "%s Error reading firmware version and config id ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s getFirmwareVersion Finished!\n", tag);
+ size += (4) * sizeof (u8)*2;
+ }
+ break;
+#ifdef FTM3_CHIP
+ case CMD_FLASHSTATUS:
+ res = flash_status(); /* return 0 = flash ready, 1 = flash busy, <0 error */
+ if (res < OK) {
+ logError(1, "%s Error reading flash status ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Flash Status: %d\n", tag, res);
+ size += (1 * sizeof (u8))*2;
+ temp = res; /* need to store the value for further display */
+ res = OK; /* set res =ok for returning code */
+ }
+ break;
+#endif
+
+ case CMD_FLASHUNLOCK:
+ res = flash_unlock();
+ if (res < OK) {
+ logError(1, "%s Impossible Unlock Flash ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Flash Unlock OK!\n", tag);
+ }
+ break;
+
+ case CMD_READFWFILE:
+ if (numberParam == 2) { /* read fw file */
+ logError(0, "%s Reading FW File...\n", tag);
+ res = readFwFile(PATH_FILE_FW, &fw, functionToTest[1]);
+ if (res < OK) {
+ logError(0, "%s Error reading FW File ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Read FW File Finished!\n", tag);
+ }
+ kfree(fw.data);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_FLASHPROCEDURE:
+ if (numberParam == 3) { /* flashing procedure */
+ logError(0, "%s Starting Flashing Procedure...\n", tag);
+ res = flashProcedure(PATH_FILE_FW, functionToTest[1], functionToTest[2]);
+ if (res < OK) {
+ logError(0, "%s Error during flash procedure ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Flash Procedure Finished!\n", tag);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ /*ITO TEST*/
+ case CMD_ITOTEST:
+ res = production_test_ito();
+ break;
+
+ /*Initialization*/
+ case CMD_INITTEST:
+ if (numberParam == 2) { /* need to specify if if save value on Flash */
+ if (functionToTest[1] == 0x01)
+ res = production_test_initialization();
+ else
+ res = production_test_splited_initialization(false);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_MSRAWTEST: /* MS Raw DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ms_raw(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_MSINITDATATEST: /* MS CX DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ms_cx(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_SSRAWTEST: /* SS RAW DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ss_raw(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_SSINITDATATEST: /* SS IX CX DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ss_ix_cx(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ /*PRODUCTION TEST*/
+ case CMD_MAINTEST:
+ if (numberParam == 3) /* need to specify if stopOnFail and saveInit */
+ res = production_test_main(LIMITS_FILE, functionToTest[1], functionToTest[2], &todoDefault, INIT_FIELD);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_POWERCYCLE:
+ res = fts_chip_powercycle(info);
+ break;
+
+ default:
+ logError(1, "%s COMMAND ID NOT VALID!! Inset a value between 00 and 1E..\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ break;
+ }
+
+ /*res2 = fts_enableInterrupt(); enabling the interrupt was disabled on purpose in this node because it can be used for testing procedure and between one step and another the interrupt wan to be kept disabled
+ if (res2 < 0) {
+ logError(0, "%s stm_driver_test_show: ERROR %08X\n", tag, (res2 | ERROR_ENABLE_INTER));
+ }*/
+ } else {
+ logError(1, "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ functionToTest = NULL;
+ }
+
+END: /* here start the reporting phase, assembling the data to send in the file node */
+ all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL);
+ memset(all_strbuff, 0, size);
+
+ snprintf(buff, sizeof (buff), "%02X", 0xAA);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%08X", res);
+ strlcat(all_strbuff, buff, size);
+
+ if (res >= OK) {
+ /*all the other cases are already fine printing only the res.*/
+ switch (functionToTest[0]) {
+ case CMD_READ:
+ case CMD_READU16:
+ case CMD_READB2:
+ case CMD_READB2U16:
+ case CMD_POLLFOREVENT:
+ for (j = 0; j < byteToRead; j++) {
+ snprintf(buff, sizeof (buff), "%02X", readData[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+ break;
+
+ case CMD_GETFORCELEN:
+ case CMD_GETSENSELEN:
+ case CMD_FLASHSTATUS:
+ snprintf(buff, sizeof (buff), "%02X", (u8) temp);
+ strlcat(all_strbuff, buff, size);
+ break;
+
+ case CMD_GETMSFRAME:
+ snprintf(buff, sizeof (buff), "%02X", (u8) frameMS.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", (u8) frameMS.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ for (j = 0; j < frameMS.node_data_size; j++) {
+ snprintf(buff, sizeof (buff), "%04X", frameMS.node_data[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(frameMS.node_data);
+ break;
+
+ case CMD_GETSSFRAME:
+ snprintf(buff, sizeof (buff), "%02X", (u8) frameSS.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", (u8) frameSS.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ /* Copying self raw data Force */
+ for (j = 0; j < frameSS.header.force_node; j++) {
+ snprintf(buff, sizeof (buff), "%04X", frameSS.force_data[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying self raw data Sense */
+ for (j = 0; j < frameSS.header.sense_node; j++) {
+ snprintf(buff, sizeof (buff), "%04X", frameSS.sense_data[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(frameSS.force_data);
+ kfree(frameSS.sense_data);
+ break;
+
+ case CMD_READMSCOMPDATA:
+ snprintf(buff, sizeof (buff), "%02X", (u8) compData.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", (u8) compData.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ /* Cpying CX1 value */
+ snprintf(buff, sizeof (buff), "%02X", compData.cx1);
+ strlcat(all_strbuff, buff, size);
+
+ /* Copying CX2 values */
+ for (j = 0; j < compData.node_data_size; j++) {
+ snprintf(buff, sizeof (buff), "%02X", *(compData.node_data + j));
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(compData.node_data);
+ break;
+
+ case CMD_READSSCOMPDATA:
+ snprintf(buff, sizeof (buff), "%02X", comData.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", comData.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", comData.f_ix1);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", comData.s_ix1);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", comData.f_cx1);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", comData.s_cx1);
+ strlcat(all_strbuff, buff, size);
+
+ /* Copying IX2 Force */
+ for (j = 0; j < comData.header.force_node; j++) {
+ snprintf(buff, sizeof (buff), "%02X", comData.ix2_fm[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying IX2 Sense */
+ for (j = 0; j < comData.header.sense_node; j++) {
+ snprintf(buff, sizeof (buff), "%02X", comData.ix2_sn[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying CX2 Force */
+ for (j = 0; j < comData.header.force_node; j++) {
+ snprintf(buff, sizeof (buff), "%02X", comData.cx2_fm[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ /* Copying CX2 Sense */
+ for (j = 0; j < comData.header.sense_node; j++) {
+ snprintf(buff, sizeof (buff), "%02X", comData.cx2_sn[j]);
+ strlcat(all_strbuff, buff, size);
+ }
+
+ kfree(comData.ix2_fm);
+ kfree(comData.ix2_sn);
+ kfree(comData.cx2_fm);
+ kfree(comData.cx2_sn);
+ break;
+
+ case CMD_READGNCOMPDATA:
+ snprintf(buff, sizeof (buff), "%02X", gnData.header.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", gnData.header.sense_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal0);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal1);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal2);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal3);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", gnData.ftsa_lp_timer_cal0);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", gnData.ftsa_lp_timer_cal1);
+ strlcat(all_strbuff, buff, size);
+ break;
+
+ case CMD_GETFWVER:
+ snprintf(buff, sizeof (buff), "%04X", fw_version);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%04X", config_id);
+ strlcat(all_strbuff, buff, size);
+ break;
+
+ case CMD_READCOMPDATAHEAD:
+ snprintf(buff, sizeof (buff), "%02X", dataHead.force_node);
+ strlcat(all_strbuff, buff, size);
+
+ snprintf(buff, sizeof (buff), "%02X", dataHead.sense_node);
+ strlcat(all_strbuff, buff, size);
+ break;
+
+ default:
+ break;
+
+ }
+ }
+
+ snprintf(buff, sizeof (buff), "%02X", 0xBB);
+ strlcat(all_strbuff, buff, size);
+
+ count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
+ numberParam = 0; /* need to reset the number of parameters in order to wait the next comand, comment if you want to repeat the last comand sent just doing a cat */
+ /* logError(0,"%s numberParameters = %d\n",tag, numberParam); */
+ kfree(all_strbuff);
+ kfree(functionToTest);
+ return count;
+
+}
+
+/*static DEVICE_ATTR(stm_driver_test, (S_IRWXU|S_IRWXG), stm_driver_test_show, stm_driver_test_store);*/
+static DEVICE_ATTR(stm_driver_test, (S_IRUGO | S_IWUSR | S_IWGRP), stm_driver_test_show, stm_driver_test_store);
+
+static struct attribute *test_cmd_attributes[] = {
+ &dev_attr_stm_driver_test.attr,
+ NULL,
+};
+
+struct attribute_group test_cmd_attr_group = {
+ .attrs = test_cmd_attributes,
+};
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_fw.h b/drivers/input/touchscreen/st/fts_fw.h
new file mode 100644
index 000000000000..d928a06951ea
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_fw.h
@@ -0,0 +1,10 @@
+#ifndef FTS_FW_H
+#define FTS_FW_H
+/* This is an auto generated header file
+* --->Remember to change the name of the two variables!<--- */
+const uint32_t myArray_size;
+
+const uint8_t myArray[] = {
+};
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_gui.c b/drivers/input/touchscreen/st/fts_gui.c
new file mode 100644
index 000000000000..f695137ada09
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_gui.c
@@ -0,0 +1,359 @@
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/completion.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include "fts.h"
+#include "fts_lib/ftsCompensation.h"
+#include "fts_lib/ftsIO.h"
+#include "fts_lib/ftsError.h"
+#include "fts_lib/ftsFrame.h"
+#include "fts_lib/ftsTest.h"
+#include "fts_lib/ftsTime.h"
+#include "fts_lib/ftsTool.h"
+
+#ifdef SCRIPTLESS
+
+unsigned int data[CMD_RESULT_STR_LEN] = {0};
+unsigned char pAddress_i2c[CMD_RESULT_STR_LEN] = {0};
+int byte_count_read;
+char Out_buff[TSP_BUF_SIZE];
+
+/*I2C CMd functions: functions to interface with GUI without script */
+
+ssize_t fts_i2c_wr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ int i;
+ char buff[16];
+ memset(Out_buff, 0x00, ARRAY_SIZE(Out_buff));
+ if (byte_count_read == 0) {
+ snprintf(Out_buff, sizeof(Out_buff), "{FAILED}");
+ return snprintf(buf, TSP_BUF_SIZE, "{%s}\n", Out_buff);
+ }
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ {", __func__);
+ for (i = 0; i < byte_count_read; i++) {
+ printk(" %02X", (unsigned int)info->cmd_wr_result[i]);
+ if (i < (byte_count_read-1)) {
+ printk(" ");
+ }
+ }
+ printk("}\n");
+#endif
+ snprintf(buff, sizeof(buff), "{");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ for (i = 0; i < (byte_count_read+2); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+
+ } else {
+ snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i-2]);
+ }
+ /* snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i]); */
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ if (i < (byte_count_read+1)) {
+ snprintf(buff, sizeof(buff), " ");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ }
+ }
+ snprintf(buff, sizeof(buff), "}");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
+}
+
+ssize_t fts_i2c_wr_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ unsigned char pAddress[8] = {0};
+ unsigned int byte_count = 0 ;
+ int i ;
+
+ unsigned int data[8] = {0};
+ memset(data, 0x00, ARRAY_SIZE(data));
+ memset(info->cmd_wr_result, 0x00, ARRAY_SIZE(info->cmd_wr_result));
+ sscanf(buf, "%x %x %x %x %x %x %x %x ", (data+7), (data), (data+1),
+ (data+2), (data+3), (data+4), (data+5), (data+6));
+
+ byte_count = data[7];
+
+ /*if (sizeof(buf) != byte_count )
+ {
+ printk("%s : Byte count is wrong\n",__func__);
+ return count;
+ }*/
+#ifdef SCRIPTLESS_DEBUG
+ printk("\n");
+ printk("%s: Input Data 1:", __func__);
+
+ for (i = 0 ; i < 7; i++) {
+ printk(" %02X", data[i]);
+ pAddress[i] = (unsigned char)data[i];
+ }
+ printk("\n");
+#else
+ for (i = 0 ; i < 7; i++) {
+ pAddress[i] = (unsigned char)data[i];
+ }
+#endif
+ byte_count_read = data[byte_count-1];
+ ret = fts_writeCmd(pAddress, 3);
+ msleep(20);
+ ret = fts_readCmd(&pAddress[3], (byte_count-4), info->cmd_wr_result,
+ byte_count_read);
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ\n{", __func__);
+ for (i = 0; i < (2+byte_count_read); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+
+ } else {
+ printk("%02X", (unsigned int)info->cmd_read_result[i-2]);
+ }
+ if (i < (byte_count_read+1)) {
+ printk(" ");
+ }
+
+ }
+ printk("}\n");
+#endif
+ if (ret)
+ dev_err(dev, "Unable to read register\n");
+ return count;
+}
+
+ssize_t fts_i2c_read_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ int i ;
+ char buff[16];
+
+ memset(Out_buff, 0x00, ARRAY_SIZE(Out_buff));
+ if (byte_count_read == 0) {
+ snprintf(Out_buff, sizeof(Out_buff), "{FAILED}");
+ return snprintf(buf, TSP_BUF_SIZE, "{%s}\n", Out_buff);
+ }
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ {", __func__);
+ for (i = 0; i < byte_count_read; i++) {
+ printk("%02X", (unsigned int)info->cmd_read_result[i]);
+ if (i < (byte_count_read-1)) {
+ printk(" ");
+ }
+ }
+ printk("}\n");
+#endif
+ snprintf(buff, sizeof(buff), "{");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ for (i = 0; i < (byte_count_read+2); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+
+ } else {
+ snprintf(buff, sizeof(buff), "%02X", info->cmd_read_result[i-2]);
+ }
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ if (i < (byte_count_read+1)) {
+ snprintf(buff, sizeof(buff), " ");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ }
+ }
+ snprintf(buff, sizeof(buff), "}");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+
+ return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
+}
+
+ssize_t fts_i2c_read_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ unsigned char pAddress[8] = {0};
+ unsigned int byte_count = 0;
+ int i ;
+ unsigned int data[8] = {0};
+
+ byte_count_read = 0;
+ memset(data, 0x00, ARRAY_SIZE(data));
+ memset(info->cmd_read_result, 0x00, ARRAY_SIZE(info->cmd_read_result));
+ sscanf(buf, "%x %x %x %x %x %x %x %x ", (data+7), (data), (data+1), (data+2), (data+3), (data+4), (data+5), (data+6));
+ byte_count = data[7];
+
+ if (byte_count > 7) {
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s : Byte count is more than 7\n", __func__);
+#endif
+ return count;
+ }
+ /*if (sizeof(buf) != byte_count )
+ {
+ printk("%s : Byte count is wrong\n",__func__);
+ return count;
+ }*/
+#ifdef SCRIPTLESS_DEBUG
+ printk("\n");
+ printk("%s: Input Data 1:", __func__);
+ for (i = 0 ; i < byte_count; i++) {
+ printk(" %02X", data[i]);
+ pAddress[i] = (unsigned char)data[i];
+ }
+ printk("\n");
+#else
+ for (i = 0 ; i < byte_count; i++) {
+ pAddress[i] = (unsigned char)data[i];
+ }
+#endif
+ byte_count_read = data[byte_count-1];
+ ret = fts_readCmd(pAddress, (byte_count-1), info->cmd_read_result, byte_count_read);
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ\n{", __func__);
+ for (i = 0; i < (byte_count_read+2); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+
+ } else {
+ printk("%02X", (unsigned int)info->cmd_read_result[i-2]);
+ }
+ if (i < (byte_count_read+1)) {
+ printk(" ");
+ }
+ }
+ printk("}\n");
+#endif
+ if (ret)
+ dev_err(dev, "Unable to read register\n");
+ return count;
+}
+
+ssize_t fts_i2c_write_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ return snprintf(buf, TSP_BUF_SIZE, "%s", info->cmd_write_result);
+
+}
+
+ssize_t fts_i2c_write_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ unsigned int byte_count = 0;
+ int i ;
+ memset(data, 0x00, ARRAY_SIZE(data));
+ memset(pAddress_i2c, 0x00, ARRAY_SIZE(pAddress_i2c));
+ memset(info->cmd_write_result, 0x00, ARRAY_SIZE(info->cmd_write_result));
+ sscanf(buf, "%x %x", data, (data + 1));
+ byte_count = data[0] << 8 | data[1];
+
+ if (byte_count <= ARRAY_SIZE(pAddress_i2c)) {
+ for (i = 0; i < (byte_count); i++) {
+ sscanf(&buf[3*(i+2)], "%x ", (data+i));
+ } } else {
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s : message size is more than allowed limit of 512 bytes\n", __func__);
+#endif
+ snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write NOT OK}\n");
+ }
+#ifdef SCRIPTLESS_DEBUG
+ printk("\n");
+ printk("%s: Byte_count= %02d | Count = %02d | size of buf:%02d\n", __func__, byte_count, (int)count, (int)sizeof(buf));
+ printk("%s: Input Data 1:", __func__);
+ for (i = 0 ; i < byte_count; i++) {
+ printk("%02X", data[i]);
+ pAddress_i2c[i] = (unsigned char)data[i];
+ }
+ printk("\n");
+#else
+ for (i = 0; i < byte_count; i++) {
+ pAddress_i2c[i] = (unsigned char)data[i];
+ }
+#endif
+ if ((pAddress_i2c[0] == 0xb3) && (pAddress_i2c[3] == 0xb1)) {
+ ret = fts_writeCmd(pAddress_i2c, 3);
+ msleep(20);
+ ret = fts_writeCmd(&pAddress_i2c[3], byte_count-3);
+ } else {
+ ret = fts_writeCmd(pAddress_i2c, byte_count);
+ }
+
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA :", __func__);
+ for (i = 0; i < byte_count; i++) {
+ printk(" %02X", (unsigned int)pAddress_i2c[i]);
+ }
+ printk(" byte_count: %02X\n", byte_count);
+#endif
+ if (ret < 0) {
+ dev_err(dev, "{Write NOT OK}\n");
+ snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write NOT OK}\n");
+ } else {
+ snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write OK}\n");
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s : {Write OK}\n", __func__);
+#endif
+ }
+ return count;
+}
+
+static DEVICE_ATTR(iread, (S_IWUSR|S_IWGRP), NULL, fts_i2c_read_store);
+static DEVICE_ATTR(iread_result, (S_IRUSR|S_IRGRP), fts_i2c_read_show, NULL);
+static DEVICE_ATTR(iwr, (S_IWUSR|S_IWGRP), NULL, fts_i2c_wr_store);
+static DEVICE_ATTR(iwr_result, (S_IRUSR|S_IRGRP), fts_i2c_wr_show, NULL);
+static DEVICE_ATTR(iwrite, (S_IWUSR|S_IWGRP), NULL, fts_i2c_write_store);
+static DEVICE_ATTR(iwrite_result, (S_IRUSR|S_IRGRP), fts_i2c_write_show, NULL);
+
+static struct attribute *i2c_cmd_attributes[] = {
+ &dev_attr_iread.attr,
+ &dev_attr_iread_result.attr,
+ &dev_attr_iwr.attr,
+ &dev_attr_iwr_result.attr,
+ &dev_attr_iwrite.attr,
+ &dev_attr_iwrite_result.attr,
+ NULL,
+};
+
+struct attribute_group i2c_cmd_attr_group = {
+ .attrs = i2c_cmd_attributes,
+};
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_lib/Makefile b/drivers/input/touchscreen/st/fts_lib/Makefile
new file mode 100644
index 000000000000..24eca48fc3cd
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the FTS touchscreen driver.
+#
+
+obj-$(CONFIG_TOUCHSCREEN_ST_I2C) += ftsCompensation.o \
+ ftsCrossCompile.o ftsError.o ftsFrame.o ftsIO.o ftsTest.o \
+ ftsTime.o ftsTool.o ftsFlash.o ftsGesture.o
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c
new file mode 100644
index 000000000000..2ca0067f34b0
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c
@@ -0,0 +1,591 @@
+/*
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting Initialization Data *
+* *
+**************************************************************************
+**************************************************************************
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.h"
+#include "ftsError.h"
+#include "ftsFrame.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTool.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+static char tag[8] = "[ FTS ]\0";
+
+chipInfo ftsInfo;
+
+int requestCompensationData(u16 type)
+{
+ int retry = 0;
+ int ret;
+ u16 answer;
+
+ int event_to_search[3];
+ u8 readEvent[FIFO_EVENT_SIZE];
+
+ u8 cmd[3] = { FTS_CMD_REQU_COMP_DATA, 0x00, 0x00 };
+ /* B8 is the command for asking compensation data */
+ u16ToU8(type, &cmd[1]);
+
+ event_to_search[0] = (int)EVENTID_COMP_DATA_READ;
+ event_to_search[1] = cmd[1];
+ event_to_search[2] = cmd[2];
+
+ while (retry < COMP_DATA_READ_RETRY) {
+ logError(0, "%s %s", tag, printHex("Command = ", cmd, 3));
+ ret = fts_writeFwCmd(cmd, 3);
+ /* send the request to the chip to load in memory the Compensation Data */
+ if (ret < OK) {
+ logError(1, "%s requestCompensationData: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ ret = pollForEvent(event_to_search, 3, readEvent, TIMEOUT_REQU_COMP_DATA);
+ if (ret < OK) {
+ logError(0, "%s Event did not Found at %d attemp! \n", tag, retry+1);
+ retry += 1;
+ } else {
+ retry = 0;
+ break;
+ }
+ }
+
+ if (retry == COMP_DATA_READ_RETRY) {
+ logError(1, "%s requestCompensationData: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+
+ u8ToU16_le(&readEvent[1], &answer);
+
+ if (answer == type)
+ return OK;
+ logError(1, "%s The event found has a different type of Compensation data ERROR %02X \n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+
+}
+
+int readCompensationDataHeader(u16 type, DataHeader *header, u16 *address)
+{
+
+ u16 offset = ADDR_FRAMEBUFFER_DATA;
+ u16 answer;
+ u8 data[COMP_DATA_HEADER];
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, COMP_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readCompensationDataHeader: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ logError(0, "%s Read Data Header done! \n", tag);
+
+ if (data[0] != HEADER_SIGNATURE) {
+ logError(1, "%s readCompensationDataHeader: ERROR %02X The Header Signature was wrong! %02X != %02X \n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE);
+ return ERROR_WRONG_COMP_SIGN;
+ }
+
+ u8ToU16_le(&data[1], &answer);
+
+ if (answer != type) {
+ logError(1, "%s readCompensationDataHeader: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+ }
+
+ logError(0, "%s Type of Compensation data OK! \n", tag);
+
+ header->type = type;
+ header->force_node = (int)data[4];
+ header->sense_node = (int)data[5];
+
+ *address = offset + COMP_DATA_HEADER;
+
+ return OK;
+
+}
+
+int readMutualSenseGlobalData(u16 *address, MutualSenseData *global)
+{
+
+ u8 data[COMP_DATA_GLOBAL];
+
+ logError(0, "%s Address for Global data= %02X \n", tag, *address);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readMutualSenseGlobalData: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ logError(0, "%s Global data Read !\n", tag);
+
+ global->tuning_ver = data[0];
+ global->cx1 = data[1];
+
+ logError(0, "%s tuning_ver = %d CX1 = %d \n", tag, global->tuning_ver, global->cx1);
+
+ *address += COMP_DATA_GLOBAL;
+ return OK;
+
+}
+
+int readMutualSenseNodeData(u16 address, MutualSenseData *node)
+{
+
+ int size = node->header.force_node*node->header.sense_node;
+
+ logError(0, "%s Address for Node data = %02X \n", tag, address);
+
+ node->node_data = (u8 *)kmalloc(size*(sizeof(u8)), GFP_KERNEL);
+
+ if (node->node_data == NULL) {
+ logError(1, "%s readMutualSenseNodeData: ERROR %02X", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ logError(0, "%s Node Data to read %d bytes \n", tag, size);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, node->node_data, size, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readMutualSenseNodeData: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ node->node_data_size = size;
+
+ logError(0, "%s Read node data ok! \n", tag);
+
+ return size;
+
+}
+
+int readMutualSenseCompensationData(u16 type, MutualSenseData *data)
+{
+
+ int ret;
+ u16 address;
+
+ if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER ||
+ type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) {
+ logError(1, "%s readMutualSenseCompensationData: Choose a MS type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestCompensationData(type);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret|ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readCompensationDataHeader(type, &(data->header), &address);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret|ERROR_COMP_DATA_HEADER);
+ }
+
+ ret = readMutualSenseGlobalData(&address, data);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X \n", tag, ERROR_COMP_DATA_GLOBAL);
+ return (ret|ERROR_COMP_DATA_GLOBAL);
+ }
+
+ ret = readMutualSenseNodeData(address, data);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_NODE);
+ return (ret|ERROR_COMP_DATA_NODE);
+ }
+
+ return OK;
+
+}
+
+int readSelfSenseGlobalData(u16 *address, SelfSenseData *global)
+{
+
+ u8 data[COMP_DATA_GLOBAL];
+
+ logError(0, "%s Address for Global data= %02X \n", tag, *address);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readSelfSenseGlobalData: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ logError(0, "%s Global data Read !\n", tag);
+
+ global->tuning_ver = data[0];
+ global->f_ix1 = data[1];
+ global->s_ix1 = data[2];
+ global->f_cx1 = data[3];
+ global->s_cx1 = data[4];
+ global->f_max_n = data[5];
+ global->s_max_n = data[6];
+
+ logError(0, "%s tuning_ver = %d f_ix1 = %d s_ix1 = %d f_cx1 = %d s_cx1 = %d \n", tag, global->tuning_ver, global->f_ix1, global->s_ix1, global->f_cx1, global->s_cx1);
+ logError(0, "%s max_n = %d s_max_n = %d \n", tag, global->f_max_n, global->s_max_n);
+
+ *address += COMP_DATA_GLOBAL;
+
+ return OK;
+
+}
+
+int readSelfSenseNodeData(u16 address, SelfSenseData *node)
+{
+
+ int size = node->header.force_node*2+node->header.sense_node*2;
+ u8 data[size];
+
+ node->ix2_fm = (u8 *)kmalloc(node->header.force_node*(sizeof(u8)), GFP_KERNEL);
+ node->cx2_fm = (u8 *)kmalloc(node->header.force_node*(sizeof(u8)), GFP_KERNEL);
+ node->ix2_sn = (u8 *)kmalloc(node->header.sense_node*(sizeof(u8)), GFP_KERNEL);
+ node->cx2_sn = (u8 *)kmalloc(node->header.sense_node*(sizeof(u8)), GFP_KERNEL);
+
+ if (node->ix2_fm == NULL || node->cx2_fm == NULL || node->ix2_sn == NULL
+ || node->cx2_sn == NULL) {
+ logError(1, "%s readSelfSenseNodeData: ERROR %02X", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ logError(0, "%s Address for Node data = %02X \n", tag, address);
+
+ logError(0, "%s Node Data to read %d bytes \n", tag, size);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readSelfSenseNodeData: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ logError(0, "%s Read node data ok! \n", tag);
+
+ memcpy(node->ix2_fm, data, node->header.force_node);
+ memcpy(node->ix2_sn, &data[node->header.force_node], node->header.sense_node);
+ memcpy(node->cx2_fm, &data[node->header.force_node + node->header.sense_node], node->header.force_node);
+ memcpy(node->cx2_sn, &data[node->header.force_node*2 + node->header.sense_node], node->header.sense_node);
+
+ return OK;
+
+}
+
+int readSelfSenseCompensationData(u16 type, SelfSenseData *data)
+{
+
+ int ret;
+ u16 address;
+
+ if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER || type == SS_PROXIMITY)) {
+ logError(1, "%s readSelfSenseCompensationData: Choose a SS type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestCompensationData(type);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret|ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readCompensationDataHeader(type, &(data->header), &address);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret|ERROR_COMP_DATA_HEADER);
+ }
+
+ ret = readSelfSenseGlobalData(&address, data);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_GLOBAL);
+ return (ret|ERROR_COMP_DATA_GLOBAL);
+ }
+
+ ret = readSelfSenseNodeData(address, data);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_NODE);
+ return (ret|ERROR_COMP_DATA_NODE);
+ }
+
+ return OK;
+
+}
+
+int readGeneralGlobalData(u16 address, GeneralData *global)
+{
+ u8 data[COMP_DATA_GLOBAL];
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readGeneralGlobalData: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ global->ftsd_lp_timer_cal0 = data[0];
+ global->ftsd_lp_timer_cal1 = data[1];
+ global->ftsd_lp_timer_cal2 = data[2];
+ global->ftsd_lp_timer_cal3 = data[3];
+ global->ftsa_lp_timer_cal0 = data[4];
+ global->ftsa_lp_timer_cal1 = data[5];
+
+ return OK;
+
+}
+
+int readGeneralCompensationData(u16 type, GeneralData *data)
+{
+
+ int ret;
+ u16 address;
+
+ if (!(type == GENERAL_TUNING)) {
+ logError(1, "%s readGeneralCompensationData: Choose a GENERAL type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestCompensationData(type);
+ if (ret < 0) {
+ logError(1, "%s readGeneralCompensationData: ERROR %02X \n", tag, ERROR_REQU_COMP_DATA);
+ return ERROR_REQU_COMP_DATA;
+ }
+
+ ret = readCompensationDataHeader(type, &(data->header), &address);
+ if (ret < 0) {
+ logError(1, "%s readGeneralCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return ERROR_COMP_DATA_HEADER;
+ }
+
+ ret = readGeneralGlobalData(address, data);
+ if (ret < 0) {
+ logError(1, "%s readGeneralCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_GLOBAL);
+ return ERROR_COMP_DATA_GLOBAL;
+ }
+
+ return OK;
+
+}
+
+int defaultChipInfo(int i2cError)
+{
+ int i;
+ logError(0, "%s Setting default Chip Info... \n", tag);
+ ftsInfo.u32_echoEn = 0x00000000;
+ ftsInfo.u8_msScrConfigTuneVer = 0;
+ ftsInfo.u8_ssTchConfigTuneVer = 0;
+ ftsInfo.u8_msScrCxmemTuneVer = 0;
+ ftsInfo.u8_ssTchCxmemTuneVer = 0;
+ if (i2cError == 1) {
+ ftsInfo.u16_fwVer = 0xFFFF;
+ ftsInfo.u16_cfgId = 0xFFFF;
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ ftsInfo.u8_extReleaseInfo[i] = 0xFF;
+ }
+ } else {
+ ftsInfo.u16_fwVer = 0x0000;
+ ftsInfo.u16_cfgId = 0x0000;
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ ftsInfo.u8_extReleaseInfo[i] = 0x00;
+ }
+ }
+ ftsInfo.u32_mpPassFlag = INIT_FIELD;
+ logError(0, "%s default Chip Info DONE! \n", tag);
+ return OK;
+
+}
+
+int readChipInfo(int doRequest)
+{
+ int ret, i;
+ u16 answer;
+ u8 data[CHIP_INFO_SIZE+3];
+ /* +3 because need to read all the field of the struct plus the signature and 2 address bytes */
+ int index = 0;
+
+ logError(0, "%s Starting Read Chip Info... \n", tag);
+ if (doRequest == 1) {
+ ret = requestCompensationData(CHIP_INFO);
+ if (ret < 0) {
+ logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ ret = (ret | ERROR_REQU_COMP_DATA);
+ goto FAIL;
+ }
+ }
+
+ logError(0, "%s Byte to read = %d bytes \n", tag, CHIP_INFO_SIZE+3);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, ADDR_FRAMEBUFFER_DATA, data, CHIP_INFO_SIZE+3, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_I2C_R);
+ ret = ERROR_I2C_R;
+ goto FAIL;
+ }
+
+ logError(0, "%s Read data ok! \n", tag);
+
+ logError(0, "%s Starting parsing of data... \n", tag);
+
+ if (data[0] != HEADER_SIGNATURE) {
+ logError(1, "%s readChipInfo: ERROR %02X The Header Signature was wrong! %02X != %02X \n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE);
+ ret = ERROR_WRONG_COMP_SIGN;
+ goto FAIL;
+ }
+
+ u8ToU16_le(&data[1], &answer);
+
+ if (answer != CHIP_INFO) {
+ logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ ret = ERROR_DIFF_COMP_TYPE;
+ goto FAIL;
+ }
+
+ index += 3;
+ ftsInfo.u8_loadCnt = data[index++];
+ ftsInfo.u8_infoVer = data[index++];
+ u8ToU16(&data[index], &ftsInfo.u16_ftsdId);
+ index += 2;
+ ftsInfo.u8_ftsdVer = data[index++];
+ ftsInfo.u8_ftsaId = data[index++];
+ ftsInfo.u8_ftsaVer = data[index++];
+ ftsInfo.u8_tchRptVer = data[index++];
+
+ logError(1, "%s External Release = ", tag);
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ ftsInfo.u8_extReleaseInfo[i] = data[index++];
+ logError(1, "%02X ", ftsInfo.u8_extReleaseInfo[i]);
+ }
+ logError(1, "\n");
+
+ for (i = 0; i < sizeof(ftsInfo.u8_custInfo); i++) {
+ ftsInfo.u8_custInfo[i] = data[index++];
+ }
+
+ u8ToU16(&data[index], &ftsInfo.u16_fwVer);
+ index += 2;
+ logError(1, "%s FW VERSION = %04X \n", tag, ftsInfo.u16_fwVer);
+
+ u8ToU16(&data[index], &ftsInfo.u16_cfgId);
+ index += 2;
+ logError(1, "%s CONFIG ID = %04X \n", tag, ftsInfo.u16_cfgId);
+
+ ftsInfo.u32_projId = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+
+ u8ToU16(&data[index], &ftsInfo.u16_scrXRes);
+ index += 2;
+
+ u8ToU16(&data[index], &ftsInfo.u16_scrYRes);
+ index += 2;
+
+ ftsInfo.u8_scrForceLen = data[index++];
+ logError(1, "%s Force Len = %d \n", tag, ftsInfo.u8_scrForceLen);
+
+ ftsInfo.u8_scrSenseLen = data[index++];
+ logError(1, "%s Sense Len = %d \n", tag, ftsInfo.u8_scrSenseLen);
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_scrForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_scrSenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_msKeyLen = data[index++];
+ logError(1, "%s MS Key Len = %d \n", tag, ftsInfo.u8_msKeyLen);
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_msKeyForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_msKeySenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_ssKeyLen = data[index++];
+ logError(1, "%s SS Key Len = %d \n", tag, ftsInfo.u8_ssKeyLen);
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_ssKeyForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_ssKeySenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_frcTchXLen = data[index++];
+
+ ftsInfo.u8_frcTchYLen = data[index++];
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_frcTchForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_frcTchSenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_msScrConfigTuneVer = data[index++];
+ logError(1, "%s CFG MS TUNING VERSION = %02X \n", tag, ftsInfo.u8_msScrConfigTuneVer);
+ ftsInfo.u8_msScrLpConfigTuneVer = data[index++];
+ ftsInfo.u8_msScrHwulpConfigTuneVer = data[index++];
+ ftsInfo.u8_msKeyConfigTuneVer = data[index++];
+ ftsInfo.u8_ssTchConfigTuneVer = data[index++];
+ logError(1, "%s CFG SS TUNING VERSION = %02X \n", tag, ftsInfo.u8_ssTchConfigTuneVer);
+ ftsInfo.u8_ssKeyConfigTuneVer = data[index++];
+ ftsInfo.u8_ssHvrConfigTuneVer = data[index++];
+ ftsInfo.u8_frcTchConfigTuneVer = data[index++];
+ ftsInfo.u8_msScrCxmemTuneVer = data[index++];
+ logError(1, "%s CX MS TUNING VERSION = %02X \n", tag, ftsInfo.u8_msScrCxmemTuneVer);
+ ftsInfo.u8_msScrLpCxmemTuneVer = data[index++];
+ ftsInfo.u8_msScrHwulpCxmemTuneVer = data[index++];
+ ftsInfo.u8_msKeyCxmemTuneVer = data[index++];
+ ftsInfo.u8_ssTchCxmemTuneVer = data[index++];
+ logError(1, "%s CX SS TUNING VERSION = %02X \n", tag, ftsInfo.u8_ssTchCxmemTuneVer);
+ ftsInfo.u8_ssKeyCxmemTuneVer = data[index++];
+ ftsInfo.u8_ssHvrCxmemTuneVer = data[index++];
+ ftsInfo.u8_frcTchCxmemTuneVer = data[index++];
+ ftsInfo.u32_mpPassFlag = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+ logError(1, "%s MP SIGNATURE = %08X \n", tag, ftsInfo.u32_mpPassFlag);
+ ftsInfo.u32_featEn = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+ ftsInfo.u32_echoEn = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+ logError(1, "%s FEATURES = %08X \n", tag, ftsInfo.u32_echoEn);
+
+ logError(1, "%s Parsed %d bytes! \n", tag, index);
+
+ if (index != CHIP_INFO_SIZE + 3) {
+ logError(1, "%s readChipInfo: index = %d different from %d ERROR %02X\n", tag, index, CHIP_INFO_SIZE+3, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ logError(1, "%s Chip Info Read DONE!\n", tag);
+ return OK;
+
+FAIL:
+ defaultChipInfo(isI2cError(ret));
+ return ret;
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h
new file mode 100644
index 000000000000..c4cc5913fc18
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h
@@ -0,0 +1,146 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting Initialization Data *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsSoftware.h"
+
+#define COMP_DATA_READ_RETRY 2
+
+/* Bytes dimension of Compensation Data Format */
+
+#define COMP_DATA_HEADER 8
+#define COMP_DATA_GLOBAL 8
+
+#define HEADER_SIGNATURE 0xA5
+
+/* Possible Compensation/Frame Data Type */
+#define GENERAL_TUNING 0x0100
+#define MS_TOUCH_ACTIVE 0x0200
+#define MS_TOUCH_LOW_POWER 0x0400
+#define MS_TOUCH_ULTRA_LOW_POWER 0x0800
+#define MS_KEY 0x1000
+#define SS_TOUCH 0x2000
+#define SS_KEY 0x4000
+#define SS_HOVER 0x8000
+#define SS_PROXIMITY 0x0001
+#define CHIP_INFO 0xFFFF
+
+#define TIMEOUT_REQU_COMP_DATA 1000 /* ms */
+
+/* CHIP INFO */
+#define CHIP_INFO_SIZE 138/* bytes to read from framebuffer (exclude the signature and the type because already checked during the reading) */
+#define EXTERNAL_RELEASE_INFO_SIZE 8/* bytes */
+
+typedef struct {
+ int force_node, sense_node;
+ u16 type;
+} DataHeader;
+
+typedef struct {
+ DataHeader header;
+ u8 tuning_ver;
+ u8 cx1;
+ u8 *node_data;
+ int node_data_size;
+} MutualSenseData;
+
+typedef struct {
+ DataHeader header;
+ u8 tuning_ver;
+ u8 f_ix1, s_ix1;
+ u8 f_cx1, s_cx1;
+ u8 f_max_n, s_max_n;
+
+ u8 *ix2_fm;
+ u8 *ix2_sn;
+ u8 *cx2_fm;
+ u8 *cx2_sn;
+
+} SelfSenseData;
+
+typedef struct {
+ DataHeader header;
+ u8 ftsd_lp_timer_cal0;
+ u8 ftsd_lp_timer_cal1;
+ u8 ftsd_lp_timer_cal2;
+
+ u8 ftsd_lp_timer_cal3;
+ u8 ftsa_lp_timer_cal0;
+ u8 ftsa_lp_timer_cal1;
+
+} GeneralData;
+
+typedef struct {
+ u8 u8_loadCnt; /* 03 - Load Counter */
+ u8 u8_infoVer; /* 04 - New chip info version */
+ u16 u16_ftsdId; /* 05 - FTSD ID */
+ u8 u8_ftsdVer; /* 07 - FTSD version */
+ u8 u8_ftsaId; /* 08 - FTSA ID */
+ u8 u8_ftsaVer; /* 09 - FTSA version */
+ u8 u8_tchRptVer; /* 0A - Touch report version (e.g. ST, Samsung etc) */
+ u8 u8_extReleaseInfo[EXTERNAL_RELEASE_INFO_SIZE]; /* 0B - External release information */
+ u8 u8_custInfo[12]; /* 13 - Customer information */
+ u16 u16_fwVer; /* 1F - Firmware version */
+ u16 u16_cfgId; /* 21 - Configuration ID */
+ u32 u32_projId; /* 23 - Project ID */
+ u16 u16_scrXRes; /* 27 - X resolution on main screen */
+ u16 u16_scrYRes; /* 29 - Y resolution on main screen */
+ u8 u8_scrForceLen; /* 2B - Number of force channel on main screen */
+ u8 u8_scrSenseLen; /* 2C - Number of sense channel on main screen */
+ u8 u64_scrForceEn[8]; /* 2D - Force channel enabled on main screen */
+ u8 u64_scrSenseEn[8]; /* 35 - Sense channel enabled on main screen */
+ u8 u8_msKeyLen; /* 3D - Number of MS Key channel */
+ u8 u64_msKeyForceEn[8]; /* 3E - MS Key force channel enable */
+ u8 u64_msKeySenseEn[8]; /* 46 - MS Key sense channel enable */
+ u8 u8_ssKeyLen; /* 4E - Number of SS Key channel */
+ u8 u64_ssKeyForceEn[8]; /* 4F - SS Key force channel enable */
+ u8 u64_ssKeySenseEn[8]; /* 57 - SS Key sense channel enable */
+ u8 u8_frcTchXLen; /* 5F - Number of force touch force channel */
+ u8 u8_frcTchYLen; /* 60 - Number of force touch sense channel */
+ u8 u64_frcTchForceEn[8]; /* 61 - Force touch force channel enable */
+ u8 u64_frcTchSenseEn[8]; /* 69 - Force touch sense channel enable */
+ u8 u8_msScrConfigTuneVer; /* 71 - MS screen tuning version in config */
+ u8 u8_msScrLpConfigTuneVer; /* 72 - MS screen LP mode tuning version in config */
+ u8 u8_msScrHwulpConfigTuneVer; /* 73 - MS screen ultra low power mode tuning version in config */
+ u8 u8_msKeyConfigTuneVer; /* 74 - MS Key tuning version in config */
+ u8 u8_ssTchConfigTuneVer; /* 75 - SS touch tuning version in config */
+ u8 u8_ssKeyConfigTuneVer; /* 76 - SS Key tuning version in config */
+ u8 u8_ssHvrConfigTuneVer; /* 77 - SS hover tuning version in config */
+ u8 u8_frcTchConfigTuneVer; /* 78 - Force touch tuning version in config */
+ u8 u8_msScrCxmemTuneVer; /* 79 - MS screen tuning version in cxmem */
+ u8 u8_msScrLpCxmemTuneVer; /* 7A - MS screen LP mode tuning version in cxmem */
+ u8 u8_msScrHwulpCxmemTuneVer; /* 7B - MS screen ultra low power mode tuning version in cxmem */
+ u8 u8_msKeyCxmemTuneVer; /* 7C - MS Key tuning version in cxmem */
+ u8 u8_ssTchCxmemTuneVer; /* 7D - SS touch tuning version in cxmem */
+ u8 u8_ssKeyCxmemTuneVer; /* 7E - SS Key tuning version in cxmem */
+ u8 u8_ssHvrCxmemTuneVer; /* 7F - SS hover tuning version in cxmem */
+ u8 u8_frcTchCxmemTuneVer; /* 80 - Force touch tuning version in cxmem */
+ u32 u32_mpPassFlag; /* 81 - Mass production pass flag */
+ u32 u32_featEn; /* 85 - Supported features */
+ u32 u32_echoEn; /* 89 - enable of particular features: first bit is Echo Enables */
+} chipInfo;
+
+int requestCompensationData(u16 type);
+int readCompensationDataHeader(u16 type, DataHeader *header, u16 *address);
+int readMutualSenseGlobalData(u16 *address, MutualSenseData *global);
+int readMutualSenseNodeData(u16 address, MutualSenseData *node);
+int readMutualSenseCompensationData(u16 type, MutualSenseData *data);
+int readSelfSenseGlobalData(u16 *address, SelfSenseData *global);
+int readSelfSenseNodeData(u16 address, SelfSenseData *node);
+int readSelfSenseCompensationData(u16 type, SelfSenseData *data);
+int readGeneralGlobalData(u16 address, GeneralData *global);
+int readGeneralCompensationData(u16 type, GeneralData *data);
+int defaultChipInfo(int i2cError);
+int readChipInfo(int doRequest);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c
new file mode 100644
index 000000000000..502dace75e4f
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c
@@ -0,0 +1,43 @@
+#include "ftsCrossCompile.h"
+#include "ftsError.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/spi/spidev.h>
+#include <linux/fcntl.h>
+#include <linux/syscalls.h>
+
+/* static char tag[8]="[ FTS ]\0"; */
+void *stmalloc(size_t size)
+{
+ return kmalloc(size, GFP_KERNEL);
+
+}
+
+void stfree(void *ptr)
+{
+ kfree(ptr);
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h
new file mode 100644
index 000000000000..8b287dd342f8
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h
@@ -0,0 +1,34 @@
+/* #define NDK */
+/* #define DEBUG */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/spi/spidev.h>
+#include <linux/fcntl.h>
+#include <linux/syscalls.h>
+
+void *stmalloc(size_t size);
+void stfree(void *ptr);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsError.c b/drivers/input/touchscreen/st/fts_lib/ftsError.c
new file mode 100644
index 000000000000..844e5019fec6
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsError.c
@@ -0,0 +1,105 @@
+/*
+***************************************************************************
+* STMicroelectronics
+**************************************************************************
+* marco.cali@st.com
+**************************************************************************
+*
+* FTS error/info kernel log reporting
+*
+**************************************************************************
+**************************************************************************
+*/
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/completion.h>
+
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+
+#include "../fts.h"
+#include "ftsCrossCompile.h"
+#include "ftsError.h"
+#include "ftsIO.h"
+#include "ftsTool.h"
+
+void logError(int force, const char *msg, ...)
+{
+ if (force == 1
+#ifdef DEBUG
+ || 1
+#endif
+ ) {
+ va_list args;
+ va_start(args, msg);
+ vprintk(msg, args);
+ va_end(args);
+ }
+}
+
+int isI2cError(int error)
+{
+ if (((error & 0x000000FF) >= (ERROR_I2C_R & 0x000000FF)) && ((error & 0x000000FF) <= (ERROR_I2C_O & 0x000000FF)))
+ return 1;
+ else
+ return 0;
+}
+
+int errorHandler(u8 *event, int size)
+{
+ int res = OK;
+ struct fts_ts_info *info = NULL;
+
+ if (getClient() != NULL)
+ info = i2c_get_clientdata(getClient());
+
+ if (info != NULL && event != NULL && size > 1 && event[0] == EVENTID_ERROR_EVENT) {
+ logError(1, "%s errorHandler: Starting handling...\n", tag);
+ switch (event[1])
+ /* TODO: write an error log for undefinied command subtype 0xBA*/
+ {
+ case EVENT_TYPE_ESD_ERROR: /* esd */
+ res = fts_chip_powercycle(info);
+ if (res < OK) {
+ logError(1, "%s errorHandler: Error performing powercycle ERROR %08X\n", tag, res);
+ }
+
+ res = fts_system_reset();
+ if (res < OK) {
+ logError(1, "%s errorHandler: Cannot reset the device ERROR %08X\n", tag, res);
+ }
+ res = (ERROR_HANDLER_STOP_PROC|res);
+ break;
+
+ case EVENT_TYPE_WATCHDOG_ERROR: /* watchdog */
+ res = fts_system_reset();
+ if (res < OK) {
+ logError(1, "%s errorHandler: Cannot reset the device ERROR %08X\n", tag, res);
+ }
+ res = (ERROR_HANDLER_STOP_PROC|res);
+ break;
+
+ default:
+ logError(1, "%s errorHandler: No Action taken! \n", tag);
+ break;
+
+ }
+ logError(1, "%s errorHandler: handling Finished! res = %08X\n", tag, res);
+ return res;
+ }
+ logError(1, "%s errorHandler: event Null or not correct size! ERROR %08X \n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsError.h b/drivers/input/touchscreen/st/fts_lib/ftsError.h
new file mode 100644
index 000000000000..fc8fa5003158
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsError.h
@@ -0,0 +1,75 @@
+/*
+**************************************************************************
+** STMicroelectronics
+**************************************************************************
+** marco.cali@st.com
+**************************************************************************
+*
+* FTS error/info kernel log reporting
+*
+**************************************************************************
+**************************************************************************
+*/
+
+
+/*FIRST LEVEL ERROR CODE*/
+#define OK ((int)0x00000000) /*No ERROR*/
+#define ERROR_ALLOC ((int)0x80000001) /*allocation of memory failed*/
+#define ERROR_I2C_R ((int)0x80000002) /*i2c read failed*/
+#define ERROR_I2C_W ((int)0x80000003) /*i2c write failed*/
+#define ERROR_I2C_WR ((int)0x80000004) /*i2c write/read failed*/
+#define ERROR_I2C_O ((int)0x80000005) /*error during opening a i2c device*/
+#define ERROR_OP_NOT_ALLOW ((int)0x80000006) /*operation not allowed*/
+#define ERROR_TIMEOUT ((int)0x80000007) /*timeout expired! exceed the max number of retries or the max waiting time*/
+#define ERROR_FILE_NOT_FOUND ((int)0x80000008) /*the file that i want to open is not found*/
+#define ERROR_FILE_PARSE ((int)0x80000009) /*error during parsing the file*/
+#define ERROR_FILE_READ ((int)0x8000000A) /*error during reading the file*/
+#define ERROR_LABEL_NOT_FOUND ((int)0x8000000B) /*label not found*/
+#define ERROR_FW_NO_UPDATE ((int)0x8000000C) /*fw in the chip newer than the one in the memmh*/
+#define ERROR_FLASH_UNKNOWN ((int)0x8000000D) /*flash status busy or unknown*/
+
+/*SECOND LEVEL ERROR CODE*/
+#define ERROR_DISABLE_INTER ((int)0x80000200) /*unable to disable the interrupt*/
+#define ERROR_ENABLE_INTER ((int)0x80000300) /*unable to activate the interrup*/
+#define ERROR_READ_B2 ((int)0x80000400) /*B2 command failed*/
+#define ERROR_GET_OFFSET ((int)0x80000500) /*unable to read an offset from memory*/
+#define ERROR_GET_FRAME_DATA ((int)0x80000600) /*unable to retrieve the data of a required frame*/
+#define ERROR_DIFF_COMP_TYPE ((int)0x80000700) /*FW answers with an event that has a different address respect the request done*/
+#define ERROR_WRONG_COMP_SIGN ((int)0x80000800) /*the signature of the compensation data is not A5*/
+#define ERROR_SENSE_ON_FAIL ((int)0x80000900) /*the command Sense On failed*/
+#define ERROR_SENSE_OFF_FAIL ((int)0x80000A00) /*the command Sense Off failed*/
+#define ERROR_SYSTEM_RESET_FAIL ((int)0x80000B00) /*the command SYSTEM RESET failed*/
+#define ERROR_FLASH_NOT_READY ((int)0x80000C00) /*flash status not ready within a timeout*/
+#define ERROR_FW_VER_READ ((int)0x80000D00) /*unable to retrieve fw_vers or the config_id*/
+#define ERROR_GESTURE_ENABLE_FAIL ((int)0x80000E00) /*unable to enable/disable the gesture*/
+#define ERROR_GESTURE_START_ADD ((int)0x80000F00) /*unable to start to add custom gesture*/
+#define ERROR_GESTURE_FINISH_ADD ((int)0x80001000) /*unable to finish to add custom gesture*/
+#define ERROR_GESTURE_DATA_ADD ((int)0x80001100) /*unable to add custom gesture data*/
+#define ERROR_GESTURE_REMOVE ((int)0x80001200) /*unable to remove custom gesture data*/
+#define ERROR_FEATURE_ENABLE_DISABLE ((int)0x80001300) /*unable to enable/disable a feature mode in the IC*/
+/*THIRD LEVEL ERROR CODE*/
+#define ERROR_CH_LEN ((int)0x80010000) /*unable to retrieve the force and/or sense length*/
+#define ERROR_REQU_COMP_DATA ((int)0x80020000) /*compensation data request failed*/
+#define ERROR_COMP_DATA_HEADER ((int)0x80030000) /*unable to retrieve the compensation data header*/
+#define ERROR_COMP_DATA_GLOBAL ((int)0x80040000) /*unable to retrieve the global compensation data*/
+#define ERROR_COMP_DATA_NODE ((int)0x80050000) /*unable to retrieve the compensation data for each node*/
+#define ERROR_TEST_CHECK_FAIL ((int)0x80060000) /*check of production limits or of fw answers failed*/
+#define ERROR_MEMH_READ ((int)0x80070000) /*memh reading failed*/
+#define ERROR_FLASH_BURN_FAILED ((int)0x80080000) /*flash burn failed*/
+#define ERROR_MS_TUNING ((int)0x80090000) /*ms tuning failed*/
+#define ERROR_SS_TUNING ((int)0x800A0000) /*ss tuning failed*/
+#define ERROR_LP_TIMER_TUNING ((int)0x800B0000) /*lp timer calibration failed*/
+#define ERROR_SAVE_CX_TUNING ((int)0x800C0000) /*save cx data to flash failed*/
+#define ERROR_HANDLER_STOP_PROC ((int)0x800D0000) /*stop the poll of the FIFO if particular errors are found*/
+#define ERROR_CHECK_ECHO_FAIL ((int)0x800E0000) /*unable to retrieve echo event*/
+
+/*FOURTH LEVEL ERROR CODE*/
+#define ERROR_PROD_TEST_DATA ((int)0x81000000) /*production data test failed*/
+#define ERROR_FLASH_PROCEDURE ((int)0x82000000) /*complete flash procedure failed*/
+#define ERROR_PROD_TEST_ITO ((int)0x83000000) /*production ito test failed*/
+#define ERROR_PROD_TEST_INITIALIZATION ((int)0x84000000) /*production initialization test failed*/
+#define ERROR_GET_INIT_STATUS ((int)0x85000000) /*mismatch of the MS or SS tuning_version*/
+
+void logError(int force, const char *msg, ...);
+int isI2cError(int error);
+int errorHandler(u8 *event, int size);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c
new file mode 100644
index 000000000000..59c73f4c4edb
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c
@@ -0,0 +1,1071 @@
+/*
+
+ **************************************************************************
+ ** STMicroelectronics **
+ **************************************************************************
+ ** marco.cali@st.com **
+ **************************************************************************
+ * *
+ * FTS API for Flashing the IC *
+ * *
+ **************************************************************************
+ **************************************************************************
+
+ */
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.h"
+#include "ftsError.h"
+#include "ftsFlash.h"
+#include "ftsFrame.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTest.h"
+#include "ftsTime.h"
+#include "ftsTool.h"
+#include "../fts.h" /* needed for the FW_H_FILE define */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+#ifdef FW_H_FILE
+#include <../fts_fw.h>
+#endif
+
+/* static char tag[8] = "[ FTS ]\0"; */
+extern chipInfo ftsInfo;
+
+int getFirmwareVersion(u16 *fw_vers, u16 *config_id)
+{
+ u8 fwvers[DCHIP_FW_VER_BYTE];
+ u8 confid[CONFIG_ID_BYTE];
+ int res;
+
+ res = readCmdU16(FTS_CMD_HW_REG_R, DCHIP_FW_VER_ADDR, fwvers, DCHIP_FW_VER_BYTE, DUMMY_HW_REG);
+ if (res < OK) {
+ logError(1, "%s getFirmwareVersion: unable to read fw_version ERROR %02X\n", tag, ERROR_FW_VER_READ);
+ return (res | ERROR_FW_VER_READ);
+ }
+
+ u8ToU16(fwvers, fw_vers); /* fw version use big endian */
+ if (*fw_vers != 0) { /* if fw_version is 00 00 means that there is no firmware running in the chip therefore will be impossible find the config_id */
+ res = readB2(CONFIG_ID_ADDR, confid, CONFIG_ID_BYTE);
+ if (res < OK) {
+ logError(1, "%s getFirmwareVersion: unable to read config_id ERROR %02X\n", tag, ERROR_FW_VER_READ);
+ return (res | ERROR_FW_VER_READ);
+ }
+ u8ToU16(confid, config_id); /* config id use little endian */
+ } else {
+ *config_id = 0x0000;
+ }
+
+ logError(0, "%s FW VERS = %04X\n", tag, *fw_vers);
+ logError(0, "%s CONFIG ID = %04X\n", tag, *config_id);
+ return OK;
+
+}
+
+#ifdef FTM3_CHIP
+
+int flash_status(void)
+{
+ u8 cmd[2] = {FLASH_CMD_READSTATUS, 0x00};
+ u8 readData;
+
+ logError(0, "%s Reading flash_status...\n", tag);
+ if (fts_readCmd(cmd, 2, &readData, FLASH_STATUS_BYTES) < 0) {
+ logError(1, "%s flash_status: ERROR % 02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ readData &= 0x01;
+ /* logError(0, "%s flash_status = %d\n", tag,readData); */
+ return (int) readData;
+
+}
+
+int flash_status_ready(void)
+{
+
+ int status = flash_status();
+
+ if (status == ERROR_I2C_R) {
+ logError(1, "%s flash_status_ready: ERROR % 02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ if (status != FLASH_READY) {
+ logError(1, "%s flash_status_ready: flash busy or unknown STATUS = % 02X\n", tag, status);
+ return ERROR_FLASH_UNKNOWN;
+ }
+
+ return FLASH_READY;
+
+}
+
+int wait_for_flash_ready(void)
+{
+ int status;
+ int(*code)(void);
+
+ code = flash_status_ready;
+
+ logError(0, "%s Waiting for flash ready...\n", tag);
+ status = attempt_function(code, FLASH_WAIT_BEFORE_RETRY, FLASH_RETRY_COUNT);
+
+ if (status != FLASH_READY) {
+ logError(1, "%s wait_for_flash_ready: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY);
+ }
+
+ logError(0, "%s Flash ready!\n", tag);
+ return OK;
+}
+
+int flash_unlock(void)
+{
+
+ int status;
+ u8 cmd[3] = {FLASH_CMD_UNLOCK, FLASH_UNLOCK_CODE0, FLASH_UNLOCK_CODE1}; /* write the comand to perform the unlock */
+
+ logError(0, "%s Try to unlock flash...\n", tag);
+ status = wait_for_flash_ready();
+
+ if (status != OK) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY); /* Flash not ready within the choosen time, better exit! */
+ }
+
+ logError(0, "%s Command unlock ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ status = wait_for_flash_ready();
+
+ if (status != OK) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY); /* Flash not ready within the choosen time, better exit! */
+ }
+
+ logError(0, "%s Unlock flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+/*int parseMemhFile(const char *pathToFile, u8** data, int* length, int dimension)
+{
+
+ int i = 0;
+ unsigned long ul;
+ u8* buff = NULL;
+ int fd = -1;
+ int n, size, pointer = 0;
+ char *data_file, *line;
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+
+ line = (char *) kmalloc(11 * sizeof (char), GFP_KERNEL);
+ if (line == NULL) {
+ logError(1, "%s parseMemhFile: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ logError(0, "%s parseMemhFile: allocating %d bytes\n", tag, dimension);
+ buff = (u8*) kmalloc(dimension * sizeof (u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s parseMemhFile: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ dev = getDev();
+ if (dev != NULL)
+ fd = request_firmware(&fw, pathToFile, dev);
+
+ if (fd == 0) {
+ size = fw->size;
+ logError(0, "%s The size of the firmware file is %d bytes...\n", tag, size);
+ data_file = (char *) fw->data;
+ logError(0, "%s Start to reading %s...\n", tag, pathToFile);
+
+ while (size - pointer > 0 && (i * 4 + 4) <= dimension) {
+ if (readLine(&data_file[pointer], &line, size - pointer, &n) < 0) {
+ break;
+ }
+ pointer += n;
+ logError(0, "%s Pointer= %d riga = %s\n", tag, pointer, line);
+ ul = simple_strtoul(line, NULL, 16);
+
+ buff[i * 4] = (u8) ((ul & 0x000000FF) >> 0);
+ buff[i * 4 + 1] = (u8) ((ul & 0x0000FF00) >> 8);
+ buff[i * 4 + 2] = (u8) ((ul & 0x00FF0000) >> 16);
+ buff[i * 4 + 3] = (u8) ((ul & 0xFF000000) >> 24);
+ i++;
+ }
+
+ kfree(line);
+
+ *length = i * 4;
+ if (*length < dimension) {
+ logError(1, "%s parseMemhFile: Read only %d instead of %d... ERROR %02X\n", tag, *length, dimension, ERROR_FILE_PARSE);
+ release_firmware(fw);
+ return ERROR_FILE_PARSE;
+ }
+ *data = buff;
+
+ logError(0, "%s READ DONE %d bytes!\n", tag, *length);
+ release_firmware(fw);
+ return OK;
+ } else {
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+}*/
+
+int parseBinFile(const char *pathToFile, u8 **data, int *length, int dimension)
+{
+
+ int fd = -1;
+ int fw_size = 0;
+ u8 *fw_data = NULL;
+
+#ifndef FW_H_FILE
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+ dev = getDev();
+
+ if (dev != NULL)
+ fd = request_firmware(&fw, pathToFile, dev);
+ else {
+ logError(1, "%s parseBinFile: No device found! ERROR %02X\n", ERROR_FILE_PARSE);
+ return ERROR_FILE_PARSE;
+ }
+#else
+ fd = 0;
+#endif
+
+ if (fd == 0) {
+#ifndef FW_H_FILE
+ fw_size = fw->size;
+ fw_data = (u8 *) (fw->data);
+#else
+ fw_size = FW_SIZE_NAME;
+ fw_data = (u8 *) FW_ARRAY_NAME;
+#endif
+ if (fw_size - FW_HEADER_SIZE != FW_SIZE) {
+ logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, FW_SIZE, ERROR_FILE_PARSE);
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return ERROR_FILE_PARSE;
+ }
+ *data = (u8 *) kmalloc(dimension * sizeof (u8), GFP_KERNEL);
+ if (*data == NULL) {
+ logError(1, "%s parseBinFile: ERROR %02X\n", tag, ERROR_ALLOC);
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return ERROR_ALLOC;
+ }
+
+ memcpy(*data, ((u8 *) (fw_data) + FW_HEADER_SIZE), dimension);
+ *length = dimension;
+
+ logError(0, "%s READ FW DONE %d bytes!\n", tag, *length);
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return OK;
+ }
+ logError(1, "%s parseBinFile: File Not Found! ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+}
+
+int readFwFile(const char *path, Firmware *fw, int keep_cx)
+{
+ int res;
+ int size;
+
+ if (keep_cx) {
+ size = FW_SIZE - FW_CX_SIZE;
+ logError(1, "%s readFwFile: Selected 124k Configuration!\n", tag);
+ } else {
+ size = FW_SIZE;
+ logError(1, "%s readFwFile: Selected 128k Configuration!\n", tag);
+ }
+
+ /* res = parseMemhFile(path, &(fw->data), &(fw->data_size), size); */
+ res = parseBinFile(path, &(fw->data), &(fw->data_size), size);
+ if (res < OK) {
+ logError(1, "%s readFwFile: ERROR %02X\n", tag, ERROR_MEMH_READ);
+ return (res | ERROR_MEMH_READ);
+ }
+
+ fw->fw_ver = (u16) (((fw->data[FW_VER_MEMH_BYTE1] & 0x00FF) << 8) + (fw->data[FW_VER_MEMH_BYTE0] & 0x00FF));
+ fw->config_id = (u16) (((fw->data[(FW_CODE_SIZE) + FW_OFF_CONFID_MEMH_BYTE1] & 0x00FF) << 8) + (fw->data[(FW_CODE_SIZE) + FW_OFF_CONFID_MEMH_BYTE0] & 0x00FF));
+
+ logError(0, "%s FW VERS File = %04X\n", tag, fw->fw_ver);
+ logError(0, "%s CONFIG ID File = %04X\n", tag, fw->config_id);
+ return OK;
+
+}
+
+int fillMemory(u32 address, u8 *data, int size)
+{
+
+ int remaining = size;
+ int toWrite = 0;
+
+ u8 *buff = (u8 *) kmalloc((MEMORY_CHUNK + 3) * sizeof (u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s fillMemory: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ if (remaining >= MEMORY_CHUNK) {
+ if ((address + MEMORY_CHUNK) < FLASH_ADDR_SWITCH_CMD) {
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = MEMORY_CHUNK;
+ remaining -= MEMORY_CHUNK;
+ } else {
+ if (address < FLASH_ADDR_SWITCH_CMD) {
+ int delta = FLASH_ADDR_SWITCH_CMD - address;
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = delta;
+ remaining -= delta;
+ } else {
+ buff[0] = FLASH_CMD_WRITE_UPPER_64;
+ toWrite = MEMORY_CHUNK;
+ remaining -= MEMORY_CHUNK;
+ }
+ }
+ } else {
+ if ((address + remaining) < FLASH_ADDR_SWITCH_CMD) {
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = remaining;
+ remaining = 0;
+ } else {
+ if (address < FLASH_ADDR_SWITCH_CMD) {
+ int delta = FLASH_ADDR_SWITCH_CMD - address;
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = delta;
+ remaining -= delta;
+ } else {
+ buff[0] = FLASH_CMD_WRITE_UPPER_64;
+ toWrite = remaining;
+ remaining = 0;
+ }
+ }
+ }
+
+ buff[1] = (u8) ((address & 0x0000FF00) >> 8);
+ buff[2] = (u8) (address & 0x000000FF);
+ memcpy(buff + 3, data, toWrite);
+ logError(0, "%s Command = %02X , address = %02X %02X, bytes = %d\n", tag, buff[0], buff[1], buff[2], toWrite);
+ if (fts_writeCmd(buff, 3 + toWrite) < 0) {
+ logError(1, "%s fillMemory: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ address += toWrite;
+ data += toWrite;
+
+ }
+ return OK;
+}
+
+int flash_burn(Firmware fw, int force_burn)
+{
+ u8 cmd;
+ int res;
+
+ if (!force_burn && (ftsInfo.u16_fwVer >= fw.fw_ver) && (ftsInfo.u16_cfgId >= fw.config_id)) {
+ logError(1, "%s flash_burn: Firmware in the chip newer or equal to the one to burn! NO UPDATE ERROR %02X\n", tag, ERROR_FW_NO_UPDATE);
+ return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED);
+ }
+
+ /* programming procedure start */
+
+ logError(0, "%s Programming Procedure for flashing started:\n\n", tag);
+
+ logError(0, "%s 1) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED!\n", tag);
+ if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT)) /* if there is no firmware i will not get the controller ready event and there will be a timeout but i can keep going, but if there is an I2C error i have to exit */
+ return (res | ERROR_FLASH_BURN_FAILED);
+ } else
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 2) FLASH UNLOCK:\n", tag);
+ res = flash_unlock();
+ if (res < 0) {
+ logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash unlock COMPLETED!\n\n", tag);
+
+ /* Write the lower part of the Program RAM */
+ logError(0, "%s 3) PREPARING DATA FOR FLASH BURN:\n", tag);
+
+ res = fillMemory(FLASH_ADDR_CODE, fw.data, fw.data_size);
+ if (res < 0) {
+ logError(1, "%s Error During filling the memory! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s Data copy COMPLETED!\n\n", tag);
+
+ logError(0, "%s 4) ERASE FLASH:\n", tag);
+ res = wait_for_flash_ready();
+ if (res < 0) {
+ logError(1, "%s Flash not ready! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ logError(0, "%s Command erase ...\n", tag);
+ cmd = FLASH_CMD_ERASE;
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s Error during erasing flash! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (ERROR_I2C_W | ERROR_FLASH_BURN_FAILED);
+ }
+
+ res = wait_for_flash_ready();
+ if (res < 0) {
+ logError(1, "%s Flash not ready 2! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ logError(0, "%s Flash erase COMPLETED!\n\n", tag);
+
+ logError(0, "%s 5) BURN FLASH:\n", tag);
+ logError(0, "%s Command burn ...\n", tag);
+ cmd = FLASH_CMD_BURN;
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s Error during burning data! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (ERROR_I2C_W | ERROR_FLASH_BURN_FAILED);
+ }
+
+ res = wait_for_flash_ready();
+ if (res < 0) {
+ logError(1, "%s Flash not ready! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ logError(0, "%s Flash burn COMPLETED!\n\n", tag);
+
+ logError(0, "%s 6) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 7) FINAL CHECK:\n", tag);
+ res = readChipInfo(0);
+ if (res < 0) {
+ logError(1, "%s flash_burn: Unable to retrieve Chip INFO! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ if ((ftsInfo.u16_fwVer != fw.fw_ver) && (ftsInfo.u16_cfgId != fw.config_id)) {
+ logError(1, "%s Firmware in the chip different from the one that was burn! fw: %x != %x , conf: %x != %x\n", tag, ftsInfo.u16_fwVer, fw.fw_ver, ftsInfo.u16_cfgId, fw.config_id);
+ return ERROR_FLASH_BURN_FAILED;
+ }
+
+ logError(0, "%s Final check OK! fw: %02X , conf: %02X\n", tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId);
+
+ return OK;
+}
+
+int flashProcedure(const char *path, int force, int keep_cx)
+{
+ Firmware fw;
+ int res;
+
+ fw.data = NULL;
+ logError(0, "%s Reading Fw file...\n", tag);
+ res = readFwFile(path, &fw, keep_cx);
+ if (res < OK) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, (res | ERROR_FLASH_PROCEDURE));
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s Fw file read COMPLETED!\n", tag);
+
+ logError(0, "%s Starting flashing procedure...\n", tag);
+ res = flash_burn(fw, force);
+ if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, ERROR_FLASH_PROCEDURE);
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s flashing procedure Finished!\n", tag);
+ kfree(fw.data);
+
+ /* cleanUp(0); //after talking with Kusuma, the SenseOn should be issued only at the very end of the initialization process, if senso on here it can trigger autotune protection */
+ return res;
+}
+
+#else
+
+int wait_for_flash_ready(u8 type)
+{
+ u8 cmd[2] = {FLASH_CMD_READ_REGISTER, type};
+ u8 readData;
+ int i, res = -1;
+
+ logError(0, "%s Waiting for flash ready ...\n", tag);
+ for (i = 0; i < FLASH_RETRY_COUNT && res != 0; i++) {
+ if (fts_readCmd(cmd, sizeof (cmd), &readData, 1) < 0) {
+ logError(1, "%s wait_for_flash_ready: ERROR % 02X\n", tag, ERROR_I2C_W);
+ } else{
+ res = readData & 0x80;
+ /* logError(0, "%s flash status = %d \n", tag, res); */
+ }
+ msleep(FLASH_WAIT_BEFORE_RETRY);
+ }
+
+ if (i == FLASH_RETRY_COUNT && res != 0) {
+ logError(1, "%s Wait for flash TIMEOUT! ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+
+ logError(0, "%s Flash READY!\n", tag);
+ return OK;
+}
+
+int fts_warm_boot(void)
+{
+
+ u8 cmd[4] = {FTS_CMD_HW_REG_W, 0x00, 0x00, WARM_BOOT_VALUE}; /* write the command to perform the warm boot */
+ u16ToU8_be(ADDR_WARM_BOOT, &cmd[1]);
+
+ logError(0, "%s Command warm boot ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ logError(0, "%s Warm boot DONE!\n", tag);
+
+ return OK;
+}
+
+int parseBinFile(const char *pathToFile, Firmware *fwData, int keep_cx)
+{
+
+ int fd = -1;
+ int dimension, index = 0;
+ u32 temp;
+ u8 *data;
+ int res, i, fw_size;
+
+#ifndef FW_H_FILE
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+ dev = getDev();
+
+ if (dev != NULL)
+ fd = request_firmware(&fw, pathToFile, dev);
+ else {
+ logError(1, "%s parseBinFile: No device found! ERROR %02X\n", ERROR_FILE_PARSE);
+ return ERROR_FILE_PARSE;
+ }
+
+ fw_size = fw->size;
+#else
+fd = 0;
+fw_size = SIZE_NAME;
+#endif
+
+ if (fd == 0 && fw_size > 0) { /* the file should contain at least the header plus the content_crc */
+ if (fw_size < FW_HEADER_SIZE+FW_BYTES_ALIGN) {
+ logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, FW_HEADER_SIZE+FW_BYTES_ALIGN, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ } else {
+ /* start parsing of bytes */
+#ifndef FW_H_FILE
+ data = (u8 *) (fw->data);
+#else
+ data = (u8 *) (ARRAY_NAME);
+#endif
+ u8ToU32(&data[index], &temp);
+ if (temp != FW_HEADER_SIGNATURE) {
+ logError(1, "%s parseBinFile: Wrong Signature %08X ... ERROR %02X\n", tag, temp, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+ logError(0, "%s parseBinFile: Fw Signature OK!\n", tag);
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ if (temp != FW_FTB_VER) {
+ logError(1, "%s parseBinFile: Wrong ftb_version %08X ... ERROR %02X\n", tag, temp, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+ logError(0, "%s parseBinFile: ftb_version OK!\n", tag);
+ index += FW_BYTES_ALIGN;
+ if (data[index] != DCHIP_ID_0 || data[index+1] != DCHIP_ID_1) {
+ logError(1, "%s parseBinFile: Wrong target %02X != %02X %02X != %02X ... ERROR %08X\n", tag, data[index], DCHIP_ID_0, data[index+1], DCHIP_ID_1, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ logError(1, "%s parseBinFile: Fw ID = %08X\n", tag, temp);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->fw_ver = temp;
+ logError(1, "%s parseBinFile: FILE Fw Version = %04X\n", tag, fwData->fw_ver);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->config_id = temp;
+ logError(1, "%s parseBinFile: FILE Config ID = %08X\n", tag, temp);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ logError(1, "%s parseBinFile: Config Version = %08X\n", tag, temp);
+
+ index += FW_BYTES_ALIGN*2; /* skip reserved data */
+
+ index += FW_BYTES_ALIGN;
+ logError(1, "%s parseBinFile: File External Release = ", tag);
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ fwData->externalRelease[i] = data[index++];
+ logError(1, "%02X ", fwData->externalRelease[i]);
+ }
+ logError(1, "\n");
+
+ /* index += FW_BYTES_ALIGN; */
+ u8ToU32(&data[index], &temp);
+ fwData->sec0_size = temp;
+ logError(1, "%s parseBinFile: sec0_size = %08X (%d bytes)\n", tag, fwData->sec0_size, fwData->sec0_size);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->sec1_size = temp;
+ logError(1, "%s parseBinFile: sec1_size = %08X (%d bytes)\n", tag, fwData->sec1_size, fwData->sec1_size);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->sec2_size = temp;
+ logError(1, "%s parseBinFile: sec2_size = %08X (%d bytes)\n", tag, fwData->sec2_size, fwData->sec2_size);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->sec3_size = temp;
+ logError(1, "%s parseBinFile: sec3_size = %08X (%d bytes)\n", tag, fwData->sec3_size, fwData->sec3_size);
+
+ index += FW_BYTES_ALIGN; /* skip header crc */
+
+ if (!keep_cx) {
+ dimension = fwData->sec0_size + fwData->sec1_size + fwData->sec2_size + fwData->sec3_size;
+ temp = fw_size;
+ } else {
+ dimension = fwData->sec0_size + fwData->sec1_size; /* sec2 may contain cx data (future implementation) sec3 atm not used */
+ temp = fw_size - fwData->sec2_size - fwData->sec3_size;
+ }
+
+ if (dimension+FW_HEADER_SIZE+FW_BYTES_ALIGN != temp) {
+ logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, dimension+FW_HEADER_SIZE+FW_BYTES_ALIGN, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+
+ fwData->data = (u8 *) kmalloc(dimension * sizeof (u8), GFP_KERNEL);
+ if (fwData->data == NULL) {
+ logError(1, "%s parseBinFile: ERROR %02X\n", tag, ERROR_ALLOC);
+ res = ERROR_ALLOC;
+ goto END;
+ }
+
+ index += FW_BYTES_ALIGN;
+ memcpy(fwData->data, &data[index], dimension);
+ fwData->data_size = dimension;
+
+ logError(0, "%s READ FW DONE %d bytes!\n", tag, fwData->data_size);
+ res = OK;
+ goto END;
+ }
+ } else {
+ logError(1, "%s parseBinFile: File Not Found! ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+END:
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return res;
+}
+
+int readFwFile(const char *path, Firmware *fw, int keep_cx)
+{
+ int res;
+
+ res = parseBinFile(path, fw, keep_cx);
+ if (res < OK) {
+ logError(1, "%s readFwFile: ERROR %02X\n", tag, ERROR_MEMH_READ);
+ return (res | ERROR_MEMH_READ);
+ }
+
+ return OK;
+
+}
+
+int flash_unlock(void)
+{
+ u8 cmd[3] = {FLASH_CMD_UNLOCK, FLASH_UNLOCK_CODE0, FLASH_UNLOCK_CODE1}; /* write the command to perform the unlock */
+
+ logError(0, "%s Command unlock ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s Unlock flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+int flash_erase_unlock(void)
+{
+ u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_UNLOCK_CODE0, FLASH_ERASE_UNLOCK_CODE1}; /* write the command to perform the unlock for erasing the flash */
+
+ logError(0, "%s Try to erase unlock flash...\n", tag);
+
+ logError(0, "%s Command erase unlock ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_erase_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ logError(0, "%s Erase Unlock flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+int flash_full_erase(void)
+{
+
+ int status;
+ u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_CODE0, FLASH_ERASE_CODE1};
+ /* write the command to erase the flash */
+
+ logError(0, "%s Command full erase sent ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_full_erase: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ status = wait_for_flash_ready(FLASH_ERASE_CODE0);
+
+ if (status != OK) {
+ logError(1, "%s flash_full_erase: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY);
+ /* Flash not ready within the chosen time, better exit! */
+ }
+
+ logError(0, "%s Full Erase flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+int start_flash_dma(void)
+{
+ int status;
+ u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_DMA_CODE0, FLASH_DMA_CODE1};
+ /* write the command to erase the flash */
+
+ logError(0, "%s Command flash DMA ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s start_flash_dma: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ status = wait_for_flash_ready(FLASH_DMA_CODE0);
+
+ if (status != OK) {
+ logError(1, "%s start_flash_dma: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY);
+ /* Flash not ready within the chosen time, better exit! */
+ }
+
+ logError(0, "%s flash DMA DONE!\n", tag);
+
+ return OK;
+}
+
+int fillFlash(u32 address, u8 *data, int size)
+{
+
+ int remaining = size;
+ int toWrite = 0;
+ int byteBlock = 0;
+ int wheel = 0;
+ u32 addr = 0;
+ int res;
+ int delta;
+
+ u8 *buff = (u8 *) kmalloc((DMA_CHUNK + 3) * sizeof (u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s fillFlash: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ byteBlock = 0;
+ addr = 0;
+ while (byteBlock < FLASH_CHUNK && remaining > 0) {
+ buff[0] = FLASH_CMD_WRITE_64K;
+ if (remaining >= DMA_CHUNK) {
+ if ((byteBlock + DMA_CHUNK) <= FLASH_CHUNK) {
+ /* logError(1, "%s fillFlash: 1\n", tag); */
+ toWrite = DMA_CHUNK;
+ remaining -= DMA_CHUNK;
+ byteBlock += DMA_CHUNK;
+ } else {
+ /* logError(1, "%s fillFlash: 2\n", tag); */
+ delta = FLASH_CHUNK - byteBlock;
+ toWrite = delta;
+ remaining -= delta;
+ byteBlock += delta;
+ }
+ } else {
+ if ((byteBlock + remaining) <= FLASH_CHUNK) {
+ /* logError(1, "%s fillFlash: 3\n", tag); */
+ toWrite = remaining;
+ byteBlock += remaining;
+ remaining = 0;
+
+ } else {
+ /* logError(1, "%s fillFlash: 4\n", tag); */
+ delta = FLASH_CHUNK - byteBlock;
+ toWrite = delta;
+ remaining -= delta;
+ byteBlock += delta;
+ }
+ }
+
+ buff[1] = (u8) ((addr & 0x0000FF00) >> 8);
+ buff[2] = (u8) (addr & 0x000000FF);
+ memcpy(&buff[3], data, toWrite);
+ if (fts_writeCmd(buff, 3 + toWrite) < 0) {
+ logError(1, "%s fillFlash: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ addr += toWrite;
+ data += toWrite;
+ }
+
+ kfree(buff);
+
+ /* configuring the DMA */
+ byteBlock = byteBlock / 4 - 1;
+
+ buff = (u8 *) kmalloc((9) * sizeof (u8), GFP_KERNEL);
+ buff[0] = FLASH_CMD_WRITE_REGISTER;
+ buff[1] = FLASH_DMA_CONFIG;
+ buff[2] = 0x00;
+ buff[3] = 0x00;
+
+ addr = address + ((wheel * FLASH_CHUNK)/4);
+ buff[4] = (u8) ((addr & 0x000000FF));
+ buff[5] = (u8) ((addr & 0x0000FF00) >> 8);
+ buff[6] = (u8) (byteBlock & 0x000000FF);
+ buff[7] = (u8) ((byteBlock & 0x0000FF00) >> 8);
+ buff[8] = 0x00;
+
+ logError(0, "%s Command = %02X , address = %02X %02X, words = %02X %02X\n", tag, buff[0], buff[5], buff[4], buff[7], buff[6]);
+ if (fts_writeCmd(buff, 9) < OK) {
+ logError(1, "%s Error during filling Flash! ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ /* msleep(FLASH_WAIT_TIME); */
+ res = start_flash_dma();
+ if (res < OK) {
+ logError(1, "%s Error during flashing DMA! ERROR %02X\n", tag, res);
+ return res;
+ }
+ wheel++;
+ }
+ return OK;
+}
+
+int flash_burn(Firmware fw, int force_burn)
+{
+ int res;
+
+ if (!force_burn) {
+ for (res = EXTERNAL_RELEASE_INFO_SIZE-1; res >= 0; res--) {
+ if (fw.externalRelease[res] > ftsInfo.u8_extReleaseInfo[res])
+ goto start;
+ }
+ logError(1, "%s flash_burn: Firmware in the chip newer or equal to the one to burn! NO UPDATE ERROR %02X\n", tag, ERROR_FW_NO_UPDATE);
+ return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED);
+ }
+
+ /* programming procedure start */
+start:
+ logError(0, "%s Programming Procedure for flashing started:\n\n", tag);
+
+ logError(0, "%s 1) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED!\n", tag);
+ if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT))
+ /* if there is no firmware i will not get the controller
+ *ready event and there will be a timeout but i can keep going,
+ *but if there is an I2C error i have to exit
+ */
+ return (res | ERROR_FLASH_BURN_FAILED);
+ } else
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 2) WARM BOOT:\n", tag);
+ res = fts_warm_boot();
+ if (res < OK) {
+ logError(1, "%s warm boot FAILED!\n", tag);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ } else
+ logError(0, "%s warm boot COMPLETED!\n\n", tag);
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s 3) FLASH UNLOCK:\n", tag);
+ res = flash_unlock();
+ if (res < OK) {
+ logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash unlock COMPLETED!\n\n", tag);
+
+ /* msleep(200); */
+ logError(0, "%s 4) FLASH ERASE UNLOCK:\n", tag);
+ res = flash_erase_unlock();
+ if (res < 0) {
+ logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash unlock COMPLETED!\n\n", tag);
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s 5) FLASH ERASE:\n", tag);
+ res = flash_full_erase();
+ if (res < 0) {
+ logError(1, "%s flash erase FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash erase COMPLETED!\n\n", tag);
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s 6) LOAD PROGRAM:\n", tag);
+ res = fillFlash(FLASH_ADDR_CODE, &fw.data[0], fw.sec0_size);
+ if (res < OK) {
+ logError(1, "%s load program ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(1, "%s load program DONE!\n", tag);
+
+ logError(0, "%s 7) LOAD CONFIG:\n", tag);
+ res = fillFlash(FLASH_ADDR_CONFIG, &(fw.data[fw.sec0_size]), fw.sec1_size);
+ if (res < OK) {
+ logError(1, "%s load config ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(1, "%s load config DONE!\n", tag);
+
+ logError(0, "%s Flash burn COMPLETED!\n\n", tag);
+
+ logError(0, "%s 8) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 9) FINAL CHECK:\n", tag);
+ res = readChipInfo(0);
+ if (res < 0) {
+ logError(1, "%s flash_burn: Unable to retrieve Chip INFO! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ for (res = 0; res < EXTERNAL_RELEASE_INFO_SIZE; res++) {
+ if (fw.externalRelease[res] != ftsInfo.u8_extReleaseInfo[res]) {
+ /* external release is prined during readChipInfo */
+ logError(1, "%s Firmware in the chip different from the one that was burn! fw: %x != %x , conf: %x != %x\n", tag, ftsInfo.u16_fwVer, fw.fw_ver, ftsInfo.u16_cfgId, fw.config_id);
+ return ERROR_FLASH_BURN_FAILED;
+ }
+ }
+
+ logError(0, "%s Final check OK! fw: %02X, conf: %02X\n", tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId);
+
+ return OK;
+}
+
+int flashProcedure(const char *path, int force, int keep_cx)
+{
+ Firmware fw;
+ int res;
+
+ fw.data = NULL;
+ logError(0, "%s Reading Fw file...\n", tag);
+ res = readFwFile(path, &fw, keep_cx);
+ if (res < OK) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, (res | ERROR_FLASH_PROCEDURE));
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s Fw file read COMPLETED!\n", tag);
+
+ logError(0, "%s Starting flashing procedure...\n", tag);
+ res = flash_burn(fw, force);
+ if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, ERROR_FLASH_PROCEDURE);
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s flashing procedure Finished!\n", tag);
+ kfree(fw.data);
+ return res;
+}
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.h b/drivers/input/touchscreen/st/fts_lib/ftsFlash.h
new file mode 100644
index 000000000000..69635e07a9f4
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.h
@@ -0,0 +1,79 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS API for Flashing the IC *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+
+/* Flash possible status */
+#define FLASH_READY 0
+#define FLASH_BUSY 1
+#define FLASH_UNKNOWN -1
+
+#define FLASH_STATUS_BYTES 1
+
+/* Flash timing parameters */
+#define FLASH_RETRY_COUNT 1000
+#define FLASH_WAIT_BEFORE_RETRY 50 /* ms */
+
+#define FLASH_WAIT_TIME 200 /* ms */
+
+/* PATHS FW FILES */
+/* #define PATH_FILE_FW "fw.memh" */
+#ifdef FTM3_CHIP
+#define PATH_FILE_FW "st_fts.bin"
+#else
+#define PATH_FILE_FW "st_fts.ftb" /* new bin file structure */
+#endif
+
+#ifndef FTM3_CHIP
+#define FLASH_CHUNK (64*1024)
+#define DMA_CHUNK 32
+#endif
+
+typedef struct {
+ u8 *data;
+ u16 fw_ver;
+ u16 config_id;
+ u8 externalRelease[EXTERNAL_RELEASE_INFO_SIZE];
+ int data_size;
+#ifndef FTM3_CHIP
+ u32 sec0_size;
+ u32 sec1_size;
+ u32 sec2_size;
+ u32 sec3_size;
+#endif
+} Firmware;
+
+#ifdef FTM3_CHIP
+int flash_status(void);
+int flash_status_ready(void);
+int wait_for_flash_ready(void);
+int parseBinFile(const char *pathToFile, u8 **data, int *length, int dimension);
+/* int parseMemhFile(const char* pathToFile, u8** data, int* length, int dimension); */
+#else
+int wait_for_flash_ready(u8 type);
+int fts_warm_boot(void);
+int parseBinFile(const char *pathToFile, Firmware *fw, int keep_cx);
+int flash_erase_unlock(void);
+int flash_full_erase(void);
+int start_flash_dma(void);
+int fillFlash(u32 address, u8 *data, int size);
+#endif
+
+int flash_unlock(void);
+int fillMemory(u32 address, u8 *data, int size);
+int getFirmwareVersion(u16 *fw_vers, u16 *config_id);
+int readFwFile(const char *path, Firmware *fw, int keep_cx);
+int flash_burn(Firmware fw, int force_burn);
+int flashProcedure(const char *path, int force, int keep_cx);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFrame.c b/drivers/input/touchscreen/st/fts_lib/ftsFrame.c
new file mode 100644
index 000000000000..c502559319a0
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFrame.c
@@ -0,0 +1,569 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting frames *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.h"
+#include "ftsError.h"
+#include "ftsFrame.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTool.h"
+#include "ftsTime.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+static char tag[8] = "[ FTS ]\0";
+static int sense_len, force_len;
+
+/*int getOffsetFrame(u16 address, u16 *offset)
+{
+
+ u8 data[2];
+ u8 cmd = { FTS_CMD_FRAMEBUFFER_R };
+
+ if (readCmdU16(cmd, address, data, OFFSET_LENGTH, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s getOffsetFrame: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ else {
+ u8ToU16(data, offset);
+ logError(0, "%s %s", tag, printHex("Offest = ", data, OFFSET_LENGTH));
+ return OK;
+ }
+
+}*/
+
+int getChannelsLength(void)
+{
+
+ int ret;
+ u8 *data = (u8 *)kmalloc(2*sizeof(u8), GFP_KERNEL);
+
+ if (data == NULL) {
+ logError(1, "%s getChannelsLength: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = readB2(ADDR_SENSE_LEN, data, 2);
+ if (ret < OK) {
+ logError(1, "%s getChannelsLength: ERROR %02X\n", tag, ERROR_READ_B2);
+ return (ret|ERROR_READ_B2);
+ }
+
+ sense_len = (int)data[0];
+ force_len = (int)data[1];
+
+ logError(0, "%s Force_len = %d Sense_Len = %d\n", tag, force_len, sense_len);
+
+ kfree(data);
+
+ return OK;
+}
+
+int getFrameData(u16 address, int size, short **frame)
+{
+ int i, j, ret;
+ u8 *data = (u8 *)kmalloc(size*sizeof(u8), GFP_KERNEL);
+ if (data == NULL) {
+ logError(1, "%s getFrameData: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, DUMMY_FRAMEBUFFER);
+ if (ret < OK) {
+ logError(1, "%s getFrameData: ERROR %02X\n", tag, ERROR_I2C_R);
+ kfree(data);
+ return ERROR_I2C_R;
+ }
+ j = 0;
+ for (i = 0; i < size; i += 2) {
+ (*frame)[j] = (short)((data[i + 1] << 8) + data[i]);
+ j++;
+ }
+ kfree(data);
+ return OK;
+}
+
+/*int getMSFrame(u16 type, short **frame, int keep_first_row)
+{
+ u16 offset;
+ int size, ret;
+
+ if (getSenseLen() == 0 || getForceLen() == 0) {
+ ret=getChannelsLength();
+ if (ret<OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag,ERROR_CH_LEN);
+ return (ret|ERROR_CH_LEN);
+ }
+ }
+
+ ret = getOffsetFrame(type, &offset);
+ if (ret<OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_OFFSET);
+ return (ret | ERROR_GET_OFFSET);
+ }
+
+ switch (type) {
+ case ADDR_RAW_TOUCH:
+ case ADDR_FILTER_TOUCH:
+ case ADDR_NORM_TOUCH:
+ case ADDR_CALIB_TOUCH:
+ if (keep_first_row ==1)
+ size = ((force_len+1)*sense_len);
+ else {
+ size = ((force_len)*sense_len);
+ offset+= (sense_len * BYTES_PER_NODE);
+ }
+ break;
+
+ default:
+ logError(1, "%s getMSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *frame = (short*)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (*frame==NULL) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret=getFrameData(offset, size*BYTES_PER_NODE, frame);
+ if (ret<OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret|ERROR_GET_FRAME_DATA);
+ }
+
+ logError(0, "%s Frame acquired!\n", tag);
+ return size;
+
+}
+
+int getMSKeyFrame(u16 type, short **frame) {
+ u16 offset;
+ int size, ret;
+ u16 address;
+ MutualSenseData data;
+
+ if (type != ADDR_RAW_MS_KEY) {
+ logError(1, "%s getMSKeyFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = getOffsetFrame(type, &offset);
+ if (ret<OK) {
+ logError(1, "%s getMSKeyFrame: ERROR %02X\n", tag, ERROR_GET_OFFSET);
+ return (ret | ERROR_GET_OFFSET);
+ }
+
+ ret = requestCompensationData(MS_KEY);
+ if (ret < OK) {
+ logError(1, "%s getMSKeyFrame: readMutualSenseCompensationData ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret | ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readCompensationDataHeader(MS_KEY, &(data.header), &address);
+ if (ret < OK) {
+ logError(1, "%s getMSKeyFrame: readMutualSenseCompensationData ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret | ERROR_COMP_DATA_HEADER);
+ }
+
+ if (data.header.force_node>data.header.sense_node)
+ size = data.header.force_node;
+ else
+ size = data.header.sense_node;
+
+ *frame = (short*)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (frame == NULL) {
+ logError(1, "%s getMSKeyFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, frame);
+ if (ret<OK) {
+ logError(1, "%s getMSKeyFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+
+ logError(0, "%s Frame acquired!\n", tag);
+}
+
+int getSSFrame(u16 type, short **frame) {
+ u16 offset;
+ int size, ret;
+
+ if (getSenseLen() == 0 || getForceLen() == 0) {
+ ret = getChannelsLength();
+ if (ret<0) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_CH_LEN);
+ return (ret | ERROR_CH_LEN);
+ }
+ }
+
+ switch (type) {
+ case ADDR_RAW_HOVER_FORCE:
+ case ADDR_FILTER_HOVER_FORCE:
+ case ADDR_NORM_HOVER_FORCE:
+ case ADDR_CALIB_HOVER_FORCE:
+ case ADDR_RAW_PRX_FORCE:
+ case ADDR_FILTER_PRX_FORCE:
+ case ADDR_NORM_PRX_FORCE:
+ case ADDR_CALIB_PRX_FORCE:
+ size = ((force_len)* 1);
+ break;
+
+ case ADDR_RAW_HOVER_SENSE:
+ case ADDR_FILTER_HOVER_SENSE:
+ case ADDR_NORM_HOVER_SENSE:
+ case ADDR_CALIB_HOVER_SENSE:
+ case ADDR_RAW_PRX_SENSE:
+ case ADDR_FILTER_PRX_SENSE:
+ case ADDR_NORM_PRX_SENSE:
+ case ADDR_CALIB_PRX_SENSE:
+ size = ((1)*sense_len);
+ break;
+
+ default:
+ logError(1, "%s getSSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+
+ }
+
+ ret = getOffsetFrame(type, &offset);
+ if (ret<OK) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_GET_OFFSET);
+ return (ret | ERROR_GET_OFFSET);
+ }
+
+ *frame = (short*)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (*frame == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, frame);
+ if (ret<OK) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+
+ logError(0, "%s Frame acquired!\n", tag);
+ return size;
+
+}
+
+int getNmsFrame(u16 type, short ***frames, int *size, int keep_first_row, int fs, int n) {
+ int i;
+ StopWatch global, local;
+ int temp;
+
+ *frames = (short **)kmalloc(n*sizeof(short *), GFP_KERNEL);
+
+ if (*frames == NULL) {
+ logError(1, "%s getNmsFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ fs = (1*1000 / fs) ;
+
+ startStopWatch(&global);
+ for (i = 0; i < n; i++) {
+
+ startStopWatch(&local);
+
+ *size = getMSFrame(type, ((*frames)+i), keep_first_row);
+ if (*size < OK) {
+ logError(1, "%s getNFrame: getFrame failed\n",tag);
+ return *size;
+ }
+
+ stopStopWatch(&local);
+ temp = elapsedMillisecond(&local);
+ logError(0, "%s Iteration %d performed in %d ms... the process wait for %ld ms\n\n", tag, i, temp, (unsigned long)(fs - temp));
+
+ if (temp < fs)
+ msleep((unsigned long)(fs - temp));
+
+ }
+
+ stopStopWatch(&global);
+ temp = elapsedMillisecond(&global);
+ logError(0, "%s Global Iteration performed in %d ms\n", tag, temp);
+ temp /= n;
+ logError(0, "%s Mean Iteration performed in %d ms\n", tag, temp);
+ return (1000 / (temp));
+
+}*/
+
+int getSenseLen(void)
+{
+ int ret;
+ if (sense_len != 0)
+ return sense_len;
+ ret = getChannelsLength();
+ if (ret < OK)
+ return ret;
+ else
+ return sense_len;
+}
+
+int getForceLen(void)
+{
+ int ret;
+ if (force_len != 0)
+ return force_len;
+ ret = getChannelsLength();
+ if (ret < OK)
+ return ret;
+ else
+ return force_len;
+}
+
+int requestFrame(u16 type)
+{
+ int retry = 0;
+ int ret;
+ u16 answer;
+
+ int event_to_search[1];
+ u8 readEvent[FIFO_EVENT_SIZE];
+
+ u8 cmd[3] = { FTS_CMD_REQU_FRAME_DATA, 0x00, 0x00 };
+ /* B7 is the command for asking frame data */
+ event_to_search[0] = (int)EVENTID_FRAME_DATA_READ;
+
+ u16ToU8(type, &cmd[1]);
+
+ while (retry < FRAME_DATA_READ_RETRY) {
+ logError(0, "%s %s", tag, printHex("Command = ", cmd, 3));
+ ret = fts_writeFwCmd(cmd, 3);
+ /* send the request to the chip to load in memory the Frame Data */
+ if (ret < OK) {
+ logError(1, "%s requestFrame: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ ret = pollForEvent(event_to_search, 1, readEvent, TIMEOUT_REQU_COMP_DATA);
+ if (ret < OK) {
+ logError(0, "%s Event did not Found at %d attemp!\n", tag, retry + 1);
+ retry += 1;
+ } else {
+ retry = 0;
+ break;
+ }
+ }
+
+ if (retry == FRAME_DATA_READ_RETRY) {
+ logError(1, "%s requestFrame: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+
+ u8ToU16_le(&readEvent[1], &answer);
+
+ if (answer == type)
+ return OK;
+ logError(1, "%s The event found has a different type of Frame data ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+
+}
+
+int readFrameDataHeader(u16 type, DataHeader *header)
+{
+
+ u16 offset = ADDR_FRAMEBUFFER_DATA;
+ u16 answer;
+ u8 data[FRAME_DATA_HEADER];
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, FRAME_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readFrameDataHeader: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ logError(0, "%s Read Data Header done!\n", tag);
+
+ if (data[0] != FRAME_HEADER_SIGNATURE) {
+ logError(1, "%s readFrameDataHeader: ERROR %02X The Header Signature was wrong! %02X != %02X\n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE);
+ return ERROR_WRONG_COMP_SIGN;
+ }
+
+ u8ToU16_le(&data[1], &answer);
+
+ if (answer != type) {
+ logError(1, "%s readFrameDataHeader: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+ }
+
+ logError(0, "%s Type of Frame data OK!\n", tag);
+
+ header->type = type;
+ header->force_node = (int)data[4];
+ header->sense_node = (int)data[5];
+
+ return OK;
+
+}
+
+int getMSFrame2(u16 type, MutualSenseFrame *frame)
+{
+ u16 offset = ADDR_FRAMEBUFFER_DATA+FRAME_DATA_HEADER;
+ int size, ret;
+
+ if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER || type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) {
+ logError(1, "%s getMSFrame: Choose a MS type of frame data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestFrame(type);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret | ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readFrameDataHeader(type, &(frame->header));
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret | ERROR_COMP_DATA_HEADER);
+ }
+
+ switch (type) {
+ case MS_TOUCH_ACTIVE:
+ case MS_TOUCH_LOW_POWER:
+ case MS_TOUCH_ULTRA_LOW_POWER:
+ size = frame->header.force_node*frame->header.sense_node;
+ break;
+ case MS_KEY:
+ if (frame->header.force_node > frame->header.sense_node)
+ /* or use directly the number in the ftsChip */
+ size = frame->header.force_node;
+ else
+ size = frame->header.sense_node;
+ frame->header.force_node = 1;
+ frame->header.sense_node = size;
+ break;
+
+ default:
+ logError(1, "%s getMSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ frame->node_data = (short *)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (frame->node_data == NULL) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, &(frame->node_data));
+ if (ret < OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+ /* if you want to access one node i,j, you should compute the offset like: offset = i*columns + j = > frame[i, j] */
+
+ logError(0, "%s Frame acquired!\n", tag);
+ frame->node_data_size = size;
+ return size; /* return the number of data put inside frame */
+
+}
+
+int getSSFrame2(u16 type, SelfSenseFrame *frame)
+{
+ u16 offset = ADDR_FRAMEBUFFER_DATA + FRAME_DATA_HEADER;
+ int size, ret;
+ short *temp = NULL;
+
+ if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER || type == SS_PROXIMITY)) {
+ logError(1, "%s getSSFrame: Choose a SS type of frame data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestFrame(type);
+ if (ret < 0) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret | ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readFrameDataHeader(type, &(frame->header));
+ if (ret < 0) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret | ERROR_COMP_DATA_HEADER);
+ }
+
+ switch (type) {
+ case SS_TOUCH:
+ case SS_HOVER:
+ case SS_PROXIMITY:
+ size = frame->header.force_node+frame->header.sense_node;
+ break;
+
+ default:
+ logError(1, "%s getSSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ temp = (short *)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (temp == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, &temp);
+ if (ret < OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+
+ frame->force_data = (short *)kmalloc(frame->header.force_node*sizeof(short), GFP_KERNEL);
+ if (frame->force_data == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ memcpy(frame->force_data, temp, frame->header.force_node*sizeof(short));
+
+ frame->sense_data = (short *)kmalloc(frame->header.sense_node*sizeof(short), GFP_KERNEL);
+ if (frame->sense_data == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ memcpy(frame->sense_data, &temp[frame->header.force_node], frame->header.sense_node*sizeof(short));
+
+ logError(0, "%s Frame acquired!\n", tag);
+ kfree(temp);
+ return size; /* return the number of data put inside frame */
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFrame.h b/drivers/input/touchscreen/st/fts_lib/ftsFrame.h
new file mode 100644
index 000000000000..89f4e5080a53
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFrame.h
@@ -0,0 +1,49 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting frames *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+
+/* Number of data bytes for each node */
+#define BYTES_PER_NODE 2
+#define OFFSET_LENGTH 2
+#define FRAME_DATA_HEADER 8
+#define FRAME_HEADER_SIGNATURE 0xB5
+#define FRAME_DATA_READ_RETRY 2
+
+typedef struct {
+ DataHeader header;
+ short *node_data;
+ int node_data_size;
+} MutualSenseFrame;
+
+typedef struct {
+ DataHeader header;
+ short *force_data;
+ short *sense_data;
+} SelfSenseFrame;
+
+/* int getOffsetFrame(u16 address, u16 *offset); */
+int getChannelsLength(void);
+int getFrameData(u16 address, int size, short **frame);
+/* int getMSFrame(u16 type, short **frame, int keep_first_row); */
+/* int getMSKeyFrame(u16 type, short **frame); */
+/* int getSSFrame(u16 type, short **frame); */
+/* int getNmsFrame(u16 type, short ***frames, int * sizes, int keep_first_row, int fs, int n); */
+int getSenseLen(void);
+int getForceLen(void);
+int requestFrame(u16 type);
+int readFrameDataHeader(u16 type, DataHeader *header);
+int getMSFrame2(u16 type, MutualSenseFrame *frame);
+int getSSFrame2(u16 type, SelfSenseFrame *frame);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c
new file mode 100644
index 000000000000..fda4ab281948
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c
@@ -0,0 +1,393 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Gesture Utilities *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+#include "ftsError.h"
+#include "ftsGesture.h"
+#include "ftsIO.h"
+#include "ftsTool.h"
+
+static char tag[8] = "[ FTS ]\0";
+
+static u8 gesture_mask[GESTURE_MASK_SIZE] = { 0 };
+static u8 custom_gestures[GESTURE_CUSTOM_NUMBER][GESTURE_CUSTOM_POINTS];
+static u8 custom_gesture_index[GESTURE_CUSTOM_NUMBER] = { 0 };
+
+int enableGesture(u8 *mask, int size)
+{
+ u8 cmd[size+2];
+ u8 readData[FIFO_EVENT_SIZE];
+ int i, res;
+ int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_ENABLE};
+
+ logError(0, "%s Trying to enable gesture...\n", tag);
+ cmd[0] = FTS_CMD_GESTURE_CMD;
+ cmd[1] = GESTURE_ENABLE;
+
+ if (size <= GESTURE_MASK_SIZE) {
+ if (mask != NULL) {
+ for (i = 0; i < size; i++) {
+ cmd[i + 2] = mask[i];
+ gesture_mask[i] = gesture_mask[i]|mask[i];
+ /* back up of the gesture enabled */
+ }
+ while (i < GESTURE_MASK_SIZE) {
+ cmd[i + 2] = gesture_mask[i];
+ i++;
+ }
+ } else {
+ for (i = 0; i < GESTURE_MASK_SIZE; i++) {
+ cmd[i + 2] = gesture_mask[i];
+ }
+ }
+
+ res = fts_writeFwCmd(cmd, GESTURE_MASK_SIZE + 2);
+ if (res < OK) {
+ logError(1, "%s enableGesture: ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s enableGesture: pollForEvent ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[4] != 0x00) {
+ logError(1, "%s enableGesture: ERROR %08X\n", tag, ERROR_GESTURE_ENABLE_FAIL);
+ return ERROR_GESTURE_ENABLE_FAIL;
+ }
+
+ logError(0, "%s enableGesture DONE!\n", tag);
+ return OK;
+ } else {
+ logError(1, "%s enableGesture: Size not valid! %d > %d ERROR %08X\n", tag, size, GESTURE_MASK_SIZE);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+}
+
+int disableGesture(u8 *mask, int size)
+{
+ u8 cmd[2+GESTURE_MASK_SIZE];
+ u8 readData[FIFO_EVENT_SIZE];
+ u8 temp;
+ int i, res;
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_DISABLE };
+
+ logError(0, "%s Trying to disable gesture...\n", tag);
+ cmd[0] = FTS_CMD_GESTURE_CMD;
+ cmd[1] = GESTURE_DISABLE;
+
+ if (size <= GESTURE_MASK_SIZE) {
+ if (mask != NULL) {
+ for (i = 0; i < size; i++) {
+ cmd[i + 2] = mask[i];
+ temp = gesture_mask[i] ^ mask[i];
+ /* enabled XOR disabled */
+ gesture_mask[i] = temp & gesture_mask[i];
+ /* disable the gestures that were enabled */
+ }
+ while (i < GESTURE_MASK_SIZE) {
+ cmd[i + 2] = gesture_mask[i];
+ /* disable all the other gesture not specified */
+ gesture_mask[i] = 0x00;
+ i++;
+ }
+ } else {
+ for (i = 0; i < GESTURE_MASK_SIZE; i++) {
+ cmd[i + 2] = gesture_mask[i];
+ }
+ }
+
+ res = fts_writeFwCmd(cmd, 2 + GESTURE_MASK_SIZE);
+ if (res < OK) {
+ logError(1, "%s disableGesture: ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s disableGesture: pollForEvent ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[4] != 0x00) {
+ logError(1, "%s disableGesture: ERROR %08X\n", tag, ERROR_GESTURE_ENABLE_FAIL);
+ return ERROR_GESTURE_ENABLE_FAIL;
+ }
+
+ logError(0, "%s disableGesture DONE!\n", tag);
+ return OK;
+ } else {
+ logError(1, "%s disableGesture: Size not valid! %d > %d ERROR %08X\n", tag, size, GESTURE_MASK_SIZE);
+ return ERROR_OP_NOT_ALLOW;
+ }
+}
+
+int startAddCustomGesture(u8 gestureID)
+{
+ u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_START_ADD, gestureID };
+ int res;
+ u8 readData[FIFO_EVENT_SIZE];
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_START_ADD };
+
+ res = fts_writeFwCmd(cmd, 3);
+ if (res < OK) {
+ logError(1, "%s startAddCustomGesture: Impossible to start adding custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s startAddCustomGesture: start add event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s startAddCustomGesture: start add event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_START_ADD;
+ }
+
+ return OK;
+}
+
+int finishAddCustomGesture(u8 gestureID)
+{
+ u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_FINISH_ADD, gestureID };
+ int res;
+ u8 readData[FIFO_EVENT_SIZE];
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_FINISH_ADD };
+
+ res = fts_writeFwCmd(cmd, 3);
+ if (res < OK) {
+ logError(1, "%s finishAddCustomGesture: Impossible to finish adding custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s finishAddCustomGesture: finish add event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s finishAddCustomGesture: finish add event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_FINISH_ADD;
+ }
+
+ return OK;
+
+}
+
+int loadCustomGesture(u8 *template, u8 gestureID)
+{
+ int res, i;
+ int remaining = GESTURE_CUSTOM_POINTS;
+ int toWrite, offset = 0;
+ u8 cmd[TEMPLATE_CHUNK + 5];
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_DATA_ADD };
+ u8 readData[FIFO_EVENT_SIZE];
+
+ logError(0, "%s Starting adding custom gesture procedure...\n", tag);
+
+ res = startAddCustomGesture(gestureID);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: unable to start adding procedure! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ cmd[0] = FTS_CMD_GESTURE_CMD;
+ cmd[1] = GESTURE_DATA_ADD;
+ cmd[2] = gestureID;
+ while (remaining > 0) {
+ if (remaining > TEMPLATE_CHUNK) {
+ toWrite = TEMPLATE_CHUNK;
+ } else {
+ toWrite = remaining;
+ }
+
+ cmd[3] = toWrite;
+ cmd[4] = offset;
+ for (i = 0; i < toWrite; i++) {
+ cmd[i + 5] = template[i];
+ }
+
+ res = fts_writeFwCmd(cmd, toWrite + 5);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: unable to start adding procedure! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: add event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s loadCustomGesture: add event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_DATA_ADD;
+ }
+
+ remaining -= toWrite;
+ offset += toWrite / 2;
+ }
+
+ res = finishAddCustomGesture(gestureID);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: unable to finish adding procedure! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ logError(0, "%s Adding custom gesture procedure DONE!\n", tag);
+ return OK;
+
+}
+
+int reloadCustomGesture(void)
+{
+ int res, i;
+
+ logError(0, "%s Starting reload Gesture Template...\n", tag);
+
+ for (i = 0; i < GESTURE_CUSTOM_NUMBER; i++) {
+ if (custom_gesture_index[i] == 1) {
+ res = loadCustomGesture(custom_gestures[i], GESTURE_CUSTOM_OFFSET+i);
+ if (res < OK) {
+ logError(1, "%s reloadCustomGesture: Impossible to load custom gesture ID = %02X! ERROR %08X\n", tag, GESTURE_CUSTOM_OFFSET + i, res);
+ return res;
+ }
+ }
+ }
+
+ logError(0, "%s Reload Gesture Template DONE!\n", tag);
+ return OK;
+
+}
+
+int enterGestureMode(int reload)
+{
+ u8 cmd = FTS_CMD_GESTURE_MODE;
+ int res, ret;
+
+ res = fts_disableInterrupt();
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: ERROR %08X\n", tag, res|ERROR_DISABLE_INTER);
+ return res | ERROR_DISABLE_INTER;
+ }
+
+ if (reload == 1) {
+
+ res = reloadCustomGesture();
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: impossible reload custom gesture! ERROR %08X\n", tag, res);
+ goto END;
+ }
+
+ res = disableGesture(NULL, 0);
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: disableGesture ERROR %08X\n", tag, res);
+ goto END;
+ }
+
+ res = enableGesture(NULL, 0);
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: enableGesture ERROR %08X\n", tag, res);
+ goto END;
+ }
+ }
+
+ res = fts_writeFwCmd(&cmd, 1);
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: enter gesture mode ERROR %08X\n", tag, res);
+ goto END;
+ }
+
+ res = OK;
+END:
+ ret = fts_enableInterrupt();
+ if (ret < OK) {
+ logError(1, "%s enterGestureMode: fts_enableInterrupt ERROR %08X\n", tag, res | ERROR_ENABLE_INTER);
+ res |= ret | ERROR_ENABLE_INTER;
+ }
+
+ return res;
+}
+
+int addCustomGesture(u8 *data, int size, u8 gestureID)
+{
+ int index, res, i;
+
+ index = gestureID - GESTURE_CUSTOM_OFFSET;
+
+ logError(0, "%s Starting Custom Gesture Adding procedure...\n", tag);
+ if (size != GESTURE_CUSTOM_POINTS && gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3 && gestureID != GES_ID_CUST4 && gestureID && GES_ID_CUST5) {
+ logError(1, "%s addCustomGesture: Invalid size (%d) or Custom GestureID (%02X)! ERROR %08X\n", tag, size, gestureID, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ for (i = 0; i < GESTURE_CUSTOM_POINTS; i++) {
+ custom_gestures[index][i] = data[i];
+ }
+
+ res = loadCustomGesture(custom_gestures[index], gestureID);
+ if (res < OK) {
+ logError(1, "%s addCustomGesture: impossible to load the custom gesture! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ custom_gesture_index[index] = 1;
+ logError(0, "%s Custom Gesture Adding procedure DONE!\n", tag);
+ return OK;
+}
+
+int removeCustomGesture(u8 gestureID)
+{
+ int res, index;
+ u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GETURE_REMOVE_CUSTOM, gestureID };
+ int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GETURE_REMOVE_CUSTOM };
+ u8 readData[FIFO_EVENT_SIZE];
+
+ index = gestureID - GESTURE_CUSTOM_OFFSET;
+
+ logError(0, "%s Starting Custom Gesture Removing procedure...\n", tag);
+ if (gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3 && gestureID != GES_ID_CUST4 && gestureID && GES_ID_CUST5) {
+ logError(1, "%s removeCustomGesture: Invalid size (%d) or Custom GestureID (%02X)! ERROR %08X\n", tag, gestureID, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ res = fts_writeFwCmd(cmd, 3);/* when a gesture is removed, it is also disabled automatically */
+ if (res < OK) {
+ logError(1, "%s removeCustomGesture: Impossible to remove custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s removeCustomGesture: remove event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s removeCustomGesture: remove event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_REMOVE;
+ }
+
+ custom_gesture_index[index] = 0;
+ logError(0, "%s Custom Gesture Remove procedure DONE!\n", tag);
+ return OK;
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.h b/drivers/input/touchscreen/st/fts_lib/ftsGesture.h
new file mode 100644
index 000000000000..a9c3e3c05573
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.h
@@ -0,0 +1,74 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Gesture Utilities *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#define GESTURE_MASK_SIZE 8
+
+#define GESTURE_CUSTOM_POINTS (30*2)
+/* for each custom gesture should be provided 30 points (each point is a couple of x,y) */
+#define GESTURE_CUSTOM_NUMBER 5 /* fw support up to 5 custom gestures */
+
+#define TEMPLATE_CHUNK (10*2)
+/* number of points to transfer with each I2C transaction */
+
+/* Gesture IDs */
+#define GES_ID_DBLTAP 0x01 /* Double Tap */
+#define GES_ID_O 0x02 /* 'O' */
+#define GES_ID_C 0x03 /* 'C' */
+#define GES_ID_M 0x04 /* 'M' */
+#define GES_ID_W 0x05 /* 'W' */
+#define GES_ID_E 0x06 /* 'e' */
+#define GES_ID_HFLIP_L2R 0x07 /* Left to right line */
+#define GES_ID_HFLIP_R2L 0x08 /* Right to left line */
+#define GES_ID_VFLIP_T2D 0x09 /* Top to bottom line */
+#define GES_ID_VFLIP_D2T 0x0A /* Bottom to Top line */
+#define GES_ID_L 0x0B /* 'L' */
+#define GES_ID_F 0x0C /* 'F' */
+#define GES_ID_V 0x0D /* 'V' */
+#define GES_ID_AT 0x0E /* '@' */
+#define GES_ID_S 0x0F /* 'S' */
+#define GES_ID_Z 0x10 /* 'Z' */
+#define GES_ID_CUST1 0x11 /* Custom gesture 1 */
+#define GES_ID_CUST2 0x12 /* Custom gesture 2 */
+#define GES_ID_CUST3 0x13 /* Custom gesture 3 */
+#define GES_ID_CUST4 0x14 /* Custom gesture 4 */
+#define GES_ID_CUST5 0x15 /* Custom gesture 5 */
+#define GES_ID_LEFTBRACE 0x20 /* '<' */
+#define GES_ID_RIGHTBRACE 0x21 /* '>' */
+
+#define GESTURE_CUSTOM_OFFSET GES_ID_CUST1
+
+/* Command sub-type */
+#define GESTURE_ENABLE 0x01
+#define GESTURE_DISABLE 0x02
+#define GESTURE_ENB_CHECK 0x03
+#define GESTURE_START_ADD 0x10
+#define GESTURE_DATA_ADD 0x11
+#define GESTURE_FINISH_ADD 0x12
+#define GETURE_REMOVE_CUSTOM 0x13
+#define GESTURE_CHECK_CUSTOM 0x14
+
+/* Event sub-type */
+#define EVENT_TYPE_ENB 0x04
+#define EVENT_TYPE_CHECK_ENB 0x03
+#define EVENT_TYPE_GESTURE_DTC1 0x01
+#define EVENT_TYPE_GESTURE_DTC2 0x02
+
+int disableGesture(u8 *mask, int size);
+int enableGesture(u8 *mask, int size);
+int startAddCustomGesture(u8 gestureID);
+int finishAddCustomGesture(u8 gestureID);
+int loadCustomGesture(u8 *template, u8 gestureID);
+int reloadCustomGesture(void);
+int enterGestureMode(int reload);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsHardware.h b/drivers/input/touchscreen/st/fts_lib/ftsHardware.h
new file mode 100644
index 000000000000..933059e671b4
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsHardware.h
@@ -0,0 +1,177 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* HW related data *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#define FTM3_CHIP
+
+/* DUMMY BYTES DATA */
+#define DUMMY_HW_REG 1
+#define DUMMY_FRAMEBUFFER 1
+#define DUMMY_MEMORY 1
+
+/* DIGITAL CHIP INFO */
+#ifdef FTM3_CHIP
+#define DCHIP_ID_0 0x39
+#define DCHIP_ID_1 0x6C
+#else
+#define DCHIP_ID_0 0x36
+#define DCHIP_ID_1 0x70
+#endif
+
+#ifdef FTM3_CHIP
+#define DCHIP_ID_ADDR 0x0007
+#define DCHIP_FW_VER_ADDR 0x000A
+#else
+#define DCHIP_ID_ADDR 0x0004
+#define DCHIP_FW_VER_ADDR 0x000B
+#endif
+
+#define DCHIP_FW_VER_BYTE 2
+
+/* CHUNKS */
+#define READ_CHUNK (2*1024)
+#define WRITE_CHUNK (2*1024)
+#define MEMORY_CHUNK (2*1024)
+
+/* PROTOCOL INFO */
+#ifdef FTM3_CHIP
+#define I2C_SAD 0x49
+#else
+#define I2C_SAD 0x48
+#endif
+
+#define I2C_INTERFACE /* comment if the chip use SPI */
+#define ICR_ADDR 0x0024
+#define ICR_SPI_VALUE 0x02
+
+/* SYSTEM RESET INFO */
+#ifdef FTM3_CHIP
+#define SYSTEM_RESET_ADDRESS 0x0023
+#define SYSTEM_RESET_VALUE 0x01
+#else
+#define SYSTEM_RESET_ADDRESS 0x0028
+#define SYSTEM_RESET_VALUE 0x80
+#endif
+
+/* INTERRUPT INFO */
+#ifdef FTM3_CHIP
+#define IER_ADDR 0x001C
+#else
+#define IER_ADDR 0x002C
+#endif
+
+#define IER_ENABLE 0x41
+#define IER_DISABLE 0x00
+
+/* FLASH COMMAND */
+
+#define FLASH_CMD_UNLOCK 0xF7
+
+#ifdef FTM3_CHIP
+#define FLASH_CMD_WRITE_LOWER_64 0xF0
+#define FLASH_CMD_WRITE_UPPER_64 0xF1
+#define FLASH_CMD_BURN 0xF2
+#define FLASH_CMD_ERASE 0xF3
+#define FLASH_CMD_READSTATUS 0xF4
+#else
+#define FLASH_CMD_WRITE_64K 0xF8
+#define FLASH_CMD_READ_REGISTER 0xF9
+#define FLASH_CMD_WRITE_REGISTER 0xFA
+#endif
+
+/* FLASH UNLOCK PARAMETER */
+#define FLASH_UNLOCK_CODE0 0x74
+#define FLASH_UNLOCK_CODE1 0x45
+
+#ifndef FTM3_CHIP
+/* FLASH ERASE and DMA PARAMETER */
+#define FLASH_ERASE_UNLOCK_CODE0 0x72
+#define FLASH_ERASE_UNLOCK_CODE1 0x03
+#define FLASH_ERASE_UNLOCK_CODE2 0x02
+#define FLASH_ERASE_CODE0 0x02
+#define FLASH_ERASE_CODE1 0xC0
+#define FLASH_DMA_CODE0 0x05
+#define FLASH_DMA_CODE1 0xC0
+#define FLASH_DMA_CONFIG 0x06
+#endif
+
+/* FLASH ADDRESS */
+#ifdef FTM3_CHIP
+#define FLASH_ADDR_SWITCH_CMD 0x00010000
+#define FLASH_ADDR_CODE 0x00000000
+#define FLASH_ADDR_CONFIG 0x0001E800
+#define FLASH_ADDR_CX 0x0001F000
+#else
+#define ADDR_WARM_BOOT 0x001E
+#define WARM_BOOT_VALUE 0x38
+#define FLASH_ADDR_CODE 0x00000000
+#define FLASH_ADDR_CONFIG 0x0000FC00
+#endif
+
+/* CRC ADDR */
+#ifdef FTM3_CHIP
+#define ADDR_CRC_BYTE0 0x00
+#define ADDR_CRC_BYTE1 0x86
+#define CRC_MASK 0x02
+#else
+#define ADDR_CRC_BYTE0 0x00
+#define ADDR_CRC_BYTE1 0x74
+#define CRC_MASK 0x03
+#endif
+
+/* SIZES FW, CODE, CONFIG, MEMH */
+#ifdef FTM3_CHIP
+#define FW_HEADER_SIZE 32
+#define FW_SIZE (int)(128*1024)
+#define FW_CODE_SIZE (int)(122*1024)
+#define FW_CONFIG_SIZE (int)(2*1024)
+#define FW_CX_SIZE (int)(FW_SIZE-FW_CODE_SIZE-FW_CONFIG_SIZE)
+#define FW_VER_MEMH_BYTE1 193
+#define FW_VER_MEMH_BYTE0 192
+#define FW_OFF_CONFID_MEMH_BYTE1 2
+#define FW_OFF_CONFID_MEMH_BYTE0 1
+#define FW_BIN_VER_OFFSET 4
+#define FW_BIN_CONFIG_VER_OFFSET (FW_HEADER_SIZE+FW_CODE_SIZE+1)
+#else
+#define FW_HEADER_SIZE 64
+#define FW_HEADER_SIGNATURE 0xAA55AA55
+#define FW_FTB_VER 0x00000001
+#define FW_BYTES_ALIGN 4
+#define FW_BIN_VER_OFFSET 16
+#define FW_BIN_CONFIG_VER_OFFSET 20
+#endif
+
+/* FIFO */
+#define FIFO_EVENT_SIZE 8
+#ifdef FTM3_CHIP
+#define FIFO_DEPTH 32
+#else
+#define FIFO_DEPTH 64
+#endif
+
+#define FIFO_CMD_READONE 0x85
+#define FIFO_CMD_READALL 0x86
+#define FIFO_CMD_LAST 0x87
+#define FIFO_CMD_FLUSH 0xA1
+
+/* CONSTANT TOTAL CX */
+#define CX1_WEIGHT 4
+#define CX2_WEIGHT 1
+
+/* OP CODES FOR MEMORY (based on protocol) */
+
+#define FTS_CMD_HW_REG_R 0xB6
+#define FTS_CMD_HW_REG_W 0xB6
+#define FTS_CMD_FRAMEBUFFER_R 0xD0
+#define FTS_CMD_FRAMEBUFFER_W 0xD0
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsIO.c b/drivers/input/touchscreen/st/fts_lib/ftsIO.c
new file mode 100644
index 000000000000..96ca8cfecd8a
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsIO.c
@@ -0,0 +1,403 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* I2C/SPI Communication *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+#include "ftsCrossCompile.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/spi/spidev.h>
+static struct i2c_client *client;
+static u16 I2CSAD;
+
+#include "ftsError.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsTool.h"
+
+static char tag[8] = "[ FTS ]\0";
+
+int openChannel(struct i2c_client *clt)
+{
+ client = clt;
+ I2CSAD = clt->addr;
+ logError(1, "%s openChannel: SAD: %02X\n", tag, I2CSAD);
+ return OK;
+}
+
+struct device *getDev(void)
+{
+ if (client != NULL)
+ return &(client->dev);
+ else
+ return NULL;
+}
+
+struct i2c_client *getClient(void)
+{
+ if (client != NULL)
+ return client;
+ else
+ return NULL;
+}
+
+int fts_readCmd(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead)
+{
+ int ret = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[2];
+
+ /* write msg */
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+
+ /* read msg */
+ I2CMsg[1].addr = (__u16)I2CSAD;
+ I2CMsg[1].flags = I2C_M_RD;
+ I2CMsg[1].len = byteToRead;
+ I2CMsg[1].buf = (__u8 *)outBuf;
+
+ if (client == NULL)
+ return ERROR_I2C_O;
+ while (retry < I2C_RETRY && ret < OK) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 2);
+ if (ret >= OK)
+ break;
+ retry++;
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ }
+ if (ret < 0) {
+ logError(1, "%s fts_readCmd: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ return OK;
+}
+
+int fts_writeCmd(u8 *cmd, int cmdLength)
+{
+ int ret = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[2];
+
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+
+ if (client == NULL)
+return ERROR_I2C_O;
+ while (retry < I2C_RETRY && ret < OK) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 1);
+ if (ret >= OK)
+ break;
+ retry++;
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ /* logError(1, "%s fts_writeCmd: attempt %d\n", tag, retry); */
+ }
+ if (ret < 0) {
+ logError(1, "%s fts_writeCmd: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ return OK;
+}
+
+int fts_writeFwCmd(u8 *cmd, int cmdLength)
+{
+ int ret = -1;
+ int ret2 = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[2];
+
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+
+ if (client == NULL)
+return ERROR_I2C_O;
+ while (retry < I2C_RETRY && (ret < OK || ret2 < OK)) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 1);
+ retry++;
+ if (ret >= 0) {
+ ret2 = checkEcho(cmd, cmdLength);
+ break;
+ }
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ /* logError(1, "%s fts_writeCmd: attempt %d\n", tag, retry); */
+ }
+ if (ret < 0) {
+ logError(1, "%s fts_writeFwCmd: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ if (ret2 < OK) {
+ logError(1, "%s fts_writeFwCmd: check echo ERROR %02X\n", tag, ret2);
+ return (ret|ERROR_I2C_W);
+ }
+ return OK;
+}
+
+int writeReadCmd(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1,
+ int readCmdLength, u8 *outBuf, int byteToRead)
+{
+ int ret = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[3];
+
+ /* write msg */
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)writeCmdLength;
+ I2CMsg[0].buf = (__u8 *)writeCmd1;
+
+ /* write msg */
+ I2CMsg[1].addr = (__u16)I2CSAD;
+ I2CMsg[1].flags = (__u16)0;
+ I2CMsg[1].len = (__u16)readCmdLength;
+ I2CMsg[1].buf = (__u8 *)readCmd1;
+
+ /* read msg */
+ I2CMsg[2].addr = (__u16)I2CSAD;
+ I2CMsg[2].flags = I2C_M_RD;
+ I2CMsg[2].len = byteToRead;
+ I2CMsg[2].buf = (__u8 *)outBuf;
+
+ if (client == NULL)
+ return ERROR_I2C_O;
+ while (retry < I2C_RETRY && ret < OK) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 3);
+ if (ret >= OK)
+ break;
+ retry++;
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ }
+
+ if (ret < 0) {
+ logError(1, "%s writeReadCmd: ERROR %02X\n", tag, ERROR_I2C_WR);
+ return ERROR_I2C_WR;
+ }
+ return OK;
+
+}
+
+int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte)
+{
+
+ int remaining = byteToRead;
+ int toRead = 0;
+ u8 rCmd[3] = { cmd, 0x00, 0x00 };
+
+ u8 *buff = (u8 *)kmalloc((READ_CHUNK + 1)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s readCmdU16: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ if (remaining >= READ_CHUNK) {
+ toRead = READ_CHUNK;
+ remaining -= READ_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ rCmd[1] = (u8)((address & 0xFF00) >> 8);
+ rCmd[2] = (u8)(address & 0xFF);
+
+ if (hasDummyByte) {
+ if (fts_readCmd(rCmd, 3, buff, toRead + 1) < 0) {
+ logError(1, "%s readCmdU16: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ memcpy(outBuf, buff + 1, toRead);
+ } else {
+ if (fts_readCmd(rCmd, 3, buff, toRead) < 0)
+ return ERROR_I2C_R;
+ memcpy(outBuf, buff, toRead);
+ }
+
+ address += toRead;
+
+ outBuf += toRead;
+
+ }
+ kfree(buff);
+
+ return OK;
+}
+
+int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite)
+{
+
+ int remaining = byteToWrite;
+ int toWrite = 0;
+
+ u8 *buff = (u8 *)kmalloc((WRITE_CHUNK + 3)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s writeCmdU16: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ buff[0] = WriteCmd;
+
+ while (remaining > 0) {
+ if (remaining >= WRITE_CHUNK) {
+ toWrite = WRITE_CHUNK;
+ remaining -= WRITE_CHUNK;
+ } else {
+ toWrite = remaining;
+ remaining = 0;
+ }
+
+ buff[1] = (u8)((address & 0xFF00) >> 8);
+ buff[2] = (u8)(address & 0xFF);
+ memcpy(buff + 3, dataToWrite, toWrite);
+ if (fts_writeCmd(buff, 3 + toWrite) < 0) {
+ logError(1, "%s writeCmdU16: ERROR %02\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ address += toWrite;
+ dataToWrite += toWrite;
+
+ }
+
+ return OK;
+}
+
+int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, int byteToWrite)
+{
+
+ int remaining = byteToWrite;
+ int toWrite = 0;
+
+ u8 buff1[3] = { writeCmd1, 0x00, 0x00 };
+ u8 *buff2 = (u8 *)kmalloc((WRITE_CHUNK + 3)*sizeof(u8), GFP_KERNEL);
+ if (buff2 == NULL) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+ buff2[0] = writeCmd2;
+
+ while (remaining > 0) {
+ if (remaining >= WRITE_CHUNK) {
+ toWrite = WRITE_CHUNK;
+ remaining -= WRITE_CHUNK;
+ } else {
+ toWrite = remaining;
+ remaining = 0;
+ }
+
+ buff1[1] = (u8)((address & 0xFF000000) >> 24);
+ buff1[2] = (u8)((address & 0x00FF0000) >> 16);
+ buff2[1] = (u8)((address & 0x0000FF00) >> 8);
+ buff2[2] = (u8)(address & 0xFF);
+ memcpy(buff2 + 3, dataToWrite, toWrite);
+
+ if (fts_writeCmd(buff1, 3) < 0) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ if (fts_writeCmd(buff2, 3 + toWrite) < 0) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ address += toWrite;
+ dataToWrite += toWrite;
+
+ }
+
+ return OK;
+}
+
+int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, int hasDummyByte)
+{
+
+ int remaining = byteToRead;
+ int toRead = 0;
+ u8 reaCmd[3];
+ u8 wriCmd[3];
+
+ u8 *buff = (u8 *)kmalloc((READ_CHUNK + 1)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s writereadCmd32: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ reaCmd[0] = rCmd;
+ wriCmd[0] = wCmd;
+
+ while (remaining > 0) {
+ if (remaining >= READ_CHUNK) {
+ toRead = READ_CHUNK;
+ remaining -= READ_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ wriCmd[1] = (u8)((address & 0xFF000000) >> 24);
+ wriCmd[2] = (u8)((address & 0x00FF0000) >> 16);
+
+ reaCmd[1] = (u8)((address & 0x0000FF00) >> 8);
+ reaCmd[2] = (u8)(address & 0x000000FF);
+
+ if (hasDummyByte) {
+ if (writeReadCmd(wriCmd, 3, reaCmd, 3, buff, toRead + 1) < 0) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_WR);
+ return ERROR_I2C_WR;
+ }
+ memcpy(outBuf, buff + 1, toRead);
+ } else {
+ if (writeReadCmd(wriCmd, 3, reaCmd, 3, buff, toRead) < 0)
+ return ERROR_I2C_WR;
+ memcpy(outBuf, buff, toRead);
+ }
+
+ address += toRead;
+
+ outBuf += toRead;
+
+ }
+
+ return OK;
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsIO.h b/drivers/input/touchscreen/st/fts_lib/ftsIO.h
new file mode 100644
index 000000000000..7bdeda2f9a2d
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsIO.h
@@ -0,0 +1,35 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* I2C/SPI Communication *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+#include "ftsCrossCompile.h"
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_RETRY 3 /* number */
+#define I2C_WAIT_BEFORE_RETRY 10 /* ms */
+
+int openChannel(struct i2c_client *clt);
+struct device *getDev(void);
+struct i2c_client *getClient(void);
+int fts_readCmd(u8 *cmd, int cmdLenght, u8 *outBuf, int byteToRead);
+int fts_writeCmd(u8 *cmd, int cmdLenght);
+int fts_writeFwCmd(u8 *cmd, int cmdLenght);
+int writeReadCmd(u8 *writeCmd, int writeCmdLenght, u8 *readCmd, int readCmdLenght, u8 *outBuf, int byteToRead);
+int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte);
+int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite);
+int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, int byteToWrite);
+int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, int hasDummyByte);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h b/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h
new file mode 100644
index 000000000000..c8bbc8e18d28
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h
@@ -0,0 +1,131 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FW related data *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsHardware.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#define ECHO_ENABLED 0x00000001
+
+/* chipInfo ftsInfo; */
+
+/* FTS FW COMAND */
+#define FTS_CMD_MS_MT_SENSE_OFF 0x92
+#define FTS_CMD_MS_MT_SENSE_ON 0x93
+#define FTS_CMD_SS_HOVER_OFF 0x94
+#define FTS_CMD_SS_HOVER_ON 0x95
+#define FTS_CMD_LP_TIMER_CALIB 0x97
+#define FTS_CMD_MS_KEY_OFF 0x9A
+#define FTS_CMD_MS_KEY_ON 0x9B
+#define FTS_CMD_MS_COMP_TUNING 0xA3
+#define FTS_CMD_SS_COMP_TUNING 0xA4
+#define FTS_CMD_FULL_INITIALIZATION 0xA5
+#define FTS_CMD_ITO_CHECK 0xA7
+#define FTS_CMD_RELEASE_INFO 0xAA
+#define FTS_CMD_GESTURE_MODE 0xAD
+#define FTS_CMD_REQU_FW_CONF 0xB2
+#define FTS_CMD_REQU_FRAME_DATA 0xB7
+#define FTS_CMD_REQU_COMP_DATA 0xB8
+#define FTS_CMD_WRITE_MP_FLAG 0xC0
+#define FTS_CMD_FEATURE_ENABLE 0xC1
+#define FTS_CMD_FEATURE_DISABLE 0xC2
+#define FTS_CMD_GESTURE_CMD 0xC3
+#define FTS_CMD_SAVE_CX_TUNING 0xFC
+
+/* Event ID */
+#define EVENTID_NO_EVENT 0x00
+#define EVENTID_ERROR_EVENT 0x0F
+#define EVENTID_CONTROL_READY 0x10
+#define EVENTID_FW_CONFIGURATION 0x12
+#define EVENTID_COMP_DATA_READ 0x13
+#define EVENTID_STATUS_UPDATE 0x16
+#define EVENTID_RELEASE_INFO 0x1C
+#define EVENTID_ENTER_POINTER 0x03
+#define EVENTID_LEAVE_POINTER 0x04
+#define EVENTID_MOTION_POINTER 0x05
+#define EVENTID_HOVER_ENTER_POINTER 0x07
+#define EVENTID_HOVER_LEAVE_POINTER 0x08
+#define EVENTID_HOVER_MOTION_POINTER 0x09
+#define EVENTID_PROXIMITY_ENTER 0x0B
+#define EVENTID_PROXIMITY_LEAVE 0x0C
+#define EVENTID_KEY_STATUS 0x0E
+#define EVENTID_GESTURE 0x22
+#define EVENTID_FRAME_DATA_READ 0x25
+#define EVENTID_ECHO 0xEC
+#define EVENTID_LAST (EVENTID_FRAME_DATA_READ+1)
+
+/* EVENT TYPE */
+#define EVENT_TYPE_MS_TUNING_CMPL 0x01
+#define EVENT_TYPE_SS_TUNING_CMPL 0x02
+#define EVENT_TYPE_COMP_DATA_SAVED 0x04
+#define EVENT_TYPE_ITO 0x05
+#define EVENT_TYPE_FULL_INITIALIZATION 0x07
+#define EVENT_TYPE_LPTIMER_TUNING_CMPL 0x20
+#define EVENT_TYPE_ESD_ERROR 0x0A
+#define EVENT_TYPE_WATCHDOG_ERROR 0x01
+
+/* CONFIG ID INFO */
+#define CONFIG_ID_ADDR 0x0001
+#define CONFIG_ID_BYTE 2
+
+/* ADDRESS OFFSET IN SYSINFO */
+#define ADDR_RAW_TOUCH 0x0000
+#define ADDR_FILTER_TOUCH 0x0002
+#define ADDR_NORM_TOUCH 0x0004
+#define ADDR_CALIB_TOUCH 0x0006
+#define ADDR_RAW_HOVER_FORCE 0x000A
+#define ADDR_RAW_HOVER_SENSE 0x000C
+#define ADDR_FILTER_HOVER_FORCE 0x000E
+#define ADDR_FILTER_HOVER_SENSE 0x0010
+#define ADDR_NORM_HOVER_FORCE 0x0012
+#define ADDR_NORM_HOVER_SENSE 0x0014
+#define ADDR_CALIB_HOVER_FORCE 0x0016
+#define ADDR_CALIB_HOVER_SENSE 0x0018
+#define ADDR_RAW_PRX_FORCE 0x001A
+#define ADDR_RAW_PRX_SENSE 0x001C
+#define ADDR_FILTER_PRX_FORCE 0x001E
+#define ADDR_FILTER_PRX_SENSE 0x0020
+#define ADDR_NORM_PRX_FORCE 0x0022
+#define ADDR_NORM_PRX_SENSE 0x0024
+#define ADDR_CALIB_PRX_FORCE 0x0026
+#define ADDR_CALIB_PRX_SENSE 0x0028
+#define ADDR_RAW_MS_KEY 0x0032
+#define ADDR_COMP_DATA 0x0050
+#define ADDR_FRAMEBUFFER_DATA 0x8000
+
+/* ADDRESS FW REGISTER */
+#define ADDR_SENSE_LEN 0x0014
+#define ADDR_FORCE_LEN 0x0015
+#define ADDR_MS_TUNING_VER 0x0729
+#define ADDR_SS_TUNING_VER 0x074E
+
+/* B2 INFO */
+#define B2_DATA_BYTES 4
+#define B2_CHUNK ((FIFO_DEPTH/2)*B2_DATA_BYTES) /* number of bytes */
+
+/* FEATURES */
+#define FEAT_GESTURE 0x00
+#define FEAT_GLOVE 0x01
+#define FEAT_STYLUS 0x02
+#define FEAT_COVER 0x04
+#define FEAT_CHARGER 0x08
+#define FEAT_VR 0x10
+#define FEAT_EDGE_REJECTION 0x20
+
+/* MP_FLAG_VALUE */
+#define INIT_MP 0xA5A5A501
+#define INIT_FIELD 0xA5A5A502
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.c b/drivers/input/touchscreen/st/fts_lib/ftsTest.c
new file mode 100644
index 000000000000..68bd04eff316
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.c
@@ -0,0 +1,2324 @@
+/*
+
+ **************************************************************************
+ ** STMicroelectronics **
+ **************************************************************************
+ ** marco.cali@st.com **
+ **************************************************************************
+ * *
+ * FTS API for MP test *
+ * *
+ **************************************************************************
+ **************************************************************************
+
+ */
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.h"
+#include "ftsError.h"
+#include "ftsFrame.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTest.h"
+#include "ftsTime.h"
+#include "ftsTool.h"
+#include "../fts.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+#ifdef LIMITS_H_FILE
+#include <../fts_limits.h>
+#endif
+
+/* static char tag[8] = "[ FTS ]\0"; */
+
+int computeAdjHoriz(u8 *data, int row, int column, u8 **result)
+{
+ int i, j;
+ int size = row * (column - 1);
+
+ if (column < 2) {
+ logError(1, "%s computeAdjHoriz: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u8 *) kmalloc(size * sizeof (u8), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjHoriz: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ for (i = 0; i < row; i++) {
+ for (j = 1; j < column; j++) {
+ *(*result + (i * (column - 1) + (j - 1))) = abs(data[i * column + j] - data[i * column + (j - 1)]);
+ }
+ }
+
+ return OK;
+
+}
+
+int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result)
+{
+ int i, j;
+ int size = row * (column - 1);
+
+ if (column < 2) {
+ logError(1, "%s computeAdjHorizTotal: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjHorizTotal: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ for (i = 0; i < row; i++) {
+ for (j = 1; j < column; j++) {
+ *(*result + (i * (column - 1) + (j - 1))) = abs(data[i * column + j] - data[i * column + (j - 1)]);
+ }
+ }
+
+ return OK;
+
+}
+
+int computeAdjVert(u8 *data, int row, int column, u8 **result)
+{
+ int i, j;
+ int size = (row - 1)*(column);
+
+ if (row < 2) {
+ logError(1, "%s computeAdjVert: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u8 *) kmalloc(size * sizeof (u8), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjVert: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ for (i = 1; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ *(*result + ((i - 1) * column + j)) = abs(data[i * column + j] - data[(i - 1) * column + j]);
+ }
+ }
+
+ return OK;
+}
+
+int computeAdjVertTotal(u16 *data, int row, int column, u16 **result)
+{
+ int i, j;
+ int size = (row - 1)*(column);
+
+ if (row < 2) {
+ logError(1, "%s computeAdjVertTotal: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjVertTotal: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ for (i = 1; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ *(*result + ((i - 1) * column + j)) = abs(data[i * column + j] - data[(i - 1) * column + j]);
+ }
+ }
+
+ return OK;
+}
+
+int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, u16 **result)
+{
+ int i, j;
+ int size = (row)*(column);
+
+ *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeTotal : ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ *(*result + (i * column + j)) = m * main + n * data[i * column + j];
+ }
+ }
+
+ return OK;
+}
+
+int checkLimitsMinMax(short *data, int row, int column, int min, int max)
+{
+ int i, j;
+ int count = 0;
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ if (data[i * column + j] < min || data[i * column + j] > max) {
+ logError(1, "%s checkLimitsMinMax: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, i, j, data[i * column + j], min, max);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+int checkLimitsGap(short *data, int row, int column, int threshold)
+{
+ int i, j;
+ int min_node;
+ int max_node;
+
+ if (row == 0 || column == 0) {
+ logError(1, "%s checkLimitsGap: invalid number of rows = %d or columns = %d ERROR %02\n", tag, row, column, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ min_node = data[0];
+ max_node = data[0];
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ if (data[i * column + j] < min_node) {
+ min_node = data[i * column + j];
+ } else {
+ if (data[i * column + j] > max_node)
+ max_node = data[i * column + j];
+ }
+ }
+ }
+
+ if (max_node - min_node > threshold) {
+ logError(1, "%s checkLimitsGap: GAP = %d exceed limit %d\n", tag, max_node - min_node, threshold);
+ return ERROR_TEST_CHECK_FAIL;
+ } else
+ return OK;
+
+}
+
+int checkLimitsMap(u8 *data, int row, int column, int *min, int *max)
+{
+ int i, j;
+ int count = 0;
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ if (data[i * column + j] < min[i * column + j] || data[i * column + j] > max[i * column + j]) {
+ logError(1, "%s checkLimitsMap: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, i, j, data[i * column + j], min[i * column + j], max[i * column + j]);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+int checkLimitsMapTotal(u16 *data, int row, int column, int *min, int *max)
+{
+ int i, j;
+ int count = 0;
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ if (data[i * column + j] < min[i * column + j] || data[i * column + j] > max[i * column + j]) {
+ logError(1, "%s checkLimitsMapTotal: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, i, j, data[i * column + j], min[i * column + j], max[i * column + j]);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+int checkLimitsMapAdj(u8 *data, int row, int column, int *max)
+{
+ int i, j;
+ int count = 0;
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ if (data[i * column + j] > max[i * column + j]) {
+ logError(1, "%s checkLimitsMapAdj: Node[%d,%d] = %d exceed limit > %d\n", tag, i, j, data[i * column + j], max[i * column + j]);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max)
+{
+ int i, j;
+ int count = 0;
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ if (data[i * column + j] > max[i * column + j]) {
+ logError(1, "%s checkLimitsMapAdjTotal: Node[%d,%d] = %d exceed limit > %d\n", tag, i, j, data[i * column + j], max[i * column + j]);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+int production_test_ito(void)
+{
+ int res = OK;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_ERROR_EVENT, EVENT_TYPE_ITO}; /* look for ito event */
+
+ logError(0, "%s ITO Production test is starting...\n", tag);
+
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_ito: ERROR %02X\n", tag, ERROR_PROD_TEST_ITO);
+ return (res | ERROR_PROD_TEST_ITO);
+ }
+
+ cmd = FTS_CMD_ITO_CHECK;
+
+ logError(0, "%s ITO Check command sent...\n", tag);
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s production_test_ito: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_PROD_TEST_ITO));
+ return (ERROR_I2C_W | ERROR_PROD_TEST_ITO);
+ }
+
+ logError(0, "%s Looking for ITO Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_ITO_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s production_test_ito: ITO Production test failed... ERROR %02X\n", tag, ERROR_PROD_TEST_ITO);
+ return (res | ERROR_PROD_TEST_ITO);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s ITO Production testes finished!.................FAILED ERROR %02X\n", tag, (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_ITO));
+ res = (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_ITO);
+ } else {
+ logError(0, "%s ITO Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ res |= fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_ito: ERROR %02X\n", tag, ERROR_PROD_TEST_ITO);
+ res = (res | ERROR_PROD_TEST_ITO);
+ }
+ return res;
+}
+
+int production_test_initialization(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_FULL_INITIALIZATION};
+
+ logError(0, "%s INITIALIZATION Production test is starting...\n", tag);
+
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ logError(0, "%s INITIALIZATION command sent...\n", tag);
+ cmd = FTS_CMD_FULL_INITIALIZATION;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s production_test_initialization: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_PROD_TEST_INITIALIZATION));
+ return (ERROR_I2C_W | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ logError(0, "%s Looking for INITIALIZATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ if (readData[2] != 0x00) {
+ logError(0, "%s INITIALIZATION Production testes finished!.................FAILED ERROR %02X\n", tag, (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_INITIALIZATION));
+ res = (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_INITIALIZATION);
+ } else {
+ logError(0, "%s INITIALIZATION Production test.................OK\n", tag);
+ res = OK;
+ }
+
+ logError(0, "%s Refresh Chip Info...\n", tag);
+ res |= readChipInfo(1);
+ /* need to update the chipInfo in order to refresh the tuning_versione */
+
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: read chip info ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ res = (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ return res;
+
+}
+
+int ms_compensation_tuning(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_MS_TUNING_CMPL};
+
+ logError(0, "%s MS INITIALIZATION command sent...\n", tag);
+ cmd = FTS_CMD_MS_COMP_TUNING;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s ms_compensation_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_MS_TUNING));
+ return (ERROR_I2C_W | ERROR_MS_TUNING);
+ }
+
+ logError(0, "%s Looking for MS INITIALIZATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s ms_compensation_tuning: MS INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_MS_TUNING);
+ return (res | ERROR_MS_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s MS INITIALIZATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_MS_TUNING);
+ res = ERROR_MS_TUNING;
+ } else {
+ logError(0, "%s MS INITIALIZATION Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int ss_compensation_tuning(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_SS_TUNING_CMPL};
+
+ logError(0, "%s SS INITIALIZATION command sent...\n", tag);
+ cmd = FTS_CMD_SS_COMP_TUNING;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s ss_compensation_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_SS_TUNING));
+ return (ERROR_I2C_W | ERROR_SS_TUNING);
+ }
+
+ logError(0, "%s Looking for SS INITIALIZATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s ms_compensation_tuning: SS INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_SS_TUNING);
+ return (res | ERROR_SS_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s SS INITIALIZATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_SS_TUNING);
+ res = ERROR_SS_TUNING;
+ } else {
+ logError(0, "%s SS INITIALIZATION Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int lp_timer_calibration(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_LPTIMER_TUNING_CMPL};
+
+ logError(0, "%s LP TIMER CALIBRATION command sent...\n", tag);
+ cmd = FTS_CMD_LP_TIMER_CALIB;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s lp_timer_calibration 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_LP_TIMER_TUNING));
+ return (ERROR_I2C_W | ERROR_LP_TIMER_TUNING);
+ }
+
+ logError(0, "%s Looking for LP TIMER CALIBRATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s lp_timer_calibration: LP TIMER CALIBRATION Production test failed... ERROR %02X\n", tag, ERROR_LP_TIMER_TUNING);
+ return (res | ERROR_LP_TIMER_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x01) {
+ logError(0, "%s LP TIMER CALIBRATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_LP_TIMER_TUNING);
+ res = ERROR_LP_TIMER_TUNING;
+ } else {
+ logError(0, "%s LP TIMER CALIBRATION Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int save_cx_tuning(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_COMP_DATA_SAVED};
+
+ logError(0, "%s SAVE CX command sent...\n", tag);
+ cmd = FTS_CMD_SAVE_CX_TUNING;
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s save_cx_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_SAVE_CX_TUNING));
+ return (ERROR_I2C_W | ERROR_SAVE_CX_TUNING);
+ }
+
+ logError(0, "%s Looking for SAVE CX Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s save_cx_tuning: SAVE CX failed... ERROR %02X\n", tag, ERROR_SAVE_CX_TUNING);
+ return (res | ERROR_SAVE_CX_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s SAVE CX finished!.................FAILED ERROR %02X\n", tag, ERROR_SAVE_CX_TUNING);
+ res = ERROR_SAVE_CX_TUNING;
+ } else {
+ logError(0, "%s SAVE CX finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int production_test_splited_initialization(int saveToFlash)
+{
+ int res;
+
+ logError(0, "%s Splitted Initialization test is starting...\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ logError(0, "%s LP INITIALIZATION TEST:\n", tag);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ logError(0, "%s MS INITIALIZATION TEST:\n", tag);
+ res = ms_compensation_tuning();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: MS INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s MS INITIALIZATION TEST OK!\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s SS INITIALIZATION TEST:\n", tag);
+ res = ss_compensation_tuning();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: SS INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s SS INITIALIZATION TEST OK!\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s LP INITIALIZATION TEST:\n", tag);
+ res = lp_timer_calibration();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: LP INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s LP INITIALIZATION TEST OK!\n", tag);
+ if (saveToFlash) {
+ logError(0, "%s\n", tag);
+ logError(0, "%s SAVE CX TEST:\n", tag);
+ res = save_cx_tuning();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: SAVE CX TEST FAILED! ERROR %02X\n", tag, res);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s SAVE CX TEST OK!\n", tag);
+ }
+ logError(0, "%s Refresh Chip Info...\n", tag);
+ res |= readChipInfo(1);
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: read chip info ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ res = (res | ERROR_PROD_TEST_INITIALIZATION);
+ } else
+ logError(0, "%s Splited Initialization test finished!.................OK\n", tag);
+ return res;
+}
+
+int production_test_main(char *pathThresholds, int stop_on_fail,
+ int saveInit, TestToDo *todo, u32 signature)
+{
+ int res, ret;
+
+ logError(0, "%s MAIN Production test is starting...\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s ITO TEST:\n", tag);
+ res = production_test_ito();
+ if (res < 0) {
+ logError(0, "%s Error during ITO TEST! ERROR %02X\n", tag, (u8) res);
+ goto END; /* in case of ITO TEST failure is no sense keep going */
+ } else {
+ logError(0, "%s ITO TEST OK!\n", tag);
+ }
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s INITIALIZATION TEST :\n", tag);
+ if (saveInit == 1) {
+ res = production_test_initialization();
+ if (res < 0) {
+ logError(0, "%s Error during INITIALIZATION TEST! ERROR %02X\n", tag, (u8) res);
+ if (stop_on_fail)
+ goto END;
+ } else {
+ logError(0, "%s INITIALIZATION TEST OK!\n", tag);
+ }
+ } else
+ logError(0, "%s INITIALIZATION TEST :................. SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ if (saveInit == 1) {
+ logError(0, "%s Cleaning up...\n", tag);
+ ret = cleanUp(0);
+ if (ret < 0) {
+ logError(1, "%s production_test_main: clean up ERROR %02X\n", tag, ret);
+ res |= ret;
+ if (stop_on_fail)
+ goto END;
+ }
+ logError(0, "%s\n", tag);
+ }
+
+ logError(0, "%s PRODUCTION DATA TEST:\n", tag);
+ ret = production_test_data(pathThresholds, stop_on_fail, todo);
+ if (ret < 0) {
+ logError(0, "%s Error during PRODUCTION DATA TEST! ERROR %02X\n", tag, ret);
+ } else {
+ logError(0, "%s PRODUCTION DATA TEST OK!\n", tag);
+ }
+
+ res |= ret;
+ /* the OR is important because if the data test is OK but the inizialization test fail,
+ * the main production test result should = FAIL
+ */
+
+ if (ret == OK && saveInit == 1) {
+ logError(0, "%s SAVE FLAG:\n", tag);
+ ret = save_mp_flag(signature);
+ if (ret < OK)
+ logError(0, "%s SAVE FLAG:................. FAIL! ERROR %08X\n", tag, ret);
+ else
+ logError(0, "%s SAVE FLAG:................. OK!\n", tag);
+ res |= ret;
+ }
+
+ logError(0, "%s\n", tag);
+END:
+ if (res < 0) {
+ logError(0, "%s MAIN Production test finished.................FAILED\n", tag);
+ return res;
+ }
+ logError(0, "%s MAIN Production test finished.................OK\n", tag);
+ return OK;
+}
+
+int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+
+ int ret, count_fail = 0;
+ MutualSenseFrame msRawFrame;
+
+ int *thresholds = NULL;
+ int trows, tcolumns;
+
+ /*********************** Mutual Sense Test **********************/
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS RAW DATA TEST is starting...\n", tag);
+ if (todo->MutualRaw == 1 || todo->MutualRawGap == 1) {
+
+ ret = getMSFrame2(MS_TOUCH_ACTIVE, &msRawFrame);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: getMSFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s MS RAW MIN MAX TEST:\n", tag);
+ if (todo->MutualRaw == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_RAW_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS RAW failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS RAW MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail == 1)
+ goto ERROR;
+ }
+ kfree(thresholds);
+ logError(0, "%s MS RAW MIN MAX TEST:.................OK\n", tag);
+ } else
+ logError(0, "%s MS RAW MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS RAW GAP TEST:\n", tag);
+ if (todo->MutualRawGap == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_RAW_GAP, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsGap(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsGap MS RAW failed... ERROR = %02X\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail == 1)
+ goto ERROR;
+
+ } else
+ logError(0, "%s MS RAW GAP TEST:.................OK\n\n", tag);
+ kfree(thresholds);
+ } else
+ logError(0, "%s MS RAW GAP TEST:.................SKIPPED\n", tag);
+
+ kfree(msRawFrame.node_data);
+ } else
+ logError(0, "%s MS RAW FRAME TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS KEY RAW TEST:\n", tag);
+ if (todo->MutualKeyRaw == 1) {
+ ret = production_test_ms_key_raw(path_limits);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: production_test_ms_key_raw failed... ERROR = %02X\n", tag, ret);
+ count_fail += 1;
+ }
+ } else
+ logError(0, "%s MS KEY RAW TEST:.................SKIPPED\n", tag);
+
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s MS RAW DATA TEST finished!.................OK\n", tag);
+ return OK;
+ }
+ print_frame_short("MS Raw frame =", array1dTo2d_short(msRawFrame.node_data, msRawFrame.node_data_size, msRawFrame.header.sense_node), msRawFrame.header.force_node, msRawFrame.header.sense_node);
+ logError(0, "%s MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+}
+
+int production_test_ms_key_raw(char *path_limits)
+{
+
+ int ret;
+ MutualSenseFrame msRawFrame;
+
+ int *thresholds = NULL;
+ int trows, tcolumns;
+
+ /******************************* Mutual Sense Test *******************************/
+ logError(0, "%s MS KEY RAW DATA TEST is starting...\n", tag);
+
+ ret = getMSFrame2(MS_KEY, &msRawFrame);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: getMSKeyFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_RAW_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_RAW_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS KEY RAW failed... ERROR COUNT = %d\n", tag, ret);
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY RAW TEST:.................OK\n\n", tag);
+
+ kfree(thresholds);
+
+ kfree(msRawFrame.node_data);
+
+ return OK;
+
+ERROR:
+ print_frame_short("MS Key Raw frame =", array1dTo2d_short(msRawFrame.node_data, msRawFrame.node_data_size, msRawFrame.header.sense_node), msRawFrame.header.force_node, msRawFrame.header.sense_node);
+ logError(0, "%s MS KEY RAW TEST:.................FAIL\n\n", tag);
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+
+}
+
+int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+
+ int ret;
+ int count_fail = 0;
+
+ int *thresholds = NULL;
+ int *thresholds_min = NULL;
+ int *thresholds_max = NULL;
+ int trows, tcolumns;
+
+ MutualSenseData msCompData;
+
+ u8 *adjhor = NULL;
+
+ u8 *adjvert = NULL;
+
+ u16 container;
+ u16 *total_cx = NULL;
+ u16 *total_adjhor = NULL;
+ u16 *total_adjvert = NULL;
+
+ /* MS CX TEST */
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS CX Testes are starting...\n", tag);
+
+ ret = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, &msCompData); /* read MS compensation data */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: readMutualSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s MS CX1 TEST:\n", tag);
+ if (todo->MutualCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, MS_CX1_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX1_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) msCompData.cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX1 TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX1 TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s MS CX1 TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+
+ logError(0, "%s MS CX2 MIN MAX TEST:\n", tag);
+ if (todo->MutualCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS CX2 MIN MAX failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX2 MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX2 MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s MS CX2 MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s MS CX2 ADJ TEST:\n", tag);
+ if (todo->MutualCx2Adj == 1) {
+ /* MS CX2 ADJ HORIZ */
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:\n", tag);
+
+ ret = computeAdjHoriz(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, &adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS CX2 ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_CX2_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjhor, msCompData.header.force_node, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj CX2 ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjhor);
+
+ /* MS CX2 ADJ VERT */
+ logError(0, "%s MS CX2 ADJ VERT TEST:\n", tag);
+
+ ret = computeAdjVert(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, &adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS CX2 ADJ VERT computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_CX2_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node - 1 || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjvert, msCompData.header.force_node - 1, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj CX2 ADJV failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX2 ADJ VERT TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjvert);
+ } else
+ logError(0, "%s MS CX2 ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* START OF TOTAL CHECK */
+ logError(0, "%s MS TOTAL CX TEST:\n", tag);
+
+ if (todo->MutualCxTotal == 1 || todo->MutualCxTotalAdj == 1) {
+ ret = computeTotal(msCompData.node_data, msCompData.cx1, msCompData.header.force_node, msCompData.header.sense_node, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotalCx failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:\n", tag);
+ if (todo->MutualCxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS TOTAL CX TEST failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s MS TOTAL CX ADJ TEST:\n", tag);
+ if (todo->MutualCxTotalAdj == 1) {
+ /* MS TOTAL CX ADJ HORIZ */
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:\n", tag);
+
+ /* thresholds_max = NULL; */
+ ret = computeAdjHorizTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, &total_adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS TOTAL CX ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjhor, msCompData.header.force_node, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjhor);
+
+ /* MS TOTAL CX ADJ VERT */
+ logError(0, "%s MS TOTAL CX ADJ VERT TEST:\n", tag);
+
+ ret = computeAdjVertTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, &total_adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS TOTAL CX ADJ VERT computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node - 1 || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjvert, msCompData.header.force_node - 1, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJV failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS TOTAL CX ADJ VERT TEST:.................OK\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjvert);
+ } else
+ logError(0, "%s MS TOTAL CX ADJ TEST:.................SKIPPED\n", tag);
+
+ kfree(total_cx);
+ } else
+ logError(0, "%s MS TOTAL CX TEST:.................SKIPPED\n", tag);
+
+ kfree(msCompData.node_data);
+
+ if ((todo->MutualKeyCx1 | todo->MutualKeyCx2 | todo->MutualKeyCxTotal) == 1) {
+ ret = production_test_ms_key_cx(path_limits, stop_on_fail, todo);
+ if (ret < 0) {
+ count_fail += 1;
+ logError(1, "%s production_test_data: production_test_ms_key_cx failed... ERROR = %02X\n", tag, ret);
+ logError(0, "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return ret;
+ }
+ } else
+ logError(0, "%s MS KEY CX TEST:.................SKIPPED\n", tag);
+
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s MS CX testes finished!.................OK\n", tag);
+ return OK;
+ }
+ print_frame_u8("MS Init Data (Cx2) =", array1dTo2d_u8(msCompData.node_data, msCompData.node_data_size, msCompData.header.sense_node), msCompData.header.force_node, msCompData.header.sense_node);
+ logError(0, "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+
+}
+
+int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+
+ int ret;
+ int count_fail = 0;
+ int num_keys = 0;
+
+ int *thresholds = NULL;
+ int *thresholds_min = NULL;
+ int *thresholds_max = NULL;
+ int trows, tcolumns;
+
+ MutualSenseData msCompData;
+
+ u16 container;
+ u16 *total_cx = NULL;
+
+ /* MS CX TEST */
+ logError(0, "%s MS KEY CX Testes are starting...\n", tag);
+
+ ret = readMutualSenseCompensationData(MS_KEY, &msCompData); /* read MS compensation data */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: readMutualSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ if (msCompData.header.force_node > msCompData.header.sense_node)
+/* the meaningful data are only in the first row, the other rows are only a copy of the first one */
+ num_keys = msCompData.header.force_node;
+ else
+ num_keys = msCompData.header.sense_node;
+
+ logError(0, "%s MS KEY CX1 TEST:\n", tag);
+ if (todo->MutualKeyCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_CX1_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX1_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) msCompData.cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS KEY CX1 TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY CX1 TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s MS KEY CX1 TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+
+ logError(0, "%s MS KEY CX2 TEST:\n", tag);
+ if (todo->MutualKeyCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_KEY_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(msCompData.node_data, 1, num_keys, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS KEY CX2 failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS KEY CX2 TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY CX2 TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s MS CX2 TEST:.................SKIPPED\n\n", tag);
+
+ /* START OF TOTAL CHECK */
+ logError(0, "%s MS KEY TOTAL CX TEST:\n", tag);
+
+ if (todo->MutualKeyCxTotal == 1) {
+ ret = computeTotal(msCompData.node_data, msCompData.cx1, 1, num_keys, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotalCx failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, 1, num_keys, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS TOTAL KEY CX TEST failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS KEY TOTAL CX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY TOTAL CX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+
+ kfree(total_cx);
+ } else
+ logError(0, "%s MS KEY TOTAL CX TEST:.................SKIPPED\n", tag);
+
+ kfree(msCompData.node_data);
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s MS KEY CX testes finished!.................OK\n", tag);
+ return OK;
+ }
+ print_frame_u8("MS Key Init Data (Cx2) =", array1dTo2d_u8(msCompData.node_data, msCompData.node_data_size, msCompData.header.sense_node), 1, msCompData.header.sense_node);
+ logError(0, "%s MS Key CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+}
+
+int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+ int ret;
+ int count_fail = 0;
+ int rows, columns;
+
+ /* short *ssRawFrame = NULL; */
+ SelfSenseFrame ssRawFrame;
+
+ int *thresholds = NULL;
+ int trows, tcolumns;
+
+ /* MS SS TEST */
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS RAW Testes are starting...\n", tag);
+
+ /******************************* Self Sense Test *******************************/
+
+ logError(0, "%s Getting SS Frame...\n", tag);
+ ret = getSSFrame2(SS_TOUCH, &ssRawFrame);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: getSSFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ /* SS RAW (PROXIMITY) FORCE TEST */
+ logError(0, "%s SS RAW (PROXIMITY) FORCE TEST:\n", tag);
+
+ if (todo->SelfForceRaw == 1 || todo->SelfForceRawGap == 1) {
+
+ columns = 1;
+ /* there are no data for the sense channels due to the fact that the force frame is analized */
+ rows = ssRawFrame.header.force_node;
+
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceRaw == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_RAW_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(ssRawFrame.force_data, rows, columns, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS RAW (PROXIMITY) FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw force frame =", array1dTo2d_short(ssRawFrame.force_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:\n", tag);
+ if (todo->SelfForceRawGap == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_RAW_FORCE_GAP, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsGap(ssRawFrame.force_data, rows, columns, thresholds[0]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsGap SS RAW (PROXIMITY) FORCE GAP failed... ERROR = %02X\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw force frame =", array1dTo2d_short(ssRawFrame.force_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................OK\n\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................SKIPPED\n\n", tag);
+
+ kfree(ssRawFrame.force_data);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s\n", tag);
+ /* SS RAW (PROXIMITY) SENSE TEST */
+ logError(0, "%s SS RAW (PROXIMITY) SENSE TEST:\n", tag);
+
+ if (todo->SelfSenseRaw == 1 || todo->SelfSenseRawGap == 1) {
+ columns = ssRawFrame.header.sense_node;
+ rows = 1; /* there are no data for the force channels due to the fact that the sense frame is analized */
+
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseRaw == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_RAW_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(ssRawFrame.sense_data, rows, columns, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS RAW (PROXIMITY) SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................FAIL\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw sense frame =", array1dTo2d_short(ssRawFrame.sense_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................OK\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:\n", tag);
+ if (todo->SelfSenseRawGap == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_RAW_SENSE_GAP, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsGap(ssRawFrame.sense_data, rows, columns, thresholds[0]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsGap SS RAW (PROXIMITY) SENSE GAP failed... ERROR = %02X\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................FAIL\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw sense frame =", array1dTo2d_short(ssRawFrame.sense_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................OK\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................SKIPPED\n", tag);
+
+ kfree(ssRawFrame.sense_data);
+ }
+
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s SS RAW testes finished!.................OK\n\n", tag);
+ return OK;
+ }
+ logError(0, "%s SS RAW testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+}
+
+int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+
+ int ret;
+ int count_fail = 0;
+
+ int *thresholds = NULL;
+ int trows, tcolumns;
+ int *thresholds_min = NULL;
+ int *thresholds_max = NULL;
+
+ SelfSenseData ssCompData;
+
+ u8 *adjhor = NULL;
+ u8 *adjvert = NULL;
+
+ u16 container;
+ int *ix1_w, *ix2_w;
+ u16 *total_ix = NULL;
+ u16 *total_cx = NULL;
+
+ u16 *total_adjhor = NULL;
+ u16 *total_adjvert = NULL;
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS IX CX testes are starting...\n", tag);
+ ret = readSelfSenseCompensationData(SS_TOUCH, &ssCompData); /* read the SS compensation data */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: readSelfSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ /*************************** SS FORCE IX *************************************/
+ /* SS IX1 FORCE TEST */
+ logError(0, "%s SS IX1 FORCE TEST:\n", tag);
+ if (todo->SelfForceIx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_IX1_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ container = (u16) ssCompData.f_ix1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS IX1 FORCE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX1 FORCE TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s SS IX1 FORCE TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+ /* SS IX2 FORCE TEST */
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceIx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.ix2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s SS IX2 FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceIx2Adj == 1) {
+ /* SS IX2 FORCE ADJV TEST */
+ logError(0, "%s SS IX2 FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVert(ssCompData.ix2_fm, ssCompData.header.force_node, 1, &adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS IX2 FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS IX2 FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max);
+ /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjvert);
+
+ } else
+ logError(0, "%s SS IX2 FORCE ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* SS TOTAL FORCE IX */
+ logError(0, "%s SS TOTAL IX FORCE TEST:\n", tag);
+ if (todo->SelfForceIxTotal == 1 || todo->SelfForceIxTotalAdj == 1) {
+ logError(0, "%s Reading TOTAL IX FORCE Weights...\n", tag);
+ ret = parseProductionTestLimits(path_limits, SS_IX1_FORCE_W, &ix1_w, &trows, &tcolumns); /* load the IX1 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_W, &ix2_w, &trows, &tcolumns); /* load the IX2 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", tag, *ix1_w, *ix2_w);
+
+ ret = computeTotal(ssCompData.ix2_fm, ssCompData.f_ix1, ssCompData.header.force_node, 1, *ix1_w, *ix2_w, &total_ix);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Ix Force failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceIxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_ix, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS TOTAL IX FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceIxTotalAdj == 1) {
+ /* SS TOTAL IX FORCE ADJV TEST */
+ logError(0, "%s SS TOTAL IX FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVertTotal(total_ix, ssCompData.header.force_node, 1, &total_adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS TOTAL IX FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL IX FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_ADJV_MAP_MAX... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjvert);
+ } else
+ logError(0, "%s SS TOTAL IX FORCE ADJ TEST:.................SKIPPED\n", tag);
+
+ kfree(total_ix);
+ } else
+ logError(0, "%s SS TOTAL IX FORCE TEST:.................SKIPPED\n\n", tag);
+
+ /******************* SS SENSE IX **************************/
+ /* SS IX1 SENSE TEST */
+ logError(0, "%s SS IX1 SENSE TEST:\n", tag);
+ if (todo->SelfSenseIx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_IX1_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) ssCompData.s_ix1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS IX1 SENSE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX1 SENSE TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s SS IX1 SENSE TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+ /* SS IX2 SENSE TEST */
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseIx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s SS IX2 SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseIx2Adj == 1) {
+ /* SS IX2 SENSE ADJH TEST */
+ logError(0, "%s SS IX2 SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHoriz(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, &adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS IX2 SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS IX2 SENSE ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS IX2 SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 SENSE ADJH TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjhor);
+ } else
+ logError(0, "%s SS IX2 SENSE ADJ TEST:.................SKIPPED\n", tag);
+
+ /* SS TOTAL IX SENSE */
+ logError(0, "%s SS TOTAL IX SENSE TEST:\n", tag);
+ if (todo->SelfSenseIxTotal == 1 || todo->SelfSenseIxTotalAdj == 1) {
+ logError(0, "%s Reading TOTAL IX SENSE Weights...\n", tag);
+ ret = parseProductionTestLimits(path_limits, SS_IX1_SENSE_W, &ix1_w, &trows, &tcolumns); /* load the IX1 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_W, &ix2_w, &trows, &tcolumns); /* load the IX2 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", tag, *ix1_w, *ix2_w);
+
+ ret = computeTotal(ssCompData.ix2_sn, ssCompData.s_ix1, 1, ssCompData.header.sense_node, *ix1_w, *ix2_w, &total_ix);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Ix Sense failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseIxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_ix, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS TOTAL IX SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseIxTotalAdj == 1) {
+ /* SS TOTAL IX SENSE ADJH TEST */
+ logError(0, "%s SS TOTAL IX SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHorizTotal(total_ix, 1, ssCompData.header.sense_node, &total_adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS TOTAL IX SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL IX SENSE ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS TOTAL IX SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX SENSE ADJH TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjhor);
+ } else
+ logError(0, "%s SS TOTAL IX SENSE ADJ TEST:.................SKIPPED\n", tag);
+ kfree(total_ix);
+ } else
+ logError(0, "%s SS TOTAL IX SENSE TEST:.................SKIPPED\n", tag);
+
+ /*********************** SS SENSE CX ******************************/
+ /* SS CX1 FORCE TEST */
+ logError(0, "%s SS CX1 FORCE TEST:\n", tag);
+ if (todo->SelfForceCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_CX1_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX1_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) ssCompData.f_cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS CX1 FORCE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ /* if (stop_on_fail) return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); */
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX1 FORCE TEST:.................OK\n\n", tag);
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS CX1 FORCE TEST:.................SKIPPED\n\n", tag);
+
+ /* SS CX2 FORCE TEST */
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.cx2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS CX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS CX2 FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceCx2Adj == 1) {
+ /* SS CX2 FORCE ADJV TEST */
+ logError(0, "%s SS CX2 FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVert(ssCompData.cx2_fm, ssCompData.header.force_node,
+ 1, &adjvert); /* comepute the ADJV for CX2 FORCE */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS CX2 FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS CX2 FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjvert);
+ } else
+ logError(0, "%s SS CX2 FORCE ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* SS TOTAL CX FORCE */
+ logError(0, "%s SS TOTAL CX FORCE TEST:\n", tag);
+ if (todo->SelfForceCxTotal == 1 || todo->SelfForceCxTotalAdj == 1) {
+ ret = computeTotal(ssCompData.cx2_fm, ssCompData.f_cx1, ssCompData.header.force_node, 1, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Cx Force failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL CX FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceCxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL CX FORCE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ /* SS TOTAL CX FORCE ADJV TEST */
+ logError(0, "%s SS TOTAL CX FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceCxTotalAdj == 1) {
+ logError(0, "%s SS TOTAL CX FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVertTotal(total_cx, ssCompData.header.force_node, 1, &total_adjvert); /* comepute the ADJV for CX2 FORCE */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS TOTAL CX FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL CX FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL CX FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL CX FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL CX FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjvert);
+
+ } else
+ logError(0, "%s SS TOTAL CX FORCE ADJ TEST:.................SKIPPED\n", tag);
+ kfree(total_cx);
+ } else
+ logError(0, "%s SS TOTAL CX FORCE TEST:.................SKIPPED\n\n", tag);
+
+ /* ********************** SS SENSE CX ************************************/
+ /* SS CX1 SENSE TEST */
+ logError(0, "%s SS CX1 SENSE TEST:\n", tag);
+ if (todo->SelfSenseCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_CX1_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX1_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) ssCompData.s_cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS CX1 SENSE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX1 SENSE TEST:.................OK\n\n", tag);
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS CX1 SENSE TEST:.................SKIPPED\n\n", tag);
+
+ /* SS CX2 SENSE TEST */
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.cx2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS CX2 SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS CX2 SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseCx2Adj == 1) {
+ /* SS CX2 SENSE ADJH TEST */
+ logError(0, "%s SS CX2 SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHoriz(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, &adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS CX2 SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS CX2 SENSE ADJH computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS CX2 SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 SENSE ADJH TEST:.................OK\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjhor);
+ } else
+ logError(0, "%s SS CX2 SENSE ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* SS TOTAL CX SENSE */
+ logError(0, "%s SS TOTAL CX SENSE TEST:\n", tag);
+ if (todo->SelfSenseCxTotal == 1 || todo->SelfSenseCxTotalAdj == 1) {
+ ret = computeTotal(ssCompData.cx2_sn, ssCompData.s_cx1, 1, ssCompData.header.sense_node, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Cx Sense failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseCxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL CX SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ /* SS TOTAL IX SENSE ADJH TEST */
+ logError(0, "%s SS TOTAL CX SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseCxTotalAdj == 1) {
+ logError(0, "%s SS TOTAL CX SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHorizTotal(total_cx, 1, ssCompData.header.sense_node, &total_adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS TOTAL CX SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL CX SENSE ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS TOTAL CX SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL CX SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL CX SENSE ADJH TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjhor);
+ } else
+ logError(0, "%s SS TOTAL CX SENSE ADJ TEST:.................SKIPPED\n", tag);
+ kfree(total_cx);
+ } else
+ logError(0, "%s SS TOTAL CX SENSE TEST:.................SKIPPED\n", tag);
+
+ /* SS compensation data are no usefull anymore */
+
+ kfree(ssCompData.ix2_fm);
+ kfree(ssCompData.ix2_sn);
+ kfree(ssCompData.cx2_fm);
+ kfree(ssCompData.cx2_sn);
+
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s SS IX CX testes finished!.................OK\n\n", tag);
+ return OK;
+ }
+ /* print all kind of data in just one row for readability reason */
+ print_frame_u8("SS Init Data Ix2_fm = ", array1dTo2d_u8(ssCompData.ix2_fm, ssCompData.header.force_node, ssCompData.header.force_node), 1, ssCompData.header.force_node);
+ print_frame_u8("SS Init Data Cx2_fm = ", array1dTo2d_u8(ssCompData.cx2_fm, ssCompData.header.force_node, ssCompData.header.force_node), 1, ssCompData.header.force_node);
+ print_frame_u8("SS Init Data Ix2_sn = ", array1dTo2d_u8(ssCompData.ix2_sn, ssCompData.header.sense_node, ssCompData.header.sense_node), 1, ssCompData.header.sense_node);
+ print_frame_u8("SS Init Data Cx2_sn = ", array1dTo2d_u8(ssCompData.cx2_sn, ssCompData.header.sense_node, ssCompData.header.sense_node), 1, ssCompData.header.sense_node);
+ logError(0, "%s SS IX CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+}
+
+int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+ int res = OK, ret;
+
+ if (todo == NULL) {
+ logError(1, "%s production_test_data: No TestToDo specified!! ERROR = %02X\n", tag, (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA));
+ return (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s DATA Production test is starting...\n", tag);
+
+ ret = production_test_ms_raw(path_limits, stop_on_fail, todo);
+ res |= ret;
+ if (ret < 0) {
+ logError(1, "%s production_test_data: production_test_ms_raw failed... ERROR = %02X\n", tag, ret);
+ if (stop_on_fail == 1)
+ goto END;
+ }
+
+ ret = production_test_ms_cx(path_limits, stop_on_fail, todo);
+ res |= ret;
+ if (res < 0) {
+ logError(1, "%s production_test_data: production_test_ms_cx failed... ERROR = %02X\n", tag, ret);
+ if (stop_on_fail == 1)
+ goto END;
+ }
+
+ ret = production_test_ss_raw(path_limits, stop_on_fail, todo);
+ res |= ret;
+ if (ret < 0) {
+ logError(1, "%s production_test_data: production_test_ss_raw failed... ERROR = %02X\n", tag, ret);
+ if (stop_on_fail == 1)
+ goto END;
+ }
+
+ ret = production_test_ss_ix_cx(path_limits, stop_on_fail, todo);
+ res |= ret;
+ if (ret < 0) {
+ logError(1, "%s production_test_data: production_test_ss_ix_cx failed... ERROR = %02X\n", tag, ret);
+ if (stop_on_fail == 1)
+ goto END;
+ }
+
+END:
+ if (res < OK)
+ logError(0, "%s DATA Production test failed!\n", tag);
+ else
+ logError(0, "%s DATA Production test finished!\n", tag);
+ return res;
+}
+
+int save_mp_flag(u32 signature)
+{
+ int res = -1, ret;
+ int i;
+ u8 cmd[6] = {FTS_CMD_WRITE_MP_FLAG, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ u32ToU8(signature, &cmd[2]);
+
+ logError(0, "%s Starting Saving Flag with signature = %08X ...\n", tag, signature);
+
+ for (i = 0; i < SAVE_FLAG_RETRY && res < OK; i++) {
+ logError(0, "%s Attempt number %d to save mp flag !\n", tag, i+1);
+ logError(0, "%s Command write flag sent...\n", tag);
+ res = fts_writeFwCmd(cmd, 6);
+ if (res >= OK)
+ res = save_cx_tuning();
+
+ }
+
+ ret = readChipInfo(1); /* need to update the MP Flag */
+ if (ret < OK) {
+ logError(1, "%s save_mp_flag: read chip info ERROR %08X\n", tag, ret);
+ }
+
+ res |= ret;
+ if (res < OK) {
+ logError(1, "%s save_mp_flag: ERROR %08X ...\n", tag, res);
+ return res;
+ }
+ logError(1, "%s Saving Flag DONE!\n", tag);
+ return OK;
+}
+
+int parseProductionTestLimits(char *path, char *label, int **data, int *row, int *column)
+{
+
+ int find = 0;
+ char *token = NULL;
+ int i = 0;
+ int j = 0;
+ int z = 0;
+
+ char *line = NULL;
+ int fd = -1;
+ char *buf = NULL;
+ int n, size, pointer = 0, ret;
+ char *data_file = NULL;
+#ifndef LIMITS_H_FILE
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+
+ dev = getDev();
+ if (dev != NULL)
+ fd = request_firmware(&fw, path, dev);
+#else
+ fd = 0;
+#endif
+
+ line = (char *)kmalloc(1800*sizeof(char), GFP_KERNEL);
+ buf = line;
+
+ if (fd == 0) {
+#ifndef LIMITS_H_FILE
+ size = fw->size;
+ data_file = (char *)fw->data;
+ logError(0, "%s Start to reading %s...\n", tag, path);
+#else
+ size = LIMITS_SIZE_NAME;
+ data_file = (char *)(LIMITS_ARRAY_NAME);
+#endif
+
+ logError(0, "%s The size of the limits file is %d bytes...\n", tag, size);
+
+ while (find == 0) {
+ /* start to look for the wanted label */
+ if (readLine(&data_file[pointer], &line, size-pointer, &n) < 0) {
+ find = -1;
+ break;
+ }
+ pointer += n;
+ if (line[0] == '*') { /* each header row start with * ex. *label,n_row,n_colum */
+ buf = line;
+ line += 1;
+ token = strsep(&line, ",");
+ if (strcmp(token, label) == 0) {
+ /* if the row is the wanted one i retrieve rows and columns info */
+ find = 1;
+ token = strsep(&line, ",");
+ if (token != NULL) {
+ sscanf(token, "%d", row);
+ logError(0, "%s Row = %d\n", tag, *row);
+ } else {
+ logError(1, "%s parseProductionTestLimits 1: ERROR %02X\n", tag, ERROR_FILE_PARSE);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_PARSE; */
+ ret = ERROR_FILE_PARSE;
+ goto END;
+ }
+ token = strsep(&line, ",");
+ if (token != NULL) {
+ sscanf(token, "%d", column);
+ logError(0, "%s Column = %d\n", tag, *column);
+ } else {
+ logError(1, "%s parseProductionTestLimits 2: ERROR %02X\n", tag, ERROR_FILE_PARSE);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_PARSE; */
+ ret = ERROR_FILE_PARSE;
+ goto END;
+ }
+
+ *data = (int *)kmalloc(((*row)*(*column))*sizeof(int), GFP_KERNEL);
+ /* allocate the memory for containing the data */
+ j = 0;
+ if (*data == NULL) {
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_ALLOC);
+ /* release_firmware(fw); */
+ /* return ERROR_ALLOC; */
+ ret = ERROR_ALLOC;
+ goto END;
+ }
+
+ /* start to read the data */
+ for (i = 0; i < *row; i++) {
+ line = buf;
+ if (readLine(&data_file[pointer], &line, size-pointer, &n) < 0) {
+ logError(1, "%s parseProductionTestLimits : ERROR %02X\n", tag, ERROR_FILE_READ);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_READ; */
+ ret = ERROR_FILE_READ;
+ goto END;
+ }
+ pointer += n;
+ token = strsep(&line, ",");
+ for (z = 0; (z < *column) && (token != NULL); z++) {
+ sscanf(token, "%d", ((*data) + j));
+ j++;
+ token = strsep(&line, ",");
+ }
+ }
+ if (j == ((*row)*(*column))) { /* check that all the data are read */
+ logError(0, "%s READ DONE!\n", tag);
+ /* release_firmware(fw); */
+ /* return OK; */
+ ret = OK;
+ goto END;
+ }
+ logError(1, "%s parseProductionTestLimits 3: ERROR %02X\n", tag, ERROR_FILE_PARSE);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_PARSE; */
+ ret = ERROR_FILE_PARSE;
+ goto END;
+ }
+ }
+
+ }
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_LABEL_NOT_FOUND);
+ ret = ERROR_LABEL_NOT_FOUND;
+END:
+#ifndef LIMITS_H_FILE
+ release_firmware(fw);
+#endif
+ return ret;
+
+ } else {
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+}
+
+int readLine(char *data, char **line, int size, int *n)
+{
+ int i = 0;
+ if (size < 1)
+ return 1;
+
+ while (data[i] != '\n' && i < size) {
+ *(*line + i) = data[i];
+ i++;
+ }
+ *n = i+1;
+ *(*line + i) = '\0';
+
+ return OK;
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.h b/drivers/input/touchscreen/st/fts_lib/ftsTest.h
new file mode 100644
index 000000000000..93da901c9f42
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.h
@@ -0,0 +1,158 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS API for MP test *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+
+#define LIMITS_FILE "stm_fts_production_limits.csv"
+
+#define WAIT_FOR_FRESH_FRAMES 100 /* ms */
+#define WAIT_AFTER_SENSEOFF 50 /* ms */
+#define TIMEOUT_ITO_TEST_RESULT 200 /* ms */
+#define TIMEOUT_INITIALIZATION_TEST_RESULT 5000 /* ms */
+
+/* LABELS PRODUCTION TEST LIMITS FILE */
+#define MS_RAW_MIN_MAX "MS_RAW_DATA_MIN_MAX"
+#define MS_RAW_GAP "MS_RAW_DATA_GAP"
+#define MS_CX1_MIN_MAX "MS_TOUCH_ACTIVE_CX1_MIN_MAX"
+#define MS_CX2_MAP_MIN "MS_TOUCH_ACTIVE_CX2_MIN"
+#define MS_CX2_MAP_MAX "MS_TOUCH_ACTIVE_CX2_MAX"
+#define MS_CX2_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL"
+#define MS_CX2_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL"
+#define MS_TOTAL_CX_MAP_MIN "MS_TOUCH_ACTIVE_TOTAL_CX_MIN"
+#define MS_TOTAL_CX_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_MAX"
+#define MS_TOTAL_CX_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL"
+#define MS_TOTAL_CX_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL"
+#define SS_RAW_FORCE_MIN_MAX "SS_RAW_DATA_FORCE_MIN_MAX"
+#define SS_RAW_SENSE_MIN_MAX "SS_RAW_DATA_SENSE_MIN_MAX"
+#define SS_RAW_FORCE_GAP "SS_RAW_DATA_FORCE_GAP"
+#define SS_RAW_SENSE_GAP "SS_RAW_DATA_SENSE_GAP"
+#define SS_IX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_FORCE_MIN_MAX"
+#define SS_IX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_SENSE_MIN_MAX"
+#define SS_CX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_FORCE_MIN_MAX"
+#define SS_CX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_SENSE_MIN_MAX"
+#define SS_IX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_FORCE_MIN"
+#define SS_IX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_FORCE_MAX"
+#define SS_IX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_SENSE_MIN"
+#define SS_IX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_SENSE_MAX"
+#define SS_IX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_VERTICAL"
+#define SS_IX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_HORIZONTAL"
+#define SS_CX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_FORCE_MIN"
+#define SS_CX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_FORCE_MAX"
+#define SS_CX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_SENSE_MIN"
+#define SS_CX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_SENSE_MAX"
+#define SS_CX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL"
+#define SS_CX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL"
+
+/* TOTAL SS */
+#define SS_TOTAL_IX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MIN"
+#define SS_TOTAL_IX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MAX"
+#define SS_TOTAL_IX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MIN"
+#define SS_TOTAL_IX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MAX"
+#define SS_TOTAL_IX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_VERTICAL"
+#define SS_TOTAL_IX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_HORIZONTAL"
+#define SS_TOTAL_CX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MIN"
+#define SS_TOTAL_CX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MAX"
+#define SS_TOTAL_CX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MIN"
+#define SS_TOTAL_CX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MAX"
+#define SS_TOTAL_CX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL"
+#define SS_TOTAL_CX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL"
+
+/* KEYS */
+#define MS_KEY_RAW_MIN_MAX "MS_KEY_RAW_DATA_MIN_MAX"
+#define MS_KEY_CX1_MIN_MAX "MS_KEY_CX1_MIN_MAX"
+#define MS_KEY_CX2_MAP_MIN "MS_KEY_CX2_MIN"
+#define MS_KEY_CX2_MAP_MAX "MS_KEY_CX2_MAX"
+#define MS_KEY_TOTAL_CX_MAP_MIN "MS_KEY_TOTAL_CX_MIN"
+#define MS_KEY_TOTAL_CX_MAP_MAX "MS_KEY_TOTAL_CX_MAX"
+
+/* CONSTANT TOTAL IX */
+#define SS_IX1_FORCE_W "SS_IX1_FORCE_W"
+#define SS_IX2_FORCE_W "SS_IX2_FORCE_W"
+#define SS_IX1_SENSE_W "SS_IX1_SENSE_W"
+#define SS_IX2_SENSE_W "SS_IX2_SENSE_W"
+
+#define SAVE_FLAG_RETRY 3
+
+typedef struct {
+ int MutualRaw;
+ int MutualRawGap;
+ int MutualCx1;
+ int MutualCx2;
+ int MutualCx2Adj;
+ int MutualCxTotal;
+ int MutualCxTotalAdj;
+
+ int MutualKeyRaw;
+ int MutualKeyCx1;
+ int MutualKeyCx2;
+ int MutualKeyCxTotal;
+
+ int SelfForceRaw;
+ int SelfForceRawGap;
+ int SelfForceIx1;
+ int SelfForceIx2;
+ int SelfForceIx2Adj;
+ int SelfForceIxTotal;
+ int SelfForceIxTotalAdj;
+ int SelfForceCx1;
+ int SelfForceCx2;
+ int SelfForceCx2Adj;
+ int SelfForceCxTotal;
+ int SelfForceCxTotalAdj;
+
+ int SelfSenseRaw;
+ int SelfSenseRawGap;
+ int SelfSenseIx1;
+ int SelfSenseIx2;
+ int SelfSenseIx2Adj;
+ int SelfSenseIxTotal;
+ int SelfSenseIxTotalAdj;
+ int SelfSenseCx1;
+ int SelfSenseCx2;
+ int SelfSenseCx2Adj;
+ int SelfSenseCxTotal;
+ int SelfSenseCxTotalAdj;
+
+} TestToDo;
+
+int computeAdjHoriz(u8 *data, int row, int column, u8 **result);
+int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result);
+int computeAdjVert(u8 *data, int row, int column, u8 **result);
+int computeAdjVertTotal(u16 *data, int row, int column, u16 **result);
+int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, u16 **result);
+int checkLimitsMinMax(short *data, int row, int column, int min, int max);
+int checkLimitsMap(u8 *data, int row, int column, int *min, int *max);
+int checkLimitsMapTotal(u16 *data, int row, int column, int *min, int *max);
+int checkLimitsMapAdj(u8 *data, int row, int column, int *max);
+int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max);
+int production_test_ito(void);
+int production_test_initialization(void);
+int ms_compensation_tuning(void);
+int ss_compensation_tuning(void);
+int lp_timer_calibration(void);
+int save_cx_tuning(void);
+int production_test_splited_initialization(int saveToFlash);
+int production_test_main(char *pathThresholds, int stop_on_fail,
+ int saveInit, TestToDo *todo, u32 signature);
+int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ms_key_raw(char *path_limits);
+int save_mp_flag(u32 signature);
+int parseProductionTestLimits(char *path, char *label, int **data, int *row, int *column);
+int readLine(char *data, char **line, int size, int *n);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTime.c b/drivers/input/touchscreen/st/fts_lib/ftsTime.c
new file mode 100644
index 000000000000..03a2a39fe10b
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTime.c
@@ -0,0 +1,84 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility for mesuring/handling the time *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsTime.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+void startStopWatch(StopWatch *w)
+{
+ w->start = current_kernel_time();
+}
+
+void stopStopWatch(StopWatch *w)
+{
+ w->end = current_kernel_time();
+}
+
+int elapsedMillisecond(StopWatch *w)
+{
+ int result;
+
+ result = ((w->end.tv_sec - w->start.tv_sec)*1000) + (w->end.tv_nsec - w->start.tv_nsec) / 1000000;
+ return result;
+}
+
+int elapsedNanosecond(StopWatch *w)
+{
+ int result;
+
+ result = ((w->end.tv_sec - w->start.tv_sec)*1000000000) + (w->end.tv_nsec - w->start.tv_nsec);
+ return result;
+}
+
+char *timestamp(void)
+{
+ char *result = NULL;
+ result = (char *)kmalloc((1)*sizeof(char), GFP_KERNEL);
+ if (result == NULL)
+ return NULL;
+ result[0] = ' ';
+ return result;
+}
+
+void stdelay(unsigned long ms)
+{
+ msleep(ms);
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTime.h b/drivers/input/touchscreen/st/fts_lib/ftsTime.h
new file mode 100644
index 000000000000..5eeca6eace97
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTime.h
@@ -0,0 +1,29 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility for mesuring/handling the time *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+
+#include <linux/time.h>
+
+typedef struct {
+ struct timespec start, end;
+} StopWatch;
+
+void startStopWatch(StopWatch *w);
+void stopStopWatch(StopWatch *w);
+int elapsedMillisecond(StopWatch *w);
+int elapsedNanosecond(StopWatch *w);
+char *timestamp(void);
+void stdelay(unsigned long ms);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTool.c b/drivers/input/touchscreen/st/fts_lib/ftsTool.c
new file mode 100644
index 000000000000..4c5d54f17ea7
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTool.c
@@ -0,0 +1,706 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility Functions *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCompensation.h"
+#include "ftsCrossCompile.h"
+#include "ftsError.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTime.h"
+#include "ftsTool.h"
+#include "../fts.h" /* needed for the PHONE_KEY define */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+
+/* static char tag[8]="[ FTS ]\0"; */
+static int reset_gpio = GPIO_NOT_DEFINED;
+static int system_resetted_up;
+static int system_resetted_down;
+extern chipInfo ftsInfo;
+
+int readB2(u16 address, u8 *outBuf, int len)
+{
+ int remaining = len;
+ int toRead = 0;
+ int retry = 0;
+ int ret;
+ int event_to_search[3];
+ u8 *readEvent = (u8 *)kmalloc(FIFO_EVENT_SIZE*sizeof(u8), GFP_KERNEL);
+ u8 cmd[4] = { FTS_CMD_REQU_FW_CONF, 0x00, 0x00, (u8)len };
+
+ if (readEvent == NULL) {
+ logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ u16ToU8_be(address, &cmd[1]);
+
+ logError(0, "%s %s", tag, printHex("Command B2 = ", cmd, 4));
+ do {
+ remaining = len;
+ ret = fts_writeFwCmd(cmd, 4);
+ if (ret < 0) {
+ logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ret;
+ } /* ask to the FW the data */
+ logError(0, "%s Command to FW sent!\n", tag);
+ event_to_search[0] = (int)EVENTID_FW_CONFIGURATION;
+
+ while (remaining > OK) {
+ event_to_search[1] = (int)((address & 0xFF00)>>8);
+ event_to_search[2] = (int) (address & 0x00FF);
+ if (remaining > B2_DATA_BYTES) {
+ toRead = B2_DATA_BYTES;
+ remaining -= B2_DATA_BYTES;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ ret = pollForEvent(event_to_search, 3, readEvent, GENERAL_TIMEOUT);
+ if (ret >= OK) { /* start the polling for reading the reply */
+ memcpy(outBuf, &readEvent[3], toRead);
+ retry = 0;
+ outBuf += toRead;
+
+ } else {
+ retry += 1;
+ break;
+ }
+ address += B2_DATA_BYTES;
+ }
+
+ } while (retry < B2_RETRY && retry != 0);
+
+ kfree(readEvent);
+ if (retry == B2_RETRY) {
+ logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+ logError(0, "%s B2 read %d bytes\n", tag, len);
+
+ return OK;
+}
+
+int readB2U16(u16 address, u8 *outBuf, int byteToRead)
+{
+
+ int remaining = byteToRead;
+ int toRead = 0;
+ int ret;
+
+ u8 *buff = (u8 *)kmalloc((B2_CHUNK + 1)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s readB2U16: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ if (remaining >= B2_CHUNK) {
+ toRead = B2_CHUNK;
+ remaining -= B2_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ ret = readB2(address, buff, toRead);
+ if (ret < 0)
+ return ret;
+ memcpy(outBuf, buff, toRead);
+
+ address += toRead;
+
+ outBuf += toRead;
+
+ }
+
+ kfree(buff);
+ return OK;
+}
+
+int releaseInformation(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_RELEASE_INFO };
+ int event_to_search[1];
+ u8 readEvent[FIFO_EVENT_SIZE];
+
+ event_to_search[0] = (int)EVENTID_RELEASE_INFO;
+
+ logError(0, "%s releaseInformation started... Chip INFO:\n", tag);
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s releaseInformation: ERROR %02X\n", tag, ret);
+ return ret;
+ }
+
+ ret = pollForEvent(event_to_search, 1, &readEvent[0], RELEASE_INFO_TIMEOUT);
+ /* start the polling for reading the reply */
+ if (ret < OK) {
+ logError(1, "%s releaseInformation: ERROR %02X\n", tag, ret);
+ return ret;
+ }
+
+ logError(0, "%s releaseInformation: Finished!\n", tag, ret);
+ return OK;
+
+}
+
+char *printHex(char *label, u8 *buff, int count)
+{
+ int i, offset;
+ char *result = NULL;
+
+ offset = strlen(label);
+ result = (char *)kmalloc(((offset + 3 * count) + 1)*sizeof(char), GFP_KERNEL);
+ if (result != NULL) {
+ strlcpy(result, label, sizeof(result));
+
+ for (i = 0; i < count; i++) {
+ snprintf(&result[offset + i * 3], 4, "%02X ", buff[i]);
+ }
+ strlcat(result, "\n", sizeof(result));
+ }
+ return result;
+}
+
+int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_to_wait)
+{
+ int i, find, retry, count_err;
+ int time_to_count;
+ int err_handling = OK;
+ StopWatch clock;
+
+ u8 cmd[1] = { FIFO_CMD_READONE };
+ char *temp = NULL;
+
+ find = 0;
+ retry = 0;
+ count_err = 0;
+ time_to_count = time_to_wait / TIMEOUT_RESOLUTION;
+
+ startStopWatch(&clock);
+ while (find != 1 && retry < time_to_count && fts_readCmd(cmd, 1, readData, FIFO_EVENT_SIZE) >= 0) {
+ /* Log of errors */
+ if (readData[0] == EVENTID_ERROR_EVENT) {
+ logError(1, "%s %s", tag, printHex("ERROR EVENT = ", readData, FIFO_EVENT_SIZE));
+ count_err++;
+ err_handling = errorHandler(readData, FIFO_EVENT_SIZE);
+ if ((err_handling&0xF0FF0000) == ERROR_HANDLER_STOP_PROC) {
+ logError(1, "%s pollForEvent: forced to be stopped! ERROR %08X\n", tag, err_handling);
+ return err_handling;
+ }
+ } else {
+ if (readData[0] != EVENTID_NO_EVENT) {
+ logError(1, "%s %s", tag, printHex("READ EVENT = ", readData, FIFO_EVENT_SIZE));
+ }
+ if (readData[0] == EVENTID_CONTROL_READY && event_to_search[0] != EVENTID_CONTROL_READY) {
+ logError(1, "%s pollForEvent: Unmanned Controller Ready Event! Setting reset flags...\n", tag);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ }
+ }
+
+ find = 1;
+
+ for (i = 0; i < event_bytes; i++) {
+
+ if (event_to_search[i] != -1 && (int)readData[i] != event_to_search[i]) {
+ find = 0;
+ break;
+ }
+ }
+
+ retry++;
+ msleep(TIMEOUT_RESOLUTION);
+ }
+ stopStopWatch(&clock);
+ if ((retry >= time_to_count) && find != 1) {
+ logError(1, "%s pollForEvent: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ } else if (find == 1) {
+ temp = printHex("FOUND EVENT = ", readData, FIFO_EVENT_SIZE);
+ if (temp != NULL)
+ logError(0, "%s %s", tag, temp);
+ kfree(temp);
+ logError(0, "%s Event found in %d ms (%d iterations)! Number of errors found = %d\n", tag, elapsedMillisecond(&clock), retry, count_err);
+ return count_err;
+ }
+ logError(1, "%s pollForEvent: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+}
+
+int flushFIFO(void)
+{
+
+ u8 cmd = FIFO_CMD_FLUSH; /* flush the FIFO */
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s flushFIFO: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ logError(0, "%s FIFO flushed!\n", tag);
+ return OK;
+
+}
+
+int fts_disableInterrupt(void)
+{
+ u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_DISABLE }; /* disable interrupt */
+ u16ToU8_be(IER_ADDR, &cmd[1]);
+
+ if (fts_writeCmd(cmd, 4) < OK) {
+ logError(1, "%s fts_disableInterrupt: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ logError(0, "%s Interrupt Disabled!\n", tag);
+ return OK;
+}
+
+int fts_enableInterrupt(void)
+{
+ u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_ENABLE }; /* enable interrupt */
+ u16ToU8_be(IER_ADDR, &cmd[1]);
+ if (fts_writeCmd(cmd, 4) < 0) {
+ logError(1, "%s fts_enableInterrupt: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ logError(0, "%s Interrupt Enabled!\n", tag);
+ return OK;
+}
+
+int u8ToU16n(u8 *src, int src_length, u16 *dst)
+{
+ int i, j;
+
+ if (src_length % 2 != 0) {
+ return 0;
+ }
+ j = 0;
+ dst = (u16 *)kmalloc((src_length / 2)*sizeof(u16), GFP_KERNEL);
+ for (i = 0; i < src_length; i += 2) {
+ dst[j] = ((src[i+1] & 0x00FF) << 8) + (src[i] & 0x00FF);
+ j++;
+ }
+
+ return (src_length / 2);
+}
+
+int u8ToU16(u8 *src, u16 *dst)
+{
+ *dst = (u16)(((src[1] & 0x00FF) << 8) + (src[0] & 0x00FF));
+ return 0;
+}
+
+int u8ToU16_le(u8 *src, u16 *dst)
+{
+ *dst = (u16)(((src[0] & 0x00FF) << 8) + (src[1] & 0x00FF));
+ return 0;
+}
+
+int u16ToU8n(u16 *src, int src_length, u8 *dst)
+{
+ int i, j;
+ dst = (u8 *)kmalloc((2 * src_length)*sizeof(u8), GFP_KERNEL);
+ j = 0;
+ for (i = 0; i < src_length; i++) {
+ dst[j] = (u8) (src[i] & 0xFF00)>>8;
+ dst[j+1] = (u8) (src[i] & 0x00FF);
+ j += 2;
+ }
+
+ return src_length * 2;
+
+}
+
+int u16ToU8(u16 src, u8 *dst)
+{
+ dst[0] = (u8)((src & 0xFF00) >> 8);
+ dst[1] = (u8)(src & 0x00FF);
+ return 0;
+}
+
+int u16ToU8_be(u16 src, u8 *dst)
+{
+ dst[0] = (u8)((src & 0xFF00) >> 8);
+ dst[1] = (u8)(src & 0x00FF);
+ return 0;
+}
+
+int u16ToU8_le(u16 src, u8 *dst)
+{
+ dst[1] = (u8)((src & 0xFF00) >> 8);
+ dst[0] = (u8)(src & 0x00FF);
+ return 0;
+}
+
+int u8ToU32(u8 *src, u32 *dst)
+{
+ *dst = (u32)(((src[3] & 0x000000FF) << 24) + ((src[2] & 0x000000FF) << 16) + ((src[1] & 0x000000FF) << 8) + (src[0] & 0x000000FF));
+ return 0;
+}
+
+int u32ToU8(u32 src, u8 *dst)
+{
+ dst[3] = (u8)((src & 0xFF000000) >> 24);
+ dst[2] = (u8)((src & 0x00FF0000) >> 16);
+ dst[1] = (u8)((src & 0x0000FF00) >> 8);
+ dst[0] = (u8)(src & 0x000000FF);
+ return 0;
+}
+
+int attempt_function(int(*code)(void), unsigned long wait_before_retry, int retry_count)
+{
+ int result;
+ int count = 0;
+
+ do {
+ result = code();
+ count++;
+ msleep(wait_before_retry);
+ } while (count < retry_count && result < 0);
+
+ if (count == retry_count)
+ return (result | ERROR_TIMEOUT);
+ else
+ return result;
+
+}
+
+void setResetGpio(int gpio)
+{
+ reset_gpio = gpio;
+ logError(1, "%s setResetGpio: reset_gpio = %d\n", tag, reset_gpio);
+}
+
+int fts_system_reset(void)
+{
+ u8 readData[FIFO_EVENT_SIZE];
+ int event_to_search;
+ int res = -1;
+ int i;
+ u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, SYSTEM_RESET_VALUE };
+ event_to_search = (int)EVENTID_CONTROL_READY;
+
+ u16ToU8_be(SYSTEM_RESET_ADDRESS, &cmd[1]);
+ logError(0, "%s System resetting...\n", tag);
+ for (i = 0; i < SYSTEM_RESET_RETRY && res < 0; i++) {
+
+ if (reset_gpio == GPIO_NOT_DEFINED) {
+ res = fts_writeCmd(cmd, 4);
+ } else {
+ gpio_set_value(reset_gpio, 0);
+ msleep(10);
+ gpio_set_value(reset_gpio, 1);
+ res = OK;
+ }
+ if (res < OK) {
+ logError(1, "%s fts_system_reset: ERROR %02X\n", tag, ERROR_I2C_W);
+ } else {
+ res = pollForEvent(&event_to_search, 1, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s fts_system_reset: ERROR %02X\n", tag, res);
+ }
+ }
+ }
+ if (res < OK) {
+ logError(1, "%s fts_system_reset...failed after 3 attempts: ERROR %02X\n", tag, (res | ERROR_SYSTEM_RESET_FAIL));
+ return (res | ERROR_SYSTEM_RESET_FAIL);
+ }
+ logError(0, "%s System reset DONE!\n", tag);
+ system_resetted_down = 1;
+ system_resetted_up = 1;
+ return OK;
+
+}
+
+int isSystemResettedDown(void)
+{
+ return system_resetted_down;
+}
+
+int isSystemResettedUp(void)
+{
+ return system_resetted_up;
+}
+
+void setSystemResettedDown(int val)
+{
+ system_resetted_down = val;
+}
+
+void setSystemResettedUp(int val)
+{
+ system_resetted_up = val;
+}
+
+int senseOn(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_MT_SENSE_ON };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s senseOn: ERROR %02X\n", tag, ERROR_SENSE_ON_FAIL);
+ return (ret|ERROR_SENSE_ON_FAIL);
+ }
+
+ logError(0, "%s senseOn: SENSE ON\n", tag);
+ return OK;
+}
+
+int senseOff(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_MT_SENSE_OFF };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s senseOff: ERROR %02X\n", tag, ERROR_SENSE_OFF_FAIL);
+ return (ret | ERROR_SENSE_OFF_FAIL);
+ }
+
+ logError(0, "%s senseOff: SENSE OFF\n", tag);
+ return OK;
+
+}
+
+int keyOn(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_KEY_ON };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s keyOn: ERROR %02X\n", tag, ERROR_SENSE_ON_FAIL);
+ return (ret | ERROR_SENSE_ON_FAIL);
+ }
+
+ logError(0, "%s keyOn: KEY ON\n", tag);
+ return OK;
+
+}
+
+int keyOff(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_KEY_OFF };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s keyOff: ERROR %02X\n", tag, ERROR_SENSE_OFF_FAIL);
+ return (ret | ERROR_SENSE_OFF_FAIL);
+ }
+
+ logError(0, "%s keyOff: KEY OFF\n", tag);
+ return OK;
+
+}
+
+int cleanUp(int enableTouch)
+{
+ int res;
+
+ logError(0, "%s cleanUp: system reset...\n", tag);
+ res = fts_system_reset();
+ if (res < OK)
+ return res;
+ if (enableTouch) {
+ logError(0, "%s cleanUp: enabling touches...\n", tag);
+ res = senseOn();
+ if (res < OK)
+ return res;
+#ifdef PHONE_KEY
+ res = keyOn();
+ if (res < OK)
+ return res;
+#endif
+ logError(0, "%s cleanUp: enabling interrupts...\n", tag);
+ res = fts_enableInterrupt();
+ if (res < OK)
+ return res;
+ }
+ return OK;
+
+}
+
+int checkEcho(u8 *cmd, int size)
+{
+ int ret, i;
+ int event_to_search[size+1];
+ u8 readData[FIFO_EVENT_SIZE];
+
+ if ((ftsInfo.u32_echoEn & 0x00000001) != ECHO_ENABLED) {
+ logError(1, "%s ECHO Not Enabled!\n", tag);
+ return OK;
+ }
+ if (size < 1) {
+ logError(1, "%s checkEcho: Error Size = %d not valid! or ECHO not Enabled! ERROR %08X\n", tag, size, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+ if ((size+2) > FIFO_EVENT_SIZE)
+ size = FIFO_EVENT_SIZE-2;
+ /* Echo event EC xx xx xx xx xx xx fifo_status therefore for command
+ *with more than 6 bytes will echo only the first 6
+ */
+ event_to_search[0] = EVENTID_ECHO;
+ for (i = 1; i <= size; i++) {
+ event_to_search[i] = cmd[i-1];
+ }
+ ret = pollForEvent(event_to_search, size+1, readData, GENERAL_TIMEOUT);
+ if (ret < OK) {
+ logError(1, "%s checkEcho: Echo Event not found! ERROR %02X\n", tag, ret);
+ return (ret | ERROR_CHECK_ECHO_FAIL);
+ }
+
+ logError(0, "%s ECHO OK!\n", tag);
+ return OK;
+}
+
+int featureEnableDisable(int on_off, u8 feature)
+{
+ int ret;
+ u8 cmd[2] = { 0x00, feature };
+
+ if (on_off == FEAT_ENABLE) {
+ cmd[0] = FTS_CMD_FEATURE_ENABLE;
+ logError(0, "%s featureEnableDisable: Enabling feature %02X ...\n", tag, feature);
+ } else {
+ cmd[0] = FTS_CMD_FEATURE_DISABLE;
+ logError(0, "%s featureEnableDisable: Disabling feature %02X ...\n", tag, feature);
+ }
+
+ ret = fts_writeCmd(cmd, 2); /* not use writeFwCmd because this function can be called also during interrupt enable and should be fast */
+ if (ret < OK) {
+ logError(1, "%s featureEnableDisable: ERROR %02X\n", tag, ret);
+ return (ret | ERROR_FEATURE_ENABLE_DISABLE);
+ }
+
+ logError(0, "%s featureEnableDisable: DONE!\n", tag);
+ return OK;
+
+}
+
+short **array1dTo2d_short(short *data, int size, int columns)
+{
+
+ int i;
+ short **matrix = (short **)kmalloc(((int)(size / columns))*sizeof(short *), GFP_KERNEL);
+ if (matrix != NULL) {
+ for (i = 0; i < (int)(size / columns); i++) {
+ matrix[i] = (short *)kmalloc(columns*sizeof(short), GFP_KERNEL);
+ }
+
+ for (i = 0; i < size; i++)
+ matrix[i / columns][i % columns] = data[i];
+ }
+
+ return matrix;
+}
+
+u8 **array1dTo2d_u8(u8 *data, int size, int columns)
+{
+
+ int i;
+ u8 **matrix = (u8 **)kmalloc(((int)(size / columns))*sizeof(u8 *), GFP_KERNEL);
+ if (matrix != NULL) {
+ for (i = 0; i < (int)(size / columns); i++) {
+ matrix[i] = (u8 *)kmalloc(columns*sizeof(u8), GFP_KERNEL);
+ }
+
+ for (i = 0; i < size; i++)
+ matrix[i / columns][i % columns] = data[i];
+ }
+
+ return matrix;
+}
+
+void print_frame_short(char *label, short **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
+
+void print_frame_u8(char *label, u8 **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
+
+void print_frame_u32(char *label, u32 **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
+
+void print_frame_int(char *label, int **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTool.h b/drivers/input/touchscreen/st/fts_lib/ftsTool.h
new file mode 100644
index 000000000000..a90e79fc5607
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTool.h
@@ -0,0 +1,64 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility Functions *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+#define GPIO_NOT_DEFINED -1
+
+#define TIMEOUT_RESOLUTION 10 /* ms */
+#define GENERAL_TIMEOUT (50*TIMEOUT_RESOLUTION) /* ms */
+#define RELEASE_INFO_TIMEOUT (15*TIMEOUT_RESOLUTION) /* ms */
+
+#define FEAT_ENABLE 1
+#define FEAT_DISABLE 0
+
+#define SYSTEM_RESET_RETRY 3
+
+#define B2_RETRY 2
+
+int readB2(u16 address, u8 *outBuf, int len);
+int readB2U16(u16 address, u8 *outBuf, int byteToRead);
+int releaseInformation(void);
+char *printHex(char *label, u8 *buff, int count);
+int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_to_wait);
+int fts_disableInterrupt(void);
+int fts_enableInterrupt(void);
+int u8ToU16(u8 *src, u16 *dst);
+int u8ToU16_le(u8 *src, u16 *dst);
+int u8ToU16n(u8 *src, int src_length, u16 *dst);
+int u16ToU8(u16 src, u8 *dst);
+int u16ToU8_le(u16 src, u8 *dst);
+int u16ToU8_be(u16 src, u8 *dst);
+int u16ToU8n(u16 *src, int src_length, u8 *dst);
+int u8ToU32(u8 *src, u32 *dst);
+int u32ToU8(u32 src, u8 *dst);
+int attempt_function(int(*code)(void), unsigned long wait_before_retry, int retry_count);
+void setResetGpio(int gpio);
+int fts_system_reset(void);
+int isSystemResettedUp(void);
+int isSystemResettedDown(void);
+void setSystemResettedUp(int val);
+void setSystemResettedDown(int val);
+int senseOn(void);
+int senseOff(void);
+int keyOn(void);
+int keyOff(void);
+int featureEnableDisable(int on_off, u8 feature);
+int checkEcho(u8 *cmd, int size);
+void print_frame_short(char *label, short **matrix, int row, int column);
+short **array1dTo2d_short(short *data, int size, int columns);
+u8 **array1dTo2d_u8(u8 *data, int size, int columns);
+void print_frame_u8(char *label, u8 **matrix, int row, int column);
+void print_frame_u32(char *label, u32 **matrix, int row, int column);
+void print_frame_int(char *label, int **matrix, int row, int column);
+int cleanUp(int enableTouch);
+int flushFIFO(void);
diff --git a/drivers/input/touchscreen/st/fts_limits.h b/drivers/input/touchscreen/st/fts_limits.h
new file mode 100644
index 000000000000..d3be1a2b1e1a
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_limits.h
@@ -0,0 +1,10 @@
+#ifndef FTS_LIMITS_H
+#define FTS_LIMITS_H
+/* This is an auto generated header file
+* --->Remember to change the name of the two variables!<--- */
+const uint32_t myArray2_size;
+
+const uint8_t myArray2[] = {
+};
+
+#endif
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
index f936f3c2ebb1..563ce16885b3 100644
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
+++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
@@ -445,11 +445,11 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
struct i2c_msg msg[1];
+ mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+
retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
if (retval < 0)
- return retval;
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+ goto exit;
retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
if (retval != PAGE_SELECT_LEN) {
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index 004f34ecbff8..6d90221486c9 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -17,7 +17,8 @@
#include <linux/vmalloc.h>
#include <asm/cacheflush.h>
#include <asm/dma-iommu.h>
-
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
/* some redundant definitions... :( TODO: move to io-pgtable-fast.h */
#define FAST_PAGE_SHIFT 12
@@ -632,7 +633,7 @@ static void __fast_smmu_mapped_over_stale(struct dma_fast_smmu_mapping *fast,
dev_err(fast->dev, "Mapped over stale tlb at %pa\n", &iova);
dev_err(fast->dev, "bitmap (failure at idx %lu):\n", bitmap_idx);
dev_err(fast->dev, "ptep: %p pmds: %p diff: %lu\n", ptep,
- fast->pgtbl_pmds, ptep - fast->pgtbl_pmds);
+ fast->pgtbl_pmds, bitmap_idx);
print_hex_dump(KERN_ERR, "bmap: ", DUMP_PREFIX_ADDRESS,
32, 8, fast->bitmap, fast->bitmap_size, false);
}
@@ -682,7 +683,7 @@ static const struct dma_map_ops fast_smmu_dma_ops = {
* fast_smmu_attach_device function.
*/
static struct dma_fast_smmu_mapping *__fast_smmu_create_mapping_sized(
- dma_addr_t base, size_t size)
+ dma_addr_t base, u64 size)
{
struct dma_fast_smmu_mapping *fast;
@@ -695,7 +696,11 @@ static struct dma_fast_smmu_mapping *__fast_smmu_create_mapping_sized(
fast->num_4k_pages = size >> FAST_PAGE_SHIFT;
fast->bitmap_size = BITS_TO_LONGS(fast->num_4k_pages) * sizeof(long);
- fast->bitmap = kzalloc(fast->bitmap_size, GFP_KERNEL);
+ fast->bitmap = kzalloc(fast->bitmap_size, GFP_KERNEL | __GFP_NOWARN |
+ __GFP_NORETRY);
+ if (!fast->bitmap)
+ fast->bitmap = vzalloc(fast->bitmap_size);
+
if (!fast->bitmap)
goto err2;
@@ -725,7 +730,7 @@ int fast_smmu_attach_device(struct device *dev,
int atomic_domain = 1;
struct iommu_domain *domain = mapping->domain;
struct iommu_pgtbl_info info;
- size_t size = mapping->bits << PAGE_SHIFT;
+ u64 size = (u64)mapping->bits << PAGE_SHIFT;
if (mapping->base + size > (SZ_1G * 4ULL))
return -EINVAL;
@@ -779,7 +784,7 @@ void fast_smmu_detach_device(struct device *dev,
dev->archdata.mapping = NULL;
set_dma_ops(dev, NULL);
- kfree(mapping->fast->bitmap);
+ kvfree(mapping->fast->bitmap);
kfree(mapping->fast);
}
EXPORT_SYMBOL(fast_smmu_detach_device);
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index a71fcdbb1899..5d32a382e291 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -20,6 +20,7 @@
#include <linux/types.h>
#include <linux/io-pgtable-fast.h>
#include <asm/cacheflush.h>
+#include <linux/vmalloc.h>
#include "io-pgtable.h"
@@ -263,11 +264,18 @@ static size_t av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova,
return size;
}
+#if defined(CONFIG_ARM64)
+#define FAST_PGDNDX(va) (((va) & 0x7fc0000000) >> 27)
+#elif defined(CONFIG_ARM)
+#define FAST_PGDNDX(va) (((va) & 0xc0000000) >> 27)
+#endif
+
static phys_addr_t av8l_fast_iova_to_phys(struct io_pgtable_ops *ops,
unsigned long iova)
{
struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
av8l_fast_iopte pte, *pgdp, *pudp, *pmdp;
+ unsigned long pgd;
phys_addr_t phys;
const unsigned long pts = AV8L_FAST_PTE_TYPE_SHIFT;
const unsigned long ptm = AV8L_FAST_PTE_TYPE_MASK;
@@ -277,8 +285,9 @@ static phys_addr_t av8l_fast_iova_to_phys(struct io_pgtable_ops *ops,
/* TODO: clean up some of these magic numbers... */
- pgdp = (av8l_fast_iopte *)
- (((unsigned long)data->pgd) | ((iova & 0x7fc0000000) >> 27));
+ pgd = (unsigned long)data->pgd | FAST_PGDNDX(iova);
+ pgdp = (av8l_fast_iopte *)pgd;
+
pte = *pgdp;
if (((pte >> pts) & ptm) != ptt)
return 0;
@@ -340,7 +349,12 @@ av8l_fast_prepopulate_pgtables(struct av8l_fast_io_pgtable *data,
int i, j, pg = 0;
struct page **pages, *page;
- pages = kmalloc(sizeof(*pages) * NUM_PGTBL_PAGES, GFP_KERNEL);
+ pages = kmalloc(sizeof(*pages) * NUM_PGTBL_PAGES, __GFP_NOWARN |
+ __GFP_NORETRY);
+
+ if (!pages)
+ pages = vmalloc(sizeof(*pages) * NUM_PGTBL_PAGES);
+
if (!pages)
return -ENOMEM;
@@ -409,7 +423,7 @@ err_free_pages:
for (i = 0; i < pg; ++i)
__free_page(pages[i]);
err_free_pages_arr:
- kfree(pages);
+ kvfree(pages);
return -ENOMEM;
}
@@ -464,6 +478,9 @@ av8l_fast_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
reg |= (64ULL - cfg->ias) << AV8L_FAST_TCR_T0SZ_SHIFT;
reg |= AV8L_FAST_TCR_EPD1_FAULT << AV8L_FAST_TCR_EPD1_SHIFT;
+#if defined(CONFIG_ARM)
+ reg |= ARM_32_LPAE_TCR_EAE;
+#endif
cfg->av8l_fast_cfg.tcr = reg;
/* MAIRs */
@@ -501,7 +518,7 @@ static void av8l_fast_free_pgtable(struct io_pgtable *iop)
vunmap(data->pmds);
for (i = 0; i < NUM_PGTBL_PAGES; ++i)
__free_page(data->pages[i]);
- kfree(data->pages);
+ kvfree(data->pages);
kfree(data);
}
@@ -549,7 +566,7 @@ static bool av8l_fast_range_has_specific_mapping(struct io_pgtable_ops *ops,
const phys_addr_t phys_start,
const size_t size)
{
- unsigned long iova = iova_start;
+ u64 iova = iova_start;
phys_addr_t phys = phys_start;
while (iova < (iova_start + size)) {
@@ -565,11 +582,12 @@ static bool av8l_fast_range_has_specific_mapping(struct io_pgtable_ops *ops,
static int __init av8l_fast_positive_testing(void)
{
int failed = 0;
- unsigned long iova;
+ u64 iova;
struct io_pgtable_ops *ops;
struct io_pgtable_cfg cfg;
struct av8l_fast_io_pgtable *data;
av8l_fast_iopte *pmds;
+ u64 max = SZ_1G * 4ULL - 1;
cfg = (struct io_pgtable_cfg) {
.quirks = 0,
@@ -589,19 +607,18 @@ static int __init av8l_fast_positive_testing(void)
pmds = data->pmds;
/* map the entire 4GB VA space with 4K map calls */
- for (iova = 0; iova < SZ_1G * 4UL; iova += SZ_4K) {
+ for (iova = 0; iova < max; iova += SZ_4K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_4K, IOMMU_READ))) {
failed++;
continue;
}
}
-
if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- SZ_1G * 4UL)))
+ max)))
failed++;
/* unmap it all */
- for (iova = 0; iova < SZ_1G * 4UL; iova += SZ_4K) {
+ for (iova = 0; iova < max; iova += SZ_4K) {
if (WARN_ON(ops->unmap(ops, iova, SZ_4K) != SZ_4K))
failed++;
}
@@ -610,7 +627,7 @@ static int __init av8l_fast_positive_testing(void)
av8l_fast_clear_stale_ptes(pmds, false);
/* map the entire 4GB VA space with 8K map calls */
- for (iova = 0; iova < SZ_1G * 4UL; iova += SZ_8K) {
+ for (iova = 0; iova < max; iova += SZ_8K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_8K, IOMMU_READ))) {
failed++;
continue;
@@ -618,11 +635,11 @@ static int __init av8l_fast_positive_testing(void)
}
if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- SZ_1G * 4UL)))
+ max)))
failed++;
/* unmap it all with 8K unmap calls */
- for (iova = 0; iova < SZ_1G * 4UL; iova += SZ_8K) {
+ for (iova = 0; iova < max; iova += SZ_8K) {
if (WARN_ON(ops->unmap(ops, iova, SZ_8K) != SZ_8K))
failed++;
}
@@ -631,7 +648,7 @@ static int __init av8l_fast_positive_testing(void)
av8l_fast_clear_stale_ptes(pmds, false);
/* map the entire 4GB VA space with 16K map calls */
- for (iova = 0; iova < SZ_1G * 4UL; iova += SZ_16K) {
+ for (iova = 0; iova < max; iova += SZ_16K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_16K, IOMMU_READ))) {
failed++;
continue;
@@ -639,11 +656,11 @@ static int __init av8l_fast_positive_testing(void)
}
if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- SZ_1G * 4UL)))
+ max)))
failed++;
/* unmap it all */
- for (iova = 0; iova < SZ_1G * 4UL; iova += SZ_16K) {
+ for (iova = 0; iova < max; iova += SZ_16K) {
if (WARN_ON(ops->unmap(ops, iova, SZ_16K) != SZ_16K))
failed++;
}
@@ -652,7 +669,7 @@ static int __init av8l_fast_positive_testing(void)
av8l_fast_clear_stale_ptes(pmds, false);
/* map the entire 4GB VA space with 64K map calls */
- for (iova = 0; iova < SZ_1G * 4UL; iova += SZ_64K) {
+ for (iova = 0; iova < max; iova += SZ_64K) {
if (WARN_ON(ops->map(ops, iova, iova, SZ_64K, IOMMU_READ))) {
failed++;
continue;
@@ -660,11 +677,11 @@ static int __init av8l_fast_positive_testing(void)
}
if (WARN_ON(!av8l_fast_range_has_specific_mapping(ops, 0, 0,
- SZ_1G * 4UL)))
+ max)))
failed++;
/* unmap it all at once */
- if (WARN_ON(ops->unmap(ops, 0, SZ_1G * 4UL) != SZ_1G * 4UL))
+ if (WARN_ON(ops->unmap(ops, 0, max) != max))
failed++;
free_io_pgtable_ops(ops);
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 937ce3f6279c..75fcde6e2c20 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -839,7 +839,7 @@ static int iommu_debug_profiling_fast_dma_api_show(struct seq_file *s,
if (!virt)
goto out;
- mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4UL);
+ mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4ULL);
if (!mapping) {
seq_puts(s, "fast_smmu_create_mapping failed\n");
goto out_kfree;
@@ -939,8 +939,8 @@ static const struct file_operations iommu_debug_profiling_fast_dma_api_fops = {
static int __tlb_stress_sweep(struct device *dev, struct seq_file *s)
{
int i, ret = 0;
- unsigned long iova;
- const unsigned long max = SZ_1G * 4UL;
+ u64 iova;
+ const u64 max = SZ_1G * 4ULL - 1;
void *virt;
phys_addr_t phys;
dma_addr_t dma_addr;
@@ -1012,8 +1012,8 @@ static int __tlb_stress_sweep(struct device *dev, struct seq_file *s)
}
/* we're all full again. unmap everything. */
- for (dma_addr = 0; dma_addr < max; dma_addr += SZ_8K)
- dma_unmap_single(dev, dma_addr, SZ_8K, DMA_TO_DEVICE);
+ for (iova = 0; iova < max; iova += SZ_8K)
+ dma_unmap_single(dev, (dma_addr_t)iova, SZ_8K, DMA_TO_DEVICE);
out:
free_pages((unsigned long)virt, get_order(SZ_8K));
@@ -1046,7 +1046,7 @@ static int __rand_va_sweep(struct device *dev, struct seq_file *s,
const size_t size)
{
u64 iova;
- const unsigned long max = SZ_1G * 4UL;
+ const u64 max = SZ_1G * 4ULL - 1;
int i, remapped, unmapped, ret = 0;
void *virt;
dma_addr_t dma_addr, dma_addr2;
@@ -1078,9 +1078,9 @@ static int __rand_va_sweep(struct device *dev, struct seq_file *s,
fib_init(&fib);
for (iova = get_next_fib(&fib) * size;
iova < max - size;
- iova = get_next_fib(&fib) * size) {
- dma_addr = iova;
- dma_addr2 = max - size - iova;
+ iova = (u64)get_next_fib(&fib) * size) {
+ dma_addr = (dma_addr_t)(iova);
+ dma_addr2 = (dma_addr_t)((max + 1) - size - iova);
if (dma_addr == dma_addr2) {
WARN(1,
"%s test needs update! The random number sequence is folding in on itself and should be changed.\n",
@@ -1106,8 +1106,8 @@ static int __rand_va_sweep(struct device *dev, struct seq_file *s,
ret = -EINVAL;
}
- for (dma_addr = 0; dma_addr < max; dma_addr += size)
- dma_unmap_single(dev, dma_addr, size, DMA_TO_DEVICE);
+ for (iova = 0; iova < max; iova += size)
+ dma_unmap_single(dev, (dma_addr_t)iova, size, DMA_TO_DEVICE);
out:
free_pages((unsigned long)virt, get_order(size));
@@ -1135,10 +1135,11 @@ static int __check_mapping(struct device *dev, struct iommu_domain *domain,
static int __full_va_sweep(struct device *dev, struct seq_file *s,
const size_t size, struct iommu_domain *domain)
{
- unsigned long iova;
+ u64 iova;
dma_addr_t dma_addr;
void *virt;
phys_addr_t phys;
+ const u64 max = SZ_1G * 4ULL - 1;
int ret = 0, i;
virt = (void *)__get_free_pages(GFP_KERNEL, get_order(size));
@@ -1153,7 +1154,7 @@ static int __full_va_sweep(struct device *dev, struct seq_file *s,
}
phys = virt_to_phys(virt);
- for (iova = 0, i = 0; iova < SZ_1G * 4UL; iova += size, ++i) {
+ for (iova = 0, i = 0; iova < max; iova += size, ++i) {
unsigned long expected = iova;
dma_addr = dma_map_single(dev, virt, size, DMA_TO_DEVICE);
@@ -1201,8 +1202,8 @@ static int __full_va_sweep(struct device *dev, struct seq_file *s,
}
out:
- for (dma_addr = 0; dma_addr < SZ_1G * 4UL; dma_addr += size)
- dma_unmap_single(dev, dma_addr, size, DMA_TO_DEVICE);
+ for (iova = 0; iova < max; iova += size)
+ dma_unmap_single(dev, (dma_addr_t)iova, size, DMA_TO_DEVICE);
free_pages((unsigned long)virt, get_order(size));
return ret;
@@ -1391,7 +1392,8 @@ static int __apply_to_new_mapping(struct seq_file *s,
int ret = -EINVAL, fast = 1;
phys_addr_t pt_phys;
- mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4UL);
+ mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
+ (SZ_1G * 4ULL));
if (!mapping)
goto out;
@@ -1460,7 +1462,9 @@ static int iommu_debug_functional_arm_dma_api_show(struct seq_file *s,
size_t sizes[] = {SZ_4K, SZ_64K, SZ_2M, SZ_1M * 12, 0};
int ret = -EINVAL;
- mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4UL);
+ /* Make the size equal to MAX_ULONG */
+ mapping = arm_iommu_create_mapping(&platform_bus_type, 0,
+ (SZ_1G * 4ULL - 1));
if (!mapping)
goto out;
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 08809a93d4b2..54d395d5e78d 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -1076,6 +1076,8 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
return rc;
}
+ /* Wait for LMH mitigation to take effect */
+ udelay(500);
}
if (led->trigger_chgr) {
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index c27c0593cd10..cd76941b87ca 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -226,6 +226,7 @@ struct flash_led_platform_data {
};
struct qpnp_flash_led_buffer {
+ struct mutex debugfs_lock; /* Prevent thread concurrency */
size_t rpos;
size_t wpos;
size_t len;
@@ -282,6 +283,7 @@ static int flash_led_dbgfs_file_open(struct qpnp_flash_led *led,
log->rpos = 0;
log->wpos = 0;
log->len = logbufsize - sizeof(*log);
+ mutex_init(&log->debugfs_lock);
led->log = log;
led->buffer_cnt = 1;
@@ -303,20 +305,26 @@ static int flash_led_dfs_close(struct inode *inode, struct file *file)
if (led && led->log) {
file->private_data = NULL;
+ mutex_destroy(&led->log->debugfs_lock);
kfree(led->log);
}
return 0;
}
+#define MIN_BUFFER_WRITE_LEN 20
static int print_to_log(struct qpnp_flash_led_buffer *log,
const char *fmt, ...)
{
va_list args;
int cnt;
- char *log_buf = &log->data[log->wpos];
+ char *log_buf;
size_t size = log->len - log->wpos;
+ if (size < MIN_BUFFER_WRITE_LEN)
+ return 0; /* not enough buffer left */
+
+ log_buf = &log->data[log->wpos];
va_start(args, fmt);
cnt = vscnprintf(log_buf, size, fmt, args);
va_end(args);
@@ -330,29 +338,31 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
struct qpnp_flash_led *led = fp->private_data;
struct qpnp_flash_led_buffer *log = led->log;
uint val;
- int rc;
+ int rc = 0;
size_t len;
size_t ret;
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
+ mutex_lock(&log->debugfs_lock);
+ if ((log->rpos >= log->wpos && led->buffer_cnt == 0) ||
+ ((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
+ goto unlock_mutex;
rc = regmap_read(led->regmap, INT_LATCHED_STS(led->base), &val);
if (rc) {
dev_err(&led->pdev->dev,
"Unable to read from address %x, rc(%d)\n",
INT_LATCHED_STS(led->base), rc);
- return -EINVAL;
+ goto unlock_mutex;
}
led->buffer_cnt--;
rc = print_to_log(log, "0x%05X ", INT_LATCHED_STS(led->base));
if (rc == 0)
- return rc;
+ goto unlock_mutex;
rc = print_to_log(log, "0x%02X ", val);
if (rc == 0)
- return rc;
+ goto unlock_mutex;
if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
log->data[log->wpos - 1] = '\n';
@@ -362,36 +372,43 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
ret = copy_to_user(buf, &log->data[log->rpos], len);
if (ret) {
pr_err("error copy register value to user\n");
- return -EFAULT;
+ rc = -EFAULT;
+ goto unlock_mutex;
}
len -= ret;
*ppos += len;
log->rpos += len;
- return len;
+ rc = len;
+
+unlock_mutex:
+ mutex_unlock(&log->debugfs_lock);
+ return rc;
}
static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
size_t count, loff_t *ppos) {
struct qpnp_flash_led *led = fp->private_data;
struct qpnp_flash_led_buffer *log = led->log;
- int rc;
+ int rc = 0;
size_t len;
size_t ret;
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
+ mutex_lock(&log->debugfs_lock);
+ if ((log->rpos >= log->wpos && led->buffer_cnt == 0) ||
+ ((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
+ goto unlock_mutex;
led->buffer_cnt--;
rc = print_to_log(log, "0x%05X ", FLASH_LED_FAULT_STATUS(led->base));
if (rc == 0)
- return rc;
+ goto unlock_mutex;
rc = print_to_log(log, "0x%02X ", led->fault_reg);
if (rc == 0)
- return rc;
+ goto unlock_mutex;
if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
log->data[log->wpos - 1] = '\n';
@@ -401,14 +418,19 @@ static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
ret = copy_to_user(buf, &log->data[log->rpos], len);
if (ret) {
pr_err("error copy register value to user\n");
- return -EFAULT;
+ rc = -EFAULT;
+ goto unlock_mutex;
}
len -= ret;
*ppos += len;
log->rpos += len;
- return len;
+ rc = len;
+
+unlock_mutex:
+ mutex_unlock(&log->debugfs_lock);
+ return rc;
}
static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
@@ -421,10 +443,14 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
size_t ret = 0;
struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
+ char *kbuf;
- if (!kbuf)
- return -ENOMEM;
+ mutex_lock(&led->log->debugfs_lock);
+ kbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
ret = copy_from_user(kbuf, buf, count);
if (!ret) {
@@ -453,6 +479,8 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
free_buf:
kfree(kbuf);
+unlock_mutex:
+ mutex_unlock(&led->log->debugfs_lock);
return ret;
}
@@ -465,10 +493,14 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,
int data;
size_t ret = 0;
struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
+ char *kbuf;
- if (!kbuf)
- return -ENOMEM;
+ mutex_lock(&led->log->debugfs_lock);
+ kbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
ret = copy_from_user(kbuf, buf, count);
if (ret == count) {
@@ -496,6 +528,8 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,
free_buf:
kfree(kbuf);
+unlock_mutex:
+ mutex_unlock(&led->log->debugfs_lock);
return ret;
}
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index 60f7cfbd9f9b..65eaf4066149 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -131,6 +131,39 @@ static const struct dvb_dmx_video_patterns h264_non_idr = {
DMX_IDX_H264_NON_IDR_START
};
+/*
+ * Forbidden (1 bit) + NAL idc (2 bits) + NAL type (5 bits)
+ * I-Slice NAL idc = 3, NAL type = 5, 01100101 mask 0x7F
+ */
+static const struct dvb_dmx_video_patterns h264_idr_islice = {
+ {0x00, 0x00, 0x01, 0x65, 0x80},
+ {0xFF, 0xFF, 0xFF, 0x7F, 0x80},
+ 5,
+ DMX_IDX_H264_IDR_ISLICE_START
+};
+
+/*
+ * Forbidden (1 bit) + NAL idc (2 bits) + NAL type (5 bits)
+ * P-Slice NAL idc = 2, NAL type = 1, 01000001 mask 0x7F
+ */
+static const struct dvb_dmx_video_patterns h264_non_idr_pslice = {
+ {0x00, 0x00, 0x01, 0x41, 0x80},
+ {0xFF, 0xFF, 0xFF, 0x7F, 0x80},
+ 5,
+ DMX_IDX_H264_NON_IDR_PSLICE_START
+};
+
+/*
+ * Forbidden (1 bit) + NAL idc (2 bits) + NAL type (5 bits)
+ * B-Slice NAL idc = 0, NAL type = 1, 00000001 mask 0x7F
+ */
+static const struct dvb_dmx_video_patterns h264_non_idr_bslice = {
+ {0x00, 0x00, 0x01, 0x01, 0x80},
+ {0xFF, 0xFF, 0xFF, 0x7F, 0x80},
+ 5,
+ DMX_IDX_H264_NON_IDR_BSLICE_START
+};
+
static const struct dvb_dmx_video_patterns h264_non_access_unit_del = {
{0x00, 0x00, 0x01, 0x09},
{0xFF, 0xFF, 0xFF, 0x1F},
@@ -1011,6 +1044,18 @@ static void dvb_dmx_process_pattern_result(struct dvb_demux_feed *feed,
} else if (feed->prev_frame_type & DMX_IDX_H264_NON_IDR_START) {
idx_event.type = DMX_IDX_H264_NON_IDR_END;
frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+ } else if (feed->prev_frame_type &
+ DMX_IDX_H264_IDR_ISLICE_START) {
+ idx_event.type = DMX_IDX_H264_IDR_END;
+ frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+ } else if (feed->prev_frame_type &
+ DMX_IDX_H264_NON_IDR_PSLICE_START) {
+ idx_event.type = DMX_IDX_H264_NON_IDR_END;
+ frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
+ } else if (feed->prev_frame_type &
+ DMX_IDX_H264_NON_IDR_BSLICE_START) {
+ idx_event.type = DMX_IDX_H264_NON_IDR_END;
+ frame_end_in_seq = DMX_IDX_H264_FIRST_SPS_FRAME_END;
} else {
idx_event.type = DMX_IDX_VC1_FRAME_END;
frame_end_in_seq = DMX_IDX_VC1_FIRST_SEQ_FRAME_END;
@@ -1848,6 +1893,15 @@ const struct dvb_dmx_video_patterns *dvb_dmx_get_pattern(u64 dmx_idx_pattern)
case DMX_IDX_H264_NON_IDR_START:
return &h264_non_idr;
+ case DMX_IDX_H264_IDR_ISLICE_START:
+ return &h264_idr_islice;
+
+ case DMX_IDX_H264_NON_IDR_PSLICE_START:
+ return &h264_non_idr_pslice;
+
+ case DMX_IDX_H264_NON_IDR_BSLICE_START:
+ return &h264_non_idr_bslice;
+
case DMX_IDX_H264_ACCESS_UNIT_DEL:
return &h264_non_access_unit_del;
@@ -1975,6 +2029,40 @@ static void dvb_dmx_init_idx_state(struct dvb_demux_feed *feed)
feed->pattern_num++;
}
+ /* H264 IDR ISlice */
+ if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+ (feed->idx_params.types &
+ (DMX_IDX_H264_IDR_ISLICE_START | DMX_IDX_H264_IDR_END |
+ DMX_IDX_H264_NON_IDR_END |
+ DMX_IDX_H264_FIRST_SPS_FRAME_START |
+ DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+ feed->patterns[feed->pattern_num] =
+ dvb_dmx_get_pattern(DMX_IDX_H264_IDR_ISLICE_START);
+ feed->pattern_num++;
+ }
+ /* H264 non-IDR PSlice */
+ if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+ (feed->idx_params.types &
+ (DMX_IDX_H264_NON_IDR_PSLICE_START | DMX_IDX_H264_NON_IDR_END |
+ DMX_IDX_H264_IDR_END |
+ DMX_IDX_H264_FIRST_SPS_FRAME_START |
+ DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+ feed->patterns[feed->pattern_num] =
+ dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_PSLICE_START);
+ feed->pattern_num++;
+ }
+ /* H264 non-IDR BSlice */
+ if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
+ (feed->idx_params.types &
+ (DMX_IDX_H264_NON_IDR_BSLICE_START | DMX_IDX_H264_NON_IDR_END |
+ DMX_IDX_H264_IDR_END |
+ DMX_IDX_H264_FIRST_SPS_FRAME_START |
+ DMX_IDX_H264_FIRST_SPS_FRAME_END))) {
+ feed->patterns[feed->pattern_num] =
+ dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_BSLICE_START);
+ feed->pattern_num++;
+ }
+
if ((feed->pattern_num < DVB_DMX_MAX_SEARCH_PATTERN_NUM) &&
(feed->idx_params.types & DMX_IDX_H264_ACCESS_UNIT_DEL)) {
feed->patterns[feed->pattern_num] =
@@ -3253,7 +3341,8 @@ static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
- memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
+ /* 4 Demux Instances each with group of 5 pids */
+ memcpy(pids, dvbdemux->pids, DMX_PES_OTHER*sizeof(u16));
return 0;
}
diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h
index 779de7ed078a..10a4cbbba2e7 100644
--- a/drivers/media/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb-core/dvb_demux.h
@@ -360,6 +360,31 @@ static inline int dvb_dmx_is_video_feed(struct dvb_demux_feed *feed)
}
/**
+ * dvb_dmx_is_audio_feed - Returns whether the PES feed
+ * is audio one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is audio feed, 0 otherwise.
+ */
+static inline int dvb_dmx_is_audio_feed(struct dvb_demux_feed *feed)
+{
+ if (feed->type != DMX_TYPE_TS)
+ return 0;
+
+ if (feed->ts_type & (~TS_DECODER))
+ return 0;
+
+ if ((feed->pes_type == DMX_PES_AUDIO0) ||
+ (feed->pes_type == DMX_PES_AUDIO1) ||
+ (feed->pes_type == DMX_PES_AUDIO2) ||
+ (feed->pes_type == DMX_PES_AUDIO3))
+ return 1;
+
+ return 0;
+}
+
+/**
* dvb_dmx_is_pcr_feed - Returns whether the PES feed
* is PCR one.
*
diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c
index 275b8b90af05..b706d598e6b8 100644
--- a/drivers/media/platform/msm/broadcast/tspp.c
+++ b/drivers/media/platform/msm/broadcast/tspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, 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
@@ -45,6 +45,8 @@
#include <linux/string.h>
#include <linux/msm-bus.h>
#include <linux/interrupt.h> /* tasklet */
+#include <asm/arch_timer.h> /* Timer */
+#include <linux/avtimer_kernel.h> /* Timer */
/*
* General defines
@@ -100,6 +102,7 @@
#define TSIF_TEST_RESET_OFF (0x1c)
#define TSIF_TEST_EXPORT_OFF (0x20)
#define TSIF_TEST_CURRENT_OFF (0x24)
+#define TSIF_TTS_CTL_OFF (0x38)
#define TSIF_DATA_PORT_OFF (0x100)
@@ -128,6 +131,12 @@
#define TSIF_STS_CTL_STOP BIT(3)
#define TSIF_STS_CTL_START BIT(0)
+/* bits for TSIF_TTS_CTRL register */
+#define TSIF_TTS_CTL_TTS_ENDIANNESS BIT(4)
+#define TSIF_TTS_CTL_TTS_SOURCE BIT(3)
+#define TSIF_TTS_CTL_TTS_LENGTH_1 BIT(1)
+#define TSIF_TTS_CTL_TTS_LENGTH_0 BIT(0)
+
/*
* TSPP register offsets
*/
@@ -255,6 +264,7 @@ static const struct debugfs_entry debugfs_tsif_regs[] = {
{"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
{"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
{"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
+ {"tts_source", S_IRUSR | S_IWUSR, TSIF_TTS_CTL_OFF},
};
static const struct debugfs_entry debugfs_tspp_regs[] = {
@@ -369,6 +379,8 @@ struct tspp_tsif_device {
u32 stat_overflow;
u32 stat_lost_sync;
u32 stat_timeout;
+ enum tsif_tts_source tts_source;
+ u32 lpass_timer_enable;
};
enum tspp_buf_state {
@@ -477,6 +489,7 @@ struct tspp_device {
/* pinctrl */
struct mutex mutex;
struct tspp_pinctrl pinctrl;
+ unsigned int tts_source; /* Time stamp source type LPASS timer/TCR */
struct dentry *dent;
struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
@@ -911,6 +924,8 @@ static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
{
int start_hardware = 0;
u32 ctl;
+ u32 tts_ctl;
+ int retval;
if (tsif_device->ref_count == 0) {
start_hardware = 1;
@@ -949,19 +964,57 @@ static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
TSIF_STS_CTL_TEST_MODE;
break;
case TSPP_TSIF_MODE_1:
- ctl |= TSIF_STS_CTL_EN_TIME_LIM |
- TSIF_STS_CTL_EN_TCR;
+ ctl |= TSIF_STS_CTL_EN_TIME_LIM;
+ if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER)
+ ctl |= TSIF_STS_CTL_EN_TCR;
break;
case TSPP_TSIF_MODE_2:
ctl |= TSIF_STS_CTL_EN_TIME_LIM |
- TSIF_STS_CTL_EN_TCR |
TSIF_STS_CTL_MODE_2;
+ if (tsif_device->tts_source != TSIF_TTS_LPASS_TIMER)
+ ctl |= TSIF_STS_CTL_EN_TCR;
break;
default:
pr_warn("tspp: unknown tsif mode 0x%x",
tsif_device->mode);
}
+ /* Set 4bytes Time Stamp for TCR */
+ if (tsif_device->tts_source == TSIF_TTS_LPASS_TIMER) {
+ if (tsif_device->lpass_timer_enable == 0) {
+ retval = avcs_core_open();
+ if (retval < 0) {
+ pr_warn("tspp: avcs open fail:%d\n",
+ retval);
+ return retval;
+ }
+ retval = avcs_core_disable_power_collapse(1);
+ if (retval < 0) {
+ pr_warn("tspp: avcs power enable:%d\n",
+ retval);
+ return retval;
+ }
+ tsif_device->lpass_timer_enable = 1;
+ }
+
+ tts_ctl = readl_relaxed(tsif_device->base +
+ TSIF_TTS_CTL_OFF);
+ tts_ctl = 0;
+ /* Set LPASS Timer TTS source */
+ tts_ctl |= TSIF_TTS_CTL_TTS_SOURCE;
+ /* Set 4 byte TTS */
+ tts_ctl |= TSIF_TTS_CTL_TTS_LENGTH_0;
+
+ writel_relaxed(tts_ctl, tsif_device->base +
+ TSIF_TTS_CTL_OFF);
+ /* write TTS control register */
+ wmb();
+ tts_ctl = readl_relaxed(tsif_device->base +
+ TSIF_TTS_CTL_OFF);
+ }
+
writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
+ /* write Status control register */
+ wmb();
writel_relaxed(tsif_device->time_limit,
tsif_device->base + TSIF_TIME_LIMIT_OFF);
/* assure register configuration is done before starting TSIF */
@@ -982,8 +1035,13 @@ static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
{
- if (tsif_device->ref_count == 0)
+ if (tsif_device->ref_count == 0) {
+ if (tsif_device->lpass_timer_enable == 1) {
+ if (avcs_core_disable_power_collapse(0) == 0)
+ tsif_device->lpass_timer_enable = 0;
+ }
return;
+ }
tsif_device->ref_count--;
@@ -1113,6 +1171,7 @@ static int tspp_global_reset(struct tspp_device *pdev)
pdev->tsif[i].data_inverse = 0;
pdev->tsif[i].sync_inverse = 0;
pdev->tsif[i].enable_inverse = 0;
+ pdev->tsif[i].lpass_timer_enable = 0;
}
writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
/* assure state is reset before continuing with configuration */
@@ -1885,6 +1944,89 @@ int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter)
EXPORT_SYMBOL(tspp_get_ref_clk_counter);
/**
+ * tspp_get_lpass_time_counter - return the LPASS Timer counter value.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @source: The TSIF source from which the counter should be read
+ * @tcr_counter: the value of TCR counter
+ *
+ * Return error status
+ *
+ * If source is neither TSIF 0 or TSIF1 0 is returned.
+ */
+int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
+ u64 *lpass_time_counter)
+{
+ struct tspp_device *pdev;
+ struct tspp_tsif_device *tsif_device;
+
+ if (!lpass_time_counter)
+ return -EINVAL;
+
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_get_lpass_time_counter: can't find device %i\n",
+ dev);
+ return -ENODEV;
+ }
+
+ switch (source) {
+ case TSPP_SOURCE_TSIF0:
+ tsif_device = &pdev->tsif[0];
+ break;
+
+ case TSPP_SOURCE_TSIF1:
+ tsif_device = &pdev->tsif[1];
+ break;
+
+ default:
+ tsif_device = NULL;
+ break;
+ }
+
+ if (tsif_device && tsif_device->ref_count) {
+ if (avcs_core_query_timer(lpass_time_counter) < 0) {
+ pr_err("tspp_get_lpass_time_counter: read error\n");
+ *lpass_time_counter = 0;
+ return -ENETRESET;
+ }
+ } else
+ *lpass_time_counter = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(tspp_get_lpass_time_counter);
+
+/**
+ * tspp_get_tts_source - Return the TTS source value.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @tts_source:Updated TTS source type
+ *
+ * Return error status
+ *
+ */
+int tspp_get_tts_source(u32 dev, int *tts_source)
+{
+ struct tspp_device *pdev;
+
+ if (tts_source == NULL)
+ return -EINVAL;
+
+ pdev = tspp_find_by_id(dev);
+ if (!pdev) {
+ pr_err("tspp_get_tts_source: can't find device %i\n",
+ dev);
+ return -ENODEV;
+ }
+
+ *tts_source = pdev->tts_source;
+
+ return 0;
+}
+EXPORT_SYMBOL(tspp_get_tts_source);
+
+/**
* tspp_add_filter - add a TSPP filter to a channel.
*
* @dev: TSPP device (up to TSPP_MAX_DEVICES)
@@ -2891,6 +3033,20 @@ static int msm_tspp_probe(struct platform_device *pdev)
goto err_irq;
device->req_irqs = false;
+ /* Check whether AV timer time stamps are enabled */
+ if (!of_property_read_u32(pdev->dev.of_node, "qcom,lpass-timer-tts",
+ &device->tts_source)) {
+ if (device->tts_source == 1)
+ device->tts_source = TSIF_TTS_LPASS_TIMER;
+ else
+ device->tts_source = TSIF_TTS_TCR;
+ } else {
+ device->tts_source = TSIF_TTS_TCR;
+ }
+
+ for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
+ device->tsif[i].tts_source = device->tts_source;
+
/* power management */
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 09de276e8418..df9691be0c28 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -1746,11 +1746,38 @@ void msm_isp_update_error_frame_count(struct vfe_device *vfe_dev)
static int msm_isp_process_iommu_page_fault(struct vfe_device *vfe_dev)
{
int rc = vfe_dev->buf_mgr->pagefault_debug_disable;
+ uint32_t irq_status0, irq_status1;
+ uint32_t overflow_mask;
+ unsigned long irq_flags;
- pr_err("%s:%d] VFE%d Handle Page fault!\n", __func__,
- __LINE__, vfe_dev->pdev->id);
-
- msm_isp_halt_send_error(vfe_dev, ISP_EVENT_IOMMU_P_FAULT);
+ /* Check if any overflow bit is set */
+ vfe_dev->hw_info->vfe_ops.core_ops.
+ get_overflow_mask(&overflow_mask);
+ vfe_dev->hw_info->vfe_ops.irq_ops.
+ read_irq_status(vfe_dev, &irq_status0, &irq_status1);
+ overflow_mask &= irq_status1;
+ spin_lock_irqsave(
+ &vfe_dev->common_data->common_dev_data_lock, irq_flags);
+ if (overflow_mask ||
+ atomic_read(&vfe_dev->error_info.overflow_state) !=
+ NO_OVERFLOW) {
+ spin_unlock_irqrestore(
+ &vfe_dev->common_data->common_dev_data_lock, irq_flags);
+ pr_err_ratelimited("%s: overflow detected during IOMMU\n",
+ __func__);
+ /* Don't treat the Overflow + Page fault scenario as fatal.
+ * Instead try to do a recovery. Using an existing event as
+ * as opposed to creating a new event.
+ */
+ msm_isp_halt_send_error(vfe_dev, ISP_EVENT_PING_PONG_MISMATCH);
+ } else {
+ spin_unlock_irqrestore(
+ &vfe_dev->common_data->common_dev_data_lock, irq_flags);
+ pr_err("%s:%d] VFE%d Handle Page fault! vfe_dev %pK\n",
+ __func__, __LINE__, vfe_dev->pdev->id, vfe_dev);
+ vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0);
+ msm_isp_halt_send_error(vfe_dev, ISP_EVENT_IOMMU_P_FAULT);
+ }
if (vfe_dev->buf_mgr->pagefault_debug_disable == 0) {
vfe_dev->buf_mgr->pagefault_debug_disable = 1;
@@ -1859,6 +1886,7 @@ int msm_isp_process_overflow_irq(
vfe_dev->recovery_irq1_mask = vfe_dev->irq1_mask;
vfe_dev->hw_info->vfe_ops.core_ops.
set_halt_restart_mask(vfe_dev);
+ vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 0);
/* mask off other vfe if dual vfe is used */
if (vfe_dev->is_split) {
int other_vfe_id;
@@ -1875,6 +1903,7 @@ int msm_isp_process_overflow_irq(
temp_vfe->recovery_irq1_mask = temp_vfe->irq1_mask;
temp_vfe->hw_info->vfe_ops.core_ops.
set_halt_restart_mask(temp_vfe);
+ temp_vfe->hw_info->vfe_ops.axi_ops.halt(temp_vfe, 0);
}
/* reset irq status so skip further process */
@@ -2143,7 +2172,8 @@ static void msm_vfe_iommu_fault_handler(struct iommu_domain *domain,
if (vfe_dev->vfe_open_cnt > 0) {
atomic_set(&vfe_dev->error_info.overflow_state,
HALT_ENFORCED);
- pr_err("%s: fault address is %lx\n", __func__, iova);
+ pr_err_ratelimited("%s: fault address is %lx\n",
+ __func__, iova);
msm_isp_process_iommu_page_fault(vfe_dev);
} else {
pr_err("%s: no handling, vfe open cnt = %d\n",
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 1cf2c54aa8b8..7885149440f9 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, 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
@@ -1770,6 +1770,17 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
goto end;
}
+ for (i = 0; i < queue_len; i++) {
+ processed_frame[i] = cpp_timer.data.processed_frame[i];
+ if (!processed_frame[i]) {
+ pr_warn("process frame null , queue len %d", queue_len);
+ msm_cpp_flush_queue_and_release_buffer(cpp_dev,
+ queue_len);
+ msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
+ goto end;
+ }
+ }
+
atomic_set(&cpp_timer.used, 1);
pr_warn("Starting timer to fire in %d ms. (jiffies=%lu)\n",
CPP_CMD_TIMEOUT_MS, jiffies);
@@ -1778,9 +1789,6 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
- for (i = 0; i < MAX_CPP_PROCESSING_FRAME; i++)
- processed_frame[i] = cpp_timer.data.processed_frame[i];
-
for (i = 0; i < queue_len; i++) {
pr_warn("Rescheduling for identity=0x%x, frame_id=%03d\n",
processed_frame[i]->identity,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 39811aa84e8e..cd48f871eb79 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2017, 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
@@ -528,6 +528,12 @@ static int32_t msm_actuator_piezo_move_focus(
return -EFAULT;
}
+ if (dest_step_position > a_ctrl->total_steps) {
+ pr_err("Step pos greater than total steps = %d\n",
+ dest_step_position);
+ return -EFAULT;
+ }
+
a_ctrl->i2c_tbl_index = 0;
a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
(num_steps *
diff --git a/drivers/media/platform/msm/dvb/adapter/Makefile b/drivers/media/platform/msm/dvb/adapter/Makefile
index f7da6b5b2f06..662bf99c4d7e 100644
--- a/drivers/media/platform/msm/dvb/adapter/Makefile
+++ b/drivers/media/platform/msm/dvb/adapter/Makefile
@@ -1,5 +1,6 @@
ccflags-y += -Idrivers/media/dvb-core/
ccflags-y += -Idrivers/media/platform/msm/dvb/include/
+ccflags-y += -Idrivers/media/platform/msm/dvb/demux/
obj-$(CONFIG_DVB_MPQ) += mpq-adapter.o
diff --git a/drivers/media/platform/msm/dvb/demux/Kconfig b/drivers/media/platform/msm/dvb/demux/Kconfig
index 319e2ab2eb96..d160c820d190 100644
--- a/drivers/media/platform/msm/dvb/demux/Kconfig
+++ b/drivers/media/platform/msm/dvb/demux/Kconfig
@@ -44,3 +44,11 @@ choice
TSPP hardware support. All demux tasks will be
performed in SW.
endchoice
+
+config DVB_MPQ_MEDIA_BOX_DEMUX
+ bool "Media box demux support"
+ depends on DVB_MPQ_DEMUX
+
+ help
+ Use this option if your HW is Qualcomm media box and demux
+ support is required on that media box.
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 0188637af85c..ef0ef1512211 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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,11 @@ static int video_nonsecure_ion_heap = ION_IOMMU_HEAP_ID;
module_param(video_nonsecure_ion_heap, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(video_nonsecure_ion_heap, "ION heap for non-secure video buffer allocation");
+/* ION heap IDs used for allocating audio output buffer */
+static int audio_nonsecure_ion_heap = ION_IOMMU_HEAP_ID;
+module_param(audio_nonsecure_ion_heap, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(audio_nonsecure_ion_heap, "ION heap for non-secure audio buffer allocation");
+
/* Value of TS packet scramble bits field for even key */
static int mpq_sdmx_scramble_even = 0x2;
module_param(mpq_sdmx_scramble_even, int, S_IRUGO | S_IWUSR);
@@ -104,6 +109,25 @@ module_param(tsif_mode, int, S_IRUGO | S_IWUSR);
static int clock_inv;
module_param(clock_inv, int, S_IRUGO | S_IWUSR);
+/* TSIF Timestamp source: 0 = TSIF Clock Reference, 1 = LPASS time counter */
+enum tsif_tts_source {
+ TSIF_TTS_TCR = 0, /* Time stamps from TCR counter */
+ TSIF_TTS_LPASS_TIMER /* Time stamps from AV/Qtimer Timer */
+};
+
+/* Store all mpq feeds corresponding to 4 TS programs in a Transport Stream */
+static struct mpq_feed *store_mpq_audio_feed[CONFIG_DVB_MPQ_NUM_DMX_DEVICES] = {
+ NULL, NULL, NULL, NULL};
+static struct mpq_feed *store_mpq_video_feed[CONFIG_DVB_MPQ_NUM_DMX_DEVICES] = {
+ NULL, NULL, NULL, NULL};
+static int non_predicted_video_frame;
+/* trigger video ES frame events on MPEG2 B frames and H264 non-IDR frames */
+#ifdef CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX
+static int video_b_frame_events = 1;
+#else
+static int video_b_frame_events;
+#endif
+
/* Global data-structure for managing demux devices */
static struct
{
@@ -147,6 +171,96 @@ int mpq_dmx_get_param_clock_inv(void)
return clock_inv;
}
+struct mpq_streambuffer *consumer_video_streambuffer(int dmx_ts_pes_video)
+{
+ struct mpq_streambuffer *streambuffer = NULL;
+ struct mpq_video_feed_info *feed_data = NULL;
+
+ switch (dmx_ts_pes_video) {
+ case DMX_PES_VIDEO0:
+ if (store_mpq_video_feed[0] != NULL) {
+ feed_data = &store_mpq_video_feed[0]->video_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO0_STREAM_IF;
+ }
+ break;
+ case DMX_PES_VIDEO1:
+ if (store_mpq_video_feed[1] != NULL) {
+ feed_data = &store_mpq_video_feed[1]->video_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO1_STREAM_IF;
+ }
+ break;
+ case DMX_PES_VIDEO2:
+ if (store_mpq_video_feed[2] != NULL) {
+ feed_data = &store_mpq_video_feed[2]->video_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO2_STREAM_IF;
+ }
+ break;
+ case DMX_PES_VIDEO3:
+ if (store_mpq_video_feed[3] != NULL) {
+ feed_data = &store_mpq_video_feed[3]->video_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO3_STREAM_IF;
+ }
+ break;
+ }
+
+ if (feed_data != NULL)
+ mpq_adapter_get_stream_if(feed_data->stream_interface,
+ &streambuffer);
+
+ return streambuffer;
+}
+EXPORT_SYMBOL(consumer_video_streambuffer);
+
+struct mpq_streambuffer *consumer_audio_streambuffer(int dmx_ts_pes_audio)
+{
+ struct mpq_streambuffer *streambuffer = NULL;
+ struct mpq_audio_feed_info *feed_data = NULL;
+
+ switch (dmx_ts_pes_audio) {
+ case DMX_PES_AUDIO0:
+ if (store_mpq_audio_feed[0] != NULL) {
+ feed_data = &store_mpq_audio_feed[0]->audio_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO0_STREAM_IF;
+ }
+ break;
+ case DMX_PES_AUDIO1:
+ if (store_mpq_audio_feed[1] != NULL) {
+ feed_data = &store_mpq_audio_feed[1]->audio_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO1_STREAM_IF;
+ }
+ break;
+ case DMX_PES_AUDIO2:
+ if (store_mpq_audio_feed[2] != NULL) {
+ feed_data = &store_mpq_audio_feed[2]->audio_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO2_STREAM_IF;
+ }
+ break;
+ case DMX_PES_AUDIO3:
+ if (store_mpq_audio_feed[3] != NULL) {
+ feed_data = &store_mpq_audio_feed[3]->audio_info;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO3_STREAM_IF;
+ }
+ break;
+ }
+
+ if (feed_data != NULL)
+ mpq_adapter_get_stream_if(feed_data->stream_interface,
+ &streambuffer);
+
+ return streambuffer;
+}
+EXPORT_SYMBOL(consumer_audio_streambuffer);
+
+
+
/* Check that PES header is valid and that it is a video PES */
static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header)
{
@@ -163,6 +277,25 @@ static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header)
return 0;
}
+static int mpq_dmx_is_valid_audio_pes(struct pes_packet_header *pes_header)
+{
+ /* start-code valid? */
+ if ((pes_header->packet_start_code_prefix_1 != 0) ||
+ (pes_header->packet_start_code_prefix_2 != 0) ||
+ (pes_header->packet_start_code_prefix_3 != 1))
+ return -EINVAL;
+
+ /* Note: AC3 stream ID = 0xBD */
+ if (pes_header->stream_id == 0xBD)
+ return 0;
+
+ /* stream_id is audio? */ /* 110x xxxx = Audio Stream IDs */
+ if ((pes_header->stream_id & 0xE0) != 0xC0)
+ return -EINVAL;
+
+ return 0;
+}
+
/* Check if a framing pattern is a video frame pattern or a header pattern */
static inline int mpq_dmx_is_video_frame(
enum dmx_video_codec codec,
@@ -170,6 +303,10 @@ static inline int mpq_dmx_is_video_frame(
{
switch (codec) {
case DMX_VIDEO_CODEC_MPEG2:
+ if (video_b_frame_events == 1)
+ if (pattern_type == DMX_IDX_MPEG_B_FRAME_START)
+ non_predicted_video_frame = 1;
+
if ((pattern_type == DMX_IDX_MPEG_I_FRAME_START) ||
(pattern_type == DMX_IDX_MPEG_P_FRAME_START) ||
(pattern_type == DMX_IDX_MPEG_B_FRAME_START))
@@ -177,9 +314,20 @@ static inline int mpq_dmx_is_video_frame(
return 0;
case DMX_VIDEO_CODEC_H264:
- if ((pattern_type == DMX_IDX_H264_IDR_START) ||
- (pattern_type == DMX_IDX_H264_NON_IDR_START))
- return 1;
+ if (video_b_frame_events == 1) {
+ if (pattern_type == DMX_IDX_H264_NON_IDR_BSLICE_START)
+ non_predicted_video_frame = 1;
+
+ if ((pattern_type == DMX_IDX_H264_IDR_ISLICE_START) ||
+ (pattern_type ==
+ DMX_IDX_H264_NON_IDR_PSLICE_START) ||
+ (pattern_type == DMX_IDX_H264_NON_IDR_BSLICE_START))
+ return 1;
+ } else {
+ if ((pattern_type == DMX_IDX_H264_IDR_START) ||
+ (pattern_type == DMX_IDX_H264_NON_IDR_START))
+ return 1;
+ }
return 0;
case DMX_VIDEO_CODEC_VC1:
@@ -219,10 +367,23 @@ static inline int mpq_dmx_get_pattern_params(
case DMX_VIDEO_CODEC_H264:
patterns[0] = dvb_dmx_get_pattern(DMX_IDX_H264_SPS);
patterns[1] = dvb_dmx_get_pattern(DMX_IDX_H264_PPS);
- patterns[2] = dvb_dmx_get_pattern(DMX_IDX_H264_IDR_START);
- patterns[3] = dvb_dmx_get_pattern(DMX_IDX_H264_NON_IDR_START);
- patterns[4] = dvb_dmx_get_pattern(DMX_IDX_H264_SEI);
- *patterns_num = 5;
+ if (video_b_frame_events != 1) {
+ patterns[2] = dvb_dmx_get_pattern
+ (DMX_IDX_H264_IDR_START);
+ patterns[3] = dvb_dmx_get_pattern
+ (DMX_IDX_H264_NON_IDR_START);
+ patterns[4] = dvb_dmx_get_pattern(DMX_IDX_H264_SEI);
+ *patterns_num = 5;
+ } else {
+ patterns[2] = dvb_dmx_get_pattern
+ (DMX_IDX_H264_IDR_ISLICE_START);
+ patterns[3] = dvb_dmx_get_pattern
+ (DMX_IDX_H264_NON_IDR_PSLICE_START);
+ patterns[4] = dvb_dmx_get_pattern
+ (DMX_IDX_H264_NON_IDR_BSLICE_START);
+ patterns[5] = dvb_dmx_get_pattern(DMX_IDX_H264_SEI);
+ *patterns_num = 6;
+ }
break;
case DMX_VIDEO_CODEC_VC1:
@@ -254,12 +415,20 @@ void mpq_dmx_update_decoder_stat(struct mpq_feed *mpq_feed)
struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
enum mpq_adapter_stream_if idx;
- if (!dvb_dmx_is_video_feed(mpq_feed->dvb_demux_feed) ||
- (mpq_feed->video_info.stream_interface >
- MPQ_ADAPTER_VIDEO3_STREAM_IF))
+ if (!dvb_dmx_is_video_feed(mpq_feed->dvb_demux_feed) &&
+ !dvb_dmx_is_audio_feed(mpq_feed->dvb_demux_feed))
return;
- idx = mpq_feed->video_info.stream_interface;
+ if (dvb_dmx_is_video_feed(mpq_feed->dvb_demux_feed) &&
+ mpq_feed->video_info.stream_interface <=
+ MPQ_ADAPTER_VIDEO3_STREAM_IF)
+ idx = mpq_feed->video_info.stream_interface;
+ else if (dvb_dmx_is_audio_feed(mpq_feed->dvb_demux_feed) &&
+ mpq_feed->audio_info.stream_interface <=
+ MPQ_ADAPTER_AUDIO3_STREAM_IF)
+ idx = mpq_feed->audio_info.stream_interface;
+ else
+ return;
curr_time = current_kernel_time();
if (unlikely(!mpq_demux->decoder_stat[idx].out_count)) {
@@ -703,6 +872,7 @@ int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func)
mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
mpq_demux->sdmx_eos = 0;
mpq_demux->sdmx_log_level = SDMX_LOG_NO_PRINT;
+ mpq_demux->ts_packet_timestamp_source = 0;
if (mpq_demux->demux.feednum > MPQ_MAX_DMX_FILES) {
MPQ_DVB_ERR_PRINT(
@@ -1050,9 +1220,33 @@ int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie)
mutex_unlock(&mpq_demux->mutex);
return ret;
- }
+ } else if (dvb_dmx_is_audio_feed(feed)) {
+ struct mpq_audio_feed_info *feed_data;
+ struct mpq_feed *mpq_feed;
+ struct mpq_streambuffer *stream_buffer;
+ int ret;
- /* else */
+ mutex_lock(&mpq_demux->mutex);
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->audio_info;
+
+ spin_lock(&feed_data->audio_buffer_lock);
+ stream_buffer = feed_data->audio_buffer;
+ if (stream_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed, feed_data->audio_buffer is NULL\n",
+ __func__);
+ spin_unlock(&feed_data->audio_buffer_lock);
+ mutex_unlock(&mpq_demux->mutex);
+ return -EINVAL;
+ }
+
+ ret = mpq_streambuffer_pkt_dispose(stream_buffer, cookie, 1);
+ spin_unlock(&feed_data->audio_buffer_lock);
+ mutex_unlock(&mpq_demux->mutex);
+
+ return ret;
+ }
MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n",
__func__, feed->pes_type);
@@ -1383,6 +1577,295 @@ int mpq_dmx_flush_stream_buffer(struct dvb_demux_feed *feed)
return ret;
}
+static int mpq_dmx_init_audio_internal_buffers(
+ struct mpq_demux *mpq_demux,
+ struct mpq_audio_feed_info *feed_data,
+ struct dmx_decoder_buffers *dec_buffs)
+{
+ struct ion_handle *temp_handle = NULL;
+ void *payload_buffer = NULL;
+ int actual_buffer_size = 0;
+ int ret = 0;
+
+ MPQ_DVB_DBG_PRINT("%s: Internal audio decoder buffer allocation\n",
+ __func__);
+
+ actual_buffer_size = dec_buffs->buffers_size;
+ actual_buffer_size += (SZ_4K - 1);
+ actual_buffer_size &= ~(SZ_4K - 1);
+
+ temp_handle = ion_alloc(mpq_demux->ion_client,
+ actual_buffer_size, SZ_4K,
+ ION_HEAP(audio_nonsecure_ion_heap),
+ mpq_demux->decoder_alloc_flags);
+
+ if (IS_ERR_OR_NULL(temp_handle)) {
+ ret = PTR_ERR(temp_handle);
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to allocate audio payload buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ payload_buffer = ion_map_kernel(mpq_demux->ion_client, temp_handle);
+
+ if (IS_ERR_OR_NULL(payload_buffer)) {
+ ret = PTR_ERR(payload_buffer);
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to map audio payload buffer %d\n",
+ __func__, ret);
+ if (!ret)
+ ret = -ENOMEM;
+ goto init_failed_free_payload_buffer;
+ }
+ feed_data->buffer_desc.decoder_buffers_num = 1;
+ feed_data->buffer_desc.ion_handle[0] = temp_handle;
+ feed_data->buffer_desc.desc[0].base = payload_buffer;
+ feed_data->buffer_desc.desc[0].size = actual_buffer_size;
+ feed_data->buffer_desc.desc[0].read_ptr = 0;
+ feed_data->buffer_desc.desc[0].write_ptr = 0;
+ feed_data->buffer_desc.desc[0].handle =
+ ion_share_dma_buf_fd(mpq_demux->ion_client, temp_handle);
+ if (IS_ERR_VALUE(feed_data->buffer_desc.desc[0].handle)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to share audio payload buffer %d\n",
+ __func__, ret);
+ ret = -ENOMEM;
+ goto init_failed_unmap_payload_buffer;
+ }
+
+ feed_data->buffer_desc.shared_file = fget(
+ feed_data->buffer_desc.desc[0].handle);
+
+ return 0;
+
+init_failed_unmap_payload_buffer:
+ ion_unmap_kernel(mpq_demux->ion_client, temp_handle);
+ feed_data->buffer_desc.desc[0].base = NULL;
+init_failed_free_payload_buffer:
+ ion_free(mpq_demux->ion_client, temp_handle);
+ feed_data->buffer_desc.ion_handle[0] = NULL;
+ feed_data->buffer_desc.desc[0].size = 0;
+ feed_data->buffer_desc.decoder_buffers_num = 0;
+ feed_data->buffer_desc.shared_file = NULL;
+end:
+ return ret;
+}
+
+static int mpq_dmx_init_audio_external_buffers(
+ struct mpq_audio_feed_info *feed_data,
+ struct dmx_decoder_buffers *dec_buffs,
+ struct ion_client *client)
+{
+ struct ion_handle *temp_handle = NULL;
+ void *payload_buffer = NULL;
+ int actual_buffer_size = 0;
+ int ret = 0;
+ int i;
+
+ /*
+ * Payload buffer was allocated externally (through ION).
+ * Map the ion handles to kernel memory
+ */
+ MPQ_DVB_DBG_PRINT("%s: External audio decoder buffer allocation\n",
+ __func__);
+
+ actual_buffer_size = dec_buffs->buffers_size;
+ if (!dec_buffs->is_linear) {
+ MPQ_DVB_DBG_PRINT("%s: Ex. Ring-buffer\n", __func__);
+ feed_data->buffer_desc.decoder_buffers_num = 1;
+ } else {
+ MPQ_DVB_DBG_PRINT("%s: Ex. Linear\n", __func__);
+ feed_data->buffer_desc.decoder_buffers_num =
+ dec_buffs->buffers_num;
+ }
+
+ for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+ ret = mpq_map_buffer_to_kernel(
+ client,
+ dec_buffs->handles[i],
+ &temp_handle,
+ &payload_buffer);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Failed mapping audio buffer %d\n",
+ __func__, i);
+ goto init_failed;
+ }
+ feed_data->buffer_desc.ion_handle[i] = temp_handle;
+ feed_data->buffer_desc.desc[i].base = payload_buffer;
+ feed_data->buffer_desc.desc[i].handle =
+ dec_buffs->handles[i];
+ feed_data->buffer_desc.desc[i].size =
+ dec_buffs->buffers_size;
+ feed_data->buffer_desc.desc[i].read_ptr = 0;
+ feed_data->buffer_desc.desc[i].write_ptr = 0;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s: Audio Buffer #%d: base=0x%p, handle=%d, size=%d\n",
+ __func__, i,
+ feed_data->buffer_desc.desc[i].base,
+ feed_data->buffer_desc.desc[i].handle,
+ feed_data->buffer_desc.desc[i].size);
+ }
+
+ return 0;
+
+init_failed:
+ for (i = 0; i < feed_data->buffer_desc.decoder_buffers_num; i++) {
+ if (feed_data->buffer_desc.ion_handle[i]) {
+ if (feed_data->buffer_desc.desc[i].base) {
+ ion_unmap_kernel(client,
+ feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.desc[i].base = NULL;
+ }
+ ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.ion_handle[i] = NULL;
+ feed_data->buffer_desc.desc[i].size = 0;
+ }
+ }
+ return ret;
+}
+static int mpq_dmx_init_audio_streambuffer(
+ struct mpq_feed *feed,
+ struct mpq_audio_feed_info *feed_data,
+ struct mpq_streambuffer *stream_buffer)
+{
+ int ret;
+ void *packet_buffer = NULL;
+ struct mpq_demux *mpq_demux = feed->mpq_demux;
+ struct ion_client *client = mpq_demux->ion_client;
+ struct dmx_decoder_buffers *dec_buffs = NULL;
+ enum mpq_streambuffer_mode mode;
+
+ dec_buffs = feed->dvb_demux_feed->feed.ts.decoder_buffers;
+
+ /* Allocate packet buffer holding the meta-data */
+ packet_buffer = vmalloc(AUDIO_META_DATA_BUFFER_SIZE);
+
+ if (packet_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to allocate packets buffer\n", __func__);
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ MPQ_DVB_DBG_PRINT("%s: dec_buffs: num=%d, size=%d, linear=%d\n",
+ __func__, dec_buffs->buffers_num,
+ dec_buffs->buffers_size,
+ dec_buffs->is_linear);
+
+ if (dec_buffs->buffers_num == 0)
+ ret = mpq_dmx_init_audio_internal_buffers(
+ mpq_demux, feed_data, dec_buffs);
+ else
+ ret = mpq_dmx_init_audio_external_buffers(
+ feed_data, dec_buffs, client);
+
+ if (ret != 0)
+ goto init_failed_free_packet_buffer;
+
+ mode = dec_buffs->is_linear ? MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR :
+ MPQ_STREAMBUFFER_BUFFER_MODE_RING;
+ ret = mpq_streambuffer_init(
+ feed_data->audio_buffer,
+ mode,
+ feed_data->buffer_desc.desc,
+ feed_data->buffer_desc.decoder_buffers_num,
+ packet_buffer,
+ AUDIO_META_DATA_BUFFER_SIZE);
+
+ if (ret != 0)
+ goto init_failed_free_packet_buffer;
+
+ goto end;
+
+
+init_failed_free_packet_buffer:
+ vfree(packet_buffer);
+end:
+ return ret;
+}
+
+static void mpq_dmx_release_audio_streambuffer(
+ struct mpq_feed *feed,
+ struct mpq_audio_feed_info *feed_data,
+ struct mpq_streambuffer *audio_buffer,
+ struct ion_client *client)
+{
+ int buf_num = 0;
+ int i;
+ struct dmx_decoder_buffers *dec_buffs =
+ feed->dvb_demux_feed->feed.ts.decoder_buffers;
+
+ mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+
+ mpq_streambuffer_terminate(audio_buffer);
+
+ vfree(audio_buffer->packet_data.data);
+
+ buf_num = feed_data->buffer_desc.decoder_buffers_num;
+
+ for (i = 0; i < buf_num; i++) {
+ if (feed_data->buffer_desc.ion_handle[i]) {
+ if (feed_data->buffer_desc.desc[i].base) {
+ ion_unmap_kernel(client,
+ feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.desc[i].base = NULL;
+ }
+
+ /*
+ * Un-share the buffer if kernel is the one that
+ * shared it.
+ */
+ if (!dec_buffs->buffers_num &&
+ feed_data->buffer_desc.shared_file) {
+ fput(feed_data->buffer_desc.shared_file);
+ feed_data->buffer_desc.shared_file = NULL;
+ }
+
+ ion_free(client, feed_data->buffer_desc.ion_handle[i]);
+ feed_data->buffer_desc.ion_handle[i] = NULL;
+ feed_data->buffer_desc.desc[i].size = 0;
+ }
+ }
+}
+
+int mpq_dmx_flush_audio_stream_buffer(struct dvb_demux_feed *feed)
+{
+ struct mpq_feed *mpq_feed = feed->priv;
+ struct mpq_audio_feed_info *feed_data = &mpq_feed->audio_info;
+ struct mpq_streambuffer *sbuff;
+ int ret = 0;
+
+ if (!dvb_dmx_is_audio_feed(feed)) {
+ MPQ_DVB_DBG_PRINT("%s: not a audio feed, feed type=%d\n",
+ __func__, feed->pes_type);
+ return 0;
+ }
+
+ spin_lock(&feed_data->audio_buffer_lock);
+
+ sbuff = feed_data->audio_buffer;
+ if (sbuff == NULL) {
+ MPQ_DVB_DBG_PRINT("%s: feed_data->audio_buffer is NULL\n",
+ __func__);
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return -ENODEV;
+ }
+
+ ret = mpq_streambuffer_flush(sbuff);
+ if (ret)
+ MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer_flush failed, ret=%d\n",
+ __func__, ret);
+
+ spin_unlock(&feed_data->audio_buffer_lock);
+
+ return ret;
+}
+
static int mpq_dmx_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length)
{
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
@@ -1398,6 +1881,10 @@ static int mpq_dmx_flush_buffer(struct dmx_ts_feed *ts_feed, size_t length)
MPQ_DVB_DBG_PRINT("%s: flushing video buffer\n", __func__);
ret = mpq_dmx_flush_stream_buffer(feed);
+ } else if (dvb_dmx_is_audio_feed(feed)) {
+ MPQ_DVB_DBG_PRINT("%s: flushing audio buffer\n", __func__);
+
+ ret = mpq_dmx_flush_audio_stream_buffer(feed);
}
mutex_unlock(&demux->mutex);
@@ -1437,21 +1924,25 @@ int mpq_dmx_init_video_feed(struct mpq_feed *mpq_feed)
/* Register the new stream-buffer interface to MPQ adapter */
switch (mpq_feed->dvb_demux_feed->pes_type) {
case DMX_PES_VIDEO0:
+ store_mpq_video_feed[0] = mpq_feed;
feed_data->stream_interface =
MPQ_ADAPTER_VIDEO0_STREAM_IF;
break;
case DMX_PES_VIDEO1:
+ store_mpq_video_feed[1] = mpq_feed;
feed_data->stream_interface =
MPQ_ADAPTER_VIDEO1_STREAM_IF;
break;
case DMX_PES_VIDEO2:
+ store_mpq_video_feed[2] = mpq_feed;
feed_data->stream_interface =
MPQ_ADAPTER_VIDEO2_STREAM_IF;
break;
case DMX_PES_VIDEO3:
+ store_mpq_video_feed[3] = mpq_feed;
feed_data->stream_interface =
MPQ_ADAPTER_VIDEO3_STREAM_IF;
break;
@@ -1551,6 +2042,126 @@ init_failed_free_priv_data:
return ret;
}
+/* Register the new stream-buffer interface to MPQ adapter */
+int mpq_dmx_init_audio_feed(struct mpq_feed *mpq_feed)
+{
+ int ret;
+ struct mpq_audio_feed_info *feed_data = &mpq_feed->audio_info;
+ struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+ struct mpq_streambuffer *stream_buffer;
+
+ switch (mpq_feed->dvb_demux_feed->pes_type) {
+ case DMX_PES_AUDIO0:
+ store_mpq_audio_feed[0] = mpq_feed;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO0_STREAM_IF;
+ break;
+
+ case DMX_PES_AUDIO1:
+ store_mpq_audio_feed[1] = mpq_feed;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO1_STREAM_IF;
+ break;
+
+ case DMX_PES_AUDIO2:
+ store_mpq_audio_feed[2] = mpq_feed;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO2_STREAM_IF;
+ break;
+
+ case DMX_PES_AUDIO3:
+ store_mpq_audio_feed[3] = mpq_feed;
+ feed_data->stream_interface =
+ MPQ_ADAPTER_AUDIO3_STREAM_IF;
+ break;
+
+ default:
+ MPQ_DVB_ERR_PRINT(
+ "%s: Invalid pes type %d\n",
+ __func__,
+ mpq_feed->dvb_demux_feed->pes_type);
+ ret = -EINVAL;
+ goto init_failed_free_priv_data;
+ }
+
+ /* make sure not occupied already */
+ stream_buffer = NULL;
+ mpq_adapter_get_stream_if(
+ feed_data->stream_interface,
+ &stream_buffer);
+ if (stream_buffer != NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Audio interface %d already occupied!\n",
+ __func__, feed_data->stream_interface);
+ ret = -EBUSY;
+ goto init_failed_free_priv_data;
+ }
+
+ feed_data->audio_buffer =
+ &mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
+
+ ret = mpq_dmx_init_audio_streambuffer(
+ mpq_feed, feed_data, feed_data->audio_buffer);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_init_streambuffer failed, err = %d\n",
+ __func__, ret);
+ goto init_failed_free_priv_data;
+ }
+
+ ret = mpq_adapter_register_stream_if(
+ feed_data->stream_interface,
+ feed_data->audio_buffer);
+
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_adapter_register_stream_if failed, err = %d\n",
+ __func__, ret);
+ goto init_failed_free_stream_buffer;
+ }
+
+ spin_lock_init(&feed_data->audio_buffer_lock);
+
+ feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+ feed_data->pes_header_offset = 0;
+ mpq_feed->dvb_demux_feed->pusi_seen = 0;
+ mpq_feed->dvb_demux_feed->peslen = 0;
+ feed_data->fullness_wait_cancel = 0;
+ mpq_streambuffer_get_data_rw_offset(feed_data->audio_buffer, NULL,
+ &feed_data->frame_offset);
+ feed_data->saved_pts_dts_info.pts_exist = 0;
+ feed_data->saved_pts_dts_info.dts_exist = 0;
+ feed_data->new_pts_dts_info.pts_exist = 0;
+ feed_data->new_pts_dts_info.dts_exist = 0;
+ feed_data->saved_info_used = 1;
+ feed_data->new_info_exists = 0;
+ feed_data->first_pts_dts_copy = 1;
+ feed_data->tei_errs = 0;
+ feed_data->last_continuity = -1;
+ feed_data->continuity_errs = 0;
+ feed_data->ts_packets_num = 0;
+ feed_data->ts_dropped_bytes = 0;
+
+ mpq_demux->decoder_stat[feed_data->stream_interface].drop_count = 0;
+ mpq_demux->decoder_stat[feed_data->stream_interface].out_count = 0;
+ mpq_demux->decoder_stat[feed_data->stream_interface].
+ out_interval_sum = 0;
+ mpq_demux->decoder_stat[feed_data->stream_interface].
+ out_interval_max = 0;
+ mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors = 0;
+ mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors = 0;
+
+ return 0;
+
+init_failed_free_stream_buffer:
+ mpq_dmx_release_audio_streambuffer(mpq_feed, feed_data,
+ feed_data->audio_buffer, mpq_demux->ion_client);
+ mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+init_failed_free_priv_data:
+ feed_data->audio_buffer = NULL;
+ return ret;
+}
+
/**
* mpq_dmx_terminate_video_feed - terminate video feed information
* that was previously initialized in mpq_dmx_init_video_feed
@@ -1563,11 +2174,12 @@ int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed)
{
struct mpq_streambuffer *video_buffer;
struct mpq_video_feed_info *feed_data;
- struct mpq_demux *mpq_demux = mpq_feed->mpq_demux;
+ struct mpq_demux *mpq_demux;
if (mpq_feed == NULL)
return -EINVAL;
+ mpq_demux = mpq_feed->mpq_demux;
feed_data = &mpq_feed->video_info;
spin_lock(&feed_data->video_buffer_lock);
@@ -1582,6 +2194,30 @@ int mpq_dmx_terminate_video_feed(struct mpq_feed *mpq_feed)
return 0;
}
+int mpq_dmx_terminate_audio_feed(struct mpq_feed *mpq_feed)
+{
+ struct mpq_streambuffer *audio_buffer;
+ struct mpq_audio_feed_info *feed_data;
+ struct mpq_demux *mpq_demux;
+
+ if (mpq_feed == NULL)
+ return -EINVAL;
+
+ mpq_demux = mpq_feed->mpq_demux;
+ feed_data = &mpq_feed->audio_info;
+
+ spin_lock(&feed_data->audio_buffer_lock);
+ audio_buffer = feed_data->audio_buffer;
+ feed_data->audio_buffer = NULL;
+ wake_up_all(&audio_buffer->raw_data.queue);
+ spin_unlock(&feed_data->audio_buffer_lock);
+
+ mpq_dmx_release_audio_streambuffer(mpq_feed, feed_data,
+ audio_buffer, mpq_demux->ion_client);
+
+ return 0;
+}
+
struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux_feed *tmp;
@@ -1814,6 +2450,12 @@ int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed)
MPQ_DVB_ERR_PRINT(
"%s: mpq_dmx_terminate_video_feed failed. ret = %d\n",
__func__, ret);
+ } else if (dvb_dmx_is_audio_feed(feed)) {
+ ret = mpq_dmx_terminate_audio_feed(mpq_feed);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_terminate_audio_feed failed. ret = %d\n",
+ __func__, ret);
}
if (mpq_feed->sdmx_buf_handle) {
@@ -1835,8 +2477,9 @@ int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed)
int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
{
+ struct mpq_feed *mpq_feed;
+
if (dvb_dmx_is_video_feed(feed)) {
- struct mpq_feed *mpq_feed;
struct mpq_video_feed_info *feed_data;
mpq_feed = feed->priv;
@@ -1844,13 +2487,18 @@ int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
feed_data->fullness_wait_cancel = 0;
return 0;
+ } else if (dvb_dmx_is_audio_feed(feed)) {
+ struct mpq_audio_feed_info *feed_data;
+
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->audio_info;
+ feed_data->fullness_wait_cancel = 0;
+
+ return 0;
}
- /* else */
- MPQ_DVB_DBG_PRINT(
- "%s: Invalid feed type %d\n",
- __func__,
- feed->pes_type);
+ MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n", __func__,
+ feed->pes_type);
return -EINVAL;
}
@@ -1864,7 +2512,7 @@ int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
*
* Return 1 if required free bytes are available, 0 otherwise.
*/
-static inline int mpq_dmx_check_decoder_fullness(
+static inline int mpq_dmx_check_video_decoder_fullness(
struct mpq_streambuffer *sbuff,
size_t required_space)
{
@@ -1888,6 +2536,29 @@ static inline int mpq_dmx_check_decoder_fullness(
return (free >= required_space);
}
+static inline int mpq_dmx_check_audio_decoder_fullness(
+ struct mpq_streambuffer *sbuff,
+ size_t required_space)
+{
+ ssize_t free = mpq_streambuffer_data_free(sbuff);
+ ssize_t free_meta = mpq_streambuffer_metadata_free(sbuff);
+
+ /* Verify meta-data buffer can contain at least 1 packet */
+ if (free_meta < AUDIO_META_DATA_PACKET_SIZE)
+ return 0;
+
+ /*
+ * For linear buffers, verify there's enough space for this TSP
+ * and an additional buffer is free, as framing might required one
+ * more buffer to be available.
+ */
+ if (sbuff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
+ return (free >= required_space &&
+ sbuff->pending_buffers_count < sbuff->buffers_num-1);
+ else
+ return (free >= required_space); /* Ring buffer mode */
+}
+
/**
* Checks whether decoder's output buffer has free space
* for specific number of bytes, if not, the function waits
@@ -1943,7 +2614,8 @@ static int mpq_dmx_decoder_fullness_check(
if ((feed_data->video_buffer != NULL) &&
(!feed_data->fullness_wait_cancel) &&
- (!mpq_dmx_check_decoder_fullness(sbuff, required_space))) {
+ (!mpq_dmx_check_video_decoder_fullness(sbuff,
+ required_space))) {
DEFINE_WAIT(__wait);
for (;;) {
@@ -1952,7 +2624,7 @@ static int mpq_dmx_decoder_fullness_check(
TASK_INTERRUPTIBLE);
if (!feed_data->video_buffer ||
feed_data->fullness_wait_cancel ||
- mpq_dmx_check_decoder_fullness(sbuff,
+ mpq_dmx_check_video_decoder_fullness(sbuff,
required_space))
break;
@@ -1987,11 +2659,102 @@ static int mpq_dmx_decoder_fullness_check(
return 0;
}
+static int mpq_dmx_audio_decoder_fullness_check(
+ struct dvb_demux_feed *feed,
+ size_t required_space,
+ int lock_feed)
+{
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_streambuffer *sbuff = NULL;
+ struct mpq_audio_feed_info *feed_data;
+ struct mpq_feed *mpq_feed;
+ int ret = 0;
+
+ if (!dvb_dmx_is_audio_feed(feed)) {
+ MPQ_DVB_DBG_PRINT("%s: Invalid feed type %d\n",
+ __func__,
+ feed->pes_type);
+ return -EINVAL;
+ }
+
+ if (lock_feed) {
+ mutex_lock(&mpq_demux->mutex);
+ } else if (!mutex_is_locked(&mpq_demux->mutex)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Mutex should have been locked\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->audio_info;
+
+ sbuff = feed_data->audio_buffer;
+ if (sbuff == NULL) {
+ if (lock_feed)
+ mutex_unlock(&mpq_demux->mutex);
+ MPQ_DVB_ERR_PRINT("%s: mpq_streambuffer object is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if ((feed_data->audio_buffer != NULL) &&
+ (!feed_data->fullness_wait_cancel) &&
+ (!mpq_dmx_check_audio_decoder_fullness(sbuff,
+ required_space))) {
+ DEFINE_WAIT(__wait);
+
+ for (;;) {
+ prepare_to_wait(&sbuff->raw_data.queue,
+ &__wait, TASK_INTERRUPTIBLE);
+ if (!feed_data->audio_buffer ||
+ feed_data->fullness_wait_cancel ||
+ mpq_dmx_check_audio_decoder_fullness(sbuff,
+ required_space))
+ break;
+
+ if (!signal_pending(current)) {
+ mutex_unlock(&mpq_demux->mutex);
+ schedule();
+ mutex_lock(&mpq_demux->mutex);
+ continue;
+ }
+
+ ret = -ERESTARTSYS;
+ break;
+ }
+ finish_wait(&sbuff->raw_data.queue, &__wait);
+ }
+
+ if (ret < 0) {
+ if (lock_feed)
+ mutex_unlock(&mpq_demux->mutex);
+ return ret;
+ }
+
+ if ((feed_data->fullness_wait_cancel) ||
+ (feed_data->audio_buffer == NULL)) {
+ if (lock_feed)
+ mutex_unlock(&mpq_demux->mutex);
+ return -EINVAL;
+ }
+
+ if (lock_feed)
+ mutex_unlock(&mpq_demux->mutex);
+ return 0;
+}
+
int mpq_dmx_decoder_fullness_wait(
struct dvb_demux_feed *feed,
size_t required_space)
{
- return mpq_dmx_decoder_fullness_check(feed, required_space, 1);
+ if (dvb_dmx_is_video_feed(feed))
+ return mpq_dmx_decoder_fullness_check(feed, required_space, 1);
+ else if (dvb_dmx_is_audio_feed(feed))
+ return mpq_dmx_audio_decoder_fullness_check(feed,
+ required_space, 1);
+
+ return 0;
}
int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
@@ -2009,8 +2772,7 @@ int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
spin_lock(&feed_data->video_buffer_lock);
if (feed_data->video_buffer == NULL) {
MPQ_DVB_DBG_PRINT(
- "%s: video_buffer released\n",
- __func__);
+ "%s: video_buffer released\n", __func__);
spin_unlock(&feed_data->video_buffer_lock);
return 0;
}
@@ -2020,13 +2782,33 @@ int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
spin_unlock(&feed_data->video_buffer_lock);
return 0;
+ } else if (dvb_dmx_is_audio_feed(feed)) {
+ struct mpq_feed *mpq_feed;
+ struct mpq_audio_feed_info *feed_data;
+ struct dvb_ringbuffer *audio_buff;
+
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->audio_info;
+
+ feed_data->fullness_wait_cancel = 1;
+
+ spin_lock(&feed_data->audio_buffer_lock);
+ if (feed_data->audio_buffer == NULL) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: audio_buffer released\n", __func__);
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0;
+ }
+
+ audio_buff = &feed_data->audio_buffer->raw_data;
+ wake_up_all(&audio_buff->queue);
+ spin_unlock(&feed_data->audio_buffer_lock);
+
+ return 0;
}
- /* else */
MPQ_DVB_ERR_PRINT(
- "%s: Invalid feed type %d\n",
- __func__,
- feed->pes_type);
+ "%s: Invalid feed type %d\n", __func__, feed->pes_type);
return -EINVAL;
}
@@ -2087,6 +2869,62 @@ int mpq_dmx_parse_mandatory_pes_header(
return 0;
}
+int mpq_dmx_parse_mandatory_audio_pes_header(
+ struct dvb_demux_feed *feed,
+ struct mpq_audio_feed_info *feed_data,
+ struct pes_packet_header *pes_header,
+ const u8 *buf,
+ u32 *ts_payload_offset,
+ int *bytes_avail)
+{
+ int left_size, copy_len;
+
+ if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) {
+ left_size =
+ PES_MANDATORY_FIELDS_LEN -
+ feed_data->pes_header_offset;
+
+ copy_len = (left_size > *bytes_avail) ?
+ *bytes_avail :
+ left_size;
+
+ memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+ (buf + *ts_payload_offset),
+ copy_len);
+
+ feed_data->pes_header_offset += copy_len;
+
+ if (left_size > *bytes_avail)
+ return -EINVAL;
+
+ /* else - we have beginning of PES header */
+ *bytes_avail -= left_size;
+ *ts_payload_offset += left_size;
+
+ /* Make sure the PES packet is valid */
+ if (mpq_dmx_is_valid_audio_pes(pes_header) < 0) {
+ /*
+ * Since the new PES header parsing
+ * failed, reset pusi_seen to drop all
+ * data until next PUSI
+ */
+ feed->pusi_seen = 0;
+ feed_data->pes_header_offset = 0;
+
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid packet\n",
+ __func__);
+
+ return -EINVAL;
+ }
+
+ feed_data->pes_header_left_bytes =
+ pes_header->pes_header_data_length;
+ }
+
+ return 0;
+}
+
static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
struct pes_packet_header *pes_header)
{
@@ -2126,6 +2964,46 @@ static inline void mpq_dmx_get_pts_dts(struct mpq_video_feed_info *feed_data,
feed_data->new_info_exists = 1;
}
+static inline void mpq_dmx_get_audio_pts_dts(
+ struct mpq_audio_feed_info *feed_data,
+ struct pes_packet_header *pes_header)
+{
+ struct dmx_pts_dts_info *info = &(feed_data->new_pts_dts_info);
+
+ /* Get PTS/DTS information from PES header */
+
+ if ((pes_header->pts_dts_flag == 2) ||
+ (pes_header->pts_dts_flag == 3)) {
+ info->pts_exist = 1;
+
+ info->pts =
+ ((u64)pes_header->pts_1 << 30) |
+ ((u64)pes_header->pts_2 << 22) |
+ ((u64)pes_header->pts_3 << 15) |
+ ((u64)pes_header->pts_4 << 7) |
+ (u64)pes_header->pts_5;
+ } else {
+ info->pts_exist = 0;
+ info->pts = 0;
+ }
+
+ if (pes_header->pts_dts_flag == 3) {
+ info->dts_exist = 1;
+
+ info->dts =
+ ((u64)pes_header->dts_1 << 30) |
+ ((u64)pes_header->dts_2 << 22) |
+ ((u64)pes_header->dts_3 << 15) |
+ ((u64)pes_header->dts_4 << 7) |
+ (u64)pes_header->dts_5;
+ } else {
+ info->dts_exist = 0;
+ info->dts = 0;
+ }
+
+ feed_data->new_info_exists = 1;
+}
+
int mpq_dmx_parse_remaining_pes_header(
struct dvb_demux_feed *feed,
struct mpq_video_feed_info *feed_data,
@@ -2218,6 +3096,96 @@ int mpq_dmx_parse_remaining_pes_header(
return 0;
}
+int mpq_dmx_parse_remaining_audio_pes_header(
+ struct dvb_demux_feed *feed,
+ struct mpq_audio_feed_info *feed_data,
+ struct pes_packet_header *pes_header,
+ const u8 *buf,
+ u32 *ts_payload_offset,
+ int *bytes_avail)
+{
+ int left_size, copy_len;
+
+ /* Remaining header bytes that need to be processed? */
+ if (!feed_data->pes_header_left_bytes)
+ return 0;
+
+ /* Did we capture the PTS value (if exists)? */
+ if ((*bytes_avail != 0) &&
+ (feed_data->pes_header_offset <
+ (PES_MANDATORY_FIELDS_LEN+5)) &&
+ ((pes_header->pts_dts_flag == 2) ||
+ (pes_header->pts_dts_flag == 3))) {
+
+ /* 5 more bytes should be there */
+ left_size =
+ PES_MANDATORY_FIELDS_LEN + 5 -
+ feed_data->pes_header_offset;
+
+ copy_len =
+ (left_size > *bytes_avail) ? *bytes_avail : left_size;
+
+ memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+ (buf + *ts_payload_offset), copy_len);
+
+ feed_data->pes_header_offset += copy_len;
+ feed_data->pes_header_left_bytes -= copy_len;
+
+ if (left_size > *bytes_avail)
+ return -EINVAL;
+
+ /* else - we have the PTS */
+ *bytes_avail -= copy_len;
+ *ts_payload_offset += copy_len;
+ }
+
+ /* Did we capture the DTS value (if exist)? */
+ if ((*bytes_avail != 0) &&
+ (feed_data->pes_header_offset <
+ (PES_MANDATORY_FIELDS_LEN+10)) &&
+ (pes_header->pts_dts_flag == 3)) {
+
+ /* 5 more bytes should be there */
+ left_size =
+ PES_MANDATORY_FIELDS_LEN + 10 -
+ feed_data->pes_header_offset;
+
+ copy_len = (left_size > *bytes_avail) ?
+ *bytes_avail :
+ left_size;
+
+ memcpy((u8 *)((u8 *)pes_header + feed_data->pes_header_offset),
+ (buf + *ts_payload_offset),
+ copy_len);
+
+ feed_data->pes_header_offset += copy_len;
+ feed_data->pes_header_left_bytes -= copy_len;
+
+ if (left_size > *bytes_avail)
+ return -EINVAL;
+
+ /* else - we have the DTS */
+ *bytes_avail -= copy_len;
+ *ts_payload_offset += copy_len;
+ }
+
+ /* Any more header bytes?! */
+ if (feed_data->pes_header_left_bytes >= *bytes_avail) {
+ feed_data->pes_header_left_bytes -= *bytes_avail;
+ return -EINVAL;
+ }
+
+ /* get PTS/DTS information from PES header to be written later */
+ mpq_dmx_get_audio_pts_dts(feed_data, pes_header);
+
+ /* Got PES header, process payload */
+ *bytes_avail -= feed_data->pes_header_left_bytes;
+ *ts_payload_offset += feed_data->pes_header_left_bytes;
+ feed_data->pes_header_left_bytes = 0;
+
+ return 0;
+}
+
static void mpq_dmx_check_continuity(struct mpq_video_feed_info *feed_data,
int current_continuity,
int discontinuity_indicator)
@@ -2249,6 +3217,37 @@ static void mpq_dmx_check_continuity(struct mpq_video_feed_info *feed_data,
feed_data->last_continuity = current_continuity;
}
+static void mpq_dmx_check_audio_continuity(
+ struct mpq_audio_feed_info *feed_data,
+ int current_continuity,
+ int discontinuity_indicator)
+{
+ const int max_continuity = 0x0F; /* 4 bits in the TS packet header */
+
+ /* sanity check */
+ if (unlikely((current_continuity < 0) ||
+ (current_continuity > max_continuity))) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: received invalid continuity counter value %d\n",
+ __func__, current_continuity);
+ return;
+ }
+
+ /* reset last continuity */
+ if ((feed_data->last_continuity == -1) || (discontinuity_indicator)) {
+ feed_data->last_continuity = current_continuity;
+ return;
+ }
+
+ /* check for continuity errors */
+ if (current_continuity !=
+ ((feed_data->last_continuity + 1) & max_continuity))
+ feed_data->continuity_errs++;
+
+ /* save for next time */
+ feed_data->last_continuity = current_continuity;
+}
+
static inline void mpq_dmx_prepare_es_event_data(
struct mpq_streambuffer_packet_header *packet,
struct mpq_adapter_video_meta_data *meta_data,
@@ -2295,6 +3294,43 @@ static inline void mpq_dmx_prepare_es_event_data(
feed_data->continuity_errs = 0;
}
+static inline void mpq_dmx_prepare_audio_es_event_data(
+ struct mpq_streambuffer_packet_header *packet,
+ struct mpq_adapter_audio_meta_data *meta_data,
+ struct mpq_audio_feed_info *feed_data,
+ struct mpq_streambuffer *stream_buffer,
+ struct dmx_data_ready *data,
+ int cookie)
+{
+ struct dmx_pts_dts_info *pts_dts;
+
+ pts_dts = &meta_data->info.pes.pts_dts_info;
+ data->buf.stc = meta_data->info.pes.stc;
+
+ data->data_length = 0;
+ data->buf.handle = packet->raw_data_handle;
+ data->buf.cookie = cookie;
+ data->buf.offset = packet->raw_data_offset;
+ data->buf.len = packet->raw_data_len;
+ data->buf.pts_exists = pts_dts->pts_exist;
+ data->buf.pts = pts_dts->pts;
+ data->buf.dts_exists = pts_dts->dts_exist;
+ data->buf.dts = pts_dts->dts;
+ data->buf.tei_counter = feed_data->tei_errs;
+ data->buf.cont_err_counter = feed_data->continuity_errs;
+ data->buf.ts_packets_num = feed_data->ts_packets_num;
+ data->buf.ts_dropped_bytes = feed_data->ts_dropped_bytes;
+ data->status = DMX_OK_DECODER_BUF;
+
+ MPQ_DVB_DBG_PRINT("%s: cookie=%d\n", __func__, data->buf.cookie);
+
+ /* reset counters */
+ feed_data->ts_packets_num = 0;
+ feed_data->ts_dropped_bytes = 0;
+ feed_data->tei_errs = 0;
+ feed_data->continuity_errs = 0;
+}
+
static int mpq_sdmx_dvr_buffer_desc(struct mpq_demux *mpq_demux,
struct sdmx_buff_descr *buf_desc)
{
@@ -2488,6 +3524,81 @@ static void mpq_dmx_decoder_pes_closure(struct mpq_demux *mpq_demux,
spin_unlock(&feed_data->video_buffer_lock);
}
+/*
+ * in audio handling although ES frames are send to decoder, close the
+ * pes packet
+ */
+static void mpq_dmx_decoder_audio_pes_closure(struct mpq_demux *mpq_demux,
+ struct mpq_feed *mpq_feed)
+{
+ struct mpq_streambuffer_packet_header packet;
+ struct mpq_streambuffer *stream_buffer;
+ struct mpq_adapter_audio_meta_data meta_data;
+ struct mpq_audio_feed_info *feed_data;
+ struct dvb_demux_feed *feed = mpq_feed->dvb_demux_feed;
+ struct dmx_data_ready data;
+ int cookie;
+
+ feed_data = &mpq_feed->audio_info;
+
+ /*
+ * spin-lock is taken to protect against manipulation of audio
+ * output buffer by the API (terminate audio feed, re-use of audio
+ * buffers).
+ */
+ spin_lock(&feed_data->audio_buffer_lock);
+ stream_buffer = feed_data->audio_buffer;
+
+ if (stream_buffer == NULL) {
+ MPQ_DVB_DBG_PRINT("%s: audio_buffer released\n", __func__);
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return;
+ }
+
+ /*
+ * Close previous PES.
+ * Push new packet to the meta-data buffer.
+ */
+ if ((feed->pusi_seen) && (feed_data->pes_header_left_bytes == 0)) {
+ packet.raw_data_len = feed->peslen;
+ mpq_streambuffer_get_buffer_handle(stream_buffer,
+ 0, /* current write buffer handle */
+ &packet.raw_data_handle);
+ packet.raw_data_offset = feed_data->frame_offset;
+ packet.user_data_len =
+ sizeof(struct mpq_adapter_audio_meta_data);
+
+ mpq_dmx_write_audio_pts_dts(feed_data,
+ &(meta_data.info.pes.pts_dts_info));
+
+ meta_data.packet_type = DMX_PES_PACKET;
+ meta_data.info.pes.stc = feed_data->prev_stc;
+
+ mpq_dmx_update_decoder_stat(mpq_feed);
+
+ cookie = mpq_streambuffer_pkt_write(stream_buffer, &packet,
+ (u8 *)&meta_data);
+ if (cookie >= 0) {
+ /* Save write offset where new PES will begin */
+ mpq_streambuffer_get_data_rw_offset(stream_buffer, NULL,
+ &feed_data->frame_offset);
+ mpq_dmx_prepare_audio_es_event_data(&packet, &meta_data,
+ feed_data, stream_buffer, &data, cookie);
+ feed->data_ready_cb.ts(&feed->feed.ts, &data);
+ } else {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_sb_pkt_write failed, ret=%d\n",
+ __func__, cookie);
+ }
+ }
+ /* Reset PES info */
+ feed->peslen = 0;
+ feed_data->pes_header_offset = 0;
+ feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+
+ spin_unlock(&feed_data->audio_buffer_lock);
+}
+
static int mpq_dmx_process_video_packet_framing(
struct dvb_demux_feed *feed,
const u8 *buf,
@@ -2824,6 +3935,7 @@ static int mpq_dmx_process_video_packet_framing(
pending_data_len -= bytes_to_write;
feed_data->pending_pattern_len += bytes_to_write;
}
+ non_predicted_video_frame = 0;
is_video_frame = mpq_dmx_is_video_frame(
feed->video_codec,
@@ -2863,9 +3975,9 @@ static int mpq_dmx_process_video_packet_framing(
ret = mpq_streambuffer_pkt_write(stream_buffer, &packet,
(u8 *)&meta_data);
if (ret < 0) {
- MPQ_DVB_ERR_PRINT(
- "%s: mpq_streambuffer_pkt_write failed, ret=%d\n",
- __func__, ret);
+ MPQ_DVB_ERR_PRINT
+ ("%s: mpq_sb_pkt_write failed ret=%d\n",
+ __func__, ret);
if (ret == -ENOSPC)
mpq_dmx_notify_overflow(feed);
} else {
@@ -2873,7 +3985,15 @@ static int mpq_dmx_process_video_packet_framing(
&packet, &meta_data, feed_data,
stream_buffer, &data, ret);
- feed->data_ready_cb.ts(&feed->feed.ts, &data);
+ /* Trigger ES Data Event for VPTS */
+ if (video_b_frame_events == 1) {
+ if (non_predicted_video_frame == 1)
+ feed->data_ready_cb.ts
+ (&feed->feed.ts, &data);
+ } else {
+ feed->data_ready_cb.ts(&feed->feed.ts,
+ &data);
+ }
if (feed_data->video_buffer->mode ==
MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR)
@@ -3071,8 +4191,8 @@ static int mpq_dmx_process_video_packet_no_framing(
stream_buffer, &packet,
(u8 *)&meta_data);
if (cookie < 0) {
- MPQ_DVB_ERR_PRINT(
- "%s: mpq_streambuffer_pkt_write failed, ret=%d\n",
+ MPQ_DVB_ERR_PRINT
+ ("%s: write failed, ret=%d\n",
__func__, cookie);
} else {
/*
@@ -3200,60 +4320,335 @@ static int mpq_dmx_process_video_packet_no_framing(
return 0;
}
-int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed,
- struct dmx_buffer_status *dmx_buffer_status)
+/*
+ * parse PES headers and send down ES packets to decoder
+ * Trigger a new ES Data Event with APTS and QTimer in 1st PES
+ */
+static int mpq_dmx_process_audio_packet_no_framing(
+ struct dvb_demux_feed *feed,
+ const u8 *buf,
+ u64 curr_stc)
{
- struct mpq_demux *mpq_demux = feed->demux->priv;
- struct mpq_video_feed_info *feed_data;
- struct mpq_streambuffer *video_buff;
+ int bytes_avail;
+ u32 ts_payload_offset;
+ struct mpq_audio_feed_info *feed_data;
+ const struct ts_packet_header *ts_header;
+ struct mpq_streambuffer *stream_buffer;
+ struct pes_packet_header *pes_header;
+ struct mpq_demux *mpq_demux;
struct mpq_feed *mpq_feed;
+ int discontinuity_indicator = 0;
+ struct dmx_data_ready data;
+ int cookie;
+ int ret;
- if (!dvb_dmx_is_video_feed(feed)) {
- MPQ_DVB_ERR_PRINT(
- "%s: Invalid feed type %d\n",
- __func__,
- feed->pes_type);
- return -EINVAL;
+ mpq_demux = feed->demux->priv;
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->audio_info;
+
+ /*
+ * spin-lock is taken to protect against manipulation of audio
+ * output buffer by the API (terminate audio feed, re-use of audio
+ * buffers). Mutex on the audio-feed cannot be held here
+ * since SW demux holds a spin-lock while calling write_to_decoder
+ */
+ spin_lock(&feed_data->audio_buffer_lock);
+ stream_buffer = feed_data->audio_buffer;
+ if (stream_buffer == NULL) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: audio_buffer released\n",
+ __func__);
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0;
}
- mutex_lock(&mpq_demux->mutex);
+ ts_header = (const struct ts_packet_header *)buf;
- mpq_feed = feed->priv;
- feed_data = &mpq_feed->video_info;
- video_buff = feed_data->video_buffer;
- if (!video_buff) {
- mutex_unlock(&mpq_demux->mutex);
- return -EINVAL;
+ pes_header = &feed_data->pes_header;
+
+ /* Make sure this TS packet has a payload and not scrambled */
+ if ((ts_header->sync_byte != 0x47) ||
+ (ts_header->adaptation_field_control == 0) ||
+ (ts_header->adaptation_field_control == 2) ||
+ (ts_header->transport_scrambling_control)) {
+ /* continue to next packet */
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0;
}
- dmx_buffer_status->error = video_buff->raw_data.error;
+ if (ts_header->payload_unit_start_indicator) { /* PUSI? */
+ if (feed->pusi_seen) { /* Did we see PUSI before? */
+ struct mpq_streambuffer_packet_header packet;
+ struct mpq_adapter_audio_meta_data meta_data;
+
+ /*
+ * Close previous PES.
+ * Push new packet to the meta-data buffer.
+ * Double check that we are not in middle of
+ * previous PES header parsing.
+ */
+
+ if (feed_data->pes_header_left_bytes == 0) {
+ packet.raw_data_len = feed->peslen;
+ mpq_streambuffer_get_buffer_handle(
+ stream_buffer,
+ 0, /* current write buffer handle */
+ &packet.raw_data_handle);
+ packet.raw_data_offset =
+ feed_data->frame_offset;
+ packet.user_data_len =
+ sizeof(struct
+ mpq_adapter_audio_meta_data);
+
+ mpq_dmx_write_audio_pts_dts(feed_data,
+ &(meta_data.info.pes.pts_dts_info));
+
+ /* Mark that we detected start of new PES */
+ feed_data->first_pts_dts_copy = 1;
+
+ meta_data.packet_type = DMX_PES_PACKET;
+ meta_data.info.pes.stc = feed_data->prev_stc;
+
+ mpq_dmx_update_decoder_stat(mpq_feed);
- if (video_buff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) {
- dmx_buffer_status->fullness =
- video_buff->buffers[0].size *
- video_buff->pending_buffers_count;
- dmx_buffer_status->free_bytes =
- video_buff->buffers[0].size *
- (video_buff->buffers_num -
- video_buff->pending_buffers_count);
- dmx_buffer_status->size =
- video_buff->buffers[0].size *
- video_buff->buffers_num;
+ /* actual writing of stream audio headers */
+ cookie = mpq_streambuffer_pkt_write(
+ stream_buffer, &packet,
+ (u8 *)&meta_data);
+ if (cookie < 0) {
+ MPQ_DVB_ERR_PRINT
+ ("%s: write failed, ret=%d\n",
+ __func__, cookie);
+ } else {
+ /*
+ * Save write offset where new PES
+ * will begin
+ */
+ mpq_streambuffer_get_data_rw_offset(
+ stream_buffer,
+ NULL,
+ &feed_data->frame_offset);
+
+ mpq_dmx_prepare_audio_es_event_data(
+ &packet, &meta_data,
+ feed_data,
+ stream_buffer, &data, cookie);
+
+ /*
+ * Trigger ES data event for APTS
+ * and AFRAME
+ */
+ feed->data_ready_cb.ts(&feed->feed.ts,
+ &data);
+ }
+ } else {
+ MPQ_DVB_ERR_PRINT(
+ "%s: received PUSI while handling PES header of previous PES\n",
+ __func__);
+ }
+
+ /* Reset PES info */
+ feed->peslen = 0;
+ feed_data->pes_header_offset = 0;
+ feed_data->pes_header_left_bytes =
+ PES_MANDATORY_FIELDS_LEN;
+ } else {
+ feed->pusi_seen = 1;
+ }
+
+ feed_data->prev_stc = curr_stc;
+ }
+
+ /*
+ * Parse PES data only if PUSI was encountered,
+ * otherwise the data is dropped
+ */
+ if (!feed->pusi_seen) {
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0; /* drop and wait for next packets */
+ }
+
+ ts_payload_offset = sizeof(struct ts_packet_header);
+
+ /*
+ * Skip adaptation field if exists.
+ * Save discontinuity indicator if exists.
+ */
+ if (ts_header->adaptation_field_control == 3) {
+ const struct ts_adaptation_field *adaptation_field =
+ (const struct ts_adaptation_field *)(buf +
+ ts_payload_offset);
+
+ discontinuity_indicator =
+ adaptation_field->discontinuity_indicator;
+ ts_payload_offset += buf[ts_payload_offset] + 1;
+ }
+
+ bytes_avail = TS_PACKET_SIZE - ts_payload_offset;
+
+ /* The audio decoder requires ES packets ! */
+
+ /* Get the mandatory fields of the audio PES header */
+ if (mpq_dmx_parse_mandatory_audio_pes_header(feed, feed_data,
+ pes_header, buf,
+ &ts_payload_offset,
+ &bytes_avail)) {
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0;
+ }
+
+ if (mpq_dmx_parse_remaining_audio_pes_header(feed, feed_data,
+ pes_header, buf,
+ &ts_payload_offset,
+ &bytes_avail)) {
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0;
+ }
+
+ /*
+ * If we reached here,
+ * then we are now at the PES payload data
+ */
+ if (bytes_avail == 0) {
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0;
+ }
+
+ /*
+ * Need to back-up the PTS information
+ * of the start of new PES
+ */
+ if (feed_data->first_pts_dts_copy) {
+ mpq_dmx_save_audio_pts_dts(feed_data);
+ feed_data->first_pts_dts_copy = 0;
+ }
+
+ /* Update error counters based on TS header */
+ feed_data->ts_packets_num++;
+ feed_data->tei_errs += ts_header->transport_error_indicator;
+ mpq_demux->decoder_stat[feed_data->stream_interface].ts_errors +=
+ ts_header->transport_error_indicator;
+ mpq_dmx_check_audio_continuity(feed_data,
+ ts_header->continuity_counter,
+ discontinuity_indicator);
+ mpq_demux->decoder_stat[feed_data->stream_interface].cc_errors +=
+ feed_data->continuity_errs;
+
+ /* actual writing of audio data for a stream */
+ ret = mpq_streambuffer_data_write(stream_buffer, buf+ts_payload_offset,
+ bytes_avail);
+ if (ret < 0) {
+ mpq_demux->decoder_stat
+ [feed_data->stream_interface].drop_count += bytes_avail;
+ feed_data->ts_dropped_bytes += bytes_avail;
+ if (ret == -ENOSPC)
+ mpq_dmx_notify_overflow(feed);
} else {
- dmx_buffer_status->fullness =
- mpq_streambuffer_data_avail(video_buff);
- dmx_buffer_status->free_bytes =
- mpq_streambuffer_data_free(video_buff);
- dmx_buffer_status->size = video_buff->buffers[0].size;
+ feed->peslen += bytes_avail;
}
- mpq_streambuffer_get_data_rw_offset(
- video_buff,
- &dmx_buffer_status->read_offset,
- &dmx_buffer_status->write_offset);
+ spin_unlock(&feed_data->audio_buffer_lock);
- mutex_unlock(&mpq_demux->mutex);
+ return 0;
+}
+
+/* function ptr used in several places, handle differently */
+int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed,
+ struct dmx_buffer_status *dmx_buffer_status)
+{
+
+ if (dvb_dmx_is_video_feed(feed)) {
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_video_feed_info *feed_data;
+ struct mpq_streambuffer *video_buff;
+ struct mpq_feed *mpq_feed;
+
+ mutex_lock(&mpq_demux->mutex);
+
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->video_info;
+ video_buff = feed_data->video_buffer;
+ if (!video_buff) {
+ mutex_unlock(&mpq_demux->mutex);
+ return -EINVAL;
+ }
+
+ dmx_buffer_status->error = video_buff->raw_data.error;
+
+ if (video_buff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) {
+ dmx_buffer_status->fullness =
+ video_buff->buffers[0].size *
+ video_buff->pending_buffers_count;
+ dmx_buffer_status->free_bytes =
+ video_buff->buffers[0].size *
+ (video_buff->buffers_num -
+ video_buff->pending_buffers_count);
+ dmx_buffer_status->size =
+ video_buff->buffers[0].size *
+ video_buff->buffers_num;
+ } else {
+ dmx_buffer_status->fullness =
+ mpq_streambuffer_data_avail(video_buff);
+ dmx_buffer_status->free_bytes =
+ mpq_streambuffer_data_free(video_buff);
+ dmx_buffer_status->size = video_buff->buffers[0].size;
+ }
+
+ mpq_streambuffer_get_data_rw_offset(
+ video_buff,
+ &dmx_buffer_status->read_offset,
+ &dmx_buffer_status->write_offset);
+
+ mutex_unlock(&mpq_demux->mutex);
+
+ } else if (dvb_dmx_is_audio_feed(feed)) {
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+ struct mpq_audio_feed_info *feed_data;
+ struct mpq_streambuffer *audio_buff;
+ struct mpq_feed *mpq_feed;
+
+ mutex_lock(&mpq_demux->mutex);
+
+ mpq_feed = feed->priv;
+ feed_data = &mpq_feed->audio_info;
+ audio_buff = feed_data->audio_buffer;
+ if (!audio_buff) {
+ mutex_unlock(&mpq_demux->mutex);
+ return -EINVAL;
+ }
+
+ dmx_buffer_status->error = audio_buff->raw_data.error;
+
+ if (audio_buff->mode == MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR) {
+ dmx_buffer_status->fullness =
+ audio_buff->buffers[0].size *
+ audio_buff->pending_buffers_count;
+ dmx_buffer_status->free_bytes =
+ audio_buff->buffers[0].size *
+ (audio_buff->buffers_num -
+ audio_buff->pending_buffers_count);
+ dmx_buffer_status->size =
+ audio_buff->buffers[0].size *
+ audio_buff->buffers_num;
+ } else {
+ dmx_buffer_status->fullness =
+ mpq_streambuffer_data_avail(audio_buff);
+ dmx_buffer_status->free_bytes =
+ mpq_streambuffer_data_free(audio_buff);
+ dmx_buffer_status->size = audio_buff->buffers[0].size;
+ }
+
+ mpq_streambuffer_get_data_rw_offset(
+ audio_buff,
+ &dmx_buffer_status->read_offset,
+ &dmx_buffer_status->write_offset);
+ mutex_unlock(&mpq_demux->mutex);
+ } else {
+ MPQ_DVB_ERR_PRINT("%s: Invalid feed type %d\n",
+ __func__, feed->pes_type);
+ return -EINVAL;
+ }
return 0;
}
@@ -3268,10 +4663,18 @@ int mpq_dmx_process_video_packet(
(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
curr_stc = 0;
} else {
- curr_stc = buf[STC_LOCATION_IDX + 2] << 16;
- curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
- curr_stc += buf[STC_LOCATION_IDX];
- curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+ if (mpq_demux->ts_packet_timestamp_source !=
+ TSIF_TTS_LPASS_TIMER) {
+ curr_stc = buf[STC_LOCATION_IDX + 2] << 16;
+ curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+ curr_stc += buf[STC_LOCATION_IDX];
+ curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+ } else {
+ curr_stc = buf[STC_LOCATION_IDX + 3] << 24;
+ curr_stc += buf[STC_LOCATION_IDX + 2] << 16;
+ curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+ curr_stc += buf[STC_LOCATION_IDX];
+ }
}
if (!video_framing)
@@ -3282,6 +4685,34 @@ int mpq_dmx_process_video_packet(
curr_stc);
}
+int mpq_dmx_process_audio_packet(
+ struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ u64 curr_stc;
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+
+ if ((mpq_demux->source >= DMX_SOURCE_DVR0) &&
+ (mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
+ curr_stc = 0;
+ } else {
+ if (mpq_demux->ts_packet_timestamp_source !=
+ TSIF_TTS_LPASS_TIMER) {
+ curr_stc = buf[STC_LOCATION_IDX + 2] << 16;
+ curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+ curr_stc += buf[STC_LOCATION_IDX];
+ curr_stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+ } else {
+ curr_stc = buf[STC_LOCATION_IDX + 3] << 24;
+ curr_stc += buf[STC_LOCATION_IDX + 2] << 16;
+ curr_stc += buf[STC_LOCATION_IDX + 1] << 8;
+ curr_stc += buf[STC_LOCATION_IDX];
+ }
+ }
+
+ return mpq_dmx_process_audio_packet_no_framing(feed, buf, curr_stc);
+}
+
int mpq_dmx_extract_pcr_and_dci(const u8 *buf, u64 *pcr, int *dci)
{
const struct ts_packet_header *ts_header;
@@ -3342,10 +4773,18 @@ int mpq_dmx_process_pcr_packet(
(mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
stc = 0;
} else {
- stc = buf[STC_LOCATION_IDX + 2] << 16;
- stc += buf[STC_LOCATION_IDX + 1] << 8;
- stc += buf[STC_LOCATION_IDX];
- stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+ if (mpq_demux->ts_packet_timestamp_source !=
+ TSIF_TTS_LPASS_TIMER) {
+ stc = buf[STC_LOCATION_IDX + 2] << 16;
+ stc += buf[STC_LOCATION_IDX + 1] << 8;
+ stc += buf[STC_LOCATION_IDX];
+ stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+ } else {
+ stc = buf[STC_LOCATION_IDX + 3] << 24;
+ stc += buf[STC_LOCATION_IDX + 2] << 16;
+ stc += buf[STC_LOCATION_IDX + 1] << 8;
+ stc += buf[STC_LOCATION_IDX];
+ }
}
data.data_length = 0;
@@ -3356,45 +4795,86 @@ int mpq_dmx_process_pcr_packet(
return 0;
}
-int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed)
+int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed, int feed_type)
{
- struct mpq_video_feed_info *feed_data = &mpq_feed->video_info;
- struct mpq_streambuffer *stream_buffer;
- struct mpq_streambuffer_packet_header oob_packet;
- struct mpq_adapter_video_meta_data oob_meta_data;
- int ret;
+ if (feed_type == 1) { /* video feed */
+ struct mpq_video_feed_info *feed_data = &mpq_feed->video_info;
+ struct mpq_streambuffer *stream_buffer;
+ struct mpq_streambuffer_packet_header oob_packet;
+ struct mpq_adapter_video_meta_data oob_meta_data;
+ int ret;
- spin_lock(&feed_data->video_buffer_lock);
- stream_buffer = feed_data->video_buffer;
+ spin_lock(&feed_data->video_buffer_lock);
+ stream_buffer = feed_data->video_buffer;
+
+ if (stream_buffer == NULL) {
+ MPQ_DVB_DBG_PRINT("%s: video_buffer released\n",
+ __func__);
+ spin_unlock(&feed_data->video_buffer_lock);
+ return 0;
+ }
+
+ memset(&oob_packet, 0, sizeof(oob_packet));
+ oob_packet.user_data_len = sizeof(oob_meta_data);
+ oob_meta_data.packet_type = DMX_EOS_PACKET;
+
+ ret = mpq_streambuffer_pkt_write(stream_buffer, &oob_packet,
+ (u8 *)&oob_meta_data);
- if (stream_buffer == NULL) {
- MPQ_DVB_DBG_PRINT("%s: video_buffer released\n", __func__);
spin_unlock(&feed_data->video_buffer_lock);
- return 0;
- }
+ return (ret < 0) ? ret : 0;
- memset(&oob_packet, 0, sizeof(oob_packet));
- oob_packet.user_data_len = sizeof(oob_meta_data);
- oob_meta_data.packet_type = DMX_EOS_PACKET;
+ } else if (feed_type == 2) { /* audio feed */
+ struct mpq_audio_feed_info *feed_data = &mpq_feed->audio_info;
+ struct mpq_streambuffer *stream_buffer;
+ struct mpq_streambuffer_packet_header oob_packet;
+ struct mpq_adapter_audio_meta_data oob_meta_data;
+ int ret;
- ret = mpq_streambuffer_pkt_write(stream_buffer, &oob_packet,
- (u8 *)&oob_meta_data);
+ spin_lock(&feed_data->audio_buffer_lock);
+ stream_buffer = feed_data->audio_buffer;
- spin_unlock(&feed_data->video_buffer_lock);
- return (ret < 0) ? ret : 0;
+ if (stream_buffer == NULL) {
+ MPQ_DVB_DBG_PRINT("%s: audio_buffer released\n",
+ __func__);
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return 0;
+ }
+
+ memset(&oob_packet, 0, sizeof(oob_packet));
+ oob_packet.user_data_len = sizeof(oob_meta_data);
+ oob_meta_data.packet_type = DMX_EOS_PACKET;
+
+ ret = mpq_streambuffer_pkt_write(stream_buffer, &oob_packet,
+ (u8 *)&oob_meta_data);
+
+ spin_unlock(&feed_data->audio_buffer_lock);
+ return (ret < 0) ? ret : 0;
+ }
+
+ return 0;
}
void mpq_dmx_convert_tts(struct dvb_demux_feed *feed,
const u8 timestamp[TIMESTAMP_LEN],
u64 *timestampIn27Mhz)
{
+ struct mpq_demux *mpq_demux = feed->demux->priv;
+
if (unlikely(!timestampIn27Mhz))
return;
- *timestampIn27Mhz = timestamp[2] << 16;
- *timestampIn27Mhz += timestamp[1] << 8;
- *timestampIn27Mhz += timestamp[0];
- *timestampIn27Mhz *= 256; /* convert from 105.47 KHZ to 27MHz */
+ if (mpq_demux->ts_packet_timestamp_source != TSIF_TTS_LPASS_TIMER) {
+ *timestampIn27Mhz = timestamp[2] << 16;
+ *timestampIn27Mhz += timestamp[1] << 8;
+ *timestampIn27Mhz += timestamp[0];
+ *timestampIn27Mhz *= 256; /* convert from 105.47 KHZ to 27MHz */
+ } else {
+ *timestampIn27Mhz = timestamp[3] << 24;
+ *timestampIn27Mhz += timestamp[2] << 16;
+ *timestampIn27Mhz += timestamp[1] << 8;
+ *timestampIn27Mhz += timestamp[0];
+ }
}
int mpq_sdmx_open_session(struct mpq_demux *mpq_demux)
@@ -3904,6 +5384,16 @@ int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed)
}
}
+ if (dvb_dmx_is_audio_feed(feed)) {
+ ret = mpq_dmx_init_audio_feed(mpq_feed);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_init_audio_feed failed, ret=%d\n",
+ __func__, ret);
+ goto init_mpq_feed_end;
+ }
+ }
+
/*
* sdmx is not relevant for recording filters, which always use
* regular filters (non-sdmx)
@@ -3924,6 +5414,8 @@ int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed)
__func__, ret);
if (dvb_dmx_is_video_feed(feed))
mpq_dmx_terminate_video_feed(mpq_feed);
+ else if (dvb_dmx_is_audio_feed(feed))
+ mpq_dmx_terminate_audio_feed(mpq_feed);
}
init_mpq_feed_end:
@@ -4662,7 +6154,7 @@ decoder_filter_check_flags:
if (sts->status_indicators & SDMX_FILTER_STATUS_EOS) {
/* Notify decoder via the stream buffer */
- ret = mpq_dmx_decoder_eos_cmd(mpq_feed);
+ ret = mpq_dmx_decoder_eos_cmd(mpq_feed, 1);
if (ret)
MPQ_DVB_ERR_PRINT(
"%s: Failed to notify decoder on EOS, ret=%d\n",
@@ -5162,11 +6654,19 @@ int mpq_dmx_oob_command(struct dvb_demux_feed *feed,
else
mpq_dmx_decoder_frame_closure(mpq_demux,
mpq_feed);
- ret = mpq_dmx_decoder_eos_cmd(mpq_feed);
+ ret = mpq_dmx_decoder_eos_cmd(mpq_feed, 1);
if (ret)
MPQ_DVB_ERR_PRINT(
"%s: Couldn't write oob eos packet\n",
__func__);
+ } else if (dvb_dmx_is_audio_feed(feed)) {
+ mpq_dmx_decoder_audio_pes_closure(mpq_demux,
+ mpq_feed);
+ ret = mpq_dmx_decoder_eos_cmd(mpq_feed, 2);
+ if (ret)
+ MPQ_DVB_ERR_PRINT(
+ "%s: Couldn't write oob eos packet\n",
+ __func__);
}
ret = feed->data_ready_cb.ts(&feed->feed.ts, &event);
} else if (!mpq_demux->sdmx_eos) {
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
index f36e9e7e7a23..ca6372b7d152 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -44,12 +44,20 @@
#define VIDEO_META_DATA_BUFFER_SIZE \
(VIDEO_NUM_OF_PES_PACKETS * VIDEO_META_DATA_PACKET_SIZE)
+#define AUDIO_NUM_OF_PES_PACKETS 100
+
+#define AUDIO_META_DATA_PACKET_SIZE \
+ (DVB_RINGBUFFER_PKTHDRSIZE + \
+ sizeof(struct mpq_streambuffer_packet_header) + \
+ sizeof(struct mpq_adapter_audio_meta_data))
+
+#define AUDIO_META_DATA_BUFFER_SIZE \
+ (AUDIO_NUM_OF_PES_PACKETS * AUDIO_META_DATA_PACKET_SIZE)
+
/* Max number open() request can be done on demux device */
#define MPQ_MAX_DMX_FILES 128
-/**
- * TSIF alias name length
- */
+/* TSIF alias name length */
#define TSIF_NAME_LENGTH 20
/**
@@ -332,6 +340,30 @@ const struct dvb_dmx_video_patterns *patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM];
u64 prev_stc;
};
+/* require a bare minimal mpq_audio_feed_info struct */
+struct mpq_audio_feed_info {
+ struct mpq_streambuffer *audio_buffer;
+ spinlock_t audio_buffer_lock;
+ struct mpq_decoder_buffers_desc buffer_desc;
+ struct pes_packet_header pes_header;
+ u32 pes_header_left_bytes;
+ u32 pes_header_offset;
+ int fullness_wait_cancel;
+ enum mpq_adapter_stream_if stream_interface;
+ u32 frame_offset; /* pes frame offset */
+ struct dmx_pts_dts_info saved_pts_dts_info;
+ struct dmx_pts_dts_info new_pts_dts_info;
+ int saved_info_used;
+ int new_info_exists;
+ int first_pts_dts_copy;
+ u32 tei_errs;
+ int last_continuity;
+ u32 continuity_errs;
+ u32 ts_packets_num;
+ u32 ts_dropped_bytes;
+ u64 prev_stc;
+};
+
/**
* mpq feed object - mpq common plugin feed information
*
@@ -367,6 +399,7 @@ struct mpq_feed {
struct ion_handle *sdmx_buf_handle;
struct mpq_video_feed_info video_info;
+ struct mpq_audio_feed_info audio_info;
};
/**
@@ -509,6 +542,7 @@ struct mpq_demux {
enum sdmx_log_level sdmx_log_level;
struct timespec last_notification_time;
+ int ts_packet_timestamp_source;
};
/**
@@ -879,11 +913,12 @@ struct dvb_demux_feed *mpq_dmx_peer_rec_feed(struct dvb_demux_feed *feed);
/**
* mpq_dmx_decoder_eos_cmd() - Report EOS event to the mpq_streambuffer
*
- * @mpq_feed: Video mpq_feed object for notification
+ * @mpq_feed: Audio/Video mpq_feed object for notification
+ * @feed_type: Feed type( Audio or Video )
*
* Return error code
*/
-int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed);
+int mpq_dmx_decoder_eos_cmd(struct mpq_feed *mpq_feed, int feed_type);
/**
* mpq_dmx_parse_mandatory_pes_header() - Parse non-optional PES header fields
@@ -1023,5 +1058,66 @@ int mpq_dmx_get_param_scramble_even(void);
/* Return the common module parameter mpq_sdmx_scramble_default_discard */
int mpq_dmx_get_param_scramble_default_discard(void);
+/* APIs for Audio stream buffers interface -- Added for broadcase use case */
+/*
+ * The Audio/Video drivers (or consumers) require the stream_buffer information
+ * for consuming packet headers and compressed AV data from the
+ * ring buffer filled by demux driver which is the producer
+ */
+struct mpq_streambuffer *consumer_audio_streambuffer(int dmx_ts_pes_audio);
+struct mpq_streambuffer *consumer_video_streambuffer(int dmx_ts_pes_video);
+
+int mpq_dmx_init_audio_feed(struct mpq_feed *mpq_feed);
+
+int mpq_dmx_terminate_audio_feed(struct mpq_feed *mpq_feed);
+
+int mpq_dmx_parse_remaining_audio_pes_header(
+ struct dvb_demux_feed *feed,
+ struct mpq_audio_feed_info *feed_data,
+ struct pes_packet_header *pes_header,
+ const u8 *buf,
+ u32 *ts_payload_offset,
+ int *bytes_avail);
+
+static inline void mpq_dmx_save_audio_pts_dts(
+ struct mpq_audio_feed_info *feed_data)
+{
+ if (feed_data->new_info_exists) {
+ feed_data->saved_pts_dts_info.pts_exist =
+ feed_data->new_pts_dts_info.pts_exist;
+ feed_data->saved_pts_dts_info.pts =
+ feed_data->new_pts_dts_info.pts;
+ feed_data->saved_pts_dts_info.dts_exist =
+ feed_data->new_pts_dts_info.dts_exist;
+ feed_data->saved_pts_dts_info.dts =
+ feed_data->new_pts_dts_info.dts;
+
+ feed_data->new_info_exists = 0;
+ feed_data->saved_info_used = 0;
+ }
+}
+
+/*
+ * mpq_dmx_process_audio_packet - Assemble Audio PES data and output to
+ * stream buffer connected to decoder.
+ */
+int mpq_dmx_process_audio_packet(struct dvb_demux_feed *feed, const u8 *buf);
+
+static inline void mpq_dmx_write_audio_pts_dts(
+ struct mpq_audio_feed_info *feed_data,
+ struct dmx_pts_dts_info *info)
+{
+ if (!feed_data->saved_info_used) {
+ info->pts_exist = feed_data->saved_pts_dts_info.pts_exist;
+ info->pts = feed_data->saved_pts_dts_info.pts;
+ info->dts_exist = feed_data->saved_pts_dts_info.dts_exist;
+ info->dts = feed_data->saved_pts_dts_info.dts;
+
+ feed_data->saved_info_used = 1;
+ } else {
+ info->pts_exist = 0;
+ info->dts_exist = 0;
+ }
+}
#endif /* _MPQ_DMX_PLUGIN_COMMON_H */
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index be88bc1bf19f..4f4b9170d639 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -1634,6 +1634,9 @@ static int mpq_tspp_dmx_write_to_decoder(
if (dvb_dmx_is_video_feed(feed))
return mpq_dmx_process_video_packet(feed, buf);
+ if (dvb_dmx_is_audio_feed(feed))
+ return mpq_dmx_process_audio_packet(feed, buf);
+
if (dvb_dmx_is_pcr_feed(feed))
return mpq_dmx_process_pcr_packet(feed, buf);
@@ -1663,7 +1666,7 @@ static int mpq_tspp_dmx_get_caps(struct dmx_demux *demux,
caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA |
DMX_CAP_TS_INSERTION | DMX_CAP_VIDEO_INDEXING |
- DMX_CAP_AUTO_BUFFER_FLUSH;
+ DMX_CAP_AUDIO_DECODER_DATA | DMX_CAP_AUTO_BUFFER_FLUSH;
caps->recording_max_video_pids_indexed = 0;
caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
@@ -1753,6 +1756,8 @@ static int mpq_tspp_dmx_get_stc(struct dmx_demux *demux, unsigned int num,
{
enum tspp_source source;
u32 tcr_counter;
+ u64 avtimer_stc = 0;
+ int tts_source = 0;
if (!demux || !stc || !base)
return -EINVAL;
@@ -1764,11 +1769,18 @@ static int mpq_tspp_dmx_get_stc(struct dmx_demux *demux, unsigned int num,
else
return -EINVAL;
- tspp_get_ref_clk_counter(0, source, &tcr_counter);
-
- *stc = ((u64)tcr_counter) * 256; /* conversion to 27MHz */
- *base = 300; /* divisor to get 90KHz clock from stc value */
+ if (tspp_get_tts_source(0, &tts_source) < 0)
+ tts_source = TSIF_TTS_TCR;
+ if (tts_source != TSIF_TTS_LPASS_TIMER) {
+ tspp_get_ref_clk_counter(0, source, &tcr_counter);
+ *stc = ((u64)tcr_counter) * 256; /* conversion to 27MHz */
+ *base = 300; /* divisor to get 90KHz clock from stc value */
+ } else {
+ if (tspp_get_lpass_time_counter(0, source, &avtimer_stc) < 0)
+ return -EINVAL;
+ *stc = avtimer_stc;
+ }
return 0;
}
@@ -1840,6 +1852,10 @@ static int mpq_tspp_dmx_init(
/* Extend dvb-demux debugfs with TSPP statistics. */
mpq_dmx_init_debugfs_entries(mpq_demux);
+ /* Get the TSIF TTS info */
+ if (tspp_get_tts_source(0, &mpq_demux->ts_packet_timestamp_source) < 0)
+ mpq_demux->ts_packet_timestamp_source = TSIF_TTS_TCR;
+
return 0;
init_failed_dmx_release:
diff --git a/drivers/media/platform/msm/dvb/include/mpq_adapter.h b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
index 54e671c3b38d..c55a5aa1ae32 100644
--- a/drivers/media/platform/msm/dvb/include/mpq_adapter.h
+++ b/drivers/media/platform/msm/dvb/include/mpq_adapter.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -27,12 +27,24 @@ enum mpq_adapter_stream_if {
/** Interface holding stream-buffer for video1 stream */
MPQ_ADAPTER_VIDEO1_STREAM_IF = 1,
- /** Interface holding stream-buffer for video1 stream */
+ /** Interface holding stream-buffer for video2 stream */
MPQ_ADAPTER_VIDEO2_STREAM_IF = 2,
- /** Interface holding stream-buffer for video1 stream */
+ /** Interface holding stream-buffer for video3 stream */
MPQ_ADAPTER_VIDEO3_STREAM_IF = 3,
+ /** Interface holding stream-buffer for audio0 stream */
+ MPQ_ADAPTER_AUDIO0_STREAM_IF = 4,
+
+ /** Interface holding stream-buffer for audio1 stream */
+ MPQ_ADAPTER_AUDIO1_STREAM_IF = 5,
+
+ /** Interface holding stream-buffer for audio2 stream */
+ MPQ_ADAPTER_AUDIO2_STREAM_IF = 6,
+
+ /** Interface holding stream-buffer for audio3 stream */
+ MPQ_ADAPTER_AUDIO3_STREAM_IF = 7,
+
/** Maximum number of interfaces holding stream-buffers */
MPQ_ADAPTER_MAX_NUM_OF_INTERFACES,
};
@@ -113,6 +125,17 @@ struct mpq_adapter_video_meta_data {
} info;
} __packed;
+/** The meta-data used for audio interface */
+struct mpq_adapter_audio_meta_data {
+ /** meta-data packet type */
+ enum dmx_packet_type packet_type;
+
+ /** packet-type specific information */
+ union {
+ struct dmx_pes_packet_info pes;
+ struct dmx_marker_info marker;
+ } info;
+} __packed;
/** Callback function to notify on registrations of specific interfaces */
typedef void (*mpq_adapter_stream_if_callback)(
diff --git a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
index b24dc1f3b5ff..62404513007a 100644
--- a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
+++ b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -15,7 +15,6 @@
#include "dvb_ringbuffer.h"
-
/**
* DOC: MPQ Stream Buffer
*
@@ -459,4 +458,37 @@ ssize_t mpq_streambuffer_metadata_free(struct mpq_streambuffer *sbuff);
*/
int mpq_streambuffer_flush(struct mpq_streambuffer *sbuff);
+/*
+ * ------------------------------------------------------
+ * Consumer or AV Decoder Stream Interface to Ring Buffer
+ * ------------------------------------------------------
+ * Producer is Demux Driver
+ * ------------------------
+ *
+ * call from Audio/Video Decoder Driver to find Audio/Video
+ * streambuffer AV handles, "DMX_PES_AUDIO0 through 3" or
+ * DMX_PES_VIDEO0 through 3" interfaces corresponding to 4 programs.
+ */
+
+/* call from Audio/Video Decoder Driver via POLLING to consume
+ * Headers and Compressed data from ring buffer using streambuffer handle.
+ * hdrdata[] and cdata[] buffers have to be malloc'd by consumer
+ *
+ * --------------------------
+ * Consumer Calling Sequence
+ * --------------------------
+ * Find the streambuffer corresponding to a DMX TS PES stream instance.
+ * 1. consumer_audio_streambuffer() or consumer_video_streambuffer()
+ * Process the packet headers if required.
+ * 2. mpq_read_new_packet_hdr_data()
+ * Process the compressed data by forwarding to AV decoder.
+ * 3. mpq_read_new_packet_compressed_data()
+ * Dispose the packet.
+ * 4. mpq_dispose_new_packet_read()
+ *
+ * The Audio/Video drivers (or consumers) require the stream_buffer information
+ * for consuming packet headers and compressed AV data from the
+ * ring buffer filled by demux driver which is the producer
+ */
+
#endif /* _MPQ_STREAM_BUFFER_H */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index b485af0ee561..92b6e8ffa92e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -438,6 +438,40 @@ static void sde_mdp_parse_vbif_qos(struct platform_device *pdev,
}
}
+static int sde_mdp_parse_vbif_xin_id(struct platform_device *pdev,
+ struct sde_rot_data_type *mdata)
+{
+ int rc = 0;
+ bool default_xin_id = false;
+
+ mdata->nxid = sde_mdp_parse_dt_prop_len(pdev,
+ "qcom,mdss-rot-xin-id");
+ if (!mdata->nxid) {
+ mdata->nxid = 2;
+ default_xin_id = true;
+ }
+ mdata->vbif_xin_id = kzalloc(sizeof(u32) *
+ mdata->nxid, GFP_KERNEL);
+ if (!mdata->vbif_xin_id) {
+ SDEROT_ERR("xin alloc failure\n");
+ return -ENOMEM;
+ }
+ if (default_xin_id) {
+ mdata->vbif_xin_id[XIN_SSPP] = XIN_SSPP;
+ mdata->vbif_xin_id[XIN_WRITEBACK] = XIN_WRITEBACK;
+ } else {
+ rc = sde_mdp_parse_dt_handler(pdev,
+ "qcom,mdss-rot-xin-id", mdata->vbif_xin_id,
+ mdata->nxid);
+ if (rc) {
+ SDEROT_ERR("vbif xin id setting not found\n");
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
struct sde_rot_data_type *mdata)
{
@@ -463,6 +497,11 @@ static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
"Could not read optional property: highest bank bit\n");
sde_mdp_parse_vbif_qos(pdev, mdata);
+ rc = sde_mdp_parse_vbif_xin_id(pdev, mdata);
+ if (rc) {
+ SDEROT_DBG("vbif xin id dt parse failure\n");
+ return rc;
+ }
mdata->mdp_base = mdata->sde_io.base + SDE_MDP_OFFSET;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 92ea32d9e819..5cbdc03ced9d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -27,6 +27,10 @@
#define MDSS_MDP_HW_REV_320 0x30020000 /* sdm660 */
#define MDSS_MDP_HW_REV_330 0x30030000 /* sdm630 */
+/* XIN mapping */
+#define XIN_SSPP 0
+#define XIN_WRITEBACK 1
+
struct sde_mult_factor {
uint32_t numer;
uint32_t denom;
@@ -167,11 +171,17 @@ struct sde_rot_data_type {
u32 *vbif_nrt_qos;
u32 npriority_lvl;
+ u32 *vbif_xin_id;
+ u32 nxid;
+
int iommu_attached;
int iommu_ref_cnt;
int (*iommu_ctrl)(int enable);
int (*secure_session_ctrl)(int enable);
int (*wait_for_transition)(int state, int request);
+ void (*vbif_reg_lock)(void);
+ void (*vbif_reg_unlock)(void);
+ bool (*handoff_pending)(void);
struct sde_rot_vbif_debug_bus *nrt_vbif_dbg_bus;
u32 nrt_vbif_dbg_bus_size;
@@ -182,6 +192,8 @@ struct sde_rot_data_type {
int sec_cam_en;
bool callback_request;
struct ion_client *iclient;
+
+ bool handoff_done;
};
int sde_rotator_base_init(struct sde_rot_data_type **pmdata,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index b55bc905ea7a..c3ed1f39c2be 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -1170,10 +1170,16 @@ static u32 sde_rotator_calc_buf_bw(struct sde_mdp_format_params *fmt,
u32 bw;
bw = width * height * frame_rate;
- if (fmt->chroma_sample == SDE_MDP_CHROMA_420)
+
+ if (sde_mdp_is_tp10_format(fmt))
+ bw *= 2;
+ else if (sde_mdp_is_p010_format(fmt))
+ bw *= 3;
+ else if (fmt->chroma_sample == SDE_MDP_CHROMA_420)
bw = (bw * 3) / 2;
else
bw *= fmt->bpp;
+ SDEROT_EVTLOG(bw, width, height, frame_rate, fmt->format);
return bw;
}
@@ -1818,6 +1824,17 @@ static int sde_rotator_validate_entry(struct sde_rot_mgr *mgr,
int ret;
struct sde_rotation_item *item;
struct sde_rot_perf *perf;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+
+ /* Check to ensure handoff is completed before 1st rotation request */
+ if (!mdata->handoff_done && mdata->handoff_pending) {
+ mdata->handoff_done = !mdata->handoff_pending();
+ if (!mdata->handoff_done) {
+ SDEROT_INFO(
+ "Splash Still on, Reject Rotation Request\n");
+ return -EINVAL;
+ }
+ }
item = &entry->item;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
index 23548b99fce4..bdd16a93bbb1 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 2015-2017, 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
@@ -124,10 +124,34 @@ static inline bool sde_mdp_is_linear_format(struct sde_mdp_format_params *fmt)
return fmt && (fmt->frame_format == SDE_MDP_FMT_LINEAR);
}
+static inline bool sde_mdp_is_nv12_format(struct sde_mdp_format_params *fmt)
+{
+ return fmt && (fmt->fetch_planes == SDE_MDP_PLANE_PSEUDO_PLANAR) &&
+ (fmt->chroma_sample == SDE_MDP_CHROMA_420);
+}
+
+static inline bool sde_mdp_is_nv12_8b_format(struct sde_mdp_format_params *fmt)
+{
+ return fmt && sde_mdp_is_nv12_format(fmt) &&
+ (fmt->pixel_mode == SDE_MDP_PIXEL_NORMAL);
+}
+
+static inline bool sde_mdp_is_nv12_10b_format(struct sde_mdp_format_params *fmt)
+{
+ return fmt && sde_mdp_is_nv12_format(fmt) &&
+ (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT);
+}
+
static inline bool sde_mdp_is_tp10_format(struct sde_mdp_format_params *fmt)
{
- return fmt && ((fmt->format == SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC) ||
- (fmt->format == SDE_PIX_FMT_Y_CBCR_H2V2_TP10));
+ return fmt && sde_mdp_is_nv12_10b_format(fmt) &&
+ fmt->unpack_tight;
+}
+
+static inline bool sde_mdp_is_p010_format(struct sde_mdp_format_params *fmt)
+{
+ return fmt && sde_mdp_is_nv12_10b_format(fmt) &&
+ !fmt->unpack_tight;
}
static inline bool sde_mdp_is_yuv_format(struct sde_mdp_format_params *fmt)
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
index 051db7863c54..8a8711ea468b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -65,6 +65,8 @@
#define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF2 0x00C8
#define MMSS_VBIF_NRT_VBIF_OUT_RD_LIM_CONF0 0x00D0
#define MMSS_VBIF_NRT_VBIF_OUT_WR_LIM_CONF0 0x00D4
+#define MDSS_VBIF_QOS_RP_REMAP_BASE 0x550
+#define MDSS_VBIF_QOS_LVL_REMAP_BASE 0x570
#define SDE_MDP_REG_TRAFFIC_SHAPER_EN BIT(31)
#define SDE_MDP_REG_TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4))
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index d7fb167ab49f..89fde987d4c1 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -42,9 +42,6 @@
#define TRAFFIC_SHAPE_CLKTICK_14MS 268800
#define TRAFFIC_SHAPE_CLKTICK_12MS 230400
-/* XIN mapping */
-#define XIN_SSPP 0
-#define XIN_WRITEBACK 1
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KOFF_TIMEOUT msecs_to_jiffies(42 * 32)
@@ -1698,11 +1695,14 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
item->input.format, item->output.format,
entry->perf->config.frame_rate);
+ if (mdata->vbif_reg_lock)
+ mdata->vbif_reg_lock();
+
if (mdata->default_ot_rd_limit) {
struct sde_mdp_set_ot_params ot_params;
memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
- ot_params.xin_id = XIN_SSPP;
+ ot_params.xin_id = mdata->vbif_xin_id[XIN_SSPP];
ot_params.num = 0; /* not used */
ot_params.width = entry->perf->config.input.width;
ot_params.height = entry->perf->config.input.height;
@@ -1724,7 +1724,7 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
struct sde_mdp_set_ot_params ot_params;
memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params));
- ot_params.xin_id = XIN_WRITEBACK;
+ ot_params.xin_id = mdata->vbif_xin_id[XIN_WRITEBACK];
ot_params.num = 0; /* not used */
ot_params.width = entry->perf->config.input.width;
ot_params.height = entry->perf->config.input.height;
@@ -1745,36 +1745,67 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
if (test_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map)) {
u32 qos_lut = 0; /* low priority for nrt read client */
- trace_rot_perf_set_qos_luts(XIN_SSPP, sspp_cfg.fmt->format,
- qos_lut, sde_mdp_is_linear_format(sspp_cfg.fmt));
+ trace_rot_perf_set_qos_luts(mdata->vbif_xin_id[XIN_SSPP],
+ sspp_cfg.fmt->format, qos_lut,
+ sde_mdp_is_linear_format(sspp_cfg.fmt));
SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CREQ_LUT, qos_lut);
}
+ /* Set CDP control registers to 0 if CDP is disabled */
+ if (!test_bit(SDE_QOS_CDP, mdata->sde_qos_map)) {
+ SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CDP_CNTL, 0x0);
+ SDE_ROTREG_WRITE(rot->mdss_base, ROT_WB_CDP_CNTL, 0x0);
+ }
+
if (mdata->npriority_lvl > 0) {
- u32 mask, reg_val, i, vbif_qos;
+ u32 mask, reg_val, i, j, vbif_qos, reg_val_lvl, reg_high;
for (i = 0; i < mdata->npriority_lvl; i++) {
- reg_val = SDE_VBIF_READ(mdata,
- MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4);
- mask = 0x3 << (XIN_SSPP * 2);
- reg_val &= ~(mask);
- vbif_qos = mdata->vbif_nrt_qos[i];
- reg_val |= vbif_qos << (XIN_SSPP * 2);
- /* ensure write is issued after the read operation */
- mb();
- SDE_VBIF_WRITE(mdata,
- MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4,
- reg_val);
+
+ for (j = 0; j < mdata->nxid; j++) {
+ reg_high = ((mdata->vbif_xin_id[j] &
+ 0x8) >> 3) * 4 + (i * 8);
+
+ reg_val = SDE_VBIF_READ(mdata,
+ MDSS_VBIF_QOS_RP_REMAP_BASE + reg_high);
+ reg_val_lvl = SDE_VBIF_READ(mdata,
+ MDSS_VBIF_QOS_LVL_REMAP_BASE + reg_high);
+
+ mask = 0x3 << (mdata->vbif_xin_id[j] * 4);
+ vbif_qos = mdata->vbif_nrt_qos[i];
+
+ reg_val &= ~(mask);
+ reg_val |= vbif_qos <<
+ (mdata->vbif_xin_id[j] * 4);
+
+ reg_val_lvl &= ~(mask);
+ reg_val_lvl |= vbif_qos <<
+ (mdata->vbif_xin_id[j] * 4);
+
+ pr_debug("idx:%d xin:%d reg:0x%x val:0x%x lvl:0x%x\n",
+ i, mdata->vbif_xin_id[j],
+ reg_high, reg_val, reg_val_lvl);
+ SDE_VBIF_WRITE(mdata,
+ MDSS_VBIF_QOS_RP_REMAP_BASE +
+ reg_high, reg_val);
+ SDE_VBIF_WRITE(mdata,
+ MDSS_VBIF_QOS_LVL_REMAP_BASE +
+ reg_high, reg_val_lvl);
+ }
}
}
/* Enable write gather for writeback to remove write gaps, which
* may hang AXI/BIMC/SDE.
*/
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
- BIT(XIN_WRITEBACK));
+ if (!((mdata->mdss_version == MDSS_MDP_HW_REV_320) ||
+ (mdata->mdss_version == MDSS_MDP_HW_REV_330)))
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
+ BIT(mdata->vbif_xin_id[XIN_WRITEBACK]));
+ if (mdata->vbif_reg_unlock)
+ mdata->vbif_reg_unlock();
return 0;
}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
index 46001fa7b429..9b1175d8f4a6 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
@@ -381,8 +381,12 @@ static void sde_smmu_callback(struct mdss_smmu_intf *smmu)
/* Copy mmu device info into sde private structure */
mdata->iommu_ctrl = smmu->iommu_ctrl;
+ mdata->vbif_reg_lock = smmu->reg_lock;
+ mdata->vbif_reg_unlock = smmu->reg_unlock;
mdata->wait_for_transition = smmu->wait_for_transition;
mdata->secure_session_ctrl = smmu->secure_session_ctrl;
+ mdata->handoff_pending = smmu->handoff_pending;
+
if (smmu->is_secure) {
mdata->sde_smmu[SDE_IOMMU_DOMAIN_ROT_SECURE].dev = smmu->dev;
mdata->sde_smmu[SDE_IOMMU_DOMAIN_ROT_SECURE].domain =
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 44c5c08f074c..c9dfb52861bc 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -75,6 +75,14 @@ static int get_device_address(struct smem_client *smem_client,
goto mem_map_failed;
}
+ /* Check if the dmabuf size matches expected size */
+ if (buf->size < *buffer_size) {
+ rc = -EINVAL;
+ dprintk(VIDC_ERR,
+ "Size mismatch! Dmabuf size: %zu Expected Size: %lu",
+ buf->size, *buffer_size);
+ goto mem_buf_size_mismatch;
+ }
/* Prepare a dma buf for dma on the given device */
attach = dma_buf_attach(buf, cb->dev);
if (IS_ERR_OR_NULL(attach)) {
@@ -143,6 +151,7 @@ mem_map_sg_failed:
dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
mem_map_table_failed:
dma_buf_detach(buf, attach);
+mem_buf_size_mismatch:
mem_buf_attach_failed:
dma_buf_put(buf);
mem_map_failed:
@@ -193,12 +202,12 @@ static void put_device_address(struct smem_client *smem_client,
}
}
-static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 size,
struct msm_smem *mem, enum hal_buffer buffer_type)
{
struct ion_handle *hndl;
ion_phys_addr_t iova = 0;
- unsigned long buffer_size = 0;
+ unsigned long buffer_size = size;
int rc = 0;
unsigned long align = SZ_4K;
unsigned long ion_flags = 0;
@@ -207,10 +216,11 @@ static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
dprintk(VIDC_DBG, "%s ion handle: %pK\n", __func__, hndl);
if (IS_ERR_OR_NULL(hndl)) {
dprintk(VIDC_ERR, "Failed to get handle: %pK, %d, %d, %pK\n",
- client, fd, offset, hndl);
+ client, fd, size, hndl);
rc = -ENOMEM;
goto fail_import_fd;
}
+
mem->kvaddr = NULL;
rc = ion_handle_get_flags(client->clnt, hndl, &ion_flags);
if (rc) {
@@ -430,7 +440,7 @@ static void ion_delete_client(struct smem_client *client)
ion_client_destroy(client->clnt);
}
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 size,
enum hal_buffer buffer_type)
{
struct smem_client *client = clt;
@@ -447,7 +457,7 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
}
switch (client->mem_type) {
case SMEM_ION:
- rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
+ rc = ion_user_to_kernel(clt, fd, size, mem, buffer_type);
break;
default:
dprintk(VIDC_ERR, "Mem type not supported\n");
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index a20252f08f44..b7e2c297a1ad 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -704,7 +704,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12,
- .num_planes = 2,
.get_frame_size = get_frame_size_nv12,
.type = CAPTURE_PORT,
},
@@ -712,7 +711,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "UBWC YCbCr Semiplanar 4:2:0",
.description = "UBWC Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12_UBWC,
- .num_planes = 2,
.get_frame_size = get_frame_size_nv12_ubwc,
.type = CAPTURE_PORT,
},
@@ -720,7 +718,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "UBWC YCbCr Semiplanar 4:2:0 10bit",
.description = "UBWC Y/CbCr 4:2:0 10bit",
.fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
- .num_planes = 2,
.get_frame_size = get_frame_size_nv12_ubwc_10bit,
.type = CAPTURE_PORT,
},
@@ -728,7 +725,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "Mpeg4",
.description = "Mpeg4 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG4,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -736,7 +732,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "Mpeg2",
.description = "Mpeg2 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG2,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -744,7 +739,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "H263",
.description = "H263 compressed format",
.fourcc = V4L2_PIX_FMT_H263,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -752,7 +746,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "VC1",
.description = "VC-1 compressed format",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -760,7 +753,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "VC1 SP",
.description = "VC-1 compressed format G",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -768,7 +760,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "H264",
.description = "H264 compressed format",
.fourcc = V4L2_PIX_FMT_H264,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -776,7 +767,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "H264_MVC",
.description = "H264_MVC compressed format",
.fourcc = V4L2_PIX_FMT_H264_MVC,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -784,7 +774,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "HEVC",
.description = "HEVC compressed format",
.fourcc = V4L2_PIX_FMT_HEVC,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -792,7 +781,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "HEVC_HYBRID",
.description = "HEVC compressed format",
.fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -800,7 +788,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -808,7 +795,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "VP9",
.description = "VP9 compressed format",
.fourcc = V4L2_PIX_FMT_VP9,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed_full_yuv,
.type = OUTPUT_PORT,
},
@@ -816,7 +802,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "DIVX 311",
.description = "DIVX 311 compressed format",
.fourcc = V4L2_PIX_FMT_DIVX_311,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
@@ -824,7 +809,6 @@ struct msm_vidc_format vdec_formats[] = {
.name = "DIVX",
.description = "DIVX 4/5/6 compressed format",
.fourcc = V4L2_PIX_FMT_DIVX,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
}
@@ -896,10 +880,10 @@ int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+ if (b->length != inst->prop.num_planes[CAPTURE_PORT]) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, allocated: %d\n",
- inst->fmts[CAPTURE_PORT].num_planes,
+ inst->prop.num_planes[CAPTURE_PORT],
b->length);
rc = -EINVAL;
break;
@@ -975,10 +959,10 @@ int msm_vdec_release_buf(struct msm_vidc_inst *inst,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+ if (b->length != inst->prop.num_planes[CAPTURE_PORT]) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, to release: %d\n",
- inst->fmts[CAPTURE_PORT].num_planes, b->length);
+ inst->prop.num_planes[CAPTURE_PORT], b->length);
rc = -EINVAL;
break;
}
@@ -1090,6 +1074,7 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
struct hfi_device *hdev;
int rc = 0, i = 0, stride = 0, scanlines = 0, color_format = 0;
unsigned int *plane_sizes = NULL, extra_idx = 0;
+ int num_planes = 0;
if (!inst || !f || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR,
@@ -1106,7 +1091,9 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
return -ENOTSUPP;
f->fmt.pix_mp.pixelformat = fmt->fourcc;
- f->fmt.pix_mp.num_planes = fmt->num_planes;
+ f->fmt.pix_mp.num_planes = inst->prop.num_planes[fmt->type];
+ num_planes = inst->prop.num_planes[fmt->type];
+
if (inst->in_reconfig) {
inst->prop.height[OUTPUT_PORT] = inst->reconfig_height;
inst->prop.width[OUTPUT_PORT] = inst->reconfig_width;
@@ -1126,7 +1113,7 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
plane_sizes = &inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[0];
- for (i = 0; i < fmt->num_planes; ++i) {
+ for (i = 0; i < num_planes; ++i) {
if (!plane_sizes[i]) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
get_frame_size(inst, fmt, f->type, i);
@@ -1169,7 +1156,7 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
inst->prop.height[CAPTURE_PORT],
inst->prop.width[CAPTURE_PORT]);
- extra_idx = EXTRADATA_IDX(fmt->num_planes);
+ extra_idx = EXTRADATA_IDX(num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
VENUS_EXTRADATA_SIZE(
@@ -1177,7 +1164,7 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
inst->prop.width[CAPTURE_PORT]);
}
- for (i = 0; i < fmt->num_planes; ++i)
+ for (i = 0; i < num_planes; ++i)
inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
@@ -1276,7 +1263,7 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
inst->fmts[fmt->type].get_frame_size(0,
f->fmt.pix_mp.height, f->fmt.pix_mp.width);
- extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
+ extra_idx = EXTRADATA_IDX(inst->prop.num_planes[fmt->type]);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
VENUS_EXTRADATA_SIZE(
@@ -1284,8 +1271,8 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
inst->prop.width[CAPTURE_PORT]);
}
- f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
- for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+ f->fmt.pix_mp.num_planes = inst->prop.num_planes[fmt->type];
+ for (i = 0; i < inst->prop.num_planes[fmt->type]; ++i) {
inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
@@ -1346,14 +1333,14 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
max_input_size = get_frame_size(
-inst, &inst->fmts[fmt->type], f->type, 0);
+ inst, &inst->fmts[fmt->type], f->type, 0);
if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
!f->fmt.pix_mp.plane_fmt[0].sizeimage) {
f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
}
- f->fmt.pix_mp.num_planes = inst->fmts[fmt->type].num_planes;
- for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
+ f->fmt.pix_mp.num_planes = inst->prop.num_planes[fmt->type];
+ for (i = 0; i < inst->prop.num_planes[fmt->type]; ++i) {
inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
@@ -1467,7 +1454,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- *num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+ *num_planes = inst->prop.num_planes[OUTPUT_PORT];
if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
@@ -1480,7 +1467,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
- *num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+ *num_planes = inst->prop.num_planes[CAPTURE_PORT];
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to open instance\n");
@@ -1564,8 +1551,7 @@ static int msm_vdec_queue_setup(struct vb2_queue *q,
break;
}
- extra_idx =
- EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
+ extra_idx = EXTRADATA_IDX(*num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
sizes[extra_idx] =
VENUS_EXTRADATA_SIZE(
@@ -1944,8 +1930,14 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst)
}
inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+ inst->prop.num_planes[CAPTURE_PORT] = 2;
+ inst->fmts[CAPTURE_PORT] = vdec_formats[0];
+
inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+ inst->prop.num_planes[OUTPUT_PORT] = 1;
+ inst->fmts[OUTPUT_PORT] = vdec_formats[2];
+
inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
inst->capability.height.max = DEFAULT_HEIGHT;
inst->capability.width.min = MIN_SUPPORTED_WIDTH;
@@ -1958,10 +1950,6 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst)
inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = DEFAULT_FPS;
inst->operating_rate = 0;
- memcpy(&inst->fmts[OUTPUT_PORT], &vdec_formats[2],
- sizeof(struct msm_vidc_format));
- memcpy(&inst->fmts[CAPTURE_PORT], &vdec_formats[0],
- sizeof(struct msm_vidc_format));
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c909511db251..ce6736509d61 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1343,7 +1343,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12,
- .num_planes = 1,
.get_frame_size = get_frame_size_nv12,
.type = OUTPUT_PORT,
},
@@ -1351,7 +1350,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "UBWC YCbCr Semiplanar 4:2:0",
.description = "UBWC Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12_UBWC,
- .num_planes = 1,
.get_frame_size = get_frame_size_nv12_ubwc,
.type = OUTPUT_PORT,
},
@@ -1359,7 +1357,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "RGBA 8:8:8:8",
.description = "RGBA 8:8:8:8",
.fourcc = V4L2_PIX_FMT_RGB32,
- .num_planes = 1,
.get_frame_size = get_frame_size_rgba,
.type = OUTPUT_PORT,
},
@@ -1367,7 +1364,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "UBWC RGBA 8:8:8:8",
.description = "UBWC RGBA 8:8:8:8",
.fourcc = V4L2_PIX_FMT_RGBA8888_UBWC,
- .num_planes = 1,
.get_frame_size = get_frame_size_rgba_ubwc,
.type = OUTPUT_PORT,
},
@@ -1375,7 +1371,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "Mpeg4",
.description = "Mpeg4 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG4,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -1383,7 +1378,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "H263",
.description = "H263 compressed format",
.fourcc = V4L2_PIX_FMT_H263,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -1391,7 +1385,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "H264",
.description = "H264 compressed format",
.fourcc = V4L2_PIX_FMT_H264,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -1399,7 +1392,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -1407,7 +1399,6 @@ static struct msm_vidc_format venc_formats[] = {
.name = "HEVC",
.description = "HEVC compressed format",
.fourcc = V4L2_PIX_FMT_HEVC,
- .num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = CAPTURE_PORT,
},
@@ -1415,57 +1406,71 @@ static struct msm_vidc_format venc_formats[] = {
.name = "YCrCb Semiplanar 4:2:0",
.description = "Y/CrCb 4:2:0",
.fourcc = V4L2_PIX_FMT_NV21,
- .num_planes = 1,
.get_frame_size = get_frame_size_nv21,
.type = OUTPUT_PORT,
},
};
-static void msm_venc_update_plane_count(struct msm_vidc_inst *inst, int type)
+static int msm_venc_set_csc(struct msm_vidc_inst *inst)
{
- struct v4l2_ctrl *ctrl = NULL;
- u32 extradata = 0;
+ int rc = 0;
+ int count = 0;
+ struct hal_vpe_color_space_conversion vpe_csc;
- if (!inst)
- return;
+ while (count < HAL_MAX_MATRIX_COEFFS) {
+ if (count < HAL_MAX_BIAS_COEFFS)
+ vpe_csc.csc_bias[count] =
+ vpe_csc_601_to_709_bias_coeff[count];
+ if (count < HAL_MAX_LIMIT_COEFFS)
+ vpe_csc.csc_limit[count] =
+ vpe_csc_601_to_709_limit_coeff[count];
+ vpe_csc.csc_matrix[count] =
+ vpe_csc_601_to_709_matrix_coeff[count];
+ count = count + 1;
+ }
+ rc = msm_comm_try_set_prop(inst,
+ HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc);
+ if (rc)
+ dprintk(VIDC_ERR, "Setting VPE coefficients failed\n");
- inst->fmts[type].num_planes = 1;
+ return rc;
+}
- ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
- V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA);
+static void msm_venc_register_extradata(
+ struct msm_vidc_inst *inst, u32 extradata) {
+ struct session_prop *prop = NULL;
- if (ctrl)
- extradata = v4l2_ctrl_g_ctrl(ctrl);
+ if (!inst)
+ return;
- if (type == CAPTURE_PORT) {
- switch (extradata) {
+ prop = &inst->prop;
+ switch (extradata) {
case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO:
case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB:
case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER:
case V4L2_MPEG_VIDC_EXTRADATA_LTR:
case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI:
- inst->fmts[CAPTURE_PORT].num_planes = 2;
- default:
+ prop->extradata[CAPTURE_PORT] |= extradata;
+ prop->num_planes[CAPTURE_PORT] = 2;
+ dprintk(VIDC_DBG, "Output Extradata: %#x",
+ prop->extradata[CAPTURE_PORT]);
break;
- }
- } else if (type == OUTPUT_PORT) {
- switch (extradata) {
case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP:
case V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM:
case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO:
case V4L2_MPEG_VIDC_EXTRADATA_YUV_STATS:
case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP:
case V4L2_MPEG_VIDC_EXTRADATA_PQ_INFO:
- inst->fmts[OUTPUT_PORT].num_planes = 2;
+ prop->extradata[OUTPUT_PORT] |= extradata;
+ prop->num_planes[OUTPUT_PORT] = 2;
+ dprintk(VIDC_DBG, "Input Extradata: %#x",
+ prop->extradata[OUTPUT_PORT]);
break;
default:
- break;
- }
+ dprintk(VIDC_ERR, "Unknown extradata: %d", extradata);
}
}
-static int msm_venc_set_csc(struct msm_vidc_inst *inst);
-
static int msm_venc_queue_setup(struct vb2_queue *q,
const void *parg,
unsigned int *num_buffers,
@@ -1508,7 +1513,7 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- *num_planes = 1;
+ *num_planes = inst->prop.num_planes[CAPTURE_PORT];
buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
if (buff_req) {
@@ -1534,9 +1539,6 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
temp, *num_buffers);
}
- msm_venc_update_plane_count(inst, CAPTURE_PORT);
- *num_planes = inst->fmts[CAPTURE_PORT].num_planes;
-
for (i = 0; i < *num_planes; i++) {
int extra_idx = EXTRADATA_IDX(*num_planes);
@@ -1571,7 +1573,7 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
- *num_planes = 1;
+ *num_planes = inst->prop.num_planes[OUTPUT_PORT];
*num_buffers = inst->buff_req.buffer[0].buffer_count_actual =
max(*num_buffers, inst->buff_req.buffer[0].
@@ -1593,9 +1595,6 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
dprintk(VIDC_DBG, "actual input buffer count set to fw = %d\n",
*num_buffers);
- msm_venc_update_plane_count(inst, OUTPUT_PORT);
- *num_planes = inst->fmts[OUTPUT_PORT].num_planes;
-
rc = call_hfi_op(hdev, session_set_property, inst->session,
property_id, &new_buf_count);
if (rc)
@@ -1610,7 +1609,7 @@ static int msm_venc_queue_setup(struct vb2_queue *q,
inst->prop.width[OUTPUT_PORT]);
extra_idx =
- EXTRADATA_IDX(inst->fmts[OUTPUT_PORT].num_planes);
+ EXTRADATA_IDX(*num_planes);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
buff_req_buffer = get_buff_req_buffer(inst,
HAL_BUFFER_EXTRADATA_INPUT);
@@ -2992,6 +2991,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
!!(inst->flags & VIDC_SECURE));
break;
case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
+ msm_venc_register_extradata(inst, (u32)ctrl->val);
property_id = HAL_PARAM_INDEX_EXTRADATA;
extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
extra.enable = 1;
@@ -3633,8 +3633,14 @@ int msm_venc_inst_init(struct msm_vidc_inst *inst)
}
inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
+ inst->prop.num_planes[CAPTURE_PORT] = 1;
+ inst->fmts[CAPTURE_PORT] = venc_formats[4];
+
inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
+ inst->prop.num_planes[OUTPUT_PORT] = 1;
+ inst->fmts[OUTPUT_PORT] = venc_formats[0];
+
inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
inst->capability.height.max = DEFAULT_HEIGHT;
inst->capability.width.min = MIN_SUPPORTED_WIDTH;
@@ -3648,10 +3654,6 @@ int msm_venc_inst_init(struct msm_vidc_inst *inst)
inst->prop.fps = DEFAULT_FPS;
inst->capability.pixelprocess_capabilities = 0;
inst->operating_rate = 0;
- memcpy(&inst->fmts[CAPTURE_PORT], &venc_formats[4],
- sizeof(struct msm_vidc_format));
- memcpy(&inst->fmts[OUTPUT_PORT], &venc_formats[0],
- sizeof(struct msm_vidc_format));
return rc;
}
@@ -3720,37 +3722,13 @@ int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
return rc;
}
-static int msm_venc_set_csc(struct msm_vidc_inst *inst)
-{
- int rc = 0;
- int count = 0;
- struct hal_vpe_color_space_conversion vpe_csc;
-
- while (count < HAL_MAX_MATRIX_COEFFS) {
- if (count < HAL_MAX_BIAS_COEFFS)
- vpe_csc.csc_bias[count] =
- vpe_csc_601_to_709_bias_coeff[count];
- if (count < HAL_MAX_LIMIT_COEFFS)
- vpe_csc.csc_limit[count] =
- vpe_csc_601_to_709_limit_coeff[count];
- vpe_csc.csc_matrix[count] =
- vpe_csc_601_to_709_matrix_coeff[count];
- count = count + 1;
- }
- rc = msm_comm_try_set_prop(inst,
- HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc);
- if (rc)
- dprintk(VIDC_ERR, "Setting VPE coefficients failed\n");
-
- return rc;
-}
-
int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
struct msm_vidc_format *fmt = NULL;
int rc = 0;
- int i;
+ int extra_idx = 0;
struct hfi_device *hdev;
+
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %pK, format = %pK\n", inst, f);
@@ -3777,9 +3755,7 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
memcpy(&inst->fmts[fmt->type], fmt,
sizeof(struct msm_vidc_format));
-
- msm_venc_update_plane_count(inst, CAPTURE_PORT);
- fmt->num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+ f->fmt.pix_mp.num_planes = inst->prop.num_planes[CAPTURE_PORT];
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
@@ -3833,10 +3809,7 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
}
memcpy(&inst->fmts[fmt->type], fmt,
sizeof(struct msm_vidc_format));
-
- msm_venc_update_plane_count(inst, OUTPUT_PORT);
- fmt->num_planes = inst->fmts[OUTPUT_PORT].num_planes;
-
+ f->fmt.pix_mp.num_planes = inst->prop.num_planes[OUTPUT_PORT];
msm_comm_set_color_format(inst, HAL_BUFFER_INPUT, fmt->fourcc);
} else {
dprintk(VIDC_ERR, "%s - Unsupported buf type: %d\n",
@@ -3845,8 +3818,6 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
goto exit;
}
- f->fmt.pix_mp.num_planes = fmt->num_planes;
-
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
struct hal_frame_size frame_sz = {0};
struct hal_buffer_requirements *bufreq = NULL;
@@ -3872,16 +3843,23 @@ int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
f->fmt.pix_mp.plane_fmt[0].sizeimage =
bufreq ? bufreq->buffer_size : 0;
+
+ extra_idx = EXTRADATA_IDX(inst->prop.num_planes[fmt->type]);
+ if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_EXTRADATA_OUTPUT);
+ f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
+ bufreq ? bufreq->buffer_size : 0;
+ }
+
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
struct hal_buffer_requirements *bufreq = NULL;
- int extra_idx = 0;
- for (i = 0; i < inst->fmts[fmt->type].num_planes; ++i) {
- f->fmt.pix_mp.plane_fmt[i].sizeimage =
- inst->fmts[fmt->type].get_frame_size(i,
- f->fmt.pix_mp.height, f->fmt.pix_mp.width);
- }
- extra_idx = EXTRADATA_IDX(inst->fmts[fmt->type].num_planes);
+ f->fmt.pix_mp.plane_fmt[0].sizeimage =
+ inst->fmts[fmt->type].get_frame_size(0,
+ f->fmt.pix_mp.height, f->fmt.pix_mp.width);
+
+ extra_idx = EXTRADATA_IDX(inst->prop.num_planes[fmt->type]);
if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) {
bufreq = get_buff_req_buffer(inst,
HAL_BUFFER_EXTRADATA_INPUT);
@@ -3919,14 +3897,12 @@ int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
fmt = &inst->fmts[CAPTURE_PORT];
height = inst->prop.height[CAPTURE_PORT];
width = inst->prop.width[CAPTURE_PORT];
- msm_venc_update_plane_count(inst, CAPTURE_PORT);
- num_planes = inst->fmts[CAPTURE_PORT].num_planes;
+ num_planes = inst->prop.num_planes[CAPTURE_PORT];
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
fmt = &inst->fmts[OUTPUT_PORT];
height = inst->prop.height[OUTPUT_PORT];
width = inst->prop.width[OUTPUT_PORT];
- msm_venc_update_plane_count(inst, OUTPUT_PORT);
- num_planes = inst->fmts[OUTPUT_PORT].num_planes;
+ num_planes = inst->prop.num_planes[OUTPUT_PORT];
} else {
dprintk(VIDC_ERR, "Invalid type: %x\n", f->type);
return -ENOTSUPP;
@@ -4027,10 +4003,10 @@ int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
- if (b->length != inst->fmts[CAPTURE_PORT].num_planes) {
+ if (b->length != inst->prop.num_planes[CAPTURE_PORT]) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, allocated: %d\n",
- inst->fmts[CAPTURE_PORT].num_planes,
+ inst->prop.num_planes[CAPTURE_PORT],
b->length);
rc = -EINVAL;
break;
@@ -4098,10 +4074,10 @@ int msm_venc_release_buf(struct msm_vidc_inst *inst,
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
if (b->length !=
- inst->fmts[CAPTURE_PORT].num_planes) {
+ inst->prop.num_planes[CAPTURE_PORT]) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, to release: %d\n",
- inst->fmts[CAPTURE_PORT].num_planes,
+ inst->prop.num_planes[CAPTURE_PORT],
b->length);
rc = -EINVAL;
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 662dcf7c8303..ec3246ed9d67 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -364,7 +364,7 @@ static struct msm_smem *map_buffer(struct msm_vidc_inst *inst,
struct msm_smem *handle = NULL;
handle = msm_comm_smem_user_to_kernel(inst,
p->reserved[0],
- p->reserved[1],
+ p->length,
buffer_type);
if (!handle) {
dprintk(VIDC_ERR,
@@ -433,8 +433,10 @@ int map_and_register_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
goto exit;
}
- dprintk(VIDC_DBG, "[MAP] Create binfo = %pK fd = %d type = %d\n",
- binfo, b->m.planes[0].reserved[0], b->type);
+ dprintk(VIDC_DBG,
+ "[MAP] Create binfo = %pK fd = %d size = %d type = %d\n",
+ binfo, b->m.planes[0].reserved[0],
+ b->m.planes[0].length, b->type);
for (i = 0; i < b->length; ++i) {
rc = 0;
@@ -686,7 +688,7 @@ static bool valid_v4l2_buffer(struct v4l2_buffer *b,
MAX_PORT_NUM;
return port != MAX_PORT_NUM &&
- inst->fmts[port].num_planes == b->length;
+ inst->prop.num_planes[port] == b->length;
}
int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
@@ -1317,9 +1319,6 @@ static void cleanup_instance(struct msm_vidc_inst *inst)
"Failed to release output buffers\n");
}
- if (inst->extradata_handle)
- msm_comm_smem_free(inst, inst->extradata_handle);
-
debugfs_remove_recursive(inst->debugfs_root);
mutex_lock(&inst->pending_getpropq.lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 50ea4a200dfa..2aebc62d09d5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -898,12 +898,12 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
if (!rc) {
dprintk(VIDC_ERR, "Wait interrupted or timed out: %d\n",
SESSION_MSG_INDEX(cmd));
- msm_comm_kill_session(inst);
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
dprintk(VIDC_ERR,
"sess resp timeout can potentially crash the system\n");
msm_comm_print_debug_info(inst);
BUG_ON(inst->core->resources.debug_timeout);
+ msm_comm_kill_session(inst);
rc = -EIO;
} else {
rc = 0;
@@ -1087,8 +1087,7 @@ static void handle_event_change(enum hal_command_response cmd, void *data)
rc = msm_comm_g_ctrl_for_id(inst,
V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER);
- if ((!IS_ERR_VALUE(rc) && rc == true) ||
- is_thumbnail_session(inst)) {
+ if (!IS_ERR_VALUE(rc) && rc == true) {
event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
if (msm_comm_get_stream_output_mode(inst) ==
@@ -1217,7 +1216,8 @@ static void handle_event_change(enum hal_command_response cmd, void *data)
"V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT due to bit-depth change\n");
}
- if (inst->pic_struct != event_notify->pic_struct) {
+ if (inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_NV12 &&
+ inst->pic_struct != event_notify->pic_struct) {
inst->pic_struct = event_notify->pic_struct;
event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
ptr[2] |= V4L2_EVENT_PICSTRUCT_FLAG;
@@ -1693,19 +1693,11 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
dprintk(VIDC_ERR,
"SYS_ERROR can potentially crash the system\n");
- /*
- * For SYS_ERROR, there will not be any inst pointer.
- * Just grab one of the inst from instances list and
- * use it.
- */
-
mutex_lock(&core->lock);
- inst = list_first_entry_or_null(&core->instances,
- struct msm_vidc_inst, list);
+ list_for_each_entry(inst, &core->instances, list)
+ msm_comm_print_inst_info(inst);
mutex_unlock(&core->lock);
- msm_comm_print_debug_info(inst);
-
BUG_ON(core->resources.debug_timeout);
}
@@ -2079,7 +2071,7 @@ static void handle_fbd(enum hal_command_response cmd, void *data)
ns_to_timeval(time_usec * NSEC_PER_USEC);
vbuf->flags = 0;
extra_idx =
- EXTRADATA_IDX(inst->fmts[CAPTURE_PORT].num_planes);
+ EXTRADATA_IDX(inst->prop.num_planes[CAPTURE_PORT]);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
vb->planes[extra_idx].m.userptr =
(unsigned long)fill_buf_done->extra_data_buffer;
@@ -3639,7 +3631,7 @@ static void populate_frame_data(struct vidc_frame_data *data,
data->buffer_type = msm_comm_get_hal_output_buffer(inst);
}
- extra_idx = EXTRADATA_IDX(inst->fmts[port].num_planes);
+ extra_idx = EXTRADATA_IDX(inst->prop.num_planes[port]);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
vb->planes[extra_idx].m.userptr) {
data->extradata_addr = vb->planes[extra_idx].m.userptr;
@@ -4065,7 +4057,6 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
__func__, inst,
SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO));
inst->state = MSM_VIDC_CORE_INVALID;
- msm_comm_kill_session(inst);
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
dprintk(VIDC_ERR,
"SESS_PROP timeout can potentially crash the system\n");
@@ -4073,6 +4064,7 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
msm_comm_print_debug_info(inst);
BUG_ON(inst->core->resources.debug_timeout);
+ msm_comm_kill_session(inst);
rc = -ETIMEDOUT;
goto exit;
} else {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 2e1df75cb248..1248a1c08103 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -290,7 +290,7 @@ static ssize_t inst_info_read(struct file *file, char __user *buf,
write_str(&dbg_buf, "capability: %s\n", i == OUTPUT_PORT ?
"Output" : "Capture");
write_str(&dbg_buf, "name : %s\n", inst->fmts[i].name);
- write_str(&dbg_buf, "planes : %d\n", inst->fmts[i].num_planes);
+ write_str(&dbg_buf, "planes : %d\n", inst->prop.num_planes[i]);
write_str(
&dbg_buf, "type: %s\n", inst->fmts[i].type == OUTPUT_PORT ?
"Output" : "Capture");
@@ -311,7 +311,7 @@ static ssize_t inst_info_read(struct file *file, char __user *buf,
write_str(&dbg_buf, "count: %u\n",
inst->bufq[i].vb2_bufq.num_buffers);
- for (j = 0; j < inst->fmts[i].num_planes; j++)
+ for (j = 0; j < inst->prop.num_planes[i]; j++)
write_str(&dbg_buf, "size for plane %d: %u\n", j,
inst->bufq[i].vb2_bufq.plane_sizes[j]);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 3ad85f53a8b0..690a61f4824f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -143,7 +143,6 @@ struct msm_vidc_format {
char name[MAX_NAME_LENGTH];
u8 description[32];
u32 fourcc;
- int num_planes;
int type;
u32 (*get_frame_size)(int plane, u32 height, u32 width);
};
@@ -165,6 +164,8 @@ struct msm_video_device {
struct session_prop {
u32 width[MAX_PORT_NUM];
u32 height[MAX_PORT_NUM];
+ u32 num_planes[MAX_PORT_NUM];
+ u32 extradata[MAX_PORT_NUM];
u32 fps;
u32 bitrate;
};
@@ -276,7 +277,6 @@ struct msm_vidc_inst {
struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
struct v4l2_ctrl **cluster;
struct v4l2_fh event_handler;
- struct msm_smem *extradata_handle;
bool in_reconfig;
u32 reconfig_width;
u32 reconfig_height;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index d3b41331faec..134995c9cd3c 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -562,7 +562,6 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
case QSEOS_REGISTER_LISTENER: {
struct qseecom_register_listener_ireq *req;
struct qseecom_register_listener_64bit_ireq *req_64bit;
- smc_id = TZ_OS_REGISTER_LISTENER_ID;
desc.arginfo =
TZ_OS_REGISTER_LISTENER_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -579,8 +578,15 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[1] = req_64bit->sb_ptr;
desc.args[2] = req_64bit->sb_len;
}
+ smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
ret = scm_call2(smc_id, &desc);
+ if (ret) {
+ smc_id = TZ_OS_REGISTER_LISTENER_ID;
+ __qseecom_reentrancy_check_if_no_app_blocked(
+ smc_id);
+ ret = scm_call2(smc_id, &desc);
+ }
break;
}
case QSEOS_DEREGISTER_LISTENER: {
diff --git a/drivers/net/ethernet/msm/msm_rmnet_mhi.c b/drivers/net/ethernet/msm/msm_rmnet_mhi.c
index ecdb806a2ae2..a55a26be4273 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_mhi.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_mhi.c
@@ -915,6 +915,7 @@ static void rmnet_mhi_cb(struct mhi_cb_info *cb_info)
} else {
rmnet_log(MSG_CRITICAL,
"Invalid data in MHI callback, quitting\n");
+ return;
}
switch (cb_info->cb_reason) {
diff --git a/drivers/net/ethernet/msm/rndis_ipa.c b/drivers/net/ethernet/msm/rndis_ipa.c
index 78ec72dd3442..683f364ed27b 100644
--- a/drivers/net/ethernet/msm/rndis_ipa.c
+++ b/drivers/net/ethernet/msm/rndis_ipa.c
@@ -170,6 +170,7 @@ enum rndis_ipa_operation {
* This callback shall be called by the Netdev once the Netdev internal
* state is changed to RNDIS_IPA_CONNECTED_AND_UP
* @xmit_error_delayed_work: work item for cases where IPA driver Tx fails
+ * @state_lock: used to protect the state variable.
*/
struct rndis_ipa_dev {
struct net_device *net;
@@ -197,6 +198,7 @@ struct rndis_ipa_dev {
u8 device_ethaddr[ETH_ALEN];
void (*device_ready_notify)(void);
struct delayed_work xmit_error_delayed_work;
+ spinlock_t state_lock; /* Spinlock for the state variable.*/
};
/**
@@ -504,6 +506,8 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
memset(rndis_ipa_ctx, 0, sizeof(*rndis_ipa_ctx));
RNDIS_IPA_DEBUG("rndis_ipa_ctx (private)=%p\n", rndis_ipa_ctx);
+ spin_lock_init(&rndis_ipa_ctx->state_lock);
+
rndis_ipa_ctx->net = net;
rndis_ipa_ctx->tx_filter = false;
rndis_ipa_ctx->rx_filter = false;
@@ -643,6 +647,7 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
struct rndis_ipa_dev *rndis_ipa_ctx = private;
int next_state;
int result;
+ unsigned long flags;
RNDIS_IPA_LOG_ENTRY();
@@ -656,12 +661,15 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
RNDIS_IPA_DEBUG("max_xfer_sz_to_host=%d\n",
max_xfer_size_bytes_to_host);
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_CONNECT);
if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
return -EPERM;
}
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
if (usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
RNDIS_IPA_ERROR("usb_to_ipa_hdl(%d) - not valid ipa handle\n",
@@ -710,7 +718,17 @@ int rndis_ipa_pipe_connect_notify(u32 usb_to_ipa_hdl,
}
RNDIS_IPA_DEBUG("netif_carrier_on() was called\n");
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
+ next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
+ RNDIS_IPA_CONNECT);
+ if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+ RNDIS_IPA_ERROR("use init()/disconnect() before connect()\n");
+ return -EPERM;
+ }
rndis_ipa_ctx->state = next_state;
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
if (next_state == RNDIS_IPA_CONNECTED_AND_UP)
@@ -747,18 +765,25 @@ static int rndis_ipa_open(struct net_device *net)
{
struct rndis_ipa_dev *rndis_ipa_ctx;
int next_state;
+ unsigned long flags;
RNDIS_IPA_LOG_ENTRY();
rndis_ipa_ctx = netdev_priv(net);
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
+
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_OPEN);
if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("can't bring driver up before initialize\n");
return -EPERM;
}
rndis_ipa_ctx->state = next_state;
+
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
@@ -1091,19 +1116,26 @@ static int rndis_ipa_stop(struct net_device *net)
{
struct rndis_ipa_dev *rndis_ipa_ctx = netdev_priv(net);
int next_state;
+ unsigned long flags;
RNDIS_IPA_LOG_ENTRY();
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
+
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state, RNDIS_IPA_STOP);
if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_DEBUG("can't do network interface down without up\n");
return -EPERM;
}
+ rndis_ipa_ctx->state = next_state;
+
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+
netif_stop_queue(net);
pr_info("RNDIS_IPA NetDev queue is stopped\n");
- rndis_ipa_ctx->state = next_state;
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
RNDIS_IPA_LOG_EXIT();
@@ -1132,18 +1164,23 @@ int rndis_ipa_pipe_disconnect_notify(void *private)
int next_state;
int outstanding_dropped_pkts;
int retval;
+ unsigned long flags;
RNDIS_IPA_LOG_ENTRY();
NULL_CHECK_RETVAL(rndis_ipa_ctx);
RNDIS_IPA_DEBUG("private=0x%p\n", private);
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
+
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_DISCONNECT);
if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("can't disconnect before connect\n");
return -EPERM;
}
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
if (rndis_ipa_ctx->during_xmit_error) {
RNDIS_IPA_DEBUG("canceling xmit-error delayed work\n");
@@ -1171,7 +1208,17 @@ int rndis_ipa_pipe_disconnect_notify(void *private)
}
RNDIS_IPA_DEBUG("RM was successfully destroyed\n");
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
+ next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
+ RNDIS_IPA_DISCONNECT);
+ if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+ RNDIS_IPA_ERROR("can't disconnect before connect\n");
+ return -EPERM;
+ }
rndis_ipa_ctx->state = next_state;
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
pr_info("RNDIS_IPA NetDev pipes disconnected (%d outstanding clr)\n",
@@ -1210,6 +1257,7 @@ void rndis_ipa_cleanup(void *private)
struct rndis_ipa_dev *rndis_ipa_ctx = private;
int next_state;
int retval;
+ unsigned long flags;
RNDIS_IPA_LOG_ENTRY();
@@ -1220,12 +1268,16 @@ void rndis_ipa_cleanup(void *private)
return;
}
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
RNDIS_IPA_CLEANUP);
if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
RNDIS_IPA_ERROR("use disconnect()before clean()\n");
return;
}
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+
RNDIS_IPA_STATE_DEBUG(rndis_ipa_ctx);
retval = rndis_ipa_deregister_properties(rndis_ipa_ctx->net->name);
@@ -1248,7 +1300,16 @@ void rndis_ipa_cleanup(void *private)
unregister_netdev(rndis_ipa_ctx->net);
RNDIS_IPA_DEBUG("netdev unregistered\n");
+ spin_lock_irqsave(&rndis_ipa_ctx->state_lock, flags);
+ next_state = rndis_ipa_next_state(rndis_ipa_ctx->state,
+ RNDIS_IPA_CLEANUP);
+ if (next_state == RNDIS_IPA_INVALID) {
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
+ RNDIS_IPA_ERROR("use disconnect()before clean()\n");
+ return;
+ }
rndis_ipa_ctx->state = next_state;
+ spin_unlock_irqrestore(&rndis_ipa_ctx->state_lock, flags);
free_netdev(rndis_ipa_ctx->net);
pr_info("RNDIS_IPA NetDev was cleaned\n");
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 2da6589bf57e..0803a963da3c 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1302,7 +1302,7 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
if (!ar->is_bmi && QCA_REV_WCN3990(ar)) {
fw_file = &ar->normal_mode_fw.fw_file;
- fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_HL_1_0;
+ fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_TLV;
fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
return 0;
}
@@ -1588,16 +1588,6 @@ static void ath10k_core_restart(struct work_struct *work)
mutex_unlock(&ar->conf_mutex);
}
-/* WAR: WCN3990 fw loading is done by PIL, assign WMI/HTT version */
-static inline void init_fw_param(struct ath10k *ar,
- struct ath10k_fw_file *fw_file)
-{
- if (QCA_REV_WCN3990(ar)) {
- fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_HL_1_0;
- fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
- }
-}
-
static int ath10k_core_init_firmware_features(struct ath10k *ar)
{
struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;
@@ -1704,7 +1694,6 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
- case ATH10K_FW_WMI_OP_VERSION_HL_1_0:
ar->max_num_peers = TARGET_TLV_NUM_PEERS;
ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
@@ -1751,7 +1740,6 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
- case ATH10K_FW_WMI_OP_VERSION_HL_1_0:
fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
break;
case ATH10K_FW_WMI_OP_VERSION_10_4:
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 42e97d99a3d1..cbb61267eb10 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1734,7 +1734,8 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
spin_unlock_bh(&ar->data_lock);
}
-static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,
+static int ath10k_htt_rx_extract_amsdu(struct ath10k *ar,
+ struct sk_buff_head *list,
struct sk_buff_head *amsdu)
{
struct sk_buff *msdu;
@@ -1755,6 +1756,9 @@ static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,
break;
}
+ if (QCA_REV_WCN3990(ar))
+ return 0;
+
msdu = skb_peek_tail(amsdu);
rxd = (void *)msdu->data - sizeof(*rxd);
if (!(rxd->msdu_end.common.info0 &
@@ -1897,7 +1901,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
while (!skb_queue_empty(&list)) {
__skb_queue_head_init(&amsdu);
- ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu);
+ ret = ath10k_htt_rx_extract_amsdu(ar, &list, &amsdu);
switch (ret) {
case 0:
/* Note: The in-order indication may report interleaved
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 2e7d90ef53f2..b59bde40714c 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -188,7 +188,6 @@ enum ath10k_fw_wmi_op_version {
ATH10K_FW_WMI_OP_VERSION_TLV = 4,
ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5,
ATH10K_FW_WMI_OP_VERSION_10_4 = 6,
- ATH10K_FW_WMI_OP_VERSION_HL_1_0 = 7,
/* keep last */
ATH10K_FW_WMI_OP_VERSION_MAX,
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 2b372ae63b60..2e51590dacbb 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7959,7 +7959,6 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
case ATH10K_FW_WMI_OP_VERSION_TLV:
- case ATH10K_FW_WMI_OP_VERSION_HL_1_0:
if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
ar->hw->wiphy->iface_combinations =
ath10k_tlv_qcs_if_comb;
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index 6260f11d4e32..bb711b525af8 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -625,8 +625,10 @@ struct rx_msdu_end {
struct rx_msdu_end_common common;
union {
struct rx_msdu_end_qca99x0 qca99x0;
- struct rx_msdu_end_wcn3990 wcn3990;
} __packed;
+#ifdef CONFIG_ATH10K_SNOC
+ struct rx_msdu_end_wcn3990 wcn3990;
+#endif
} __packed;
/*
@@ -1123,7 +1125,6 @@ struct rx_ppdu_end_qca9984 {
struct rx_timing_offset {
__le32 timing_offset;
- __le32 reserved;
};
struct rx_ppdu_end_wcn3990 {
@@ -1147,7 +1148,9 @@ struct rx_ppdu_end {
struct rx_ppdu_end_qca6174 qca6174;
struct rx_ppdu_end_qca99x0 qca99x0;
struct rx_ppdu_end_qca9984 qca9984;
+#ifdef CONFIG_ATH10K_SNOC
struct rx_ppdu_end_wcn3990 wcn3990;
+#endif
} __packed;
} __packed;
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index 487c243e18ec..be8ec97574f0 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -48,8 +48,6 @@ const char *ce_name[WCN3990_MAX_IRQ] = {
#define SNOC_HIF_POWER_DOWN_DELAY 30
static void ath10k_snoc_buffer_cleanup(struct ath10k *ar);
-static int ath10k_snoc_init_irq(struct ath10k *ar);
-static int ath10k_snoc_deinit_irq(struct ath10k *ar);
static int ath10k_snoc_request_irq(struct ath10k *ar);
static void ath10k_snoc_free_irq(struct ath10k *ar);
static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
@@ -703,31 +701,6 @@ static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,
ath10k_ce_per_engine_service(ar, pipe);
}
-static void ath10k_snoc_kill_tasklet(struct ath10k *ar)
-{
- struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
- int i;
-
- for (i = 0; i < CE_COUNT; i++)
- tasklet_kill(&ar_snoc->pipe_info[i].intr);
-
- del_timer_sync(&ar_snoc->rx_post_retry);
-}
-
-static void ath10k_snoc_ce_deinit(struct ath10k *ar)
-{
- int i;
-
- for (i = 0; i < CE_COUNT; i++)
- ath10k_ce_deinit_pipe(ar, i);
-}
-
-static void ath10k_snoc_release_resource(struct ath10k *ar)
-{
- netif_napi_del(&ar->napi);
- ath10k_snoc_ce_deinit(ar);
-}
-
static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,
u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
@@ -862,6 +835,7 @@ static void ath10k_snoc_buffer_cleanup(struct ath10k *ar)
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
int pipe_num;
+ del_timer_sync(&ar_snoc->rx_post_retry);
for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
struct ath10k_snoc_pipe *pipe_info;
@@ -873,7 +847,6 @@ static void ath10k_snoc_buffer_cleanup(struct ath10k *ar)
static void ath10k_snoc_flush(struct ath10k *ar)
{
- ath10k_snoc_kill_tasklet(ar);
ath10k_snoc_buffer_cleanup(ar);
}
@@ -921,6 +894,12 @@ static void ath10k_snoc_free_pipes(struct ath10k *ar)
ath10k_ce_free_pipe(ar, i);
}
+static void ath10k_snoc_release_resource(struct ath10k *ar)
+{
+ netif_napi_del(&ar->napi);
+ ath10k_snoc_free_pipes(ar);
+}
+
static int ath10k_snoc_init_pipes(struct ath10k *ar)
{
int i, ret;
@@ -944,14 +923,6 @@ static void ath10k_snoc_hif_power_down(struct ath10k *ar)
icnss_wlan_disable(ICNSS_OFF);
}
-static void ath10k_snoc_ce_tasklet(unsigned long ptr)
-{
- struct ath10k_snoc_pipe *pipe = (struct ath10k_snoc_pipe *)ptr;
- struct ath10k_snoc *ar_snoc = pipe->ar_snoc;
-
- ath10k_ce_per_engine_service(ar_snoc->ar, pipe->pipe_num);
-}
-
int ath10k_snoc_get_ce_id(struct ath10k *ar, int irq)
{
int i;
@@ -1015,30 +986,6 @@ static void ath10k_snoc_free_irq(struct ath10k *ar)
free_irq(ar_snoc->ce_irqs[id], ar);
}
-static void ath10k_snoc_init_irq_tasklets(struct ath10k *ar)
-{
- struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
- int i;
-
- for (i = 0; i < CE_COUNT; i++) {
- ar_snoc->pipe_info[i].ar_snoc = ar_snoc;
- tasklet_init(&ar_snoc->pipe_info[i].intr,
- ath10k_snoc_ce_tasklet,
- (unsigned long)&ar_snoc->pipe_info[i]);
- }
-}
-
-static int ath10k_snoc_init_irq(struct ath10k *ar)
-{
- ath10k_snoc_init_irq_tasklets(ar);
- return 0;
-}
-
-static int ath10k_snoc_deinit_irq(struct ath10k *ar)
-{
- ath10k_snoc_irq_disable(ar);
- return 0;
-}
static int ath10k_snoc_get_soc_info(struct ath10k *ar)
{
@@ -1282,16 +1229,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll,
ATH10K_NAPI_BUDGET);
- ret = ath10k_snoc_init_irq(ar);
- if (ret) {
- ath10k_err(ar, "failed to init irqs: %d\n", ret);
- goto err_free_pipes;
- }
-
ret = ath10k_snoc_request_irq(ar);
if (ret) {
ath10k_warn(ar, "failed to request irqs: %d\n", ret);
- goto err_deinit_irq;
+ goto err_free_pipes;
}
chip_id = ar_snoc->target_info.soc_version;
@@ -1307,10 +1248,6 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
err_free_irq:
ath10k_snoc_free_irq(ar);
- ath10k_snoc_kill_tasklet(ar);
-
-err_deinit_irq:
- ath10k_snoc_deinit_irq(ar);
err_free_pipes:
ath10k_snoc_free_pipes(ar);
@@ -1334,8 +1271,6 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
ath10k_core_unregister(ar);
ath10k_snoc_free_irq(ar);
- ath10k_snoc_kill_tasklet(ar);
- ath10k_snoc_deinit_irq(ar);
ath10k_snoc_release_resource(ar);
ath10k_snoc_free_pipes(ar);
ath10k_core_destroy(ar);
@@ -1365,6 +1300,10 @@ static int __init ath10k_snoc_init(void)
{
int ret;
+ if (!icnss_is_fw_ready()) {
+ pr_err("failed to get fw ready indication\n");
+ return -EAGAIN;
+ }
ret = platform_driver_register(&ath10k_snoc_driver);
if (ret)
pr_err("failed to register ath10k snoc driver: %d\n",
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
index 7c8a3ca8fabf..1754a3e91a00 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -35,7 +35,6 @@ struct snoc_state {
* @buf_sz: buffer size
* @pipe_lock: pipe lock
* @ar_snoc: snoc private structure
- * @intr: tasklet structure
*/
struct ath10k_snoc_pipe {
@@ -46,7 +45,6 @@ struct ath10k_snoc_pipe {
/* protect ce info */
spinlock_t pipe_lock;
struct ath10k_snoc *ar_snoc;
- struct tasklet_struct intr;
};
/* struct ath10k_snoc_supp_chip: supported chip set
@@ -97,7 +95,6 @@ struct ath10k_target_info {
* @mem_pa: mem base physical address
* @target_info: snoc target info
* @mem_len: mempry map length
- * @intr_tq: rx tasklet handle
* @pipe_info: pipe info struct
* @ce_lock: protect ce structures
* @ce_states: maps ce id to ce state
@@ -112,7 +109,6 @@ struct ath10k_snoc {
dma_addr_t mem_pa;
struct ath10k_target_info target_info;
size_t mem_len;
- struct tasklet_struct intr_tq;
struct ath10k_snoc_pipe pipe_info[CE_COUNT_MAX];
/* protects CE info */
spinlock_t ce_lock;
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index de95e13a6036..3fef967ca1ad 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -3637,7 +3637,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
- /* .gen_mgmt_tx = not implemented; HTT is used */
+ .gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx,
.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
@@ -3663,6 +3663,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_tlv_op_gen_echo,
+ .gen_set_pdev_mac_addr = ath10k_wmi_tlv_op_gen_set_base_mac_addr,
};
static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
@@ -3683,81 +3684,6 @@ static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
.pmf = WMI_TLV_PEER_PMF,
};
-static const struct wmi_ops wmi_hl_1_0_ops = {
- .rx = ath10k_wmi_tlv_op_rx,
- .map_svc = wmi_hl_1_0_svc_map,
- .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev,
- .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev,
- .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev,
- .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,
- .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,
- .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev,
- .pull_phyerr_hdr = ath10k_wmi_tlv_op_pull_phyerr_ev_hdr,
- .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
- .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev,
- .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev,
- .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats,
- .pull_roam_ev = ath10k_wmi_tlv_op_pull_roam_ev,
- .pull_wow_event = ath10k_wmi_tlv_op_pull_wow_ev,
- .get_txbf_conf_scheme = ath10k_wmi_tlv_txbf_conf_scheme,
- .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend,
- .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume,
- .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd,
- .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param,
- .gen_init = ath10k_wmi_tlv_op_gen_init,
- .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan,
- .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan,
- .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create,
- .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete,
- .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start,
- .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop,
- .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up,
- .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down,
- .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param,
- .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key,
- .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf,
- .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create,
- .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete,
- .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush,
- .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param,
- .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc,
- .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode,
- .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps,
- .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps,
- .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list,
- .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma,
- .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
- .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
- .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
- .gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx,
- .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
- .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
- .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl,
- .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl,
- .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie,
- .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
- .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
- .gen_wow_enable = ath10k_wmi_tlv_op_gen_wow_enable,
- .gen_wow_add_wakeup_event = ath10k_wmi_tlv_op_gen_wow_add_wakeup_event,
- .gen_wow_host_wakeup_ind = ath10k_wmi_tlv_gen_wow_host_wakeup_ind,
- .gen_wow_add_pattern = ath10k_wmi_tlv_op_gen_wow_add_pattern,
- .gen_wow_del_pattern = ath10k_wmi_tlv_op_gen_wow_del_pattern,
- .gen_update_fw_tdls_state = ath10k_wmi_tlv_op_gen_update_fw_tdls_state,
- .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
- .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
- .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
- .gen_set_pdev_mac_addr = ath10k_wmi_tlv_op_gen_set_base_mac_addr,
-};
-
-void ath10k_wmi_hl_1_0_attach(struct ath10k *ar)
-{
- ar->wmi.cmd = &wmi_tlv_cmd_map;
- ar->wmi.vdev_param = &wmi_tlv_vdev_param_map;
- ar->wmi.pdev_param = &wmi_tlv_pdev_param_map;
- ar->wmi.ops = &wmi_hl_1_0_ops;
- ar->wmi.peer_flags = &wmi_tlv_peer_flags_map;
-}
-
/* TLV init */
/************/
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index 31f34b43e381..79f324f132e9 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -969,125 +969,50 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
WMI_TLV_SERVICE_MDNS_OFFLOAD,
WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
-};
-
-enum wmi_hl_10_service {
- WMI_HL_10_SERVICE_BEACON_OFFLOAD = 0,
- WMI_HL_10_SERVICE_SCAN_OFFLOAD,
- WMI_HL_10_SERVICE_ROAM_SCAN_OFFLOAD,
- WMI_HL_10_SERVICE_BCN_MISS_OFFLOAD,
- WMI_HL_10_SERVICE_STA_PWRSAVE,
- WMI_HL_10_SERVICE_STA_ADVANCED_PWRSAVE,
- WMI_HL_10_SERVICE_AP_UAPSD,
- WMI_HL_10_SERVICE_AP_DFS,
- WMI_HL_10_SERVICE_11AC,
- WMI_HL_10_SERVICE_BLOCKACK,
- WMI_HL_10_SERVICE_PHYERR,
- WMI_HL_10_SERVICE_BCN_FILTER,
- WMI_HL_10_SERVICE_RTT,
- WMI_HL_10_SERVICE_WOW,
- WMI_HL_10_SERVICE_RATECTRL_CACHE,
- WMI_HL_10_SERVICE_IRAM_TIDS,
- WMI_HL_10_SERVICE_ARPNS_OFFLOAD,
- WMI_HL_10_SERVICE_NLO,
- WMI_HL_10_SERVICE_GTK_OFFLOAD,
- WMI_HL_10_SERVICE_SCAN_SCH,
- WMI_HL_10_SERVICE_CSA_OFFLOAD,
- WMI_HL_10_SERVICE_CHATTER,
- WMI_HL_10_SERVICE_COEX_FREQAVOID,
- WMI_HL_10_SERVICE_PACKET_POWER_SAVE,
- WMI_HL_10_SERVICE_FORCE_FW_HANG,
- WMI_HL_10_SERVICE_GPIO,
- WMI_HL_10_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
- WMI_HL_10_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
- WMI_HL_10_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
- WMI_HL_10_SERVICE_STA_KEEP_ALIVE,
- WMI_HL_10_SERVICE_TX_ENCAP,
- WMI_HL_10_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
- WMI_HL_10_SERVICE_EARLY_RX,
- WMI_HL_10_SERVICE_STA_SMPS,
- WMI_HL_10_SERVICE_FWTEST,
- WMI_HL_10_SERVICE_STA_WMMAC,
- WMI_HL_10_SERVICE_TDLS,
- WMI_HL_10_SERVICE_BURST,
- WMI_HL_10_SERVICE_MCC_BCN_INTERVAL_CHANGE,
- WMI_HL_10_SERVICE_ADAPTIVE_OCS,
- WMI_HL_10_SERVICE_BA_SSN_SUPPORT,
- WMI_HL_10_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
- WMI_HL_10_SERVICE_WLAN_HB,
- WMI_HL_10_SERVICE_LTE_ANT_SHARE_SUPPORT,
- WMI_HL_10_SERVICE_BATCH_SCAN,
- WMI_HL_10_SERVICE_QPOWER,
- WMI_HL_10_SERVICE_PLMREQ,
- WMI_HL_10_SERVICE_THERMAL_MGMT,
- WMI_HL_10_SERVICE_RMC,
- WMI_HL_10_SERVICE_MHF_OFFLOAD,
- WMI_HL_10_SERVICE_COEX_SAR,
- WMI_HL_10_SERVICE_BCN_TXRATE_OVERRIDE,
- WMI_HL_10_SERVICE_NAN,
- WMI_HL_10_SERVICE_L1SS_STAT,
- WMI_HL_10_SERVICE_ESTIMATE_LINKSPEED,
- WMI_HL_10_SERVICE_OBSS_SCAN,
- WMI_HL_10_SERVICE_TDLS_OFFCHAN,
- WMI_HL_10_SERVICE_TDLS_UAPSD_BUFFER_STA,
- WMI_HL_10_SERVICE_TDLS_UAPSD_SLEEP_STA,
- WMI_HL_10_SERVICE_IBSS_PWRSAVE,
- WMI_HL_10_SERVICE_LPASS,
- WMI_HL_10_SERVICE_EXTSCAN,
- WMI_HL_10_SERVICE_D0WOW,
- WMI_HL_10_SERVICE_HSOFFLOAD,
- WMI_HL_10_SERVICE_ROAM_HO_OFFLOAD,
- WMI_HL_10_SERVICE_RX_FULL_REORDER,
- WMI_HL_10_SERVICE_DHCP_OFFLOAD,
- WMI_HL_10_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
- WMI_HL_10_SERVICE_MDNS_OFFLOAD,
- WMI_HL_10_SERVICE_SAP_AUTH_OFFLOAD,
- WMI_HL_10_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
- WMI_HL_10_SERVICE_OCB,
- WMI_HL_10_SERVICE_AP_ARPNS_OFFLOAD,
- WMI_HL_10_SERVICE_PER_BAND_CHAINMASK_SUPPORT,
- WMI_HL_10_SERVICE_PACKET_FILTER_OFFLOAD,
- WMI_HL_10_SERVICE_MGMT_TX_HTT,
- WMI_HL_10_SERVICE_MGMT_TX_WMI,
- WMI_HL_10_SERVICE_EXT_MSG,
- WMI_HL_10_SERVICE_MAWC,
- WMI_HL_10_SERVICE_PEER_ASSOC_CONF,
- WMI_HL_10_SERVICE_EGAP,
- WMI_HL_10_SERVICE_STA_PMF_OFFLOAD,
- WMI_HL_10_SERVICE_UNIFIED_WOW_CAPABILITY,
- WMI_HL_10_SERVICE_ENHANCED_PROXY_STA,
- WMI_HL_10_SERVICE_ATF,
- WMI_HL_10_SERVICE_COEX_GPIO,
- WMI_HL_10_SERVICE_AUX_SPECTRAL_INTF,
- WMI_HL_10_SERVICE_AUX_CHAN_LOAD_INTF,
- WMI_HL_10_SERVICE_BSS_CHANNEL_INFO_64,
- WMI_HL_10_SERVICE_ENTERPRISE_MESH,
- WMI_HL_10_SERVICE_RESTRT_CHNL_SUPPORT,
- WMI_HL_10_SERVICE_BPF_OFFLOAD,
- WMI_HL_10_SERVICE_SYNC_DELETE_CMDS,
- WMI_HL_10_SERVICE_SMART_ANTENNA_SW_SUPPORT,
- WMI_HL_10_SERVICE_SMART_ANTENNA_HW_SUPPORT,
- WMI_HL_10_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES,
- WMI_HL_10_SERVICE_NAN_DATA,
- WMI_HL_10_SERVICE_NAN_RTT,
- WMI_HL_10_SERVICE_11AX,
- WMI_HL_10_SERVICE_DEPRECATED_REPLACE,
- WMI_HL_10_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
- WMI_HL_10_SERVICE_ENHANCED_MCAST_FILTER,
- WMI_HL_10_SERVICE_PERIODIC_CHAN_STAT_SUPPORT,
- WMI_HL_10_SERVICE_MESH_11S,
- WMI_HL_10_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT,
- WMI_HL_10_SERVICE_VDEV_RX_FILTER,
- WMI_HL_10_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT,
- WMI_HL_10_SERVICE_MARK_FIRST_WAKEUP_PACKET,
- WMI_HL_10_SERVICE_MULTIPLE_MCAST_FILTER_SET,
- WMI_HL_10_SERVICE_HOST_MANAGED_RX_REORDER,
- WMI_HL_10_SERVICE_FLASH_RDWR_SUPPORT,
- WMI_HL_10_SERVICE_WLAN_STATS_REPORT,
- WMI_HL_10_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT,
- WMI_HL_10_SERVICE_DFS_PHYERR_OFFLOAD,
- WMI_HL_10_MAX_SERVICE = 128,
- WMI_HL_10_MAX_EXT_SERVICE
+ WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
+ WMI_TLV_SERVICE_OCB,
+ WMI_TLV_SERVICE_AP_ARPNS_OFFLOAD,
+ WMI_TLV_SERVICE_PER_BAND_CHAINMASK_SUPPORT,
+ WMI_TLV_SERVICE_PACKET_FILTER_OFFLOAD,
+ WMI_TLV_SERVICE_MGMT_TX_HTT,
+ WMI_TLV_SERVICE_MGMT_TX_WMI,
+ WMI_TLV_SERVICE_EXT_MSG,
+ WMI_TLV_SERVICE_MAWC,
+ WMI_TLV_SERVICE_PEER_ASSOC_CONF,
+ WMI_TLV_SERVICE_EGAP,
+ WMI_TLV_SERVICE_STA_PMF_OFFLOAD,
+ WMI_TLV_SERVICE_UNIFIED_WOW_CAPABILITY,
+ WMI_TLV_SERVICE_ENHANCED_PROXY_STA,
+ WMI_TLV_SERVICE_ATF,
+ WMI_TLV_SERVICE_COEX_GPIO,
+ WMI_TLV_SERVICE_AUX_SPECTRAL_INTF,
+ WMI_TLV_SERVICE_AUX_CHAN_LOAD_INTF,
+ WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64,
+ WMI_TLV_SERVICE_ENTERPRISE_MESH,
+ WMI_TLV_SERVICE_RESTRT_CHNL_SUPPORT,
+ WMI_TLV_SERVICE_BPF_OFFLOAD,
+ WMI_TLV_SERVICE_SYNC_DELETE_CMDS,
+ WMI_TLV_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+ WMI_TLV_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+ WMI_TLV_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES,
+ WMI_TLV_SERVICE_NAN_DATA,
+ WMI_TLV_SERVICE_NAN_RTT,
+ WMI_TLV_SERVICE_11AX,
+ WMI_TLV_SERVICE_DEPRECATED_REPLACE,
+ WMI_TLV_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
+ WMI_TLV_SERVICE_ENHANCED_MCAST_FILTER,
+ WMI_TLV_SERVICE_PERIODIC_CHAN_STAT_SUPPORT,
+ WMI_TLV_SERVICE_MESH_11S,
+ WMI_TLV_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT,
+ WMI_TLV_SERVICE_VDEV_RX_FILTER,
+ WMI_TLV_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT,
+ WMI_TLV_SERVICE_MARK_FIRST_WAKEUP_PACKET,
+ WMI_TLV_SERVICE_MULTIPLE_MCAST_FILTER_SET,
+ WMI_TLV_SERVICE_HOST_MANAGED_RX_REORDER,
+ WMI_TLV_SERVICE_FLASH_RDWR_SUPPORT,
+ WMI_TLV_SERVICE_WLAN_STATS_REPORT,
+ WMI_TLV_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT,
+ WMI_TLV_SERVICE_DFS_PHYERR_OFFLOAD,
};
#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
@@ -1102,65 +1027,6 @@ enum wmi_hl_10_service {
} while (0)
static inline void
-wmi_hl_1_0_svc_map(const __le32 *in, unsigned long *out, size_t len)
-{
- SVCMAP(WMI_HL_10_SERVICE_BEACON_OFFLOAD,
- WMI_SERVICE_BEACON_OFFLOAD, len);
- SVCMAP(WMI_HL_10_SERVICE_SCAN_OFFLOAD,
- WMI_SERVICE_SCAN_OFFLOAD, len);
- SVCMAP(WMI_HL_10_SERVICE_ROAM_SCAN_OFFLOAD,
- WMI_SERVICE_ROAM_SCAN_OFFLOAD, len);
- SVCMAP(WMI_HL_10_SERVICE_BCN_MISS_OFFLOAD,
- WMI_SERVICE_BCN_MISS_OFFLOAD, len);
- SVCMAP(WMI_HL_10_SERVICE_STA_PWRSAVE,
- WMI_SERVICE_STA_PWRSAVE, len);
- SVCMAP(WMI_HL_10_SERVICE_STA_ADVANCED_PWRSAVE,
- WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
- SVCMAP(WMI_HL_10_SERVICE_AP_UAPSD,
- WMI_SERVICE_AP_UAPSD, len);
- SVCMAP(WMI_HL_10_SERVICE_AP_DFS,
- WMI_SERVICE_AP_DFS, len);
- SVCMAP(WMI_HL_10_SERVICE_11AC,
- WMI_SERVICE_11AC, len);
- SVCMAP(WMI_HL_10_SERVICE_BLOCKACK,
- WMI_SERVICE_BLOCKACK, len);
- SVCMAP(WMI_HL_10_SERVICE_PHYERR,
- WMI_SERVICE_PHYERR, len);
- SVCMAP(WMI_HL_10_SERVICE_BCN_FILTER,
- WMI_SERVICE_BCN_FILTER, len);
- SVCMAP(WMI_HL_10_SERVICE_RTT,
- WMI_SERVICE_RTT, len);
- SVCMAP(WMI_HL_10_SERVICE_WOW,
- WMI_SERVICE_WOW, len);
- SVCMAP(WMI_HL_10_SERVICE_RATECTRL_CACHE,
- WMI_SERVICE_RATECTRL_CACHE, len);
- SVCMAP(WMI_HL_10_SERVICE_IRAM_TIDS,
- WMI_SERVICE_IRAM_TIDS, len);
- SVCMAP(WMI_HL_10_SERVICE_ARPNS_OFFLOAD,
- WMI_SERVICE_ARPNS_OFFLOAD, len);
- SVCMAP(WMI_HL_10_SERVICE_NLO,
- WMI_SERVICE_NLO, len);
- SVCMAP(WMI_HL_10_SERVICE_GTK_OFFLOAD,
- WMI_SERVICE_GTK_OFFLOAD, len);
- SVCMAP(WMI_HL_10_SERVICE_SCAN_SCH,
- WMI_SERVICE_SCAN_SCH, len);
- SVCMAP(WMI_HL_10_SERVICE_CSA_OFFLOAD,
- WMI_SERVICE_CSA_OFFLOAD, len);
- SVCMAP(WMI_HL_10_SERVICE_CHATTER,
- WMI_SERVICE_CHATTER, len);
- SVCMAP(WMI_HL_10_SERVICE_COEX_FREQAVOID,
- WMI_SERVICE_COEX_FREQAVOID, len);
- SVCMAP(WMI_HL_10_SERVICE_PACKET_POWER_SAVE,
- WMI_SERVICE_PACKET_POWER_SAVE, len);
- SVCMAP(WMI_HL_10_SERVICE_FORCE_FW_HANG,
- WMI_SERVICE_FORCE_FW_HANG, len);
- SVCMAP(WMI_HL_10_SERVICE_RX_FULL_REORDER,
- WMI_SERVICE_RX_FULL_REORDER, len);
- SVCMAP(WMI_HL_10_SERVICE_MGMT_TX_WMI,
- WMI_SERVICE_MGMT_TX_WMI, len);
-}
-
-static inline void
wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
{
SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD,
@@ -1303,6 +1169,8 @@ wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
WMI_SERVICE_MDNS_OFFLOAD, len);
SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_MGMT_TX_WMI,
+ WMI_SERVICE_MGMT_TX_WMI, len);
}
#undef SVCMAP
@@ -1832,7 +1700,7 @@ struct wmi_tlv_tx_pause_ev {
} __packed;
void ath10k_wmi_tlv_attach(struct ath10k *ar);
-void ath10k_wmi_hl_1_0_attach(struct ath10k *ar);
+
struct wmi_tlv_mgmt_tx_hdr {
__le32 vdev_id;
__le32 desc_id;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 2ce61e64c82e..4dd60b74853d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -8233,9 +8233,6 @@ int ath10k_wmi_attach(struct ath10k *ar)
case ATH10K_FW_WMI_OP_VERSION_TLV:
ath10k_wmi_tlv_attach(ar);
break;
- case ATH10K_FW_WMI_OP_VERSION_HL_1_0:
- ath10k_wmi_hl_1_0_attach(ar);
- break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
case ATH10K_FW_WMI_OP_VERSION_MAX:
ath10k_err(ar, "unsupported WMI op version: %d\n",
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 0a3928a8fe90..ca06394c48bb 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -21,6 +21,10 @@
#define WIL_MAX_ROC_DURATION_MS 5000
+bool disable_ap_sme;
+module_param(disable_ap_sme, bool, S_IRUGO);
+MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME");
+
#define CHAN60G(_channel, _flags) { \
.band = IEEE80211_BAND_60GHZ, \
.center_freq = 56160 + (2160 * (_channel)), \
@@ -147,9 +151,16 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
},
[NL80211_IFTYPE_AP] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+ BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
+ BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4),
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
- BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4)
},
[NL80211_IFTYPE_P2P_CLIENT] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
@@ -1411,6 +1422,28 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
return 0;
}
+static int wil_cfg80211_add_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *mac,
+ struct station_parameters *params)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+ wil_dbg_misc(wil, "add station %pM aid %d\n", mac, params->aid);
+
+ if (!disable_ap_sme) {
+ wil_err(wil, "not supported with AP SME enabled\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (params->aid > WIL_MAX_DMG_AID) {
+ wil_err(wil, "invalid aid\n");
+ return -EINVAL;
+ }
+
+ return wmi_new_sta(wil, mac, params->aid);
+}
+
static int wil_cfg80211_del_station(struct wiphy *wiphy,
struct net_device *dev,
struct station_del_parameters *params)
@@ -1427,6 +1460,52 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
return 0;
}
+static int wil_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *mac,
+ struct station_parameters *params)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ int authorize;
+ int cid, i;
+ struct vring_tx_data *txdata = NULL;
+
+ wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x\n", mac,
+ params->sta_flags_mask, params->sta_flags_set);
+
+ if (!disable_ap_sme) {
+ wil_dbg_misc(wil, "not supported with AP SME enabled\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+ return 0;
+
+ cid = wil_find_cid(wil, mac);
+ if (cid < 0) {
+ wil_err(wil, "station not found\n");
+ return -ENOLINK;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++)
+ if (wil->vring2cid_tid[i][0] == cid) {
+ txdata = &wil->vring_tx_data[i];
+ break;
+ }
+
+ if (!txdata) {
+ wil_err(wil, "vring data not found\n");
+ return -ENOLINK;
+ }
+
+ authorize = params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED);
+ txdata->dot1x_open = authorize ? 1 : 0;
+ wil_dbg_misc(wil, "cid %d vring %d authorize %d\n", cid, i,
+ txdata->dot1x_open);
+
+ return 0;
+}
+
/* probe_client handling */
static void wil_probe_client_handle(struct wil6210_priv *wil,
struct wil_probe_client_req *req)
@@ -1610,7 +1689,9 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.change_beacon = wil_cfg80211_change_beacon,
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
+ .add_station = wil_cfg80211_add_station,
.del_station = wil_cfg80211_del_station,
+ .change_station = wil_cfg80211_change_station,
.probe_client = wil_cfg80211_probe_client,
.change_bss = wil_cfg80211_change_bss,
/* P2P device */
@@ -1631,10 +1712,11 @@ static void wil_wiphy_init(struct wiphy *wiphy)
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE) |
BIT(NL80211_IFTYPE_MONITOR);
- wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ if (!disable_ap_sme)
+ wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
dev_dbg(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
__func__, wiphy->flags);
wiphy->probe_resp_offload =
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index d3e420f1b26b..865bb11e2a07 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -1705,6 +1705,7 @@ static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(recovery_count, S_IRUGO, doff_u32),
WIL_FIELD(ap_isolate, S_IRUGO, doff_u32),
WIL_FIELD(discovery_mode, S_IRUGO | S_IWUSR, doff_u8),
+ WIL_FIELD(chip_revision, S_IRUGO, doff_u8),
{},
};
diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c
index 82aae2d705b4..540fc20984d8 100644
--- a/drivers/net/wireless/ath/wil6210/fw.c
+++ b/drivers/net/wireless/ath/wil6210/fw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015,2017 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,8 +19,9 @@
#include "wil6210.h"
#include "fw.h"
-MODULE_FIRMWARE(WIL_FW_NAME);
-MODULE_FIRMWARE(WIL_FW2_NAME);
+MODULE_FIRMWARE(WIL_FW_NAME_DEFAULT);
+MODULE_FIRMWARE(WIL_FW_NAME_SPARROW_PLUS);
+MODULE_FIRMWARE(WIL_BOARD_FILE_NAME);
static
void wil_memset_toio_32(volatile void __iomem *dst, u32 val,
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 8f40eb301924..f4901587c005 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -537,3 +537,22 @@ out:
release_firmware(fw);
return rc;
}
+
+/**
+ * wil_fw_verify_file_exists - checks if firmware file exist
+ *
+ * @wil: driver context
+ * @name: firmware file name
+ *
+ * return value - boolean, true for success, false for failure
+ */
+bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name)
+{
+ const struct firmware *fw;
+ int rc;
+
+ rc = request_firmware(&fw, name, wil_to_dev(wil));
+ if (!rc)
+ release_firmware(fw);
+ return rc != -ENOENT;
+}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index eb1fd9dd09ba..32e217e7159e 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -176,8 +176,12 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
sta->status);
/* inform upper/lower layers */
if (sta->status != wil_sta_unused) {
- if (!from_event)
- wmi_disconnect_sta(wil, sta->addr, reason_code, true);
+ if (!from_event) {
+ bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
+ disable_ap_sme : false;
+ wmi_disconnect_sta(wil, sta->addr, reason_code,
+ true, del_sta);
+ }
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
@@ -943,16 +947,16 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil_set_oob_mode(wil, oob_mode);
if (load_fw) {
- wil_info(wil, "Use firmware <%s> + board <%s>\n", WIL_FW_NAME,
- WIL_FW2_NAME);
+ wil_info(wil, "Use firmware <%s> + board <%s>\n",
+ wil->wil_fw_name, WIL_BOARD_FILE_NAME);
wil_halt_cpu(wil);
memset(wil->fw_version, 0, sizeof(wil->fw_version));
/* Loading f/w from the file */
- rc = wil_request_firmware(wil, WIL_FW_NAME, true);
+ rc = wil_request_firmware(wil, wil->wil_fw_name, true);
if (rc)
return rc;
- rc = wil_request_firmware(wil, WIL_FW2_NAME, true);
+ rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
if (rc)
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index fdbc51ae1e1a..c97263b45cbd 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -36,18 +36,38 @@ static int wil6210_pm_notify(struct notifier_block *notify_block,
static
void wil_set_capabilities(struct wil6210_priv *wil)
{
- u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
+ u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
+ u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
+ RGF_USER_REVISION_ID_MASK);
bitmap_zero(wil->hw_capabilities, hw_capability_last);
bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
-
- switch (rev_id) {
- case JTAG_DEV_ID_SPARROW_B0:
- wil->hw_name = "Sparrow B0";
- wil->hw_version = HW_VER_SPARROW_B0;
+ wil->wil_fw_name = WIL_FW_NAME_DEFAULT;
+ wil->chip_revision = chip_revision;
+
+ switch (jtag_id) {
+ case JTAG_DEV_ID_SPARROW:
+ switch (chip_revision) {
+ case REVISION_ID_SPARROW_D0:
+ wil->hw_name = "Sparrow D0";
+ wil->hw_version = HW_VER_SPARROW_D0;
+ if (wil_fw_verify_file_exists(wil,
+ WIL_FW_NAME_SPARROW_PLUS))
+ wil->wil_fw_name = WIL_FW_NAME_SPARROW_PLUS;
+ break;
+ case REVISION_ID_SPARROW_B0:
+ wil->hw_name = "Sparrow B0";
+ wil->hw_version = HW_VER_SPARROW_B0;
+ break;
+ default:
+ wil->hw_name = "Unknown";
+ wil->hw_version = HW_VER_UNKNOWN;
+ break;
+ }
break;
default:
- wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id);
+ wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
+ jtag_id, chip_revision);
wil->hw_name = "Unknown";
wil->hw_version = HW_VER_UNKNOWN;
}
@@ -55,7 +75,7 @@ void wil_set_capabilities(struct wil6210_priv *wil)
wil_info(wil, "Board hardware is %s\n", wil->hw_name);
/* extract FW capabilities from file without loading the FW */
- wil_request_firmware(wil, WIL_FW_NAME, false);
+ wil_request_firmware(wil, wil->wil_fw_name, false);
}
void wil_disable_irq(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index b9727ebe79ac..19de0ebb48f7 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -34,10 +34,12 @@ extern int agg_wsize;
extern u32 vring_idle_trsh;
extern bool rx_align_2;
extern bool debug_fw;
+extern bool disable_ap_sme;
#define WIL_NAME "wil6210"
-#define WIL_FW_NAME "wil6210.fw" /* code */
-#define WIL_FW2_NAME "wil6210.brd" /* board & radio parameters */
+#define WIL_FW_NAME_DEFAULT "wil6210.fw" /* code Sparrow B0 */
+#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */
+#define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
@@ -100,6 +102,9 @@ static inline u32 wil_mtu2macbuf(u32 mtu)
#define WIL6210_RX_HIGH_TRSH_INIT (0)
#define WIL6210_RX_HIGH_TRSH_DEFAULT \
(1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
+#define WIL_MAX_DMG_AID 254 /* for DMG only 1-254 allowed (see
+ * 802.11REVmc/D5.0, section 9.4.1.8)
+ */
/* Hardware definitions begin */
/*
@@ -254,7 +259,12 @@ struct RGF_ICR {
#define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0)
#define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */
- #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f)
+ #define JTAG_DEV_ID_SPARROW (0x2632072f)
+
+#define RGF_USER_REVISION_ID (0x88afe4)
+#define RGF_USER_REVISION_ID_MASK (3)
+ #define REVISION_ID_SPARROW_B0 (0x0)
+ #define REVISION_ID_SPARROW_D0 (0x3)
/* crash codes for FW/Ucode stored here */
#define RGF_FW_ASSERT_CODE (0x91f020)
@@ -262,7 +272,8 @@ struct RGF_ICR {
enum {
HW_VER_UNKNOWN,
- HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */
+ HW_VER_SPARROW_B0, /* REVISION_ID_SPARROW_B0 */
+ HW_VER_SPARROW_D0, /* REVISION_ID_SPARROW_D0 */
};
/* popular locations */
@@ -588,7 +599,9 @@ struct wil6210_priv {
DECLARE_BITMAP(status, wil_status_last);
u8 fw_version[ETHTOOL_FWVERS_LEN];
u32 hw_version;
+ u8 chip_revision;
const char *hw_name;
+ const char *wil_fw_name;
DECLARE_BITMAP(hw_capabilities, hw_capability_last);
DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
u8 n_mids; /* number of additional MIDs as reported by FW */
@@ -824,8 +837,8 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
-int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
- bool full_disconnect);
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
+ u16 reason, bool full_disconnect, bool del_sta);
int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
@@ -835,6 +848,7 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
enum wmi_ps_profile_type ps_profile);
int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
+int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid);
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
u8 dialog_token, __le16 ba_param_set,
__le16 ba_timeout, __le16 ba_seq_ctrl);
@@ -928,6 +942,7 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type);
int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
int wil_request_firmware(struct wil6210_priv *wil, const char *name,
bool load);
+bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 0bddc9d9c632..ef6472fb1f7e 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -556,7 +556,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
wil_err(wil, "%s: config tx vring failed for CID %d, rc (%d)\n",
__func__, evt->cid, rc);
wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
- WLAN_REASON_UNSPECIFIED, false);
+ WLAN_REASON_UNSPECIFIED, false, false);
} else {
wil_info(wil, "%s: successful connection to CID %d\n",
__func__, evt->cid);
@@ -584,8 +584,12 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
}
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
- if (rc)
+ if (rc) {
+ if (disable_ap_sme)
+ /* notify new_sta has failed */
+ cfg80211_del_sta(ndev, evt->bssid, GFP_KERNEL);
goto out;
+ }
memset(&sinfo, 0, sizeof(sinfo));
@@ -688,6 +692,7 @@ static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
{
struct wmi_vring_en_event *evt = d;
u8 vri = evt->vring_index;
+ struct wireless_dev *wdev = wil_to_wdev(wil);
wil_dbg_wmi(wil, "Enable vring %d\n", vri);
@@ -695,7 +700,12 @@ static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len)
wil_err(wil, "Enable for invalid vring %d\n", vri);
return;
}
- wil->vring_tx_data[vri].dot1x_open = true;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
+ /* in AP mode with disable_ap_sme, this is done by
+ * wil_cfg80211_change_station()
+ */
+ wil->vring_tx_data[vri].dot1x_open = true;
if (vri == wil->bcast_vring) /* no BA for bcast */
return;
if (agg_wsize >= 0)
@@ -1102,6 +1112,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
.pcp_max_assoc_sta = max_assoc_sta,
.hidden_ssid = hidden_ssid,
.is_go = is_go,
+ .disable_ap_sme = disable_ap_sme,
};
struct {
struct wmi_cmd_hdr wmi;
@@ -1119,6 +1130,13 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
}
+ if (disable_ap_sme &&
+ !test_bit(WMI_FW_CAPABILITY_DISABLE_AP_SME,
+ wil->fw_capabilities)) {
+ wil_err(wil, "disable_ap_sme not supported by FW\n");
+ return -EOPNOTSUPP;
+ }
+
/*
* Processing time may be huge, in case of secure AP it takes about
* 3500ms for FW to start AP
@@ -1489,12 +1507,15 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
return 0;
}
-int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
- bool full_disconnect)
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
+ u16 reason, bool full_disconnect, bool del_sta)
{
int rc;
u16 reason_code;
- struct wmi_disconnect_sta_cmd cmd = {
+ struct wmi_disconnect_sta_cmd disc_sta_cmd = {
+ .disconnect_reason = cpu_to_le16(reason),
+ };
+ struct wmi_del_sta_cmd del_sta_cmd = {
.disconnect_reason = cpu_to_le16(reason),
};
struct {
@@ -1502,12 +1523,19 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
struct wmi_disconnect_event evt;
} __packed reply;
- ether_addr_copy(cmd.dst_mac, mac);
-
wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason);
- rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd),
- WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), 1000);
+ if (del_sta) {
+ ether_addr_copy(del_sta_cmd.dst_mac, mac);
+ rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
+ sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID,
+ &reply, sizeof(reply), 1000);
+ } else {
+ ether_addr_copy(disc_sta_cmd.dst_mac, mac);
+ rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &disc_sta_cmd,
+ sizeof(disc_sta_cmd), WMI_DISCONNECT_EVENTID,
+ &reply, sizeof(reply), 1000);
+ }
/* failure to disconnect in reasonable time treated as FW error */
if (rc) {
wil_fw_error_recovery(wil);
@@ -1719,6 +1747,24 @@ int wmi_abort_scan(struct wil6210_priv *wil)
return rc;
}
+int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid)
+{
+ int rc;
+ struct wmi_new_sta_cmd cmd = {
+ .aid = aid,
+ };
+
+ wil_dbg_wmi(wil, "new sta %pM, aid %d\n", mac, aid);
+
+ ether_addr_copy(cmd.dst_mac, mac);
+
+ rc = wmi_send(wil, WMI_NEW_STA_CMDID, &cmd, sizeof(cmd));
+ if (rc)
+ wil_err(wil, "Failed to send new sta (%d)\n", rc);
+
+ return rc;
+}
+
void wmi_event_flush(struct wil6210_priv *wil)
{
ulong flags;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index d93a4d490d24..9c4a0bdc51f3 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2006-2012 Wilocity
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -56,6 +56,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_PS_CONFIG = 1,
WMI_FW_CAPABILITY_RF_SECTORS = 2,
WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3,
+ WMI_FW_CAPABILITY_DISABLE_AP_SME = 4,
WMI_FW_CAPABILITY_MAX,
};
@@ -187,6 +188,8 @@ enum wmi_command_id {
WMI_AOA_MEAS_CMDID = 0x923,
WMI_SET_MGMT_RETRY_LIMIT_CMDID = 0x930,
WMI_GET_MGMT_RETRY_LIMIT_CMDID = 0x931,
+ WMI_NEW_STA_CMDID = 0x935,
+ WMI_DEL_STA_CMDID = 0x936,
WMI_TOF_SESSION_START_CMDID = 0x991,
WMI_TOF_GET_CAPABILITIES_CMDID = 0x992,
WMI_TOF_SET_LCR_CMDID = 0x993,
@@ -543,7 +546,8 @@ struct wmi_pcp_start_cmd {
u8 pcp_max_assoc_sta;
u8 hidden_ssid;
u8 is_go;
- u8 reserved0[7];
+ u8 reserved0[6];
+ u8 disable_ap_sme;
u8 network_type;
u8 channel;
u8 disable_sec_offload;
@@ -902,6 +906,18 @@ struct wmi_set_mgmt_retry_limit_cmd {
u8 reserved[3];
} __packed;
+/* WMI_NEW_STA_CMDID */
+struct wmi_new_sta_cmd {
+ u8 dst_mac[WMI_MAC_LEN];
+ u8 aid;
+} __packed;
+
+/* WMI_DEL_STA_CMDID */
+struct wmi_del_sta_cmd {
+ u8 dst_mac[WMI_MAC_LEN];
+ __le16 disconnect_reason;
+} __packed;
+
enum wmi_tof_burst_duration {
WMI_TOF_BURST_DURATION_250_USEC = 2,
WMI_TOF_BURST_DURATION_500_USEC = 3,
@@ -1292,7 +1308,7 @@ struct wmi_connect_event {
u8 assoc_info[0];
} __packed;
-/* WMI_DISCONNECT_EVENTID */
+/* disconnect_reason */
enum wmi_disconnect_reason {
WMI_DIS_REASON_NO_NETWORK_AVAIL = 0x01,
/* bmiss */
@@ -1310,6 +1326,7 @@ enum wmi_disconnect_reason {
WMI_DIS_REASON_IBSS_MERGE = 0x0E,
};
+/* WMI_DISCONNECT_EVENTID */
struct wmi_disconnect_event {
/* reason code, see 802.11 spec. */
__le16 protocol_reason_status;
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 8e585aefebf2..c1448955d3ed 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2013, Sony Mobile Communications AB.
- * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -27,6 +27,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
#include <linux/reboot.h>
#include <linux/irqchip/msm-mpm-irq.h>
#include "../core.h"
@@ -70,6 +71,8 @@ struct msm_pinctrl {
void __iomem *regs;
};
+static struct msm_pinctrl *msm_pinctrl_data;
+
static inline struct msm_pinctrl *to_msm_pinctrl(struct gpio_chip *gc)
{
return container_of(gc, struct msm_pinctrl, chip);
@@ -896,6 +899,52 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl)
}
}
+#ifdef CONFIG_PM
+static int msm_pinctrl_suspend(void)
+{
+ return 0;
+}
+
+static void msm_pinctrl_resume(void)
+{
+ int i, irq;
+ u32 val;
+ unsigned long flags;
+ struct irq_desc *desc;
+ const struct msm_pingroup *g;
+ const char *name = "null";
+ struct msm_pinctrl *pctrl = msm_pinctrl_data;
+
+ if (!msm_show_resume_irq_mask)
+ return;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+ for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
+ g = &pctrl->soc->groups[i];
+ val = readl_relaxed(pctrl->regs + g->intr_status_reg);
+ if (val & BIT(g->intr_status_bit)) {
+ irq = irq_find_mapping(pctrl->chip.irqdomain, i);
+ desc = irq_to_desc(irq);
+ if (desc == NULL)
+ name = "stray irq";
+ else if (desc->action && desc->action->name)
+ name = desc->action->name;
+
+ pr_warn("%s: %d triggered %s\n", __func__, irq, name);
+ }
+ }
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+#else
+#define msm_pinctrl_suspend NULL
+#define msm_pinctrl_resume NULL
+#endif
+
+static struct syscore_ops msm_pinctrl_pm_ops = {
+ .suspend = msm_pinctrl_suspend,
+ .resume = msm_pinctrl_resume,
+};
+
int msm_pinctrl_probe(struct platform_device *pdev,
const struct msm_pinctrl_soc_data *soc_data)
{
@@ -903,7 +952,8 @@ int msm_pinctrl_probe(struct platform_device *pdev,
struct resource *res;
int ret;
- pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ msm_pinctrl_data = pctrl = devm_kzalloc(&pdev->dev,
+ sizeof(*pctrl), GFP_KERNEL);
if (!pctrl) {
dev_err(&pdev->dev, "Can't allocate msm_pinctrl\n");
return -ENOMEM;
@@ -944,6 +994,7 @@ int msm_pinctrl_probe(struct platform_device *pdev,
pctrl->irq_chip_extn = &mpm_pinctrl_extn;
platform_set_drvdata(pdev, pctrl);
+ register_syscore_ops(&msm_pinctrl_pm_ops);
dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n");
return 0;
@@ -958,6 +1009,7 @@ int msm_pinctrl_remove(struct platform_device *pdev)
pinctrl_unregister(pctrl->pctrl);
unregister_restart_handler(&pctrl->restart_nb);
+ unregister_syscore_ops(&msm_pinctrl_pm_ops);
return 0;
}
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 54fdd04ce9d5..e986fdacc0bf 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -121,4 +121,5 @@ int msm_pinctrl_probe(struct platform_device *pdev,
const struct msm_pinctrl_soc_data *soc_data);
int msm_pinctrl_remove(struct platform_device *pdev);
+extern int msm_show_resume_irq_mask;
#endif
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 4dc3910737e1..1a6ba1a915a0 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -113,7 +113,8 @@ const char *ipa_clients_strings[IPA_CLIENT_MAX] = {
__stringify(IPA_CLIENT_A5_WLAN_AMPDU_PROD),
__stringify(IPA_CLIENT_A2_EMBEDDED_PROD),
__stringify(IPA_CLIENT_A2_TETHERED_PROD),
- __stringify(IPA_CLIENT_APPS_LAN_WAN_PROD),
+ __stringify(IPA_CLIENT_APPS_LAN_PROD),
+ __stringify(IPA_CLIENT_APPS_WAN_PROD),
__stringify(IPA_CLIENT_APPS_CMD_PROD),
__stringify(IPA_CLIENT_ODU_PROD),
__stringify(IPA_CLIENT_MHI_PROD),
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 1e79fd954969..fde087f07226 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1827,7 +1827,7 @@ static int ipa_q6_clean_q6_tables(void)
u32 max_cmds = ipa_get_max_flt_rt_cmds(ipa_ctx->ipa_num_pipes);
mem.base = dma_alloc_coherent(ipa_ctx->pdev, 4, &mem.phys_base,
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!mem.base) {
IPAERR("failed to alloc DMA buff of size 4\n");
return -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index 2cd8d5c975f4..9cab7e010c3a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -86,6 +86,7 @@ static const int ep_mapping[3][IPA_CLIENT_MAX] = {
[IPA_1_1][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = 15,
[IPA_1_1][IPA_CLIENT_A2_EMBEDDED_PROD] = 8,
[IPA_1_1][IPA_CLIENT_A2_TETHERED_PROD] = 6,
+ [IPA_1_1][IPA_CLIENT_APPS_LAN_PROD] = -1,
[IPA_1_1][IPA_CLIENT_APPS_LAN_WAN_PROD] = 2,
[IPA_1_1][IPA_CLIENT_APPS_CMD_PROD] = 1,
[IPA_1_1][IPA_CLIENT_ODU_PROD] = -1,
@@ -133,6 +134,7 @@ static const int ep_mapping[3][IPA_CLIENT_MAX] = {
[IPA_2_0][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = -1,
[IPA_2_0][IPA_CLIENT_A2_EMBEDDED_PROD] = -1,
[IPA_2_0][IPA_CLIENT_A2_TETHERED_PROD] = -1,
+ [IPA_2_0][IPA_CLIENT_APPS_LAN_PROD] = -1,
[IPA_2_0][IPA_CLIENT_APPS_LAN_WAN_PROD] = 4,
[IPA_2_0][IPA_CLIENT_APPS_CMD_PROD] = 3,
[IPA_2_0][IPA_CLIENT_ODU_PROD] = 12,
@@ -207,6 +209,7 @@ static const int ep_mapping[3][IPA_CLIENT_MAX] = {
[IPA_2_6L][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = -1,
[IPA_2_6L][IPA_CLIENT_A2_EMBEDDED_PROD] = -1,
[IPA_2_6L][IPA_CLIENT_A2_TETHERED_PROD] = -1,
+ [IPA_2_6L][IPA_CLIENT_APPS_LAN_PROD] = -1,
[IPA_2_6L][IPA_CLIENT_APPS_LAN_WAN_PROD] = 4,
[IPA_2_6L][IPA_CLIENT_APPS_CMD_PROD] = 3,
[IPA_2_6L][IPA_CLIENT_ODU_PROD] = -1,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 8a588d26e827..e90f69b466e1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2809,7 +2809,7 @@ static int ipa3_setup_apps_pipes(void)
result = ipa_gsi_ch20_wa();
if (result) {
IPAERR("ipa_gsi_ch20_wa failed %d\n", result);
- goto fail_cmd;
+ goto fail_ch20_wa;
}
}
@@ -2820,9 +2820,9 @@ static int ipa3_setup_apps_pipes(void)
sys_in.ipa_ep_cfg.mode.mode = IPA_DMA;
sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_APPS_LAN_CONS;
if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_cmd)) {
- IPAERR(":setup sys pipe failed.\n");
+ IPAERR(":setup sys pipe (APPS_CMD_PROD) failed.\n");
result = -EPERM;
- goto fail_cmd;
+ goto fail_ch20_wa;
}
IPADBG("Apps to IPA cmd pipe is connected\n");
@@ -2847,32 +2847,32 @@ static int ipa3_setup_apps_pipes(void)
if (ipa3_setup_flt_hash_tuple()) {
IPAERR(":fail to configure flt hash tuple\n");
result = -EPERM;
- goto fail_schedule_delayed_work;
+ goto fail_flt_hash_tuple;
}
IPADBG("flt hash tuple is configured\n");
if (ipa3_setup_rt_hash_tuple()) {
IPAERR(":fail to configure rt hash tuple\n");
result = -EPERM;
- goto fail_schedule_delayed_work;
+ goto fail_flt_hash_tuple;
}
IPADBG("rt hash tuple is configured\n");
if (ipa3_setup_exception_path()) {
IPAERR(":fail to setup excp path\n");
result = -EPERM;
- goto fail_schedule_delayed_work;
+ goto fail_flt_hash_tuple;
}
IPADBG("Exception path was successfully set");
if (ipa3_setup_dflt_rt_tables()) {
IPAERR(":fail to setup dflt routes\n");
result = -EPERM;
- goto fail_schedule_delayed_work;
+ goto fail_flt_hash_tuple;
}
IPADBG("default routing was set\n");
- /* LAN IN (IPA->A5) */
+ /* LAN IN (IPA->AP) */
memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
sys_in.client = IPA_CLIENT_APPS_LAN_CONS;
sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
@@ -2896,27 +2896,27 @@ static int ipa3_setup_apps_pipes(void)
*/
spin_lock_init(&ipa3_ctx->disconnect_lock);
if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_data_in)) {
- IPAERR(":setup sys pipe failed.\n");
+ IPAERR(":setup sys pipe (LAN_CONS) failed.\n");
result = -EPERM;
- goto fail_schedule_delayed_work;
+ goto fail_flt_hash_tuple;
}
- /* LAN-WAN OUT (AP->IPA) */
+ /* LAN OUT (AP->IPA) */
memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
- sys_in.client = IPA_CLIENT_APPS_LAN_WAN_PROD;
+ sys_in.client = IPA_CLIENT_APPS_LAN_PROD;
sys_in.desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
sys_in.ipa_ep_cfg.mode.mode = IPA_BASIC;
if (ipa3_setup_sys_pipe(&sys_in, &ipa3_ctx->clnt_hdl_data_out)) {
- IPAERR(":setup sys pipe failed.\n");
+ IPAERR(":setup sys pipe (LAN_PROD) failed.\n");
result = -EPERM;
- goto fail_data_out;
+ goto fail_lan_data_out;
}
return 0;
-fail_data_out:
+fail_lan_data_out:
ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
-fail_schedule_delayed_work:
+fail_flt_hash_tuple:
if (ipa3_ctx->dflt_v6_rt_rule_hdl)
__ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
if (ipa3_ctx->dflt_v4_rt_rule_hdl)
@@ -2924,7 +2924,7 @@ fail_schedule_delayed_work:
if (ipa3_ctx->excp_hdr_hdl)
__ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
-fail_cmd:
+fail_ch20_wa:
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 00bfbf84c75a..e3dfe8927682 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -46,6 +46,20 @@ int ipa3_enable_data_path(u32 clnt_hdl)
int res = 0;
struct ipahal_reg_endp_init_rsrc_grp rsrc_grp;
+ /* Assign the resource group for pipe */
+ memset(&rsrc_grp, 0, sizeof(rsrc_grp));
+ rsrc_grp.rsrc_grp = ipa_get_ep_group(ep->client);
+ if (rsrc_grp.rsrc_grp == -1) {
+ IPAERR("invalid group for client %d\n", ep->client);
+ WARN_ON(1);
+ return -EFAULT;
+ }
+
+ IPADBG("Setting group %d for pipe %d\n",
+ rsrc_grp.rsrc_grp, clnt_hdl);
+ ipahal_write_reg_n_fields(IPA_ENDP_INIT_RSRC_GRP_n, clnt_hdl,
+ &rsrc_grp);
+
IPADBG("Enabling data path\n");
if (IPA_CLIENT_IS_CONS(ep->client)) {
memset(&holb_cfg, 0 , sizeof(holb_cfg));
@@ -64,20 +78,6 @@ int ipa3_enable_data_path(u32 clnt_hdl)
res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
}
- /* Assign the resource group for pipe */
- memset(&rsrc_grp, 0, sizeof(rsrc_grp));
- rsrc_grp.rsrc_grp = ipa_get_ep_group(ep->client);
- if (rsrc_grp.rsrc_grp == -1) {
- IPAERR("invalid group for client %d\n", ep->client);
- WARN_ON(1);
- return -EFAULT;
- }
-
- IPADBG("Setting group %d for pipe %d\n",
- rsrc_grp.rsrc_grp, clnt_hdl);
- ipahal_write_reg_n_fields(IPA_ENDP_INIT_RSRC_GRP_n, clnt_hdl,
- &rsrc_grp);
-
return res;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index be2946c873b3..5c678f1cfc28 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -62,7 +62,7 @@
#define IPA_SIZE_DL_CSUM_META_TRAILER 8
#define IPA_GSI_MAX_CH_LOW_WEIGHT 15
-#define IPA_GSI_EVT_RING_INT_MODT 3200 /* 0.1s under 32KHz clock */
+#define IPA_GSI_EVT_RING_INT_MODT (32 * 1) /* 1ms under 32KHz clock */
#define IPA_GSI_CH_20_WA_NUM_CH_TO_ALLOC 10
/* The below virtual channel cannot be used by any entity */
@@ -637,10 +637,12 @@ int ipa3_send(struct ipa3_sys_context *sys,
if (i == (num_desc - 1)) {
gsi_xfer_elem_array[i].flags |=
GSI_XFER_FLAG_EOT;
+ if (sys->ep->client == IPA_CLIENT_APPS_WAN_PROD
+ && sys->policy == IPA_POLICY_INTR_MODE)
+ gsi_xfer_elem_array[i].flags |=
+ GSI_XFER_FLAG_BEI;
gsi_xfer_elem_array[i].xfer_user_data =
tx_pkt_first;
- /* "mark" the last desc */
- tx_pkt->cnt = IPA_LAST_DESC_CNT;
} else
gsi_xfer_elem_array[i].flags |=
GSI_XFER_FLAG_CHAIN;
@@ -1262,37 +1264,12 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
- IPA_ACTIVE_CLIENTS_INC_EP(sys_in->client);
-
if (ep->valid == 1) {
- if (sys_in->client != IPA_CLIENT_APPS_LAN_WAN_PROD) {
- IPAERR("EP already allocated.\n");
- goto fail_and_disable_clocks;
- } else {
- if (ipa3_cfg_ep_hdr(ipa_ep_idx,
- &sys_in->ipa_ep_cfg.hdr)) {
- IPAERR("fail to configure hdr prop of EP.\n");
- result = -EFAULT;
- goto fail_and_disable_clocks;
- }
- if (ipa3_cfg_ep_cfg(ipa_ep_idx,
- &sys_in->ipa_ep_cfg.cfg)) {
- IPAERR("fail to configure cfg prop of EP.\n");
- result = -EFAULT;
- goto fail_and_disable_clocks;
- }
- IPADBG("client %d (ep: %d) overlay ok sys=%p\n",
- sys_in->client, ipa_ep_idx, ep->sys);
- ep->client_notify = sys_in->notify;
- ep->priv = sys_in->priv;
- *clnt_hdl = ipa_ep_idx;
- if (!ep->keep_ipa_awake)
- IPA_ACTIVE_CLIENTS_DEC_EP(sys_in->client);
-
- return 0;
- }
+ IPAERR("EP %d already allocated.\n", ipa_ep_idx);
+ goto fail_gen;
}
+ IPA_ACTIVE_CLIENTS_INC_EP(sys_in->client);
memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
if (!ep->sys) {
@@ -1360,13 +1337,6 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
}
}
- result = ipa3_enable_data_path(ipa_ep_idx);
- if (result) {
- IPAERR("enable data path failed res=%d clnt=%d.\n", result,
- ipa_ep_idx);
- goto fail_gen2;
- }
-
if (!ep->skip_ep_cfg) {
if (ipa3_cfg_ep(ipa_ep_idx, &sys_in->ipa_ep_cfg)) {
IPAERR("fail to configure EP.\n");
@@ -1376,9 +1346,9 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
IPAERR("fail to configure status of EP.\n");
goto fail_gen2;
}
- IPADBG("ep configuration successful\n");
+ IPADBG("ep %d configuration successful\n", ipa_ep_idx);
} else {
- IPADBG("skipping ep configuration\n");
+ IPADBG("skipping ep %d configuration\n", ipa_ep_idx);
}
if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
@@ -1492,12 +1462,19 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl)
ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg;
if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(sys_in->client)) {
if (ipa3_ctx->modem_cfg_emb_pipe_flt &&
- sys_in->client == IPA_CLIENT_APPS_LAN_WAN_PROD)
+ sys_in->client == IPA_CLIENT_APPS_WAN_PROD)
IPADBG("modem cfg emb pipe flt\n");
else
ipa3_install_dflt_flt_rules(ipa_ep_idx);
}
+ result = ipa3_enable_data_path(ipa_ep_idx);
+ if (result) {
+ IPAERR("enable data path failed res=%d ep=%d.\n", result,
+ ipa_ep_idx);
+ goto fail_gen2;
+ }
+
if (!ep->keep_ipa_awake)
IPA_ACTIVE_CLIENTS_DEC_EP(sys_in->client);
@@ -1632,7 +1609,7 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(ep->client)) {
if (ipa3_ctx->modem_cfg_emb_pipe_flt &&
- ep->client == IPA_CLIENT_APPS_LAN_WAN_PROD)
+ ep->client == IPA_CLIENT_APPS_WAN_PROD)
IPADBG("modem cfg emb pipe flt\n");
else
ipa3_delete_dflt_flt_rules(clnt_hdl);
@@ -1723,6 +1700,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
struct ipa3_sys_context *sys;
int src_ep_idx;
int num_frags, f;
+ int data_idx;
struct ipa_gsi_ep_config *gsi_ep;
if (unlikely(!ipa3_ctx)) {
@@ -1745,10 +1723,10 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
*
*/
if (IPA_CLIENT_IS_CONS(dst)) {
- src_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_WAN_PROD);
+ src_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_PROD);
if (-1 == src_ep_idx) {
IPAERR("Client %u is not mapped\n",
- IPA_CLIENT_APPS_LAN_WAN_PROD);
+ IPA_CLIENT_APPS_LAN_PROD);
goto fail_gen;
}
dst_ep_idx = ipa3_get_ep_mapping(dst);
@@ -1859,40 +1837,54 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
IPA_STATS_INC_CNT(ipa3_ctx->stats.tx_sw_pkts);
} else {
/* HW data path */
- desc[0].opcode =
- ipahal_imm_cmd_get_opcode(
- IPA_IMM_CMD_IP_PACKET_TAG_STATUS);
- desc[0].type = IPA_IMM_CMD_DESC;
- desc[0].callback = ipa3_tag_destroy_imm;
- desc[1].pyld = skb->data;
- desc[1].len = skb_headlen(skb);
- desc[1].type = IPA_DATA_DESC_SKB;
- desc[1].callback = ipa3_tx_comp_usr_notify_release;
- desc[1].user1 = skb;
- desc[1].user2 = src_ep_idx;
+ data_idx = 0;
+ if (sys->policy == IPA_POLICY_NOINTR_MODE) {
+ /*
+ * For non-interrupt mode channel (where there is no
+ * event ring) TAG STATUS are used for completion
+ * notification. IPA will generate a status packet with
+ * tag info as a result of the TAG STATUS command.
+ */
+ desc[data_idx].opcode =
+ ipahal_imm_cmd_get_opcode(
+ IPA_IMM_CMD_IP_PACKET_TAG_STATUS);
+ desc[data_idx].type = IPA_IMM_CMD_DESC;
+ desc[data_idx].callback = ipa3_tag_destroy_imm;
+ data_idx++;
+ }
+ desc[data_idx].pyld = skb->data;
+ desc[data_idx].len = skb_headlen(skb);
+ desc[data_idx].type = IPA_DATA_DESC_SKB;
+ desc[data_idx].callback = ipa3_tx_comp_usr_notify_release;
+ desc[data_idx].user1 = skb;
+ desc[data_idx].user2 = src_ep_idx;
if (meta && meta->dma_address_valid) {
- desc[1].dma_address_valid = true;
- desc[1].dma_address = meta->dma_address;
+ desc[data_idx].dma_address_valid = true;
+ desc[data_idx].dma_address = meta->dma_address;
}
if (num_frags == 0) {
- if (ipa3_send(sys, 2, desc, true)) {
+ if (ipa3_send(sys, data_idx + 1, desc, true)) {
IPAERR("fail to send skb %p HWP\n", skb);
goto fail_mem;
}
} else {
for (f = 0; f < num_frags; f++) {
- desc[2+f].frag = &skb_shinfo(skb)->frags[f];
- desc[2+f].type = IPA_DATA_DESC_SKB_PAGED;
- desc[2+f].len = skb_frag_size(desc[2+f].frag);
+ desc[data_idx+f+1].frag =
+ &skb_shinfo(skb)->frags[f];
+ desc[data_idx+f+1].type =
+ IPA_DATA_DESC_SKB_PAGED;
+ desc[data_idx+f+1].len =
+ skb_frag_size(desc[data_idx+f+1].frag);
}
/* don't free skb till frag mappings are released */
- desc[2+f-1].callback = desc[1].callback;
- desc[2+f-1].user1 = desc[1].user1;
- desc[2+f-1].user2 = desc[1].user2;
- desc[1].callback = NULL;
+ desc[data_idx+f].callback = desc[data_idx].callback;
+ desc[data_idx+f].user1 = desc[data_idx].user1;
+ desc[data_idx+f].user2 = desc[data_idx].user2;
+ desc[data_idx].callback = NULL;
- if (ipa3_send(sys, num_frags + 2, desc, true)) {
+ if (ipa3_send(sys, num_frags + data_idx + 1,
+ desc, true)) {
IPAERR("fail to send skb %p num_frags %u HWP\n",
skb, num_frags);
goto fail_mem;
@@ -3234,7 +3226,8 @@ static void ipa3_free_rx_wrapper(struct ipa3_rx_pkt_wrapper *rk_pkt)
static int ipa3_assign_policy(struct ipa_sys_connect_params *in,
struct ipa3_sys_context *sys)
{
- if (in->client == IPA_CLIENT_APPS_CMD_PROD) {
+ if (in->client == IPA_CLIENT_APPS_CMD_PROD ||
+ in->client == IPA_CLIENT_APPS_WAN_PROD) {
sys->policy = IPA_POLICY_INTR_MODE;
sys->sps_option = (SPS_O_AUTO_ENABLE | SPS_O_EOT);
sys->sps_callback = ipa3_sps_irq_tx_no_aggr_notify;
@@ -3665,7 +3658,7 @@ int ipa3_sys_setup(struct ipa_sys_connect_params *sys_in,
IPA_ACTIVE_CLIENTS_INC_EP(sys_in->client);
if (ep->valid == 1) {
- if (sys_in->client != IPA_CLIENT_APPS_LAN_WAN_PROD) {
+ if (sys_in->client != IPA_CLIENT_APPS_WAN_PROD) {
IPAERR("EP %d already allocated\n", ipa_ep_idx);
goto fail_and_disable_clocks;
} else {
@@ -4002,7 +3995,15 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
gsi_evt_ring_props.ring_base_vaddr;
gsi_evt_ring_props.int_modt = IPA_GSI_EVT_RING_INT_MODT;
- gsi_evt_ring_props.int_modc = 1;
+ if (ep->client == IPA_CLIENT_APPS_WAN_PROD)
+ gsi_evt_ring_props.int_modc = 248;
+ else
+ gsi_evt_ring_props.int_modc = 1;
+
+ IPADBG("client=%d moderation threshold cycles=%u cnt=%u\n",
+ ep->client,
+ gsi_evt_ring_props.int_modt,
+ gsi_evt_ring_props.int_modc);
gsi_evt_ring_props.rp_update_addr = 0;
gsi_evt_ring_props.exclusive = true;
gsi_evt_ring_props.err_cb = ipa_gsi_evt_ring_err_cb;
@@ -4038,9 +4039,13 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
* GSI ring length is calculated based on the desc_fifo_sz which was
* meant to define the BAM desc fifo. GSI descriptors are 16B as opposed
* to 8B for BAM. For PROD pipes there is also an additional descriptor
- * for TAG STATUS immediate command.
+ * for TAG STATUS immediate command. APPS_WAN_PROD pipe is an exception
+ * as this pipe do not use TAG STATUS for completion. Instead it uses
+ * event ring based completions.
*/
- if (IPA_CLIENT_IS_PROD(ep->client))
+ if (ep->client == IPA_CLIENT_APPS_WAN_PROD)
+ gsi_channel_props.ring_len = 2 * in->desc_fifo_sz;
+ else if (IPA_CLIENT_IS_PROD(ep->client))
gsi_channel_props.ring_len = 4 * in->desc_fifo_sz;
else
gsi_channel_props.ring_len = 2 * in->desc_fifo_sz;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index df413c991a53..c3a12dd0b17c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -438,7 +438,7 @@ static bool ipa_flt_skip_pipe_config(int pipe)
return true;
}
- if ((ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_WAN_PROD) == pipe
+ if ((ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD) == pipe
&& ipa3_ctx->modem_cfg_emb_pipe_flt)) {
IPADBG_LOW("skip %d\n", pipe);
return true;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 9938221e34b0..0cf77bbde496 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -42,6 +42,7 @@
#define IPA_COOKIE 0x57831603
#define MTU_BYTE 1500
+#define IPA_EP_NOT_ALLOCATED (-1)
#define IPA3_MAX_NUM_PIPES 31
#define IPA_SYS_DESC_FIFO_SZ 0x800
#define IPA_SYS_TX_DATA_DESC_FIFO_SZ 0x1000
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 3b909acdd823..9f38af1b520b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -95,7 +95,8 @@
#define QMB_MASTER_SELECT_PCIE (1)
#define IPA_CLIENT_NOT_USED \
- {-1, -1, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR}
+ {IPA_EP_NOT_ALLOCATED, IPA_EP_NOT_ALLOCATED, false, \
+ IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR}
/* Resource Group index*/
#define IPA_GROUP_UL (0)
@@ -208,7 +209,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping
[IPA_3_0][IPA_CLIENT_A5_WLAN_AMPDU_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_A2_EMBEDDED_PROD] = IPA_CLIENT_NOT_USED,
[IPA_3_0][IPA_CLIENT_A2_TETHERED_PROD] = IPA_CLIENT_NOT_USED,
- [IPA_3_0][IPA_CLIENT_APPS_LAN_WAN_PROD] = {14, IPA_GROUP_UL, true,
+ [IPA_3_0][IPA_CLIENT_APPS_LAN_PROD]
+ = {14, IPA_GROUP_DL, false,
+ IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
+ QMB_MASTER_SELECT_DDR},
+ [IPA_3_0][IPA_CLIENT_APPS_WAN_PROD]
+ = {3, IPA_GROUP_UL, true,
IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
QMB_MASTER_SELECT_DDR},
[IPA_3_0][IPA_CLIENT_APPS_CMD_PROD]
@@ -919,12 +925,18 @@ u8 ipa3_get_hw_type_index(void)
*/
int ipa3_get_ep_mapping(enum ipa_client_type client)
{
+ int ipa_ep_idx;
+
if (client >= IPA_CLIENT_MAX || client < 0) {
IPAERR("Bad client number! client =%d\n", client);
return -EINVAL;
}
- return ipa3_ep_mapping[ipa3_get_hw_type_index()][client].pipe_num;
+ ipa_ep_idx = ipa3_ep_mapping[ipa3_get_hw_type_index()][client].pipe_num;
+ if (ipa_ep_idx < 0 || ipa_ep_idx >= IPA3_MAX_NUM_PIPES)
+ return IPA_EP_NOT_ALLOCATED;
+
+ return ipa_ep_idx;
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 87743c98e0fa..6731150ce4e7 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -47,9 +47,9 @@
#define TAILROOM 0 /* for padding by mux layer */
#define MAX_NUM_OF_MUX_CHANNEL 10 /* max mux channels */
#define UL_FILTER_RULE_HANDLE_START 69
-#define DEFAULT_OUTSTANDING_HIGH_CTL 96
-#define DEFAULT_OUTSTANDING_HIGH 64
-#define DEFAULT_OUTSTANDING_LOW 32
+#define DEFAULT_OUTSTANDING_HIGH 128
+#define DEFAULT_OUTSTANDING_HIGH_CTL (DEFAULT_OUTSTANDING_HIGH+32)
+#define DEFAULT_OUTSTANDING_LOW 64
#define IPA_WWAN_DEV_NAME "rmnet_ipa%d"
#define IPA_UPSTEAM_WLAN_IFACE_NAME "wlan0"
@@ -140,7 +140,7 @@ struct rmnet_ipa3_context {
void *subsys_notify_handle;
u32 apps_to_ipa3_hdl;
u32 ipa3_to_apps_hdl;
- struct mutex ipa_to_apps_pipe_handle_guard;
+ struct mutex pipe_handle_guard;
};
static struct rmnet_ipa3_context *rmnet_ipa3_ctx;
@@ -661,7 +661,7 @@ static int ipa3_wwan_add_ul_flt_rule_to_ipa(void)
}
param->commit = 1;
- param->ep = IPA_CLIENT_APPS_LAN_WAN_PROD;
+ param->ep = IPA_CLIENT_APPS_WAN_PROD;
param->global = false;
param->num_rules = (uint8_t)1;
@@ -700,7 +700,7 @@ static int ipa3_wwan_add_ul_flt_rule_to_ipa(void)
/* send ipa_fltr_installed_notif_req_msg_v01 to Q6*/
req->source_pipe_index =
- ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_WAN_PROD);
+ ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD);
req->install_status = QMI_RESULT_SUCCESS_V01;
req->rule_id_valid = 1;
req->rule_id_len = rmnet_ipa3_ctx->num_q6_rules;
@@ -850,14 +850,14 @@ static int ipa3_wwan_register_to_ipa(int index)
rx_ipv4_property->attrib.meta_data =
rmnet_ipa3_ctx->mux_channel[index].mux_id << WWAN_METADATA_SHFT;
rx_ipv4_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
- rx_ipv4_property->src_pipe = IPA_CLIENT_APPS_LAN_WAN_PROD;
+ rx_ipv4_property->src_pipe = IPA_CLIENT_APPS_WAN_PROD;
rx_ipv6_property = &rx_properties.prop[1];
rx_ipv6_property->ip = IPA_IP_v6;
rx_ipv6_property->attrib.attrib_mask |= IPA_FLT_META_DATA;
rx_ipv6_property->attrib.meta_data =
rmnet_ipa3_ctx->mux_channel[index].mux_id << WWAN_METADATA_SHFT;
rx_ipv6_property->attrib.meta_data_mask = WWAN_METADATA_MASK;
- rx_ipv6_property->src_pipe = IPA_CLIENT_APPS_LAN_WAN_PROD;
+ rx_ipv6_property->src_pipe = IPA_CLIENT_APPS_WAN_PROD;
rx_properties.num_props = 2;
pyld_sz = rmnet_ipa3_ctx->num_q6_rules *
@@ -1139,9 +1139,10 @@ send:
memset(&meta, 0, sizeof(meta));
meta.pkt_init_dst_ep_valid = true;
meta.pkt_init_dst_ep_remote = true;
- ret = ipa3_tx_dp(IPA_CLIENT_Q6_LAN_CONS, skb, &meta);
+ meta.pkt_init_dst_ep = IPA_CLIENT_Q6_LAN_CONS;
+ ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, &meta);
} else {
- ret = ipa3_tx_dp(IPA_CLIENT_APPS_LAN_WAN_PROD, skb, NULL);
+ ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
}
if (ret) {
@@ -1283,7 +1284,7 @@ static int handle3_ingress_format(struct net_device *dev,
IPA_ENABLE_CS_OFFLOAD_DL;
if ((in->u.data) & RMNET_IOCTL_INGRESS_FORMAT_AGG_DATA) {
- IPAWANERR("get AGG size %d count %d\n",
+ IPAWANDBG("get AGG size %d count %d\n",
in->u.ingress_format.agg_size,
in->u.ingress_format.agg_count);
@@ -1328,17 +1329,17 @@ static int handle3_ingress_format(struct net_device *dev,
ipa_wan_ep_cfg->desc_fifo_sz =
ipa3_rmnet_res.wan_rx_desc_size * sizeof(struct sps_iovec);
- mutex_lock(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
+ mutex_lock(&rmnet_ipa3_ctx->pipe_handle_guard);
if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
IPAWANDBG("In SSR sequence/recovery\n");
- mutex_unlock(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
+ mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
return -EFAULT;
}
ret = ipa3_setup_sys_pipe(&rmnet_ipa3_ctx->ipa_to_apps_ep_cfg,
&rmnet_ipa3_ctx->ipa3_to_apps_hdl);
- mutex_unlock(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
+ mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
if (ret)
IPAWANERR("failed to configure ingress\n");
@@ -1347,6 +1348,104 @@ static int handle3_ingress_format(struct net_device *dev,
}
/**
+ * handle3_egress_format() - Egress data format configuration
+ *
+ * Setup IPA egress system pipe and Configure:
+ * header handling, checksum, de-aggregation and fifo size
+ *
+ * @dev: network device
+ * @e: egress configuration
+ */
+static int handle3_egress_format(struct net_device *dev,
+ struct rmnet_ioctl_extended_s *e)
+{
+ int rc;
+ struct ipa_sys_connect_params *ipa_wan_ep_cfg;
+
+ IPAWANDBG("get RMNET_IOCTL_SET_EGRESS_DATA_FORMAT\n");
+ ipa_wan_ep_cfg = &rmnet_ipa3_ctx->apps_to_ipa_ep_cfg;
+ if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_CHECKSUM) {
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 8;
+ ipa_wan_ep_cfg->ipa_ep_cfg.cfg.cs_offload_en =
+ IPA_ENABLE_CS_OFFLOAD_UL;
+ ipa_wan_ep_cfg->ipa_ep_cfg.cfg.cs_metadata_hdr_offset = 1;
+ } else {
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4;
+ }
+
+ if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION) {
+ IPAWANERR("WAN UL Aggregation not supported!!\n");
+ WARN_ON(1);
+ return -EINVAL;
+ ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
+ ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr = IPA_QCMAP;
+
+ ipa_wan_ep_cfg->ipa_ep_cfg.deaggr.packet_offset_valid = false;
+
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 2;
+
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_valid =
+ true;
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad =
+ IPA_HDR_PAD;
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_pad_to_alignment =
+ 2;
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_payload_len_inc_padding =
+ true;
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_total_len_or_pad_offset =
+ 0;
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr_ext.hdr_little_endian =
+ false;
+ } else {
+ IPAWANDBG("WAN UL Aggregation disabled\n");
+ ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
+ }
+
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1;
+ /* modem want offset at 0! */
+ ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata = 0;
+
+ ipa_wan_ep_cfg->ipa_ep_cfg.mode.dst = IPA_CLIENT_APPS_WAN_PROD;
+ ipa_wan_ep_cfg->ipa_ep_cfg.mode.mode = IPA_BASIC;
+
+ ipa_wan_ep_cfg->client = IPA_CLIENT_APPS_WAN_PROD;
+ ipa_wan_ep_cfg->notify = apps_ipa_tx_complete_notify;
+ ipa_wan_ep_cfg->desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
+ ipa_wan_ep_cfg->priv = dev;
+
+ mutex_lock(&rmnet_ipa3_ctx->pipe_handle_guard);
+ if (atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
+ IPAWANDBG("In SSR sequence/recovery\n");
+ mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
+ return -EFAULT;
+ }
+ rc = ipa3_setup_sys_pipe(
+ ipa_wan_ep_cfg, &rmnet_ipa3_ctx->apps_to_ipa3_hdl);
+ if (rc) {
+ IPAWANERR("failed to config egress endpoint\n");
+ mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
+ return rc;
+ }
+ mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
+
+ if (rmnet_ipa3_ctx->num_q6_rules != 0) {
+ /* already got Q6 UL filter rules*/
+ if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt == false)
+ rc = ipa3_wwan_add_ul_flt_rule_to_ipa();
+ if (rc)
+ IPAWANERR("install UL rules failed\n");
+ else
+ rmnet_ipa3_ctx->a7_ul_flt_set = true;
+ } else {
+ /* wait Q6 UL filter rules*/
+ IPAWANDBG("no UL-rules\n");
+ }
+ rmnet_ipa3_ctx->egress_set = true;
+
+ return rc;
+}
+
+/**
* ipa3_wwan_ioctl() - I/O control for wwan network driver.
*
* @dev: network device
@@ -1507,7 +1606,7 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case RMNET_IOCTL_GET_EP_PAIR:
IPAWANDBG("get ioctl: RMNET_IOCTL_GET_EP_PAIR\n");
extend_ioctl_data.u.ipa_ep_pair.consumer_pipe_num =
- ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_WAN_PROD);
+ ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_PROD);
extend_ioctl_data.u.ipa_ep_pair.producer_pipe_num =
ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
if (copy_to_user((u8 *)ifr->ifr_ifru.ifru_data,
@@ -1593,72 +1692,7 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
rmnet_ipa3_ctx->rmnet_index++;
break;
case RMNET_IOCTL_SET_EGRESS_DATA_FORMAT:
- IPAWANDBG("get RMNET_IOCTL_SET_EGRESS_DATA_FORMAT\n");
- if ((extend_ioctl_data.u.data) &
- RMNET_IOCTL_EGRESS_FORMAT_CHECKSUM) {
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.
- ipa_ep_cfg.hdr.hdr_len = 8;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.
- ipa_ep_cfg.cfg.cs_offload_en =
- IPA_ENABLE_CS_OFFLOAD_UL;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.
- ipa_ep_cfg.cfg.cs_metadata_hdr_offset
- = 1;
- } else {
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.
- ipa_ep_cfg.hdr.hdr_len = 4;
- }
- if ((extend_ioctl_data.u.data) &
- RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION)
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.
- ipa_ep_cfg.aggr.aggr_en =
- IPA_ENABLE_AGGR;
- else
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.
- ipa_ep_cfg.aggr.aggr_en =
- IPA_BYPASS_AGGR;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.ipa_ep_cfg.hdr.
- hdr_ofst_metadata_valid = 1;
- /* modem want offset at 0! */
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.ipa_ep_cfg.hdr.
- hdr_ofst_metadata = 0;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.ipa_ep_cfg.mode.
- dst = IPA_CLIENT_APPS_LAN_WAN_PROD;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.ipa_ep_cfg.mode.
- mode = IPA_BASIC;
-
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.client =
- IPA_CLIENT_APPS_LAN_WAN_PROD;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.notify =
- apps_ipa_tx_complete_notify;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.desc_fifo_sz =
- IPA_SYS_TX_DATA_DESC_FIFO_SZ;
- rmnet_ipa3_ctx->apps_to_ipa_ep_cfg.priv = dev;
-
- rc = ipa3_setup_sys_pipe(
- &rmnet_ipa3_ctx->apps_to_ipa_ep_cfg,
- &rmnet_ipa3_ctx->apps_to_ipa3_hdl);
- if (rc)
- IPAWANERR("failed to config egress endpoint\n");
-
- if (rmnet_ipa3_ctx->num_q6_rules != 0) {
- /* already got Q6 UL filter rules*/
- if (ipa3_qmi_ctx->modem_cfg_emb_pipe_flt
- == false)
- rc = ipa3_wwan_add_ul_flt_rule_to_ipa();
- else
- rc = 0;
- rmnet_ipa3_ctx->egress_set = true;
- if (rc)
- IPAWANERR("install UL rules failed\n");
- else
- rmnet_ipa3_ctx->a7_ul_flt_set = true;
- } else {
- /* wait Q6 UL filter rules*/
- rmnet_ipa3_ctx->egress_set = true;
- IPAWANDBG("no UL-rules, egress_set(%d)\n",
- rmnet_ipa3_ctx->egress_set);
- }
+ rc = handle3_egress_format(dev, &extend_ioctl_data);
break;
case RMNET_IOCTL_SET_INGRESS_DATA_FORMAT:/* Set IDF */
rc = handle3_ingress_format(dev, &extend_ioctl_data);
@@ -2263,15 +2297,20 @@ static int ipa3_wwan_remove(struct platform_device *pdev)
int ret;
pr_info("rmnet_ipa started deinitialization\n");
- mutex_lock(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
+ mutex_lock(&rmnet_ipa3_ctx->pipe_handle_guard);
ret = ipa3_teardown_sys_pipe(rmnet_ipa3_ctx->ipa3_to_apps_hdl);
if (ret < 0)
IPAWANERR("Failed to teardown IPA->APPS pipe\n");
else
rmnet_ipa3_ctx->ipa3_to_apps_hdl = -1;
+ ret = ipa3_teardown_sys_pipe(rmnet_ipa3_ctx->apps_to_ipa3_hdl);
+ if (ret < 0)
+ IPAWANERR("Failed to teardown APPS->IPA pipe\n");
+ else
+ rmnet_ipa3_ctx->apps_to_ipa3_hdl = -1;
if (ipa3_rmnet_res.ipa_napi_enable)
netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
- mutex_unlock(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
+ mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
unregister_netdev(IPA_NETDEV());
ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
IPA_RM_RESOURCE_Q6_CONS);
@@ -3160,8 +3199,9 @@ static int __init ipa3_wwan_init(void)
atomic_set(&rmnet_ipa3_ctx->is_initialized, 0);
atomic_set(&rmnet_ipa3_ctx->is_ssr, 0);
- mutex_init(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
+ mutex_init(&rmnet_ipa3_ctx->pipe_handle_guard);
rmnet_ipa3_ctx->ipa3_to_apps_hdl = -1;
+ rmnet_ipa3_ctx->apps_to_ipa3_hdl = -1;
/* Register for Modem SSR */
rmnet_ipa3_ctx->subsys_notify_handle = subsys_notif_register_notifier(
SUBSYS_MODEM,
@@ -3175,7 +3215,7 @@ static int __init ipa3_wwan_init(void)
static void __exit ipa3_wwan_cleanup(void)
{
int ret;
- mutex_destroy(&rmnet_ipa3_ctx->ipa_to_apps_pipe_handle_guard);
+ mutex_destroy(&rmnet_ipa3_ctx->pipe_handle_guard);
ret = subsys_notif_unregister_notifier(
rmnet_ipa3_ctx->subsys_notify_handle, &ipa3_ssr_notifier);
if (ret)
diff --git a/drivers/platform/msm/mhi/mhi_ring_ops.c b/drivers/platform/msm/mhi/mhi_ring_ops.c
index a8521a7fe814..e5a6dd51f51a 100644
--- a/drivers/platform/msm/mhi/mhi_ring_ops.c
+++ b/drivers/platform/msm/mhi/mhi_ring_ops.c
@@ -19,7 +19,7 @@ static int add_element(struct mhi_ring *ring, void **rp,
uintptr_t d_wp = 0, d_rp = 0, ring_size = 0;
int r;
- if (0 == ring->el_size || NULL == ring
+ if (NULL == ring || 0 == ring->el_size
|| NULL == ring->base || 0 == ring->len) {
mhi_log(MHI_MSG_ERROR, "Bad input parameters, quitting.\n");
return -EINVAL;
@@ -77,7 +77,7 @@ int delete_element(struct mhi_ring *ring, void **rp,
uintptr_t d_wp = 0, d_rp = 0, ring_size = 0;
int r;
- if (0 == ring->el_size || NULL == ring ||
+ if (NULL == ring || 0 == ring->el_size ||
NULL == ring->base || 0 == ring->len)
return -EINVAL;
@@ -143,7 +143,7 @@ int get_nr_enclosed_el(struct mhi_ring *ring, void *rp,
uintptr_t ring_size = 0;
int r = 0;
- if (0 == ring->el_size || NULL == ring ||
+ if (NULL == ring || 0 == ring->el_size ||
NULL == ring->base || 0 == ring->len) {
mhi_log(MHI_MSG_ERROR, "Bad input parameters, quitting.\n");
return -EINVAL;
diff --git a/drivers/platform/msm/mhi/mhi_ssr.c b/drivers/platform/msm/mhi/mhi_ssr.c
index 856bb58fe013..8ee3deddbb95 100644
--- a/drivers/platform/msm/mhi/mhi_ssr.c
+++ b/drivers/platform/msm/mhi/mhi_ssr.c
@@ -179,7 +179,7 @@ static int set_mhi_base_state(struct mhi_pcie_dev_info *mhi_pcie_dev)
void mhi_link_state_cb(struct msm_pcie_notify *notify)
{
int ret_val = 0;
- struct mhi_pcie_dev_info *mhi_pcie_dev = notify->data;
+ struct mhi_pcie_dev_info *mhi_pcie_dev;
struct mhi_device_ctxt *mhi_dev_ctxt = NULL;
int r = 0;
@@ -188,6 +188,8 @@ void mhi_link_state_cb(struct msm_pcie_notify *notify)
"Incomplete handle received\n");
return;
}
+
+ mhi_pcie_dev = notify->data;
mhi_dev_ctxt = &mhi_pcie_dev->mhi_ctxt;
switch (notify->event) {
case MSM_PCIE_EVENT_LINKDOWN:
diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c
index e1bd39dfeb34..b8652770275e 100644
--- a/drivers/platform/msm/mhi/mhi_sys.c
+++ b/drivers/platform/msm/mhi/mhi_sys.c
@@ -53,16 +53,16 @@ static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf,
*offp = (u32)(*offp) % MHI_MAX_CHANNELS;
while (!valid_chan) {
- client_handle = mhi_dev_ctxt->client_handle_list[*offp];
if (*offp == (MHI_MAX_CHANNELS - 1))
msleep(1000);
if (!VALID_CHAN_NR(*offp) ||
!cc_list[*offp].mhi_trb_ring_base_addr ||
- !client_handle) {
+ !mhi_dev_ctxt->client_handle_list[*offp]) {
*offp += 1;
*offp = (u32)(*offp) % MHI_MAX_CHANNELS;
continue;
}
+ client_handle = mhi_dev_ctxt->client_handle_list[*offp];
valid_chan = 1;
}
diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c
index 9ae1b63a75c9..d6eb96a3e89e 100644
--- a/drivers/platform/msm/mhi_uci/mhi_uci.c
+++ b/drivers/platform/msm/mhi_uci/mhi_uci.c
@@ -623,17 +623,20 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
struct file *file_handle)
{
struct uci_client *uci_handle = file_handle->private_data;
- struct mhi_uci_ctxt_t *uci_ctxt = uci_handle->uci_ctxt;
+ struct mhi_uci_ctxt_t *uci_ctxt;
u32 nr_in_bufs = 0;
int in_chan = 0;
int i = 0;
u32 buf_size = 0;
+
+ if (uci_handle == NULL)
+ return -EINVAL;
+
+ uci_ctxt = uci_handle->uci_ctxt;
in_chan = iminor(mhi_inode) + 1;
nr_in_bufs = uci_ctxt->chan_attrib[in_chan].nr_trbs;
buf_size = uci_ctxt->chan_attrib[in_chan].max_packet_size;
- if (uci_handle == NULL)
- return -EINVAL;
if (atomic_sub_return(1, &uci_handle->ref_count) == 0) {
uci_log(UCI_DBG_ERROR,
"Last client left, closing channel 0x%x\n",
@@ -1021,14 +1024,15 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info)
u32 client_index;
struct mhi_result *result;
- if (!cb_info)
+ if (!cb_info || !cb_info->result) {
uci_log(UCI_DBG_CRITICAL, "Bad CB info from MHI.\n");
- if (cb_info->result) {
- chan_nr = (uintptr_t)cb_info->result->user_data;
- client_index = CHAN_TO_CLIENT(chan_nr);
- uci_handle =
- &uci_ctxt.client_handles[client_index];
+ return;
}
+
+ chan_nr = (uintptr_t)cb_info->result->user_data;
+ client_index = CHAN_TO_CLIENT(chan_nr);
+ uci_handle = &uci_ctxt.client_handles[client_index];
+
switch (cb_info->cb_reason) {
case MHI_CB_MHI_ENABLED:
atomic_set(&uci_handle->mhi_disabled, 0);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 55ab6177e6db..201a53e66ef0 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -60,7 +60,7 @@ static ssize_t power_supply_show_property(struct device *dev,
"Unknown", "Good", "Overheat", "Dead", "Over voltage",
"Unspecified failure", "Cold", "Watchdog timer expire",
"Safety timer expire",
- "Warm", "Cool"
+ "Warm", "Cool", "Hot"
};
static char *technology_text[] = {
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
@@ -122,6 +122,10 @@ static ssize_t power_supply_show_property(struct device *dev,
return sprintf(buf, "%s\n", typec_text[value.intval]);
else if (off == POWER_SUPPLY_PROP_TYPEC_POWER_ROLE)
return sprintf(buf, "%s\n", typec_pr_text[value.intval]);
+ else if (off == POWER_SUPPLY_PROP_DIE_HEALTH)
+ return sprintf(buf, "%s\n", health_text[value.intval]);
+ else if (off == POWER_SUPPLY_PROP_CONNECTOR_HEALTH)
+ return sprintf(buf, "%s\n", health_text[value.intval]);
else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
return sprintf(buf, "%s\n", value.strval);
@@ -235,6 +239,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(input_current_max),
POWER_SUPPLY_ATTR(input_current_trim),
POWER_SUPPLY_ATTR(input_current_settled),
+ POWER_SUPPLY_ATTR(input_voltage_settled),
POWER_SUPPLY_ATTR(bypass_vchg_loop_debouncer),
POWER_SUPPLY_ATTR(charge_counter_shadow),
POWER_SUPPLY_ATTR(hi_power),
@@ -259,6 +264,8 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(dp_dm),
POWER_SUPPLY_ATTR(input_current_limited),
POWER_SUPPLY_ATTR(input_current_now),
+ POWER_SUPPLY_ATTR(current_qnovo),
+ POWER_SUPPLY_ATTR(voltage_qnovo),
POWER_SUPPLY_ATTR(rerun_aicl),
POWER_SUPPLY_ATTR(cycle_count_id),
POWER_SUPPLY_ATTR(safety_timer_expired),
@@ -282,7 +289,9 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(fcc_delta),
POWER_SUPPLY_ATTR(icl_reduction),
POWER_SUPPLY_ATTR(parallel_mode),
- POWER_SUPPLY_ATTR(connector_therm_zone),
+ POWER_SUPPLY_ATTR(die_health),
+ POWER_SUPPLY_ATTR(connector_health),
+ POWER_SUPPLY_ATTR(ctm_current_max),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index efa88c239379..35dc3842017b 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -247,12 +247,11 @@ done:
* FCC *
**********/
#define EFFICIENCY_PCT 80
-#define MICRO_5V 5000000
static void split_fcc(struct pl_data *chip, int total_ua,
int *master_ua, int *slave_ua)
{
int rc, effective_total_ua, slave_limited_ua, hw_cc_delta_ua = 0,
- aicl_settled_ua, input_limited_fcc_ua;
+ icl_ua, adapter_uv, bcl_ua;
union power_supply_propval pval = {0, };
rc = power_supply_get_property(chip->main_psy,
@@ -262,24 +261,30 @@ static void split_fcc(struct pl_data *chip, int total_ua,
else
hw_cc_delta_ua = pval.intval;
- input_limited_fcc_ua = INT_MAX;
+ bcl_ua = INT_MAX;
if (chip->pl_mode == POWER_SUPPLY_PARALLEL_MID_MID) {
rc = power_supply_get_property(chip->main_psy,
- POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
- &pval);
- if (rc < 0)
- aicl_settled_ua = 0;
- else
- aicl_settled_ua = pval.intval;
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get aicl settled value rc=%d\n", rc);
+ return;
+ }
+ icl_ua = pval.intval;
- input_limited_fcc_ua = div64_s64(
- (s64)aicl_settled_ua * MICRO_5V * EFFICIENCY_PCT,
- (s64)get_effective_result(chip->fv_votable)
- * 100);
+ rc = power_supply_get_property(chip->main_psy,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get adaptive voltage rc=%d\n", rc);
+ return;
+ }
+ adapter_uv = pval.intval;
+
+ bcl_ua = div64_s64((s64)icl_ua * adapter_uv * EFFICIENCY_PCT,
+ (s64)get_effective_result(chip->fv_votable) * 100);
}
effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
- slave_limited_ua = min(effective_total_ua, input_limited_fcc_ua);
+ slave_limited_ua = min(effective_total_ua, bcl_ua);
*slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
*slave_ua = (*slave_ua * chip->taper_pct) / 100;
*master_ua = max(0, total_ua - *slave_ua);
@@ -298,6 +303,19 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
if (!chip->main_psy)
return 0;
+ if (chip->batt_psy) {
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CURRENT_QNOVO,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get qnovo fcc, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (pval.intval != -EINVAL)
+ total_fcc_ua = pval.intval;
+ }
+
if (chip->pl_mode == POWER_SUPPLY_PARALLEL_NONE
|| get_effective_result_locked(chip->pl_disable_votable)) {
pval.intval = total_fcc_ua;
@@ -343,6 +361,7 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
struct pl_data *chip = data;
union power_supply_propval pval = {0, };
int rc = 0;
+ int effective_fv_uv = fv_uv;
if (fv_uv < 0)
return 0;
@@ -350,7 +369,21 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
if (!chip->main_psy)
return 0;
- pval.intval = fv_uv;
+ if (chip->batt_psy) {
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get qnovo fv, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (pval.intval != -EINVAL)
+ effective_fv_uv = pval.intval;
+ }
+
+ pval.intval = effective_fv_uv;
+
rc = power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
if (rc < 0) {
@@ -359,7 +392,7 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
}
if (chip->pl_mode != POWER_SUPPLY_PARALLEL_NONE) {
- pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
+ pval.intval += PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
rc = power_supply_set_property(chip->pl_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
if (rc < 0) {
@@ -514,9 +547,9 @@ static bool is_parallel_available(struct pl_data *chip)
return false;
}
/*
- * Note that pl_mode only be udpated to anything other than a _NONE
+ * Note that pl_mode will be updated to anything other than a _NONE
* only after pl_psy is found. IOW pl_mode != _NONE implies that
- * pl_psy is present and valid
+ * pl_psy is present and valid.
*/
chip->pl_mode = pval.intval;
vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 0d3fcc2ede86..c146654e438b 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -71,6 +71,10 @@
#define KI_COEFF_MAX 62200
#define KI_COEFF_SOC_LEVELS 3
+#define SLOPE_LIMIT_COEFF_MAX 31
+
+#define BATT_THERM_NUM_COEFFS 3
+
/* Debug flag definitions */
enum fg_debug_flag {
FG_IRQ = BIT(0), /* Show interrupts */
@@ -164,6 +168,7 @@ enum fg_sram_param_id {
FG_SRAM_KI_COEFF_HI_DISCHG,
FG_SRAM_ESR_TIGHT_FILTER,
FG_SRAM_ESR_BROAD_FILTER,
+ FG_SRAM_SLOPE_LIMIT,
FG_SRAM_MAX,
};
@@ -202,6 +207,14 @@ enum wa_flags {
PMI8998_V1_REV_WA = BIT(0),
};
+enum slope_limit_status {
+ LOW_TEMP_DISCHARGE = 0,
+ LOW_TEMP_CHARGE,
+ HIGH_TEMP_DISCHARGE,
+ HIGH_TEMP_CHARGE,
+ SLOPE_LIMIT_NUM_COEFFS,
+};
+
/* DT parameters for FG device */
struct fg_dt_props {
bool force_load_profile;
@@ -234,10 +247,13 @@ struct fg_dt_props {
int esr_broad_flt_upct;
int esr_tight_lt_flt_upct;
int esr_broad_lt_flt_upct;
+ int slope_limit_temp;
int jeita_thresholds[NUM_JEITA_LEVELS];
int ki_coeff_soc[KI_COEFF_SOC_LEVELS];
int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
int ki_coeff_hi_dischg[KI_COEFF_SOC_LEVELS];
+ int slope_limit_coeffs[SLOPE_LIMIT_NUM_COEFFS];
+ u8 batt_therm_coeffs[BATT_THERM_NUM_COEFFS];
};
/* parameters from battery profile */
@@ -341,6 +357,7 @@ struct fg_chip {
int maint_soc;
int delta_soc;
int last_msoc;
+ enum slope_limit_status slope_limit_sts;
bool profile_available;
bool profile_loaded;
bool battery_missing;
@@ -352,6 +369,7 @@ struct fg_chip {
bool soc_reporting_ready;
bool esr_flt_cold_temp_en;
bool bsoc_delta_irq_en;
+ bool slope_limit_en;
struct completion soc_update;
struct completion soc_ready;
struct delayed_work profile_load_work;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 1015ab73ac11..1fd092c550f3 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -31,6 +31,8 @@
#define FG_MEM_INFO_PMI8998 0x0D
/* SRAM address and offset in ascending order */
+#define SLOPE_LIMIT_WORD 3
+#define SLOPE_LIMIT_OFFSET 0
#define CUTOFF_VOLT_WORD 5
#define CUTOFF_VOLT_OFFSET 0
#define SYS_TERM_CURR_WORD 6
@@ -220,6 +222,8 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = {
1, 512, 1000000, 0, fg_encode_default, NULL),
PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
1, 512, 1000000, 0, fg_encode_default, NULL),
+ PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
+ 0, fg_encode_default, NULL),
};
static struct fg_sram_param pmi8998_v2_sram_params[] = {
@@ -286,6 +290,8 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
1, 512, 1000000, 0, fg_encode_default, NULL),
PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
1, 512, 1000000, 0, fg_encode_default, NULL),
+ PARAM(SLOPE_LIMIT, SLOPE_LIMIT_WORD, SLOPE_LIMIT_OFFSET, 1, 8192, 1000,
+ 0, fg_encode_default, NULL),
};
static struct fg_alg_flag pmi8998_v1_alg_flags[] = {
@@ -1770,6 +1776,48 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip)
return 0;
}
+static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
+{
+ enum slope_limit_status status;
+ int rc;
+ u8 buf;
+
+ if (!chip->slope_limit_en)
+ return 0;
+
+ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
+ chip->charge_status == POWER_SUPPLY_STATUS_FULL) {
+ if (batt_temp < chip->dt.slope_limit_temp)
+ status = LOW_TEMP_CHARGE;
+ else
+ status = HIGH_TEMP_CHARGE;
+ } else {
+ if (batt_temp < chip->dt.slope_limit_temp)
+ status = LOW_TEMP_DISCHARGE;
+ else
+ status = HIGH_TEMP_DISCHARGE;
+ }
+
+ if (chip->slope_limit_sts == status)
+ return 0;
+
+ fg_encode(chip->sp, FG_SRAM_SLOPE_LIMIT,
+ chip->dt.slope_limit_coeffs[status], &buf);
+ rc = fg_sram_write(chip, chip->sp[FG_SRAM_SLOPE_LIMIT].addr_word,
+ chip->sp[FG_SRAM_SLOPE_LIMIT].addr_byte, &buf,
+ chip->sp[FG_SRAM_SLOPE_LIMIT].len, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in configuring slope_limit coefficient, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ chip->slope_limit_sts = status;
+ fg_dbg(chip, FG_STATUS, "Slope limit status: %d value: %x\n", status,
+ buf);
+ return 0;
+}
+
static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
{
u8 esr_tight_lt_flt, esr_broad_lt_flt;
@@ -1918,7 +1966,7 @@ static void status_change_work(struct work_struct *work)
struct fg_chip *chip = container_of(work,
struct fg_chip, status_change_work);
union power_supply_propval prop = {0, };
- int rc;
+ int rc, batt_temp;
if (!batt_psy_initialized(chip)) {
fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
@@ -1971,6 +2019,14 @@ static void status_change_work(struct work_struct *work)
if (rc < 0)
pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
+ rc = fg_get_battery_temp(chip, &batt_temp);
+ if (!rc) {
+ rc = fg_slope_limit_config(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring slope limiter rc:%d\n",
+ rc);
+ }
+
fg_batt_avg_update(chip);
out:
@@ -2316,7 +2372,8 @@ static void sram_dump_work(struct work_struct *work)
sram_dump_work.work);
u8 buf[FG_SRAM_LEN];
int rc;
- s64 timestamp_ms;
+ s64 timestamp_ms, quotient;
+ s32 remainder;
rc = fg_sram_read(chip, 0, 0, buf, FG_SRAM_LEN, FG_IMA_DEFAULT);
if (rc < 0) {
@@ -2325,12 +2382,14 @@ static void sram_dump_work(struct work_struct *work)
}
timestamp_ms = ktime_to_ms(ktime_get_boottime());
- fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%lld\n",
- timestamp_ms / 1000, timestamp_ms % 1000);
+ quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
+ fg_dbg(chip, FG_STATUS, "SRAM Dump Started at %lld.%d\n",
+ quotient, remainder);
dump_sram(buf, 0, FG_SRAM_LEN);
timestamp_ms = ktime_to_ms(ktime_get_boottime());
- fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%lld\n",
- timestamp_ms / 1000, timestamp_ms % 1000);
+ quotient = div_s64_rem(timestamp_ms, 1000, &remainder);
+ fg_dbg(chip, FG_STATUS, "SRAM Dump done at %lld.%d\n",
+ quotient, remainder);
resched:
schedule_delayed_work(&chip->sram_dump_work,
msecs_to_jiffies(fg_sram_dump_period_ms));
@@ -2983,6 +3042,21 @@ static int fg_hw_init(struct fg_chip *chip)
}
}
+ /*
+ * configure battery thermal coefficients c1,c2,c3
+ * if its value is not zero.
+ */
+ if (chip->dt.batt_therm_coeffs[0] > 0) {
+ rc = fg_write(chip, BATT_INFO_THERM_C1(chip),
+ chip->dt.batt_therm_coeffs, BATT_THERM_NUM_COEFFS);
+ if (rc < 0) {
+ pr_err("Error in writing battery thermal coefficients, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+
if (chip->dt.recharge_soc_thr > 0 && chip->dt.recharge_soc_thr < 100) {
rc = fg_set_recharge_soc(chip, chip->dt.recharge_soc_thr);
if (rc < 0) {
@@ -3218,6 +3292,10 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
if (rc < 0)
pr_err("Error in configuring ESR filter rc:%d\n", rc);
+ rc = fg_slope_limit_config(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring slope limiter rc:%d\n", rc);
+
if (!batt_psy_initialized(chip)) {
chip->last_batt_temp = batt_temp;
return IRQ_HANDLED;
@@ -3455,6 +3533,40 @@ static int fg_register_interrupts(struct fg_chip *chip)
return 0;
}
+static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
+{
+ struct device_node *node = chip->dev->of_node;
+ int rc, i;
+
+ rc = of_property_read_u32(node, "qcom,slope-limit-temp-threshold",
+ &chip->dt.slope_limit_temp);
+ if (rc < 0)
+ return 0;
+
+ rc = of_property_count_elems_of_size(node, "qcom,slope-limit-coeffs",
+ sizeof(u32));
+ if (rc != SLOPE_LIMIT_NUM_COEFFS)
+ return -EINVAL;
+
+ rc = of_property_read_u32_array(node, "qcom,slope-limit-coeffs",
+ chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
+ if (rc < 0) {
+ pr_err("Error in reading qcom,slope-limit-coeffs, rc=%d\n", rc);
+ return rc;
+ }
+
+ for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
+ if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
+ chip->dt.slope_limit_coeffs[i] < 0) {
+ pr_err("Incorrect slope limit coefficient\n");
+ return -EINVAL;
+ }
+ }
+
+ chip->slope_limit_en = true;
+ return 0;
+}
+
static int fg_parse_ki_coefficients(struct fg_chip *chip)
{
struct device_node *node = chip->dev->of_node;
@@ -3717,6 +3829,18 @@ static int fg_parse_dt(struct fg_chip *chip)
rc);
}
+ if (of_property_count_elems_of_size(node,
+ "qcom,battery-thermal-coefficients",
+ sizeof(u8)) == BATT_THERM_NUM_COEFFS) {
+ rc = of_property_read_u8_array(node,
+ "qcom,battery-thermal-coefficients",
+ chip->dt.batt_therm_coeffs,
+ BATT_THERM_NUM_COEFFS);
+ if (rc < 0)
+ pr_warn("Error reading battery thermal coefficients, rc:%d\n",
+ rc);
+ }
+
rc = of_property_read_u32(node, "qcom,fg-esr-timer-charging", &temp);
if (rc < 0)
chip->dt.esr_timer_charging = -EINVAL;
@@ -3843,6 +3967,11 @@ static int fg_parse_dt(struct fg_chip *chip)
chip->dt.esr_broad_lt_flt_upct = DEFAULT_ESR_BROAD_LT_FLT_UPCT;
else
chip->dt.esr_broad_lt_flt_upct = temp;
+
+ rc = fg_parse_slope_limit_coefficients(chip);
+ if (rc < 0)
+ pr_err("Error in parsing slope limit coeffs, rc=%d\n", rc);
+
return 0;
}
diff --git a/drivers/power/supply/qcom/qpnp-fg.c b/drivers/power/supply/qcom/qpnp-fg.c
index e4a8ade80d4f..cfd2f64a9bb8 100644
--- a/drivers/power/supply/qcom/qpnp-fg.c
+++ b/drivers/power/supply/qcom/qpnp-fg.c
@@ -549,6 +549,7 @@ struct fg_trans {
struct fg_chip *chip;
struct fg_log_buffer *log; /* log buffer */
u8 *data; /* fg data that is read */
+ struct mutex memif_dfs_lock; /* Prevent thread concurrency */
};
struct fg_dbgfs {
@@ -5730,6 +5731,7 @@ static int fg_memif_data_open(struct inode *inode, struct file *file)
trans->addr = dbgfs_data.addr;
trans->chip = dbgfs_data.chip;
trans->offset = trans->addr;
+ mutex_init(&trans->memif_dfs_lock);
file->private_data = trans;
return 0;
@@ -5741,6 +5743,7 @@ static int fg_memif_dfs_close(struct inode *inode, struct file *file)
if (trans && trans->log && trans->data) {
file->private_data = NULL;
+ mutex_destroy(&trans->memif_dfs_lock);
kfree(trans->log);
kfree(trans->data);
kfree(trans);
@@ -5898,10 +5901,13 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf,
size_t ret;
size_t len;
+ mutex_lock(&trans->memif_dfs_lock);
/* Is the the log buffer empty */
if (log->rpos >= log->wpos) {
- if (get_log_data(trans) <= 0)
- return 0;
+ if (get_log_data(trans) <= 0) {
+ len = 0;
+ goto unlock_mutex;
+ }
}
len = min(count, log->wpos - log->rpos);
@@ -5909,7 +5915,8 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf,
ret = copy_to_user(buf, &log->data[log->rpos], len);
if (ret == len) {
pr_err("error copy sram register values to user\n");
- return -EFAULT;
+ len = -EFAULT;
+ goto unlock_mutex;
}
/* 'ret' is the number of bytes not copied */
@@ -5917,6 +5924,9 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf,
*ppos += len;
log->rpos += len;
+
+unlock_mutex:
+ mutex_unlock(&trans->memif_dfs_lock);
return len;
}
@@ -5937,14 +5947,20 @@ static ssize_t fg_memif_dfs_reg_write(struct file *file, const char __user *buf,
int cnt = 0;
u8 *values;
size_t ret = 0;
+ char *kbuf;
+ u32 offset;
struct fg_trans *trans = file->private_data;
- u32 offset = trans->offset;
+
+ mutex_lock(&trans->memif_dfs_lock);
+ offset = trans->offset;
/* Make a copy of the user data */
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
+ kbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
ret = copy_from_user(kbuf, buf, count);
if (ret == count) {
@@ -5995,6 +6011,8 @@ static ssize_t fg_memif_dfs_reg_write(struct file *file, const char __user *buf,
free_buf:
kfree(kbuf);
+unlock_mutex:
+ mutex_unlock(&trans->memif_dfs_lock);
return ret;
}
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index 078bbaaad5a2..d36db8d8f3f1 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -148,8 +148,6 @@ struct qnovo {
struct work_struct status_change_work;
int fv_uV_request;
int fcc_uA_request;
- struct votable *fcc_max_votable;
- struct votable *fv_votable;
};
static int debug_mask;
@@ -226,6 +224,50 @@ unlock:
return rc;
}
+static bool is_batt_available(struct qnovo *chip)
+{
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+
+ if (!chip->batt_psy)
+ return false;
+
+ return true;
+}
+
+static int qnovo_batt_psy_update(struct qnovo *chip, bool disable)
+{
+ union power_supply_propval pval = {0};
+ int rc = 0;
+
+ if (!is_batt_available(chip))
+ return -EINVAL;
+
+ if (chip->fv_uV_request != -EINVAL) {
+ pval.intval = disable ? -EINVAL : chip->fv_uV_request;
+ rc = power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set prop qnovo_fv rc = %d\n", rc);
+ return -EINVAL;
+ }
+ }
+
+ if (chip->fcc_uA_request != -EINVAL) {
+ pval.intval = disable ? -EINVAL : chip->fcc_uA_request;
+ rc = power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CURRENT_QNOVO,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set prop qnovo_fcc rc = %d\n", rc);
+ return -EINVAL;
+ }
+ }
+
+ return rc;
+}
+
static int qnovo_disable_cb(struct votable *votable, void *data, int disable,
const char *client)
{
@@ -233,15 +275,9 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable,
int rc = 0;
if (disable) {
- if (chip->fv_uV_request != -EINVAL) {
- if (chip->fv_votable)
- vote(chip->fv_votable, QNOVO_VOTER, false, 0);
- }
- if (chip->fcc_uA_request != -EINVAL) {
- if (chip->fcc_max_votable)
- vote(chip->fcc_max_votable, QNOVO_VOTER,
- false, 0);
- }
+ rc = qnovo_batt_psy_update(chip, true);
+ if (rc < 0)
+ return rc;
}
rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
@@ -253,20 +289,9 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable,
}
if (!disable) {
- if (chip->fv_uV_request != -EINVAL) {
- if (!chip->fv_votable)
- chip->fv_votable = find_votable("FV");
- if (chip->fv_votable)
- vote(chip->fv_votable, QNOVO_VOTER,
- true, chip->fv_uV_request);
- }
- if (chip->fcc_uA_request != -EINVAL) {
- if (!chip->fcc_max_votable)
- chip->fcc_max_votable = find_votable("FCC_MAX");
- if (chip->fcc_max_votable)
- vote(chip->fcc_max_votable, QNOVO_VOTER,
- true, chip->fcc_uA_request);
- }
+ rc = qnovo_batt_psy_update(chip, false);
+ if (rc < 0)
+ return rc;
}
return rc;
@@ -817,7 +842,7 @@ static ssize_t current_show(struct class *c, struct class_attribute *attr,
}
comp_val_nA = div_s64(regval_nA * gain, 1000000) + offset_nA;
- comp_val_uA = comp_val_nA / 1000;
+ comp_val_uA = div_s64(comp_val_nA, 1000);
return snprintf(ubuf, PAGE_SIZE, "%d%s\n",
comp_val_uA, params[i].units_str);
@@ -848,7 +873,7 @@ static ssize_t voltage_show(struct class *c, struct class_attribute *attr,
gain = chip->v_gain_mega;
comp_val_nV = div_s64(regval_nV * gain, 1000000) + offset_nV;
- comp_val_uV = comp_val_nV / 1000;
+ comp_val_uV = div_s64(comp_val_nV, 1000);
return snprintf(ubuf, PAGE_SIZE, "%d%s\n",
comp_val_uV, params[i].units_str);
@@ -979,10 +1004,7 @@ static ssize_t batt_prop_show(struct class *c, struct class_attribute *attr,
int prop = params[i].start_addr;
union power_supply_propval pval = {0};
- if (!chip->batt_psy)
- chip->batt_psy = power_supply_get_by_name("battery");
-
- if (!chip->batt_psy)
+ if (!is_batt_available(chip))
return -EINVAL;
rc = power_supply_get_property(chip->batt_psy, prop, &pval);
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 3bfab47dd6c9..b51ce758a16b 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -16,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/power_supply.h>
-#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/qpnp/qpnp-revid.h>
@@ -387,6 +386,8 @@ static int smb2_parse_dt(struct smb2 *chip)
chg->dcp_icl_ua = chip->dt.usb_icl_ua;
+ chg->suspend_input_on_debug_batt = of_property_read_bool(node,
+ "qcom,suspend-input-on-debug-batt");
return 0;
}
@@ -412,6 +413,7 @@ static enum power_supply_property smb2_usb_props[] = {
POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
POWER_SUPPLY_PROP_BOOST_CURRENT,
POWER_SUPPLY_PROP_PE_START,
+ POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -497,6 +499,9 @@ static int smb2_usb_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_PE_START:
rc = smblib_get_pe_start(chg, val);
break;
+ case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+ val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER);
+ break;
default:
pr_err("get prop %d is not supported in usb\n", psp);
rc = -EINVAL;
@@ -545,6 +550,10 @@ static int smb2_usb_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_BOOST_CURRENT:
rc = smblib_set_prop_boost_current(chg, val);
break;
+ case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
+ rc = vote(chg->usb_icl_votable, CTM_VOTER,
+ val->intval >= 0, val->intval);
+ break;
default:
pr_err("set prop %d is not supported\n", psp);
rc = -EINVAL;
@@ -558,7 +567,9 @@ static int smb2_usb_prop_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
+ case POWER_SUPPLY_PROP_CTM_CURRENT_MAX:
return 1;
default:
break;
@@ -603,6 +614,7 @@ static enum power_supply_property smb2_usb_main_props[] = {
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_TYPE,
POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
POWER_SUPPLY_PROP_FCC_DELTA,
/*
* TODO move the TEMP and TEMP_MAX properties here,
@@ -635,6 +647,9 @@ static int smb2_usb_main_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
rc = smblib_get_prop_input_current_settled(chg, val);
break;
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED:
+ rc = smblib_get_prop_input_voltage_settled(chg, val);
+ break;
case POWER_SUPPLY_PROP_FCC_DELTA:
rc = smblib_get_prop_fcc_delta(chg, val);
break;
@@ -663,8 +678,7 @@ static int smb2_usb_main_set_prop(struct power_supply *psy,
rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
break;
case POWER_SUPPLY_PROP_ICL_REDUCTION:
- chg->icl_reduction_ua = val->intval;
- rc = rerun_election(chg->usb_icl_votable);
+ rc = smblib_set_icl_reduction(chg, val->intval);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
@@ -833,6 +847,7 @@ static enum power_supply_property smb2_batt_props[] = {
POWER_SUPPLY_PROP_CHARGE_DONE,
POWER_SUPPLY_PROP_PARALLEL_DISABLE,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
+ POWER_SUPPLY_PROP_DIE_HEALTH,
};
static int smb2_batt_get_prop(struct power_supply *psy,
@@ -885,11 +900,17 @@ static int smb2_batt_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
val->intval = get_client_vote(chg->fv_votable, DEFAULT_VOTER);
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
+ val->intval = chg->qnovo_fv_uv;
+ break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
rc = smblib_get_prop_batt_current_now(chg, val);
break;
+ case POWER_SUPPLY_PROP_CURRENT_QNOVO:
+ val->intval = chg->qnovo_fcc_ua;
+ break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- val->intval = get_client_vote(chg->fcc_max_votable,
+ val->intval = get_client_vote(chg->fcc_votable,
DEFAULT_VOTER);
break;
case POWER_SUPPLY_PROP_TEMP:
@@ -909,6 +930,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
/* Not in ship mode as long as device is active */
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_DIE_HEALTH:
+ rc = smblib_get_prop_die_health(chg, val);
+ break;
default:
pr_err("batt power supply prop %d not supported\n", psp);
return -EINVAL;
@@ -945,8 +969,16 @@ static int smb2_batt_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
vote(chg->fv_votable, DEFAULT_VOTER, true, val->intval);
break;
+ case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
+ chg->qnovo_fv_uv = val->intval;
+ rc = rerun_election(chg->fv_votable);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_QNOVO:
+ chg->qnovo_fcc_ua = val->intval;
+ rc = rerun_election(chg->fcc_votable);
+ break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- vote(chg->fcc_max_votable, DEFAULT_VOTER, true, val->intval);
+ vote(chg->fcc_votable, DEFAULT_VOTER, true, val->intval);
break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as the device is active */
@@ -1316,9 +1348,10 @@ static int smb2_init_hw(struct smb2 *chip)
if (chip->dt.fv_uv < 0)
smblib_get_charge_param(chg, &chg->param.fv, &chip->dt.fv_uv);
+ smblib_get_charge_param(chg, &chg->param.usb_icl,
+ &chg->default_icl_ua);
if (chip->dt.usb_icl_ua < 0)
- smblib_get_charge_param(chg, &chg->param.usb_icl,
- &chip->dt.usb_icl_ua);
+ chip->dt.usb_icl_ua = chg->default_icl_ua;
if (chip->dt.dc_icl_ua < 0)
smblib_get_charge_param(chg, &chg->param.dc_icl,
@@ -1357,11 +1390,12 @@ static int smb2_init_hw(struct smb2 *chip)
}
/* votes must be cast before configuring software control */
- vote(chg->usb_suspend_votable,
+ /* vote 0mA on usb_icl for non battery platforms */
+ vote(chg->usb_icl_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0);
vote(chg->dc_suspend_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0);
- vote(chg->fcc_max_votable,
+ vote(chg->fcc_votable,
DEFAULT_VOTER, true, chip->dt.fcc_ua);
vote(chg->fv_votable,
DEFAULT_VOTER, true, chip->dt.fv_uv);
@@ -1580,6 +1614,7 @@ static int smb2_chg_config_init(struct smb2 *chip)
switch (pmic_rev_id->pmic_subtype) {
case PMI8998_SUBTYPE:
+ chip->chg.smb_version = PMI8998_SUBTYPE;
chip->chg.wa_flags |= BOOST_BACK_WA;
if (pmic_rev_id->rev4 == PMI8998_V1P1_REV4) /* PMI rev 1.1 */
chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT;
@@ -1594,6 +1629,7 @@ static int smb2_chg_config_init(struct smb2 *chip)
chg->chg_freq.freq_above_otg_threshold = 800;
break;
case PM660_SUBTYPE:
+ chip->chg.smb_version = PM660_SUBTYPE;
chip->chg.wa_flags |= BOOST_BACK_WA;
chg->param.freq_buck = pm660_params.freq_buck;
chg->param.freq_boost = pm660_params.freq_boost;
@@ -1640,180 +1676,172 @@ static int smb2_determine_initial_status(struct smb2 *chip)
* INTERRUPT REGISTRATION *
**************************/
-struct smb2_irq_info {
- const char *name;
- const irq_handler_t handler;
- const bool wake;
- const struct storm_watch storm_data;
- int irq;
-};
-
-static struct smb2_irq_info smb2_irqs[] = {
+static struct smb_irq_info smb2_irqs[] = {
/* CHARGER IRQs */
- {
+ [CHG_ERROR_IRQ] = {
.name = "chg-error",
.handler = smblib_handle_debug,
},
- {
+ [CHG_STATE_CHANGE_IRQ] = {
.name = "chg-state-change",
.handler = smblib_handle_chg_state_change,
.wake = true,
},
- {
+ [STEP_CHG_STATE_CHANGE_IRQ] = {
.name = "step-chg-state-change",
.handler = smblib_handle_step_chg_state_change,
.wake = true,
},
- {
+ [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
.name = "step-chg-soc-update-fail",
.handler = smblib_handle_step_chg_soc_update_fail,
.wake = true,
},
- {
+ [STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
.name = "step-chg-soc-update-request",
.handler = smblib_handle_step_chg_soc_update_request,
.wake = true,
},
/* OTG IRQs */
- {
+ [OTG_FAIL_IRQ] = {
.name = "otg-fail",
.handler = smblib_handle_debug,
},
- {
+ [OTG_OVERCURRENT_IRQ] = {
.name = "otg-overcurrent",
.handler = smblib_handle_otg_overcurrent,
},
- {
+ [OTG_OC_DIS_SW_STS_IRQ] = {
.name = "otg-oc-dis-sw-sts",
.handler = smblib_handle_debug,
},
- {
+ [TESTMODE_CHANGE_DET_IRQ] = {
.name = "testmode-change-detect",
.handler = smblib_handle_debug,
},
/* BATTERY IRQs */
- {
+ [BATT_TEMP_IRQ] = {
.name = "bat-temp",
.handler = smblib_handle_batt_temp_changed,
},
- {
+ [BATT_OCP_IRQ] = {
.name = "bat-ocp",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_OV_IRQ] = {
.name = "bat-ov",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_LOW_IRQ] = {
.name = "bat-low",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_THERM_ID_MISS_IRQ] = {
.name = "bat-therm-or-id-missing",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_TERM_MISS_IRQ] = {
.name = "bat-terminal-missing",
.handler = smblib_handle_batt_psy_changed,
},
/* USB INPUT IRQs */
- {
+ [USBIN_COLLAPSE_IRQ] = {
.name = "usbin-collapse",
.handler = smblib_handle_debug,
},
- {
+ [USBIN_LT_3P6V_IRQ] = {
.name = "usbin-lt-3p6v",
.handler = smblib_handle_debug,
},
- {
+ [USBIN_UV_IRQ] = {
.name = "usbin-uv",
- .handler = smblib_handle_debug,
+ .handler = smblib_handle_usbin_uv,
},
- {
+ [USBIN_OV_IRQ] = {
.name = "usbin-ov",
.handler = smblib_handle_debug,
},
- {
+ [USBIN_PLUGIN_IRQ] = {
.name = "usbin-plugin",
.handler = smblib_handle_usb_plugin,
.wake = true,
},
- {
+ [USBIN_SRC_CHANGE_IRQ] = {
.name = "usbin-src-change",
.handler = smblib_handle_usb_source_change,
.wake = true,
},
- {
+ [USBIN_ICL_CHANGE_IRQ] = {
.name = "usbin-icl-change",
.handler = smblib_handle_icl_change,
.wake = true,
},
- {
+ [TYPE_C_CHANGE_IRQ] = {
.name = "type-c-change",
.handler = smblib_handle_usb_typec_change,
.wake = true,
},
/* DC INPUT IRQs */
- {
+ [DCIN_COLLAPSE_IRQ] = {
.name = "dcin-collapse",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_LT_3P6V_IRQ] = {
.name = "dcin-lt-3p6v",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_UV_IRQ] = {
.name = "dcin-uv",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_OV_IRQ] = {
.name = "dcin-ov",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_PLUGIN_IRQ] = {
.name = "dcin-plugin",
.handler = smblib_handle_dc_plugin,
.wake = true,
},
- {
+ [DIV2_EN_DG_IRQ] = {
.name = "div2-en-dg",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_ICL_CHANGE_IRQ] = {
.name = "dcin-icl-change",
.handler = smblib_handle_debug,
},
/* MISCELLANEOUS IRQs */
- {
+ [WDOG_SNARL_IRQ] = {
.name = "wdog-snarl",
.handler = NULL,
},
- {
+ [WDOG_BARK_IRQ] = {
.name = "wdog-bark",
.handler = NULL,
},
- {
+ [AICL_FAIL_IRQ] = {
.name = "aicl-fail",
.handler = smblib_handle_debug,
},
- {
+ [AICL_DONE_IRQ] = {
.name = "aicl-done",
.handler = smblib_handle_debug,
},
- {
+ [HIGH_DUTY_CYCLE_IRQ] = {
.name = "high-duty-cycle",
.handler = smblib_handle_high_duty_cycle,
.wake = true,
},
- {
+ [INPUT_CURRENT_LIMIT_IRQ] = {
.name = "input-current-limiting",
.handler = smblib_handle_debug,
},
- {
+ [TEMPERATURE_CHANGE_IRQ] = {
.name = "temperature-change",
.handler = smblib_handle_debug,
},
- {
+ [SWITCH_POWER_OK_IRQ] = {
.name = "switcher-power-ok",
.handler = smblib_handle_switcher_power_ok,
.storm_data = {true, 1000, 3},
@@ -1861,6 +1889,7 @@ static int smb2_request_interrupt(struct smb2 *chip,
irq_data->parent_data = chip;
irq_data->name = irq_name;
irq_data->storm_data = smb2_irqs[irq_index].storm_data;
+ mutex_init(&irq_data->storm_data.storm_lock);
rc = devm_request_threaded_irq(chg->dev, irq, NULL,
smb2_irqs[irq_index].handler,
@@ -1871,6 +1900,7 @@ static int smb2_request_interrupt(struct smb2 *chip,
}
smb2_irqs[irq_index].irq = irq;
+ smb2_irqs[irq_index].irq_data = irq_data;
if (smb2_irqs[irq_index].wake)
enable_irq_wake(irq);
@@ -1984,6 +2014,7 @@ static int smb2_probe(struct platform_device *pdev)
chg->param = v1_params;
chg->debug_mask = &__debug_mask;
chg->mode = PARALLEL_MASTER;
+ chg->irq_info = smb2_irqs;
chg->name = "PMI";
chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 11c82b53a9a1..33339588599e 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -16,6 +16,7 @@
#include <linux/iio/consumer.h>
#include <linux/power_supply.h>
#include <linux/regulator/driver.h>
+#include <linux/qpnp/qpnp-revid.h>
#include <linux/input/qpnp-power-on.h>
#include <linux/irq.h>
#include "smb-lib.h"
@@ -156,11 +157,24 @@ int smblib_icl_override(struct smb_charger *chg, bool override)
int rc;
bool override_status;
u8 stat;
+ u16 reg;
- rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
+ switch (chg->smb_version) {
+ case PMI8998_SUBTYPE:
+ reg = APSD_RESULT_STATUS_REG;
+ break;
+ case PM660_SUBTYPE:
+ reg = AICL_STATUS_REG;
+ break;
+ default:
+ smblib_dbg(chg, PR_MISC, "Unknown chip version=%x\n",
+ chg->smb_version);
+ return -EINVAL;
+ }
+
+ rc = smblib_read(chg, reg, &stat);
if (rc < 0) {
- smblib_err(chg, "Couldn't read APSD_RESULT_STATUS_REG rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read reg=%x rc=%d\n", reg, rc);
return rc;
}
override_status = (bool)(stat & ICL_OVERRIDE_LATCH_BIT);
@@ -317,7 +331,6 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
return result;
}
-
/********************
* REGISTER SETTERS *
********************/
@@ -616,7 +629,7 @@ static void smblib_uusb_removal(struct smb_charger *chg)
/* reset both usbin current and voltage votes */
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
- vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, true, 0);
+ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -640,6 +653,19 @@ static void smblib_uusb_removal(struct smb_charger *chg)
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
if (rc < 0)
smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
+
+ /* clear USB ICL vote for DCP_VOTER */
+ rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
+
+ /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
+ rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
+ rc);
}
static bool smblib_sysok_reason_usbin(struct smb_charger *chg)
@@ -662,6 +688,9 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg)
int rc;
union power_supply_propval val;
+ if (!chg->suspend_input_on_debug_batt)
+ return;
+
rc = power_supply_get_property(chg->bms_psy,
POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
if (rc < 0) {
@@ -669,7 +698,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg)
return;
}
- vote(chg->usb_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+ vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
if (val.intval)
pr_info("Input suspended: Fake battery\n");
@@ -712,18 +741,6 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg)
* VOTABLE CALLBACKS *
*********************/
-static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
- int suspend, const char *client)
-{
- struct smb_charger *chg = data;
-
- /* resume input if suspend is invalid */
- if (suspend < 0)
- suspend = 0;
-
- return smblib_set_usb_suspend(chg, (bool)suspend);
-}
-
static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
int suspend, const char *client)
{
@@ -736,57 +753,17 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
return smblib_set_dc_suspend(chg, (bool)suspend);
}
-static int smblib_fcc_max_vote_callback(struct votable *votable, void *data,
- int fcc_ua, const char *client)
-{
- struct smb_charger *chg = data;
-
- return vote(chg->fcc_votable, FCC_MAX_RESULT_VOTER, true, fcc_ua);
-}
-
#define USBIN_25MA 25000
#define USBIN_100MA 100000
#define USBIN_150MA 150000
#define USBIN_500MA 500000
#define USBIN_900MA 900000
-static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
- int icl_ua, const char *client)
-{
- struct smb_charger *chg = data;
- int rc = 0;
- bool suspend, override;
- u8 icl_options = 0;
-
- override = true;
- /* remove override if no voters or type = SDP or CDP */
- if (client == NULL
- || chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB
- || chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP)
- override = false;
-
- suspend = false;
- if (client && (icl_ua < USBIN_25MA))
- suspend = true;
-
- if (suspend)
- goto out;
- if (chg->usb_psy_desc.type != POWER_SUPPLY_TYPE_USB) {
- if (client) {
- rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
- icl_ua - chg->icl_reduction_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't set HC ICL rc=%d\n",
- rc);
- return rc;
- }
- }
- smblib_dbg(chg, PR_PARALLEL,
- "icl_ua=%d icl_reduction=%d\n",
- icl_ua, chg->icl_reduction_ua);
- goto out;
- }
+static int set_sdp_current(struct smb_charger *chg, int icl_ua)
+{
+ int rc;
+ u8 icl_options;
/* power source is SDP */
switch (icl_ua) {
@@ -808,35 +785,97 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
break;
default:
smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
- icl_options = 0;
- break;
+ return -EINVAL;
}
-out:
- if (override)
- icl_options |= USBIN_MODE_CHG_BIT;
-
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- CFG_USB3P0_SEL_BIT | USB51_MODE_BIT | USBIN_MODE_CHG_BIT,
- icl_options);
+ CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
if (rc < 0) {
smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
return rc;
}
- rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
+ return rc;
+}
+
+static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
+ int icl_ua, const char *client)
+{
+ struct smb_charger *chg = data;
+ int rc = 0;
+ bool override;
+ union power_supply_propval pval;
+
+ /* suspend and return if 25mA or less is requested */
+ if (client && (icl_ua < USBIN_25MA))
+ return smblib_set_usb_suspend(chg, true);
+
+ disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
+ if (!client)
+ goto override_suspend_config;
+
+ rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0) {
- smblib_err(chg, "Couldn't %s input rc=%d\n",
- suspend ? "suspend" : "resume", rc);
- return rc;
+ smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
+ goto enable_icl_changed_interrupt;
+ }
+
+ /* configure current */
+ if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+ && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
+ rc = set_sdp_current(chg, icl_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
+ goto enable_icl_changed_interrupt;
+ }
+ } else {
+ rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
+ icl_ua - chg->icl_reduction_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
+ goto enable_icl_changed_interrupt;
+ }
+ }
+
+override_suspend_config:
+ /* determine if override needs to be enforced */
+ override = true;
+ if (client == NULL) {
+ /* remove override if no voters - hw defaults is desired */
+ override = false;
+ } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
+ if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
+ /* For std cable with type = SDP never override */
+ override = false;
+ else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP
+ && icl_ua - chg->icl_reduction_ua == 1500000)
+ /*
+ * For std cable with type = CDP override only if
+ * current is not 1500mA
+ */
+ override = false;
}
+ /* enforce override */
+ rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
+ USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
+
rc = smblib_icl_override(chg, override);
if (rc < 0) {
smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
- return rc;
+ goto enable_icl_changed_interrupt;
+ }
+
+ /* unsuspend after configuring current and override */
+ rc = smblib_set_usb_suspend(chg, false);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
+ goto enable_icl_changed_interrupt;
}
+enable_icl_changed_interrupt:
+ enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
+
return rc;
}
@@ -1248,8 +1287,9 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
int smblib_get_prop_input_suspend(struct smb_charger *chg,
union power_supply_propval *val)
{
- val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER) &&
- get_client_vote(chg->dc_suspend_votable, USER_VOTER);
+ val->intval
+ = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
+ && get_client_vote(chg->dc_suspend_votable, USER_VOTER);
return 0;
}
@@ -1546,7 +1586,8 @@ int smblib_set_prop_input_suspend(struct smb_charger *chg,
{
int rc;
- rc = vote(chg->usb_suspend_votable, USER_VOTER, (bool)val->intval, 0);
+ /* vote 0mA when suspended */
+ rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
if (rc < 0) {
smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
(bool)val->intval ? "suspend" : "resume", rc);
@@ -1692,7 +1733,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg,
int rc = 0;
u8 stat;
- if (get_client_vote(chg->usb_suspend_votable, USER_VOTER)) {
+ if (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0) {
val->intval = false;
return rc;
}
@@ -1971,6 +2012,39 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg,
return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval);
}
+#define HVDCP3_STEP_UV 200000
+int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
+ int rc, pulses;
+ u8 stat;
+
+ val->intval = MICRO_5V;
+ if (apsd_result == NULL) {
+ smblib_err(chg, "APSD result is NULL\n");
+ return 0;
+ }
+
+ switch (apsd_result->pst) {
+ case POWER_SUPPLY_TYPE_USB_HVDCP_3:
+ rc = smblib_read(chg, QC_PULSE_COUNT_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg,
+ "Couldn't read QC_PULSE_COUNT rc=%d\n", rc);
+ return 0;
+ }
+ pulses = (stat & QC_PULSE_COUNT_MASK);
+ val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
+ break;
+ default:
+ val->intval = MICRO_5V;
+ break;
+ }
+
+ return 0;
+}
+
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
union power_supply_propval *val)
{
@@ -2000,10 +2074,10 @@ int smblib_get_pe_start(struct smb_charger *chg,
return 0;
}
-int smblib_get_prop_connector_therm_zone(struct smb_charger *chg,
+int smblib_get_prop_die_health(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc, i;
+ int rc;
u8 stat;
rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
@@ -2013,13 +2087,24 @@ int smblib_get_prop_connector_therm_zone(struct smb_charger *chg,
return rc;
}
- i = fls((stat & TEMP_RANGE_MASK) >> TEMP_RANGE_SHIFT) - 1;
- if (i < 0) {
- smblib_err(chg, "TEMP_RANGE is invalid\n");
- return -EINVAL;
+ /* TEMP_RANGE bits are mutually exclusive */
+ switch (stat & TEMP_RANGE_MASK) {
+ case TEMP_BELOW_RANGE_BIT:
+ val->intval = POWER_SUPPLY_HEALTH_COOL;
+ break;
+ case TEMP_WITHIN_RANGE_BIT:
+ val->intval = POWER_SUPPLY_HEALTH_WARM;
+ break;
+ case TEMP_ABOVE_RANGE_BIT:
+ val->intval = POWER_SUPPLY_HEALTH_HOT;
+ break;
+ case ALERT_LEVEL_BIT:
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
}
- val->intval = i;
return 0;
}
@@ -2203,12 +2288,19 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
return rc;
}
- /* remove DCP_VOTER */
+ /* clear USB ICL vote for DCP_VOTER */
rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
- if (rc < 0) {
- smblib_err(chg, "Couldn't unvote DCP rc=%d\n", rc);
- return rc;
- }
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't un-vote DCP from USB ICL rc=%d\n",
+ rc);
+
+ /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
+ rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
+ rc);
/* remove USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
@@ -2216,6 +2308,16 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
return rc;
}
+
+ /* pd active set, parallel charger can be enabled now */
+ rc = vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER,
+ false, 0);
+ if (rc < 0) {
+ smblib_err(chg,
+ "Couldn't unvote PL_DELAY_HVDCP_VOTER rc=%d\n",
+ rc);
+ return rc;
+ }
}
/* CC pin selection s/w override in PD session; h/w otherwise. */
@@ -2255,39 +2357,6 @@ int smblib_set_prop_ship_mode(struct smb_charger *chg,
return rc;
}
-/***********************
-* USB MAIN PSY GETTERS *
-*************************/
-int smblib_get_prop_fcc_delta(struct smb_charger *chg,
- union power_supply_propval *val)
-{
- int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
-
- rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
- step_cc_delta_ua = 0;
- } else {
- hw_cc_delta_ua = step_cc_delta_ua;
- }
-
- rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
- jeita_cc_delta_ua = 0;
- } else if (jeita_cc_delta_ua < 0) {
- /* HW will take the min between JEITA and step charge */
- hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
- }
-
- val->intval = hw_cc_delta_ua;
- return 0;
-}
-
-/***********************
-* USB MAIN PSY SETTERS *
-*************************/
-
int smblib_reg_block_update(struct smb_charger *chg,
struct reg_info *entry)
{
@@ -2463,6 +2532,155 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
return rc;
}
+/***********************
+* USB MAIN PSY GETTERS *
+*************************/
+int smblib_get_prop_fcc_delta(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
+
+ rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
+ step_cc_delta_ua = 0;
+ } else {
+ hw_cc_delta_ua = step_cc_delta_ua;
+ }
+
+ rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
+ jeita_cc_delta_ua = 0;
+ } else if (jeita_cc_delta_ua < 0) {
+ /* HW will take the min between JEITA and step charge */
+ hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
+ }
+
+ val->intval = hw_cc_delta_ua;
+ return 0;
+}
+
+/***********************
+* USB MAIN PSY SETTERS *
+*************************/
+
+#define SDP_CURRENT_MA 500000
+#define CDP_CURRENT_MA 1500000
+#define DCP_CURRENT_MA 1500000
+#define HVDCP_CURRENT_MA 3000000
+#define TYPEC_DEFAULT_CURRENT_MA 900000
+#define TYPEC_MEDIUM_CURRENT_MA 1500000
+#define TYPEC_HIGH_CURRENT_MA 3000000
+static int smblib_get_charge_current(struct smb_charger *chg,
+ int *total_current_ua)
+{
+ const struct apsd_result *apsd_result = smblib_update_usb_type(chg);
+ union power_supply_propval val = {0, };
+ int rc, typec_source_rd, current_ua;
+ bool non_compliant;
+ u8 stat5;
+
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
+ return rc;
+ }
+ non_compliant = stat5 & TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT;
+
+ /* get settled ICL */
+ rc = smblib_get_prop_input_current_settled(chg, &val);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get settled ICL rc=%d\n", rc);
+ return rc;
+ }
+
+ typec_source_rd = smblib_get_prop_ufp_mode(chg);
+
+ /* QC 2.0/3.0 adapter */
+ if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) {
+ *total_current_ua = HVDCP_CURRENT_MA;
+ return 0;
+ }
+
+ if (non_compliant) {
+ switch (apsd_result->bit) {
+ case CDP_CHARGER_BIT:
+ current_ua = CDP_CURRENT_MA;
+ break;
+ case DCP_CHARGER_BIT:
+ case OCP_CHARGER_BIT:
+ case FLOAT_CHARGER_BIT:
+ current_ua = DCP_CURRENT_MA;
+ break;
+ default:
+ current_ua = 0;
+ break;
+ }
+
+ *total_current_ua = max(current_ua, val.intval);
+ return 0;
+ }
+
+ switch (typec_source_rd) {
+ case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
+ switch (apsd_result->bit) {
+ case CDP_CHARGER_BIT:
+ current_ua = CDP_CURRENT_MA;
+ break;
+ case DCP_CHARGER_BIT:
+ case OCP_CHARGER_BIT:
+ case FLOAT_CHARGER_BIT:
+ current_ua = chg->default_icl_ua;
+ break;
+ default:
+ current_ua = 0;
+ break;
+ }
+ break;
+ case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
+ current_ua = TYPEC_MEDIUM_CURRENT_MA;
+ break;
+ case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
+ current_ua = TYPEC_HIGH_CURRENT_MA;
+ break;
+ case POWER_SUPPLY_TYPEC_NON_COMPLIANT:
+ case POWER_SUPPLY_TYPEC_NONE:
+ default:
+ current_ua = 0;
+ break;
+ }
+
+ *total_current_ua = max(current_ua, val.intval);
+ return 0;
+}
+
+int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua)
+{
+ int current_ua, rc;
+
+ if (reduction_ua == 0) {
+ chg->icl_reduction_ua = 0;
+ vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+ } else {
+ /*
+ * No usb_icl voter means we are defaulting to hw chosen
+ * max limit. We need a vote from s/w to enforce the reduction.
+ */
+ if (get_effective_result(chg->usb_icl_votable) == -EINVAL) {
+ rc = smblib_get_charge_current(chg, &current_ua);
+ if (rc < 0) {
+ pr_err("Failed to get ICL rc=%d\n", rc);
+ return rc;
+ }
+ vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, true,
+ current_ua);
+ }
+ }
+
+ return rerun_election(chg->usb_icl_votable);
+}
+
/************************
* PARALLEL PSY GETTERS *
************************/
@@ -2613,6 +2831,21 @@ irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data)
return IRQ_HANDLED;
}
+irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+ struct storm_watch *wdata;
+
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+ if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data)
+ return IRQ_HANDLED;
+
+ wdata = &chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data->storm_data;
+ reset_storm_count(wdata);
+ return IRQ_HANDLED;
+}
+
irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
@@ -2653,8 +2886,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
}
} else {
if (chg->wa_flags & BOOST_BACK_WA)
- vote(chg->usb_suspend_votable,
- BOOST_BACK_VOTER, false, 0);
+ vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
@@ -2684,22 +2916,20 @@ irqreturn_t smblib_handle_icl_change(int irq, void *data)
struct smb_charger *chg = irq_data->parent_data;
int rc, settled_ua;
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
-
rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
return IRQ_HANDLED;
}
- if (chg->mode != PARALLEL_MASTER)
- return IRQ_HANDLED;
-
- power_supply_changed(chg->usb_main_psy);
-
- vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
- settled_ua >= USB_WEAK_INPUT_UA, 0);
+ if (chg->mode == PARALLEL_MASTER) {
+ power_supply_changed(chg->usb_main_psy);
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
+ settled_ua >= USB_WEAK_INPUT_UA, 0);
+ }
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s icl_settled=%d\n",
+ irq_data->name, settled_ua);
return IRQ_HANDLED;
}
@@ -2726,6 +2956,7 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
u8 stat;
int pulses;
+ power_supply_changed(chg->usb_main_psy);
if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_HVDCP) {
rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat);
if (rc < 0) {
@@ -2778,13 +3009,6 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
}
}
-static void smblib_handle_adaptive_voltage_done(struct smb_charger *chg,
- bool rising)
-{
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: adaptive-voltage-done %s\n",
- rising ? "rising" : "falling");
-}
-
/* triggers when HVDCP 3.0 authentication has finished */
static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
bool rising)
@@ -2808,7 +3032,7 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
/* QC authentication done, parallel charger can be enabled now */
- vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, false, 0);
+ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0);
/* the APSD done handler will set the USB supply type */
apsd_result = smblib_get_apsd_result(chg);
@@ -2844,7 +3068,7 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
* to complete.
*/
if (!qc_charger)
- vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER,
+ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER,
false, 0);
}
@@ -2882,9 +3106,13 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
true);
case OCP_CHARGER_BIT:
case FLOAT_CHARGER_BIT:
- /* if not DCP then no hvdcp timeout happens. Enable pd here */
+ /*
+ * if not DCP then no hvdcp timeout happens. Enable
+ * pd/parallel here.
+ */
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
+ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, false, 0);
break;
case DCP_CHARGER_BIT:
if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
@@ -2926,9 +3154,6 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
smblib_handle_hvdcp_3p0_auth_done(chg,
(bool)(stat & QC_AUTH_DONE_STATUS_BIT));
- smblib_handle_adaptive_voltage_done(chg,
- (bool)(stat & VADP_CHANGE_DONE_AFTER_AUTH_BIT));
-
smblib_handle_sdp_enumeration_done(chg,
(bool)(stat & ENUMERATION_DONE_BIT));
@@ -2939,6 +3164,13 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
power_supply_changed(chg->usb_psy);
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
+ return IRQ_HANDLED;
+ }
+ smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+
return IRQ_HANDLED;
}
@@ -2984,6 +3216,13 @@ static void typec_source_removal(struct smb_charger *chg)
if (rc < 0)
smblib_err(chg,
"Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
+
+ /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */
+ rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
+ rc);
}
static void typec_source_insertion(struct smb_charger *chg)
@@ -3012,7 +3251,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
vote(chg->pd_disallowed_votable_indirect, LEGACY_CABLE_VOTER, true, 0);
vote(chg->pd_disallowed_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
- vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, true, 0);
+ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
/* reset votes from vbus_cc_short */
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
@@ -3027,12 +3266,13 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
chg->vconn_attempts = 0;
chg->otg_attempts = 0;
- typec_source_removal(chg);
- typec_sink_removal(chg);
chg->usb_ever_removed = true;
smblib_update_usb_type(chg);
+
+ typec_source_removal(chg);
+ typec_sink_removal(chg);
}
static void smblib_handle_typec_insertion(struct smb_charger *chg,
@@ -3215,15 +3455,15 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
}
if ((stat & USE_USBIN_BIT) &&
- get_effective_result(chg->usb_suspend_votable))
+ get_effective_result(chg->usb_icl_votable) < USBIN_25MA)
return IRQ_HANDLED;
if (stat & USE_DCIN_BIT)
return IRQ_HANDLED;
if (is_storming(&irq_data->storm_data)) {
- smblib_err(chg, "Reverse boost detected: suspending input\n");
- vote(chg->usb_suspend_votable, BOOST_BACK_VOTER, true, 0);
+ smblib_err(chg, "Reverse boost detected: voting 0mA to suspend input\n");
+ vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
}
return IRQ_HANDLED;
@@ -3570,15 +3810,7 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
- vote(chg->pl_disable_votable, PL_DISABLE_HVDCP_VOTER, true, 0);
-
- chg->usb_suspend_votable = create_votable("USB_SUSPEND", VOTE_SET_ANY,
- smblib_usb_suspend_vote_callback,
- chg);
- if (IS_ERR(chg->usb_suspend_votable)) {
- rc = PTR_ERR(chg->usb_suspend_votable);
- return rc;
- }
+ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
smblib_dc_suspend_vote_callback,
@@ -3588,14 +3820,6 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
- chg->fcc_max_votable = create_votable("FCC_MAX", VOTE_MAX,
- smblib_fcc_max_vote_callback,
- chg);
- if (IS_ERR(chg->fcc_max_votable)) {
- rc = PTR_ERR(chg->fcc_max_votable);
- return rc;
- }
-
chg->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
smblib_usb_icl_vote_callback,
chg);
@@ -3685,12 +3909,8 @@ static int smblib_create_votables(struct smb_charger *chg)
static void smblib_destroy_votables(struct smb_charger *chg)
{
- if (chg->usb_suspend_votable)
- destroy_votable(chg->usb_suspend_votable);
if (chg->dc_suspend_votable)
destroy_votable(chg->dc_suspend_votable);
- if (chg->fcc_max_votable)
- destroy_votable(chg->fcc_max_votable);
if (chg->usb_icl_votable)
destroy_votable(chg->usb_icl_votable);
if (chg->dc_icl_votable)
@@ -3741,6 +3961,8 @@ int smblib_init(struct smb_charger *chg)
switch (chg->mode) {
case PARALLEL_MASTER:
+ chg->qnovo_fcc_ua = -EINVAL;
+ chg->qnovo_fv_uv = -EINVAL;
rc = smblib_create_votables(chg);
if (rc < 0) {
smblib_err(chg, "Couldn't create votables rc=%d\n",
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index a0190ae44f29..b2cfeeda5792 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -13,6 +13,7 @@
#ifndef __SMB2_CHARGER_H
#define __SMB2_CHARGER_H
#include <linux/types.h>
+#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/consumer.h>
@@ -31,6 +32,7 @@ enum print_reason {
#define USER_VOTER "USER_VOTER"
#define PD_VOTER "PD_VOTER"
#define DCP_VOTER "DCP_VOTER"
+#define PL_USBIN_USBIN_VOTER "PL_USBIN_USBIN_VOTER"
#define USB_PSY_VOTER "USB_PSY_VOTER"
#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER"
#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
@@ -39,7 +41,6 @@ enum print_reason {
#define CHG_STATE_VOTER "CHG_STATE_VOTER"
#define TYPEC_SRC_VOTER "TYPEC_SRC_VOTER"
#define TAPER_END_VOTER "TAPER_END_VOTER"
-#define FCC_MAX_RESULT_VOTER "FCC_MAX_RESULT_VOTER"
#define THERMAL_DAEMON_VOTER "THERMAL_DAEMON_VOTER"
#define CC_DETACHED_VOTER "CC_DETACHED_VOTER"
#define HVDCP_TIMEOUT_VOTER "HVDCP_TIMEOUT_VOTER"
@@ -53,7 +54,8 @@ enum print_reason {
#define MICRO_USB_VOTER "MICRO_USB_VOTER"
#define DEBUG_BOARD_VOTER "DEBUG_BOARD_VOTER"
#define PD_SUSPEND_SUPPORTED_VOTER "PD_SUSPEND_SUPPORTED_VOTER"
-#define PL_DISABLE_HVDCP_VOTER "PL_DISABLE_HVDCP_VOTER"
+#define PL_DELAY_HVDCP_VOTER "PL_DELAY_HVDCP_VOTER"
+#define CTM_VOTER "CTM_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -77,6 +79,57 @@ enum {
TYPEC_CC2_REMOVAL_WA_BIT = BIT(2),
};
+enum smb_irq_index {
+ CHG_ERROR_IRQ = 0,
+ CHG_STATE_CHANGE_IRQ,
+ STEP_CHG_STATE_CHANGE_IRQ,
+ STEP_CHG_SOC_UPDATE_FAIL_IRQ,
+ STEP_CHG_SOC_UPDATE_REQ_IRQ,
+ OTG_FAIL_IRQ,
+ OTG_OVERCURRENT_IRQ,
+ OTG_OC_DIS_SW_STS_IRQ,
+ TESTMODE_CHANGE_DET_IRQ,
+ BATT_TEMP_IRQ,
+ BATT_OCP_IRQ,
+ BATT_OV_IRQ,
+ BATT_LOW_IRQ,
+ BATT_THERM_ID_MISS_IRQ,
+ BATT_TERM_MISS_IRQ,
+ USBIN_COLLAPSE_IRQ,
+ USBIN_LT_3P6V_IRQ,
+ USBIN_UV_IRQ,
+ USBIN_OV_IRQ,
+ USBIN_PLUGIN_IRQ,
+ USBIN_SRC_CHANGE_IRQ,
+ USBIN_ICL_CHANGE_IRQ,
+ TYPE_C_CHANGE_IRQ,
+ DCIN_COLLAPSE_IRQ,
+ DCIN_LT_3P6V_IRQ,
+ DCIN_UV_IRQ,
+ DCIN_OV_IRQ,
+ DCIN_PLUGIN_IRQ,
+ DIV2_EN_DG_IRQ,
+ DCIN_ICL_CHANGE_IRQ,
+ WDOG_SNARL_IRQ,
+ WDOG_BARK_IRQ,
+ AICL_FAIL_IRQ,
+ AICL_DONE_IRQ,
+ HIGH_DUTY_CYCLE_IRQ,
+ INPUT_CURRENT_LIMIT_IRQ,
+ TEMPERATURE_CHANGE_IRQ,
+ SWITCH_POWER_OK_IRQ,
+ SMB_IRQ_MAX,
+};
+
+struct smb_irq_info {
+ const char *name;
+ const irq_handler_t handler;
+ const bool wake;
+ const struct storm_watch storm_data;
+ struct smb_irq_data *irq_data;
+ int irq;
+};
+
static const unsigned int smblib_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
@@ -165,12 +218,14 @@ struct smb_charger {
struct device *dev;
char *name;
struct regmap *regmap;
+ struct smb_irq_info *irq_info;
struct smb_params param;
struct smb_iio iio;
int *debug_mask;
enum smb_mode mode;
bool external_vconn;
struct smb_chg_freq chg_freq;
+ int smb_version;
/* locks */
struct mutex write_lock;
@@ -197,9 +252,7 @@ struct smb_charger {
struct regulator *dpdm_reg;
/* votables */
- struct votable *usb_suspend_votable;
struct votable *dc_suspend_votable;
- struct votable *fcc_max_votable;
struct votable *fcc_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
@@ -242,8 +295,10 @@ struct smb_charger {
bool micro_usb_mode;
bool otg_en;
bool vconn_en;
+ bool suspend_input_on_debug_batt;
int otg_attempts;
int vconn_attempts;
+ int default_icl_ua;
/* workaround flag */
u32 wa_flags;
@@ -255,6 +310,10 @@ struct smb_charger {
bool usb_ever_removed;
int icl_reduction_ua;
+
+ /* qnovo */
+ int qnovo_fcc_ua;
+ int qnovo_fv_uv;
};
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -297,6 +356,7 @@ irqreturn_t smblib_handle_step_chg_soc_update_request(int irq, void *data);
irqreturn_t smblib_handle_batt_temp_changed(int irq, void *data);
irqreturn_t smblib_handle_batt_psy_changed(int irq, void *data);
irqreturn_t smblib_handle_usb_psy_changed(int irq, void *data);
+irqreturn_t smblib_handle_usbin_uv(int irq, void *data);
irqreturn_t smblib_handle_usb_plugin(int irq, void *data);
irqreturn_t smblib_handle_usb_source_change(int irq, void *data);
irqreturn_t smblib_handle_icl_change(int irq, void *data);
@@ -373,6 +433,8 @@ int smblib_get_prop_pd_allowed(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_input_current_settled(struct smb_charger *chg,
union power_supply_propval *val);
+int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
+ union power_supply_propval *val);
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_pe_start(struct smb_charger *chg,
@@ -381,7 +443,7 @@ int smblib_get_prop_charger_temp(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
union power_supply_propval *val);
-int smblib_get_prop_connector_therm_zone(struct smb_charger *chg,
+int smblib_get_prop_die_health(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_pd_current_max(struct smb_charger *chg,
const union power_supply_propval *val);
@@ -408,6 +470,7 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg);
int smblib_get_prop_fcc_delta(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_icl_override(struct smb_charger *chg, bool override);
+int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index f238b055d271..e005a27e8dd9 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -825,7 +825,6 @@ enum {
#define THERM_REG_ACTIVE_BIT BIT(6)
#define TLIM_BIT BIT(5)
#define TEMP_RANGE_MASK GENMASK(4, 1)
-#define TEMP_RANGE_SHIFT 1
#define ALERT_LEVEL_BIT BIT(4)
#define TEMP_ABOVE_RANGE_BIT BIT(3)
#define TEMP_WITHIN_RANGE_BIT BIT(2)
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 9287b7c37b97..4180edc89a4c 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -14,7 +14,6 @@
#include <linux/device.h>
#include <linux/iio/consumer.h>
-#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -108,6 +107,17 @@ module_param_named(
debug_mask, __debug_mask, int, S_IRUSR | S_IWUSR
);
+irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb138x *chip = irq_data->parent_data;
+
+ if (chip->parallel_psy)
+ power_supply_changed(chip->parallel_psy);
+
+ return IRQ_HANDLED;
+}
+
static int smb138x_parse_dt(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -145,7 +155,7 @@ static int smb138x_parse_dt(struct smb138x *chip)
rc = of_property_read_u32(node,
"qcom,connector-temp-max-mdegc",
- &chip->dt.chg_temp_max_mdegc);
+ &chip->dt.connector_temp_max_mdegc);
if (rc < 0)
chip->dt.connector_temp_max_mdegc = 105000;
@@ -432,7 +442,7 @@ static enum power_supply_property smb138x_parallel_props[] = {
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PARALLEL_MODE,
- POWER_SUPPLY_PROP_CONNECTOR_THERM_ZONE,
+ POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
};
static int smb138x_parallel_get_prop(struct power_supply *psy,
@@ -485,8 +495,8 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = POWER_SUPPLY_PARALLEL_MID_MID;
break;
- case POWER_SUPPLY_PROP_CONNECTOR_THERM_ZONE:
- rc = smblib_get_prop_connector_therm_zone(chg, val);
+ case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
+ rc = smblib_get_prop_die_health(chg, val);
break;
default:
pr_err("parallel power supply get prop %d not supported\n",
@@ -817,8 +827,6 @@ static int smb138x_init_hw(struct smb138x *chip)
int rc = 0;
/* votes must be cast before configuring software control */
- vote(chg->usb_suspend_votable,
- DEFAULT_VOTER, chip->dt.suspend_input, 0);
vote(chg->dc_suspend_votable,
DEFAULT_VOTER, chip->dt.suspend_input, 0);
vote(chg->fcc_votable,
@@ -974,170 +982,164 @@ static int smb138x_determine_initial_status(struct smb138x *chip)
* INTERRUPT REGISTRATION *
**************************/
-struct smb138x_irq_info {
- const char *name;
- const irq_handler_t handler;
- const bool wake;
- const struct storm_watch storm_data;
-};
-
-static const struct smb138x_irq_info smb138x_irqs[] = {
+static struct smb_irq_info smb138x_irqs[] = {
/* CHARGER IRQs */
- {
+ [CHG_ERROR_IRQ] = {
.name = "chg-error",
.handler = smblib_handle_debug,
},
- {
+ [CHG_STATE_CHANGE_IRQ] = {
.name = "chg-state-change",
- .handler = smblib_handle_debug,
+ .handler = smb138x_handle_slave_chg_state_change,
+ .wake = true,
},
- {
+ [STEP_CHG_STATE_CHANGE_IRQ] = {
.name = "step-chg-state-change",
.handler = smblib_handle_debug,
},
- {
+ [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = {
.name = "step-chg-soc-update-fail",
.handler = smblib_handle_debug,
},
- {
+ [STEP_CHG_SOC_UPDATE_REQ_IRQ] = {
.name = "step-chg-soc-update-request",
.handler = smblib_handle_debug,
},
/* OTG IRQs */
- {
+ [OTG_FAIL_IRQ] = {
.name = "otg-fail",
.handler = smblib_handle_debug,
},
- {
+ [OTG_OVERCURRENT_IRQ] = {
.name = "otg-overcurrent",
.handler = smblib_handle_debug,
},
- {
+ [OTG_OC_DIS_SW_STS_IRQ] = {
.name = "otg-oc-dis-sw-sts",
.handler = smblib_handle_debug,
},
- {
+ [TESTMODE_CHANGE_DET_IRQ] = {
.name = "testmode-change-detect",
.handler = smblib_handle_debug,
},
/* BATTERY IRQs */
- {
+ [BATT_TEMP_IRQ] = {
.name = "bat-temp",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_OCP_IRQ] = {
.name = "bat-ocp",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_OV_IRQ] = {
.name = "bat-ov",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_LOW_IRQ] = {
.name = "bat-low",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_THERM_ID_MISS_IRQ] = {
.name = "bat-therm-or-id-missing",
.handler = smblib_handle_batt_psy_changed,
},
- {
+ [BATT_TERM_MISS_IRQ] = {
.name = "bat-terminal-missing",
.handler = smblib_handle_batt_psy_changed,
},
/* USB INPUT IRQs */
- {
+ [USBIN_COLLAPSE_IRQ] = {
.name = "usbin-collapse",
.handler = smblib_handle_debug,
},
- {
+ [USBIN_LT_3P6V_IRQ] = {
.name = "usbin-lt-3p6v",
.handler = smblib_handle_debug,
},
- {
+ [USBIN_UV_IRQ] = {
.name = "usbin-uv",
.handler = smblib_handle_debug,
},
- {
+ [USBIN_OV_IRQ] = {
.name = "usbin-ov",
.handler = smblib_handle_debug,
},
- {
+ [USBIN_PLUGIN_IRQ] = {
.name = "usbin-plugin",
.handler = smblib_handle_usb_plugin,
},
- {
+ [USBIN_SRC_CHANGE_IRQ] = {
.name = "usbin-src-change",
.handler = smblib_handle_usb_source_change,
},
- {
+ [USBIN_ICL_CHANGE_IRQ] = {
.name = "usbin-icl-change",
.handler = smblib_handle_debug,
},
- {
+ [TYPE_C_CHANGE_IRQ] = {
.name = "type-c-change",
.handler = smblib_handle_usb_typec_change,
},
/* DC INPUT IRQs */
- {
+ [DCIN_COLLAPSE_IRQ] = {
.name = "dcin-collapse",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_LT_3P6V_IRQ] = {
.name = "dcin-lt-3p6v",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_UV_IRQ] = {
.name = "dcin-uv",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_OV_IRQ] = {
.name = "dcin-ov",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_PLUGIN_IRQ] = {
.name = "dcin-plugin",
.handler = smblib_handle_debug,
},
- {
+ [DIV2_EN_DG_IRQ] = {
.name = "div2-en-dg",
.handler = smblib_handle_debug,
},
- {
+ [DCIN_ICL_CHANGE_IRQ] = {
.name = "dcin-icl-change",
.handler = smblib_handle_debug,
},
/* MISCELLANEOUS IRQs */
- {
+ [WDOG_SNARL_IRQ] = {
.name = "wdog-snarl",
.handler = smblib_handle_debug,
},
- {
+ [WDOG_BARK_IRQ] = {
.name = "wdog-bark",
.handler = smblib_handle_wdog_bark,
.wake = true,
},
- {
+ [AICL_FAIL_IRQ] = {
.name = "aicl-fail",
.handler = smblib_handle_debug,
},
- {
+ [AICL_DONE_IRQ] = {
.name = "aicl-done",
.handler = smblib_handle_debug,
},
- {
+ [HIGH_DUTY_CYCLE_IRQ] = {
.name = "high-duty-cycle",
.handler = smblib_handle_debug,
},
- {
+ [INPUT_CURRENT_LIMIT_IRQ] = {
.name = "input-current-limiting",
.handler = smblib_handle_debug,
},
- {
+ [TEMPERATURE_CHANGE_IRQ] = {
.name = "temperature-change",
.handler = smb138x_handle_temperature_change,
},
- {
+ [SWITCH_POWER_OK_IRQ] = {
.name = "switcher-power-ok",
.handler = smblib_handle_debug,
},
@@ -1185,6 +1187,7 @@ static int smb138x_request_interrupt(struct smb138x *chip,
irq_data->parent_data = chip;
irq_data->name = irq_name;
irq_data->storm_data = smb138x_irqs[irq_index].storm_data;
+ mutex_init(&irq_data->storm_data.storm_lock);
rc = devm_request_threaded_irq(chg->dev, irq, NULL,
smb138x_irqs[irq_index].handler,
@@ -1398,6 +1401,7 @@ static int smb138x_probe(struct platform_device *pdev)
chip->chg.dev = &pdev->dev;
chip->chg.debug_mask = &__debug_mask;
+ chip->chg.irq_info = smb138x_irqs;
chip->chg.name = "SMB";
chip->chg.regmap = dev_get_regmap(chip->chg.dev->parent, NULL);
diff --git a/drivers/power/supply/qcom/storm-watch.c b/drivers/power/supply/qcom/storm-watch.c
index 90fec12bd742..5275079c53e0 100644
--- a/drivers/power/supply/qcom/storm-watch.c
+++ b/drivers/power/supply/qcom/storm-watch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017 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
@@ -39,6 +39,7 @@ bool is_storming(struct storm_watch *data)
if (data->storm_period_ms <= 0)
return false;
+ mutex_lock(&data->storm_lock);
curr_kt = ktime_get_boottime();
delta_kt = ktime_sub(curr_kt, data->last_kt);
@@ -53,5 +54,13 @@ bool is_storming(struct storm_watch *data)
}
data->last_kt = curr_kt;
+ mutex_unlock(&data->storm_lock);
return is_storming;
}
+
+void reset_storm_count(struct storm_watch *data)
+{
+ mutex_lock(&data->storm_lock);
+ data->storm_count = 0;
+ mutex_unlock(&data->storm_lock);
+}
diff --git a/drivers/power/supply/qcom/storm-watch.h b/drivers/power/supply/qcom/storm-watch.h
index 44b9d64d8a87..ff05c4a661c3 100644
--- a/drivers/power/supply/qcom/storm-watch.h
+++ b/drivers/power/supply/qcom/storm-watch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017 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
@@ -13,6 +13,7 @@
#ifndef __STORM_WATCH_H
#define __STORM_WATCH_H
#include <linux/ktime.h>
+#include <linux/mutex.h>
/**
* Data used to track an event storm.
@@ -23,14 +24,17 @@
* @max_storm_count: The number of chained events required to trigger a storm.
* @storm_count: The current number of chained events.
* @last_kt: Kernel time of the last event seen.
+ * @storm_lock: Mutex lock to protect storm_watch data.
*/
struct storm_watch {
- bool enabled;
- int storm_period_ms;
- int max_storm_count;
- int storm_count;
- ktime_t last_kt;
+ bool enabled;
+ int storm_period_ms;
+ int max_storm_count;
+ int storm_count;
+ ktime_t last_kt;
+ struct mutex storm_lock;
};
bool is_storming(struct storm_watch *data);
+void reset_storm_count(struct storm_watch *data);
#endif
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index c51ed182ba96..3ffe094fe53c 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -174,6 +174,7 @@
#define CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN BIT(27)
#define CPR4_REG_MISC 0x700
+#define CPR4_MISC_RESET_STEP_QUOT_LOOP_EN BIT(2)
#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK GENMASK(23, 20)
#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT 20
#define CPR4_MISC_TEMP_SENSOR_ID_START_MASK GENMASK(27, 24)
@@ -698,6 +699,11 @@ static int cpr3_regulator_init_cpr4(struct cpr3_controller *ctrl)
int thread_id = 0;
u64 temp;
+ if (ctrl->reset_step_quot_loop_en)
+ cpr3_masked_write(ctrl, CPR4_REG_MISC,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
+
if (ctrl->supports_hw_closed_loop) {
if (ctrl->saw_use_unit_mV)
pmic_step_size = ctrl->step_volt / 1000;
@@ -1310,6 +1316,11 @@ static int cpr3_regulator_init_cprh(struct cpr3_controller *ctrl)
return rc;
}
+ if (ctrl->reset_step_quot_loop_en)
+ cpr3_masked_write(ctrl, CPR4_REG_MISC,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
+ CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
+
if (ctrl->saw_use_unit_mV)
pmic_step_size = ctrl->step_volt / 1000;
cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 7dae23ca0e70..1ac0f7b816b3 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -735,6 +735,12 @@ struct cpr3_panic_regs_info {
* @panic_notifier: Notifier block registered to global panic notifier list.
* @support_ldo300_vreg: Boolean value which indicates that this CPR controller
* manages an underlying LDO regulator of type LDO300.
+ * @reset_step_quot_loop_en: Boolean value which indicates that this CPR
+ * controller should be configured to reset step_quot on
+ * each loop_en = 0 transition. This configuration allows
+ * the CPR controller to first use the default step_quot
+ * and then later switch to the run-time calibrated
+ * step_quot.
*
* This structure contains both configuration and runtime state data. The
* elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
@@ -836,6 +842,7 @@ struct cpr3_controller {
struct cpr3_panic_regs_info *panic_regs_info;
struct notifier_block panic_notifier;
bool support_ldo300_vreg;
+ bool reset_step_quot_loop_en;
};
/* Used for rounding voltages to the closest physically available set point. */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 0a1a1c56bd16..fcbaf9f5f51f 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -1221,6 +1221,14 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl)
}
/*
+ * Reset step_quot to default on each loop_en = 0 transition is
+ * optional.
+ */
+ ctrl->reset_step_quot_loop_en
+ = of_property_read_bool(ctrl->dev->of_node,
+ "qcom,cpr-reset-step-quot-loop-en");
+
+ /*
* Regulator device handles are not necessary for CPRh controllers
* since communication with the regulators is completely managed
* in hardware.
diff --git a/drivers/regulator/cpr4-mmss-ldo-regulator.c b/drivers/regulator/cpr4-mmss-ldo-regulator.c
index c4aef84e26eb..525f9d6fcf75 100644
--- a/drivers/regulator/cpr4-mmss-ldo-regulator.c
+++ b/drivers/regulator/cpr4-mmss-ldo-regulator.c
@@ -737,6 +737,10 @@ static const struct of_device_id cpr4_mmss_regulator_match_table[] = {
.compatible = "qcom,cpr4-sdm660-mmss-ldo-regulator",
.data = (void *)NULL,
},
+ {
+ .compatible = "qcom,cpr4-sdm630-mmss-ldo-regulator",
+ .data = (void *)NULL,
+ },
{ },
};
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index f21800e00d80..9be8bb94b257 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -37,6 +37,7 @@
#define MSM8998_KBSS_FUSE_CORNERS 4
#define SDM660_KBSS_FUSE_CORNERS 5
+#define SDM630_KBSS_FUSE_CORNERS 4
/**
* struct cprh_kbss_fuses - KBSS specific fuse data
@@ -79,6 +80,7 @@ struct cprh_kbss_fuses {
*/
#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32
#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 16
+#define CPRH_SDM630_KBSS_FUSE_COMBO_COUNT 24
/*
* Constants which define the name of each fuse corner.
@@ -129,6 +131,20 @@ static const char * const cprh_sdm660_perf_kbss_fuse_corner_name[] = {
[CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2] = "TURBO_L2",
};
+enum cprh_sdm630_kbss_fuse_corner {
+ CPRH_SDM630_KBSS_FUSE_CORNER_LOWSVS = 0,
+ CPRH_SDM630_KBSS_FUSE_CORNER_SVSPLUS = 1,
+ CPRH_SDM630_KBSS_FUSE_CORNER_NOM = 2,
+ CPRH_SDM630_KBSS_FUSE_CORNER_TURBO_L1 = 3,
+};
+
+static const char * const cprh_sdm630_kbss_fuse_corner_name[] = {
+ [CPRH_SDM630_KBSS_FUSE_CORNER_LOWSVS] = "LowSVS",
+ [CPRH_SDM630_KBSS_FUSE_CORNER_SVSPLUS] = "SVSPLUS",
+ [CPRH_SDM630_KBSS_FUSE_CORNER_NOM] = "NOM",
+ [CPRH_SDM630_KBSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1",
+};
+
/* KBSS cluster IDs */
#define CPRH_KBSS_POWER_CLUSTER_ID 0
#define CPRH_KBSS_PERFORMANCE_CLUSTER_ID 1
@@ -186,6 +202,22 @@ sdm660_kbss_ro_sel_param[2][SDM660_KBSS_FUSE_CORNERS][3] = {
};
static const struct cpr3_fuse_param
+sdm630_kbss_ro_sel_param[2][SDM630_KBSS_FUSE_CORNERS][3] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ {{67, 12, 15}, {} },
+ {{65, 56, 59}, {} },
+ {{67, 4, 7}, {} },
+ {{67, 0, 3}, {} },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ {{68, 61, 63}, {69, 0, 0} },
+ {{69, 1, 4}, {} },
+ {{68, 57, 60}, {} },
+ {{66, 14, 17}, {} },
+ },
+};
+
+static const struct cpr3_fuse_param
msm8998_kbss_init_voltage_param[2][MSM8998_KBSS_FUSE_CORNERS][2] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
{{67, 34, 39}, {} },
@@ -220,6 +252,22 @@ sdm660_kbss_init_voltage_param[2][SDM660_KBSS_FUSE_CORNERS][2] = {
};
static const struct cpr3_fuse_param
+sdm630_kbss_init_voltage_param[2][SDM630_KBSS_FUSE_CORNERS][2] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ {{67, 34, 39}, {} },
+ {{71, 3, 8}, {} },
+ {{67, 22, 27}, {} },
+ {{67, 16, 21}, {} },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ {{69, 17, 22}, {} },
+ {{69, 23, 28}, {} },
+ {{69, 11, 16}, {} },
+ {{70, 42, 47}, {} },
+ },
+};
+
+static const struct cpr3_fuse_param
msm8998_kbss_target_quot_param[2][MSM8998_KBSS_FUSE_CORNERS][3] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
{{68, 18, 29}, {} },
@@ -254,6 +302,22 @@ sdm660_kbss_target_quot_param[2][SDM660_KBSS_FUSE_CORNERS][3] = {
};
static const struct cpr3_fuse_param
+sdm630_kbss_target_quot_param[2][SDM630_KBSS_FUSE_CORNERS][3] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ {{68, 12, 23}, {} },
+ {{71, 9, 20}, {} },
+ {{67, 52, 63}, {} },
+ {{67, 40, 51}, {} },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ {{69, 53, 63}, {70, 0, 0}, {} },
+ {{70, 1, 12}, {} },
+ {{69, 41, 52}, {} },
+ {{70, 48, 59}, {} },
+ },
+};
+
+static const struct cpr3_fuse_param
msm8998_kbss_quot_offset_param[2][MSM8998_KBSS_FUSE_CORNERS][3] = {
[CPRH_KBSS_POWER_CLUSTER_ID] = {
{{} },
@@ -287,6 +351,22 @@ sdm660_kbss_quot_offset_param[2][SDM660_KBSS_FUSE_CORNERS][3] = {
},
};
+static const struct cpr3_fuse_param
+sdm630_kbss_quot_offset_param[2][SDM630_KBSS_FUSE_CORNERS][3] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ {{} },
+ {{71, 21, 27}, {} },
+ {{68, 31, 37}, {} },
+ {{68, 24, 30}, {} },
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ {{} },
+ {{70, 27, 33}, {} },
+ {{70, 20, 26}, {} },
+ {{70, 60, 63}, {71, 0, 2}, {} },
+ },
+};
+
static const struct cpr3_fuse_param msm8998_cpr_fusing_rev_param[] = {
{39, 51, 53},
{},
@@ -297,6 +377,11 @@ static const struct cpr3_fuse_param sdm660_cpr_fusing_rev_param[] = {
{},
};
+static const struct cpr3_fuse_param sdm630_cpr_fusing_rev_param[] = {
+ {71, 28, 30},
+ {},
+};
+
static const struct cpr3_fuse_param kbss_speed_bin_param[] = {
{38, 29, 31},
{},
@@ -332,6 +417,18 @@ sdm660_kbss_aging_init_quot_diff_param[2][2] = {
},
};
+static const struct cpr3_fuse_param
+sdm630_kbss_aging_init_quot_diff_param[2][2] = {
+ [CPRH_KBSS_POWER_CLUSTER_ID] = {
+ {68, 45, 52},
+ {},
+ },
+ [CPRH_KBSS_PERFORMANCE_CLUSTER_ID] = {
+ {70, 34, 41},
+ {},
+ },
+};
+
/*
* Open loop voltage fuse reference voltages in microvolts for MSM8998 v1
*/
@@ -383,6 +480,25 @@ sdm660_kbss_fuse_ref_volt[2][SDM660_KBSS_FUSE_CORNERS] = {
},
};
+/*
+ * Open loop voltage fuse reference voltages in microvolts for SDM630
+ */
+static const int
+sdm630_kbss_fuse_ref_volt[SDM630_KBSS_FUSE_CORNERS] = {
+ 644000,
+ 788000,
+ 868000,
+ 1068000,
+};
+
+static const int
+sdm630_kbss_speed_bin_2_fuse_ref_volt[SDM630_KBSS_FUSE_CORNERS] = {
+ 644000,
+ 788000,
+ 868000,
+ 1140000,
+};
+
#define CPRH_KBSS_FUSE_STEP_VOLT 10000
#define CPRH_KBSS_VOLTAGE_FUSE_SIZE 6
#define CPRH_KBSS_QUOT_OFFSET_SCALE 5
@@ -433,12 +549,19 @@ sdm660_kbss_fuse_ref_volt[2][SDM660_KBSS_FUSE_CORNERS] = {
#define SDM660_KBSS_PERFORMANCE_AGING_BYPASS_MASK0 0
/*
+ * sdm630 configuration
+ */
+#define SDM630_KBSS_POWER_CPR_SENSOR_COUNT 6
+#define SDM630_KBSS_PERFORMANCE_CPR_SENSOR_COUNT 9
+
+/*
* SOC IDs
*/
enum soc_id {
MSM8998_V1_SOC_ID = 1,
MSM8998_V2_SOC_ID = 2,
SDM660_SOC_ID = 3,
+ SDM630_SOC_ID = 4,
};
/**
@@ -623,6 +746,90 @@ static int cprh_sdm660_kbss_read_fuse_data(struct cpr3_regulator *vreg,
};
/**
+ * cprh_sdm630_kbss_read_fuse_data() - load SDM630 KBSS specific fuse parameter
+ * values
+ * @vreg: Pointer to the CPR3 regulator
+ * @fuse: KBSS specific fuse data
+ *
+ * This function fills cprh_kbss_fuses struct with values read out of hardware
+ * fuses.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cprh_sdm630_kbss_read_fuse_data(struct cpr3_regulator *vreg,
+ struct cprh_kbss_fuses *fuse)
+{
+ void __iomem *base = vreg->thread->ctrl->fuse_base;
+ int i, id, rc;
+
+ rc = cpr3_read_fuse_param(base, sdm630_cpr_fusing_rev_param,
+ &fuse->cpr_fusing_rev);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read CPR fusing revision fuse, rc=%d\n",
+ rc);
+ return rc;
+ }
+ cpr3_info(vreg, "CPR fusing revision = %llu\n", fuse->cpr_fusing_rev);
+
+ id = vreg->thread->ctrl->ctrl_id;
+ for (i = 0; i < SDM630_KBSS_FUSE_CORNERS; i++) {
+ rc = cpr3_read_fuse_param(base,
+ sdm630_kbss_init_voltage_param[id][i],
+ &fuse->init_voltage[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d initial voltage fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ sdm630_kbss_target_quot_param[id][i],
+ &fuse->target_quot[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d target quotient fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ sdm630_kbss_ro_sel_param[id][i],
+ &fuse->ro_sel[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d RO select fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ sdm630_kbss_quot_offset_param[id][i],
+ &fuse->quot_offset[i]);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read fuse-corner %d quotient offset fuse, rc=%d\n",
+ i, rc);
+ return rc;
+ }
+ }
+
+ rc = cpr3_read_fuse_param(base,
+ sdm630_kbss_aging_init_quot_diff_param[id],
+ &fuse->aging_init_quot_diff);
+ if (rc) {
+ cpr3_err(vreg, "Unable to read aging initial quotient difference fuse, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ vreg->fuse_combo = fuse->cpr_fusing_rev + 8 * fuse->speed_bin;
+ if (vreg->fuse_combo >= CPRH_SDM630_KBSS_FUSE_COMBO_COUNT) {
+ cpr3_err(vreg, "invalid CPR fuse combo = %d found\n",
+ vreg->fuse_combo);
+ return -EINVAL;
+ }
+
+ return rc;
+};
+
+/**
* cprh_kbss_read_fuse_data() - load KBSS specific fuse parameter values
* @vreg: Pointer to the CPR3 regulator
*
@@ -648,6 +855,9 @@ static int cprh_kbss_read_fuse_data(struct cpr3_regulator *vreg)
case SDM660_SOC_ID:
fuse_corners = SDM660_KBSS_FUSE_CORNERS;
break;
+ case SDM630_SOC_ID:
+ fuse_corners = SDM630_KBSS_FUSE_CORNERS;
+ break;
case MSM8998_V1_SOC_ID:
case MSM8998_V2_SOC_ID:
fuse_corners = MSM8998_KBSS_FUSE_CORNERS;
@@ -686,6 +896,14 @@ static int cprh_kbss_read_fuse_data(struct cpr3_regulator *vreg)
return rc;
}
break;
+ case SDM630_SOC_ID:
+ rc = cprh_sdm630_kbss_read_fuse_data(vreg, fuse);
+ if (rc) {
+ cpr3_err(vreg, "sdm630 kbss fuse data read failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ break;
case MSM8998_V1_SOC_ID:
case MSM8998_V2_SOC_ID:
rc = cprh_msm8998_kbss_read_fuse_data(vreg, fuse);
@@ -789,6 +1007,12 @@ static int cprh_kbss_calculate_open_loop_voltages(struct cpr3_regulator *vreg)
else
corner_name = cprh_sdm660_perf_kbss_fuse_corner_name;
break;
+ case SDM630_SOC_ID:
+ ref_volt = sdm630_kbss_fuse_ref_volt;
+ if (vreg->speed_bin_fuse == 2)
+ ref_volt = sdm630_kbss_speed_bin_2_fuse_ref_volt;
+ corner_name = cprh_sdm630_kbss_fuse_corner_name;
+ break;
case MSM8998_V1_SOC_ID:
ref_volt = msm8998_v1_kbss_fuse_ref_volt;
corner_name = cprh_msm8998_kbss_fuse_corner_name;
@@ -1356,6 +1580,13 @@ static int cprh_kbss_calculate_target_quotients(struct cpr3_regulator *vreg)
CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2;
}
break;
+ case SDM630_SOC_ID:
+ corner_name = cprh_sdm630_kbss_fuse_corner_name;
+ lowest_fuse_corner =
+ CPRH_SDM630_KBSS_FUSE_CORNER_LOWSVS;
+ highest_fuse_corner =
+ CPRH_SDM630_KBSS_FUSE_CORNER_TURBO_L1;
+ break;
case MSM8998_V1_SOC_ID:
case MSM8998_V2_SOC_ID:
corner_name = cprh_msm8998_kbss_fuse_corner_name;
@@ -1923,6 +2154,14 @@ static int cprh_kbss_init_controller(struct cpr3_controller *ctrl)
ctrl->sensor_count =
SDM660_KBSS_PERFORMANCE_CPR_SENSOR_COUNT;
break;
+ case SDM630_SOC_ID:
+ if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID)
+ ctrl->sensor_count =
+ SDM630_KBSS_POWER_CPR_SENSOR_COUNT;
+ else
+ ctrl->sensor_count =
+ SDM630_KBSS_PERFORMANCE_CPR_SENSOR_COUNT;
+ break;
case MSM8998_V1_SOC_ID:
case MSM8998_V2_SOC_ID:
if (ctrl->ctrl_id == CPRH_KBSS_POWER_CLUSTER_ID)
@@ -2024,6 +2263,10 @@ static const struct of_device_id cprh_regulator_match_table[] = {
.compatible = "qcom,cprh-sdm660-kbss-regulator",
.data = (void *)(uintptr_t)SDM660_SOC_ID,
},
+ {
+ .compatible = "qcom,cprh-sdm630-kbss-regulator",
+ .data = (void *)(uintptr_t)SDM630_SOC_ID,
+ },
{}
};
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index bf357b50e798..f5d7cd0f4701 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4332,13 +4332,9 @@ int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit",
ktime_to_us(ktime_sub(ktime_get(), start)), ret);
- /*
- * Do full reinit if exit failed or if LINERESET was detected during
- * Hibern8 operation. After LINERESET, link moves to default PWM-G1
- * mode hence full reinit is required to move link to HS speeds.
- */
- if (ret || hba->full_init_linereset) {
- hba->full_init_linereset = false;
+
+ /* Do full reinit if exit failed */
+ if (ret) {
ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_EXIT);
dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d",
__func__, ret);
@@ -6083,14 +6079,16 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
__func__, reg);
ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg);
- /* Don't ignore LINERESET indication during hibern8 operation */
+ /*
+ * Don't ignore LINERESET indication during hibern8
+ * enter operation.
+ */
if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) {
struct uic_command *cmd = hba->active_uic_cmd;
if (cmd) {
- if ((cmd->command == UIC_CMD_DME_HIBER_ENTER)
- || (cmd->command == UIC_CMD_DME_HIBER_EXIT)) {
- dev_err(hba->dev, "%s: LINERESET during hibern8, reg 0x%x\n",
+ if (cmd->command == UIC_CMD_DME_HIBER_ENTER) {
+ dev_err(hba->dev, "%s: LINERESET during hibern8 enter, reg 0x%x\n",
__func__, reg);
hba->full_init_linereset = true;
}
@@ -7292,13 +7290,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (ufshcd_scsi_add_wlus(hba))
goto out;
- /* Enable auto hibern8 if supported, after full host and
- * device initialization.
- */
- if (ufshcd_is_auto_hibern8_supported(hba))
- ufshcd_set_auto_hibern8_timer(hba,
- hba->hibern8_on_idle.delay_ms);
-
/* Initialize devfreq after UFS device is detected */
if (ufshcd_is_clkscaling_supported(hba)) {
memcpy(&hba->clk_scaling.saved_pwr_info.info,
@@ -7327,6 +7318,13 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (!hba->is_init_prefetch)
hba->is_init_prefetch = true;
+ /*
+ * Enable auto hibern8 if supported, after full host and
+ * device initialization.
+ */
+ if (ufshcd_is_auto_hibern8_supported(hba))
+ ufshcd_set_auto_hibern8_timer(hba,
+ hba->hibern8_on_idle.delay_ms);
out:
/*
* If we failed to initialize the device or the device is not
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 1e5970b31404..d3f1050499f3 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -865,4 +865,13 @@ config QCOM_EARLY_RANDOM
may not be truly random. Select this option to make an early call
to get some random data to put in the pool. If unsure, say N.
+config QCOM_CX_IPEAK
+ bool "Common driver to handle Cx iPeak limitation"
+ help
+ Cx ipeak HW module is used to limit the current drawn by various subsystem
+ blocks on Cx power rail. Each client needs to set their
+ bit in tcsr register if it is going to cross its own threshold. If all
+ clients are going to cross their thresholds then Cx ipeak hw module will raise
+ an interrupt to cDSP block to throttle cDSP fmax.
+
source "drivers/soc/qcom/memshare/Kconfig"
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index f56c6bf1539a..2605107e2dbd 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -95,9 +95,10 @@ obj-$(CONFIG_QCOM_REMOTEQDSS) += remoteqdss.o
obj-$(CONFIG_MSM_SERVICE_LOCATOR) += service-locator.o
obj-$(CONFIG_MSM_QBT1000) += qbt1000.o
obj-$(CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG) += rpm_rbcpr_stats_v2.o
-obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o system_stats.o
+obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o rpm_master_stat.o rpm_rail_stats.o system_stats.o
obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
obj-$(CONFIG_WCD_DSP_GLINK) += wcd-dsp-glink.o
obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o
+obj-$(CONFIG_QCOM_CX_IPEAK) += cx_ipeak.o
diff --git a/drivers/soc/qcom/cx_ipeak.c b/drivers/soc/qcom/cx_ipeak.c
new file mode 100644
index 000000000000..c5933a285522
--- /dev/null
+++ b/drivers/soc/qcom/cx_ipeak.c
@@ -0,0 +1,202 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/printk.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include <soc/qcom/cx_ipeak.h>
+
+#define TCSR_CXIP_LM_VOTE_BYPASS_OFFSET 0x4
+#define TCSR_CXIP_LM_VOTE_CLEAR_OFFSET 0x8
+#define TCSR_CXIP_LM_VOTE_SET_OFFSET 0xC
+#define TCSR_CXIP_LM_VOTE_FEATURE_ENABLE_OFFSET 0x10
+#define TCSR_CXIP_LM_TRS_OFFSET 0x24
+
+#define CXIP_POLL_TIMEOUT_US (50 * 1000)
+
+static struct cx_ipeak_device {
+ spinlock_t vote_lock;
+ void __iomem *tcsr_vptr;
+} device_ipeak;
+
+struct cx_ipeak_client {
+ int vote_count;
+ unsigned int vote_mask;
+ struct cx_ipeak_device *dev;
+};
+
+/**
+ * cx_ipeak_register() - allocate client structure and fill device private and
+ * bit details.
+ * @dev_node: device node of the client
+ * @client_name: property name of the client
+ *
+ * Allocate client memory and fill the structure with device private and bit
+ *
+ */
+struct cx_ipeak_client *cx_ipeak_register(struct device_node *dev_node,
+ const char *client_name)
+{
+ struct of_phandle_args cx_spec;
+ struct cx_ipeak_client *client;
+ unsigned int reg_enable, reg_bypass;
+ int ret;
+
+ ret = of_parse_phandle_with_fixed_args(dev_node, client_name,
+ 1, 0, &cx_spec);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ if (!of_device_is_available(cx_spec.np))
+ return NULL;
+
+ if (device_ipeak.tcsr_vptr == NULL)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ if (cx_spec.args[0] > 31)
+ return ERR_PTR(-EINVAL);
+
+ reg_enable = readl_relaxed(device_ipeak.tcsr_vptr +
+ TCSR_CXIP_LM_VOTE_FEATURE_ENABLE_OFFSET);
+ reg_bypass = readl_relaxed(device_ipeak.tcsr_vptr +
+ TCSR_CXIP_LM_VOTE_BYPASS_OFFSET) &
+ BIT(cx_spec.args[0]);
+
+ if (!reg_enable || reg_bypass)
+ return NULL;
+
+ client = kzalloc(sizeof(struct cx_ipeak_client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->vote_mask = BIT(cx_spec.args[0]);
+ client->dev = &device_ipeak;
+
+ return client;
+}
+EXPORT_SYMBOL(cx_ipeak_register);
+
+/**
+ * cx_ipeak_unregister() - unregister client
+ * @client: client address to free
+ *
+ * Free the client memory
+ */
+void cx_ipeak_unregister(struct cx_ipeak_client *client)
+{
+ kfree(client);
+}
+EXPORT_SYMBOL(cx_ipeak_unregister);
+
+/*
+ * cx_ipeak_update() - Set/Clear client vote for Cx iPeak limit
+ * manager to throttle cDSP.
+ * @client: client handle.
+ * @vote: True to set the vote and False for reset.
+ *
+ * Receives vote from each client and decides whether to throttle cDSP or not.
+ * This function is NOP for the targets which does not support TCSR Cx iPeak.
+ */
+int cx_ipeak_update(struct cx_ipeak_client *client, bool vote)
+{
+ unsigned int reg_val;
+ int ret = 0;
+
+ /* Check for client and device availability and proceed */
+ if (client == NULL || client->dev->tcsr_vptr == NULL)
+ return ret;
+
+ spin_lock(&client->dev->vote_lock);
+
+ if (vote) {
+ if (client->vote_count == 0) {
+ writel_relaxed(client->vote_mask,
+ client->dev->tcsr_vptr +
+ TCSR_CXIP_LM_VOTE_SET_OFFSET);
+
+ /*
+ * Do a dummy read to give enough time for TRS register
+ * to become 1 when the last client votes.
+ */
+ readl_relaxed(client->dev->tcsr_vptr +
+ TCSR_CXIP_LM_TRS_OFFSET);
+
+ ret = readl_poll_timeout(client->dev->tcsr_vptr +
+ TCSR_CXIP_LM_TRS_OFFSET, reg_val, !reg_val,
+ 0, CXIP_POLL_TIMEOUT_US);
+ if (ret) {
+ writel_relaxed(client->vote_mask,
+ client->dev->tcsr_vptr +
+ TCSR_CXIP_LM_VOTE_CLEAR_OFFSET);
+ goto done;
+ }
+ }
+ client->vote_count++;
+ } else {
+ if (client->vote_count > 0) {
+ client->vote_count--;
+ if (client->vote_count == 0) {
+ writel_relaxed(client->vote_mask,
+ client->dev->tcsr_vptr +
+ TCSR_CXIP_LM_VOTE_CLEAR_OFFSET);
+ }
+ } else
+ ret = -EINVAL;
+ }
+
+done:
+ spin_unlock(&client->dev->vote_lock);
+ return ret;
+}
+EXPORT_SYMBOL(cx_ipeak_update);
+
+static int cx_ipeak_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ device_ipeak.tcsr_vptr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(device_ipeak.tcsr_vptr))
+ return PTR_ERR(device_ipeak.tcsr_vptr);
+
+ spin_lock_init(&device_ipeak.vote_lock);
+ return 0;
+}
+
+static const struct of_device_id cx_ipeak_match_table[] = {
+ { .compatible = "qcom,cx-ipeak-sdm660"},
+ {}
+};
+
+static struct platform_driver cx_ipeak_platform_driver = {
+ .probe = cx_ipeak_probe,
+ .driver = {
+ .name = "cx_ipeak",
+ .of_match_table = cx_ipeak_match_table,
+ .suppress_bind_attrs = true,
+ }
+};
+
+static int __init cx_ipeak_init(void)
+{
+ return platform_driver_register(&cx_ipeak_platform_driver);
+}
+
+arch_initcall(cx_ipeak_init);
diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c
index 5de6e7eac7ea..6794c30605d7 100644
--- a/drivers/soc/qcom/glink_spi_xprt.c
+++ b/drivers/soc/qcom/glink_spi_xprt.c
@@ -891,7 +891,7 @@ static void __rx_worker(struct edge_info *einfo)
}
glink_spi_xprt_set_poll_mode(einfo);
- while (inactive_cycles < MAX_INACTIVE_CYCLES) {
+ do {
if (einfo->tx_resume_needed &&
glink_spi_xprt_write_avail(einfo)) {
einfo->tx_resume_needed = false;
@@ -926,7 +926,7 @@ static void __rx_worker(struct edge_info *einfo)
}
process_rx_cmd(einfo, rx_data, rx_avail);
kfree(rx_data);
- }
+ } while (inactive_cycles < MAX_INACTIVE_CYCLES && !einfo->in_ssr);
glink_spi_xprt_set_irq_mode(einfo);
srcu_read_unlock(&einfo->use_ref, rcu_id);
}
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 7a5a53695329..768871ffa9a7 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -77,15 +77,6 @@ module_param(qmi_timeout, ulong, 0600);
ipc_log_string(icnss_ipc_log_context, _x); \
} while (0)
-#ifdef CONFIG_ICNSS_DEBUG
-#define icnss_ipc_log_long_string(_x...) do { \
- if (icnss_ipc_log_long_context) \
- ipc_log_string(icnss_ipc_log_long_context, _x); \
- } while (0)
-#else
-#define icnss_ipc_log_long_string(_x...)
-#endif
-
#define icnss_pr_err(_fmt, ...) do { \
pr_err(_fmt, ##__VA_ARGS__); \
icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \
@@ -110,12 +101,6 @@ module_param(qmi_timeout, ulong, 0600);
##__VA_ARGS__); \
} while (0)
-#define icnss_reg_dbg(_fmt, ...) do { \
- pr_debug(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_long_string("REG: " pr_fmt(_fmt), \
- ##__VA_ARGS__); \
- } while (0)
-
#ifdef CONFIG_ICNSS_DEBUG
#define ICNSS_ASSERT(_condition) do { \
if (!(_condition)) { \
@@ -157,10 +142,6 @@ module_param(dynamic_feature_mask, ullong, 0600);
void *icnss_ipc_log_context;
-#ifdef CONFIG_ICNSS_DEBUG
-void *icnss_ipc_log_long_context;
-#endif
-
#define ICNSS_EVENT_PENDING 2989
#define ICNSS_EVENT_SYNC BIT(0)
@@ -4034,26 +4015,6 @@ static struct platform_driver icnss_driver = {
},
};
-#ifdef CONFIG_ICNSS_DEBUG
-static void __init icnss_ipc_log_long_context_init(void)
-{
- icnss_ipc_log_long_context = ipc_log_context_create(NUM_REG_LOG_PAGES,
- "icnss_long", 0);
- if (!icnss_ipc_log_long_context)
- icnss_pr_err("Unable to create register log context\n");
-}
-
-static void __exit icnss_ipc_log_long_context_destroy(void)
-{
- ipc_log_context_destroy(icnss_ipc_log_long_context);
- icnss_ipc_log_long_context = NULL;
-}
-#else
-
-static void __init icnss_ipc_log_long_context_init(void) { }
-static void __exit icnss_ipc_log_long_context_destroy(void) { }
-#endif
-
static int __init icnss_initialize(void)
{
icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
@@ -4061,8 +4022,6 @@ static int __init icnss_initialize(void)
if (!icnss_ipc_log_context)
icnss_pr_err("Unable to create log context\n");
- icnss_ipc_log_long_context_init();
-
return platform_driver_register(&icnss_driver);
}
@@ -4071,8 +4030,6 @@ static void __exit icnss_exit(void)
platform_driver_unregister(&icnss_driver);
ipc_log_context_destroy(icnss_ipc_log_context);
icnss_ipc_log_context = NULL;
-
- icnss_ipc_log_long_context_destroy();
}
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 2244c64d28af..4d9767b6f8a3 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -583,11 +583,35 @@ static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt)
return pil_init_entry_addr(priv, mdt);
}
+struct pil_map_fw_info {
+ void *region;
+ struct dma_attrs attrs;
+ phys_addr_t base_addr;
+ struct device *dev;
+};
+
static void pil_release_mmap(struct pil_desc *desc)
{
struct pil_priv *priv = desc->priv;
struct pil_seg *p, *tmp;
u64 zero = 0ULL;
+ u8 __iomem *buf;
+
+ struct pil_map_fw_info map_fw_info = {
+ .attrs = desc->attrs,
+ .region = priv->region,
+ .base_addr = priv->region_start,
+ .dev = desc->dev,
+ };
+
+ void *map_data = desc->map_data ? desc->map_data : &map_fw_info;
+
+ /* Clear memory so that unauthorized ELF code is not left behind */
+ buf = desc->map_fw_mem(priv->region_start, (priv->region_end -
+ priv->region_start), map_data);
+ pil_memset_io(buf, 0, (priv->region_end - priv->region_start));
+ desc->unmap_fw_mem(buf, (priv->region_end - priv->region_start),
+ map_data);
if (priv->info) {
__iowrite32_copy(&priv->info->start, &zero,
@@ -603,13 +627,6 @@ static void pil_release_mmap(struct pil_desc *desc)
#define IOMAP_SIZE SZ_1M
-struct pil_map_fw_info {
- void *region;
- struct dma_attrs attrs;
- phys_addr_t base_addr;
- struct device *dev;
-};
-
static void *map_fw_mem(phys_addr_t paddr, size_t size, void *data)
{
struct pil_map_fw_info *info = data;
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index dd543daca1b4..4ba92436bd06 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -90,6 +90,7 @@ struct qbt1000_drvdata {
struct finger_detect_gpio fd_gpio;
DECLARE_KFIFO(fw_events, struct fw_event_desc, MAX_FW_EVENTS);
wait_queue_head_t read_wait_queue;
+ struct qseecom_handle *app_handle;
struct qseecom_handle *fp_app_handle;
};
@@ -147,7 +148,8 @@ static int get_cmd_rsp_buffers(struct qseecom_handle *hdl,
*cmd_len = ALIGN(*cmd_len, 64);
*rsp_len = ALIGN(*rsp_len, 64);
- if ((*rsp_len + *cmd_len) > g_app_buf_size) {
+ if (((uint64_t)*rsp_len + (uint64_t)*cmd_len)
+ > (uint64_t)g_app_buf_size) {
pr_err("buffer too small to hold cmd=%d and rsp=%d\n",
*cmd_len, *rsp_len);
return -ENOMEM;
@@ -261,6 +263,13 @@ static int send_tz_cmd(struct qbt1000_drvdata *drvdata,
if (rc != 0)
goto end;
+ if (!aligned_cmd) {
+ dev_err(drvdata->dev, "%s: Null command buffer\n",
+ __func__);
+ rc = -EINVAL;
+ goto end;
+ }
+
if (aligned_cmd - cmd + cmd_len > g_app_buf_size) {
rc = -ENOMEM;
goto end;
@@ -392,13 +401,26 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
goto end;
}
+ if (drvdata->app_handle) {
+ dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n",
+ __func__);
+ drvdata->fp_app_handle = 0;
+ rc = qseecom_shutdown_app(&drvdata->app_handle);
+ if (rc != 0) {
+ dev_err(drvdata->dev, "%s: LOAD current app failed to shutdown\n",
+ __func__);
+ goto end;
+ }
+ }
+
pr_debug("app %s load before\n", app.name);
/* start the TZ app */
- rc = qseecom_start_app(&app_handle, app.name, app.size);
+ rc = qseecom_start_app(
+ &drvdata->app_handle, app.name, app.size);
if (rc == 0) {
g_app_buf_size = app.size;
- rc = qseecom_set_bandwidth(app_handle,
+ rc = qseecom_set_bandwidth(drvdata->app_handle,
app.high_band_width == 1 ? true : false);
if (rc != 0) {
/* log error, allow to continue */
@@ -409,7 +431,9 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
goto end;
}
- /* copy the app handle to user */
+ /* copy a fake app handle to user */
+ app_handle = drvdata->app_handle ?
+ (struct qseecom_handle *)123456 : 0;
rc = copy_to_user((void __user *)app.app_handle, &app_handle,
sizeof(*app.app_handle));
@@ -424,14 +448,14 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_debug("app %s load after\n", app.name);
if (!strcmp(app.name, FP_APP_NAME))
- drvdata->fp_app_handle = app_handle;
+ drvdata->fp_app_handle = drvdata->app_handle;
break;
}
case QBT1000_UNLOAD_APP:
{
struct qbt1000_app app;
- struct qseecom_handle *app_handle;
+ struct qseecom_handle *app_handle = 0;
if (copy_from_user(&app, priv_arg,
sizeof(app)) != 0) {
@@ -459,19 +483,19 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* if the app hasn't been loaded already, return err */
- if (!app_handle) {
+ if (!drvdata->app_handle) {
pr_err("app not loaded\n");
rc = -EINVAL;
goto end;
}
- if (drvdata->fp_app_handle == app_handle)
+ if (drvdata->fp_app_handle == drvdata->app_handle)
drvdata->fp_app_handle = 0;
/* set bw & shutdown the TZ app */
- qseecom_set_bandwidth(app_handle,
+ qseecom_set_bandwidth(drvdata->app_handle,
app.high_band_width == 1 ? true : false);
- rc = qseecom_shutdown_app(&app_handle);
+ rc = qseecom_shutdown_app(&drvdata->app_handle);
if (rc != 0) {
pr_err("app failed to shutdown\n");
goto end;
@@ -513,14 +537,14 @@ static long qbt1000_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* if the app hasn't been loaded already, return err */
- if (!tzcmd.app_handle) {
+ if (!drvdata->app_handle) {
pr_err("app not loaded\n");
rc = -EINVAL;
goto end;
}
rc = send_tz_cmd(drvdata,
- tzcmd.app_handle, 1,
+ drvdata->app_handle, 1,
tzcmd.req_buf, tzcmd.req_buf_len,
&rsp_buf, tzcmd.rsp_buf_len);
@@ -1112,6 +1136,7 @@ static int qbt1000_read_device_tree(struct platform_device *pdev,
}
/* read finger detect GPIO configuration */
+
gpio = of_get_named_gpio_flags(pdev->dev.of_node,
"qcom,finger-detect-gpio", 0, &flags);
if (gpio < 0) {
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
index 50dd9256b270..10f71b85a15b 100644
--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -42,6 +42,12 @@ struct voice_svc_prvt {
struct list_head response_queue;
wait_queue_head_t response_wait;
spinlock_t response_lock;
+ /*
+ * This mutex ensures responses are processed in sequential order and
+ * that no two threads access and free the same response at the same
+ * time.
+ */
+ struct mutex response_mutex_lock;
};
struct apr_data {
@@ -467,6 +473,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
goto done;
}
+ mutex_lock(&prtd->response_mutex_lock);
spin_lock_irqsave(&prtd->response_lock, spin_flags);
if (list_empty(&prtd->response_queue)) {
@@ -480,7 +487,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
pr_debug("%s: Read timeout\n", __func__);
ret = -ETIMEDOUT;
- goto done;
+ goto unlock;
} else if (ret > 0 && !list_empty(&prtd->response_queue)) {
pr_debug("%s: Interrupt recieved for response\n",
__func__);
@@ -488,7 +495,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
pr_debug("%s: Interrupted by SIGNAL %d\n",
__func__, ret);
- goto done;
+ goto unlock;
}
spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -507,7 +514,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
__func__, count, size);
ret = -ENOMEM;
- goto done;
+ goto unlock;
}
if (!access_ok(VERIFY_WRITE, arg, size)) {
@@ -515,7 +522,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
__func__);
ret = -EPERM;
- goto done;
+ goto unlock;
}
ret = copy_to_user(arg, &resp->resp,
@@ -525,7 +532,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
pr_err("%s: copy_to_user failed %d\n", __func__, ret);
ret = -EPERM;
- goto done;
+ goto unlock;
}
spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -539,6 +546,8 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
ret = count;
+unlock:
+ mutex_unlock(&prtd->response_mutex_lock);
done:
return ret;
}
@@ -594,6 +603,7 @@ static int voice_svc_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&prtd->response_queue);
init_waitqueue_head(&prtd->response_wait);
spin_lock_init(&prtd->response_lock);
+ mutex_init(&prtd->response_mutex_lock);
file->private_data = (void *)prtd;
/* Current APR implementation doesn't support session based
@@ -644,6 +654,7 @@ static int voice_svc_release(struct inode *inode, struct file *file)
pr_err("%s: Failed to dereg MVM %d\n", __func__, ret);
}
+ mutex_lock(&prtd->response_mutex_lock);
spin_lock_irqsave(&prtd->response_lock, spin_flags);
while (!list_empty(&prtd->response_queue)) {
@@ -657,6 +668,9 @@ static int voice_svc_release(struct inode *inode, struct file *file)
}
spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+ mutex_unlock(&prtd->response_mutex_lock);
+
+ mutex_destroy(&prtd->response_mutex_lock);
kfree(file->private_data);
file->private_data = NULL;
diff --git a/drivers/soc/qcom/rpm_rail_stats.c b/drivers/soc/qcom/rpm_rail_stats.c
new file mode 100644
index 000000000000..d80a9fc5146a
--- /dev/null
+++ b/drivers/soc/qcom/rpm_rail_stats.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2015,2017, 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/debugfs.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/uaccess.h>
+
+#include "rpm_stats.h"
+
+#define RPM_RAIL_BUF_LEN 600
+
+#define SNPRINTF(buf, size, format, ...) \
+{ \
+ if (size > 0) { \
+ int ret; \
+ ret = snprintf(buf, size, format, ## __VA_ARGS__); \
+ if (ret > size) { \
+ buf += size; \
+ size = 0; \
+ } else { \
+ buf += ret; \
+ size -= ret; \
+ } \
+ } \
+}
+
+#define NAMELEN (sizeof(uint32_t)+1)
+
+struct msm_rpm_rail_stats_platform_data {
+ phys_addr_t phys_addr_base;
+ u32 phys_size;
+};
+
+struct msm_rpm_rail_corner {
+ uint64_t time;
+ uint32_t corner;
+ uint32_t reserved;
+};
+
+struct msm_rpm_rail_type {
+ uint32_t rail;
+ uint32_t num_corners;
+ uint32_t current_corner;
+ uint32_t last_entered;
+};
+
+struct msm_rpm_rail_stats {
+ uint32_t num_rails;
+ uint32_t reserved;
+};
+
+struct msm_rpm_rail_stats_private_data {
+ void __iomem *reg_base;
+ u32 len;
+ char buf[RPM_RAIL_BUF_LEN];
+ struct msm_rpm_rail_stats_platform_data *platform_data;
+};
+
+int msm_rpm_rail_stats_file_close(struct inode *inode, struct file *file)
+{
+ struct msm_rpm_rail_stats_private_data *private = file->private_data;
+
+ if (private->reg_base)
+ iounmap(private->reg_base);
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static int msm_rpm_rail_corner_copy(void __iomem **base, char **buf,
+ int count)
+{
+ struct msm_rpm_rail_corner rc;
+ char corner[NAMELEN];
+
+ memset(&rc, 0, sizeof(rc));
+ memcpy_fromio(&rc, *base, sizeof(rc));
+
+ corner[NAMELEN - 1] = '\0';
+ memcpy(corner, &rc.corner, NAMELEN - 1);
+ SNPRINTF(*buf, count, "\t\tcorner:%-5s time:%-16llu\n",
+ corner, rc.time);
+
+ *base += sizeof(rc);
+
+ return count;
+}
+
+static int msm_rpm_rail_type_copy(void __iomem **base, char **buf, int count)
+{
+ struct msm_rpm_rail_type rt;
+ char rail[NAMELEN];
+ int i;
+
+ memset(&rt, 0, sizeof(rt));
+ memcpy_fromio(&rt, *base, sizeof(rt));
+
+ rail[NAMELEN - 1] = '\0';
+ memcpy(rail, &rt.rail, NAMELEN - 1);
+ SNPRINTF(*buf, count,
+ "\trail:%-2s num_corners:%-2u current_corner:%-2u last_entered:%-8u\n",
+ rail, rt.num_corners, rt.current_corner, rt.last_entered);
+
+ *base += sizeof(rt);
+
+ for (i = 0; i < rt.num_corners; i++)
+ count = msm_rpm_rail_corner_copy(base, buf, count);
+
+ return count;
+}
+
+static int msm_rpm_rail_stats_copy(
+ struct msm_rpm_rail_stats_private_data *prvdata)
+{
+ struct msm_rpm_rail_stats rs;
+ void __iomem *base = prvdata->reg_base;
+ char *buf = prvdata->buf;
+ int count = RPM_RAIL_BUF_LEN;
+ int i;
+
+ memset(&rs, 0, sizeof(rs));
+ memcpy_fromio(&rs, base, sizeof(rs));
+
+ SNPRINTF(buf, count, "Number of Rails:%u\n", rs.num_rails);
+
+ base = prvdata->reg_base + sizeof(rs);
+
+ for (i = 0; i < rs.num_rails; i++)
+ count = msm_rpm_rail_type_copy(&base, &buf, count);
+
+ return RPM_RAIL_BUF_LEN - count;
+}
+
+static ssize_t msm_rpm_rail_stats_file_read(struct file *file,
+ char __user *bufu, size_t count, loff_t *ppos)
+{
+ struct msm_rpm_rail_stats_private_data *prvdata =
+ file->private_data;
+ struct msm_rpm_rail_stats_platform_data *pdata;
+
+ if (!prvdata)
+ return -EINVAL;
+
+ if (!prvdata->platform_data)
+ return -EINVAL;
+
+ if (!bufu || count == 0)
+ return -EINVAL;
+
+ pdata = prvdata->platform_data;
+
+ if (*ppos <= pdata->phys_size) {
+ prvdata->len = msm_rpm_rail_stats_copy(prvdata);
+ *ppos = 0;
+ }
+
+ return simple_read_from_buffer(bufu, count, ppos,
+ prvdata->buf, prvdata->len);
+}
+
+static int msm_rpm_rail_stats_file_open(struct inode *inode,
+ struct file *file)
+{
+ struct msm_rpm_rail_stats_private_data *prvdata;
+ struct msm_rpm_rail_stats_platform_data *pdata = inode->i_private;
+
+ file->private_data =
+ kzalloc(sizeof(struct msm_rpm_rail_stats_private_data),
+ GFP_KERNEL);
+
+ if (!file->private_data)
+ return -ENOMEM;
+ prvdata = file->private_data;
+
+ prvdata->reg_base = ioremap(pdata->phys_addr_base,
+ pdata->phys_size);
+ if (!prvdata->reg_base) {
+ kfree(file->private_data);
+ prvdata = NULL;
+ pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n",
+ __func__, &pdata->phys_addr_base,
+ pdata->phys_size);
+ return -EBUSY;
+ }
+
+ prvdata->len = 0;
+ prvdata->platform_data = pdata;
+ return 0;
+}
+
+
+static const struct file_operations msm_rpm_rail_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_rpm_rail_stats_file_open,
+ .read = msm_rpm_rail_stats_file_read,
+ .release = msm_rpm_rail_stats_file_close,
+ .llseek = no_llseek,
+};
+
+static int msm_rpm_rail_stats_probe(struct platform_device *pdev)
+{
+ struct dentry *dent;
+ struct msm_rpm_rail_stats_platform_data *pdata;
+ struct resource *res;
+ struct resource *offset;
+ struct device_node *node;
+ uint32_t offset_addr;
+ void __iomem *phys_ptr;
+
+ if (!pdev)
+ return -EINVAL;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "phys_addr_base");
+ if (!res)
+ return -EINVAL;
+
+ offset = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "offset_addr");
+ if (!offset)
+ return -EINVAL;
+
+ phys_ptr = ioremap_nocache(offset->start, SZ_4);
+ if (!phys_ptr) {
+ dev_err(&pdev->dev, "%s: Failed to ioremap address.\n",
+ __func__);
+ return -ENODEV;
+ }
+ offset_addr = readl_relaxed(phys_ptr);
+ iounmap(phys_ptr);
+
+ if (!offset_addr) {
+ dev_err(&pdev->dev, "%s: RPM Rail Stats not available: Exit\n",
+ __func__);
+ return 0;
+ }
+
+ node = pdev->dev.of_node;
+
+ if (pdev->dev.platform_data) {
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENOMEM;
+ } else if (node) {
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ } else {
+ dev_err(&pdev->dev, "%s: pdata is not available: Exit\n",
+ __func__);
+ return 0;
+ }
+
+ pdata->phys_addr_base = res->start + offset_addr;
+ pdata->phys_size = resource_size(res);
+
+ dent = debugfs_create_file("rpm_rail_stats", S_IRUGO, NULL,
+ pdata, &msm_rpm_rail_stats_fops);
+
+ if (!dent) {
+ dev_err(&pdev->dev, "%s: ERROR debugfs_create_file failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, dent);
+ return 0;
+}
+
+static int msm_rpm_rail_stats_remove(struct platform_device *pdev)
+{
+ struct dentry *dent = platform_get_drvdata(pdev);
+
+ debugfs_remove(dent);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static const struct of_device_id rpm_rail_table[] = {
+ {.compatible = "qcom,rpm-rail-stats"},
+ {},
+};
+
+static struct platform_driver msm_rpm_rail_stats_driver = {
+ .probe = msm_rpm_rail_stats_probe,
+ .remove = msm_rpm_rail_stats_remove,
+ .driver = {
+ .name = "msm_rpm_rail_stats",
+ .owner = THIS_MODULE,
+ .of_match_table = rpm_rail_table,
+ },
+};
+
+static int __init msm_rpm_rail_stats_init(void)
+{
+ return platform_driver_register(&msm_rpm_rail_stats_driver);
+}
+
+static void __exit msm_rpm_rail_stats_exit(void)
+{
+ platform_driver_unregister(&msm_rpm_rail_stats_driver);
+}
+
+module_init(msm_rpm_rail_stats_init);
+module_exit(msm_rpm_rail_stats_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM RPM rail Statistics driver");
+MODULE_ALIAS("platform:msm_rail_stat_log");
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 35ccc57a2dea..6a60e3624420 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -359,6 +359,11 @@ static void spcom_link_state_notif_cb(struct glink_link_state_cb_info *cb_info,
struct spcom_channel *ch = NULL;
const char *ch_name = "sp_kernel";
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return;
+ }
+
spcom_dev->link_state = cb_info->link_state;
pr_debug("spcom_link_state_notif_cb called. transport = %s edge = %s\n",
@@ -1017,7 +1022,10 @@ static void spcom_rx_abort_pending_server(void)
*/
bool spcom_is_sp_subsystem_link_up(void)
{
- return (spcom_dev->link_state == GLINK_LINK_STATE_UP);
+ if (spcom_dev == NULL)
+ return false;
+
+ return (spcom_dev->link_state == GLINK_LINK_STATE_UP);
}
EXPORT_SYMBOL(spcom_is_sp_subsystem_link_up);
@@ -1039,6 +1047,11 @@ struct spcom_client *spcom_register_client(struct spcom_client_info *info)
struct spcom_channel *ch;
struct spcom_client *client;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return NULL;
+ }
+
if (!info) {
pr_err("Invalid parameter.\n");
return NULL;
@@ -1080,6 +1093,11 @@ int spcom_unregister_client(struct spcom_client *client)
{
struct spcom_channel *ch;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return -ENODEV;
+ }
+
if (!client) {
pr_err("Invalid parameter.\n");
return -EINVAL;
@@ -1118,6 +1136,11 @@ int spcom_client_send_message_sync(struct spcom_client *client,
int ret;
struct spcom_channel *ch;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return -ENODEV;
+ }
+
if (!client || !req_ptr || !resp_ptr) {
pr_err("Invalid parameter.\n");
return -EINVAL;
@@ -1159,9 +1182,14 @@ bool spcom_client_is_server_connected(struct spcom_client *client)
{
bool connected;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return false;
+ }
+
if (!client) {
pr_err("Invalid parameter.\n");
- return -EINVAL;
+ return false;
}
connected = spcom_is_channel_connected(client->ch);
@@ -1188,6 +1216,11 @@ struct spcom_server *spcom_register_service(struct spcom_service_info *info)
struct spcom_channel *ch;
struct spcom_server *server;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return NULL;
+ }
+
if (!info) {
pr_err("Invalid parameter.\n");
return NULL;
@@ -1226,6 +1259,11 @@ int spcom_unregister_service(struct spcom_server *server)
{
struct spcom_channel *ch;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return -ENODEV;
+ }
+
if (!server) {
pr_err("Invalid parameter.\n");
return -EINVAL;
@@ -1290,6 +1328,11 @@ int spcom_server_wait_for_request(struct spcom_server *server,
int ret;
struct spcom_channel *ch;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return -ENODEV;
+ }
+
if (!server || !req_ptr) {
pr_err("Invalid parameter.\n");
return -EINVAL;
@@ -1323,6 +1366,11 @@ int spcom_server_send_response(struct spcom_server *server,
int ret;
struct spcom_channel *ch;
+ if (!spcom_is_ready()) {
+ pr_err("spcom is not ready.\n");
+ return -ENODEV;
+ }
+
if (!server || !resp_ptr) {
pr_err("Invalid parameter.\n");
return -EINVAL;
@@ -2373,7 +2421,7 @@ static int spcom_create_channel_chardev(const char *name)
devt = spcom_dev->device_no + spcom_dev->channel_count;
priv = ch;
dev = device_create(cls, parent, devt, priv, name);
- if (!dev) {
+ if (IS_ERR(dev)) {
pr_err("device_create failed.\n");
kfree(cdev);
return -ENODEV;
@@ -2426,7 +2474,7 @@ static int __init spcom_register_chardev(void)
spcom_dev->device_no, priv,
DEVICE_NAME);
- if (!spcom_dev->class_dev) {
+ if (IS_ERR(spcom_dev->class_dev)) {
pr_err("class_device_create failed %d\n", ret);
ret = -ENOMEM;
goto exit_destroy_class;
@@ -2479,6 +2527,11 @@ static int spcom_parse_dt(struct device_node *np)
pr_debug("num of predefined channels [%d].\n", num_ch);
+ if (num_ch > ARRAY_SIZE(spcom_dev->predefined_ch_name)) {
+ pr_err("too many predefined channels [%d].\n", num_ch);
+ return -EINVAL;
+ }
+
for (i = 0; i < num_ch; i++) {
ret = of_property_read_string_index(np, propname, i, &name);
if (ret) {
@@ -2544,21 +2597,23 @@ static int spcom_probe(struct platform_device *pdev)
pr_debug("register_link_state_cb(), transport [%s] edge [%s]\n",
link_info.transport, link_info.edge);
notif_handle = glink_register_link_state_cb(&link_info, spcom_dev);
- if (!notif_handle) {
+ if (IS_ERR(notif_handle)) {
pr_err("glink_register_link_state_cb(), err [%d]\n", ret);
goto fail_reg_chardev;
}
spcom_dev->ion_client = msm_ion_client_create(DEVICE_NAME);
- if (spcom_dev->ion_client == NULL) {
+ if (IS_ERR(spcom_dev->ion_client)) {
pr_err("fail to create ion client.\n");
- goto fail_reg_chardev;
+ goto fail_ion_client;
}
pr_info("Driver Initialization ok.\n");
return 0;
+fail_ion_client:
+ glink_unregister_link_state_cb(notif_handle);
fail_reg_chardev:
pr_err("Failed to init driver.\n");
spcom_unregister_chrdev();
@@ -2596,7 +2651,7 @@ static int __init spcom_init(void)
if (ret)
pr_err("spcom_driver register failed %d\n", ret);
- return 0;
+ return ret;
}
module_init(spcom_init);
diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c
index e17a1370d1f0..cbf44be7fbab 100644
--- a/drivers/soc/qcom/spss_utils.c
+++ b/drivers/soc/qcom/spss_utils.c
@@ -140,7 +140,7 @@ static ssize_t spss_debug_reg_show(struct device *dev,
{
int ret;
void __iomem *spss_debug_reg = NULL;
- int val1, val2;
+ u32 val1, val2;
if (!dev || !attr || !buf) {
pr_err("invalid param.\n");
@@ -149,7 +149,7 @@ static ssize_t spss_debug_reg_show(struct device *dev,
pr_debug("spss_debug_reg_addr [0x%x].\n", spss_debug_reg_addr);
- spss_debug_reg = ioremap_nocache(spss_debug_reg_addr, 0x16);
+ spss_debug_reg = ioremap_nocache(spss_debug_reg_addr, sizeof(u32)*2);
if (!spss_debug_reg) {
pr_err("can't map debug reg addr.\n");
@@ -157,7 +157,7 @@ static ssize_t spss_debug_reg_show(struct device *dev,
}
val1 = readl_relaxed(spss_debug_reg);
- val2 = readl_relaxed(((char *) spss_debug_reg) + 0x04);
+ val2 = readl_relaxed(((char *) spss_debug_reg) + sizeof(u32));
ret = snprintf(buf, PAGE_SIZE, "val1 [0x%x] val2 [0x%x]", val1, val2);
@@ -192,12 +192,15 @@ static int spss_create_sysfs(struct device *dev)
ret = device_create_file(dev, &dev_attr_test_fuse_state);
if (ret < 0) {
pr_err("failed to create sysfs file for test_fuse_state.\n");
+ device_remove_file(dev, &dev_attr_firmware_name);
return ret;
}
ret = device_create_file(dev, &dev_attr_spss_debug_reg);
if (ret < 0) {
pr_err("failed to create sysfs file for spss_debug_reg.\n");
+ device_remove_file(dev, &dev_attr_firmware_name);
+ device_remove_file(dev, &dev_attr_test_fuse_state);
return ret;
}
@@ -284,13 +287,16 @@ static int spss_parse_dt(struct device_node *node)
(int) spss_fuse2_addr, (int) spss_fuse2_bit);
spss_fuse1_reg = ioremap_nocache(spss_fuse1_addr, sizeof(u32));
- spss_fuse2_reg = ioremap_nocache(spss_fuse2_addr, sizeof(u32));
if (!spss_fuse1_reg) {
pr_err("can't map fuse1 addr.\n");
return -EFAULT;
}
+
+ spss_fuse2_reg = ioremap_nocache(spss_fuse2_addr, sizeof(u32));
+
if (!spss_fuse2_reg) {
+ iounmap(spss_fuse1_reg);
pr_err("can't map fuse2 addr.\n");
return -EFAULT;
}
@@ -380,7 +386,11 @@ static int spss_probe(struct platform_device *pdev)
return -EFAULT;
}
- spss_create_sysfs(dev);
+ ret = spss_create_sysfs(dev);
+ if (ret < 0) {
+ pr_err("fail to create sysfs.\n");
+ return -EFAULT;
+ }
pr_info("Initialization completed ok, firmware_name [%s].\n",
firmware_name);
@@ -415,7 +425,7 @@ static int __init spss_init(void)
if (ret)
pr_err("register platform driver failed, ret [%d]\n", ret);
- return 0;
+ return ret;
}
late_initcall(spss_init); /* start after PIL driver */
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index b81348ceb469..2d52fcaf954a 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1118,7 +1118,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd)
void *tx_buf, *rx_buf;
u32 tx_len, rx_len;
- dev = &dd->spi->dev;
+ dev = dd->dev;
xfr = dd->cur_transfer;
tx_buf = (void *)xfr->tx_buf;
@@ -2484,6 +2484,7 @@ static int msm_spi_probe(struct platform_device *pdev)
dd->use_dma = 1;
}
+ spi_dma_mask(&pdev->dev);
skip_dma_resources:
spin_lock_init(&dd->queue_lock);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 53ec1e600594..7a5cfadaa5a0 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -165,6 +165,13 @@ enum msm_spi_state {
/* Data Mover commands should be aligned to 64 bit(8 bytes) */
#define DM_BYTE_ALIGN 8
+#if defined(CONFIG_ARM64) || defined(CONFIG_LPAE)
+#define spi_dma_mask(dev) (dma_set_mask((dev), DMA_BIT_MASK(36)))
+#else
+#define spi_dma_mask(dev) (dma_set_mask((dev), DMA_BIT_MASK(32)))
+#endif
+
+
enum msm_spi_qup_version {
SPI_QUP_VERSION_NONE = 0x0,
SPI_QUP_VERSION_BFAM = 0x2,
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 2ac9b28e036f..5b648460e621 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1079,7 +1079,7 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->regs_size = resource_size(res);
/* default to highest possible threshold */
- lpm_nyet_threshold = 0xff;
+ lpm_nyet_threshold = 0xf;
/* default to -3.5dB de-emphasis */
tx_de_emphasis = 1;
diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c
index 061095b78c37..baffff7e52e9 100644
--- a/drivers/usb/gadget/function/f_qc_rndis.c
+++ b/drivers/usb/gadget/function/f_qc_rndis.c
@@ -1257,7 +1257,7 @@ usb_function *rndis_qc_bind_config_vendor(struct usb_function_instance *fi,
static struct usb_function *qcrndis_alloc(struct usb_function_instance *fi)
{
- return rndis_qc_bind_config_vendor(fi, 0, NULL, 1, 0);
+ return rndis_qc_bind_config_vendor(fi, 0, NULL, 0, 0);
}
static int rndis_qc_open_dev(struct inode *ip, struct file *fp)
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 93262f3034d1..b2f082d64855 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -816,6 +816,7 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf)
case RNDIS_MSG_INIT:
pr_debug("%s: RNDIS_MSG_INIT\n",
__func__);
+ tmp++; /* to get RequestID */
major = get_unaligned_le32(tmp++);
minor = get_unaligned_le32(tmp++);
max_transfer_size = get_unaligned_le32(tmp++);
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
index 83a98f1196f8..4975ba474f97 100644
--- a/drivers/usb/gadget/function/u_data_ipa.c
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -95,6 +95,7 @@ static void ipa_data_start_endless_xfer(struct ipa_data_ch_info *port, bool in)
{
unsigned long flags;
int status;
+ struct usb_ep *ep;
spin_lock_irqsave(&port->port_lock, flags);
if (!port->port_usb || (in && !port->tx_req)
@@ -103,18 +104,22 @@ static void ipa_data_start_endless_xfer(struct ipa_data_ch_info *port, bool in)
pr_err("%s(): port_usb/req is NULL.\n", __func__);
return;
}
+
+ if (in)
+ ep = port->port_usb->in;
+ else
+ ep = port->port_usb->out;
+
spin_unlock_irqrestore(&port->port_lock, flags);
if (in) {
pr_debug("%s: enqueue endless TX_REQ(IN)\n", __func__);
- status = usb_ep_queue(port->port_usb->in,
- port->tx_req, GFP_ATOMIC);
+ status = usb_ep_queue(ep, port->tx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing endless TX_REQ, %d\n", status);
} else {
pr_debug("%s: enqueue endless RX_REQ(OUT)\n", __func__);
- status = usb_ep_queue(port->port_usb->out,
- port->rx_req, GFP_ATOMIC);
+ status = usb_ep_queue(ep, port->rx_req, GFP_ATOMIC);
if (status)
pr_err("error enqueuing endless RX_REQ, %d\n", status);
}
@@ -132,6 +137,7 @@ static void ipa_data_stop_endless_xfer(struct ipa_data_ch_info *port, bool in)
{
unsigned long flags;
int status;
+ struct usb_ep *ep;
spin_lock_irqsave(&port->port_lock, flags);
if (!port->port_usb || (in && !port->tx_req)
@@ -140,16 +146,22 @@ static void ipa_data_stop_endless_xfer(struct ipa_data_ch_info *port, bool in)
pr_err("%s(): port_usb/req is NULL.\n", __func__);
return;
}
+
+ if (in)
+ ep = port->port_usb->in;
+ else
+ ep = port->port_usb->out;
+
spin_unlock_irqrestore(&port->port_lock, flags);
if (in) {
pr_debug("%s: dequeue endless TX_REQ(IN)\n", __func__);
- status = usb_ep_dequeue(port->port_usb->in, port->tx_req);
+ status = usb_ep_dequeue(ep, port->tx_req);
if (status)
pr_err("error dequeueing endless TX_REQ, %d\n", status);
} else {
pr_debug("%s: dequeue endless RX_REQ(OUT)\n", __func__);
- status = usb_ep_dequeue(port->port_usb->out, port->rx_req);
+ status = usb_ep_dequeue(ep, port->rx_req);
if (status)
pr_err("error dequeueing endless RX_REQ, %d\n", status);
}
@@ -164,6 +176,7 @@ void ipa_data_start_rx_tx(enum ipa_func_type func)
{
struct ipa_data_ch_info *port;
unsigned long flags;
+ struct usb_ep *epin, *epout;
pr_debug("%s: Triggered: starting tx, rx", __func__);
/* queue in & out requests */
@@ -194,15 +207,17 @@ void ipa_data_start_rx_tx(enum ipa_func_type func)
return;
}
+ epout = port->port_usb->out;
+ epin = port->port_usb->in;
spin_unlock_irqrestore(&port->port_lock, flags);
/* queue in & out requests */
pr_debug("%s: Starting rx", __func__);
- if (port->port_usb->out)
+ if (epout)
ipa_data_start_endless_xfer(port, false);
pr_debug("%s: Starting tx", __func__);
- if (port->port_usb->in)
+ if (epin)
ipa_data_start_endless_xfer(port, true);
}
/**
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 611750e209f9..087cd9fecfe9 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -309,7 +309,7 @@ struct usbpd {
spinlock_t rx_lock;
u32 received_pdos[7];
- int src_cap_id;
+ u16 src_cap_id;
u8 selected_pdo;
u8 requested_pdo;
u32 rdo; /* can be either source or sink */
@@ -338,8 +338,10 @@ struct usbpd {
enum power_role current_pr;
bool in_pr_swap;
bool pd_phy_opened;
- struct completion swap_complete;
+ bool send_request;
+ struct completion is_ready;
+ struct mutex swap_lock;
struct dual_role_phy_instance *dual_role;
struct dual_role_phy_desc dr_desc;
bool send_pr_swap;
@@ -463,6 +465,9 @@ static inline void pd_reset_protocol(struct usbpd *pd)
*/
pd->rx_msgid = -1;
pd->tx_msgid = 0;
+ pd->send_request = false;
+ pd->send_pr_swap = false;
+ pd->send_dr_swap = false;
}
static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
@@ -842,7 +847,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
- complete(&pd->swap_complete);
+ complete(&pd->is_ready);
dual_role_instance_changed(pd->dual_role);
break;
@@ -977,7 +982,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SNK_READY:
pd->in_explicit_contract = true;
kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
- complete(&pd->swap_complete);
+ complete(&pd->is_ready);
dual_role_instance_changed(pd->dual_role);
break;
@@ -1546,9 +1551,9 @@ static void usbpd_sm(struct work_struct *w)
pd->hard_reset_recvd = false;
pd->caps_count = 0;
pd->hard_reset_count = 0;
- pd->src_cap_id = 0;
pd->requested_voltage = 0;
pd->requested_current = 0;
+ pd->selected_pdo = pd->requested_pdo = 0;
memset(&pd->received_pdos, 0, sizeof(pd->received_pdos));
rx_msg_cleanup(pd);
@@ -1616,8 +1621,12 @@ static void usbpd_sm(struct work_struct *w)
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
pd->in_pr_swap = false;
+ pd->in_explicit_contract = false;
+ pd->selected_pdo = pd->requested_pdo = 0;
+ pd->rdo = 0;
rx_msg_cleanup(pd);
reset_vdm_state(pd);
+ kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
if (pd->current_pr == PR_SINK) {
usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT);
@@ -1840,8 +1849,10 @@ static void usbpd_sm(struct work_struct *w)
pd_send_hard_reset(pd);
pd->in_explicit_contract = false;
+ pd->rdo = 0;
rx_msg_cleanup(pd);
reset_vdm_state(pd);
+ kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
pd->current_state = PE_SRC_TRANSITION_TO_DEFAULT;
kick_sm(pd, PS_HARD_RESET_TIME);
@@ -2075,6 +2086,9 @@ static void usbpd_sm(struct work_struct *w)
vconn_swap(pd);
} else if (IS_DATA(rx_msg, MSG_VDM)) {
handle_vdm_rx(pd, rx_msg);
+ } else if (pd->send_request) {
+ pd->send_request = false;
+ usbpd_set_state(pd, PE_SNK_SELECT_CAPABILITY);
} else if (pd->send_pr_swap && is_sink_tx_ok(pd)) {
pd->send_pr_swap = false;
ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
@@ -2158,7 +2172,10 @@ static void usbpd_sm(struct work_struct *w)
pd_send_hard_reset(pd);
pd->in_explicit_contract = false;
+ pd->selected_pdo = pd->requested_pdo = 0;
+ pd->rdo = 0;
reset_vdm_state(pd);
+ kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
usbpd_set_state(pd, PE_SNK_TRANSITION_TO_DEFAULT);
break;
@@ -2540,17 +2557,21 @@ static int usbpd_dr_set_property(struct dual_role_phy_instance *dual_role,
return -EAGAIN;
}
- reinit_completion(&pd->swap_complete);
+ mutex_lock(&pd->swap_lock);
+ reinit_completion(&pd->is_ready);
pd->send_dr_swap = true;
kick_sm(pd, 0);
/* wait for operation to complete */
- if (!wait_for_completion_timeout(&pd->swap_complete,
+ if (!wait_for_completion_timeout(&pd->is_ready,
msecs_to_jiffies(100))) {
usbpd_err(&pd->dev, "data_role swap timed out\n");
+ mutex_unlock(&pd->swap_lock);
return -ETIMEDOUT;
}
+ mutex_unlock(&pd->swap_lock);
+
if ((*val == DUAL_ROLE_PROP_DR_HOST &&
pd->current_dr != DR_DFP) ||
(*val == DUAL_ROLE_PROP_DR_DEVICE &&
@@ -2591,17 +2612,21 @@ static int usbpd_dr_set_property(struct dual_role_phy_instance *dual_role,
return -EAGAIN;
}
- reinit_completion(&pd->swap_complete);
+ mutex_lock(&pd->swap_lock);
+ reinit_completion(&pd->is_ready);
pd->send_pr_swap = true;
kick_sm(pd, 0);
/* wait for operation to complete */
- if (!wait_for_completion_timeout(&pd->swap_complete,
+ if (!wait_for_completion_timeout(&pd->is_ready,
msecs_to_jiffies(2000))) {
usbpd_err(&pd->dev, "power_role swap timed out\n");
+ mutex_unlock(&pd->swap_lock);
return -ETIMEDOUT;
}
+ mutex_unlock(&pd->swap_lock);
+
if ((*val == DUAL_ROLE_PROP_PR_SRC &&
pd->current_pr != PR_SRC) ||
(*val == DUAL_ROLE_PROP_PR_SNK &&
@@ -2864,36 +2889,62 @@ static ssize_t select_pdo_store(struct device *dev,
int pdo, uv = 0, ua = 0;
int ret;
+ mutex_lock(&pd->swap_lock);
+
/* Only allowed if we are already in explicit sink contract */
if (pd->current_state != PE_SNK_READY || !is_sink_tx_ok(pd)) {
usbpd_err(&pd->dev, "select_pdo: Cannot select new PDO yet\n");
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
ret = sscanf(buf, "%d %d %d %d", &src_cap_id, &pdo, &uv, &ua);
if (ret != 2 && ret != 4) {
usbpd_err(&pd->dev, "select_pdo: Must specify <src cap id> <PDO> [<uV> <uA>]\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (src_cap_id != pd->src_cap_id) {
usbpd_err(&pd->dev, "select_pdo: src_cap_id mismatch. Requested:%d, current:%d\n",
src_cap_id, pd->src_cap_id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (pdo < 1 || pdo > 7) {
usbpd_err(&pd->dev, "select_pdo: invalid PDO:%d\n", pdo);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ret = pd_select_pdo(pd, pdo, uv, ua);
if (ret)
- return ret;
+ goto out;
- usbpd_set_state(pd, PE_SNK_SELECT_CAPABILITY);
+ reinit_completion(&pd->is_ready);
+ pd->send_request = true;
+ kick_sm(pd, 0);
- return size;
+ /* wait for operation to complete */
+ if (!wait_for_completion_timeout(&pd->is_ready,
+ msecs_to_jiffies(1000))) {
+ usbpd_err(&pd->dev, "select_pdo: request timed out\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ /* determine if request was accepted/rejected */
+ if (pd->selected_pdo != pd->requested_pdo ||
+ pd->current_voltage != pd->requested_voltage) {
+ usbpd_err(&pd->dev, "select_pdo: request rejected\n");
+ ret = -EINVAL;
+ }
+
+out:
+ pd->send_request = false;
+ mutex_unlock(&pd->swap_lock);
+ return ret ? ret : size;
}
static ssize_t select_pdo_show(struct device *dev,
@@ -3123,6 +3174,7 @@ struct usbpd *usbpd_create(struct device *parent)
INIT_WORK(&pd->sm_work, usbpd_sm);
hrtimer_init(&pd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pd->timer.function = pd_timeout;
+ mutex_init(&pd->swap_lock);
pd->usb_psy = power_supply_get_by_name("usb");
if (!pd->usb_psy) {
@@ -3166,7 +3218,7 @@ struct usbpd *usbpd_create(struct device *parent)
pd->num_sink_caps = device_property_read_u32_array(parent,
"qcom,default-sink-caps", NULL, 0);
- if (pd->num_sink_caps) {
+ if (pd->num_sink_caps > 0) {
int i;
u32 sink_caps[14];
@@ -3233,7 +3285,7 @@ struct usbpd *usbpd_create(struct device *parent)
spin_lock_init(&pd->rx_lock);
INIT_LIST_HEAD(&pd->rx_q);
INIT_LIST_HEAD(&pd->svid_handlers);
- init_completion(&pd->swap_complete);
+ init_completion(&pd->is_ready);
pd->psy_nb.notifier_call = psy_changed;
ret = power_supply_reg_notifier(&pd->psy_nb);
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index 170cbf0a853f..6430e419fc9c 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -151,6 +151,7 @@ struct qusb_phy {
int *emu_dcm_reset_seq;
int emu_dcm_reset_seq_len;
bool put_into_high_z_state;
+ struct mutex phy_lock;
};
static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
@@ -326,6 +327,7 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
switch (value) {
case POWER_SUPPLY_DP_DM_DPF_DMF:
dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPF_DMF\n");
+ mutex_lock(&qphy->phy_lock);
if (!qphy->rm_pulldown) {
ret = qusb_phy_enable_power(qphy, true);
if (ret >= 0) {
@@ -372,14 +374,17 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
/* Make sure that above write is completed */
wmb();
- qusb_phy_enable_clocks(qphy, false);
+ if (qphy->suspended)
+ qusb_phy_enable_clocks(qphy, false);
}
}
+ mutex_unlock(&qphy->phy_lock);
break;
case POWER_SUPPLY_DP_DM_DPR_DMR:
dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPR_DMR\n");
+ mutex_lock(&qphy->phy_lock);
if (qphy->rm_pulldown) {
if (!qphy->cable_connected) {
if (qphy->tcsr_clamp_dig_n)
@@ -394,6 +399,7 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value)
qphy->rm_pulldown);
}
}
+ mutex_unlock(&qphy->phy_lock);
break;
default:
@@ -707,6 +713,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
qusb_phy_enable_clocks(qphy, false);
} else { /* Disconnect case */
+ mutex_lock(&qphy->phy_lock);
/* Disable all interrupts */
writel_relaxed(0x00,
qphy->base + QUSB2PHY_PORT_INTR_CTRL);
@@ -723,6 +730,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend)
qusb_phy_enable_power(qphy, false);
else
dev_dbg(phy->dev, "race with rm_pulldown. Keep ldo ON\n");
+ mutex_unlock(&qphy->phy_lock);
/*
* Set put_into_high_z_state to true so next USB
@@ -1081,6 +1089,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
return PTR_ERR(qphy->vdda18);
}
+ mutex_init(&qphy->phy_lock);
platform_set_drvdata(pdev, qphy);
qphy->phy.label = "msm-qusb-phy";
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 0ab6ae4bb38f..6182aa2c626e 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -576,12 +576,15 @@ struct mdss_util_intf {
int (*iommu_ctrl)(int enable);
void (*iommu_lock)(void);
void (*iommu_unlock)(void);
+ void (*vbif_reg_lock)(void);
+ void (*vbif_reg_unlock)(void);
int (*secure_session_ctrl)(int enable);
void (*bus_bandwidth_ctrl)(int enable);
int (*bus_scale_set_quota)(int client, u64 ab_quota, u64 ib_quota);
int (*panel_intf_status)(u32 disp_num, u32 intf_type);
struct mdss_panel_cfg* (*panel_intf_type)(int intf_val);
int (*dyn_clk_gating_ctrl)(int enable);
+ bool (*mdp_handoff_pending)(void);
};
struct mdss_util_intf *mdss_get_util_intf(void);
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index 8d06edf01d1d..3e1dbba7c9ae 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2017, 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
@@ -1362,7 +1362,9 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id,
(mdata->mdp_rev ==
MDSS_MDP_HW_REV_301) ||
(mdata->mdp_rev ==
- MDSS_MDP_HW_REV_320)) {
+ MDSS_MDP_HW_REV_320) ||
+ (mdata->mdp_rev ==
+ MDSS_MDP_HW_REV_330)) {
ctrl_reg += 0x8;
value_reg += 0x8;
}
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index aa74a2ec27b2..bd8e710870f7 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -132,7 +132,7 @@ static int mdss_dp_is_clk_prefix(const char *clk_prefix, const char *clk_name)
static int mdss_dp_parse_prop(struct platform_device *pdev,
struct mdss_dp_drv_pdata *dp_drv)
{
- int len = 0, i = 0;
+ int len = 0, i = 0, rc = 0;
const char *data;
data = of_get_property(pdev->dev.of_node,
@@ -160,6 +160,11 @@ static int mdss_dp_parse_prop(struct platform_device *pdev,
dp_drv->l_map[i] = data[i];
}
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,max-pclk-frequency-khz", &dp_drv->max_pclk_khz);
+ if (rc)
+ dp_drv->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
+
return 0;
}
@@ -1476,8 +1481,7 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv)
if (ret)
goto exit;
- if (dp_drv->new_vic && (dp_drv->new_vic != dp_drv->vic))
- dp_init_panel_info(dp_drv, dp_drv->new_vic);
+ dp_init_panel_info(dp_drv, dp_drv->new_vic);
dp_drv->link_rate = mdss_dp_gen_link_clk(dp_drv);
if (!dp_drv->link_rate) {
@@ -1683,7 +1687,6 @@ static int mdss_dp_edid_init(struct mdss_panel_data *pdata)
dp_drv = container_of(pdata, struct mdss_dp_drv_pdata,
panel_data);
- dp_drv->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
edid_init_data.kobj = dp_drv->kobj;
edid_init_data.max_pclk_khz = dp_drv->max_pclk_khz;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index e75e4e187de0..d57558a1b52d 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -1437,6 +1437,7 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
int ret = 0;
unsigned long flag;
+ int ignore_underflow = 0;
if (ctrl_pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -1451,6 +1452,9 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
mutex_lock(&ctrl_pdata->cmd_mutex);
+ if (ctrl_pdata->panel_mode == DSI_VIDEO_MODE)
+ ignore_underflow = 1;
+
pr_debug("%s: Checking BTA status\n", __func__);
mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle,
@@ -1459,6 +1463,9 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
reinit_completion(&ctrl_pdata->bta_comp);
mdss_dsi_enable_irq(ctrl_pdata, DSI_BTA_TERM);
spin_unlock_irqrestore(&ctrl_pdata->mdp_lock, flag);
+ /* mask out overflow errors */
+ if (ignore_underflow)
+ mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0x0f0000);
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger */
wmb();
@@ -1469,6 +1476,13 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
pr_err("%s: DSI BTA error: %i\n", __func__, ret);
}
+ if (ignore_underflow) {
+ /* clear pending overflow status */
+ mdss_dsi_set_reg(ctrl_pdata, 0xc, 0xffffffff, 0x44440000);
+ /* restore overflow isr */
+ mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0);
+ }
+
mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle,
MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF);
pr_debug("%s: BTA done with ret: %d\n", __func__, ret);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 5804d88e5af5..f05d4cb2922a 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -1251,7 +1251,6 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
- u32 const hdr_param_count = 13;
struct hdmi_tx_ctrl *ctrl = NULL;
ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
@@ -1267,26 +1266,14 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev,
goto end;
}
- if (sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u %u",
- &ctrl->hdr_data.eotf,
- &ctrl->hdr_data.display_primaries_x[0],
- &ctrl->hdr_data.display_primaries_y[0],
- &ctrl->hdr_data.display_primaries_x[1],
- &ctrl->hdr_data.display_primaries_y[1],
- &ctrl->hdr_data.display_primaries_x[2],
- &ctrl->hdr_data.display_primaries_y[2],
- &ctrl->hdr_data.white_point_x,
- &ctrl->hdr_data.white_point_y,
- &ctrl->hdr_data.max_luminance,
- &ctrl->hdr_data.min_luminance,
- &ctrl->hdr_data.max_content_light_level,
- &ctrl->hdr_data.max_average_light_level)
- != hdr_param_count) {
- pr_err("%s: Invalid HDR stream data\n", __func__);
+ if (buf == NULL) {
+ pr_err("%s: hdr stream is NULL\n", __func__);
ret = -EINVAL;
goto end;
}
+ memcpy(&ctrl->hdr_data, buf, sizeof(struct mdp_hdr_stream));
+
pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
__func__,
ctrl->hdr_data.eotf,
@@ -1306,6 +1293,14 @@ static ssize_t hdmi_tx_sysfs_wta_hdr_stream(struct device *dev,
ctrl->hdr_data.max_content_light_level,
ctrl->hdr_data.max_average_light_level);
+ pr_debug("%s: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
+ __func__,
+ ctrl->hdr_data.pixel_encoding,
+ ctrl->hdr_data.colorimetry,
+ ctrl->hdr_data.range,
+ ctrl->hdr_data.bits_per_component,
+ ctrl->hdr_data.content_type);
+
hdmi_panel_set_hdr_infoframe(ctrl);
ret = strnlen(buf, PAGE_SIZE);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
index ca316a350238..3469b8a5819f 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2017, 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
@@ -14,13 +14,13 @@
#define __MDSS_HDMI_TX_H__
#include <linux/switch.h>
+#include <linux/msm_mdp_ext.h>
#include "mdss_hdmi_util.h"
#include "mdss_hdmi_panel.h"
#include "mdss_cec_core.h"
#include "mdss_hdmi_audio.h"
#define MAX_SWITCH_NAME_SIZE 5
-#define HDR_PRIMARIES_COUNT 3
enum hdmi_tx_io_type {
HDMI_TX_CORE_IO,
@@ -62,30 +62,6 @@ struct hdmi_tx_pinctrl {
struct hdmi_tx_ctrl;
typedef int (*hdmi_tx_evt_handler) (struct hdmi_tx_ctrl *);
-/*
- * struct hdmi_tx_hdr_stream - HDR video stream characteristics
- * @eotf: Electro-Optical Transfer Function
- * @display_primaries_x: display primaries data for x-coordinate
- * @display_primaries_y: display primaries data for y-coordinate
- * @white_point_x: white point data for x-coordinate
- * @white_point_y: white point data for y-coordinate
- * @max_luminance: content maximum luminance
- * @min_luminance: content minimum luminance
- * @max_content_light_level: content maximum light level
- * @max_average_light_level: content average light level
- */
-struct hdmi_tx_hdr_stream_data {
- u32 eotf;
- u32 display_primaries_x[HDR_PRIMARIES_COUNT];
- u32 display_primaries_y[HDR_PRIMARIES_COUNT];
- u32 white_point_x;
- u32 white_point_y;
- u32 max_luminance;
- u32 min_luminance;
- u32 max_content_light_level;
- u32 max_average_light_level;
-};
-
struct hdmi_tx_ctrl {
struct platform_device *pdev;
struct platform_device *ext_pdev;
@@ -114,7 +90,7 @@ struct hdmi_tx_ctrl {
struct msm_ext_disp_audio_setup_params audio_params;
struct msm_ext_disp_init_data ext_audio_data;
struct work_struct fps_work;
- struct hdmi_tx_hdr_stream_data hdr_data;
+ struct mdp_hdr_stream hdr_data;
spinlock_t hpd_state_lock;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 4ee22abda4a2..d8d11f21f3b2 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -784,6 +784,26 @@ int mdss_update_reg_bus_vote(struct reg_bus_client *bus_client, u32 usecase_ndx)
}
#endif
+void mdss_mdp_vbif_reg_lock(void)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ mutex_lock(&mdata->reg_lock);
+}
+
+void mdss_mdp_vbif_reg_unlock(void)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ mutex_unlock(&mdata->reg_lock);
+}
+
+bool mdss_mdp_handoff_pending(void)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ return mdata->handoff_pending;
+}
static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
{
@@ -2110,6 +2130,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_set_quirk(mdata, MDSS_QUIRK_HDR_SUPPORT_ENABLED);
break;
case MDSS_MDP_HW_REV_320:
+ case MDSS_MDP_HW_REV_330:
mdata->max_target_zorder = 7; /* excluding base layer */
mdata->max_cursor_size = 512;
mdata->per_pipe_ib_factor.numer = 8;
@@ -2118,7 +2139,9 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdata->hflip_buffer_reused = false;
mdata->min_prefill_lines = 25;
mdata->has_ubwc = true;
- mdata->pixel_ram_size = 50 * 1024;
+ mdata->pixel_ram_size =
+ (mdata->mdp_rev == MDSS_MDP_HW_REV_320) ? 50 : 40;
+ mdata->pixel_ram_size *= 1024;
mdata->rects_per_sspp[MDSS_MDP_PIPE_TYPE_DMA] = 2;
mem_protect_sd_ctrl_id = MEM_PROTECT_SD_CTRL_SWITCH;
@@ -2869,6 +2892,9 @@ static int mdss_mdp_probe(struct platform_device *pdev)
mdss_res->mdss_util->bus_bandwidth_ctrl = mdss_bus_bandwidth_ctrl;
mdss_res->mdss_util->panel_intf_type = mdss_panel_intf_type;
mdss_res->mdss_util->panel_intf_status = mdss_panel_get_intf_status;
+ mdss_res->mdss_util->vbif_reg_lock = mdss_mdp_vbif_reg_lock;
+ mdss_res->mdss_util->vbif_reg_unlock = mdss_mdp_vbif_reg_unlock;
+ mdss_res->mdss_util->mdp_handoff_pending = mdss_mdp_handoff_pending;
rc = msm_dss_ioremap_byname(pdev, &mdata->mdss_io, "mdp_phys");
if (rc) {
@@ -4853,6 +4879,7 @@ static void apply_dynamic_ot_limit(u32 *ot_lim,
*ot_lim = 6;
break;
case MDSS_MDP_HW_REV_320:
+ case MDSS_MDP_HW_REV_330:
if ((res <= RES_1080p) && (params->frame_rate <= 30))
*ot_lim = 2;
else if ((res <= RES_1080p) && (params->frame_rate <= 60))
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 3542573b72ed..5e98de043e55 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -1299,7 +1299,9 @@ static inline int mdss_mdp_panic_signal_support_mode(
IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev,
MDSS_MDP_HW_REV_300) ||
IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev,
- MDSS_MDP_HW_REV_320))
+ MDSS_MDP_HW_REV_320) ||
+ IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev,
+ MDSS_MDP_HW_REV_330))
signal_mode = MDSS_MDP_PANIC_PER_PIPE_CFG;
return signal_mode;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 2a62ae5881b3..c97a58c86c29 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -1981,22 +1981,34 @@ int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
bool handoff)
{
struct mdss_panel_data *pdata;
- struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
+ struct mdss_mdp_ctl *sctl = NULL;
+ struct mdss_mdp_cmd_ctx *sctx = NULL;
struct dsi_panel_clk_ctrl clk_ctrl;
int ret = 0;
+ /* Get both controllers in the correct order for dual displays */
+ mdss_mdp_get_split_display_ctls(&ctl, &sctl);
+
+ if (sctl)
+ sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX];
+
+ /* In pingpong split we have single controller, dual context */
+ if (is_pingpong_split(ctl->mfd))
+ sctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[SLAVE_CTX];
+
pdata = ctl->panel_data;
clk_ctrl.state = MDSS_DSI_CLK_OFF;
clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
- if (sctl) {
+
+ if (sctx) { /* then slave */
u32 flags = CTL_INTF_EVENT_FLAG_SKIP_BROADCAST;
- if (is_pingpong_split(sctl->mfd))
+ if (sctx->pingpong_split_slave)
flags |= CTL_INTF_EVENT_FLAG_SLAVE_INTF;
- mdss_mdp_ctl_intf_event(sctl, MDSS_EVENT_PANEL_CLK_CTRL,
- (void *)&clk_ctrl, flags);
+ mdss_mdp_ctl_intf_event(sctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+ (void *)&clk_ctrl, flags);
}
mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index bd41cb9e025c..965a6533dfcb 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -2410,9 +2410,10 @@ bool mdss_mdp_is_amortizable_pipe(struct mdss_mdp_pipe *pipe,
(mixer->type == MDSS_MDP_MIXER_TYPE_INTF)))
return false;
- /* do not apply for sdm660 in command mode */
- if ((IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev,
- MDSS_MDP_HW_REV_320)) && !mixer->ctl->is_video_mode)
+ /* do not apply for sdm660 & sdm630 in command mode */
+ if ((IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_320) ||
+ IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_330))
+ && !mixer->ctl->is_video_mode)
return false;
return true;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 7212de8a43f9..38bff6b8edee 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -1124,6 +1124,7 @@ static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
mdata = mdss_mdp_get_mdata();
if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_320) ||
+ IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_330) ||
IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_301) ||
IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_300)) {
if (pipe->src_fmt->is_yuv) {
@@ -7666,6 +7667,7 @@ static int pp_get_driver_ops(struct mdp_pp_driver_ops *ops)
case MDSS_MDP_HW_REV_300:
case MDSS_MDP_HW_REV_301:
case MDSS_MDP_HW_REV_320:
+ case MDSS_MDP_HW_REV_330:
/*
* Some of the REV_300 PP features are same as REV_107.
* Get the driver ops for both the versions and update the
diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c
index d001f148b443..0307d570ff64 100644
--- a/drivers/video/fbdev/msm/mdss_rotator.c
+++ b/drivers/video/fbdev/msm/mdss_rotator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -1034,6 +1034,12 @@ static int mdss_rotator_calc_perf(struct mdss_rot_perf *perf)
pr_err("invalid output format\n");
return -EINVAL;
}
+ if (!config->input.width ||
+ (0xffffffff/config->input.width < config->input.height))
+ return -EINVAL;
+ if (!perf->clk_rate ||
+ (0xffffffff/perf->clk_rate < config->frame_rate))
+ return -EINVAL;
perf->clk_rate = config->input.width * config->input.height;
perf->clk_rate *= config->frame_rate;
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 7ca0cd37d43c..6930444118b6 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -845,9 +845,12 @@ int mdss_smmu_probe(struct platform_device *pdev)
}
mdss_smmu->base.iommu_ctrl = mdata->mdss_util->iommu_ctrl;
+ mdss_smmu->base.reg_lock = mdata->mdss_util->vbif_reg_lock;
+ mdss_smmu->base.reg_unlock = mdata->mdss_util->vbif_reg_unlock;
mdss_smmu->base.secure_session_ctrl =
mdata->mdss_util->secure_session_ctrl;
mdss_smmu->base.wait_for_transition = mdss_smmu_secure_wait;
+ mdss_smmu->base.handoff_pending = mdata->mdss_util->mdp_handoff_pending;
list_add(&mdss_smmu->_client, &prv->smmu_device_list);
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 5f83efb824a3..0443e06d1902 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -421,6 +421,10 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
{
spin_lock(&fiq->waitq.lock);
+ if (test_bit(FR_FINISHED, &req->flags)) {
+ spin_unlock(&fiq->waitq.lock);
+ return;
+ }
if (list_empty(&req->intr_entry)) {
list_add_tail(&req->intr_entry, &fiq->interrupts);
wake_up_locked(&fiq->waitq);
diff --git a/include/dt-bindings/clock/qcom,mmcc-msm8996.h b/include/dt-bindings/clock/qcom,mmcc-msm8996.h
index f924b92b0188..436badbaad7d 100644
--- a/include/dt-bindings/clock/qcom,mmcc-msm8996.h
+++ b/include/dt-bindings/clock/qcom,mmcc-msm8996.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -14,213 +14,177 @@
#ifndef _DT_BINDINGS_CLK_MSM_MMCC_8996_H
#define _DT_BINDINGS_CLK_MSM_MMCC_8996_H
-#define MMPLL0_EARLY 0
-#define MMPLL0_PLL 1
-#define MMPLL1_EARLY 2
-#define MMPLL1_PLL 3
-#define MMPLL2_EARLY 4
-#define MMPLL2_PLL 5
-#define MMPLL3_EARLY 6
-#define MMPLL3_PLL 7
-#define MMPLL4_EARLY 8
-#define MMPLL4_PLL 9
-#define MMPLL5_EARLY 10
-#define MMPLL5_PLL 11
-#define MMPLL8_EARLY 12
-#define MMPLL8_PLL 13
-#define MMPLL9_EARLY 14
-#define MMPLL9_PLL 15
-#define AHB_CLK_SRC 16
-#define AXI_CLK_SRC 17
-#define MAXI_CLK_SRC 18
-#define DSA_CORE_CLK_SRC 19
-#define GFX3D_CLK_SRC 20
-#define RBBMTIMER_CLK_SRC 21
-#define ISENSE_CLK_SRC 22
-#define RBCPR_CLK_SRC 23
-#define VIDEO_CORE_CLK_SRC 24
-#define VIDEO_SUBCORE0_CLK_SRC 25
-#define VIDEO_SUBCORE1_CLK_SRC 26
-#define PCLK0_CLK_SRC 27
-#define PCLK1_CLK_SRC 28
-#define MDP_CLK_SRC 29
-#define EXTPCLK_CLK_SRC 30
-#define VSYNC_CLK_SRC 31
-#define HDMI_CLK_SRC 32
-#define BYTE0_CLK_SRC 33
-#define BYTE1_CLK_SRC 34
-#define ESC0_CLK_SRC 35
-#define ESC1_CLK_SRC 36
-#define CAMSS_GP0_CLK_SRC 37
-#define CAMSS_GP1_CLK_SRC 38
-#define MCLK0_CLK_SRC 39
-#define MCLK1_CLK_SRC 40
-#define MCLK2_CLK_SRC 41
-#define MCLK3_CLK_SRC 42
-#define CCI_CLK_SRC 43
-#define CSI0PHYTIMER_CLK_SRC 44
-#define CSI1PHYTIMER_CLK_SRC 45
-#define CSI2PHYTIMER_CLK_SRC 46
-#define CSIPHY0_3P_CLK_SRC 47
-#define CSIPHY1_3P_CLK_SRC 48
-#define CSIPHY2_3P_CLK_SRC 49
-#define JPEG0_CLK_SRC 50
-#define JPEG2_CLK_SRC 51
-#define JPEG_DMA_CLK_SRC 52
-#define VFE0_CLK_SRC 53
-#define VFE1_CLK_SRC 54
-#define CPP_CLK_SRC 55
-#define CSI0_CLK_SRC 56
-#define CSI1_CLK_SRC 57
-#define CSI2_CLK_SRC 58
-#define CSI3_CLK_SRC 59
-#define FD_CORE_CLK_SRC 60
-#define MMSS_CXO_CLK 61
-#define MMSS_SLEEPCLK_CLK 62
-#define MMSS_MMAGIC_AHB_CLK 63
-#define MMSS_MMAGIC_CFG_AHB_CLK 64
-#define MMSS_MISC_AHB_CLK 65
-#define MMSS_MISC_CXO_CLK 66
-#define MMSS_BTO_AHB_CLK 67
-#define MMSS_MMAGIC_AXI_CLK 68
-#define MMSS_S0_AXI_CLK 69
+/* Hardware/Dummy/Voter clocks */
+#define GPLL0_DIV 0
+#define MDSS_MDP_VOTE_CLK 1
+#define MDSS_ROTATOR_VOTE_CLK 2
+
+/* RCG and Branches */
+#define MMPLL0_EARLY 10
+#define MMPLL0_PLL 11
+#define MMPLL1_EARLY 12
+#define MMPLL1_PLL 13
+#define MMPLL2_EARLY 14
+#define MMPLL2_PLL 15
+#define MMPLL3_EARLY 16
+#define MMPLL3_PLL 17
+#define MMPLL4_EARLY 18
+#define MMPLL4_PLL 19
+#define MMPLL5_EARLY 20
+#define MMPLL5_PLL 21
+#define MMPLL8_EARLY 22
+#define MMPLL8_PLL 23
+#define MMPLL9_EARLY 24
+#define MMPLL9_PLL 25
+#define AHB_CLK_SRC 26
+#define MAXI_CLK_SRC 27
+#define RBCPR_CLK_SRC 28
+#define VIDEO_CORE_CLK_SRC 29
+#define VIDEO_SUBCORE0_CLK_SRC 30
+#define VIDEO_SUBCORE1_CLK_SRC 31
+#define PCLK0_CLK_SRC 32
+#define PCLK1_CLK_SRC 33
+#define MDP_CLK_SRC 34
+#define EXTPCLK_CLK_SRC 35
+#define VSYNC_CLK_SRC 36
+#define HDMI_CLK_SRC 37
+#define BYTE0_CLK_SRC 38
+#define BYTE1_CLK_SRC 39
+#define ESC0_CLK_SRC 40
+#define ESC1_CLK_SRC 41
+#define CAMSS_GP0_CLK_SRC 42
+#define CAMSS_GP1_CLK_SRC 43
+#define MCLK0_CLK_SRC 44
+#define MCLK1_CLK_SRC 45
+#define MCLK2_CLK_SRC 46
+#define MCLK3_CLK_SRC 47
+#define CCI_CLK_SRC 48
+#define CSI0PHYTIMER_CLK_SRC 49
+#define CSI1PHYTIMER_CLK_SRC 50
+#define CSI2PHYTIMER_CLK_SRC 51
+#define CSIPHY0_3P_CLK_SRC 52
+#define CSIPHY1_3P_CLK_SRC 53
+#define CSIPHY2_3P_CLK_SRC 54
+#define JPEG0_CLK_SRC 55
+#define JPEG2_CLK_SRC 56
+#define JPEG_DMA_CLK_SRC 57
+#define VFE0_CLK_SRC 58
+#define VFE1_CLK_SRC 59
+#define CPP_CLK_SRC 60
+#define CSI0_CLK_SRC 61
+#define CSI1_CLK_SRC 62
+#define CSI2_CLK_SRC 63
+#define CSI3_CLK_SRC 64
+#define FD_CORE_CLK_SRC 65
+#define MMSS_MMAGIC_AHB_CLK 66
+#define MMSS_MMAGIC_CFG_AHB_CLK 67
+#define MMSS_MISC_AHB_CLK 68
+#define MMSS_MISC_CXO_CLK 69
#define MMSS_MMAGIC_MAXI_CLK 70
-#define DSA_CORE_CLK 71
-#define DSA_NOC_CFG_AHB_CLK 72
-#define MMAGIC_CAMSS_AXI_CLK 73
-#define MMAGIC_CAMSS_NOC_CFG_AHB_CLK 74
-#define THROTTLE_CAMSS_CXO_CLK 75
-#define THROTTLE_CAMSS_AHB_CLK 76
-#define THROTTLE_CAMSS_AXI_CLK 77
-#define SMMU_VFE_AHB_CLK 78
-#define SMMU_VFE_AXI_CLK 79
-#define SMMU_CPP_AHB_CLK 80
-#define SMMU_CPP_AXI_CLK 81
-#define SMMU_JPEG_AHB_CLK 82
-#define SMMU_JPEG_AXI_CLK 83
-#define MMAGIC_MDSS_AXI_CLK 84
-#define MMAGIC_MDSS_NOC_CFG_AHB_CLK 85
-#define THROTTLE_MDSS_CXO_CLK 86
-#define THROTTLE_MDSS_AHB_CLK 87
-#define THROTTLE_MDSS_AXI_CLK 88
-#define SMMU_ROT_AHB_CLK 89
-#define SMMU_ROT_AXI_CLK 90
-#define SMMU_MDP_AHB_CLK 91
-#define SMMU_MDP_AXI_CLK 92
-#define MMAGIC_VIDEO_AXI_CLK 93
-#define MMAGIC_VIDEO_NOC_CFG_AHB_CLK 94
-#define THROTTLE_VIDEO_CXO_CLK 95
-#define THROTTLE_VIDEO_AHB_CLK 96
-#define THROTTLE_VIDEO_AXI_CLK 97
-#define SMMU_VIDEO_AHB_CLK 98
-#define SMMU_VIDEO_AXI_CLK 99
-#define MMAGIC_BIMC_AXI_CLK 100
-#define MMAGIC_BIMC_NOC_CFG_AHB_CLK 101
-#define GPU_GX_GFX3D_CLK 102
-#define GPU_GX_RBBMTIMER_CLK 103
-#define GPU_AHB_CLK 104
-#define GPU_AON_ISENSE_CLK 105
-#define VMEM_MAXI_CLK 106
-#define VMEM_AHB_CLK 107
-#define MMSS_RBCPR_CLK 108
-#define MMSS_RBCPR_AHB_CLK 109
-#define VIDEO_CORE_CLK 110
-#define VIDEO_AXI_CLK 111
-#define VIDEO_MAXI_CLK 112
-#define VIDEO_AHB_CLK 113
-#define VIDEO_SUBCORE0_CLK 114
-#define VIDEO_SUBCORE1_CLK 115
-#define MDSS_AHB_CLK 116
-#define MDSS_HDMI_AHB_CLK 117
-#define MDSS_AXI_CLK 118
-#define MDSS_PCLK0_CLK 119
-#define MDSS_PCLK1_CLK 120
-#define MDSS_MDP_CLK 121
-#define MDSS_EXTPCLK_CLK 122
-#define MDSS_VSYNC_CLK 123
-#define MDSS_HDMI_CLK 124
-#define MDSS_BYTE0_CLK 125
-#define MDSS_BYTE1_CLK 126
-#define MDSS_ESC0_CLK 127
-#define MDSS_ESC1_CLK 128
-#define CAMSS_TOP_AHB_CLK 129
-#define CAMSS_AHB_CLK 130
-#define CAMSS_MICRO_AHB_CLK 131
-#define CAMSS_GP0_CLK 132
-#define CAMSS_GP1_CLK 133
-#define CAMSS_MCLK0_CLK 134
-#define CAMSS_MCLK1_CLK 135
-#define CAMSS_MCLK2_CLK 136
-#define CAMSS_MCLK3_CLK 137
-#define CAMSS_CCI_CLK 138
-#define CAMSS_CCI_AHB_CLK 139
-#define CAMSS_CSI0PHYTIMER_CLK 140
-#define CAMSS_CSI1PHYTIMER_CLK 141
-#define CAMSS_CSI2PHYTIMER_CLK 142
-#define CAMSS_CSIPHY0_3P_CLK 143
-#define CAMSS_CSIPHY1_3P_CLK 144
-#define CAMSS_CSIPHY2_3P_CLK 145
-#define CAMSS_JPEG0_CLK 146
-#define CAMSS_JPEG2_CLK 147
-#define CAMSS_JPEG_DMA_CLK 148
-#define CAMSS_JPEG_AHB_CLK 149
-#define CAMSS_JPEG_AXI_CLK 150
-#define CAMSS_VFE_AHB_CLK 151
-#define CAMSS_VFE_AXI_CLK 152
-#define CAMSS_VFE0_CLK 153
-#define CAMSS_VFE0_STREAM_CLK 154
-#define CAMSS_VFE0_AHB_CLK 155
-#define CAMSS_VFE1_CLK 156
-#define CAMSS_VFE1_STREAM_CLK 157
-#define CAMSS_VFE1_AHB_CLK 158
-#define CAMSS_CSI_VFE0_CLK 159
-#define CAMSS_CSI_VFE1_CLK 160
-#define CAMSS_CPP_VBIF_AHB_CLK 161
-#define CAMSS_CPP_AXI_CLK 162
-#define CAMSS_CPP_CLK 163
-#define CAMSS_CPP_AHB_CLK 164
-#define CAMSS_CSI0_CLK 165
-#define CAMSS_CSI0_AHB_CLK 166
-#define CAMSS_CSI0PHY_CLK 167
-#define CAMSS_CSI0RDI_CLK 168
-#define CAMSS_CSI0PIX_CLK 169
-#define CAMSS_CSI1_CLK 170
-#define CAMSS_CSI1_AHB_CLK 171
-#define CAMSS_CSI1PHY_CLK 172
-#define CAMSS_CSI1RDI_CLK 173
-#define CAMSS_CSI1PIX_CLK 174
-#define CAMSS_CSI2_CLK 175
-#define CAMSS_CSI2_AHB_CLK 176
-#define CAMSS_CSI2PHY_CLK 177
-#define CAMSS_CSI2RDI_CLK 178
-#define CAMSS_CSI2PIX_CLK 179
-#define CAMSS_CSI3_CLK 180
-#define CAMSS_CSI3_AHB_CLK 181
-#define CAMSS_CSI3PHY_CLK 182
-#define CAMSS_CSI3RDI_CLK 183
-#define CAMSS_CSI3PIX_CLK 184
-#define CAMSS_ISPIF_AHB_CLK 185
-#define FD_CORE_CLK 186
-#define FD_CORE_UAR_CLK 187
-#define FD_AHB_CLK 188
-#define MMSS_SPDM_CSI0_CLK 189
-#define MMSS_SPDM_JPEG_DMA_CLK 190
-#define MMSS_SPDM_CPP_CLK 191
-#define MMSS_SPDM_PCLK0_CLK 192
-#define MMSS_SPDM_AHB_CLK 193
-#define MMSS_SPDM_GFX3D_CLK 194
-#define MMSS_SPDM_PCLK1_CLK 195
-#define MMSS_SPDM_JPEG2_CLK 196
-#define MMSS_SPDM_DEBUG_CLK 197
-#define MMSS_SPDM_VFE1_CLK 198
-#define MMSS_SPDM_VFE0_CLK 199
-#define MMSS_SPDM_VIDEO_CORE_CLK 200
-#define MMSS_SPDM_AXI_CLK 201
-#define MMSS_SPDM_MDP_CLK 202
-#define MMSS_SPDM_JPEG0_CLK 203
-#define MMSS_SPDM_RM_AXI_CLK 204
-#define MMSS_SPDM_RM_MAXI_CLK 205
+#define MMAGIC_CAMSS_AXI_CLK 71
+#define MMAGIC_CAMSS_NOC_CFG_AHB_CLK 72
+#define SMMU_VFE_AHB_CLK 73
+#define SMMU_VFE_AXI_CLK 74
+#define SMMU_CPP_AHB_CLK 75
+#define SMMU_CPP_AXI_CLK 76
+#define SMMU_JPEG_AHB_CLK 77
+#define SMMU_JPEG_AXI_CLK 78
+#define MMAGIC_MDSS_AXI_CLK 79
+#define MMAGIC_MDSS_NOC_CFG_AHB_CLK 80
+#define SMMU_ROT_AHB_CLK 81
+#define SMMU_ROT_AXI_CLK 82
+#define SMMU_MDP_AHB_CLK 83
+#define SMMU_MDP_AXI_CLK 84
+#define MMAGIC_VIDEO_AXI_CLK 85
+#define MMAGIC_VIDEO_NOC_CFG_AHB_CLK 86
+#define SMMU_VIDEO_AHB_CLK 87
+#define SMMU_VIDEO_AXI_CLK 88
+#define MMAGIC_BIMC_NOC_CFG_AHB_CLK 89
+#define VMEM_MAXI_CLK 90
+#define VMEM_AHB_CLK 91
+#define MMSS_RBCPR_CLK 92
+#define MMSS_RBCPR_AHB_CLK 93
+#define VIDEO_CORE_CLK 94
+#define VIDEO_AXI_CLK 95
+#define VIDEO_MAXI_CLK 96
+#define VIDEO_AHB_CLK 97
+#define VIDEO_SUBCORE0_CLK 98
+#define VIDEO_SUBCORE1_CLK 99
+#define MDSS_AHB_CLK 100
+#define MDSS_HDMI_AHB_CLK 101
+#define MDSS_AXI_CLK 102
+#define MDSS_PCLK0_CLK 103
+#define MDSS_PCLK1_CLK 104
+#define MDSS_MDP_CLK 105
+#define MDSS_EXTPCLK_CLK 106
+#define MDSS_VSYNC_CLK 107
+#define MDSS_HDMI_CLK 108
+#define MDSS_BYTE0_CLK 109
+#define MDSS_BYTE1_CLK 110
+#define MDSS_ESC0_CLK 111
+#define MDSS_ESC1_CLK 112
+#define CAMSS_TOP_AHB_CLK 113
+#define CAMSS_AHB_CLK 114
+#define CAMSS_MICRO_AHB_CLK 115
+#define CAMSS_GP0_CLK 116
+#define CAMSS_GP1_CLK 117
+#define CAMSS_MCLK0_CLK 118
+#define CAMSS_MCLK1_CLK 119
+#define CAMSS_MCLK2_CLK 120
+#define CAMSS_MCLK3_CLK 121
+#define CAMSS_CCI_CLK 122
+#define CAMSS_CCI_AHB_CLK 123
+#define CAMSS_CSI0PHYTIMER_CLK 124
+#define CAMSS_CSI1PHYTIMER_CLK 125
+#define CAMSS_CSI2PHYTIMER_CLK 126
+#define CAMSS_CSIPHY0_3P_CLK 127
+#define CAMSS_CSIPHY1_3P_CLK 128
+#define CAMSS_CSIPHY2_3P_CLK 129
+#define CAMSS_JPEG0_CLK 130
+#define CAMSS_JPEG2_CLK 131
+#define CAMSS_JPEG_DMA_CLK 132
+#define CAMSS_JPEG_AHB_CLK 133
+#define CAMSS_JPEG_AXI_CLK 134
+#define CAMSS_VFE_AHB_CLK 135
+#define CAMSS_VFE_AXI_CLK 136
+#define CAMSS_VFE0_CLK 137
+#define CAMSS_VFE0_STREAM_CLK 138
+#define CAMSS_VFE0_AHB_CLK 139
+#define CAMSS_VFE1_CLK 140
+#define CAMSS_VFE1_STREAM_CLK 141
+#define CAMSS_VFE1_AHB_CLK 142
+#define CAMSS_CSI_VFE0_CLK 143
+#define CAMSS_CSI_VFE1_CLK 144
+#define CAMSS_CPP_VBIF_AHB_CLK 145
+#define CAMSS_CPP_AXI_CLK 146
+#define CAMSS_CPP_CLK 147
+#define CAMSS_CPP_AHB_CLK 148
+#define CAMSS_CSI0_CLK 149
+#define CAMSS_CSI0_AHB_CLK 150
+#define CAMSS_CSI0PHY_CLK 151
+#define CAMSS_CSI0RDI_CLK 152
+#define CAMSS_CSI0PIX_CLK 153
+#define CAMSS_CSI1_CLK 154
+#define CAMSS_CSI1_AHB_CLK 155
+#define CAMSS_CSI1PHY_CLK 156
+#define CAMSS_CSI1RDI_CLK 157
+#define CAMSS_CSI1PIX_CLK 158
+#define CAMSS_CSI2_CLK 159
+#define CAMSS_CSI2_AHB_CLK 160
+#define CAMSS_CSI2PHY_CLK 161
+#define CAMSS_CSI2RDI_CLK 162
+#define CAMSS_CSI2PIX_CLK 163
+#define CAMSS_CSI3_CLK 164
+#define CAMSS_CSI3_AHB_CLK 165
+#define CAMSS_CSI3PHY_CLK 166
+#define CAMSS_CSI3RDI_CLK 167
+#define CAMSS_CSI3PIX_CLK 168
+#define CAMSS_ISPIF_AHB_CLK 169
+#define FD_CORE_CLK 170
+#define FD_CORE_UAR_CLK 171
+#define FD_AHB_CLK 172
+/* Block resets */
#define MMAGICAHB_BCR 0
#define MMAGIC_CFG_BCR 1
#define MISC_BCR 2
@@ -241,63 +205,60 @@
#define THROTTLE_VIDEO_BCR 17
#define SMMU_VIDEO_BCR 18
#define MMAGIC_BIMC_BCR 19
-#define GPU_GX_BCR 20
-#define GPU_BCR 21
-#define GPU_AON_BCR 22
-#define VMEM_BCR 23
-#define MMSS_RBCPR_BCR 24
-#define VIDEO_BCR 25
-#define MDSS_BCR 26
-#define CAMSS_TOP_BCR 27
-#define CAMSS_AHB_BCR 28
-#define CAMSS_MICRO_BCR 29
-#define CAMSS_CCI_BCR 30
-#define CAMSS_PHY0_BCR 31
-#define CAMSS_PHY1_BCR 32
-#define CAMSS_PHY2_BCR 33
-#define CAMSS_CSIPHY0_3P_BCR 34
-#define CAMSS_CSIPHY1_3P_BCR 35
-#define CAMSS_CSIPHY2_3P_BCR 36
-#define CAMSS_JPEG_BCR 37
-#define CAMSS_VFE_BCR 38
-#define CAMSS_VFE0_BCR 39
-#define CAMSS_VFE1_BCR 40
-#define CAMSS_CSI_VFE0_BCR 41
-#define CAMSS_CSI_VFE1_BCR 42
-#define CAMSS_CPP_TOP_BCR 43
-#define CAMSS_CPP_BCR 44
-#define CAMSS_CSI0_BCR 45
-#define CAMSS_CSI0RDI_BCR 46
-#define CAMSS_CSI0PIX_BCR 47
-#define CAMSS_CSI1_BCR 48
-#define CAMSS_CSI1RDI_BCR 49
-#define CAMSS_CSI1PIX_BCR 50
-#define CAMSS_CSI2_BCR 51
-#define CAMSS_CSI2RDI_BCR 52
-#define CAMSS_CSI2PIX_BCR 53
-#define CAMSS_CSI3_BCR 54
-#define CAMSS_CSI3RDI_BCR 55
-#define CAMSS_CSI3PIX_BCR 56
-#define CAMSS_ISPIF_BCR 57
-#define FD_BCR 58
-#define MMSS_SPDM_RM_BCR 59
+#define VMEM_BCR 20
+#define MMSS_RBCPR_BCR 21
+#define VIDEO_BCR 22
+#define MDSS_BCR 23
+#define CAMSS_TOP_BCR 24
+#define CAMSS_AHB_BCR 25
+#define CAMSS_MICRO_BCR 26
+#define CAMSS_CCI_BCR 27
+#define CAMSS_PHY0_BCR 28
+#define CAMSS_PHY1_BCR 29
+#define CAMSS_PHY2_BCR 30
+#define CAMSS_CSIPHY0_3P_BCR 31
+#define CAMSS_CSIPHY1_3P_BCR 32
+#define CAMSS_CSIPHY2_3P_BCR 33
+#define CAMSS_JPEG_BCR 34
+#define CAMSS_VFE_BCR 35
+#define CAMSS_VFE0_BCR 36
+#define CAMSS_VFE1_BCR 37
+#define CAMSS_CSI_VFE0_BCR 38
+#define CAMSS_CSI_VFE1_BCR 39
+#define CAMSS_CPP_TOP_BCR 40
+#define CAMSS_CPP_BCR 41
+#define CAMSS_CSI0_BCR 42
+#define CAMSS_CSI0RDI_BCR 43
+#define CAMSS_CSI0PIX_BCR 44
+#define CAMSS_CSI1_BCR 45
+#define CAMSS_CSI1RDI_BCR 46
+#define CAMSS_CSI1PIX_BCR 47
+#define CAMSS_CSI2_BCR 48
+#define CAMSS_CSI2RDI_BCR 49
+#define CAMSS_CSI2PIX_BCR 50
+#define CAMSS_CSI3_BCR 51
+#define CAMSS_CSI3RDI_BCR 52
+#define CAMSS_CSI3PIX_BCR 53
+#define CAMSS_ISPIF_BCR 54
+#define FD_BCR 55
+#define MMSS_SPDM_RM_BCR 56
/* Indexes for GDSCs */
-#define MMAGIC_VIDEO_GDSC 0
-#define MMAGIC_MDSS_GDSC 1
-#define MMAGIC_CAMSS_GDSC 2
-#define GPU_GDSC 3
-#define VENUS_GDSC 4
-#define VENUS_CORE0_GDSC 5
-#define VENUS_CORE1_GDSC 6
-#define CAMSS_GDSC 7
-#define VFE0_GDSC 8
-#define VFE1_GDSC 9
-#define JPEG_GDSC 10
-#define CPP_GDSC 11
-#define FD_GDSC 12
-#define MDSS_GDSC 13
-#define GPU_GX_GDSC 14
-#define MMAGIC_BIMC_GDSC 15
+#define MMAGIC_VIDEO_GDSC 0
+#define MMAGIC_MDSS_GDSC 1
+#define MMAGIC_CAMSS_GDSC 2
+#define GPU_GDSC 3
+#define VENUS_GDSC 4
+#define VENUS_CORE0_GDSC 5
+#define VENUS_CORE1_GDSC 6
+#define CAMSS_GDSC 7
+#define VFE0_GDSC 8
+#define VFE1_GDSC 9
+#define JPEG_GDSC 10
+#define CPP_GDSC 11
+#define FD_GDSC 12
+#define MDSS_GDSC 13
+#define GPU_GX_GDSC 14
+#define MMAGIC_BIMC_GDSC 15
#endif
diff --git a/include/linux/mdss_smmu_ext.h b/include/linux/mdss_smmu_ext.h
index 414ab055595a..12ad4305f145 100644
--- a/include/linux/mdss_smmu_ext.h
+++ b/include/linux/mdss_smmu_ext.h
@@ -22,6 +22,7 @@
* @iommu_ctrl: iommu ctrl function for enable/disable attach.
* @secure_session_ctrl: ctrl function for enable/disable session.
* @wait_for_transition:function to wait till secure transtion is complete.
+ * @reg_lock /reg_unlock: Lock to access shared registers.
*/
struct mdss_smmu_intf {
struct device *dev;
@@ -30,6 +31,9 @@ struct mdss_smmu_intf {
int (*iommu_ctrl)(int);
int (*secure_session_ctrl)(int);
int (*wait_for_transition)(int state, int request);
+ void (*reg_lock)(void);
+ void (*reg_unlock)(void);
+ bool (*handoff_pending)(void);
};
typedef void (*msm_smmu_handler_t) (struct mdss_smmu_intf *smmu);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 64f5c4ca09d5..457d862cb9a8 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -61,6 +61,7 @@ enum {
POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE,
POWER_SUPPLY_HEALTH_WARM,
POWER_SUPPLY_HEALTH_COOL,
+ POWER_SUPPLY_HEALTH_HOT,
};
enum {
@@ -190,6 +191,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_TRIM,
POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED,
POWER_SUPPLY_PROP_VCHG_LOOP_DBC_BYPASS,
POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW,
POWER_SUPPLY_PROP_HI_POWER,
@@ -214,6 +216,8 @@ enum power_supply_property {
POWER_SUPPLY_PROP_DP_DM,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_QNOVO,
+ POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
POWER_SUPPLY_PROP_RERUN_AICL,
POWER_SUPPLY_PROP_CYCLE_COUNT_ID,
POWER_SUPPLY_PROP_SAFETY_TIMER_EXPIRED,
@@ -237,7 +241,9 @@ enum power_supply_property {
POWER_SUPPLY_PROP_FCC_DELTA,
POWER_SUPPLY_PROP_ICL_REDUCTION,
POWER_SUPPLY_PROP_PARALLEL_MODE,
- POWER_SUPPLY_PROP_CONNECTOR_THERM_ZONE,
+ POWER_SUPPLY_PROP_DIE_HEALTH,
+ POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
+ POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/qcom_tspp.h b/include/linux/qcom_tspp.h
index 28e6695fb057..1b34c389d7f0 100644
--- a/include/linux/qcom_tspp.h
+++ b/include/linux/qcom_tspp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -70,6 +70,11 @@ struct tspp_select_source {
int enable_inverse;
};
+enum tsif_tts_source {
+ TSIF_TTS_TCR = 0, /* Time stamps from TCR counter */
+ TSIF_TTS_LPASS_TIMER /* Time stamps from AV/Qtimer Timer */
+};
+
typedef void (tspp_notifier)(int channel_id, void *user);
typedef void* (tspp_allocator)(int channel_id, u32 size,
phys_addr_t *phys_base, void *user);
@@ -96,4 +101,8 @@ int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count,
u32 size, u32 int_freq, tspp_allocator *alloc,
tspp_memfree *memfree, void *user);
+int tspp_get_tts_source(u32 dev, int *tts_source);
+int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
+ u64 *lpass_time_counter);
+
#endif /* _MSM_TSPP_H_ */
diff --git a/include/soc/qcom/cx_ipeak.h b/include/soc/qcom/cx_ipeak.h
new file mode 100644
index 000000000000..b47e6b4f9b9d
--- /dev/null
+++ b/include/soc/qcom/cx_ipeak.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2016-2017, 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_COM_CX_IPEAK_H
+#define __SOC_COM_CX_IPEAK_H
+
+struct device_node;
+struct cx_ipeak_client;
+
+#ifndef CONFIG_QCOM_CX_IPEAK
+
+static inline struct cx_ipeak_client *cx_ipeak_register(
+ struct device_node *dev_node,
+ const char *client_name)
+{
+ return NULL;
+}
+
+static inline void cx_ipeak_unregister(struct cx_ipeak_client *client)
+{
+}
+
+static inline int cx_ipeak_update(struct cx_ipeak_client *ipeak_client,
+ bool vote)
+{
+ return 0;
+}
+#else
+
+struct cx_ipeak_client *cx_ipeak_register(struct device_node *dev_node,
+ const char *client_name);
+void cx_ipeak_unregister(struct cx_ipeak_client *client);
+int cx_ipeak_update(struct cx_ipeak_client *ipeak_client, bool vote);
+
+#endif
+
+#endif /*__SOC_COM_CX_IPEAK_H*/
diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h
index e33fd9fc1841..6497d962e347 100644
--- a/include/soc/qcom/qseecomi.h
+++ b/include/soc/qcom/qseecomi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, 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
@@ -511,6 +511,9 @@ __packed struct qseecom_continue_blocked_request_ireq {
#define TZ_OS_REGISTER_LISTENER_ID \
TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x01)
+#define TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID \
+ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x06)
+
#define TZ_OS_REGISTER_LISTENER_ID_PARAM_ID \
TZ_SYSCALL_CREATE_PARAM_ID_3( \
TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1f8bba7e9ab7..ddc21d0c1bbb 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1818,11 +1818,14 @@ struct afe_port_data_cmd_rt_proxy_port_read_v2 {
#define AFE_PORT_SAMPLE_RATE_16K 16000
#define AFE_PORT_SAMPLE_RATE_48K 48000
#define AFE_PORT_SAMPLE_RATE_96K 96000
+#define AFE_PORT_SAMPLE_RATE_176P4K 176400
#define AFE_PORT_SAMPLE_RATE_192K 192000
+#define AFE_PORT_SAMPLE_RATE_352P8K 352800
#define AFE_LINEAR_PCM_DATA 0x0
#define AFE_NON_LINEAR_DATA 0x1
#define AFE_LINEAR_PCM_DATA_PACKED_60958 0x2
#define AFE_NON_LINEAR_DATA_PACKED_60958 0x3
+#define AFE_GENERIC_COMPRESSED 0x8
/* This param id is used to configure I2S interface */
#define AFE_PARAM_ID_I2S_CONFIG 0x0001020D
@@ -2471,6 +2474,13 @@ struct afe_param_id_slimbus_cfg {
*/
#define AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS 0x000102A5
+
+/* ID of the parameter used to set the endianness value for the
+ * USB audio device. It should be used with
+ * AFE_MODULE_AUDIO_DEV_INTERFACE
+ */
+#define AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT 0x000102AA
+
/* Minor version used for tracking USB audio configuration */
#define AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG 0x1
@@ -2486,6 +2496,15 @@ struct afe_param_id_usb_audio_dev_params {
u32 dev_token;
} __packed;
+struct afe_param_id_usb_audio_dev_lpcm_fmt {
+/* Minor version used for tracking USB audio device parameter.
+ * Supported values: AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG
+ */
+ u32 cfg_minor_version;
+/* Endianness of actual end USB audio device */
+ u32 endian;
+} __packed;
+
/* ID of the parameter used by AFE_PARAM_ID_USB_AUDIO_CONFIG to configure
* USB audio interface. It should be used with AFE_MODULE_AUDIO_DEV_INTERFACE
*/
@@ -2530,13 +2549,18 @@ struct afe_param_id_usb_audio_cfg {
u16 reserved;
/* device token of actual end USB aduio device */
u32 dev_token;
+/* endianness of this interface */
+ u32 endian;
} __packed;
struct afe_usb_audio_dev_param_command {
struct apr_hdr hdr;
struct afe_port_cmd_set_param_v2 param;
struct afe_port_param_data_v2 pdata;
- struct afe_param_id_usb_audio_dev_params usb_dev;
+ union {
+ struct afe_param_id_usb_audio_dev_params usb_dev;
+ struct afe_param_id_usb_audio_dev_lpcm_fmt lpcm_fmt;
+ };
} __packed;
/*
@@ -2734,25 +2758,31 @@ struct afe_param_id_tdm_cfg {
- #AFE_PORT_SAMPLE_RATE_16K
- #AFE_PORT_SAMPLE_RATE_24K
- #AFE_PORT_SAMPLE_RATE_32K
- - #AFE_PORT_SAMPLE_RATE_48K @tablebulletend */
+ - #AFE_PORT_SAMPLE_RATE_48K
+ - #AFE_PORT_SAMPLE_RATE_176P4K
+ - #AFE_PORT_SAMPLE_RATE_352P8K @tablebulletend
+ */
u32 bit_width;
/**< Bit width of the sample.
- @values 16, 24 */
+ * @values 16, 24, 32
+ */
u16 data_format;
- /**< Data format: linear and compressed
-
+ /**< Data format: linear ,compressed, generic compresssed
@values
- #AFE_LINEAR_PCM_DATA
- - #AFE_NON_LINEAR_DATA @tablebulletend */
+ - #AFE_NON_LINEAR_DATA
+ - #AFE_GENERIC_COMPRESSED
+ */
u16 sync_mode;
/**< TDM synchronization setting.
@values (short, long, slot) sync mode
- #AFE_PORT_TDM_SHORT_SYNC_BIT_MODE
- #AFE_PORT_TDM_LONG_SYNC_MODE
- - #AFE_PORT_TDM_SHORT_SYNC_SLOT_MODE @tablebulletend */
+ - #AFE_PORT_TDM_SHORT_SYNC_SLOT_MODE @tablebulletend
+ */
u16 sync_src;
/**< Synchronization source.
@@ -3608,7 +3638,7 @@ struct afe_lpass_core_shared_clk_config_command {
#define DEFAULT_COPP_TOPOLOGY 0x00010314
#define DEFAULT_POPP_TOPOLOGY 0x00010BE4
#define COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY 0x0001076B
-#define COMPRESS_PASSTHROUGH_NONE_TOPOLOGY 0x00010774
+#define COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY 0x00010774
#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
@@ -3914,6 +3944,8 @@ struct asm_softvolume_params {
#define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
+#define ASM_MEDIA_FMT_GENERIC_COMPRESSED 0x00013212
+
#define ASM_MAX_EQ_BANDS 12
#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98
@@ -3923,6 +3955,40 @@ u32 fmt_blk_size;
/* Media format block size in bytes.*/
} __packed;
+struct asm_generic_compressed_fmt_blk_t {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+
+ /*
+ * Channel mapping array of bitstream output.
+ * Channel[i] mapping describes channel i inside the buffer, where
+ * i < num_channels. All valid used channels must be
+ * present at the beginning of the array.
+ */
+ uint8_t channel_mapping[8];
+
+ /*
+ * Number of channels of the incoming bitstream.
+ * Supported values: 1,2,3,4,5,6,7,8
+ */
+ uint16_t num_channels;
+
+ /*
+ * Nominal bits per sample value of the incoming bitstream.
+ * Supported values: 16, 32
+ */
+ uint16_t bits_per_sample;
+
+ /*
+ * Nominal sampling rate of the incoming bitstream.
+ * Supported values: 8000, 11025, 16000, 22050, 24000, 32000,
+ * 44100, 48000, 88200, 96000, 176400, 192000,
+ * 352800, 384000
+ */
+ uint32_t sampling_rate;
+
+} __packed;
+
struct asm_multi_channel_pcm_fmt_blk_v2 {
struct apr_hdr hdr;
struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
@@ -9971,6 +10037,108 @@ struct afe_port_group_create {
union afe_port_group_config data;
} __packed;
+/* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to specify
+ * the timing statistics of the corresponding device interface.
+ * Client can periodically query for the device time statistics to help adjust
+ * the PLL based on the drift value. The get param command must be sent to
+ * AFE port ID corresponding to device interface
+
+ * This parameter ID supports following get param commands:
+ * #AFE_PORT_CMD_GET_PARAM_V2 and
+ * #AFE_PORT_CMD_GET_PARAM_V3.
+ */
+#define AFE_PARAM_ID_DEV_TIMING_STATS 0x000102AD
+
+/* Version information used to handle future additions to AFE device
+ * interface timing statistics (for backward compatibility).
+ */
+#define AFE_API_VERSION_DEV_TIMING_STATS 0x1
+
+/* Enumeration for specifying a sink(Rx) device */
+#define AFE_SINK_DEVICE 0x0
+
+/* Enumeration for specifying a source(Tx) device */
+#define AFE_SOURCE_DEVICE 0x1
+
+/* Enumeration for specifying the drift reference is of type AV Timer */
+#define AFE_REF_TIMER_TYPE_AVTIMER 0x0
+
+/* Message payload structure for the
+ * AFE_PARAM_ID_DEV_TIMING_STATS parameter.
+ */
+struct afe_param_id_dev_timing_stats {
+ /* Minor version used to track the version of device interface timing
+ * statistics. Currently, the supported version is 1.
+ * @values #AFE_API_VERSION_DEV_TIMING_STATS
+ */
+ u32 minor_version;
+
+ /* Indicates the device interface direction as either
+ * source (Tx) or sink (Rx).
+ * @values
+ * #AFE_SINK_DEVICE
+ * #AFE_SOURCE_DEVICE
+ */
+ u16 device_direction;
+
+ /* Reference timer for drift accumulation and time stamp information.
+ * @values
+ * #AFE_REF_TIMER_TYPE_AVTIMER @tablebulletend
+ */
+ u16 reference_timer;
+
+ /*
+ * Flag to indicate if resync is required on the client side for
+ * drift correction. Flag is set to TRUE for the first get_param
+ * response after device interface starts. This flag value can be
+ * used by client to identify if device interface restart has
+ * happened and if any re-sync is required at their end for drift
+ * correction.
+ * @values
+ * 0: FALSE (Resync not required)
+ * 1: TRUE (Resync required) @tablebulletend
+ */
+ u32 resync_flag;
+
+ /* Accumulated drift value in microseconds. This value is updated
+ * every 100th ms.
+ * Positive drift value indicates AV timer is running faster than device
+ * Negative drift value indicates AV timer is running slower than device
+ * @values Any valid int32 number
+ */
+ s32 acc_drift_value;
+
+ /* Lower 32 bits of the 64-bit absolute timestamp of reference
+ * timer in microseconds.
+
+ * This timestamp corresponds to the time when the drift values
+ * are accumlated for every 100th ms.
+ * @values Any valid uint32 number
+ */
+ u32 ref_timer_abs_ts_lsw;
+
+ /* Upper 32 bits of the 64-bit absolute timestamp of reference
+ * timer in microseconds.
+ * This timestamp corresponds to the time when the drift values
+ * are accumlated for every 100th ms.
+ * @values Any valid uint32 number
+ */
+ u32 ref_timer_abs_ts_msw;
+} __packed;
+
+struct afe_av_dev_drift_get_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_get_param_v2 get_param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_dev_timing_stats timing_stats;
+} __packed;
+
+struct afe_av_dev_drift_get_param_resp {
+ uint32_t status;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_dev_timing_stats timing_stats;
+} __packed;
+
/* Command for Matrix or Stream Router */
#define ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2 0x00010DCE
/* Module for AVSYNC */
@@ -10182,6 +10350,7 @@ enum {
COMPRESSED_PASSTHROUGH_CONVERT,
COMPRESSED_PASSTHROUGH_DSD,
LISTEN,
+ COMPRESSED_PASSTHROUGH_GEN,
};
#define AUDPROC_MODULE_ID_COMPRESSED_MUTE 0x00010770
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index e4033e712804..b1c3b0baf4b3 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -364,6 +364,8 @@ int afe_send_custom_tdm_header_cfg(
struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header_cfg,
u16 port_id);
int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
- u32 rate);
+ u32 rate, u16 num_groups);
void afe_set_routing_callback(routing_cb);
+int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
+ u16 port);
#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 9a3db9aaa25e..76bb795119c2 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -54,6 +54,7 @@
#define FORMAT_DTS 0x001c
#define FORMAT_DSD 0x001d
#define FORMAT_APTX 0x001e
+#define FORMAT_GEN_COMPR 0x001f
#define ENCDEC_SBCBITRATE 0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -500,6 +501,11 @@ int q6asm_media_format_block_multi_ch_pcm_v2(
uint32_t rate, uint32_t channels,
bool use_default_chmap, char *channel_map,
uint16_t bits_per_sample);
+int q6asm_media_format_block_gen_compr(
+ struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample);
int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
uint32_t rate, uint32_t channels,
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 8387688fb71b..19136453a5e2 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -304,6 +304,7 @@ DEFINE_EVENT(wakeup_source, wakeup_source_deactivate,
* The clock events are used for clock enable/disable and for
* clock rate change
*/
+#if defined(CONFIG_COMMON_CLK_MSM)
DECLARE_EVENT_CLASS(clock,
TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
@@ -401,6 +402,7 @@ TRACE_EVENT(clock_state,
__get_str(name), __entry->prepare_count,
__entry->count, __entry->rate, __entry->vdd_level)
);
+#endif /* CONFIG_COMMON_CLK_MSM */
/*
* The power domain events are used for power domains transitions
diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h
index a768696c90f8..175534a26792 100644
--- a/include/uapi/linux/dvb/dmx.h
+++ b/include/uapi/linux/dvb/dmx.h
@@ -148,6 +148,9 @@ enum dmx_video_codec {
#define DMX_IDX_VC1_FRAME_END 0x02000000
#define DMX_IDX_H264_ACCESS_UNIT_DEL 0x04000000
#define DMX_IDX_H264_SEI 0x08000000
+#define DMX_IDX_H264_IDR_ISLICE_START 0x10000000
+#define DMX_IDX_H264_NON_IDR_PSLICE_START 0x20000000
+#define DMX_IDX_H264_NON_IDR_BSLICE_START 0x40000000
struct dmx_pes_filter_params
{
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 6aa021e12930..16e4b8e30b07 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -147,7 +147,9 @@ enum ipa_client_type {
IPA_CLIENT_A5_WLAN_AMPDU_PROD,
IPA_CLIENT_A2_EMBEDDED_PROD,
IPA_CLIENT_A2_TETHERED_PROD,
- IPA_CLIENT_APPS_LAN_WAN_PROD,
+ IPA_CLIENT_APPS_LAN_PROD,
+ IPA_CLIENT_APPS_WAN_PROD,
+ IPA_CLIENT_APPS_LAN_WAN_PROD = IPA_CLIENT_APPS_WAN_PROD,
IPA_CLIENT_APPS_CMD_PROD,
IPA_CLIENT_ODU_PROD,
IPA_CLIENT_MHI_PROD,
diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h
index fca2a3c2d494..481814cb8498 100644
--- a/include/uapi/linux/msm_mdp.h
+++ b/include/uapi/linux/msm_mdp.h
@@ -119,6 +119,7 @@
#define MDSS_MDP_HW_REV_300 MDSS_MDP_REV(3, 0, 0) /* msm8998 */
#define MDSS_MDP_HW_REV_301 MDSS_MDP_REV(3, 0, 1) /* msm8998 v1.0 */
#define MDSS_MDP_HW_REV_320 MDSS_MDP_REV(3, 2, 0) /* sdm660 */
+#define MDSS_MDP_HW_REV_330 MDSS_MDP_REV(3, 3, 0) /* sdm630 */
enum {
NOTIFY_UPDATE_INIT,
diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h
index 3bd8bea8ae0d..ee68675bfe13 100644
--- a/include/uapi/linux/msm_mdp_ext.h
+++ b/include/uapi/linux/msm_mdp_ext.h
@@ -179,6 +179,77 @@ VALIDATE/COMMIT FLAG CONFIGURATION
#define OUT_LAYER_COLOR_SPACE
+/* From CEA.861.3 */
+#define MDP_HDR_EOTF_SMTPE_ST2084 0x2
+#define MDP_HDR_EOTF_HLG 0x3
+
+/* From Vesa DPv1.4 - Pixel Encoding - Table 2-120 */
+#define MDP_PIXEL_ENCODING_RGB 0x0
+#define MDP_PIXEL_ENCODING_YCBCR_444 0x1
+#define MDP_PIXEL_ENCODING_YCBCR_422 0x2
+#define MDP_PIXEL_ENCODING_YCBCR_420 0x3
+#define MDP_PIXEL_ENCODING_Y_ONLY 0x4
+#define MDP_PIXEL_ENCODING_RAW 0x5
+
+/* From Vesa DPv1.4 - Colorimetry Formats - Table 2-120 */
+/* RGB - used with MDP_DP_PIXEL_ENCODING_RGB */
+#define MDP_COLORIMETRY_RGB_SRGB 0x0
+#define MDP_COLORIMETRY_RGB_WIDE_FIXED_POINT 0x1
+#define MDP_COLORIMETRY_RGB_WIDE_FLOAT_POINT 0x2
+#define MDP_COLORIMETRY_RGB_ADOBE 0x3
+#define MDP_COLORIMETRY_RGB_DPI_P3 0x4
+#define MDP_COLORIMETRY_RGB_CUSTOM 0x5
+#define MDP_COLORIMETRY_RGB_ITU_R_BT_2020 0x6
+
+/* YUV - used with MDP_DP_PIXEL_ENCODING_YCBCR(444 or 422 or 420) */
+#define MDP_COLORIMETRY_YCBCR_ITU_R_BT_601 0x0
+#define MDP_COLORIMETRY_YCBCR_ITU_R_BT_709 0x1
+#define MDP_COLORIMETRY_YCBCR_XV_YCC_601 0x2
+#define MDP_COLORIMETRY_YCBCR_XV_YCC_709 0x3
+#define MDP_COLORIMETRY_YCBCR_S_YCC_601 0x4
+#define MDP_COLORIMETRY_YCBCR_ADOBE_YCC_601 0x5
+#define MDP_COLORIMETRY_YCBCR_ITU_R_BT_2020_YCBCR_CONST 0x6
+#define MDP_COLORIMETRY_YCBCR_ITU_R_BT_2020_YCBCR 0x7
+
+/* Dynamic Range - Table 2-120 */
+/* Full range */
+#define MDP_DYNAMIC_RANGE_VESA 0x0
+/* Limited range */
+#define MDP_DYNAMIC_RANGE_CEA 0x1
+
+/* Bits per component(bpc) for Pixel encoding format RGB from Table 2-120 */
+#define MDP_RGB_6_BPC 0x0
+#define MDP_RGB_8_BPC 0x1
+#define MDP_RGB_10_BPC 0x2
+#define MDP_RGB_12_BPC 0x3
+#define MDP_RGB_16_BPC 0x4
+
+/*
+ * Bits per component(bpc) for Pixel encoding format YCbCr444, YCbCr422,
+ * YCbCr420 and Y only
+ * from Table 2-120
+ */
+#define MDP_YUV_8_BPC 0x1
+#define MDP_YUV_10_BPC 0x2
+#define MDP_YUV_12_BPC 0x3
+#define MDP_YUV_16_BPC 0x4
+
+/* Bits per component(bpc) for Pixel encoding format RAW from Table 2-120 */
+#define MDP_RAW_6_BPC 0x1
+#define MDP_RAW_7_BPC 0x2
+#define MDP_RAW_8_BPC 0x3
+#define MDP_RAW_10_BPC 0x4
+#define MDP_RAW_12_BPC 0x5
+#define MDP_RAW_14_BPC 0x6
+#define MDP_RAW16_BPC 0x7
+
+/* Content Type - Table 2-120 */
+#define MDP_CONTENT_TYPE_NOT_DEFINED 0x0
+#define MDP_CONTENT_TYPE_GRAPHICS 0x1
+#define MDP_CONTENT_TYPE_PHOTO 0x2
+#define MDP_CONTENT_TYPE_VIDEO 0x3
+#define MDP_CONTENT_TYPE_GAME 0x4
+
/**********************************************************************
Configuration structures
All parameters are input to driver unless mentioned output parameter
@@ -709,4 +780,27 @@ struct mdp_set_cfg {
uint32_t len;
uint64_t __user payload;
};
+
+#define HDR_PRIMARIES_COUNT 3
+
+#define MDP_HDR_STREAM
+
+struct mdp_hdr_stream {
+ uint32_t eotf;
+ uint32_t display_primaries_x[HDR_PRIMARIES_COUNT];
+ uint32_t display_primaries_y[HDR_PRIMARIES_COUNT];
+ uint32_t white_point_x;
+ uint32_t white_point_y;
+ uint32_t max_luminance;
+ uint32_t min_luminance;
+ uint32_t max_content_light_level;
+ uint32_t max_average_light_level;
+ /* DP related */
+ uint32_t pixel_encoding;
+ uint32_t colorimetry;
+ uint32_t range;
+ uint32_t bits_per_component;
+ uint32_t content_type;
+ uint32_t reserved[5];
+};
#endif
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 582b66e882ce..e6eceb0aa496 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -597,7 +597,11 @@ void pm_qos_add_request(struct pm_qos_request *req,
case PM_QOS_REQ_AFFINE_IRQ:
if (irq_can_set_affinity(req->irq)) {
struct irq_desc *desc = irq_to_desc(req->irq);
- struct cpumask *mask = desc->irq_data.common->affinity;
+ struct cpumask *mask;
+
+ if (!desc)
+ return;
+ mask = desc->irq_data.common->affinity;
/* Get the current affinity */
cpumask_copy(&req->cpus_affine, mask);
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index aac12bfc2ae6..133b412eabc7 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -36,7 +36,7 @@ struct cluster_data {
cpumask_t cpu_mask;
unsigned int need_cpus;
unsigned int task_thres;
- s64 last_isolate_ts;
+ s64 need_ts;
struct list_head lru;
bool pending;
spinlock_t pending_lock;
@@ -549,6 +549,7 @@ static bool eval_need(struct cluster_data *cluster)
bool need_flag = false;
unsigned int active_cpus;
unsigned int new_need;
+ s64 now;
if (unlikely(!cluster->inited))
return 0;
@@ -573,9 +574,10 @@ static bool eval_need(struct cluster_data *cluster)
need_flag = adjustment_possible(cluster, new_need);
last_need = cluster->need_cpus;
- cluster->need_cpus = new_need;
+ now = ktime_to_ms(ktime_get());
- if (!need_flag) {
+ if (new_need == last_need) {
+ cluster->need_ts = now;
spin_unlock_irqrestore(&state_lock, flags);
return 0;
}
@@ -583,12 +585,15 @@ static bool eval_need(struct cluster_data *cluster)
if (need_cpus > cluster->active_cpus) {
ret = 1;
} else if (need_cpus < cluster->active_cpus) {
- s64 now = ktime_to_ms(ktime_get());
- s64 elapsed = now - cluster->last_isolate_ts;
+ s64 elapsed = now - cluster->need_ts;
ret = elapsed >= cluster->offline_delay_ms;
}
+ if (ret) {
+ cluster->need_ts = now;
+ cluster->need_cpus = new_need;
+ }
trace_core_ctl_eval_need(cluster->first_cpu, last_need, need_cpus,
ret && need_flag);
spin_unlock_irqrestore(&state_lock, flags);
@@ -746,7 +751,6 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need)
if (!sched_isolate_cpu(c->cpu)) {
c->isolated_by_us = true;
move_cpu_lru(c);
- cluster->last_isolate_ts = ktime_to_ms(ktime_get());
} else {
pr_debug("Unable to isolate CPU%u\n", c->cpu);
}
@@ -779,7 +783,6 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need)
if (!sched_isolate_cpu(c->cpu)) {
c->isolated_by_us = true;
move_cpu_lru(c);
- cluster->last_isolate_ts = ktime_to_ms(ktime_get());
} else {
pr_debug("Unable to isolate CPU%u\n", c->cpu);
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 6f68b0e19c4a..00bbd91d6767 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2620,7 +2620,6 @@ struct cpu_select_env {
u8 need_idle:1;
u8 need_waker_cluster:1;
u8 sync:1;
- u8 ignore_prev_cpu:1;
enum sched_boost_policy boost_policy;
u8 pack_task:1;
int prev_cpu;
@@ -2630,6 +2629,7 @@ struct cpu_select_env {
u64 cpu_load;
u32 sbc_best_flag;
u32 sbc_best_cluster_flag;
+ struct cpumask search_cpus;
};
struct cluster_cpu_stats {
@@ -2834,11 +2834,14 @@ struct cpu_select_env *env, struct cluster_cpu_stats *stats)
{
struct sched_cluster *next = NULL;
int i;
+ struct cpumask search_cpus;
while (!bitmap_empty(env->backup_list, num_clusters)) {
next = next_candidate(env->backup_list, 0, num_clusters);
__clear_bit(next->id, env->backup_list);
- for_each_cpu_and(i, &env->p->cpus_allowed, &next->cpus) {
+
+ cpumask_and(&search_cpus, &env->search_cpus, &next->cpus);
+ for_each_cpu(i, &search_cpus) {
trace_sched_cpu_load_wakeup(cpu_rq(i), idle_cpu(i),
sched_irqload(i), power_cost(i, task_load(env->p) +
cpu_cravg_sync(i, env->sync)), 0);
@@ -3010,11 +3013,7 @@ static void find_best_cpu_in_cluster(struct sched_cluster *c,
int i;
struct cpumask search_cpus;
- cpumask_and(&search_cpus, tsk_cpus_allowed(env->p), &c->cpus);
- cpumask_andnot(&search_cpus, &search_cpus, cpu_isolated_mask);
-
- if (env->ignore_prev_cpu)
- cpumask_clear_cpu(env->prev_cpu, &search_cpus);
+ cpumask_and(&search_cpus, &env->search_cpus, &c->cpus);
env->need_idle = wake_to_idle(env->p) || c->wake_up_idle;
@@ -3026,7 +3025,7 @@ static void find_best_cpu_in_cluster(struct sched_cluster *c,
power_cost(i, task_load(env->p) +
cpu_cravg_sync(i, env->sync)), 0);
- if (unlikely(!cpu_active(i)) || skip_cpu(i, env))
+ if (skip_cpu(i, env))
continue;
update_spare_capacity(stats, env, i, c->capacity,
@@ -3081,9 +3080,7 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats)
return false;
prev_cpu = env->prev_cpu;
- if (!cpumask_test_cpu(prev_cpu, tsk_cpus_allowed(task)) ||
- unlikely(!cpu_active(prev_cpu)) ||
- cpu_isolated(prev_cpu))
+ if (!cpumask_test_cpu(prev_cpu, &env->search_cpus))
return false;
if (task->ravg.mark_start - task->last_cpu_selected_ts >=
@@ -3116,7 +3113,7 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats)
spill_threshold_crossed(env, cpu_rq(prev_cpu))) {
update_spare_capacity(stats, env, prev_cpu,
cluster->capacity, env->cpu_load);
- env->ignore_prev_cpu = 1;
+ cpumask_clear_cpu(prev_cpu, &env->search_cpus);
return false;
}
@@ -3132,23 +3129,17 @@ wake_to_waker_cluster(struct cpu_select_env *env)
}
static inline bool
-bias_to_waker_cpu(struct task_struct *p, int cpu)
+bias_to_waker_cpu(struct cpu_select_env *env, int cpu)
{
return sysctl_sched_prefer_sync_wakee_to_waker &&
cpu_rq(cpu)->nr_running == 1 &&
- cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) &&
- cpu_active(cpu) && !cpu_isolated(cpu);
+ cpumask_test_cpu(cpu, &env->search_cpus);
}
static inline int
-cluster_allowed(struct task_struct *p, struct sched_cluster *cluster)
+cluster_allowed(struct cpu_select_env *env, struct sched_cluster *cluster)
{
- cpumask_t tmp_mask;
-
- cpumask_and(&tmp_mask, &cluster->cpus, cpu_active_mask);
- cpumask_and(&tmp_mask, &tmp_mask, &p->cpus_allowed);
-
- return !cpumask_empty(&tmp_mask);
+ return cpumask_intersects(&env->search_cpus, &cluster->cpus);
}
/* return cheapest cpu that can fit this task */
@@ -3169,7 +3160,6 @@ static int select_best_cpu(struct task_struct *p, int target, int reason,
.need_waker_cluster = 0,
.sync = sync,
.prev_cpu = target,
- .ignore_prev_cpu = 0,
.rtg = NULL,
.sbc_best_flag = 0,
.sbc_best_cluster_flag = 0,
@@ -3182,6 +3172,9 @@ static int select_best_cpu(struct task_struct *p, int target, int reason,
bitmap_copy(env.candidate_list, all_cluster_ids, NR_CPUS);
bitmap_zero(env.backup_list, NR_CPUS);
+ cpumask_and(&env.search_cpus, tsk_cpus_allowed(p), cpu_active_mask);
+ cpumask_andnot(&env.search_cpus, &env.search_cpus, cpu_isolated_mask);
+
init_cluster_cpu_stats(&stats);
special = env_has_special_flags(&env);
@@ -3191,19 +3184,19 @@ static int select_best_cpu(struct task_struct *p, int target, int reason,
if (grp && grp->preferred_cluster) {
pref_cluster = grp->preferred_cluster;
- if (!cluster_allowed(p, pref_cluster))
+ if (!cluster_allowed(&env, pref_cluster))
clear_bit(pref_cluster->id, env.candidate_list);
else
env.rtg = grp;
} else if (!special) {
cluster = cpu_rq(cpu)->cluster;
if (wake_to_waker_cluster(&env)) {
- if (bias_to_waker_cpu(p, cpu)) {
+ if (bias_to_waker_cpu(&env, cpu)) {
target = cpu;
sbc_flag = SBC_FLAG_WAKER_CLUSTER |
SBC_FLAG_WAKER_CPU;
goto out;
- } else if (cluster_allowed(p, cluster)) {
+ } else if (cluster_allowed(&env, cluster)) {
env.need_waker_cluster = 1;
bitmap_zero(env.candidate_list, NR_CPUS);
__set_bit(cluster->id, env.candidate_list);
@@ -3499,8 +3492,15 @@ static inline int migration_needed(struct task_struct *p, int cpu)
nice = task_nice(p);
rcu_read_lock();
grp = task_related_thread_group(p);
+ /*
+ * Don't assume higher capacity means higher power. If the task
+ * is running on the power efficient CPU, avoid migrating it
+ * to a lower capacity cluster.
+ */
if (!grp && (nice > SCHED_UPMIGRATE_MIN_NICE ||
- upmigrate_discouraged(p)) && cpu_capacity(cpu) > min_capacity) {
+ upmigrate_discouraged(p)) &&
+ cpu_capacity(cpu) > min_capacity &&
+ cpu_max_power_cost(cpu) == max_power_cost) {
rcu_read_unlock();
return DOWN_MIGRATION;
}
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index 3acf96d1f1d6..744c60dfb4fb 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -455,6 +455,12 @@ compare_clusters(void *priv, struct list_head *a, struct list_head *b)
cluster1 = container_of(a, struct sched_cluster, list);
cluster2 = container_of(b, struct sched_cluster, list);
+ /*
+ * Don't assume higher capacity means higher power. If the
+ * power cost is same, sort the higher capacity cluster before
+ * the lower capacity cluster to start placing the tasks
+ * on the higher capacity cluster.
+ */
ret = cluster1->max_power_cost > cluster2->max_power_cost ||
(cluster1->max_power_cost == cluster2->max_power_cost &&
cluster1->max_possible_capacity <
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 6f7985e6f129..5dd643d524d6 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -361,6 +361,9 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
unsigned long flags;
void *data;
+ if (IS_ENABLED(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE))
+ gfp_mask |= GFP_DMA;
+
local_irq_save(flags);
nc = this_cpu_ptr(&netdev_alloc_cache);
data = __alloc_page_frag(nc, fragsz, gfp_mask);
@@ -419,6 +422,9 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
len += NET_SKB_PAD;
+ if (IS_ENABLED(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE))
+ gfp_mask |= GFP_DMA;
+
if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) ||
(gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index e0b149cf1f7e..4fe9e2d50f7a 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -8098,13 +8098,8 @@ static struct snd_soc_dai_driver tavil_dai[] = {
static void tavil_codec_power_gate_digital_core(struct tavil_priv *tavil)
{
- struct snd_soc_codec *codec = tavil->codec;
-
- if (!codec)
- return;
-
mutex_lock(&tavil->power_lock);
- dev_dbg(codec->dev, "%s: Entering power gating function, %d\n",
+ dev_dbg(tavil->dev, "%s: Entering power gating function, %d\n",
__func__, tavil->power_active_ref);
if (tavil->power_active_ref > 0)
@@ -8113,16 +8108,16 @@ static void tavil_codec_power_gate_digital_core(struct tavil_priv *tavil)
wcd9xxx_set_power_state(tavil->wcd9xxx,
WCD_REGION_POWER_COLLAPSE_BEGIN,
WCD9XXX_DIG_CORE_REGION_1);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
- 0x04, 0x04);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
- 0x01, 0x00);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
- 0x02, 0x00);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04, 0x04);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x01, 0x00);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x02, 0x00);
wcd9xxx_set_power_state(tavil->wcd9xxx, WCD_REGION_POWER_DOWN,
WCD9XXX_DIG_CORE_REGION_1);
exit:
- dev_dbg(codec->dev, "%s: Exiting power gating function, %d\n",
+ dev_dbg(tavil->dev, "%s: Exiting power gating function, %d\n",
__func__, tavil->power_active_ref);
mutex_unlock(&tavil->power_lock);
}
@@ -8131,34 +8126,32 @@ static void tavil_codec_power_gate_work(struct work_struct *work)
{
struct tavil_priv *tavil;
struct delayed_work *dwork;
- struct snd_soc_codec *codec;
dwork = to_delayed_work(work);
tavil = container_of(dwork, struct tavil_priv, power_gate_work);
- codec = tavil->codec;
-
- if (!codec)
- return;
tavil_codec_power_gate_digital_core(tavil);
}
/* called under power_lock acquisition */
-static int tavil_dig_core_remove_power_collapse(struct snd_soc_codec *codec)
+static int tavil_dig_core_remove_power_collapse(struct tavil_priv *tavil)
{
- struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
-
- snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
- snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
- snd_soc_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+ regmap_write(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x05);
+ regmap_write(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x07);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+ regmap_write(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x03);
wcd9xxx_set_power_state(tavil->wcd9xxx,
WCD_REGION_POWER_COLLAPSE_REMOVE,
WCD9XXX_DIG_CORE_REGION_1);
- regcache_mark_dirty(codec->component.regmap);
- regcache_sync_region(codec->component.regmap,
+ regcache_mark_dirty(tavil->wcd9xxx->regmap);
+ regcache_sync_region(tavil->wcd9xxx->regmap,
WCD934X_DIG_CORE_REG_MIN,
WCD934X_DIG_CORE_REG_MAX);
@@ -8168,7 +8161,6 @@ static int tavil_dig_core_remove_power_collapse(struct snd_soc_codec *codec)
static int tavil_dig_core_power_collapse(struct tavil_priv *tavil,
int req_state)
{
- struct snd_soc_codec *codec;
int cur_state;
/* Exit if feature is disabled */
@@ -8189,10 +8181,6 @@ static int tavil_dig_core_power_collapse(struct tavil_priv *tavil,
goto unlock_mutex;
}
- codec = tavil->codec;
- if (!codec)
- goto unlock_mutex;
-
if (req_state == POWER_COLLAPSE) {
if (tavil->power_active_ref == 0) {
schedule_delayed_work(&tavil->power_gate_work,
@@ -8210,7 +8198,7 @@ static int tavil_dig_core_power_collapse(struct tavil_priv *tavil,
tavil->wcd9xxx,
WCD9XXX_DIG_CORE_REGION_1);
if (cur_state == WCD_REGION_POWER_DOWN) {
- tavil_dig_core_remove_power_collapse(codec);
+ tavil_dig_core_remove_power_collapse(tavil);
} else {
mutex_unlock(&tavil->power_lock);
cancel_delayed_work_sync(
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 83ae4c14d8ba..e6fa1143af02 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -159,6 +159,21 @@ struct msm_wsa881x_dev_info {
u32 index;
};
+enum pinctrl_pin_state {
+ STATE_DISABLE = 0, /* All pins are in sleep state */
+ STATE_MI2S_ACTIVE, /* IS2 = active, TDM = sleep */
+ STATE_TDM_ACTIVE, /* IS2 = sleep, TDM = active */
+};
+
+struct msm_pinctrl_info {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *mi2s_disable;
+ struct pinctrl_state *tdm_disable;
+ struct pinctrl_state *mi2s_active;
+ struct pinctrl_state *tdm_active;
+ enum pinctrl_pin_state curr_state;
+};
+
struct msm_asoc_mach_data {
u32 mclk_freq;
int us_euro_gpio; /* used by gpio driver API */
@@ -166,6 +181,7 @@ struct msm_asoc_mach_data {
struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
struct snd_info_entry *codec_root;
+ struct msm_pinctrl_info pinctrl_info;
};
struct msm_asoc_wcd93xx_codec {
@@ -174,6 +190,9 @@ struct msm_asoc_wcd93xx_codec {
void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
};
+static const char *const pin_states[] = {"sleep", "i2s-active",
+ "tdm-active"};
+
enum {
TDM_0 = 0,
TDM_1,
@@ -3993,6 +4012,275 @@ done:
return ret;
}
+static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info,
+ enum pinctrl_pin_state new_state)
+{
+ int ret = 0;
+ int curr_state = 0;
+
+ if (pinctrl_info == NULL) {
+ pr_err("%s: pinctrl_info is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ curr_state = pinctrl_info->curr_state;
+ pinctrl_info->curr_state = new_state;
+ pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
+ pin_states[curr_state], pin_states[pinctrl_info->curr_state]);
+
+ if (curr_state == pinctrl_info->curr_state) {
+ pr_debug("%s: Already in same state\n", __func__);
+ goto err;
+ }
+
+ if (curr_state != STATE_DISABLE &&
+ pinctrl_info->curr_state != STATE_DISABLE) {
+ pr_debug("%s: state already active cannot switch\n", __func__);
+ ret = -EIO;
+ goto err;
+ }
+
+ switch (pinctrl_info->curr_state) {
+ case STATE_MI2S_ACTIVE:
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_active);
+ if (ret) {
+ pr_err("%s: MI2S state select failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ case STATE_TDM_ACTIVE:
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->tdm_active);
+ if (ret) {
+ pr_err("%s: TDM state select failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ case STATE_DISABLE:
+ if (curr_state == STATE_MI2S_ACTIVE) {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_disable);
+ } else {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->tdm_disable);
+ }
+ if (ret) {
+ pr_err("%s: state disable failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ default:
+ pr_err("%s: TLMM pin state is invalid\n", __func__);
+ return -EINVAL;
+ }
+
+err:
+ return ret;
+}
+
+static void msm_release_pinctrl(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ if (pinctrl_info->pinctrl) {
+ devm_pinctrl_put(pinctrl_info->pinctrl);
+ pinctrl_info->pinctrl = NULL;
+ }
+}
+
+static int msm_get_pinctrl(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = NULL;
+ struct pinctrl *pinctrl;
+ int ret;
+
+ pinctrl_info = &pdata->pinctrl_info;
+
+ if (pinctrl_info == NULL) {
+ pr_err("%s: pinctrl_info is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR_OR_NULL(pinctrl)) {
+ pr_err("%s: Unable to get pinctrl handle\n", __func__);
+ return -EINVAL;
+ }
+ pinctrl_info->pinctrl = pinctrl;
+
+ /* get all the states handles from Device Tree */
+ pinctrl_info->mi2s_disable = pinctrl_lookup_state(pinctrl,
+ "quat-mi2s-sleep");
+ if (IS_ERR(pinctrl_info->mi2s_disable)) {
+ pr_err("%s: could not get mi2s_disable pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->mi2s_active = pinctrl_lookup_state(pinctrl,
+ "quat-mi2s-active");
+ if (IS_ERR(pinctrl_info->mi2s_active)) {
+ pr_err("%s: could not get mi2s_active pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->tdm_disable = pinctrl_lookup_state(pinctrl,
+ "quat-tdm-sleep");
+ if (IS_ERR(pinctrl_info->tdm_disable)) {
+ pr_err("%s: could not get tdm_disable pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->tdm_active = pinctrl_lookup_state(pinctrl,
+ "quat-tdm-active");
+ if (IS_ERR(pinctrl_info->tdm_active)) {
+ pr_err("%s: could not get tdm_active pinstate\n",
+ __func__);
+ goto err;
+ }
+ /* Reset the TLMM pins to a default state */
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_disable);
+ if (ret != 0) {
+ pr_err("%s: Disable TLMM pins failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ pinctrl_info->curr_state = STATE_DISABLE;
+
+ return 0;
+
+err:
+ devm_pinctrl_put(pinctrl);
+ pinctrl_info->pinctrl = NULL;
+ return -EINVAL;
+}
+
+static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) {
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ } else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) {
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ } else {
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n",
+ __func__, cpu_dai->id, channels->max, rate->max,
+ params_format(params));
+
+ return 0;
+}
+
+static int msm8998_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width, slots;
+ unsigned int slot_mask;
+ unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ /*2 slot config - bits 0 and 1 set for the first two slots */
+ slot_mask = 0x0000FFFF >> (16-slots);
+ slot_width = 32;
+ channels = slots;
+
+ pr_debug("%s: slot_width %d slots %d\n", __func__, slot_width, slots);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: slot_width %d\n", __func__, slot_width);
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ 0, NULL, channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ pr_err("%s: invalid use case, err:%d\n",
+ __func__, ret);
+ }
+
+end:
+ return ret;
+}
+
+static int msm8998_tdm_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static void msm8998_tdm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+
+}
+
+static struct snd_soc_ops msm8998_tdm_be_ops = {
+ .hw_params = msm8998_tdm_snd_hw_params,
+ .startup = msm8998_tdm_snd_startup,
+ .shutdown = msm8998_tdm_snd_shutdown
+};
+
static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
@@ -4000,6 +4288,9 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int index = cpu_dai->id;
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -4013,6 +4304,15 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
__func__, cpu_dai->id);
goto done;
}
+ if (index == QUAT_MI2S) {
+ ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+ if (ret) {
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+ goto done;
+ }
+ }
+
/*
* Muxtex protection in case the same MI2S
* interface using for both TX and RX so
@@ -4065,6 +4365,9 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
int ret;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int index = rtd->cpu_dai->id;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -4083,6 +4386,13 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
}
}
mutex_unlock(&mi2s_intf_conf[index].lock);
+
+ if (index == QUAT_MI2S) {
+ ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+ }
}
static struct snd_soc_ops msm_mi2s_be_ops = {
@@ -5210,8 +5520,8 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = {
.no_pcm = 1,
.dpcm_playback = 1,
.be_id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm_tdm_be_ops,
+ .be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+ .ops = &msm8998_tdm_be_ops,
.ignore_suspend = 1,
},
{
@@ -6883,6 +7193,17 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
ret);
+ /* Parse pinctrl info from devicetree */
+ ret = msm_get_pinctrl(pdev);
+ if (!ret) {
+ pr_debug("%s: pinctrl parsing successful\n", __func__);
+ } else {
+ dev_dbg(&pdev->dev,
+ "%s: Parsing pinctrl failed with %d. Cannot use Ports\n",
+ __func__, ret);
+ ret = 0;
+ }
+
i2s_auxpcm_init(pdev);
is_initial_boot = true;
@@ -6900,6 +7221,7 @@ err:
gpio_free(pdata->us_euro_gpio);
pdata->us_euro_gpio = 0;
}
+ msm_release_pinctrl(pdev);
devm_kfree(&pdev->dev, pdata);
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index 69a9e14c47de..46e2f7109b5a 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, 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
@@ -124,6 +124,45 @@ static const struct soc_enum hdmi_config_enum[] = {
SOC_ENUM_SINGLE_EXT(2, hdmi_format),
};
+static int msm_dai_q6_ext_disp_drift_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(struct afe_param_id_dev_timing_stats);
+
+ return 0;
+}
+
+static int msm_dai_q6_ext_disp_drift_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = -EINVAL;
+ struct afe_param_id_dev_timing_stats timing_stats;
+ struct snd_soc_dai *dai = kcontrol->private_data;
+ struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_err("%s: afe port not started. status_mask = %ld\n",
+ __func__, *dai_data->status_mask);
+ goto done;
+ }
+
+ memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats));
+ ret = afe_get_av_dev_drift(&timing_stats, dai->id);
+ if (ret) {
+ pr_err("%s: Error getting AFE Drift for port %d, err=%d\n",
+ __func__, dai->id, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(ucontrol->value.bytes.data, (void *)&timing_stats,
+ sizeof(struct afe_param_id_dev_timing_stats));
+done:
+ return ret;
+}
+
static const struct snd_kcontrol_new hdmi_config_controls[] = {
SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
msm_dai_q6_ext_disp_format_get,
@@ -132,6 +171,13 @@ static const struct snd_kcontrol_new hdmi_config_controls[] = {
HDMI_RX_CA_MAX, 0, 1,
msm_dai_q6_ext_disp_ca_get,
msm_dai_q6_ext_disp_ca_put),
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "HDMI RX Drift",
+ .info = msm_dai_q6_ext_disp_drift_info,
+ .get = msm_dai_q6_ext_disp_drift_get,
+ },
};
static const struct snd_kcontrol_new display_port_config_controls[] = {
@@ -142,6 +188,13 @@ static const struct snd_kcontrol_new display_port_config_controls[] = {
HDMI_RX_CA_MAX, 0, 1,
msm_dai_q6_ext_disp_ca_get,
msm_dai_q6_ext_disp_ca_put),
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "DISPLAY Port RX Drift",
+ .info = msm_dai_q6_ext_disp_drift_info,
+ .get = msm_dai_q6_ext_disp_drift_get,
+ },
};
/* Current implementation assumes hw_param is called once
@@ -299,6 +352,10 @@ static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
kcontrol = &hdmi_config_controls[1];
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(kcontrol, dai_data));
+
+ kcontrol = &hdmi_config_controls[2];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai));
} else if (dai->driver->id == DISPLAY_PORT_RX) {
kcontrol = &display_port_config_controls[0];
rc = snd_ctl_add(dai->component->card->snd_card,
@@ -307,6 +364,10 @@ static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
kcontrol = &display_port_config_controls[1];
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(kcontrol, dai_data));
+
+ kcontrol = &display_port_config_controls[2];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai));
} else {
dev_err(dai->dev, "%s: Invalid id:%d\n",
__func__, dai->driver->id);
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 7b292eef02f8..19e2fad2920d 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -219,6 +219,7 @@ struct msm_dai_q6_tdm_dai_data {
u32 rate;
u32 channels;
u32 bitwidth;
+ u32 num_group_ports;
struct afe_clk_set clk_set; /* hold LPASS clock config. */
union afe_port_group_config group_cfg; /* hold tdm group config */
struct afe_tdm_port_config port_cfg; /* hold tdm config */
@@ -260,6 +261,7 @@ static const struct soc_enum sb_config_enum[] = {
static const char *const tdm_data_format[] = {
"LPCM",
"Compr",
+ "Gen Compr"
};
static const char *const tdm_header_type[] = {
@@ -269,8 +271,8 @@ static const char *const tdm_header_type[] = {
};
static const struct soc_enum tdm_config_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, tdm_data_format),
- SOC_ENUM_SINGLE_EXT(3, tdm_header_type),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_data_format), tdm_data_format),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_header_type), tdm_header_type),
};
static DEFINE_MUTEX(tdm_mutex);
@@ -298,6 +300,8 @@ static struct afe_param_id_group_device_tdm_cfg tdm_group_cfg = {
0xFF,
};
+static u32 num_tdm_group_ports;
+
static struct afe_clk_set tdm_clk_set = {
AFE_API_VERSION_CLOCK_SET,
Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT,
@@ -2077,6 +2081,42 @@ static int msm_dai_q6_usb_audio_cfg_get(struct snd_kcontrol *kcontrol,
return 0;
}
+static int msm_dai_q6_usb_audio_endian_cfg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+ u32 val = ucontrol->value.integer.value[0];
+
+ if (dai_data) {
+ dai_data->port_config.usb_audio.endian = val;
+ pr_debug("%s: endian = 0x%x\n", __func__,
+ dai_data->port_config.usb_audio.endian);
+ } else {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_usb_audio_endian_cfg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ ucontrol->value.integer.value[0] =
+ dai_data->port_config.usb_audio.endian;
+ pr_debug("%s: endian = 0x%x\n", __func__,
+ dai_data->port_config.usb_audio.endian);
+ } else {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int msm_dai_q6_afe_enc_cfg_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -2327,9 +2367,15 @@ static const struct snd_kcontrol_new usb_audio_cfg_controls[] = {
SOC_SINGLE_EXT("USB_AUDIO_RX dev_token", 0, 0, UINT_MAX, 0,
msm_dai_q6_usb_audio_cfg_get,
msm_dai_q6_usb_audio_cfg_put),
+ SOC_SINGLE_EXT("USB_AUDIO_RX endian", 0, 0, 1, 0,
+ msm_dai_q6_usb_audio_endian_cfg_get,
+ msm_dai_q6_usb_audio_endian_cfg_put),
SOC_SINGLE_EXT("USB_AUDIO_TX dev_token", 0, 0, UINT_MAX, 0,
msm_dai_q6_usb_audio_cfg_get,
msm_dai_q6_usb_audio_cfg_put),
+ SOC_SINGLE_EXT("USB_AUDIO_TX endian", 0, 0, 1, 0,
+ msm_dai_q6_usb_audio_endian_cfg_get,
+ msm_dai_q6_usb_audio_endian_cfg_put),
};
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
@@ -2401,10 +2447,16 @@ static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(&usb_audio_cfg_controls[0],
dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&usb_audio_cfg_controls[1],
+ dai_data));
break;
case AFE_PORT_ID_USB_TX:
rc = snd_ctl_add(dai->component->card->snd_card,
- snd_ctl_new1(&usb_audio_cfg_controls[1],
+ snd_ctl_new1(&usb_audio_cfg_controls[2],
+ dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&usb_audio_cfg_controls[3],
dai_data));
break;
}
@@ -4933,7 +4985,6 @@ static struct platform_driver msm_dai_q6_spdif_driver = {
static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
{
int rc = 0;
- u32 num_ports = 0;
const uint32_t *port_id_array = NULL;
uint32_t array_length = 0;
int i = 0;
@@ -4956,18 +5007,19 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,msm-cpudai-tdm-group-num-ports",
- &num_ports);
+ &num_tdm_group_ports);
if (rc) {
dev_err(&pdev->dev, "%s: Group Num Ports from DT file %s\n",
__func__, "qcom,msm-cpudai-tdm-group-num-ports");
goto rtn;
}
dev_dbg(&pdev->dev, "%s: Group Num Ports from DT file 0x%x\n",
- __func__, num_ports);
+ __func__, num_tdm_group_ports);
- if (num_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
+ if (num_tdm_group_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
dev_err(&pdev->dev, "%s Group Num Ports %d greater than Max %d\n",
- __func__, num_ports, AFE_GROUP_DEVICE_NUM_PORTS);
+ __func__, num_tdm_group_ports,
+ AFE_GROUP_DEVICE_NUM_PORTS);
rc = -EINVAL;
goto rtn;
}
@@ -4981,18 +5033,19 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
rc = -EINVAL;
goto rtn;
}
- if (array_length != sizeof(uint32_t) * num_ports) {
+ if (array_length != sizeof(uint32_t) * num_tdm_group_ports) {
dev_err(&pdev->dev, "%s array_length is %d, expected is %zd\n",
- __func__, array_length, sizeof(uint32_t) * num_ports);
+ __func__, array_length,
+ sizeof(uint32_t) * num_tdm_group_ports);
rc = -EINVAL;
goto rtn;
}
- for (i = 0; i < num_ports; i++)
+ for (i = 0; i < num_tdm_group_ports; i++)
tdm_group_cfg.port_id[i] =
(u16)be32_to_cpu(port_id_array[i]);
/* Unused index should be filled with 0 or AFE_PORT_INVALID */
- for (i = num_ports; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
+ for (i = num_tdm_group_ports; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
tdm_group_cfg.port_id[i] =
AFE_PORT_INVALID;
@@ -5059,7 +5112,20 @@ static int msm_dai_q6_tdm_data_format_put(struct snd_kcontrol *kcontrol,
struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
int value = ucontrol->value.integer.value[0];
- dai_data->port_cfg.tdm.data_format = value;
+ switch (value) {
+ case 0:
+ dai_data->port_cfg.tdm.data_format = AFE_LINEAR_PCM_DATA;
+ break;
+ case 1:
+ dai_data->port_cfg.tdm.data_format = AFE_NON_LINEAR_DATA;
+ break;
+ case 2:
+ dai_data->port_cfg.tdm.data_format = AFE_GENERIC_COMPRESSED;
+ break;
+ default:
+ pr_err("%s: data_format invalid\n", __func__);
+ break;
+ }
pr_debug("%s: data_format = %d\n",
__func__, dai_data->port_cfg.tdm.data_format);
return 0;
@@ -5999,6 +6065,9 @@ static int msm_dai_q6_tdm_set_tdm_slot(struct snd_soc_dai *dai,
/* HW only supports 16 and 8 slots configuration */
switch (slots) {
+ case 2:
+ cap_mask = 0x03;
+ break;
case 8:
cap_mask = 0xFF;
break;
@@ -6417,17 +6486,25 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream,
__func__, dai->id);
goto rtn;
}
- rc = afe_port_group_enable(group_id,
- &dai_data->group_cfg, true);
- if (IS_ERR_VALUE(rc)) {
- dev_err(dai->dev, "%s: fail to enable AFE group 0x%x\n",
+
+ /*
+ * if only one port, don't do group enable as there
+ * is no group need for only one port
+ */
+ if (dai_data->num_group_ports > 1) {
+ rc = afe_port_group_enable(group_id,
+ &dai_data->group_cfg, true);
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev,
+ "%s: fail to enable AFE group 0x%x\n",
__func__, group_id);
- goto rtn;
+ goto rtn;
+ }
}
}
rc = afe_tdm_port_start(dai->id, &dai_data->port_cfg,
- dai_data->rate);
+ dai_data->rate, dai_data->num_group_ports);
if (IS_ERR_VALUE(rc)) {
if (atomic_read(group_ref) == 0) {
afe_port_group_enable(group_id,
@@ -6521,13 +6598,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM0 Playback",
.aif_name = "PRI_TDM_RX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX,
@@ -6539,13 +6618,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM1 Playback",
.aif_name = "PRI_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_1,
@@ -6557,13 +6638,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM2 Playback",
.aif_name = "PRI_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_2,
@@ -6575,13 +6658,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM3 Playback",
.aif_name = "PRI_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_3,
@@ -6593,13 +6678,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM4 Playback",
.aif_name = "PRI_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_4,
@@ -6611,13 +6698,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM5 Playback",
.aif_name = "PRI_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_5,
@@ -6629,13 +6718,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM6 Playback",
.aif_name = "PRI_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_6,
@@ -6647,13 +6738,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM7 Playback",
.aif_name = "PRI_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_7,
@@ -6665,13 +6758,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM0 Capture",
.aif_name = "PRI_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX,
@@ -6683,13 +6778,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM1 Capture",
.aif_name = "PRI_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_1,
@@ -6701,13 +6798,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM2 Capture",
.aif_name = "PRI_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_2,
@@ -6719,13 +6818,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM3 Capture",
.aif_name = "PRI_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_3,
@@ -6737,13 +6838,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM4 Capture",
.aif_name = "PRI_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_4,
@@ -6755,13 +6858,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM5 Capture",
.aif_name = "PRI_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_5,
@@ -6773,13 +6878,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM6 Capture",
.aif_name = "PRI_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_6,
@@ -6791,13 +6898,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Primary TDM7 Capture",
.aif_name = "PRI_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_7,
@@ -6809,13 +6918,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM0 Playback",
.aif_name = "SEC_TDM_RX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX,
@@ -6827,13 +6938,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM1 Playback",
.aif_name = "SEC_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_1,
@@ -6845,13 +6958,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM2 Playback",
.aif_name = "SEC_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_2,
@@ -6863,13 +6978,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM3 Playback",
.aif_name = "SEC_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_3,
@@ -6881,13 +6998,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM4 Playback",
.aif_name = "SEC_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_4,
@@ -6899,13 +7018,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM5 Playback",
.aif_name = "SEC_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_5,
@@ -6917,13 +7038,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM6 Playback",
.aif_name = "SEC_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_6,
@@ -6935,13 +7058,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM7 Playback",
.aif_name = "SEC_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_7,
@@ -6953,13 +7078,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM0 Capture",
.aif_name = "SEC_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX,
@@ -6971,13 +7098,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM1 Capture",
.aif_name = "SEC_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_1,
@@ -6989,13 +7118,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM2 Capture",
.aif_name = "SEC_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_2,
@@ -7007,13 +7138,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM3 Capture",
.aif_name = "SEC_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_3,
@@ -7025,13 +7158,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM4 Capture",
.aif_name = "SEC_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_4,
@@ -7043,13 +7178,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM5 Capture",
.aif_name = "SEC_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_5,
@@ -7061,13 +7198,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM6 Capture",
.aif_name = "SEC_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_6,
@@ -7079,13 +7218,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Secondary TDM7 Capture",
.aif_name = "SEC_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_7,
@@ -7097,13 +7238,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM0 Playback",
.aif_name = "TERT_TDM_RX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX,
@@ -7115,13 +7258,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM1 Playback",
.aif_name = "TERT_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_1,
@@ -7133,13 +7278,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM2 Playback",
.aif_name = "TERT_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_2,
@@ -7151,13 +7298,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM3 Playback",
.aif_name = "TERT_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_3,
@@ -7169,13 +7318,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM4 Playback",
.aif_name = "TERT_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_4,
@@ -7187,13 +7338,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM5 Playback",
.aif_name = "TERT_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_5,
@@ -7205,13 +7358,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM6 Playback",
.aif_name = "TERT_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_6,
@@ -7223,13 +7378,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM7 Playback",
.aif_name = "TERT_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_7,
@@ -7241,13 +7398,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM0 Capture",
.aif_name = "TERT_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX,
@@ -7259,13 +7418,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM1 Capture",
.aif_name = "TERT_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_1,
@@ -7277,13 +7438,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM2 Capture",
.aif_name = "TERT_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_2,
@@ -7295,13 +7458,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM3 Capture",
.aif_name = "TERT_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_3,
@@ -7313,13 +7478,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM4 Capture",
.aif_name = "TERT_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_4,
@@ -7331,13 +7498,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM5 Capture",
.aif_name = "TERT_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_5,
@@ -7349,13 +7518,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM6 Capture",
.aif_name = "TERT_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_6,
@@ -7367,13 +7538,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Tertiary TDM7 Capture",
.aif_name = "TERT_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_7,
@@ -7385,13 +7558,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM0 Playback",
.aif_name = "QUAT_TDM_RX_0",
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
- SNDRV_PCM_RATE_16000,
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX,
@@ -7403,13 +7578,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM1 Playback",
.aif_name = "QUAT_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_1,
@@ -7421,13 +7598,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM2 Playback",
.aif_name = "QUAT_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_2,
@@ -7439,13 +7618,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM3 Playback",
.aif_name = "QUAT_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_3,
@@ -7457,13 +7638,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM4 Playback",
.aif_name = "QUAT_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_4,
@@ -7475,13 +7658,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM5 Playback",
.aif_name = "QUAT_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_5,
@@ -7493,13 +7678,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM6 Playback",
.aif_name = "QUAT_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_6,
@@ -7511,13 +7698,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM7 Playback",
.aif_name = "QUAT_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_7,
@@ -7529,13 +7718,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM0 Capture",
.aif_name = "QUAT_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX,
@@ -7547,13 +7738,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM1 Capture",
.aif_name = "QUAT_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_1,
@@ -7565,13 +7758,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM2 Capture",
.aif_name = "QUAT_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_2,
@@ -7583,13 +7778,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM3 Capture",
.aif_name = "QUAT_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_3,
@@ -7601,13 +7798,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM4 Capture",
.aif_name = "QUAT_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_4,
@@ -7619,13 +7818,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM5 Capture",
.aif_name = "QUAT_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_5,
@@ -7637,13 +7838,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM6 Capture",
.aif_name = "QUAT_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_6,
@@ -7655,13 +7858,15 @@ static struct snd_soc_dai_driver msm_dai_q6_tdm_dai[] = {
.stream_name = "Quaternary TDM7 Capture",
.aif_name = "QUAT_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_7,
@@ -7854,6 +8059,9 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev)
dai_data->clk_set = tdm_clk_set;
/* copy static group cfg per parent node */
dai_data->group_cfg.tdm_cfg = tdm_group_cfg;
+ /* copy static num group ports per parent node */
+ dai_data->num_group_ports = num_tdm_group_ports;
+
dev_set_drvdata(&pdev->dev, dai_data);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
index 1fdb878a1a1f..33c5b6486cca 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -139,6 +139,17 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.mask = 0,
};
+static unsigned long msm_pcm_fe_topology[MSM_FRONTEND_DAI_MAX];
+
+/* default value is DTS (i.e read from device tree) */
+static char const *msm_pcm_fe_topology_text[] = {
+ "DTS", "ULL", "ULL_PP", "LL" };
+
+static const struct soc_enum msm_pcm_fe_topology_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_pcm_fe_topology_text),
+ msm_pcm_fe_topology_text),
+};
+
static void event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -258,6 +269,8 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
uint16_t bits_per_sample;
int ret;
int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT;
+ unsigned long topology;
+ int perf_mode;
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
@@ -268,11 +281,24 @@ static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ topology = msm_pcm_fe_topology[soc_prtd->dai_link->be_id];
+
+ if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL_PP"))
+ perf_mode = ULL_POST_PROCESSING_PCM_MODE;
+ else if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL"))
+ perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ else if (!strcmp(msm_pcm_fe_topology_text[topology], "LL"))
+ perf_mode = LOW_LATENCY_PCM_MODE;
+ else
+ /* use the default from the device tree */
+ perf_mode = pdata->perf_mode;
+
+
/* need to set LOW_LATENCY_PCM_MODE for capture since
* push mode does not support ULL
*/
prtd->audio_client->perf_mode = (dir == IN) ?
- pdata->perf_mode :
+ perf_mode :
LOW_LATENCY_PCM_MODE;
/* rate and channels are sent to audio driver */
@@ -721,6 +747,93 @@ static int msm_pcm_add_chmap_control(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int msm_pcm_fe_topology_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ const struct soc_enum *e = &msm_pcm_fe_topology_enum[0];
+
+ return snd_ctl_enum_info(uinfo, 1, e->items, e->texts);
+}
+
+static int msm_pcm_fe_topology_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned long fe_id = kcontrol->private_value;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: %lu topology %s\n", __func__, fe_id,
+ msm_pcm_fe_topology_text[msm_pcm_fe_topology[fe_id]]);
+ ucontrol->value.enumerated.item[0] = msm_pcm_fe_topology[fe_id];
+ return 0;
+}
+
+static int msm_pcm_fe_topology_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned long fe_id = kcontrol->private_value;
+ unsigned int item;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+ return -EINVAL;
+ }
+
+ item = ucontrol->value.enumerated.item[0];
+ if (item >= ARRAY_SIZE(msm_pcm_fe_topology_text)) {
+ pr_err("%s Received out of bound topology %lu\n", __func__,
+ fe_id);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: %lu new topology %s\n", __func__, fe_id,
+ msm_pcm_fe_topology_text[item]);
+ msm_pcm_fe_topology[fe_id] = item;
+ return 0;
+}
+
+static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "PCM_Dev";
+ const char *deviceNo = "NN";
+ const char *topo_text = "Topology";
+ char *mixer_str = NULL;
+ int ctl_len;
+ int ret;
+ struct snd_kcontrol_new topology_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "?",
+ .info = msm_pcm_fe_topology_info,
+ .get = msm_pcm_fe_topology_get,
+ .put = msm_pcm_fe_topology_put,
+ .private_value = 0,
+ },
+ };
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
+ strlen(topo_text) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+ if (!mixer_str)
+ return -ENOMEM;
+
+ snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
+ rtd->pcm->device, topo_text);
+
+ topology_control[0].name = mixer_str;
+ topology_control[0].private_value = rtd->dai_link->be_id;
+ ret = snd_soc_add_platform_controls(rtd->platform, topology_control,
+ ARRAY_SIZE(topology_control));
+ msm_pcm_fe_topology[rtd->dai_link->be_id] = 0;
+ kfree(mixer_str);
+ return ret;
+}
+
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
@@ -741,6 +854,12 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: Could not add pcm Volume Control %d\n",
__func__, ret);
}
+
+ ret = msm_pcm_add_fe_topology_control(rtd);
+ if (ret) {
+ pr_err("%s: Could not add pcm topology control %d\n",
+ __func__, ret);
+ }
pcm->nonatomic = true;
exit:
return ret;
@@ -778,8 +897,12 @@ static int msm_pcm_probe(struct platform_device *pdev)
rc = of_property_read_string(pdev->dev.of_node,
"qcom,latency-level", &latency_level);
- if (!rc && !strcmp(latency_level, "ultra"))
- perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ if (!rc) {
+ if (!strcmp(latency_level, "ultra"))
+ perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ else if (!strcmp(latency_level, "ull-pp"))
+ perf_mode = ULL_POST_PROCESSING_PCM_MODE;
+ }
}
pdata = devm_kzalloc(&pdev->dev,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index e2f662f26cff..e14f410bd310 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -110,7 +110,7 @@ static struct snd_pcm_hardware msm_pcm_hardware_playback = {
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
- 88200, 96000, 176400, 192000, 384000
+ 88200, 96000, 176400, 192000, 352800, 384000
};
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -285,6 +285,7 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
struct msm_plat_data *pdata;
struct snd_pcm_hw_params *params;
int ret;
+ uint32_t fmt_type = FORMAT_LINEAR_PCM;
uint16_t bits_per_sample;
uint16_t sample_word_size;
@@ -333,38 +334,67 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
sample_word_size = 16;
break;
}
+ if (prtd->compress_enable) {
+ fmt_type = FORMAT_GEN_COMPR;
+ pr_debug("%s: Compressed enabled!\n", __func__);
+ ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
+ COMPRESSED_PASSTHROUGH_GEN);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
+ __func__, ret);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
+ } else {
+ ret = q6asm_open_write_v4(prtd->audio_client,
+ fmt_type, bits_per_sample);
- ret = q6asm_open_write_v4(prtd->audio_client,
- FORMAT_LINEAR_PCM, bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_write_v4 failed (%d)\n",
+ __func__, ret);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
- if (ret < 0) {
- pr_err("%s: q6asm_open_write_v2 failed\n", __func__);
- q6asm_audio_client_free(prtd->audio_client);
- prtd->audio_client = NULL;
- return -ENOMEM;
+ ret = q6asm_send_cal(prtd->audio_client);
+ if (ret < 0)
+ pr_debug("%s : Send cal failed : %d", __func__, ret);
}
-
- ret = q6asm_send_cal(prtd->audio_client);
- if (ret < 0)
- pr_debug("%s : Send cal failed : %d", __func__, ret);
-
pr_debug("%s: session ID %d\n", __func__,
prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+
+ if (prtd->compress_enable) {
+ ret = msm_pcm_routing_reg_phy_compr_stream(
+ soc_prtd->dai_link->be_id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id,
+ SNDRV_PCM_STREAM_PLAYBACK,
+ COMPRESSED_PASSTHROUGH_GEN);
+ } else {
+ ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
+ }
if (ret) {
pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
return ret;
}
-
- ret = q6asm_media_format_block_multi_ch_pcm_v4(
+ if (prtd->compress_enable) {
+ ret = q6asm_media_format_block_gen_compr(
+ prtd->audio_client, runtime->rate,
+ runtime->channels, !prtd->set_channel_map,
+ prtd->channel_map, bits_per_sample);
+ } else {
+ ret = q6asm_media_format_block_multi_ch_pcm_v4(
prtd->audio_client, runtime->rate,
runtime->channels, !prtd->set_channel_map,
prtd->channel_map, bits_per_sample,
sample_word_size, ASM_LITTLE_ENDIAN,
DEFAULT_QF);
+ }
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -1091,6 +1121,136 @@ static int msm_pcm_add_volume_control(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x2000;
+ return 0;
+}
+
+static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+ struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ if (!pdata) {
+ pr_err("%s pdata is NULL\n", __func__);
+ return -ENODEV;
+ }
+ substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -EINVAL;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->compress_enable;
+ return 0;
+}
+
+static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+ struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+ int compress = ucontrol->value.integer.value[0];
+
+ if (!pdata) {
+ pr_err("%s pdata is NULL\n", __func__);
+ return -ENODEV;
+ }
+ substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ pr_debug("%s: compress : 0x%x\n", __func__, compress);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -EINVAL;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ pr_debug("%s: setting compress flag to 0x%x\n",
+ __func__, compress);
+ prtd->compress_enable = compress;
+ }
+ return rc;
+}
+
+static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "Playback ";
+ const char *mixer_ctl_end_name = " Compress";
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len;
+ int ret = 0;
+ struct msm_plat_data *pdata;
+ struct snd_kcontrol_new pcm_compress_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_pcm_compress_ctl_info,
+ .get = msm_pcm_compress_ctl_get,
+ .put = msm_pcm_compress_ctl_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s: NULL rtd\n", __func__);
+ return -EINVAL;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
+ strlen(mixer_ctl_end_name) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+ if (!mixer_str)
+ return -ENOMEM;
+
+ snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
+ rtd->pcm->device, mixer_ctl_end_name);
+
+ pcm_compress_control[0].name = mixer_str;
+ pcm_compress_control[0].private_value = rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ pdata = dev_get_drvdata(rtd->platform->dev);
+ if (pdata) {
+ if (!pdata->pcm) {
+ pdata->pcm = rtd->pcm;
+ snd_soc_add_platform_controls(rtd->platform,
+ pcm_compress_control,
+ ARRAY_SIZE
+ (pcm_compress_control));
+ pr_debug("%s: add control success plt = %pK\n",
+ __func__, rtd->platform);
+ }
+ } else {
+ pr_err("%s: NULL pdata\n", __func__);
+ ret = -EINVAL;
+ }
+ kfree(mixer_str);
+ return ret;
+}
+
static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1381,6 +1541,11 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: Could not add pcm Volume Control %d\n",
__func__, ret);
+ ret = msm_pcm_add_compress_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm Compress Control %d\n",
+ __func__, ret);
+
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 8fe31394eef0..f5ff63f34b82 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 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
@@ -109,6 +109,7 @@ struct msm_audio {
int cmd_interrupt;
bool meta_data_mode;
uint32_t volume;
+ bool compress_enable;
/* array of frame info */
struct msm_audio_in_frame_info in_frame_info[CAPTURE_MAX_NUM_PERIODS];
};
@@ -123,6 +124,7 @@ struct output_meta_data_st {
struct msm_plat_data {
int perf_mode;
+ struct snd_pcm *pcm;
};
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 312eda29e8a0..cfade420c509 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -101,12 +101,15 @@ enum {
#define TERT_MI2S_TX_TEXT "TERT_MI2S_TX"
#define QUAT_MI2S_TX_TEXT "QUAT_MI2S_TX"
#define ADM_LSM_TX_TEXT "ADM_LSM_TX"
+#define INT3_MI2S_TX_TEXT "INT3_MI2S_TX"
+
#define LSM_FUNCTION_TEXT "LSM Function"
static const char * const lsm_port_text[] = {
"None",
SLIMBUS_0_TX_TEXT, SLIMBUS_1_TX_TEXT, SLIMBUS_2_TX_TEXT,
SLIMBUS_3_TX_TEXT, SLIMBUS_4_TX_TEXT, SLIMBUS_5_TX_TEXT,
- TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT
+ TERT_MI2S_TX_TEXT, QUAT_MI2S_TX_TEXT, ADM_LSM_TX_TEXT,
+ INT3_MI2S_TX_TEXT, SLIMBUS_TX_VI_TEXT
};
struct msm_pcm_route_bdai_pp_params {
@@ -1140,8 +1143,10 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
topology = msm_routing_get_adm_topology(fe_id,
session_type,
i);
- if (passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
- topology = COMPRESS_PASSTHROUGH_NONE_TOPOLOGY;
+ if ((passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
+ || (passthr_mode ==
+ COMPRESSED_PASSTHROUGH_GEN))
+ topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
pr_debug("%s: Before adm open topology %d\n", __func__,
topology);
@@ -1191,7 +1196,9 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
num_copps++;
}
}
- if (passthr_mode != COMPRESSED_PASSTHROUGH_DSD) {
+ if (passthr_mode != COMPRESSED_PASSTHROUGH_DSD
+ && passthr_mode !=
+ COMPRESSED_PASSTHROUGH_GEN) {
msm_routing_send_device_pp_params(
msm_bedais[i].port_id,
copp_idx);
@@ -2309,6 +2316,9 @@ static int msm_routing_lsm_port_put(struct snd_kcontrol *kcontrol,
case 9:
lsm_port = ADM_LSM_PORT_ID;
break;
+ case 10:
+ lsm_port = AFE_PORT_ID_INT3_MI2S_TX;
+ break;
default:
pr_err("Default lsm port");
break;
@@ -2337,17 +2347,21 @@ static int msm_routing_lsm_func_get(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- /*Check for Tertiary TX port*/
- if (!strcmp(kcontrol->id.name, lsm_port_text[7])) {
- ucontrol->value.integer.value[0] = MADSWAUDIO;
- return 0;
- }
-
port_id = i * 2 + 1 + SLIMBUS_0_RX;
- if (!strcmp(kcontrol->id.name, lsm_port_text[8]))
+ /*Check for Tertiary/Quaternary/INT3 TX port*/
+ if (strnstr(kcontrol->id.name, lsm_port_text[7],
+ strlen(lsm_port_text[7])))
+ port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+
+ if (strnstr(kcontrol->id.name, lsm_port_text[8],
+ strlen(lsm_port_text[8])))
port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ if (strnstr(kcontrol->id.name, lsm_port_text[10],
+ strlen(lsm_port_text[10])))
+ port_id = AFE_PORT_ID_INT3_MI2S_TX;
+
mad_type = afe_port_get_mad_type(port_id);
pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
mad_type);
@@ -2414,17 +2428,19 @@ static int msm_routing_lsm_func_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- /*Check for Tertiary TX port*/
+ /*Check for Tertiary/Quaternary/INT3 TX port*/
if (strnstr(kcontrol->id.name, lsm_port_text[7],
- strlen(lsm_port_text[7]))) {
+ strlen(lsm_port_text[7])))
port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
- mad_type = MAD_SW_AUDIO;
- }
if (strnstr(kcontrol->id.name, lsm_port_text[8],
strlen(lsm_port_text[8])))
port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+ if (strnstr(kcontrol->id.name, lsm_port_text[10],
+ strlen(lsm_port_text[10])))
+ port_id = AFE_PORT_ID_INT3_MI2S_TX;
+
pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
mad_type);
return afe_port_set_mad_type(port_id, mad_type);
@@ -9227,6 +9243,9 @@ static const struct snd_kcontrol_new lsm1_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm2_mixer_controls[] = {
@@ -9251,6 +9270,9 @@ static const struct snd_kcontrol_new lsm2_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm3_mixer_controls[] = {
@@ -9275,6 +9297,9 @@ static const struct snd_kcontrol_new lsm3_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm4_mixer_controls[] = {
@@ -9299,6 +9324,9 @@ static const struct snd_kcontrol_new lsm4_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm5_mixer_controls[] = {
@@ -9323,6 +9351,9 @@ static const struct snd_kcontrol_new lsm5_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm6_mixer_controls[] = {
@@ -9347,6 +9378,9 @@ static const struct snd_kcontrol_new lsm6_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm7_mixer_controls[] = {
@@ -9371,6 +9405,9 @@ static const struct snd_kcontrol_new lsm7_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new lsm8_mixer_controls[] = {
@@ -9395,6 +9432,9 @@ static const struct snd_kcontrol_new lsm8_mixer_controls[] = {
SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
msm_routing_put_listen_mixer),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX,
+ MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer,
+ msm_routing_put_listen_mixer),
};
static const struct snd_kcontrol_new slim_fm_switch_mixer_controls =
@@ -9509,6 +9549,8 @@ static const struct snd_kcontrol_new lsm_controls[] = {
msm_routing_lsm_func_get, msm_routing_lsm_func_put),
SOC_ENUM_EXT(QUAT_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
msm_routing_lsm_func_get, msm_routing_lsm_func_put),
+ SOC_ENUM_EXT(INT3_MI2S_TX_TEXT" "LSM_FUNCTION_TEXT, lsm_func_enum,
+ msm_routing_lsm_func_get, msm_routing_lsm_func_put),
/* kcontrol of lsm_port */
SOC_ENUM_EXT("LSM1 Port", lsm_port_enum,
msm_routing_lsm_port_get,
@@ -12137,6 +12179,42 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
+
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
+
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -13046,7 +13124,6 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SLIM4_UL_HL", NULL, "SLIMBUS_4_TX"},
{"SLIM8_UL_HL", NULL, "SLIMBUS_8_TX"},
-
{"LSM1 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
{"LSM1 Mixer", "SLIMBUS_1_TX", "SLIMBUS_1_TX"},
{"LSM1 Mixer", "SLIMBUS_3_TX", "SLIMBUS_3_TX"},
@@ -13054,6 +13131,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"LSM1 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
{"LSM1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"LSM1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM1 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"LSM1_UL_HL", NULL, "LSM1 Mixer"},
{"LSM2 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
@@ -13063,6 +13141,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"LSM2 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
{"LSM2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"LSM2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM2 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"LSM2_UL_HL", NULL, "LSM2 Mixer"},
@@ -13073,6 +13152,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"LSM3 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
{"LSM3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"LSM3 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM3 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"LSM3_UL_HL", NULL, "LSM3 Mixer"},
@@ -13083,6 +13163,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"LSM4 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
{"LSM4 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"LSM4 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM4 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"LSM4_UL_HL", NULL, "LSM4 Mixer"},
{"LSM5 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
@@ -13092,6 +13173,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"LSM5 Mixer", "SLIMBUS_5_TX", "SLIMBUS_5_TX"},
{"LSM5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"},
{"LSM5 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+ {"LSM5 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"LSM5_UL_HL", NULL, "LSM5 Mixer"},
{"LSM6 Mixer", "SLIMBUS_0_TX", "SLIMBUS_0_TX"},
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 68c71c6f7469..bc1d21a826b5 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -113,6 +113,7 @@ struct afe_ctl {
struct audio_cal_info_sp_ex_vi_ftm_cfg ex_ftm_cfg;
struct afe_sp_th_vi_get_param_resp th_vi_resp;
struct afe_sp_ex_vi_get_param_resp ex_vi_resp;
+ struct afe_av_dev_drift_get_param_resp av_dev_drift_resp;
int vi_tx_port;
int vi_rx_port;
uint32_t afe_sample_rates[AFE_MAX_PORTS];
@@ -189,6 +190,38 @@ static void afe_callback_debug_print(struct apr_client_data *data)
__func__, data->opcode, data->payload_size);
}
+static void av_dev_drift_afe_cb_handler(uint32_t *payload,
+ uint32_t payload_size)
+{
+ u32 param_id;
+ struct afe_av_dev_drift_get_param_resp *resp =
+ (struct afe_av_dev_drift_get_param_resp *) payload;
+
+ if (!(&(resp->pdata))) {
+ pr_err("%s: Error: resp pdata is NULL\n", __func__);
+ return;
+ }
+
+ param_id = resp->pdata.param_id;
+ if (param_id == AFE_PARAM_ID_DEV_TIMING_STATS) {
+ if (payload_size < sizeof(this_afe.av_dev_drift_resp)) {
+ pr_err("%s: Error: received size %d, resp size %zu\n",
+ __func__, payload_size,
+ sizeof(this_afe.av_dev_drift_resp));
+ return;
+ }
+ memcpy(&this_afe.av_dev_drift_resp, payload,
+ sizeof(this_afe.av_dev_drift_resp));
+ if (!this_afe.av_dev_drift_resp.status) {
+ atomic_set(&this_afe.state, 0);
+ } else {
+ pr_debug("%s: av_dev_drift_resp status: %d", __func__,
+ this_afe.av_dev_drift_resp.status);
+ atomic_set(&this_afe.state, -1);
+ }
+ }
+}
+
static int32_t sp_make_afe_callback(uint32_t *payload, uint32_t payload_size)
{
u32 param_id;
@@ -309,10 +342,7 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
}
afe_callback_debug_print(data);
if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) {
- u8 *payload = data->payload;
-
- if (rtac_make_afe_callback(data->payload, data->payload_size))
- return 0;
+ uint32_t *payload = data->payload;
if (!payload || (data->token >= AFE_MAX_PORTS)) {
pr_err("%s: Error: size %d payload %pK token %d\n",
@@ -320,9 +350,19 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
payload, data->token);
return -EINVAL;
}
- if (sp_make_afe_callback(data->payload, data->payload_size))
- return -EINVAL;
+ if (payload[2] == AFE_PARAM_ID_DEV_TIMING_STATS) {
+ av_dev_drift_afe_cb_handler(data->payload,
+ data->payload_size);
+ } else {
+ if (rtac_make_afe_callback(data->payload,
+ data->payload_size))
+ return 0;
+
+ if (sp_make_afe_callback(data->payload,
+ data->payload_size))
+ return -EINVAL;
+ }
wake_up(&this_afe.wait[data->token]);
} else if (data->payload_size) {
uint32_t *payload;
@@ -1181,6 +1221,7 @@ static int afe_send_hw_delay(u16 port_id, u32 rate)
pr_debug("%s:\n", __func__);
+ memset(&delay_entry, 0, sizeof(delay_entry));
delay_entry.sample_rate = rate;
if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
ret = afe_get_cal_hw_delay(TX_DEVICE, &delay_entry);
@@ -1983,7 +2024,8 @@ int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type)
{
int i;
- if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX) {
+ if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
+ port_id == AFE_PORT_ID_INT3_MI2S_TX) {
mad_type = MAD_SW_AUDIO;
return 0;
}
@@ -2001,7 +2043,8 @@ enum afe_mad_type afe_port_get_mad_type(u16 port_id)
{
int i;
- if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX)
+ if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
+ port_id == AFE_PORT_ID_INT3_MI2S_TX)
return MAD_SW_AUDIO;
i = port_id - SLIMBUS_0_RX;
@@ -2539,7 +2582,7 @@ fail_cmd:
}
int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
- u32 rate)
+ u32 rate, u16 num_groups)
{
struct afe_audioif_config_command config;
int ret = 0;
@@ -2579,9 +2622,10 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
}
- /* Also send the topology id here: */
+ /* Also send the topology id here if multiple ports: */
port_index = afe_get_port_index(port_id);
- if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE)) {
+ if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE) &&
+ num_groups > 1) {
/* One time call: only for first time */
afe_send_custom_topology();
afe_send_port_topology_id(port_id);
@@ -2643,11 +2687,14 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
ret = -EINVAL;
goto fail_cmd;
}
-
- ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping, port_id);
- if (ret < 0) {
- pr_err("%s: afe send failed %d\n", __func__, ret);
- goto fail_cmd;
+ /* slot mapping is not need if there is only one group */
+ if (num_groups > 1) {
+ ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping,
+ port_id);
+ if (ret < 0) {
+ pr_err("%s: afe send failed %d\n", __func__, ret);
+ goto fail_cmd;
+ }
}
if (tdm_port->custom_tdm_header.header_type) {
@@ -2723,6 +2770,21 @@ int afe_port_send_usb_dev_param(u16 port_id, union afe_port_config *afe_config)
ret = -EINVAL;
goto exit;
}
+
+ config.pdata.param_id = AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT;
+ config.pdata.param_size = sizeof(config.lpcm_fmt);
+ config.lpcm_fmt.cfg_minor_version =
+ AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG;
+ config.lpcm_fmt.endian = afe_config->usb_audio.endian;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE device param cmd LPCM_FMT failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
exit:
return ret;
}
@@ -2746,6 +2808,11 @@ static int q6afe_send_enc_config(u16 port_id,
}
memset(&config, 0, sizeof(config));
index = q6audio_get_port_index(port_id);
+ if (index < 0) {
+ pr_err("%s: Invalid index number: %d\n", __func__, index);
+ return -EINVAL;
+ }
+
config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
config.hdr.pkt_size = sizeof(config);
@@ -6146,6 +6213,88 @@ done:
return ret;
}
+int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
+ u16 port)
+{
+ int ret = -EINVAL;
+ int index = 0;
+ struct afe_av_dev_drift_get_param av_dev_drift;
+
+ if (!timing_stats) {
+ pr_err("%s: Invalid params\n", __func__);
+ goto exit;
+ }
+
+ ret = q6audio_validate_port(port);
+ if (ret < 0) {
+ pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ index = q6audio_get_port_index(port);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: Invalid AFE port index[%d]\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ memset(&av_dev_drift, 0, sizeof(struct afe_av_dev_drift_get_param));
+
+ av_dev_drift.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ av_dev_drift.hdr.pkt_size = sizeof(av_dev_drift);
+ av_dev_drift.hdr.src_port = 0;
+ av_dev_drift.hdr.dest_port = 0;
+ av_dev_drift.hdr.token = index;
+ av_dev_drift.hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
+ av_dev_drift.get_param.mem_map_handle = 0;
+ av_dev_drift.get_param.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ av_dev_drift.get_param.param_id = AFE_PARAM_ID_DEV_TIMING_STATS;
+ av_dev_drift.get_param.payload_address_lsw = 0;
+ av_dev_drift.get_param.payload_address_msw = 0;
+ av_dev_drift.get_param.payload_size = sizeof(av_dev_drift)
+ - sizeof(av_dev_drift.get_param) - sizeof(av_dev_drift.hdr);
+ av_dev_drift.get_param.port_id = q6audio_get_port_id(port);
+ av_dev_drift.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ av_dev_drift.pdata.param_id = AFE_PARAM_ID_DEV_TIMING_STATS;
+ av_dev_drift.pdata.param_size = sizeof(av_dev_drift.timing_stats);
+ atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *)&av_dev_drift);
+ if (ret < 0) {
+ pr_err("%s: get param port 0x%x param id[0x%x] failed %d\n",
+ __func__, port, av_dev_drift.get_param.param_id, ret);
+ goto exit;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto exit;
+ }
+
+ memcpy(timing_stats, &this_afe.av_dev_drift_resp.timing_stats,
+ sizeof(this_afe.av_dev_drift_resp.timing_stats));
+ ret = 0;
+exit:
+ return ret;
+}
+
int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
{
int ret = -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 74fbe984e6e9..d55c28fab652 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -2490,6 +2490,10 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
case FORMAT_DSD:
open.fmt_id = ASM_MEDIA_FMT_DSD;
break;
+ case FORMAT_GEN_COMPR:
+ open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
+ break;
+
default:
pr_err("%s: Invalid format[%d]\n", __func__, format);
rc = -EINVAL;
@@ -2498,7 +2502,8 @@ int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format,
/*Below flag indicates the DSP that Compressed audio input
stream is not IEC 61937 or IEC 60958 packetizied*/
if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
- passthrough_flag == COMPRESSED_PASSTHROUGH_DSD) {
+ passthrough_flag == COMPRESSED_PASSTHROUGH_DSD ||
+ passthrough_flag == COMPRESSED_PASSTHROUGH_GEN) {
open.flags = 0x0;
pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
} else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
@@ -2665,6 +2670,9 @@ static int __q6asm_open_write(struct audio_client *ac, uint32_t format,
case FORMAT_APTX:
open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
break;
+ case FORMAT_GEN_COMPR:
+ open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
+ break;
default:
pr_err("%s: Invalid format 0x%x\n", __func__, format);
rc = -EINVAL;
@@ -5191,6 +5199,82 @@ int q6asm_media_format_block_multi_ch_pcm_v4(struct audio_client *ac,
}
EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
+/*
+ * q6asm_media_format_block_gen_compr - set up generic compress format params
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @bits_per_sample: bit width of gen compress stream
+ */
+int q6asm_media_format_block_gen_compr(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample)
+{
+ struct asm_generic_compressed_fmt_blk_t fmt;
+ u8 *channel_mapping;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
+ __func__, ac->session, rate,
+ channels, bits_per_sample);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.num_channels = channels;
+ fmt.bits_per_sample = bits_per_sample;
+ fmt.sampling_rate = rate;
+
+ channel_mapping = fmt.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ atomic_set(&ac->cmd_state, -1);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
+
static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg, int stream_id)
{