summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/clk-qpnp-div.txt52
-rw-r--r--Documentation/devicetree/bindings/cnss/icnss.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/leds/leds-qpnp.txt14
-rw-r--r--Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt2
-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/power/supply/qcom/smb138x-charger.txt12
-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/regulator/mem-acc-regulator.txt2
-rw-r--r--Documentation/devicetree/bindings/regulator/msm_gfx_ldo.txt5
-rw-r--r--Documentation/devicetree/bindings/regulator/qpnp-regulator.txt2
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,cx_ipeak.txt22
-rw-r--r--Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt9
-rw-r--r--Documentation/scheduler/sched-hmp.txt2
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/Kconfig.debug12
-rw-r--r--arch/arm/boot/dts/qcom/Makefile4
-rw-r--r--arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts6
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi260
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi262
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi256
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi254
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi15
-rw-r--r--arch/arm/boot/dts/qcom/msm-audio.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8998.dtsi83
-rw-r--r--arch/arm/boot/dts/qcom/msm-smb138x.dtsi28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-audio.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-cdp.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mtp.dtsi17
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi13
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd.dtsi17
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/sda630-cdp.dts11
-rw-r--r--arch/arm/boot/dts/qcom/sda630-mtp.dts5
-rw-r--r--arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts11
-rw-r--r--arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts5
-rw-r--r--arch/arm/boot/dts/qcom/sda630-pm660a-rcm.dts11
-rw-r--r--arch/arm/boot/dts/qcom/sda630-rcm.dts10
-rw-r--r--arch/arm/boot/dts/qcom/sda660-cdp.dts13
-rw-r--r--arch/arm/boot/dts/qcom/sda660-mtp.dts7
-rw-r--r--arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts13
-rw-r--r--arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts7
-rw-r--r--arch/arm/boot/dts/qcom/sda660-pm660a-rcm.dts13
-rw-r--r--arch/arm/boot/dts/qcom/sda660-rcm.dts13
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-cdp.dts11
-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-internal-codec-cdp.dts1
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts5
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts1
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts5
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-rcm.dts1
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-internal-codec-rcm.dts1
-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.dts5
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mtp.dtsi35
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts11
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts5
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-pm660a-rcm.dts11
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-qrd.dtsi80
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-rcm.dts11
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-regulator.dtsi350
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi317
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-camera.dtsi36
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-cdp.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-common.dtsi47
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-coresight.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-rcm.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi44
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi37
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss.dtsi76
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mtp.dtsi35
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi63
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts10
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts38
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-rcm.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pm660a-rcm.dts10
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-regulator.dtsi57
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi116
-rw-r--r--arch/arm/configs/sdm660-perf_defconfig11
-rw-r--r--arch/arm/configs/sdm660_defconfig16
-rw-r--r--arch/arm/include/asm/cacheflush.h12
-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.c37
-rw-r--r--arch/arm/mm/dma.h3
-rw-r--r--arch/arm/mm/highmem.c56
-rw-r--r--arch/arm/mm/init.c58
-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_defconfig3
-rw-r--r--arch/arm64/configs/msmcortex_defconfig5
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig708
-rw-r--r--arch/arm64/configs/sdm660-perf_defconfig1
-rw-r--r--arch/arm64/configs/sdm660_defconfig2
-rw-r--r--arch/arm64/kernel/entry.S3
-rw-r--r--arch/arm64/kernel/process.c2
-rw-r--r--arch/arm64/kernel/vdso/gettimeofday.S17
-rw-r--r--arch/arm64/mm/dma-mapping.c22
-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/Kconfig4
-rw-r--r--drivers/base/regmap/regmap-debugfs.c7
-rw-r--r--drivers/bluetooth/btfm_slim.c5
-rw-r--r--drivers/char/adsprpc.c33
-rw-r--r--drivers/char/diag/diag_dci.c7
-rw-r--r--drivers/clk/clk.c3
-rw-r--r--drivers/clk/clk.h1
-rw-r--r--drivers/clk/msm/clock-mmss-8998.c2
-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.c21
-rw-r--r--drivers/clk/qcom/common.h29
-rw-r--r--drivers/clk/qcom/gcc-sdm660.c200
-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.c49
-rw-r--r--drivers/gpio/Kconfig23
-rw-r--r--drivers/gpio/qpnp-pin.c72
-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/adreno-gpulist.h16
-rw-r--r--drivers/gpu/msm/adreno.h2
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c13
-rw-r--r--drivers/gpu/msm/kgsl.c7
-rw-r--r--drivers/iio/adc/qcom-tadc.c587
-rw-r--r--drivers/iio/inkern.c18
-rw-r--r--drivers/input/keyboard/gpio_keys.c90
-rw-r--r--drivers/input/misc/vl53L0/Makefile20
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l010_api.h1476
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l010_device.h237
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l010_strings.h134
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l010_tuning.h58
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_api.h1950
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_api_calibration.h85
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_api_core.h108
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_api_histogram.h70
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_api_ranging.h47
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_api_strings.h277
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_def.h663
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_device.h261
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_i2c_platform.h402
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_interrupt_threshold_settings.h194
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_platform.h231
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_platform_log.h128
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_tuning.h146
-rw-r--r--drivers/input/misc/vl53L0/inc/vl53l0_types.h69
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l010_api.c4175
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l010_tuning.c138
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_api.c3109
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_api_calibration.c1284
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_api_core.c2270
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_api_histogram.c750
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_api_ranging.c42
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_api_strings.c463
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_i2c_platform.c383
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_platform.c242
-rw-r--r--drivers/input/misc/vl53L0/src/vl53l0_port_i2c.c155
-rw-r--r--drivers/input/misc/vl53L0/stmvl53l0-cci.h61
-rw-r--r--drivers/input/misc/vl53L0/stmvl53l0-i2c.h35
-rw-r--r--drivers/input/misc/vl53L0/stmvl53l0.h217
-rw-r--r--drivers/input/misc/vl53L0/stmvl53l0_module-cci.c509
-rw-r--r--drivers/input/misc/vl53L0/stmvl53l0_module-i2c.c266
-rw-r--r--drivers/input/misc/vl53L0/stmvl53l0_module.c2878
-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/Kconfig69
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c9
-rw-r--r--drivers/leds/leds-qpnp-flash.c107
-rw-r--r--drivers/leds/leds-qpnp-wled.c50
-rw-r--r--drivers/leds/leds-qpnp.c217
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c55
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp48.c38
-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/sde/rotator/sde_rotator_base.c41
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_base.h21
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c54
-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.c67
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c73
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.h9
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_util.c11
-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/mfd/Kconfig3
-rw-r--r--drivers/misc/qseecom.c18
-rw-r--r--drivers/mmc/card/block.c4
-rw-r--r--drivers/mmc/core/core.c4
-rw-r--r--drivers/mmc/host/sdhci-msm.c8
-rw-r--r--drivers/net/ethernet/msm/ecm_ipa.c25
-rw-r--r--drivers/net/ethernet/msm/msm_rmnet_mhi.c1
-rw-r--r--drivers/net/ethernet/msm/rndis_ipa.c88
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c21
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h2
-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-ops.h24
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c104
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h231
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c42
-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.c71
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h23
-rw-r--r--drivers/platform/msm/Kconfig18
-rw-r--r--drivers/platform/msm/gsi/gsi.c12
-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.c81
-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.h3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c97
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c18
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c15
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h9
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c224
-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/platform/msm/qpnp-coincell.c4
-rw-r--r--drivers/platform/msm/qpnp-revid.c4
-rw-r--r--drivers/power/power_supply_sysfs.c12
-rw-r--r--drivers/power/supply/qcom/Makefile2
-rw-r--r--drivers/power/supply/qcom/battery.c120
-rw-r--r--drivers/power/supply/qcom/fg-core.h18
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c371
-rw-r--r--drivers/power/supply/qcom/qpnp-qnovo.c130
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c229
-rw-r--r--drivers/power/supply/qcom/smb-lib.c1148
-rw-r--r--drivers/power/supply/qcom/smb-lib.h97
-rw-r--r--drivers/power/supply/qcom/smb-reg.h13
-rw-r--r--drivers/power/supply/qcom/smb1351-charger.c158
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c403
-rw-r--r--drivers/power/supply/qcom/storm-watch.c11
-rw-r--r--drivers/power/supply/qcom/storm-watch.h16
-rw-r--r--drivers/pwm/Kconfig13
-rw-r--r--drivers/pwm/pwm-qpnp.c143
-rw-r--r--drivers/regulator/Kconfig54
-rw-r--r--drivers/regulator/cpr3-hmss-regulator.c6
-rw-r--r--drivers/regulator/cpr3-mmss-regulator.c2
-rw-r--r--drivers/regulator/cpr3-regulator.c97
-rw-r--r--drivers/regulator/cpr3-regulator.h15
-rw-r--r--drivers/regulator/cpr3-util.c8
-rw-r--r--drivers/regulator/cpr4-apss-regulator.c4
-rw-r--r--drivers/regulator/cpr4-mmss-ldo-regulator.c5
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c245
-rw-r--r--drivers/regulator/kryo-regulator.c18
-rw-r--r--drivers/regulator/mem-acc-regulator.c47
-rw-r--r--drivers/regulator/msm_gfx_ldo.c30
-rw-r--r--drivers/regulator/qpnp-labibb-regulator.c14
-rw-r--r--drivers/regulator/qpnp-lcdb-regulator.c6
-rw-r--r--drivers/regulator/qpnp-oledb-regulator.c2
-rw-r--r--drivers/regulator/qpnp-regulator.c49
-rw-r--r--drivers/rtc/Kconfig21
-rw-r--r--drivers/rtc/qpnp-rtc.c37
-rw-r--r--drivers/scsi/ufs/ufshcd.c34
-rw-r--r--drivers/soc/qcom/Kconfig21
-rw-r--r--drivers/soc/qcom/Makefile3
-rw-r--r--drivers/soc/qcom/cx_ipeak.c202
-rw-r--r--drivers/soc/qcom/icnss.c212
-rw-r--r--drivers/soc/qcom/memshare/msm_memshare.c2
-rw-r--r--drivers/soc/qcom/peripheral-loader.c31
-rw-r--r--drivers/soc/qcom/qdsp6v2/voice_svc.c26
-rw-r--r--drivers/soc/qcom/qpnp-haptic.c125
-rw-r--r--drivers/soc/qcom/rpm_rail_stats.c329
-rw-r--r--drivers/soc/qcom/service-notifier.c28
-rw-r--r--drivers/soc/qcom/spcom.c36
-rw-r--r--drivers/soundwire/swr-wcd-ctrl.c19
-rw-r--r--drivers/spi/spi_qsd.c3
-rw-r--r--drivers/spi/spi_qsd.h7
-rw-r--r--drivers/thermal/Kconfig25
-rw-r--r--drivers/thermal/msm_thermal.c17
-rw-r--r--drivers/thermal/qpnp-temp-alarm.c4
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c5
-rw-r--r--drivers/usb/gadget/function/f_diag.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.c32
-rw-r--r--drivers/usb/host/xhci-mem.c6
-rw-r--r--drivers/usb/host/xhci.c8
-rw-r--r--drivers/usb/pd/policy_engine.c88
-rw-r--r--drivers/video/fbdev/msm/mdss.h11
-rw-r--r--drivers/video/fbdev/msm/mdss_debug.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c18
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c201
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c91
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h13
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c54
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c36
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c7
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c20
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c17
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c16
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h9
-rw-r--r--drivers/video/fbdev/msm/mdss_rotator.c8
-rw-r--r--drivers/video/fbdev/msm/mdss_smmu.c211
-rw-r--r--drivers/video/fbdev/msm/mdss_smmu.h18
-rw-r--r--drivers/video/fbdev/msm/msm_ext_display.c2
-rw-r--r--include/dt-bindings/clock/qcom,gcc-sdm660.h1
-rw-r--r--include/dt-bindings/clock/qcom,mmcc-msm8996.h485
-rw-r--r--include/linux/iio/consumer.h10
-rw-r--r--include/linux/mdss_smmu_ext.h53
-rw-r--r--include/linux/msm_ext_display.h5
-rw-r--r--include/linux/pfk.h6
-rw-r--r--include/linux/pid.h4
-rw-r--r--include/linux/power_supply.h7
-rw-r--r--include/linux/qdsp6v2/rtac.h4
-rw-r--r--include/linux/regulator/qpnp-regulator.h6
-rw-r--r--include/linux/sched.h19
-rw-r--r--include/soc/qcom/cx_ipeak.h46
-rw-r--r--include/soc/qcom/icnss.h11
-rw-r--r--include/soc/qcom/qseecomi.h5
-rw-r--r--include/soc/qcom/service-notifier.h11
-rw-r--r--include/sound/apr_audio-v2.h185
-rw-r--r--include/sound/jack.h12
-rw-r--r--include/sound/q6adm-v2.h6
-rw-r--r--include/sound/q6afe-v2.h7
-rw-r--r--include/sound/q6asm-v2.h6
-rw-r--r--include/trace/events/power.h2
-rw-r--r--include/uapi/linux/msm_ipa.h4
-rw-r--r--include/uapi/linux/msm_mdp.h1
-rw-r--r--kernel/pid.c11
-rw-r--r--kernel/sched/hmp.c15
-rw-r--r--kernel/sysctl.c7
-rw-r--r--net/core/skbuff.c9
-rw-r--r--security/pfe/pfk.c14
-rw-r--r--security/pfe/pfk_kc.c24
-rw-r--r--security/pfe/pfk_kc.h3
-rw-r--r--sound/soc/codecs/msm_hdmi_codec_rx.c11
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c2
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c2
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c43
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.h1
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsd.c7
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-routing.h6
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c87
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.c13
-rw-r--r--sound/soc/codecs/wsa881x.c6
-rw-r--r--sound/soc/msm/msm8998.c342
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c94
-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-lsm-client.c44
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c92
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c131
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c289
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h4
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c483
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h14
-rw-r--r--sound/soc/msm/qdsp6v2/msm-qti-pp-config.c35
-rw-r--r--sound/soc/msm/qdsp6v2/q6adm.c10
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c274
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c86
-rw-r--r--sound/soc/msm/qdsp6v2/rtac.c20
-rw-r--r--sound/soc/msm/sdm660-ext-dai-links.c35
-rw-r--r--sound/soc/msm/sdm660-internal.c23
446 files changed, 49582 insertions, 5405 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/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt
index 15feda3b7407..a1cbf480890a 100644
--- a/Documentation/devicetree/bindings/cnss/icnss.txt
+++ b/Documentation/devicetree/bindings/cnss/icnss.txt
@@ -19,6 +19,7 @@ Required properties:
Optional properties:
- qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
- qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs.
+ - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
Example:
@@ -43,4 +44,5 @@ Example:
<0 140 0 /* CE10 */ >,
<0 141 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x200000>;
+ qcom,smmu-s1-bypass;
};
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/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index 4564bfff3996..85e097586466 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -1,10 +1,10 @@
-Qualcomm QPNP Leds
+Qualcomm Technologies, Inc. QPNP LEDs
-QPNP (Qualcomm Plug N Play) LEDs driver is used for
-controlling LEDs that are part of PMIC on Qualcomm reference
-platforms. The PMIC is connected to Host processor via
-SPMI bus. This driver supports various LED modules such as
-Keypad backlight, WLED (white LED), RGB LED and flash LED.
+Qualcomm Technologies, Inc. Plug N Play (QPNP) LED modules
+are used for controlling LEDs that are connected to a QPNP PMIC.
+The PMIC is connected to a host processor via the SPMI bus. Various
+LED modules are supported such as Keypad backlight, WLED (white LED),
+RGB LED and flash LED.
Each LED module is represented as a node of "leds-qpnp". This
node will further contain the type of LED supported and its
@@ -83,7 +83,7 @@ Optional properties for RGB led:
- qcom,turn-off-delay-ms: delay in millisecond for turning off the led when its default-state is "on". Value is being ignored in case default-state is "off".
- qcom,use-blink: Use blink sysfs entry for switching into lpg mode. For optimal use, set default mode to pwm. All required lpg parameters must be supplied.
-MPP LED is an LED controled through a Multi Purpose Pin.
+MPP LED is an LED controlled through a Multi Purpose Pin.
Optional properties for MPP LED:
- linux,default-trigger: trigger the led from external modules such as display
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt
index 10c1bbf3c604..4d55f0cecefe 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-coincell.txt
@@ -1,4 +1,4 @@
-Qualcomm QPNP Coincell - coincell battery charger devices
+Qualcomm Technologies, Inc. QPNP Coincell - coincell battery charger devices
Required properties:
- compatible: Must be "qcom,qpnp-coincell".
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/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index 0244f910017a..c8f2a5a8e496 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -52,6 +52,18 @@ Charger specific properties:
Value type: <u32>
Definition: Specifies the DC input current limit in micro-amps.
+- qcom,charger-temp-max-mdegc
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the maximum charger temperature in milli-degrees
+ Celsius. If unspecified a default of 80000 will be used.
+
+- qcom,connector-temp-max-mdegc
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the maximum connector temperature in milli-degrees
+ Celsius. If unspecified a default value of 105000 will be used.
+
- io-channels
Usage: optional
Value type: List of <phandle u32>
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/regulator/mem-acc-regulator.txt b/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt
index d217a4ea9fc8..55154579840a 100644
--- a/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/mem-acc-regulator.txt
@@ -1,4 +1,4 @@
-Qualcomm Technologies Memory Accelerator
+Qualcomm Technologies, Inc. Memory Accelerator
Memory accelerator configures the power-mode (corner) for the
accelerator.
diff --git a/Documentation/devicetree/bindings/regulator/msm_gfx_ldo.txt b/Documentation/devicetree/bindings/regulator/msm_gfx_ldo.txt
index dcbb120eea2a..bd7627b132ea 100644
--- a/Documentation/devicetree/bindings/regulator/msm_gfx_ldo.txt
+++ b/Documentation/devicetree/bindings/regulator/msm_gfx_ldo.txt
@@ -8,8 +8,9 @@ This document describes the bindings that apply for the GFX LDO regulator.
- compatible
Usage: required
Value type: <string>
- Definition: should be "qcom,msm8953-gfx-ldo" for MSM8953 and
- "qcom,sdm660-gfx-ldo" for SDM660
+ Definition: should be "qcom,msm8953-gfx-ldo" for MSM8953,
+ "qcom,sdm660-gfx-ldo" for SDM660 and "qcom,sdm630-gfx-ldo"
+ for SDM630.
- reg
Usage: required
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
index e1ebaf636ec3..601903bc60de 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-regulator.txt
@@ -1,4 +1,4 @@
-Qualcomm QPNP Regulators
+Qualcomm Technologies, Inc. QPNP Regulators
qpnp-regulator is a regulator driver which supports regulators inside of PMICs
that utilize the MSM SPMI implementation.
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/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
index 545cdedeca4c..bb20644afde6 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
@@ -1,8 +1,9 @@
-Qualcomm QPNP Temperature Alarm
+Qualcomm Technologies, Inc. QPNP Temperature Alarm
-QPNP temperature alarm peripherals are found inside of Qualcomm PMIC chips that
-utilize the MSM SPMI implementation. These peripherals provide an interrupt
-signal and status register to identify high PMIC die temperature.
+QPNP temperature alarm peripherals are found inside of Qualcomm Technologies,
+Inc. PMIC chips that utilize the MSM SPMI implementation. These peripherals
+provide an interrupt signal and status register to identify high PMIC die
+temperature.
Required properties:
- compatible: Must be "qcom,qpnp-temp-alarm".
diff --git a/Documentation/scheduler/sched-hmp.txt b/Documentation/scheduler/sched-hmp.txt
index 766c01d321b5..32906610b25f 100644
--- a/Documentation/scheduler/sched-hmp.txt
+++ b/Documentation/scheduler/sched-hmp.txt
@@ -917,7 +917,7 @@ returns prev_runnable_sum, scaled to the efficiency and fmax of given
CPU. The same applies to nt_curr_runnable_sum and nt_prev_runnable_sum.
A 'new' task is defined as a task whose number of active windows since fork is
-less than sysctl_sched_new_task_windows. An active window is defined as a window
+less than SCHED_NEW_TASK_WINDOWS. An active window is defined as a window
where a task was observed to be runnable.
Moving on the second type of statistics; top-tasks, the scheduler tracks a list
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8d3d7a283eed..56961334bb7e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -230,6 +230,9 @@ config NEED_RET_TO_USER
config ARCH_MTD_XIP
bool
+config ARCH_WANT_KMAP_ATOMIC_FLUSH
+ bool
+
config VECTORS_BASE
hex
default 0xffff0000 if MMU || CPU_HIGH_VECTOR
@@ -652,6 +655,7 @@ config ARCH_QCOM
select SPARSE_IRQ
select USE_OF
select PINCTRL
+ select ARCH_WANT_KMAP_ATOMIC_FLUSH
help
Support for Qualcomm MSM/QSD based systems. This runs on the
apps processor of the MSM/QSD and depends on a shared memory
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 815018770fb9..553b02b31847 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -86,6 +86,18 @@ config FORCE_PAGES
If unsure say N.
+config FREE_PAGES_RDONLY
+ bool "Set pages as read only while on the buddy list"
+ select FORCE_PAGES
+ select PAGE_POISONING
+ help
+ Pages are always mapped in the kernel. This means that anyone
+ can write to the page if they have the address. Enable this option
+ to mark pages as read only to trigger a fault if any code attempts
+ to write to a page on the buddy list. This may have a performance
+ impact.
+
+ If unsure, say N.
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 83fee34e5265..d572568eb94e 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -160,6 +160,10 @@ dtb-$(CONFIG_ARCH_SDM660) += sdm660-sim.dtb \
sda660-pm660a-cdp.dtb \
sda660-pm660a-mtp.dtb \
sda660-pm660a-rcm.dtb \
+ sdm660-headset-jacktype-no-cdp.dtb \
+ sdm660-headset-jacktype-no-rcm.dtb \
+ sdm660-pm660a-headset-jacktype-no-cdp.dtb \
+ sdm660-pm660a-headset-jacktype-no-rcm.dtb \
sdm658-mtp.dtb \
sdm658-cdp.dtb \
sdm658-rcm.dtb \
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 78fdba4fdb9b..6288031fdd50 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
+++ b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
@@ -21,12 +21,8 @@
qcom,board-id = <8 1>;
};
-&pil_modem {
- status = "disabled";
-};
-
&msm_ath10k_wlan {
- status = "enabled";
+ status = "ok";
};
&mdss_mdp {
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
index 89bf222231fb..39d3db3067e6 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
@@ -37,162 +37,162 @@
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
- 15 01 00 00 10 00 02 ff 20
- 15 01 00 00 10 00 02 fb 01
- 15 01 00 00 10 00 02 00 01
- 15 01 00 00 10 00 02 01 55
- 15 01 00 00 10 00 02 02 45
- 15 01 00 00 10 00 02 05 40
- 15 01 00 00 10 00 02 06 19
- 15 01 00 00 10 00 02 07 1e
- 15 01 00 00 10 00 02 0b 73
- 15 01 00 00 10 00 02 0c 73
- 15 01 00 00 10 00 02 0e b0
- 15 01 00 00 10 00 02 0f ae
- 15 01 00 00 10 00 02 11 b8
- 15 01 00 00 10 00 02 13 00
- 15 01 00 00 10 00 02 58 80
- 15 01 00 00 10 00 02 59 01
- 15 01 00 00 10 00 02 5a 00
- 15 01 00 00 10 00 02 5b 01
- 15 01 00 00 10 00 02 5c 80
- 15 01 00 00 10 00 02 5d 81
- 15 01 00 00 10 00 02 5e 00
- 15 01 00 00 10 00 02 5f 01
- 15 01 00 00 10 00 02 72 31
- 15 01 00 00 10 00 02 68 03
+ 15 01 00 00 00 00 02 ff 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1e
+ 15 01 00 00 00 00 02 0b 73
+ 15 01 00 00 00 00 02 0c 73
+ 15 01 00 00 00 00 02 0e b0
+ 15 01 00 00 00 00 02 0f ae
+ 15 01 00 00 00 00 02 11 b8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5a 00
+ 15 01 00 00 00 00 02 5b 01
+ 15 01 00 00 00 00 02 5c 80
+ 15 01 00 00 00 00 02 5d 81
+ 15 01 00 00 00 00 02 5e 00
+ 15 01 00 00 00 00 02 5f 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
- 15 01 00 00 10 00 02 ff 24
- 15 01 00 00 10 00 02 fb 01
- 15 01 00 00 10 00 02 00 1c
- 15 01 00 00 10 00 02 01 0b
- 15 01 00 00 10 00 02 02 0c
- 15 01 00 00 10 00 02 03 01
- 15 01 00 00 10 00 02 04 0f
- 15 01 00 00 10 00 02 05 10
- 15 01 00 00 10 00 02 06 10
- 15 01 00 00 10 00 02 07 10
- 15 01 00 00 10 00 02 08 89
- 15 01 00 00 10 00 02 09 8a
- 15 01 00 00 10 00 02 0a 13
- 15 01 00 00 10 00 02 0b 13
- 15 01 00 00 10 00 02 0c 15
- 15 01 00 00 10 00 02 0d 15
- 15 01 00 00 10 00 02 0e 17
- 15 01 00 00 10 00 02 0f 17
- 15 01 00 00 10 00 02 10 1c
- 15 01 00 00 10 00 02 11 0b
- 15 01 00 00 10 00 02 12 0c
- 15 01 00 00 10 00 02 13 01
- 15 01 00 00 10 00 02 14 0f
- 15 01 00 00 10 00 02 15 10
- 15 01 00 00 10 00 02 16 10
- 15 01 00 00 10 00 02 17 10
- 15 01 00 00 10 00 02 18 89
- 15 01 00 00 10 00 02 19 8a
- 15 01 00 00 10 00 02 1a 13
- 15 01 00 00 10 00 02 1b 13
- 15 01 00 00 10 00 02 1c 15
- 15 01 00 00 10 00 02 1d 15
- 15 01 00 00 10 00 02 1e 17
- 15 01 00 00 10 00 02 1f 17
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1c
+ 15 01 00 00 00 00 02 01 0b
+ 15 01 00 00 00 00 02 02 0c
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0f
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8a
+ 15 01 00 00 00 00 02 0a 13
+ 15 01 00 00 00 00 02 0b 13
+ 15 01 00 00 00 00 02 0c 15
+ 15 01 00 00 00 00 02 0d 15
+ 15 01 00 00 00 00 02 0e 17
+ 15 01 00 00 00 00 02 0f 17
+ 15 01 00 00 00 00 02 10 1c
+ 15 01 00 00 00 00 02 11 0b
+ 15 01 00 00 00 00 02 12 0c
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0f
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8a
+ 15 01 00 00 00 00 02 1a 13
+ 15 01 00 00 00 00 02 1b 13
+ 15 01 00 00 00 00 02 1c 15
+ 15 01 00 00 00 00 02 1d 15
+ 15 01 00 00 00 00 02 1e 17
+ 15 01 00 00 00 00 02 1f 17
/* STV */
- 15 01 00 00 10 00 02 20 40
- 15 01 00 00 10 00 02 21 01
- 15 01 00 00 10 00 02 22 00
- 15 01 00 00 10 00 02 23 40
- 15 01 00 00 10 00 02 24 40
- 15 01 00 00 10 00 02 25 6d
- 15 01 00 00 10 00 02 26 40
- 15 01 00 00 10 00 02 27 40
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6d
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
/* Vend */
- 15 01 00 00 10 00 02 e0 00
- 15 01 00 00 10 00 02 dc 21
- 15 01 00 00 10 00 02 dd 22
- 15 01 00 00 10 00 02 de 07
- 15 01 00 00 10 00 02 df 07
- 15 01 00 00 10 00 02 e3 6D
- 15 01 00 00 10 00 02 e1 07
- 15 01 00 00 10 00 02 e2 07
+ 15 01 00 00 00 00 02 e0 00
+ 15 01 00 00 00 00 02 dc 21
+ 15 01 00 00 00 00 02 dd 22
+ 15 01 00 00 00 00 02 de 07
+ 15 01 00 00 00 00 02 df 07
+ 15 01 00 00 00 00 02 e3 6D
+ 15 01 00 00 00 00 02 e1 07
+ 15 01 00 00 00 00 02 e2 07
/* UD */
- 15 01 00 00 10 00 02 29 d8
- 15 01 00 00 10 00 02 2a 2a
+ 15 01 00 00 00 00 02 29 d8
+ 15 01 00 00 00 00 02 2a 2a
/* CLK */
- 15 01 00 00 10 00 02 4b 03
- 15 01 00 00 10 00 02 4c 11
- 15 01 00 00 10 00 02 4d 10
- 15 01 00 00 10 00 02 4e 01
- 15 01 00 00 10 00 02 4f 01
- 15 01 00 00 10 00 02 50 10
- 15 01 00 00 10 00 02 51 00
- 15 01 00 00 10 00 02 52 80
- 15 01 00 00 10 00 02 53 00
- 15 01 00 00 10 00 02 56 00
- 15 01 00 00 10 00 02 54 07
- 15 01 00 00 10 00 02 58 07
- 15 01 00 00 10 00 02 55 25
+ 15 01 00 00 00 00 02 4b 03
+ 15 01 00 00 00 00 02 4c 11
+ 15 01 00 00 00 00 02 4d 10
+ 15 01 00 00 00 00 02 4e 01
+ 15 01 00 00 00 00 02 4f 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
/* Reset XDONB */
- 15 01 00 00 10 00 02 5b 43
- 15 01 00 00 10 00 02 5c 00
- 15 01 00 00 10 00 02 5f 73
- 15 01 00 00 10 00 02 60 73
- 15 01 00 00 10 00 02 63 22
- 15 01 00 00 10 00 02 64 00
- 15 01 00 00 10 00 02 67 08
- 15 01 00 00 10 00 02 68 04
+ 15 01 00 00 00 00 02 5b 43
+ 15 01 00 00 00 00 02 5c 00
+ 15 01 00 00 00 00 02 5f 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
/* Resolution:1440x2560*/
- 15 01 00 00 10 00 02 72 02
+ 15 01 00 00 00 00 02 72 02
/* mux */
- 15 01 00 00 10 00 02 7a 80
- 15 01 00 00 10 00 02 7b 91
- 15 01 00 00 10 00 02 7c D8
- 15 01 00 00 10 00 02 7d 60
- 15 01 00 00 10 00 02 7f 15
- 15 01 00 00 10 00 02 75 15
+ 15 01 00 00 00 00 02 7a 80
+ 15 01 00 00 00 00 02 7b 91
+ 15 01 00 00 00 00 02 7c D8
+ 15 01 00 00 00 00 02 7d 60
+ 15 01 00 00 00 00 02 7f 15
+ 15 01 00 00 00 00 02 75 15
/* ABOFF */
- 15 01 00 00 10 00 02 b3 C0
- 15 01 00 00 10 00 02 b4 00
- 15 01 00 00 10 00 02 b5 00
+ 15 01 00 00 00 00 02 b3 C0
+ 15 01 00 00 00 00 02 b4 00
+ 15 01 00 00 00 00 02 b5 00
/* Source EQ */
- 15 01 00 00 10 00 02 78 00
- 15 01 00 00 10 00 02 79 00
- 15 01 00 00 10 00 02 80 00
- 15 01 00 00 10 00 02 83 00
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
/* FP BP */
- 15 01 00 00 10 00 02 93 0a
- 15 01 00 00 10 00 02 94 0a
+ 15 01 00 00 00 00 02 93 0a
+ 15 01 00 00 00 00 02 94 0a
/* Inversion Type */
- 15 01 00 00 10 00 02 8a 00
- 15 01 00 00 10 00 02 9b ff
+ 15 01 00 00 00 00 02 8a 00
+ 15 01 00 00 00 00 02 9b ff
/* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 10 00 02 9d b0
- 15 01 00 00 10 00 02 9f 63
- 15 01 00 00 10 00 02 98 10
+ 15 01 00 00 00 00 02 9d b0
+ 15 01 00 00 00 00 02 9f 63
+ 15 01 00 00 00 00 02 98 10
/* FRM */
- 15 01 00 00 10 00 02 ec 00
+ 15 01 00 00 00 00 02 ec 00
/* CMD1 */
- 15 01 00 00 10 00 02 ff 10
+ 15 01 00 00 00 00 02 ff 10
/* VESA DSC PPS settings(1440x2560 slide 16H) */
- 39 01 00 00 10 00 11 c1 09 20 00 10 02 00 02 68
+ 39 01 00 00 00 00 11 c1 09 20 00 10 02 00 02 68
01 bb 00 0a 06 67 04 c5
- 39 01 00 00 10 00 03 c2 10 f0
+ 39 01 00 00 00 00 03 c2 10 f0
/* C0h = 0x0(2 Port SDC)0x01(1 PortA FBC)
* 0x02(MTK) 0x03(1 PortA VESA)
*/
- 15 01 00 00 10 00 02 c0 03
+ 15 01 00 00 00 00 02 c0 03
/* VBP+VSA=,VFP = 10H */
- 15 01 00 00 10 00 04 3b 03 0a 0a
+ 15 01 00 00 00 00 04 3b 03 0a 0a
/* FTE on */
- 15 01 00 00 10 00 02 35 00
+ 15 01 00 00 00 00 02 35 00
/* EN_BK =1(auto black) */
- 15 01 00 00 10 00 02 e5 01
+ 15 01 00 00 00 00 02 e5 01
/* CMD mode(10) VDO mode(03) */
- 15 01 00 00 10 00 02 bb 10
+ 15 01 00 00 00 00 02 bb 10
/* Non Reload MTP */
- 15 01 00 00 10 00 02 fb 01
+ 15 01 00 00 00 00 02 fb 01
/* SlpOut + DispOn */
- 05 01 00 00 a0 00 02 11 00
- 05 01 00 00 a0 00 02 29 00
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
];
qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
05 01 00 00 78 00 02 10 00];
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
index ca2ff6eb4924..353b3b2b09bd 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
@@ -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
@@ -32,162 +32,162 @@
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
- 15 01 00 00 10 00 02 ff 20
- 15 01 00 00 10 00 02 fb 01
- 15 01 00 00 10 00 02 00 01
- 15 01 00 00 10 00 02 01 55
- 15 01 00 00 10 00 02 02 45
- 15 01 00 00 10 00 02 05 40
- 15 01 00 00 10 00 02 06 19
- 15 01 00 00 10 00 02 07 1e
- 15 01 00 00 10 00 02 0b 73
- 15 01 00 00 10 00 02 0c 73
- 15 01 00 00 10 00 02 0e b0
- 15 01 00 00 10 00 02 0f aE
- 15 01 00 00 10 00 02 11 b8
- 15 01 00 00 10 00 02 13 00
- 15 01 00 00 10 00 02 58 80
- 15 01 00 00 10 00 02 59 01
- 15 01 00 00 10 00 02 5a 00
- 15 01 00 00 10 00 02 5b 01
- 15 01 00 00 10 00 02 5c 80
- 15 01 00 00 10 00 02 5d 81
- 15 01 00 00 10 00 02 5e 00
- 15 01 00 00 10 00 02 5f 01
- 15 01 00 00 10 00 02 72 31
- 15 01 00 00 10 00 02 68 03
+ 15 01 00 00 00 00 02 ff 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1e
+ 15 01 00 00 00 00 02 0b 73
+ 15 01 00 00 00 00 02 0c 73
+ 15 01 00 00 00 00 02 0e b0
+ 15 01 00 00 00 00 02 0f aE
+ 15 01 00 00 00 00 02 11 b8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5a 00
+ 15 01 00 00 00 00 02 5b 01
+ 15 01 00 00 00 00 02 5c 80
+ 15 01 00 00 00 00 02 5d 81
+ 15 01 00 00 00 00 02 5e 00
+ 15 01 00 00 00 00 02 5f 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
- 15 01 00 00 10 00 02 ff 24
- 15 01 00 00 10 00 02 fb 01
- 15 01 00 00 10 00 02 00 1c
- 15 01 00 00 10 00 02 01 0b
- 15 01 00 00 10 00 02 02 0c
- 15 01 00 00 10 00 02 03 01
- 15 01 00 00 10 00 02 04 0f
- 15 01 00 00 10 00 02 05 10
- 15 01 00 00 10 00 02 06 10
- 15 01 00 00 10 00 02 07 10
- 15 01 00 00 10 00 02 08 89
- 15 01 00 00 10 00 02 09 8a
- 15 01 00 00 10 00 02 0a 13
- 15 01 00 00 10 00 02 0b 13
- 15 01 00 00 10 00 02 0c 15
- 15 01 00 00 10 00 02 0d 15
- 15 01 00 00 10 00 02 0e 17
- 15 01 00 00 10 00 02 0f 17
- 15 01 00 00 10 00 02 10 1c
- 15 01 00 00 10 00 02 11 0b
- 15 01 00 00 10 00 02 12 0c
- 15 01 00 00 10 00 02 13 01
- 15 01 00 00 10 00 02 14 0f
- 15 01 00 00 10 00 02 15 10
- 15 01 00 00 10 00 02 16 10
- 15 01 00 00 10 00 02 17 10
- 15 01 00 00 10 00 02 18 89
- 15 01 00 00 10 00 02 19 8a
- 15 01 00 00 10 00 02 1a 13
- 15 01 00 00 10 00 02 1b 13
- 15 01 00 00 10 00 02 1c 15
- 15 01 00 00 10 00 02 1d 15
- 15 01 00 00 10 00 02 1e 17
- 15 01 00 00 10 00 02 1f 17
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1c
+ 15 01 00 00 00 00 02 01 0b
+ 15 01 00 00 00 00 02 02 0c
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0f
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8a
+ 15 01 00 00 00 00 02 0a 13
+ 15 01 00 00 00 00 02 0b 13
+ 15 01 00 00 00 00 02 0c 15
+ 15 01 00 00 00 00 02 0d 15
+ 15 01 00 00 00 00 02 0e 17
+ 15 01 00 00 00 00 02 0f 17
+ 15 01 00 00 00 00 02 10 1c
+ 15 01 00 00 00 00 02 11 0b
+ 15 01 00 00 00 00 02 12 0c
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0f
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8a
+ 15 01 00 00 00 00 02 1a 13
+ 15 01 00 00 00 00 02 1b 13
+ 15 01 00 00 00 00 02 1c 15
+ 15 01 00 00 00 00 02 1d 15
+ 15 01 00 00 00 00 02 1e 17
+ 15 01 00 00 00 00 02 1f 17
/* STV */
- 15 01 00 00 10 00 02 20 40
- 15 01 00 00 10 00 02 21 01
- 15 01 00 00 10 00 02 22 00
- 15 01 00 00 10 00 02 23 40
- 15 01 00 00 10 00 02 24 40
- 15 01 00 00 10 00 02 25 6d
- 15 01 00 00 10 00 02 26 40
- 15 01 00 00 10 00 02 27 40
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6d
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
/* Vend */
- 15 01 00 00 10 00 02 e0 00
- 15 01 00 00 10 00 02 dc 21
- 15 01 00 00 10 00 02 dd 22
- 15 01 00 00 10 00 02 de 07
- 15 01 00 00 10 00 02 df 07
- 15 01 00 00 10 00 02 e3 6d
- 15 01 00 00 10 00 02 e1 07
- 15 01 00 00 10 00 02 e2 07
+ 15 01 00 00 00 00 02 e0 00
+ 15 01 00 00 00 00 02 dc 21
+ 15 01 00 00 00 00 02 dd 22
+ 15 01 00 00 00 00 02 de 07
+ 15 01 00 00 00 00 02 df 07
+ 15 01 00 00 00 00 02 e3 6d
+ 15 01 00 00 00 00 02 e1 07
+ 15 01 00 00 00 00 02 e2 07
/* UD */
- 15 01 00 00 10 00 02 29 d8
- 15 01 00 00 10 00 02 2a 2a
+ 15 01 00 00 00 00 02 29 d8
+ 15 01 00 00 00 00 02 2a 2a
/* CLK */
- 15 01 00 00 10 00 02 4b 03
- 15 01 00 00 10 00 02 4c 11
- 15 01 00 00 10 00 02 4d 10
- 15 01 00 00 10 00 02 4e 01
- 15 01 00 00 10 00 02 4f 01
- 15 01 00 00 10 00 02 50 10
- 15 01 00 00 10 00 02 51 00
- 15 01 00 00 10 00 02 52 80
- 15 01 00 00 10 00 02 53 00
- 15 01 00 00 10 00 02 56 00
- 15 01 00 00 10 00 02 54 07
- 15 01 00 00 10 00 02 58 07
- 15 01 00 00 10 00 02 55 25
+ 15 01 00 00 00 00 02 4b 03
+ 15 01 00 00 00 00 02 4c 11
+ 15 01 00 00 00 00 02 4d 10
+ 15 01 00 00 00 00 02 4e 01
+ 15 01 00 00 00 00 02 4f 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
/* Reset XDONB */
- 15 01 00 00 10 00 02 5b 43
- 15 01 00 00 10 00 02 5c 00
- 15 01 00 00 10 00 02 5f 73
- 15 01 00 00 10 00 02 60 73
- 15 01 00 00 10 00 02 63 22
- 15 01 00 00 10 00 02 64 00
- 15 01 00 00 10 00 02 67 08
- 15 01 00 00 10 00 02 68 04
+ 15 01 00 00 00 00 02 5b 43
+ 15 01 00 00 00 00 02 5c 00
+ 15 01 00 00 00 00 02 5f 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
/* Resolution:1440x2560*/
- 15 01 00 00 10 00 02 72 02
+ 15 01 00 00 00 00 02 72 02
/* mux */
- 15 01 00 00 10 00 02 7a 80
- 15 01 00 00 10 00 02 7b 91
- 15 01 00 00 10 00 02 7c d8
- 15 01 00 00 10 00 02 7d 60
- 15 01 00 00 10 00 02 7f 15
- 15 01 00 00 10 00 02 75 15
+ 15 01 00 00 00 00 02 7a 80
+ 15 01 00 00 00 00 02 7b 91
+ 15 01 00 00 00 00 02 7c d8
+ 15 01 00 00 00 00 02 7d 60
+ 15 01 00 00 00 00 02 7f 15
+ 15 01 00 00 00 00 02 75 15
/* ABOFF */
- 15 01 00 00 10 00 02 b3 c0
- 15 01 00 00 10 00 02 b4 00
- 15 01 00 00 10 00 02 b5 00
+ 15 01 00 00 00 00 02 b3 c0
+ 15 01 00 00 00 00 02 b4 00
+ 15 01 00 00 00 00 02 b5 00
/* Source EQ */
- 15 01 00 00 10 00 02 78 00
- 15 01 00 00 10 00 02 79 00
- 15 01 00 00 10 00 02 80 00
- 15 01 00 00 10 00 02 83 00
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
/* FP BP */
- 15 01 00 00 10 00 02 93 0a
- 15 01 00 00 10 00 02 94 0a
+ 15 01 00 00 00 00 02 93 0a
+ 15 01 00 00 00 00 02 94 0a
/* Inversion Type */
- 15 01 00 00 10 00 02 8a 00
- 15 01 00 00 10 00 02 9b ff
+ 15 01 00 00 00 00 02 8a 00
+ 15 01 00 00 00 00 02 9b ff
/* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 10 00 02 9d b0
- 15 01 00 00 10 00 02 9f 63
- 15 01 00 00 10 00 02 98 10
+ 15 01 00 00 00 00 02 9d b0
+ 15 01 00 00 00 00 02 9f 63
+ 15 01 00 00 00 00 02 98 10
/* FRM */
- 15 01 00 00 10 00 02 ec 00
+ 15 01 00 00 00 00 02 ec 00
/* CMD1 */
- 15 01 00 00 10 00 02 ff 10
+ 15 01 00 00 00 00 02 ff 10
/* VESA DSC PPS settings(1440x2560 slide 16H) */
- 39 01 00 00 10 00 11 c1 09 20 00 10 02 00 02 68 01
+ 39 01 00 00 00 00 11 c1 09 20 00 10 02 00 02 68 01
bb 00 0a 06 67 04 c5
- 39 01 00 00 10 00 03 c2 10 f0
+ 39 01 00 00 00 00 03 c2 10 f0
/* C0h = 0x00(2 Port SDC); 0x01(1 PortA FBC);
* 0x02(MTK); 0x03(1 PortA VESA)
*/
- 15 01 00 00 10 00 02 c0 03
+ 15 01 00 00 00 00 02 c0 03
/* VBP+VSA=,VFP = 10H */
- 39 01 00 00 10 00 04 3b 03 0a 0a
+ 39 01 00 00 00 00 04 3b 03 0a 0a
/* FTE on */
- 15 01 00 00 10 00 02 35 00
+ 15 01 00 00 00 00 02 35 00
/* EN_BK =1(auto black) */
- 15 01 00 00 10 00 02 e5 01
+ 15 01 00 00 00 00 02 e5 01
/* CMD mode(10) VDO mode(03) */
- 15 01 00 00 10 00 02 bb 03
+ 15 01 00 00 00 00 02 bb 03
/* Non Reload MTP */
- 15 01 00 00 10 00 02 fb 01
+ 15 01 00 00 00 00 02 fb 01
/* SlpOut + DispOn */
- 05 01 00 00 a0 00 02 11 00
- 05 01 00 00 a0 00 02 29 00
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
];
qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
05 01 00 00 78 00 02 10 00];
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
index 28b0d6d9cf14..6ff016676de7 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
@@ -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
@@ -61,154 +61,154 @@
qcom,ulps-enabled;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
- 15 01 00 00 10 00 02 FF 20
- 15 01 00 00 10 00 02 fb 01
- 15 01 00 00 10 00 02 00 01
- 15 01 00 00 10 00 02 01 55
- 15 01 00 00 10 00 02 02 45
- 15 01 00 00 10 00 02 05 40
- 15 01 00 00 10 00 02 06 19
- 15 01 00 00 10 00 02 07 1E
- 15 01 00 00 10 00 02 0B 73
- 15 01 00 00 10 00 02 0C 73
- 15 01 00 00 10 00 02 0E B0
- 15 01 00 00 10 00 02 0F AE
- 15 01 00 00 10 00 02 11 B8
- 15 01 00 00 10 00 02 13 00
- 15 01 00 00 10 00 02 58 80
- 15 01 00 00 10 00 02 59 01
- 15 01 00 00 10 00 02 5A 00
- 15 01 00 00 10 00 02 5B 01
- 15 01 00 00 10 00 02 5C 80
- 15 01 00 00 10 00 02 5D 81
- 15 01 00 00 10 00 02 5E 00
- 15 01 00 00 10 00 02 5F 01
- 15 01 00 00 10 00 02 72 31
- 15 01 00 00 10 00 02 68 03
+ 15 01 00 00 00 00 02 FF 20
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1E
+ 15 01 00 00 00 00 02 0B 73
+ 15 01 00 00 00 00 02 0C 73
+ 15 01 00 00 00 00 02 0E B0
+ 15 01 00 00 00 00 02 0F AE
+ 15 01 00 00 00 00 02 11 B8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5A 00
+ 15 01 00 00 00 00 02 5B 01
+ 15 01 00 00 00 00 02 5C 80
+ 15 01 00 00 00 00 02 5D 81
+ 15 01 00 00 00 00 02 5E 00
+ 15 01 00 00 00 00 02 5F 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
- 15 01 00 00 10 00 02 ff 24
- 15 01 00 00 10 00 02 fb 01
- 15 01 00 00 10 00 02 00 1C
- 15 01 00 00 10 00 02 01 0B
- 15 01 00 00 10 00 02 02 0C
- 15 01 00 00 10 00 02 03 01
- 15 01 00 00 10 00 02 04 0F
- 15 01 00 00 10 00 02 05 10
- 15 01 00 00 10 00 02 06 10
- 15 01 00 00 10 00 02 07 10
- 15 01 00 00 10 00 02 08 89
- 15 01 00 00 10 00 02 09 8A
- 15 01 00 00 10 00 02 0A 13
- 15 01 00 00 10 00 02 0B 13
- 15 01 00 00 10 00 02 0C 15
- 15 01 00 00 10 00 02 0D 15
- 15 01 00 00 10 00 02 0E 17
- 15 01 00 00 10 00 02 0F 17
- 15 01 00 00 10 00 02 10 1C
- 15 01 00 00 10 00 02 11 0B
- 15 01 00 00 10 00 02 12 0C
- 15 01 00 00 10 00 02 13 01
- 15 01 00 00 10 00 02 14 0F
- 15 01 00 00 10 00 02 15 10
- 15 01 00 00 10 00 02 16 10
- 15 01 00 00 10 00 02 17 10
- 15 01 00 00 10 00 02 18 89
- 15 01 00 00 10 00 02 19 8A
- 15 01 00 00 10 00 02 1A 13
- 15 01 00 00 10 00 02 1B 13
- 15 01 00 00 10 00 02 1C 15
- 15 01 00 00 10 00 02 1D 15
- 15 01 00 00 10 00 02 1E 17
- 15 01 00 00 10 00 02 1F 17
+ 15 01 00 00 00 00 02 ff 24
+ 15 01 00 00 00 00 02 fb 01
+ 15 01 00 00 00 00 02 00 1C
+ 15 01 00 00 00 00 02 01 0B
+ 15 01 00 00 00 00 02 02 0C
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0F
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8A
+ 15 01 00 00 00 00 02 0A 13
+ 15 01 00 00 00 00 02 0B 13
+ 15 01 00 00 00 00 02 0C 15
+ 15 01 00 00 00 00 02 0D 15
+ 15 01 00 00 00 00 02 0E 17
+ 15 01 00 00 00 00 02 0F 17
+ 15 01 00 00 00 00 02 10 1C
+ 15 01 00 00 00 00 02 11 0B
+ 15 01 00 00 00 00 02 12 0C
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0F
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8A
+ 15 01 00 00 00 00 02 1A 13
+ 15 01 00 00 00 00 02 1B 13
+ 15 01 00 00 00 00 02 1C 15
+ 15 01 00 00 00 00 02 1D 15
+ 15 01 00 00 00 00 02 1E 17
+ 15 01 00 00 00 00 02 1F 17
/* STV */
- 15 01 00 00 10 00 02 20 40
- 15 01 00 00 10 00 02 21 01
- 15 01 00 00 10 00 02 22 00
- 15 01 00 00 10 00 02 23 40
- 15 01 00 00 10 00 02 24 40
- 15 01 00 00 10 00 02 25 6D
- 15 01 00 00 10 00 02 26 40
- 15 01 00 00 10 00 02 27 40
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6D
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
/* Vend */
- 15 01 00 00 10 00 02 E0 00
- 15 01 00 00 10 00 02 DC 21
- 15 01 00 00 10 00 02 DD 22
- 15 01 00 00 10 00 02 DE 07
- 15 01 00 00 10 00 02 DF 07
- 15 01 00 00 10 00 02 E3 6D
- 15 01 00 00 10 00 02 E1 07
- 15 01 00 00 10 00 02 E2 07
+ 15 01 00 00 00 00 02 E0 00
+ 15 01 00 00 00 00 02 DC 21
+ 15 01 00 00 00 00 02 DD 22
+ 15 01 00 00 00 00 02 DE 07
+ 15 01 00 00 00 00 02 DF 07
+ 15 01 00 00 00 00 02 E3 6D
+ 15 01 00 00 00 00 02 E1 07
+ 15 01 00 00 00 00 02 E2 07
/* UD */
- 15 01 00 00 10 00 02 29 D8
- 15 01 00 00 10 00 02 2A 2A
+ 15 01 00 00 00 00 02 29 D8
+ 15 01 00 00 00 00 02 2A 2A
/* CLK */
- 15 01 00 00 10 00 02 4B 03
- 15 01 00 00 10 00 02 4C 11
- 15 01 00 00 10 00 02 4D 10
- 15 01 00 00 10 00 02 4E 01
- 15 01 00 00 10 00 02 4F 01
- 15 01 00 00 10 00 02 50 10
- 15 01 00 00 10 00 02 51 00
- 15 01 00 00 10 00 02 52 80
- 15 01 00 00 10 00 02 53 00
- 15 01 00 00 10 00 02 56 00
- 15 01 00 00 10 00 02 54 07
- 15 01 00 00 10 00 02 58 07
- 15 01 00 00 10 00 02 55 25
+ 15 01 00 00 00 00 02 4B 03
+ 15 01 00 00 00 00 02 4C 11
+ 15 01 00 00 00 00 02 4D 10
+ 15 01 00 00 00 00 02 4E 01
+ 15 01 00 00 00 00 02 4F 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
/* Reset XDONB */
- 15 01 00 00 10 00 02 5B 43
- 15 01 00 00 10 00 02 5C 00
- 15 01 00 00 10 00 02 5F 73
- 15 01 00 00 10 00 02 60 73
- 15 01 00 00 10 00 02 63 22
- 15 01 00 00 10 00 02 64 00
- 15 01 00 00 10 00 02 67 08
- 15 01 00 00 10 00 02 68 04
+ 15 01 00 00 00 00 02 5B 43
+ 15 01 00 00 00 00 02 5C 00
+ 15 01 00 00 00 00 02 5F 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
/* Resolution:1440x2560*/
- 15 01 00 00 10 00 02 72 02
+ 15 01 00 00 00 00 02 72 02
/* mux */
- 15 01 00 00 10 00 02 7A 80
- 15 01 00 00 10 00 02 7B 91
- 15 01 00 00 10 00 02 7C D8
- 15 01 00 00 10 00 02 7D 60
- 15 01 00 00 10 00 02 7F 15
- 15 01 00 00 10 00 02 75 15
+ 15 01 00 00 00 00 02 7A 80
+ 15 01 00 00 00 00 02 7B 91
+ 15 01 00 00 00 00 02 7C D8
+ 15 01 00 00 00 00 02 7D 60
+ 15 01 00 00 00 00 02 7F 15
+ 15 01 00 00 00 00 02 75 15
/* ABOFF */
- 15 01 00 00 10 00 02 B3 C0
- 15 01 00 00 10 00 02 B4 00
- 15 01 00 00 10 00 02 B5 00
+ 15 01 00 00 00 00 02 B3 C0
+ 15 01 00 00 00 00 02 B4 00
+ 15 01 00 00 00 00 02 B5 00
/* Source EQ */
- 15 01 00 00 10 00 02 78 00
- 15 01 00 00 10 00 02 79 00
- 15 01 00 00 10 00 02 80 00
- 15 01 00 00 10 00 02 83 00
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
/* FP BP */
- 15 01 00 00 10 00 02 93 0A
- 15 01 00 00 10 00 02 94 0A
+ 15 01 00 00 00 00 02 93 0A
+ 15 01 00 00 00 00 02 94 0A
/* Inversion Type */
- 15 01 00 00 10 00 02 8A 00
- 15 01 00 00 10 00 02 9B FF
+ 15 01 00 00 00 00 02 8A 00
+ 15 01 00 00 00 00 02 9B FF
/* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 10 00 02 9D B0
- 15 01 00 00 10 00 02 9F 63
- 15 01 00 00 10 00 02 98 10
+ 15 01 00 00 00 00 02 9D B0
+ 15 01 00 00 00 00 02 9F 63
+ 15 01 00 00 00 00 02 98 10
/* FRM */
- 15 01 00 00 10 00 02 EC 00
+ 15 01 00 00 00 00 02 EC 00
/* CMD1 */
- 15 01 00 00 10 00 02 ff 10
+ 15 01 00 00 00 00 02 ff 10
/* VBP+VSA=,VFP = 10H */
- 15 01 00 00 10 00 04 3B 03 0A 0A
+ 15 01 00 00 00 00 04 3B 03 0A 0A
/* FTE on */
- 15 01 00 00 10 00 02 35 00
+ 15 01 00 00 00 00 02 35 00
/* EN_BK =1(auto black) */
- 15 01 00 00 10 00 02 E5 01
+ 15 01 00 00 00 00 02 E5 01
/* CMD mode(10) VDO mode(03) */
- 15 01 00 00 10 00 02 BB 10
+ 15 01 00 00 00 00 02 BB 10
/* Non Reload MTP */
- 15 01 00 00 10 00 02 FB 01
+ 15 01 00 00 00 00 02 FB 01
/* SlpOut + DispOn */
- 05 01 00 00 a0 00 02 11 00
- 05 01 00 00 a0 00 02 29 00
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
];
qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
05 01 00 00 78 00 02 10 00];
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
index 752345283819..d179acd043ed 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
@@ -32,154 +32,154 @@
qcom,mdss-dsi-border-color = <0>;
qcom,mdss-dsi-on-command = [
/* CMD2_P0 */
- 15 01 00 00 10 00 02 FF 20
- 15 01 00 00 10 00 02 FB 01
- 15 01 00 00 10 00 02 00 01
- 15 01 00 00 10 00 02 01 55
- 15 01 00 00 10 00 02 02 45
- 15 01 00 00 10 00 02 05 40
- 15 01 00 00 10 00 02 06 19
- 15 01 00 00 10 00 02 07 1E
- 15 01 00 00 10 00 02 0B 73
- 15 01 00 00 10 00 02 0C 73
- 15 01 00 00 10 00 02 0E B0
- 15 01 00 00 10 00 02 0F AE
- 15 01 00 00 10 00 02 11 B8
- 15 01 00 00 10 00 02 13 00
- 15 01 00 00 10 00 02 58 80
- 15 01 00 00 10 00 02 59 01
- 15 01 00 00 10 00 02 5A 00
- 15 01 00 00 10 00 02 5B 01
- 15 01 00 00 10 00 02 5C 80
- 15 01 00 00 10 00 02 5D 81
- 15 01 00 00 10 00 02 5E 00
- 15 01 00 00 10 00 02 5F 01
- 15 01 00 00 10 00 02 72 31
- 15 01 00 00 10 00 02 68 03
+ 15 01 00 00 00 00 02 FF 20
+ 15 01 00 00 00 00 02 FB 01
+ 15 01 00 00 00 00 02 00 01
+ 15 01 00 00 00 00 02 01 55
+ 15 01 00 00 00 00 02 02 45
+ 15 01 00 00 00 00 02 05 40
+ 15 01 00 00 00 00 02 06 19
+ 15 01 00 00 00 00 02 07 1E
+ 15 01 00 00 00 00 02 0B 73
+ 15 01 00 00 00 00 02 0C 73
+ 15 01 00 00 00 00 02 0E B0
+ 15 01 00 00 00 00 02 0F AE
+ 15 01 00 00 00 00 02 11 B8
+ 15 01 00 00 00 00 02 13 00
+ 15 01 00 00 00 00 02 58 80
+ 15 01 00 00 00 00 02 59 01
+ 15 01 00 00 00 00 02 5A 00
+ 15 01 00 00 00 00 02 5B 01
+ 15 01 00 00 00 00 02 5C 80
+ 15 01 00 00 00 00 02 5D 81
+ 15 01 00 00 00 00 02 5E 00
+ 15 01 00 00 00 00 02 5F 01
+ 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
- 15 01 00 00 10 00 02 FF 24
- 15 01 00 00 10 00 02 FB 01
- 15 01 00 00 10 00 02 00 1C
- 15 01 00 00 10 00 02 01 0B
- 15 01 00 00 10 00 02 02 0C
- 15 01 00 00 10 00 02 03 01
- 15 01 00 00 10 00 02 04 0F
- 15 01 00 00 10 00 02 05 10
- 15 01 00 00 10 00 02 06 10
- 15 01 00 00 10 00 02 07 10
- 15 01 00 00 10 00 02 08 89
- 15 01 00 00 10 00 02 09 8A
- 15 01 00 00 10 00 02 0A 13
- 15 01 00 00 10 00 02 0B 13
- 15 01 00 00 10 00 02 0C 15
- 15 01 00 00 10 00 02 0D 15
- 15 01 00 00 10 00 02 0E 17
- 15 01 00 00 10 00 02 0F 17
- 15 01 00 00 10 00 02 10 1C
- 15 01 00 00 10 00 02 11 0B
- 15 01 00 00 10 00 02 12 0C
- 15 01 00 00 10 00 02 13 01
- 15 01 00 00 10 00 02 14 0F
- 15 01 00 00 10 00 02 15 10
- 15 01 00 00 10 00 02 16 10
- 15 01 00 00 10 00 02 17 10
- 15 01 00 00 10 00 02 18 89
- 15 01 00 00 10 00 02 19 8A
- 15 01 00 00 10 00 02 1A 13
- 15 01 00 00 10 00 02 1B 13
- 15 01 00 00 10 00 02 1C 15
- 15 01 00 00 10 00 02 1D 15
- 15 01 00 00 10 00 02 1E 17
- 15 01 00 00 10 00 02 1F 17
+ 15 01 00 00 00 00 02 FF 24
+ 15 01 00 00 00 00 02 FB 01
+ 15 01 00 00 00 00 02 00 1C
+ 15 01 00 00 00 00 02 01 0B
+ 15 01 00 00 00 00 02 02 0C
+ 15 01 00 00 00 00 02 03 01
+ 15 01 00 00 00 00 02 04 0F
+ 15 01 00 00 00 00 02 05 10
+ 15 01 00 00 00 00 02 06 10
+ 15 01 00 00 00 00 02 07 10
+ 15 01 00 00 00 00 02 08 89
+ 15 01 00 00 00 00 02 09 8A
+ 15 01 00 00 00 00 02 0A 13
+ 15 01 00 00 00 00 02 0B 13
+ 15 01 00 00 00 00 02 0C 15
+ 15 01 00 00 00 00 02 0D 15
+ 15 01 00 00 00 00 02 0E 17
+ 15 01 00 00 00 00 02 0F 17
+ 15 01 00 00 00 00 02 10 1C
+ 15 01 00 00 00 00 02 11 0B
+ 15 01 00 00 00 00 02 12 0C
+ 15 01 00 00 00 00 02 13 01
+ 15 01 00 00 00 00 02 14 0F
+ 15 01 00 00 00 00 02 15 10
+ 15 01 00 00 00 00 02 16 10
+ 15 01 00 00 00 00 02 17 10
+ 15 01 00 00 00 00 02 18 89
+ 15 01 00 00 00 00 02 19 8A
+ 15 01 00 00 00 00 02 1A 13
+ 15 01 00 00 00 00 02 1B 13
+ 15 01 00 00 00 00 02 1C 15
+ 15 01 00 00 00 00 02 1D 15
+ 15 01 00 00 00 00 02 1E 17
+ 15 01 00 00 00 00 02 1F 17
/* STV */
- 15 01 00 00 10 00 02 20 40
- 15 01 00 00 10 00 02 21 01
- 15 01 00 00 10 00 02 22 00
- 15 01 00 00 10 00 02 23 40
- 15 01 00 00 10 00 02 24 40
- 15 01 00 00 10 00 02 25 6D
- 15 01 00 00 10 00 02 26 40
- 15 01 00 00 10 00 02 27 40
+ 15 01 00 00 00 00 02 20 40
+ 15 01 00 00 00 00 02 21 01
+ 15 01 00 00 00 00 02 22 00
+ 15 01 00 00 00 00 02 23 40
+ 15 01 00 00 00 00 02 24 40
+ 15 01 00 00 00 00 02 25 6D
+ 15 01 00 00 00 00 02 26 40
+ 15 01 00 00 00 00 02 27 40
/* Vend */
- 15 01 00 00 10 00 02 E0 00
- 15 01 00 00 10 00 02 DC 21
- 15 01 00 00 10 00 02 DD 22
- 15 01 00 00 10 00 02 DE 07
- 15 01 00 00 10 00 02 DF 07
- 15 01 00 00 10 00 02 E3 6D
- 15 01 00 00 10 00 02 E1 07
- 15 01 00 00 10 00 02 E2 07
+ 15 01 00 00 00 00 02 E0 00
+ 15 01 00 00 00 00 02 DC 21
+ 15 01 00 00 00 00 02 DD 22
+ 15 01 00 00 00 00 02 DE 07
+ 15 01 00 00 00 00 02 DF 07
+ 15 01 00 00 00 00 02 E3 6D
+ 15 01 00 00 00 00 02 E1 07
+ 15 01 00 00 00 00 02 E2 07
/* UD */
- 15 01 00 00 10 00 02 29 D8
- 15 01 00 00 10 00 02 2A 2A
+ 15 01 00 00 00 00 02 29 D8
+ 15 01 00 00 00 00 02 2A 2A
/* CLK */
- 15 01 00 00 10 00 02 4B 03
- 15 01 00 00 10 00 02 4C 11
- 15 01 00 00 10 00 02 4D 10
- 15 01 00 00 10 00 02 4E 01
- 15 01 00 00 10 00 02 4F 01
- 15 01 00 00 10 00 02 50 10
- 15 01 00 00 10 00 02 51 00
- 15 01 00 00 10 00 02 52 80
- 15 01 00 00 10 00 02 53 00
- 15 01 00 00 10 00 02 56 00
- 15 01 00 00 10 00 02 54 07
- 15 01 00 00 10 00 02 58 07
- 15 01 00 00 10 00 02 55 25
+ 15 01 00 00 00 00 02 4B 03
+ 15 01 00 00 00 00 02 4C 11
+ 15 01 00 00 00 00 02 4D 10
+ 15 01 00 00 00 00 02 4E 01
+ 15 01 00 00 00 00 02 4F 01
+ 15 01 00 00 00 00 02 50 10
+ 15 01 00 00 00 00 02 51 00
+ 15 01 00 00 00 00 02 52 80
+ 15 01 00 00 00 00 02 53 00
+ 15 01 00 00 00 00 02 56 00
+ 15 01 00 00 00 00 02 54 07
+ 15 01 00 00 00 00 02 58 07
+ 15 01 00 00 00 00 02 55 25
/* Reset XDONB */
- 15 01 00 00 10 00 02 5B 43
- 15 01 00 00 10 00 02 5C 00
- 15 01 00 00 10 00 02 5F 73
- 15 01 00 00 10 00 02 60 73
- 15 01 00 00 10 00 02 63 22
- 15 01 00 00 10 00 02 64 00
- 15 01 00 00 10 00 02 67 08
- 15 01 00 00 10 00 02 68 04
+ 15 01 00 00 00 00 02 5B 43
+ 15 01 00 00 00 00 02 5C 00
+ 15 01 00 00 00 00 02 5F 73
+ 15 01 00 00 00 00 02 60 73
+ 15 01 00 00 00 00 02 63 22
+ 15 01 00 00 00 00 02 64 00
+ 15 01 00 00 00 00 02 67 08
+ 15 01 00 00 00 00 02 68 04
/* Resolution:1440x2560*/
- 15 01 00 00 10 00 02 72 02
+ 15 01 00 00 00 00 02 72 02
/* mux */
- 15 01 00 00 10 00 02 7A 80
- 15 01 00 00 10 00 02 7B 91
- 15 01 00 00 10 00 02 7C D8
- 15 01 00 00 10 00 02 7D 60
- 15 01 00 00 10 00 02 7F 15
- 15 01 00 00 10 00 02 75 15
+ 15 01 00 00 00 00 02 7A 80
+ 15 01 00 00 00 00 02 7B 91
+ 15 01 00 00 00 00 02 7C D8
+ 15 01 00 00 00 00 02 7D 60
+ 15 01 00 00 00 00 02 7F 15
+ 15 01 00 00 00 00 02 75 15
/* ABOFF */
- 15 01 00 00 10 00 02 B3 C0
- 15 01 00 00 10 00 02 B4 00
- 15 01 00 00 10 00 02 B5 00
+ 15 01 00 00 00 00 02 B3 C0
+ 15 01 00 00 00 00 02 B4 00
+ 15 01 00 00 00 00 02 B5 00
/* Source EQ */
- 15 01 00 00 10 00 02 78 00
- 15 01 00 00 10 00 02 79 00
- 15 01 00 00 10 00 02 80 00
- 15 01 00 00 10 00 02 83 00
+ 15 01 00 00 00 00 02 78 00
+ 15 01 00 00 00 00 02 79 00
+ 15 01 00 00 00 00 02 80 00
+ 15 01 00 00 00 00 02 83 00
/* FP BP */
- 15 01 00 00 10 00 02 93 0A
- 15 01 00 00 10 00 02 94 0A
+ 15 01 00 00 00 00 02 93 0A
+ 15 01 00 00 00 00 02 94 0A
/* Inversion Type */
- 15 01 00 00 10 00 02 8A 00
- 15 01 00 00 10 00 02 9B FF
+ 15 01 00 00 00 00 02 8A 00
+ 15 01 00 00 00 00 02 9B FF
/* IMGSWAP =1 @PortSwap=1 */
- 15 01 00 00 10 00 02 9D B0
- 15 01 00 00 10 00 02 9F 63
- 15 01 00 00 10 00 02 98 10
+ 15 01 00 00 00 00 02 9D B0
+ 15 01 00 00 00 00 02 9F 63
+ 15 01 00 00 00 00 02 98 10
/* FRM */
- 15 01 00 00 10 00 02 EC 00
+ 15 01 00 00 00 00 02 EC 00
/* CMD1 */
- 15 01 00 00 10 00 02 FF 10
+ 15 01 00 00 00 00 02 FF 10
/* VBP+VSA=,VFP = 10H */
- 15 01 00 00 10 00 04 3B 03 0A 0A
+ 15 01 00 00 00 00 04 3B 03 0A 0A
/* FTE on */
- 15 01 00 00 10 00 02 35 00
+ 15 01 00 00 00 00 02 35 00
/* EN_BK =1(auto black) */
- 15 01 00 00 10 00 02 E5 01
+ 15 01 00 00 00 00 02 E5 01
/* CMD mode(10) VDO mode(03) */
- 15 01 00 00 10 00 02 BB 03
+ 15 01 00 00 00 00 02 BB 03
/* Non Reload MTP */
- 15 01 00 00 10 00 02 FB 01
+ 15 01 00 00 00 00 02 FB 01
/* SlpOut + DispOn */
- 05 01 00 00 a0 00 02 11 00
- 05 01 00 00 a0 00 02 29 00
+ 05 01 00 00 78 00 02 11 00
+ 05 01 00 00 78 00 02 29 00
];
qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00
05 01 00 00 78 00 02 10 00];
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi
index 3c0134b665fc..e3f60de3c3eb 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi
@@ -20,13 +20,13 @@
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <1080>;
qcom,mdss-dsi-panel-height = <1920>;
- qcom,mdss-dsi-h-front-porch = <96>;
- qcom,mdss-dsi-h-back-porch = <64>;
- qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-front-porch = <120>;
+ qcom,mdss-dsi-h-back-porch = <60>;
+ qcom,mdss-dsi-h-pulse-width = <12>;
qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <16>;
- qcom,mdss-dsi-v-front-porch = <4>;
- qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-v-back-porch = <2>;
+ qcom,mdss-dsi-v-front-porch = <12>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi
index d6b24f4e54d2..068459bf2504 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi
@@ -20,13 +20,13 @@
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <1080>;
qcom,mdss-dsi-panel-height = <1920>;
- qcom,mdss-dsi-h-front-porch = <96>;
- qcom,mdss-dsi-h-back-porch = <64>;
- qcom,mdss-dsi-h-pulse-width = <16>;
+ qcom,mdss-dsi-h-front-porch = <120>;
+ qcom,mdss-dsi-h-back-porch = <60>;
+ qcom,mdss-dsi-h-pulse-width = <12>;
qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <16>;
- qcom,mdss-dsi-v-front-porch = <4>;
- qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-v-back-porch = <2>;
+ qcom,mdss-dsi-v-front-porch = <12>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
qcom,mdss-dsi-h-left-border = <0>;
qcom,mdss-dsi-h-right-border = <0>;
qcom,mdss-dsi-v-top-border = <0>;
@@ -169,8 +169,7 @@
15 01 00 00 00 00 02 e3 00
15 01 00 00 00 00 02 ec 00
15 01 00 00 00 00 02 ff 10
- 15 01 00 00 00 00 02 bb 10
- 15 01 00 00 00 00 02 35 02
+ 15 01 00 00 00 00 02 bb 03
05 01 00 00 78 00 02 11 00
05 01 00 00 78 00 02 29 00];
qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00
diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi
index fc0e828eb2bc..a8a174300c7e 100644
--- a/arch/arm/boot/dts/qcom/msm-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi
@@ -696,6 +696,7 @@
qcom,auxpcm-audio-intf;
qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
qcom,audio-routing =
+ "AIF4 VI", "MCLK",
"RX_BIAS", "MCLK",
"MADINPUT", "MCLK",
"AMIC2", "MIC BIAS2",
diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index 1154c28bb9ea..131ad649ef8b 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -23,6 +23,7 @@
pm660_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
reg = <0x100 0x100>;
+ qcom,fab-id-valid;
};
qcom,power-on@800 {
@@ -606,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 2aa730898f75..8edc1fc61830 100644
--- a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
@@ -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
@@ -96,16 +96,30 @@
#size-cells = <1>;
interrupt-parent = <&smb138x>;
io-channels = <&smb138x_tadc 2>,
- <&smb138x_tadc 12>,
- <&smb138x_tadc 3>;
+ <&smb138x_tadc 3>,
+ <&smb138x_tadc 14>,
+ <&smb138x_tadc 15>,
+ <&smb138x_tadc 16>,
+ <&smb138x_tadc 17>;
io-channel-names = "charger_temp",
- "charger_temp_max",
- "batt_i";
+ "batt_i",
+ "connector_temp_thr1",
+ "connector_temp_thr2",
+ "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>;
- interrupt-names = "wdog-bark";
+ interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog-bark",
+ "temperature-change";
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
index 4e7b3d4ee65d..ac1e37fa1d63 100644
--- a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
@@ -31,7 +31,7 @@
qcom,clk-div = <27>;
};
- sound-9335 {
+ snd_9335: sound-9335 {
compatible = "qcom,msm8998-asoc-snd-tasha";
qcom,model = "msm8998-tasha-snd-card";
qcom,ext-disp-audio-rx;
@@ -183,6 +183,7 @@
"lpaif_quat_mode_muxsel";
qcom,audio-routing =
+ "AIF4 VI", "MCLK",
"RX_BIAS", "MCLK",
"MADINPUT", "MCLK",
"hifi amp", "LINEOUT1",
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
index c35ea886408d..e0ba982d7932 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
@@ -408,10 +408,22 @@
qcom,clock-rates = <0 0 0 0 200000000 200000000 0 0 0 0 0>;
qcom,min-clock-rate = <200000000>;
qcom,bus-master = <1>;
- qcom,vbif-qos-setting = <0x20 0x10000000>,
- <0x24 0x10000000>,
- <0x28 0x10000000>,
- <0x2C 0x10000000>;
+ qcom,vbif-qos-setting = <0x550 0x33333333>,
+ <0x554 0x03333333>,
+ <0x558 0x33333333>,
+ <0x55c 0x03333333>,
+ <0x560 0x33333333>,
+ <0x564 0x03333333>,
+ <0x568 0x33333333>,
+ <0x56c 0x03333333>,
+ <0x570 0x33333333>,
+ <0x574 0x03333333>,
+ <0x578 0x33333333>,
+ <0x57c 0x03333333>,
+ <0x580 0x33333333>,
+ <0x584 0x03333333>,
+ <0x588 0x33333333>,
+ <0x58c 0x03333333>;
status = "ok";
qcom,msm-bus,name = "msm_camera_cpp";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
index f91b29bca493..48415eb81406 100644
--- a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
@@ -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
@@ -512,6 +512,10 @@
status = "ok";
};
+&snd_9335 {
+ qcom,mbhc-audio-jack-type = "6-pole-jack";
+};
+
&soc {
gpio_keys {
compatible = "gpio-keys";
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-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
index 4aadd4802b51..dd10c3b1ea96 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
@@ -171,6 +171,19 @@
};
};
+&pmi8998_gpios {
+ /* GPIO 6 for the internal QNOVO discharge FET control signal */
+ gpio@c500 {
+ status = "okay";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,out-strength = <1>;
+ qcom,master-en = <1>;
+ };
+};
+
&i2c_5 {
status = "okay";
synaptics@20 {
@@ -521,6 +534,10 @@
status = "ok";
};
+&snd_9335 {
+ qcom,mbhc-audio-jack-type = "6-pole-jack";
+};
+
&soc {
gpio_keys {
compatible = "gpio-keys";
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
index 25e381c2cb18..3c1c49edcc82 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
@@ -143,6 +143,19 @@
};
};
+&pmi8998_gpios {
+ /* GPIO 6 for the internal QNOVO discharge FET control signal */
+ gpio@c500 {
+ status = "okay";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,out-strength = <1>;
+ qcom,master-en = <1>;
+ };
+};
+
&soc {
gpio_keys {
compatible = "gpio-keys";
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
index fb69a793a680..d67d23b79d36 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
@@ -159,6 +159,19 @@
};
};
+&pmi8998_gpios {
+ /* GPIO 6 for the internal QNOVO discharge FET control signal */
+ gpio@c500 {
+ status = "okay";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,out-strength = <1>;
+ qcom,master-en = <1>;
+ };
+};
+
&i2c_5 {
status = "okay";
synaptics@20 {
@@ -289,6 +302,7 @@
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-panel-orientation = "180";
};
&dsi_dual_nt35597_truly_cmd {
@@ -297,6 +311,7 @@
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-panel-orientation = "180";
};
&dsi_nt35597_dsc_video {
@@ -320,6 +335,7 @@
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-panel-orientation = "180";
};
&dsi_sharp_4k_dsc_cmd {
@@ -327,6 +343,7 @@
qcom,mdss-dsi-bl-min-level = <1>;
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-panel-orientation = "180";
};
&dsi_dual_jdi_video {
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index 2e41f3a3567d..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>;
};
@@ -2186,6 +2186,7 @@
qcom,sensor-type = "tsens";
qcom,sensor-name = "tsens_tz_sensor12";
qcom,scaling-factor = <10>;
+ qcom,alias-name = "gpu_1";
};
sensor_information13: qcom,sensor-information-13 {
qcom,sensor-type = "tsens";
@@ -3041,7 +3042,7 @@
};
- msm_ath10k_wlan: qcom,msm_ath10k_wlan@18000000 {
+ msm_ath10k_wlan: qcom,msm_ath10k_wlan {
status = "disabled";
compatible = "qcom,wcn3990-wifi";
interrupts =
diff --git a/arch/arm/boot/dts/qcom/sda630-cdp.dts b/arch/arm/boot/dts/qcom/sda630-cdp.dts
index 8db5a9e76126..665fa94d9713 100644
--- a/arch/arm/boot/dts/qcom/sda630-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sda630-cdp.dts
@@ -15,6 +15,7 @@
#include "sda630.dtsi"
#include "sdm630-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660L CDP";
@@ -23,3 +24,13 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda630-mtp.dts b/arch/arm/boot/dts/qcom/sda630-mtp.dts
index 5c4372600ad7..08a996ddb709 100644
--- a/arch/arm/boot/dts/qcom/sda630-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sda630-mtp.dts
@@ -15,6 +15,7 @@
#include "sda630.dtsi"
#include "sdm630-mtp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660L MTP";
@@ -23,3 +24,7 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts
index 9afa16ff920d..6094d22c1c92 100644
--- a/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sda630-pm660a-cdp.dts
@@ -16,6 +16,7 @@
#include "sda630.dtsi"
#include "sdm630-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660A CDP";
@@ -23,3 +24,13 @@
qcom,board-id = <1 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts
index 8bfd54e46e72..49c10129aada 100644
--- a/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sda630-pm660a-mtp.dts
@@ -16,6 +16,7 @@
#include "sda630.dtsi"
#include "sdm630-mtp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660A MTP";
@@ -23,3 +24,7 @@
qcom,board-id = <8 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda630-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sda630-pm660a-rcm.dts
index 04f2c3726a05..aed97f122407 100644
--- a/arch/arm/boot/dts/qcom/sda630-pm660a-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sda630-pm660a-rcm.dts
@@ -16,6 +16,7 @@
#include "sda630.dtsi"
#include "sdm630-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 630 PM660 + PM660A RCM";
@@ -23,3 +24,13 @@
qcom,board-id = <21 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda630-rcm.dts b/arch/arm/boot/dts/qcom/sda630-rcm.dts
index 4a2ed2624a0d..5bc031a56c38 100644
--- a/arch/arm/boot/dts/qcom/sda630-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sda630-rcm.dts
@@ -23,3 +23,13 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda660-cdp.dts b/arch/arm/boot/dts/qcom/sda660-cdp.dts
index 43e43f7f7125..92097729087b 100644
--- a/arch/arm/boot/dts/qcom/sda660-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sda660-cdp.dts
@@ -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
@@ -15,6 +15,7 @@
#include "sda660.dtsi"
#include "sdm660-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660L CDP";
@@ -23,3 +24,13 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda660-mtp.dts b/arch/arm/boot/dts/qcom/sda660-mtp.dts
index 0e14f3df9d8b..027137e54c0e 100644
--- a/arch/arm/boot/dts/qcom/sda660-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sda660-mtp.dts
@@ -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
@@ -15,6 +15,7 @@
#include "sda660.dtsi"
#include "sdm660-mtp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660L MTP";
@@ -23,3 +24,7 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts
index bfccd541e4b6..a46083a00298 100644
--- a/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sda660-pm660a-cdp.dts
@@ -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
@@ -16,6 +16,7 @@
#include "sda660.dtsi"
#include "sdm660-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A CDP";
@@ -23,3 +24,13 @@
qcom,board-id = <1 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts
index 1b7cfe1e1077..d94cf8ea1eb5 100644
--- a/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sda660-pm660a-mtp.dts
@@ -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
@@ -16,6 +16,7 @@
#include "sda660.dtsi"
#include "sdm660-mtp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A MTP";
@@ -23,3 +24,7 @@
qcom,board-id = <8 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda660-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sda660-pm660a-rcm.dts
index aa7a890fbe39..7172d00c1a1e 100644
--- a/arch/arm/boot/dts/qcom/sda660-pm660a-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sda660-pm660a-rcm.dts
@@ -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
@@ -16,6 +16,7 @@
#include "sda660.dtsi"
#include "sdm660-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A RCM";
@@ -23,3 +24,13 @@
qcom,board-id = <21 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda660-rcm.dts b/arch/arm/boot/dts/qcom/sda660-rcm.dts
index 73ea188c5221..1a790466d9a9 100644
--- a/arch/arm/boot/dts/qcom/sda660-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sda660-rcm.dts
@@ -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
@@ -15,6 +15,7 @@
#include "sda660.dtsi"
#include "sdm660-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660L RCM";
@@ -23,3 +24,13 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-cdp.dts
index 9ad4322f2af0..973df0df3be5 100644
--- a/arch/arm/boot/dts/qcom/sdm630-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dts
@@ -15,6 +15,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L CDP";
@@ -23,3 +24,13 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
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-internal-codec-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-cdp.dts
index c15abc5ffa39..baa55fa15160 100644
--- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-cdp.dts
@@ -15,6 +15,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
+#include "sdm660-internal-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L Int. Audio Codec CDP";
diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts
index 0e180392e9de..b469a59d7818 100644
--- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-mtp.dts
@@ -15,6 +15,7 @@
#include "sdm630.dtsi"
#include "sdm630-mtp.dtsi"
+#include "sdm660-internal-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L Int. Audio Codec MTP";
@@ -23,3 +24,7 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&int_codec {
+ qcom,model = "sdm660-snd-card-mtp";
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts
index fc4c216b2b57..c4e71835b701 100644
--- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-cdp.dts
@@ -16,6 +16,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-internal-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A Int. Audio Codec CDP";
diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts
index aab0eda3448b..e11cdfbed668 100644
--- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-mtp.dts
@@ -16,6 +16,7 @@
#include "sdm630.dtsi"
#include "sdm630-mtp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-internal-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A Int. Audio Codec MTP";
@@ -23,3 +24,7 @@
qcom,board-id = <8 1>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&int_codec {
+ qcom,model = "sdm660-snd-card-mtp";
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-rcm.dts
index f6e2d180ccb6..4cb49ce12969 100644
--- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-pm660a-rcm.dts
@@ -16,6 +16,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-internal-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A Int. Audio Codec RCM";
diff --git a/arch/arm/boot/dts/qcom/sdm630-internal-codec-rcm.dts b/arch/arm/boot/dts/qcom/sdm630-internal-codec-rcm.dts
index a6d318cea8e0..ee03652c394d 100644
--- a/arch/arm/boot/dts/qcom/sdm630-internal-codec-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-internal-codec-rcm.dts
@@ -15,6 +15,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
+#include "sdm660-internal-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L Int. Audio Codec RCM";
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.dts b/arch/arm/boot/dts/qcom/sdm630-mtp.dts
index 4933fcb8fce3..b1a9bb86149d 100644
--- a/arch/arm/boot/dts/qcom/sdm630-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dts
@@ -15,6 +15,7 @@
#include "sdm630.dtsi"
#include "sdm630-mtp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L MTP";
@@ -23,3 +24,7 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
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-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts
index 478f3acde81e..d9b6a8ae9d34 100644
--- a/arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-cdp.dts
@@ -16,6 +16,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A CDP";
@@ -23,3 +24,13 @@
qcom,board-id = <1 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts
index 3da1116c4352..8ebdbc08a00c 100644
--- a/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-mtp.dts
@@ -16,6 +16,7 @@
#include "sdm630.dtsi"
#include "sdm630-mtp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A MTP";
@@ -23,3 +24,7 @@
qcom,board-id = <8 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-rcm.dts
index 49938fa254cb..4bdbbbe26380 100644
--- a/arch/arm/boot/dts/qcom/sdm630-pm660a-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-rcm.dts
@@ -16,6 +16,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A RCM";
@@ -23,3 +24,13 @@
qcom,board-id = <21 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
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-rcm.dts b/arch/arm/boot/dts/qcom/sdm630-rcm.dts
index 79b3f8edfcc2..1de2a4dead6f 100644
--- a/arch/arm/boot/dts/qcom/sdm630-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-rcm.dts
@@ -15,6 +15,7 @@
#include "sdm630.dtsi"
#include "sdm630-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L RCM";
@@ -23,3 +24,13 @@
qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
index 73735159101d..13cf99ef0b40 100644
--- a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
@@ -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
@@ -10,6 +10,11 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/clock/qcom,gcc-sdm660.h>
+#include <dt-bindings/clock/qcom,gpu-sdm660.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
&rpm_bus {
rpm-regulator-smpa4 {
status = "okay";
@@ -488,10 +493,347 @@
/* Stub regulators */
/ {
/* GFX Supply */
- gfx_vreg_corner: regulator-gfx-corner {
+ gfx_stub_vreg: regulator-gfx-stub {
compatible = "qcom,stub-regulator";
- regulator-name = "gfx_corner";
+ regulator-name = "gfx_stub_corner";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1070000>;
+ };
+};
+
+&soc {
+ /* MEM ACC regulators */
+ gfx_mem_acc_vreg: regulator@01fcf004 {
+ compatible = "qcom,mem-acc-regulator";
+ reg = <0x01fcf004 0x4>;
+ reg-names = "acc-sel-l1";
+ regulator-name = "gfx_mem_acc_corner";
regulator-min-microvolt = <1>;
- regulator-max-microvolt = <7>;
+ regulator-max-microvolt = <2>;
+
+ qcom,corner-acc-map = <0x1 0x0>;
+ qcom,acc-sel-l1-bit-pos = <0>;
+ qcom,acc-sel-l1-bit-size = <1>;
+ };
+
+ gfx_ldo_vreg: ldo@0506e000 {
+ compatible = "qcom,sdm660-gfx-ldo";
+ reg = <0x0506e000 0x34>;
+ reg-names = "ldo_addr";
+ regulator-name = "msm_gfx_ldo";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <925000>;
+ };
+
+/* CPR controller regulators */
+ /* MMSS CPR Controller node */
+ gfx_cpr: cpr4-ctrl@05061000 {
+ compatible = "qcom,cpr4-sdm660-mmss-ldo-regulator";
+ reg = <0x05061000 0x4000>, <0x00784000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base";
+ clocks = <&clock_gpu GPUCC_RBCPR_CLK>,
+ <&clock_rpmcc RPM_CNOC_CLK>;
+ clock-names = "core_clk", "bus_clk";
+ interrupts = <GIC_SPI 285 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "cpr";
+ qcom,cpr-ctrl-name = "gfx";
+
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ 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>;
+
+ vdd-supply = <&gfx_stub_vreg>;
+ mem-acc-supply = <&gfx_mem_acc_vreg>;
+ system-supply = <&pm660l_s3_level>; /* vdd_cx */
+ qcom,voltage-step = <5000>;
+ vdd-thread0-ldo-supply = <&gfx_ldo_vreg>;
+
+ 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>;
+
+ gfx_vreg_corner: regulator {
+ regulator-name = "gfx_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+
+ qcom,cpr-fuse-corners = <6>;
+ qcom,cpr-fuse-combos = <8>;
+ qcom,cpr-corners = <7>;
+
+ qcom,cpr-corner-fmax-map = <1 2 3 4 5 6>;
+
+ qcom,cpr-voltage-ceiling =
+ <585000 645000 725000 790000
+ 870000 925000 1070000>;
+ qcom,cpr-voltage-floor =
+ <504000 504000 596000 652000
+ 712000 744000 1070000>;
+
+ qcom,mem-acc-voltage = <1 1 1 2 2 2 2>;
+ qcom,system-voltage =
+ <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+ qcom,corner-frequencies =
+ <160000000 240000000 370000000
+ 465000000 588000000 647000000
+ 775000000>;
+
+ qcom,cpr-target-quotients =
+ <0 0 0 0 0 0 174 167
+ 294 292 303 313 0 0 0 0>,
+ <0 0 0 0 0 0 263 247
+ 413 397 415 412 0 0 0 0>,
+ <0 0 0 0 0 0 375 354
+ 554 519 573 554 0 0 0 0>,
+ <0 0 0 0 0 0 412 380
+ 597 562 612 591 0 0 0 0>,
+ <0 0 0 0 0 0 513 476
+ 722 680 738 718 0 0 0 0>,
+ <0 0 0 0 0 0 595 553
+ 811 768 837 811 0 0 0 0>,
+ <0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0>;
+
+ qcom,cpr-ro-scaling-factor =
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>;
+
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+ qcom,cpr-corner-allow-ldo-mode =
+ <0 0 0 0 0 0 0>;
+ qcom,cpr-corner-allow-closed-loop =
+ <0 0 0 0 0 0 0>;
+ };
+ };
+ };
+
+ /* 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 38bb266bcf7d..206628149f7d 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -15,6 +15,7 @@
#include <dt-bindings/clock/qcom,gpu-sdm660.h>
#include <dt-bindings/clock/qcom,mmcc-sdm660.h>
#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/clock/audio-ext-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
#include <dt-bindings/clock/qcom,cpu-osm.h>
@@ -68,6 +69,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_100: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU1: cpu@101 {
@@ -87,6 +91,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_101: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU2: cpu@102 {
@@ -106,6 +113,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_102: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU3: cpu@103 {
@@ -125,6 +135,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_103: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU4: cpu@0 {
@@ -150,6 +163,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_0: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU5: cpu@1 {
@@ -169,6 +185,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_1: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU6: cpu@2 {
@@ -188,6 +207,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_2: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU7: cpu@3 {
@@ -207,6 +229,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_3: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
cpu-map {
@@ -320,6 +345,36 @@
alignment = <0x0 0x400000>;
size = <0x0 0x5c00000>;
};
+
+ /* global autoconfigured region for contiguous allocations */
+ linux,cma {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>;
+ reusable;
+ alignment = <0x0 0x400000>;
+ size = <0x0 0x2000000>;
+ linux,cma-default;
+ };
+
+ };
+
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-core-supply = <&pm660_l9_pin_ctrl>;
+ qca,bt-vdd-pa-supply = <&pm660_l6_pin_ctrl>;
+ qca,bt-vdd-ldo-supply = <&pm660_l19_pin_ctrl>;
+ qca,bt-chip-pwd-supply = <&pm660l_bob_pin1>;
+ clocks = <&clock_rpmcc RPM_RF_CLK1_PIN>;
+ clock-names = "rf_clk1";
+
+ qca,bt-vdd-core-voltage-level = <1800000 1900000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1370000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3400000>;
+ qca,bt-chip-pwd-voltage-level = <3600000 3600000>;
+
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
};
};
@@ -444,6 +499,38 @@
qcom,dump-node = <&L1_D_103>;
qcom,dump-id = <0x87>;
};
+ qcom,l1_tlb_dump0 {
+ qcom,dump-node = <&L1_TLB_0>;
+ qcom,dump-id = <0x20>;
+ };
+ qcom,l1_tlb_dump1 {
+ qcom,dump-node = <&L1_TLB_1>;
+ qcom,dump-id = <0x21>;
+ };
+ qcom,l1_tlb_dump2 {
+ qcom,dump-node = <&L1_TLB_2>;
+ qcom,dump-id = <0x22>;
+ };
+ qcom,l1_tlb_dump3 {
+ qcom,dump-node = <&L1_TLB_3>;
+ qcom,dump-id = <0x23>;
+ };
+ qcom,l1_tlb_dump100 {
+ qcom,dump-node = <&L1_TLB_100>;
+ qcom,dump-id = <0x24>;
+ };
+ qcom,l1_tlb_dump101 {
+ qcom,dump-node = <&L1_TLB_101>;
+ qcom,dump-id = <0x25>;
+ };
+ qcom,l1_tlb_dump102 {
+ qcom,dump-node = <&L1_TLB_102>;
+ qcom,dump-id = <0x26>;
+ };
+ qcom,l1_tlb_dump103 {
+ qcom,dump-node = <&L1_TLB_103>;
+ qcom,dump-id = <0x27>;
+ };
};
qcom,sps {
@@ -607,7 +694,7 @@
};
mitigation_profile4: qcom,limit_info-4 {
- qcom,temperature-sensor = <&sensor_information1>;
+ qcom,temperature-sensor = <&sensor_information7>;
qcom,hotplug-mitigation-enable;
};
@@ -625,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>;
@@ -766,7 +854,14 @@
interrupts = <0 291 0>, <0 292 0>;
interrupt-names = "slimbus_irq", "slimbus_bam_irq";
qcom,apps-ch-pipes = <0x1800>;
- status = "disabled";
+
+ /* Slimbus Slave DT for WCN3990 */
+ btfmslim_codec: wcn3990 {
+ compatible = "qcom,btfmslim_slave";
+ elemental-addr = [00 01 20 02 17 02];
+ qcom,btfm-slim-ifd = "btfmslim_slave_ifd";
+ qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02];
+ };
};
timer@17920000 {
@@ -867,7 +962,14 @@
#reset-cells = <1>;
};
- clock_gfx: clock-controller@5065000 {
+ clock_gpu: clock-controller@5065000 {
+ compatible = "qcom,gpu-sdm660";
+ reg = <0x5065000 0x10000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_gfx: gfx@5065000 {
compatible = "qcom,gpucc-sdm630";
reg = <0x5065000 0x10000>;
vdd_dig_gfx-supply = <&pm660l_s3_level>;
@@ -916,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>;
@@ -1010,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 =
@@ -1021,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 =
@@ -1033,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 =
@@ -1045,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 >;
@@ -1145,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>;
@@ -1357,6 +1611,7 @@
<0 424 0>, /* CE10 */
<0 425 0>; /* CE11 */
qcom,wlan-msa-memory = <0x100000>;
+ qcom,smmu-s1-bypass;
};
qcom,lpass@15700000 {
@@ -1808,9 +2063,14 @@
#include "msm-gdsc-660.dtsi"
#include "sdm660-common.dtsi"
#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";
@@ -1882,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-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi
index de2a44640972..16127bfccf35 100644
--- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi
@@ -54,8 +54,8 @@
"csiphy_timer_src_clk", "csiphy_timer_clk",
"camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk",
"csiphy_ahb2crif";
- qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
- 0 384000000 0 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0
+ 0 200000000 0 0>;
status = "ok";
};
@@ -92,8 +92,8 @@
"csiphy_timer_src_clk", "csiphy_timer_clk",
"camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk",
"csiphy_ahb2crif";
- qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
- 0 384000000 0 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0
+ 0 200000000 0 0>;
status = "ok";
};
@@ -130,8 +130,8 @@
"csiphy_timer_src_clk", "csiphy_timer_clk",
"camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk",
"csiphy_ahb2crif";
- qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
- 0 384000000 0 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0
+ 0 200000000 0 0>;
status = "ok";
};
@@ -171,7 +171,7 @@
"ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
"csi_clk", "csi_ahb_clk", "csi_rdi_clk",
"csi_pix_clk", "cphy_csid_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000
0 0 0 0 0>;
status = "ok";
};
@@ -212,7 +212,7 @@
"ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
"csi_clk", "csi_ahb_clk", "csi_rdi_clk",
"csi_pix_clk", "cphy_csid_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000
+ qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000
0 0 0 0 0>;
status = "ok";
};
@@ -253,7 +253,7 @@
"ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
"csi_clk", "csi_ahb_clk", "csi_rdi_clk",
"csi_pix_clk", "cphy_csid_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000
+ qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000
0 0 0 0 0>;
status = "ok";
};
@@ -294,7 +294,7 @@
"ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src",
"csi_clk", "csi_ahb_clk", "csi_rdi_clk",
"csi_pix_clk", "cphy_csid_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 256000000 256000000
+ qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000
0 0 0 0 0>;
status = "ok";
};
@@ -367,6 +367,22 @@
qcom,clock-rates = <0 0 0 0 200000000 200000000 0 0 0 0 0>;
qcom,min-clock-rate = <200000000>;
qcom,bus-master = <1>;
+ qcom,vbif-qos-setting = <0x550 0x55555555>,
+ <0x554 0x55555555>,
+ <0x558 0x55555555>,
+ <0x55c 0x55555555>,
+ <0x560 0x55555555>,
+ <0x564 0x55555555>,
+ <0x568 0x55555555>,
+ <0x56c 0x55555555>,
+ <0x570 0x55555555>,
+ <0x574 0x55555555>,
+ <0x578 0x55555555>,
+ <0x57c 0x55555555>,
+ <0x580 0x55555555>,
+ <0x584 0x55555555>,
+ <0x588 0x55555555>,
+ <0x58c 0x55555555>;
status = "ok";
qcom,msm-bus,name = "msm_camera_cpp";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi
index 5bdca492fee2..1145bfa63cba 100644
--- a/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-cdp.dtsi
@@ -184,6 +184,15 @@
qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
};
+&mdss_dp_ctrl {
+ pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+ pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>;
+ pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>;
+ qcom,aux-en-gpio = <&tlmm 55 0>;
+ qcom,aux-sel-gpio = <&tlmm 56 0>;
+ qcom,usbplug-cc-gpio = <&tlmm 58 0>;
+};
+
&sdhc_1 {
/* device core power supply */
vdd-supply = <&pm660l_l4>;
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 b0002dddf419..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>;
@@ -626,7 +627,7 @@
qcom,cti-gpio-trigout = <4>;
pinctrl-names = "cti-trigout-pctrl";
- pinctrl-0 = <&trigout_b>;
+ pinctrl-0 = <&trigout_a>;
};
cti3: cti@6013000 {
diff --git a/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts
new file mode 100644
index 000000000000..48cfefb4cdd0
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-cdp.dts
@@ -0,0 +1,26 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm660.dtsi"
+#include "sdm660-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, Headset Jacktype NO, CDP";
+ compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-rcm.dts b/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-rcm.dts
new file mode 100644
index 000000000000..aad1d7bd6aec
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm660-headset-jacktype-no-rcm.dts
@@ -0,0 +1,26 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm660.dtsi"
+#include "sdm660-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, Headset Jacktype NO, RCM";
+ compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp";
+ qcom,board-id = <21 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi
index 51e88eb8dcf2..2f71f2407891 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi
@@ -133,6 +133,10 @@
23 18 07 08 04 03 04 a0];
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-min-refresh-rate = <53>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_dual_nt35597_truly_cmd {
@@ -159,6 +163,10 @@
23 20 06 09 05 03 04 a0
23 20 06 09 05 03 04 a0
23 2e 06 08 05 03 04 a0];
+ qcom,mdss-dsi-min-refresh-rate = <53>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_nt35597_truly_dsc_video {
@@ -168,6 +176,10 @@
20 1d 05 07 03 03 04 a0
20 12 05 06 03 13 04 a0];
qcom,config-select = <&dsi_nt35597_truly_dsc_video_config2>;
+ qcom,mdss-dsi-min-refresh-rate = <53>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_nt35597_truly_dsc_cmd {
@@ -185,6 +197,10 @@
23 1e 07 08 05 03 04 a0
23 1e 07 08 05 03 04 a0
23 18 07 08 04 03 04 a0];
+ qcom,mdss-dsi-min-refresh-rate = <53>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_dual_nt35597_cmd {
@@ -196,19 +212,23 @@
};
&dsi_nt35695b_truly_fhd_video {
- qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 18 07 08 04 03 04 a0];
+ 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];
+ qcom,mdss-dsi-min-refresh-rate = <48>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_nt35695b_truly_fhd_cmd {
- qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 18 07 08 04 03 04 a0];
+ 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_truly_1080_vid {
@@ -217,6 +237,10 @@
23 1e 08 09 05 03 04 a0
23 1e 08 09 05 03 04 a0
23 1a 08 09 05 03 04 a0];
+ qcom,mdss-dsi-min-refresh-rate = <48>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_truly_1080_cmd {
diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi
index d2134c56541e..69d3736d4ba8 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi
@@ -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
@@ -79,4 +79,39 @@
};
};
};
+
+ mdss_dp_pll: qcom,mdss_dp_pll@c011000 {
+ compatible = "qcom,mdss_dp_pll_sdm660";
+ status = "ok";
+ label = "MDSS DP PLL";
+ cell-index = <0>;
+ #clock-cells = <1>;
+
+ reg = <0xc011c00 0x190>,
+ <0xc011000 0x910>,
+ <0x0c8c2300 0x8>;
+ reg-names = "pll_base", "phy_base", "gdsc_base";
+
+ gdsc-supply = <&gdsc_mdss>;
+
+ clocks = <&clock_mmss MMSS_MDSS_AHB_CLK>,
+ <&clock_rpmcc RPM_LN_BB_CLK1>,
+ <&clock_gcc GCC_USB3_CLKREF_CLK>;
+ clock-names = "iface_clk", "ref_clk_src", "ref_clk";
+ clock-rate = <0>;
+
+ 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/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
index 32cf55a99ac0..7f82a00e9f19 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
@@ -437,7 +437,7 @@
};
msm_ext_disp: qcom,msm_ext_disp {
- status = "disabled";
+ status = "ok";
compatible = "qcom,msm-ext-disp";
ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
@@ -447,16 +447,16 @@
};
mdss_dp_ctrl: qcom,dp_ctrl@c990000 {
- status = "disabled";
+ status = "ok";
cell-index = <0>;
compatible = "qcom,mdss-dp";
qcom,mdss-fb-map = <&mdss_fb2>;
gdsc-supply = <&gdsc_mdss>;
- vdda-1p2-supply = <&pm660_l1>;
+ vdda-1p8-supply = <&pm660_l10>;
vdda-0p9-supply = <&pm660l_l1>;
- reg = <0xc990000 0xa84>,
+ reg = <0xc990000 0xa8c>,
<0xc011000 0x910>,
<0x1fcb200 0x050>,
<0xc8c2200 0x1a0>,
@@ -465,8 +465,37 @@
reg-names = "dp_ctrl", "dp_phy", "tcsr_regs", "dp_mmss_cc",
"qfprom_physical","hdcp_physical";
+ clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_AXI_CLK>,
+ <&clock_mmss MMSS_MDSS_MDP_CLK>,
+ <&clock_mmss MMSS_MDSS_HDMI_DP_AHB_CLK>,
+ <&clock_mmss MMSS_MDSS_DP_AUX_CLK>,
+ <&clock_rpmcc RPM_LN_BB_CLK1>,
+ <&clock_gcc GCC_USB3_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_mmss MMSS_MDSS_DP_LINK_CLK>,
+ <&clock_mmss MMSS_MDSS_DP_LINK_INTF_CLK>,
+ <&clock_mmss MMSS_MDSS_DP_CRYPTO_CLK>,
+ <&clock_mmss MMSS_MDSS_DP_PIXEL_CLK>,
+ <&clock_mmss DP_PIXEL_CLK_SRC>,
+ <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
+ clock-names = "core_mnoc_clk", "core_iface_clk", "core_bus_clk",
+ "core_mdp_core_clk", "core_alt_iface_clk",
+ "core_aux_clk", "core_ref_clk_src", "core_ref_clk",
+ "core_ahb_phy_clk", "ctrl_link_clk",
+ "ctrl_link_iface_clk", "ctrl_crypto_clk",
+ "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
+
+ qcom,dp-usbpd-detection = <&pm660_pdphy>;
+
qcom,msm_ext_disp = <&msm_ext_disp>;
+ 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 = <300000>;
+
qcom,core-supply-entries {
#address-cells = <1>;
#size-cells = <0>;
@@ -487,9 +516,9 @@
qcom,ctrl-supply-entry@0 {
reg = <0>;
- qcom,supply-name = "vdda-1p2";
- qcom,supply-min-voltage = <1200000>;
- qcom,supply-max-voltage = <1250000>;
+ qcom,supply-name = "vdda-1p8";
+ qcom,supply-min-voltage = <1780000>;
+ qcom,supply-max-voltage = <1950000>;
qcom,supply-enable-load = <12560>;
qcom,supply-disable-load = <4>;
};
@@ -518,7 +547,7 @@
"rot_vbif_phys";
qcom,mdss-rot-mode = <1>;
- qcom,mdss-highest-bank-bit = <0x2>;
+ qcom,mdss-highest-bank-bit = <0x1>;
/* Bus Scale Settings */
qcom,msm-bus,name = "mdss_rotator";
@@ -546,39 +575,10 @@
/* 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>;
-
- smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
- compatible = "qcom,smmu_sde_rot_unsec";
- iommus = <&mmss_bimc_smmu 0xe00>;
- gdsc-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_rot_sec: qcom,smmu_rot_sec_cb {
- compatible = "qcom,smmu_sde_rot_sec";
- iommus = <&mmss_bimc_smmu 0xe01>;
- gdsc-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";
- };
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi
index b666d846ca04..23514467ba73 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi
@@ -106,6 +106,15 @@
qcom,platform-te-gpio = <&tlmm 59 0>;
};
+&mdss_dp_ctrl {
+ pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+ pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>;
+ pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>;
+ qcom,aux-en-gpio = <&tlmm 55 0>;
+ qcom,aux-sel-gpio = <&tlmm 56 0>;
+ qcom,usbplug-cc-gpio = <&tlmm 58 0>;
+};
+
&pm660l_wled {
qcom,led-strings-list = [01 02];
};
@@ -147,6 +156,20 @@
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
};
+&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>;
+};
+
&sdhc_1 {
/* device core power supply */
vdd-supply = <&pm660l_l4>;
@@ -219,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-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
index dbc98a97fc8d..7ecab691dadf 100644
--- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
@@ -49,16 +49,17 @@
};
};
- trigout_b: trigout_b {
+ trigout_a: trigout_a {
mux {
- pins = "gpio12";
- function = "qdss_cti1_b";
+ pins = "gpio49";
+ function = "qdss_cti_trig_out_a";
};
config {
- pins = "gpio12";
- drive-strength = <16>;
+ pins = "gpio49";
+ drive-strength = <2>;
bias-disable;
+ output-low;
};
};
@@ -1439,6 +1440,58 @@
};
};
+ mdss_dp_aux_active: mdss_dp_aux_active {
+ mux {
+ pins = "gpio55", "gpio56";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio55", "gpio56";
+ bias-disable = <0>; /* no pull */
+ drive-strength = <8>;
+ };
+ };
+
+ mdss_dp_aux_suspend: mdss_dp_aux_suspend {
+ mux {
+ pins = "gpio55", "gpio56";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio55", "gpio56";
+ bias-pull-down;
+ drive-strength = <2>;
+ };
+ };
+
+ mdss_dp_usbplug_cc_active: mdss_dp_usbplug_cc_active {
+ mux {
+ pins = "gpio58";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio58";
+ bias-disable;
+ drive-strength = <16>;
+ };
+ };
+
+ mdss_dp_usbplug_cc_suspend: mdss_dp_usbplug_cc_suspend {
+ mux {
+ pins = "gpio58";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio58";
+ bias-pull-down;
+ drive-strength = <2>;
+ };
+ };
+
ts_mux {
ts_active: ts_active {
mux {
diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts
index 335f454d2bba..7ca31fcc41a2 100644
--- a/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-cdp.dts
@@ -36,3 +36,13 @@
lab-supply = <&lab_regulator>;
ibb-supply = <&ibb_regulator>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts
new file mode 100644
index 000000000000..281af3b1768e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts
@@ -0,0 +1,38 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm660.dtsi"
+#include "sdm660-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A, Headset Jacktype NO, CDP";
+ compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&mdss_dsi0 {
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-rcm.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-rcm.dts
new file mode 100644
index 000000000000..8b009718eb87
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-headset-jacktype-no-rcm.dts
@@ -0,0 +1,26 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm660.dtsi"
+#include "sdm660-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A, Headset Jacktype NO, RCM";
+ compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp";
+ qcom,board-id = <21 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts
index a783060d0155..d6e1f6a32def 100644
--- a/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-mtp.dts
@@ -36,3 +36,7 @@
lab-supply = <&lab_regulator>;
ibb-supply = <&ibb_regulator>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-rcm.dts
index 6c3afd4e1a4a..14af76ff84b9 100644
--- a/arch/arm/boot/dts/qcom/sdm660-pm660a-rcm.dts
+++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-rcm.dts
@@ -24,3 +24,13 @@
qcom,board-id = <21 0>;
qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <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 c00595934cf0..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>;
@@ -592,39 +593,39 @@
qcom,corner-frequencies =
<160000000 266000000 370000000
465000000 588000000 647000000
- 800000000>;
+ 750000000>;
qcom,cpr-target-quotients =
- <0 0 0 0 0 0 202 193
- 331 326 337 345 0 0 0 0>,
- <0 0 0 0 0 0 202 193
- 331 326 337 345 0 0 0 0>,
- <0 0 0 0 0 0 317 300
- 476 463 489 489 0 0 0 0>,
- <0 0 0 0 0 0 411 387
- 595 572 611 602 0 0 0 0>,
- <0 0 0 0 0 0 522 489
- 727 696 748 732 0 0 0 0>,
- <0 0 0 0 0 0 606 568
- 818 786 848 826 0 0 0 0>,
+ <0 0 0 0 0 0 174 167
+ 294 292 303 313 0 0 0 0>,
+ <0 0 0 0 0 0 263 247
+ 413 397 415 412 0 0 0 0>,
+ <0 0 0 0 0 0 375 354
+ 554 519 573 554 0 0 0 0>,
+ <0 0 0 0 0 0 412 380
+ 597 562 612 591 0 0 0 0>,
+ <0 0 0 0 0 0 513 476
+ 722 680 738 718 0 0 0 0>,
+ <0 0 0 0 0 0 595 553
+ 811 768 837 811 0 0 0 0>,
<0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0>;
qcom,cpr-ro-scaling-factor =
- < 0 0 0 0 0 0 1740 1620
- 2040 1960 2160 2040 0 0 0 0>,
- < 0 0 0 0 0 0 1740 1620
- 2040 1960 2160 2040 0 0 0 0>,
- < 0 0 0 0 0 0 1740 1620
- 2040 1960 2160 2040 0 0 0 0>,
- < 0 0 0 0 0 0 1740 1620
- 2040 1960 2160 2040 0 0 0 0>,
- < 0 0 0 0 0 0 1740 1620
- 2040 1960 2160 2040 0 0 0 0>,
- < 0 0 0 0 0 0 1740 1620
- 2040 1960 2160 2040 0 0 0 0>,
- < 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0>;
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>,
+ < 0 0 0 0 0 0 1790 1760
+ 1990 1900 2140 2020 0 0 0 0>;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
qcom,cpr-corner-allow-ldo-mode =
@@ -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 f35619d2a21e..8633d89821ec 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -70,6 +70,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_0: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU1: cpu@1 {
@@ -90,6 +93,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_1: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU2: cpu@2 {
@@ -110,6 +116,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_2: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU3: cpu@3 {
@@ -130,6 +139,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x9040>;
};
+ L1_TLB_3: l1-tlb {
+ qcom,dump-size = <0x2800>;
+ };
};
CPU4: cpu@100 {
@@ -154,6 +166,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
};
+ L1_TLB_100: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
};
CPU5: cpu@101 {
@@ -174,6 +189,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
};
+ L1_TLB_101: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
};
CPU6: cpu@102 {
@@ -194,6 +212,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
};
+ L1_TLB_102: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
};
CPU7: cpu@103 {
@@ -214,6 +235,9 @@
compatible = "arm,arch-cache";
qcom,dump-size = <0x12000>;
};
+ L1_TLB_103: l1-tlb {
+ qcom,dump-size = <0x4800>;
+ };
};
cpu-map {
@@ -510,6 +534,38 @@
qcom,dump-node = <&L1_D_103>;
qcom,dump-id = <0x87>;
};
+ qcom,l1_tlb_dump0 {
+ qcom,dump-node = <&L1_TLB_0>;
+ qcom,dump-id = <0x20>;
+ };
+ qcom,l1_tlb_dump1 {
+ qcom,dump-node = <&L1_TLB_1>;
+ qcom,dump-id = <0x21>;
+ };
+ qcom,l1_tlb_dump2 {
+ qcom,dump-node = <&L1_TLB_2>;
+ qcom,dump-id = <0x22>;
+ };
+ qcom,l1_tlb_dump3 {
+ qcom,dump-node = <&L1_TLB_3>;
+ qcom,dump-id = <0x23>;
+ };
+ qcom,l1_tlb_dump100 {
+ qcom,dump-node = <&L1_TLB_100>;
+ qcom,dump-id = <0x24>;
+ };
+ qcom,l1_tlb_dump101 {
+ qcom,dump-node = <&L1_TLB_101>;
+ qcom,dump-id = <0x25>;
+ };
+ qcom,l1_tlb_dump102 {
+ qcom,dump-node = <&L1_TLB_102>;
+ qcom,dump-id = <0x26>;
+ };
+ qcom,l1_tlb_dump103 {
+ qcom,dump-node = <&L1_TLB_103>;
+ qcom,dump-id = <0x27>;
+ };
};
wdog: qcom,wdt@17817000 {
@@ -1163,8 +1219,8 @@
< 902400000 0x0404002f 0x04260026 0x1 3 >,
< 1113600000 0x0404003a 0x052e002e 0x2 4 >,
< 1401600000 0x04040049 0x073a003a 0x2 5 >,
- < 1536000000 0x04040050 0x08400040 0x3 6 >,
- < 1747200000 0x0404005b 0x09480048 0x3 7 >,
+ < 1536000000 0x04040050 0x08400040 0x2 6 >,
+ < 1747200000 0x0404005b 0x09480048 0x2 7 >,
< 1843200000 0x04040060 0x094c004c 0x3 8 >;
qcom,perfcl-speedbin0-v0 =
@@ -1172,8 +1228,8 @@
< 1113600000 0x0404003a 0x052e002e 0x1 2 >,
< 1401600000 0x04040049 0x073a003a 0x2 3 >,
< 1747200000 0x0404005b 0x09480048 0x2 4 >,
- < 1958400000 0x04040066 0x0a510051 0x3 5 >,
- < 2150400000 0x04040070 0x0b590059 0x3 6 >,
+ < 1958400000 0x04040066 0x0a510051 0x2 5 >,
+ < 2150400000 0x04040070 0x0b590059 0x2 6 >,
< 2457600000 0x04040080 0x0c660066 0x3 7 >;
qcom,perfcl-speedbin1-v0 =
@@ -1181,8 +1237,8 @@
< 1113600000 0x0404003a 0x052e002e 0x1 2 >,
< 1401600000 0x04040049 0x073a003a 0x2 3 >,
< 1747200000 0x0404005b 0x09480048 0x2 4 >,
- < 1958400000 0x04040066 0x0a510051 0x3 5 >,
- < 2150400000 0x04040070 0x0b590059 0x3 6 >,
+ < 1958400000 0x04040066 0x0a510051 0x2 5 >,
+ < 2150400000 0x04040070 0x0b590059 0x2 6 >,
< 2208000000 0x04040073 0x0b5c005c 0x3 7 >;
qcom,up-timer = <1000 1000>;
@@ -1251,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>;
@@ -1558,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>;
@@ -1835,6 +1846,7 @@
<0 424 0>, /* CE10 */
<0 425 0>; /* CE11 */
qcom,wlan-msa-memory = <0x100000>;
+ qcom,smmu-s1-bypass;
};
qcom,lpass@15700000 {
diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig
index d7eb67ff85c1..7df369de029a 100644
--- a/arch/arm/configs/sdm660-perf_defconfig
+++ b/arch/arm/configs/sdm660-perf_defconfig
@@ -35,6 +35,7 @@ CONFIG_EMBEDDED=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_ARCH_MMAP_RND_BITS=16
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -234,7 +235,6 @@ CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=40
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
@@ -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,7 +501,11 @@ 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
+CONFIG_IOMMU_TESTS=y
CONFIG_QCOM_COMMON_LOG=y
CONFIG_MSM_SMEM=y
CONFIG_QPNP_HAPTIC=y
diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig
index c2ceac22f15f..3a757a7dc7b5 100644
--- a/arch/arm/configs/sdm660_defconfig
+++ b/arch/arm/configs/sdm660_defconfig
@@ -7,7 +7,6 @@ CONFIG_RCU_EXPERT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
-CONFIG_CGROUPS=y
CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CPUSETS=y
@@ -15,7 +14,6 @@ CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_SCHEDTUNE=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
-CONFIG_CGROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_SCHED_HMP=y
CONFIG_SCHED_HMP_CSTATE_AWARE=y
@@ -23,6 +21,7 @@ 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
@@ -35,6 +34,7 @@ CONFIG_EMBEDDED=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_ARCH_MMAP_RND_BITS=16
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -233,7 +233,6 @@ CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=40
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
@@ -325,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
@@ -375,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
@@ -445,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
@@ -497,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
@@ -643,6 +648,7 @@ CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_MEMTEST=y
CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_FREE_PAGES_RDONLY=y
CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_CORESIGHT=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 2005a47b491e..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 *);
@@ -539,4 +542,13 @@ static inline void secure_flush_area(const void *addr, size_t size)
outer_flush_range(phys, phys + size);
}
+#ifdef CONFIG_FREE_PAGES_RDONLY
+#define mark_addr_rdonly(a) set_memory_ro((unsigned long)a, 1)
+#define mark_addr_rdwrite(a) set_memory_rw((unsigned long)a, 1)
+#else
+#define mark_addr_rdonly(a)
+#define mark_addr_rdwrite(a)
+#endif
+
+
#endif
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 48836eba4ab7..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;
@@ -1875,7 +1876,11 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
{
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
dma_addr_t dma_addr;
- int ret, prot, len = PAGE_ALIGN(size + offset);
+ int ret, prot, len, start_offset, map_offset;
+
+ map_offset = offset & ~PAGE_MASK;
+ start_offset = offset & PAGE_MASK;
+ len = PAGE_ALIGN(map_offset + size);
dma_addr = __alloc_iova(mapping, len);
if (dma_addr == DMA_ERROR_CODE)
@@ -1883,11 +1888,12 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
prot = __dma_direction_to_prot(dir);
- ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot);
+ ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page) +
+ start_offset, len, prot);
if (ret < 0)
goto fail;
- return dma_addr + offset;
+ return dma_addr + map_offset;
fail:
__free_iova(mapping, dma_addr, len);
return DMA_ERROR_CODE;
@@ -1983,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,
@@ -2002,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,
@@ -2161,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)
@@ -2177,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) {
@@ -2186,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);
@@ -2221,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;
}
@@ -2284,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/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index d02f8187b1cc..5d73327f8491 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
@@ -147,3 +148,58 @@ void *kmap_atomic_pfn(unsigned long pfn)
return (void *)vaddr;
}
+
+#ifdef CONFIG_ARCH_WANT_KMAP_ATOMIC_FLUSH
+static void kmap_remove_unused_cpu(int cpu)
+{
+ int start_idx, idx, type;
+
+ pagefault_disable();
+ type = kmap_atomic_idx();
+ start_idx = type + 1 + KM_TYPE_NR * cpu;
+
+ for (idx = start_idx; idx < KM_TYPE_NR + KM_TYPE_NR * cpu; idx++) {
+ unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ pte_t ptep;
+
+ ptep = get_top_pte(vaddr);
+ if (ptep)
+ set_top_pte(vaddr, __pte(0));
+ }
+ pagefault_enable();
+}
+
+static void kmap_remove_unused(void *unused)
+{
+ kmap_remove_unused_cpu(smp_processor_id());
+}
+
+void kmap_atomic_flush_unused(void)
+{
+ on_each_cpu(kmap_remove_unused, NULL, 1);
+}
+
+static int hotplug_kmap_atomic_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ switch (action & (~CPU_TASKS_FROZEN)) {
+ case CPU_DYING:
+ kmap_remove_unused_cpu((int)hcpu);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block hotplug_kmap_atomic_notifier = {
+ .notifier_call = hotplug_kmap_atomic_callback,
+};
+
+static int __init init_kmap_atomic(void)
+{
+ return register_hotcpu_notifier(&hotplug_kmap_atomic_notifier);
+}
+early_initcall(init_kmap_atomic);
+#endif
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 107b5f1b864b..d3d718772381 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -625,6 +625,9 @@ struct section_perm {
pmdval_t mask;
pmdval_t prot;
pmdval_t clear;
+ pteval_t ptemask;
+ pteval_t pteprot;
+ pteval_t pteclear;
};
static struct section_perm nx_perms[] = {
@@ -634,6 +637,8 @@ static struct section_perm nx_perms[] = {
.end = (unsigned long)_stext,
.mask = ~PMD_SECT_XN,
.prot = PMD_SECT_XN,
+ .ptemask = ~L_PTE_XN,
+ .pteprot = L_PTE_XN,
},
/* Make init RW (set NX). */
{
@@ -641,6 +646,8 @@ static struct section_perm nx_perms[] = {
.end = (unsigned long)_sdata,
.mask = ~PMD_SECT_XN,
.prot = PMD_SECT_XN,
+ .ptemask = ~L_PTE_XN,
+ .pteprot = L_PTE_XN,
},
#ifdef CONFIG_DEBUG_RODATA
/* Make rodata NX (set RO in ro_perms below). */
@@ -649,6 +656,8 @@ static struct section_perm nx_perms[] = {
.end = (unsigned long)__init_begin,
.mask = ~PMD_SECT_XN,
.prot = PMD_SECT_XN,
+ .ptemask = ~L_PTE_XN,
+ .pteprot = L_PTE_XN,
},
#endif
};
@@ -667,6 +676,8 @@ static struct section_perm ro_perms[] = {
.prot = PMD_SECT_APX | PMD_SECT_AP_WRITE,
.clear = PMD_SECT_AP_WRITE,
#endif
+ .ptemask = ~L_PTE_RDONLY,
+ .pteprot = L_PTE_RDONLY,
},
};
#endif
@@ -676,6 +687,35 @@ static struct section_perm ro_perms[] = {
* copied into each mm). During startup, this is the init_mm. Is only
* safe to be called with preemption disabled, as under stop_machine().
*/
+struct pte_data {
+ pteval_t mask;
+ pteval_t val;
+};
+
+static int __pte_update(pte_t *ptep, pgtable_t token, unsigned long addr,
+ void *d)
+{
+ struct pte_data *data = d;
+ pte_t pte = *ptep;
+
+ pte = __pte((pte_val(*ptep) & data->mask) | data->val);
+ set_pte_ext(ptep, pte, 0);
+
+ return 0;
+}
+
+static inline void pte_update(unsigned long addr, pteval_t mask,
+ pteval_t prot, struct mm_struct *mm)
+{
+ struct pte_data data;
+
+ data.mask = mask;
+ data.val = prot;
+
+ apply_to_page_range(mm, addr, SECTION_SIZE, __pte_update, &data);
+ flush_tlb_kernel_range(addr, addr + SECTION_SIZE);
+}
+
static inline void section_update(unsigned long addr, pmdval_t mask,
pmdval_t prot, struct mm_struct *mm)
{
@@ -724,11 +764,21 @@ void set_section_perms(struct section_perm *perms, int n, bool set,
for (addr = perms[i].start;
addr < perms[i].end;
- addr += SECTION_SIZE)
- section_update(addr, perms[i].mask,
- set ? perms[i].prot : perms[i].clear, mm);
+ addr += SECTION_SIZE) {
+ pmd_t *pmd;
+
+ pmd = pmd_offset(pud_offset(pgd_offset(mm, addr),
+ addr), addr);
+ if (pmd_bad(*pmd))
+ section_update(addr, perms[i].mask,
+ set ? perms[i].prot : perms[i].clear,
+ mm);
+ else
+ pte_update(addr, perms[i].ptemask,
+ set ? perms[i].pteprot : perms[i].pteclear,
+ mm);
+ }
}
-
}
static void update_sections_early(struct section_perm perms[], int n)
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 f4a7d9107f36..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
@@ -65,6 +66,8 @@ CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_RANDOMIZE_BASE=y
+# CONFIG_RANDOMIZE_MODULE_REGION_FULL is not set
# CONFIG_EFI is not set
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index d0fdb7206d5b..dd1c4ffe3dc5 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -5,6 +5,7 @@ CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
@@ -52,17 +53,20 @@ 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
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_COMPAT=y
@@ -230,6 +234,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_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
new file mode 100644
index 000000000000..06b4554ec362
--- /dev/null
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -0,0 +1,708 @@
+# 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_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-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig
index b24885a89bff..d00772c12626 100644
--- a/arch/arm64/configs/sdm660-perf_defconfig
+++ b/arch/arm64/configs/sdm660-perf_defconfig
@@ -37,6 +37,7 @@ 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
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index bc633548bbc3..af8902054b8a 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -35,6 +35,7 @@ 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
@@ -58,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/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S
index efa79e8d4196..9f8eeccae67c 100644
--- a/arch/arm64/kernel/vdso/gettimeofday.S
+++ b/arch/arm64/kernel/vdso/gettimeofday.S
@@ -216,16 +216,25 @@ ENDPROC(__kernel_clock_getres)
ENTRY(__do_get_tspec)
.cfi_startproc
+ /* Read the virtual counter. */
+ isb
+#if IS_ENABLED(CONFIG_MSM_TIMER_LEAP)
+#define LEAST_32BITS 0x00000000FFFFFFFF
+reread:
+ mrs x15, cntvct_el0
+ and x13, x15, #LEAST_32BITS
+ eor x13, x13, #LEAST_32BITS
+ cbz x13, reread
+#else
+ mrs x15, cntvct_el0
+#endif
+
/* Read from the vDSO data page. */
ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST]
ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC]
ldp w11, w12, [vdso_data, #VDSO_CS_MULT]
seqcnt_read w9
- /* Read the virtual counter. */
- isb
- mrs x15, cntvct_el0
-
/* Calculate cycle delta and convert to ns. */
sub x10, x15, x10
/* We can only guarantee 56 bits of precision. */
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 1ad799523a54..45c365290553 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1756,7 +1756,11 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev,
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
dma_addr_t dma_addr;
- int ret, prot, len = PAGE_ALIGN(size + offset);
+ int ret, prot, len, start_offset, map_offset;
+
+ map_offset = offset & ~PAGE_MASK;
+ start_offset = offset & PAGE_MASK;
+ len = PAGE_ALIGN(map_offset + size);
dma_addr = __alloc_iova(mapping, len);
if (dma_addr == DMA_ERROR_CODE)
@@ -1766,12 +1770,12 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev,
prot = __get_iommu_pgprot(attrs, prot,
is_dma_coherent(dev, attrs));
- ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len,
- prot);
+ ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page) +
+ start_offset, len, prot);
if (ret < 0)
goto fail;
- return dma_addr + offset;
+ return dma_addr + map_offset;
fail:
__free_iova(mapping, dma_addr, len);
return DMA_ERROR_CODE;
@@ -1923,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;
@@ -1938,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:
@@ -1952,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 fc814a36ad07..5b83a06ee1a9 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -32,3 +32,7 @@ config REGMAP_IRQ
config REGMAP_SWR
tristate
+
+config REGMAP_ALLOW_WRITE_DEBUGFS
+ depends on REGMAP && DEBUG_FS
+ bool "Allow REGMAP debugfs write"
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 8d456e3e42a0..3120bdc84fce 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -259,8 +259,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
count, ppos);
}
-#define REGMAP_ALLOW_WRITE_DEBUGFS
-#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
/*
* This can be dangerous especially when we have clients such as
* PMICs, therefore don't provide any real compile time configuration option
@@ -330,7 +329,7 @@ static ssize_t regmap_data_read_file(struct file *file, char __user *user_buf,
new_count, ppos);
}
-#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
static ssize_t regmap_data_write_file(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -656,7 +655,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
if (map->max_register || regmap_readable(map, 0)) {
umode_t registers_mode;
-#if defined(REGMAP_ALLOW_WRITE_DEBUGFS)
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
registers_mode = 0600;
#else
registers_mode = 0400;
diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c
index a88ae0f59e63..37cc6284cf97 100644
--- a/drivers/bluetooth/btfm_slim.c
+++ b/drivers/bluetooth/btfm_slim.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* 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
@@ -512,7 +512,6 @@ static int btfm_slim_remove(struct slim_device *slim)
BTFMSLIM_DBG("");
mutex_destroy(&btfm_slim->io_lock);
mutex_destroy(&btfm_slim->xfer_lock);
- kfree(btfm_slim);
snd_soc_unregister_codec(&slim->dev);
BTFMSLIM_DBG("slim_remove_device() - btfm_slim->slim_ifd");
@@ -520,6 +519,8 @@ static int btfm_slim_remove(struct slim_device *slim)
BTFMSLIM_DBG("slim_remove_device() - btfm_slim->slim_pgd");
slim_remove_device(slim);
+
+ kfree(btfm_slim);
return 0;
}
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index fe3af13f0d38..88bd6afdeea5 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -815,9 +815,9 @@ static int overlap_ptr_cmp(const void *a, const void *b)
return st == 0 ? ed : st;
}
-static void context_build_overlap(struct smq_invoke_ctx *ctx)
+static int context_build_overlap(struct smq_invoke_ctx *ctx)
{
- int i;
+ int i, err = 0;
remote_arg_t *lpra = ctx->lpra;
int inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc);
@@ -826,6 +826,11 @@ static void context_build_overlap(struct smq_invoke_ctx *ctx)
for (i = 0; i < nbufs; ++i) {
ctx->overs[i].start = (uintptr_t)lpra[i].buf.pv;
ctx->overs[i].end = ctx->overs[i].start + lpra[i].buf.len;
+ if (lpra[i].buf.len) {
+ VERIFY(err, ctx->overs[i].end > ctx->overs[i].start);
+ if (err)
+ goto bail;
+ }
ctx->overs[i].raix = i;
ctx->overps[i] = &ctx->overs[i];
}
@@ -851,6 +856,8 @@ static void context_build_overlap(struct smq_invoke_ctx *ctx)
max = *ctx->overps[i];
}
}
+bail:
+ return err;
}
#define K_COPY_FROM_USER(err, kernel, dst, src, size) \
@@ -923,8 +930,11 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel,
}
ctx->sc = invoke->sc;
- if (bufs)
- context_build_overlap(ctx);
+ if (bufs) {
+ VERIFY(err, 0 == context_build_overlap(ctx));
+ if (err)
+ goto bail;
+ }
ctx->retval = -1;
ctx->pid = current->pid;
ctx->tgid = current->tgid;
@@ -1092,6 +1102,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
/* calculate len requreed for copying */
for (oix = 0; oix < inbufs + outbufs; ++oix) {
int i = ctx->overps[oix]->raix;
+ uintptr_t mstart, mend;
ssize_t len = lpra[i].buf.len;
if (!len)
continue;
@@ -1099,7 +1110,15 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
continue;
if (ctx->overps[oix]->offset == 0)
copylen = ALIGN(copylen, BALIGN);
- copylen += ctx->overps[oix]->mend - ctx->overps[oix]->mstart;
+ mstart = ctx->overps[oix]->mstart;
+ mend = ctx->overps[oix]->mend;
+ VERIFY(err, (mend - mstart) <= LONG_MAX);
+ if (err)
+ goto bail;
+ copylen += mend - mstart;
+ VERIFY(err, copylen >= 0);
+ if (err)
+ goto bail;
}
ctx->used = copylen;
@@ -1171,7 +1190,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
for (oix = 0; oix < inbufs + outbufs; ++oix) {
int i = ctx->overps[oix]->raix;
struct fastrpc_mmap *map = ctx->maps[i];
- int mlen = ctx->overps[oix]->mend - ctx->overps[oix]->mstart;
+ ssize_t mlen;
uint64_t buf;
ssize_t len = lpra[i].buf.len;
if (!len)
@@ -1182,6 +1201,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
rlen -= ALIGN(args, BALIGN) - args;
args = ALIGN(args, BALIGN);
}
+ mlen = ctx->overps[oix]->mend - ctx->overps[oix]->mstart;
VERIFY(err, rlen >= mlen);
if (err)
goto bail;
@@ -1961,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/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index f47b390375c4..2c7662a24cd1 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.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
@@ -2203,8 +2203,9 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid)
struct diag_dci_client_tbl *entry = NULL;
list_for_each_safe(start, temp, &driver->dci_client_list) {
entry = list_entry(start, struct diag_dci_client_tbl, track);
- if (entry->client->tgid == tgid)
- return entry;
+ if (entry->client && entry->tgid == entry->client->tgid)
+ if (entry->client->tgid == tgid)
+ return entry;
}
return NULL;
}
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/msm/clock-mmss-8998.c b/drivers/clk/msm/clock-mmss-8998.c
index a72de47c34c0..1661878fc650 100644
--- a/drivers/clk/msm/clock-mmss-8998.c
+++ b/drivers/clk/msm/clock-mmss-8998.c
@@ -240,7 +240,7 @@ static struct rcg_clk ahb_clk_src = {
.set_rate = set_rate_hid,
.freq_tbl = ftbl_ahb_clk_src,
.current_freq = &rcg_dummy_freq,
- .non_local_control_timeout = 1000,
+ .non_local_children = true,
.base = &virt_base,
.c = {
.dbg_name = "ahb_clk_src",
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.c b/drivers/clk/qcom/common.c
index cba778b827ec..f6ce3106ab6f 100644
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -334,16 +334,17 @@ static u32 run_measurement(unsigned ticks, struct regmap *regmap,
static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
{
unsigned long flags, ret = 0;
- u32 gcc_xo4_reg, sample_ticks = 0x10000, multiplier = 1;
+ u32 gcc_xo4_reg, sample_ticks = 0x10000, multiplier;
u64 raw_count_short, raw_count_full;
struct clk_debug_mux *meas = to_clk_measure(hw);
struct measure_clk_data *data = meas->priv;
-
clk_prepare_enable(data->cxo);
spin_lock_irqsave(&clk_reg_lock, flags);
+ multiplier = meas->multiplier + 1;
+
/* Enable CXO/4 and RINGOSC branch. */
regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
gcc_xo4_reg |= BIT(0);
@@ -404,6 +405,7 @@ static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_debug_mux *meas = to_clk_measure(hw);
+ unsigned long lsb = 0;
u32 regval = 0;
int dbg_cc = 0;
@@ -412,6 +414,16 @@ static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
if (dbg_cc != GCC) {
regmap_read(meas->regmap[dbg_cc], 0x0, &regval);
+ /* Clear & Set post divider bits */
+ if (meas->parent[index].post_div_mask) {
+ regval &= ~meas->parent[index].post_div_mask;
+ lsb = find_first_bit((unsigned long *)
+ &meas->parent[index].post_div_mask, 32);
+ regval |= (meas->parent[index].post_div_val << lsb) &
+ meas->parent[index].post_div_mask;
+ meas->multiplier = meas->parent[index].post_div_val;
+ }
+
if (meas->parent[index].mask)
regval &= ~meas->parent[index].mask <<
meas->parent[index].shift;
@@ -436,6 +448,11 @@ static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
/* clear post divider bits */
regval &= ~BM(15, 12);
+ lsb = find_first_bit((unsigned long *)
+ &meas->parent[index].post_div_mask, 32);
+ regval |= (meas->parent[index].post_div_val << lsb) &
+ meas->parent[index].post_div_mask;
+ meas->multiplier = meas->parent[index].post_div_val;
regval &= ~meas->mask;
regval |= (meas->parent[index].sel & meas->mask);
regval |= meas->en_mask;
diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h
index 76c010970b51..95408a47fef0 100644
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2016-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
@@ -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;
@@ -94,6 +96,10 @@ enum debug_cc {
* Incase the recursive debug mux does not have a enable bit,
* 0xFF should be used to indicate the same, otherwise global
* enable bit would be used.
+ * @post_div_mask: indicates the post div mask to be used at debug/recursive
+ * debug mux.
+ * @post_div_val: indicates the post div value to be used at debug/recursive
+ * debug mux.
*/
struct clk_src {
const char *parents;
@@ -103,6 +109,8 @@ struct clk_src {
u32 mask;
u32 shift;
u32 en_mask;
+ u32 post_div_mask;
+ u32 post_div_val;
};
#define MUX_SRC_LIST(...) \
@@ -123,6 +131,7 @@ struct clk_src {
* controller debug mux.
* @debug_offset: Start of debug mux offset.
* @hw: handle between common and hardware-specific interfaces.
+ * @multiplier: internally used by debug mux as post div multiplier.
*/
struct clk_debug_mux {
struct clk_src *parent;
@@ -134,6 +143,9 @@ struct clk_debug_mux {
u32 mask;
u32 debug_offset;
struct clk_hw hw;
+
+ /* internal */
+ u32 multiplier;
};
#define BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb)
@@ -143,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/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
index d8ae85b65a47..3413859a56ef 100644
--- a/drivers/clk/qcom/gcc-sdm660.c
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -2082,19 +2082,6 @@ static struct clk_branch gcc_rx1_usb2_clkref_clk = {
},
};
-static struct clk_branch gcc_rx2_qlink_clkref_clk = {
- .halt_reg = 0x88034,
- .halt_check = BRANCH_HALT_VOTED,
- .clkr = {
- .enable_reg = 0x88034,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "gcc_rx2_qlink_clkref_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch gcc_sdcc1_ahb_clk = {
.halt_reg = 0x16008,
.halt_check = BRANCH_HALT,
@@ -2671,7 +2658,6 @@ static struct clk_regmap *gcc_660_clocks[] = {
[GCC_QSPI_SER_CLK] = &gcc_qspi_ser_clk.clkr,
[GCC_RX0_USB2_CLKREF_CLK] = &gcc_rx0_usb2_clkref_clk.clkr,
[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
- [GCC_RX2_QLINK_CLKREF_CLK] = &gcc_rx2_qlink_clkref_clk.clkr,
[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
[GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
@@ -2816,6 +2802,9 @@ static int gcc_660_probe(struct platform_device *pdev)
/* This clock is used for all GPUCC register access */
clk_prepare_enable(gcc_gpu_cfg_ahb_clk.clkr.hw.clk);
+ /* Keep bimc gfx clock port on all the time */
+ clk_prepare_enable(gcc_bimc_gfx_clk.clkr.hw.clk);
+
dev_info(&pdev->dev, "Registered GCC clocks\n");
return ret;
@@ -3109,182 +3098,185 @@ static struct clk_debug_mux gcc_debug_mux = {
{ "gcc_ufs_tx_symbol_0_clk", 0x0EC },
{ "gcc_usb3_phy_pipe_clk", 0x040 },
{ "mmssnoc_axi_clk", 0x22, MMCC,
- 0x004, 0, 0, 0x1000 },
+ 0x004, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_bimc_smmu_ahb_clk", 0x22, MMCC,
- 0x00C, 0, 0, 0x1000 },
+ 0x00C, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_bimc_smmu_axi_clk", 0x22, MMCC,
- 0x00D, 0, 0, 0x1000 },
+ 0x00D, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_ahb_clk", 0x22, MMCC,
- 0x037, 0, 0, 0x1000 },
+ 0x037, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cci_ahb_clk", 0x22, MMCC,
- 0x02E, 0, 0, 0x1000 },
+ 0x02E, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cci_clk", 0x22, MMCC,
- 0x02D, 0, 0, 0x1000 },
+ 0x02D, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cphy_csid0_clk", 0x22, MMCC,
- 0x08D, 0, 0, 0x1000 },
+ 0x08D, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cphy_csid1_clk", 0x22, MMCC,
- 0x08E, 0, 0, 0x1000 },
+ 0x08E, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cphy_csid2_clk", 0x22, MMCC,
- 0x08F, 0, 0, 0x1000 },
+ 0x08F, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cphy_csid3_clk", 0x22, MMCC,
- 0x090, 0, 0, 0x1000 },
+ 0x090, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cpp_ahb_clk", 0x22, MMCC,
- 0x03B, 0, 0, 0x1000 },
+ 0x03B, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cpp_axi_clk", 0x22, MMCC,
- 0x07A, 0, 0, 0x1000 },
+ 0x07A, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cpp_clk", 0x22, MMCC,
- 0x03A, 0, 0, 0x1000 },
+ 0x03A, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_cpp_vbif_ahb_clk", 0x22, MMCC,
- 0x073, 0, 0, 0x1000 },
+ 0x073, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi0_ahb_clk", 0x22, MMCC,
- 0x042, 0, 0, 0x1000 },
+ 0x042, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi0_clk", 0x22, MMCC,
- 0x041, 0, 0, 0x1000 },
+ 0x041, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi0phytimer_clk", 0x22, MMCC,
- 0x02F, 0, 0, 0x1000 },
+ 0x02F, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi0pix_clk", 0x22, MMCC,
- 0x045, 0, 0, 0x1000 },
+ 0x045, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi0rdi_clk", 0x22, MMCC,
- 0x044, 0, 0, 0x1000 },
+ 0x044, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi1_ahb_clk", 0x22, MMCC,
- 0x047, 0, 0, 0x1000 },
+ 0x047, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi1_clk", 0x22, MMCC,
- 0x046, 0, 0, 0x1000 },
+ 0x046, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi1phytimer_clk", 0x22, MMCC,
- 0x030, 0, 0, 0x1000 },
+ 0x030, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi1pix_clk", 0x22, MMCC,
- 0x04A, 0, 0, 0x1000 },
+ 0x04A, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi1rdi_clk", 0x22, MMCC,
- 0x049, 0, 0, 0x1000 },
+ 0x049, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi2_ahb_clk", 0x22, MMCC,
- 0x04C, 0, 0, 0x1000 },
+ 0x04C, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi2_clk", 0x22, MMCC,
- 0x04B, 0, 0, 0x1000 },
+ 0x04B, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi2phytimer_clk", 0x22, MMCC,
- 0x031, 0, 0, 0x1000 },
+ 0x031, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi2pix_clk", 0x22, MMCC,
- 0x04F, 0, 0, 0x1000 },
+ 0x04F, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi2rdi_clk", 0x22, MMCC,
- 0x04E, 0, 0, 0x1000 },
+ 0x04E, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi3_ahb_clk", 0x22, MMCC,
- 0x051, 0, 0, 0x1000 },
+ 0x051, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi3_clk", 0x22, MMCC,
- 0x050, 0, 0, 0x1000 },
+ 0x050, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi3pix_clk", 0x22, MMCC,
- 0x054, 0, 0, 0x1000 },
+ 0x054, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi3rdi_clk", 0x22, MMCC,
- 0x053, 0, 0, 0x1000 },
+ 0x053, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi_vfe0_clk", 0x22, MMCC,
- 0x03F, 0, 0, 0x1000 },
+ 0x03F, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csi_vfe1_clk", 0x22, MMCC,
- 0x040, 0, 0, 0x1000 },
+ 0x040, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csiphy0_clk", 0x22, MMCC,
- 0x043, 0, 0, 0x1000 },
+ 0x043, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csiphy1_clk", 0x22, MMCC,
- 0x085, 0, 0, 0x1000 },
+ 0x085, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_csiphy2_clk", 0x22, MMCC,
- 0x088, 0, 0, 0x1000 },
+ 0x088, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_gp0_clk", 0x22, MMCC,
- 0x027, 0, 0, 0x1000 },
+ 0x027, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_gp1_clk", 0x22, MMCC,
- 0x028, 0, 0, 0x1000 },
+ 0x028, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_ispif_ahb_clk", 0x22, MMCC,
- 0x033, 0, 0, 0x1000 },
+ 0x033, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_jpeg0_clk", 0x22, MMCC,
- 0x032, 0, 0, 0x1000 },
+ 0x032, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_jpeg_ahb_clk", 0x22, MMCC,
- 0x035, 0, 0, 0x1000 },
+ 0x035, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_jpeg_axi_clk", 0x22, MMCC,
- 0x036, 0, 0, 0x1000 },
+ 0x036, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_mclk0_clk", 0x22, MMCC,
- 0x029, 0, 0, 0x1000 },
+ 0x029, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_mclk1_clk", 0x22, MMCC,
- 0x02A, 0, 0, 0x1000 },
+ 0x02A, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_mclk2_clk", 0x22, MMCC,
- 0x02B, 0, 0, 0x1000 },
+ 0x02B, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_mclk3_clk", 0x22, MMCC,
- 0x02C, 0, 0, 0x1000 },
+ 0x02C, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_micro_ahb_clk", 0x22, MMCC,
- 0x026, 0, 0, 0x1000 },
+ 0x026, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_top_ahb_clk", 0x22, MMCC,
- 0x025, 0, 0, 0x1000 },
+ 0x025, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe0_ahb_clk", 0x22, MMCC,
- 0x086, 0, 0, 0x1000 },
+ 0x086, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe0_clk", 0x22, MMCC,
- 0x038, 0, 0, 0x1000 },
+ 0x038, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe0_stream_clk", 0x22, MMCC,
- 0x071, 0, 0, 0x1000 },
+ 0x071, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe1_ahb_clk", 0x22, MMCC,
- 0x087, 0, 0, 0x1000 },
+ 0x087, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe1_clk", 0x22, MMCC,
- 0x039, 0, 0, 0x1000 },
+ 0x039, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe1_stream_clk", 0x22, MMCC,
- 0x072, 0, 0, 0x1000 },
+ 0x072, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe_vbif_ahb_clk", 0x22, MMCC,
- 0x03C, 0, 0, 0x1000 },
+ 0x03C, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_camss_vfe_vbif_axi_clk", 0x22, MMCC,
- 0x03D, 0, 0, 0x1000 },
+ 0x03D, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_csiphy_ahb2crif_clk", 0x22, MMCC,
- 0x0B8, 0, 0, 0x1000 },
+ 0x0B8, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_ahb_clk", 0x22, MMCC,
- 0x022, 0, 0, 0x1000 },
+ 0x022, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_axi_clk", 0x22, MMCC,
- 0x024, 0, 0, 0x1000 },
+ 0x024, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_byte0_clk", 0x22, MMCC,
- 0x01E, 0, 0, 0x1000 },
+ 0x01E, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_byte0_intf_clk", 0x22, MMCC,
- 0x0AD, 0, 0, 0x1000 },
+ 0x0AD, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_byte1_clk", 0x22, MMCC,
- 0x01F, 0, 0, 0x1000 },
+ 0x01F, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_byte1_intf_clk", 0x22, MMCC,
- 0x0B6, 0, 0, 0x1000 },
+ 0x0B6, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_dp_aux_clk", 0x22, MMCC,
- 0x09C, 0, 0, 0x1000 },
+ 0x09C, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_dp_crypto_clk", 0x22, MMCC,
- 0x09A, 0, 0, 0x1000 },
+ 0x09A, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_dp_gtc_clk", 0x22, MMCC,
- 0x09D, 0, 0, 0x1000 },
+ 0x09D, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_dp_link_clk", 0x22, MMCC,
- 0x098, 0, 0, 0x1000 },
+ 0x098, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_dp_link_intf_clk", 0x22, MMCC,
- 0x099, 0, 0, 0x1000 },
+ 0x099, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_dp_pixel_clk", 0x22, MMCC,
- 0x09B, 0, 0, 0x1000 },
+ 0x09B, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_esc0_clk", 0x22, MMCC,
- 0x020, 0, 0, 0x1000 },
+ 0x020, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_esc1_clk", 0x22, MMCC,
- 0x021, 0, 0, 0x1000 },
+ 0x021, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_hdmi_dp_ahb_clk", 0x22, MMCC,
- 0x023, 0, 0, 0x1000 },
+ 0x023, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_mdp_clk", 0x22, MMCC,
- 0x014, 0, 0, 0x1000 },
+ 0x014, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_pclk0_clk", 0x22, MMCC,
- 0x016, 0, 0, 0x1000 },
+ 0x016, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_pclk1_clk", 0x22, MMCC,
- 0x017, 0, 0, 0x1000 },
+ 0x017, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_rot_clk", 0x22, MMCC,
- 0x012, 0, 0, 0x1000 },
+ 0x012, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mdss_vsync_clk", 0x22, MMCC,
- 0x01C, 0, 0, 0x1000 },
+ 0x01C, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_misc_ahb_clk", 0x22, MMCC,
- 0x003, 0, 0, 0x1000 },
+ 0x003, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_misc_cxo_clk", 0x22, MMCC,
- 0x077, 0, 0, 0x1000 },
+ 0x077, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_mnoc_ahb_clk", 0x22, MMCC,
- 0x001, 0, 0, 0x1000 },
+ 0x001, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_snoc_dvm_axi_clk", 0x22, MMCC,
- 0x013, 0, 0, 0x1000 },
+ 0x013, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_video_ahb_clk", 0x22, MMCC,
- 0x011, 0, 0, 0x1000 },
+ 0x011, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_video_axi_clk", 0x22, MMCC,
- 0x00F, 0, 0, 0x1000 },
+ 0x00F, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_video_core_clk", 0x22, MMCC,
- 0x00E, 0, 0, 0x1000 },
+ 0x00E, 0, 0, 0x1000, BM(14, 13) },
{ "mmss_video_subcore0_clk", 0x22, MMCC,
- 0x01A, 0, 0, 0x1000 },
- { "gpucc_gfx3d_clk", 0x13d, GPU, 0x008 },
- { "gpucc_rbbmtimer_clk", 0x13d, GPU, 0x005 },
- { "gpucc_rbcpr_clk", 0x13d, GPU, 0x003 },
+ 0x01A, 0, 0, 0x1000, BM(14, 13) },
+ { "gpucc_gfx3d_clk", 0x13d, GPU,
+ 0x008, 0, 0, 0, BM(18, 17) },
+ { "gpucc_rbbmtimer_clk", 0x13d, GPU,
+ 0x005, 0, 0, 0, BM(18, 17) },
+ { "gpucc_rbcpr_clk", 0x13d, GPU,
+ 0x003, 0, 0, 0, BM(18, 17) },
{ "pwrcl_clk", 0x0c0, CPU, 0x000, 0x3, 8, 0x0FF },
{ "perfcl_clk", 0x0c0, CPU, 0x100, 0x3, 8, 0x0FF },
),
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 2788c0add14a..ab21334d5813 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -24,6 +24,7 @@
#include <linux/pfk.h>
#include <crypto/ice.h>
#include <soc/qcom/scm.h>
+#include <soc/qcom/qseecomi.h>
#include "iceregs.h"
#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
@@ -40,11 +41,20 @@
#define TZ_OS_KS_RESTORE_KEY_ID_PARAM_ID \
TZ_SYSCALL_CREATE_PARAM_ID_0
+#define TZ_OS_KS_RESTORE_KEY_CONFIG_ID \
+ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_KEYSTORE, 0x06)
+
+#define TZ_OS_KS_RESTORE_KEY_CONFIG_ID_PARAM_ID \
+ TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL)
+
+
#define ICE_REV(x, y) (((x) & ICE_CORE_##y##_REV_MASK) >> ICE_CORE_##y##_REV)
#define QCOM_UFS_ICE_DEV "iceufs"
#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;
@@ -830,6 +840,29 @@ static int qcom_ice_restore_config(void)
return ret;
}
+static int qcom_ice_restore_key_config(struct ice_device *ice_dev)
+{
+ struct scm_desc desc = {0};
+ int ret = -1;
+
+ /* For ice 3, key configuration needs to be restored in case of reset */
+
+ desc.arginfo = TZ_OS_KS_RESTORE_KEY_CONFIG_ID_PARAM_ID;
+
+ 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);
+
+ if (ret)
+ pr_err("%s: Error: 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
static int qcom_ice_init_clocks(struct ice_device *ice)
{
int ret = -EINVAL;
@@ -1103,6 +1136,22 @@ static int qcom_ice_finish_power_collapse(struct ice_device *ice_dev)
err = -EFAULT;
goto out;
}
+
+ /*
+ * ICE looses its key configuration when UFS is reset,
+ * restore it
+ */
+ } else if (ICE_REV(ice_dev->ice_hw_version, MAJOR) > 2) {
+ err = qcom_ice_restore_key_config(ice_dev);
+ if (err)
+ goto out;
+
+ /*
+ * for PFE case, clear the cached ICE key table,
+ * this will force keys to be reconfigured
+ * per each next transaction
+ */
+ pfk_clear_on_reset();
}
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 008b8babf31e..d4729fa59edb 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -339,22 +339,23 @@ config GPIO_PXA
Say yes here to support the PXA GPIO device
config GPIO_QPNP_PIN
+ tristate "Qualcomm Technologies, Inc. QPNP GPIO support"
depends on SPMI
- tristate "Qualcomm QPNP gpio support"
help
- Say 'y' here to include support for the Qualcomm QPNP gpio
- driver. This driver supports Device Tree and allows a
- device_node to be registered as a gpio-controller. It
- does not handle gpio interrupts directly, they are handled
- via the spmi arbiter interrupt driver.
+ Say 'y' here to include support for the Qualcomm Technologies, Inc.
+ QPNP GPIO driver. This driver supports Device Tree and allows a
+ device_node to be registered as a gpio-controller. It does not handle
+ GPIO interrupts directly; they are handled via the SPMI arbiter
+ interrupt driver.
config GPIO_QPNP_PIN_DEBUG
- depends on GPIO_QPNP_PIN
- depends on DEBUG_FS
- bool "Qualcomm QPNP GPIO debug support"
+ bool "Qualcomm Technologies, Inc. QPNP GPIO debug support"
+ depends on GPIO_QPNP_PIN && DEBUG_FS
help
- Say 'y' here to include debug support for the Qualcomm
- QPNP gpio driver.
+ Say 'y' here to include debug support for the Qualcomm Technologies,
+ Inc. QPNP GPIO driver. This provides a userspace debug interface to
+ get and set all of the supported features of PMIC GPIO and MPP pins
+ including those which are managed by the gpio framework.
config GPIO_RCAR
tristate "Renesas R-Car GPIO"
diff --git a/drivers/gpio/qpnp-pin.c b/drivers/gpio/qpnp-pin.c
index de24d99ea34e..62cd78a95303 100644
--- a/drivers/gpio/qpnp-pin.c
+++ b/drivers/gpio/qpnp-pin.c
@@ -295,7 +295,7 @@ static int qpnp_pin_check_config(enum qpnp_pin_param_type idx,
if (val >= QPNP_PIN_GPIO_LV_MV_MODE_INVALID)
return -EINVAL;
} else if (val >= QPNP_PIN_GPIO_MODE_INVALID) {
- return -EINVAL;
+ return -EINVAL;
}
} else if (q_spec->type == Q_MPP_TYPE) {
if (val >= QPNP_PIN_MPP_MODE_INVALID)
@@ -753,16 +753,17 @@ int qpnp_pin_config(int gpio, struct qpnp_pin_cfg *param)
}
EXPORT_SYMBOL(qpnp_pin_config);
-#define Q_MAX_CHIP_NAME 128
int qpnp_pin_map(const char *name, uint32_t pmic_pin)
{
struct qpnp_pin_chip *q_chip;
struct qpnp_pin_spec *q_spec = NULL;
+ if (!name)
+ return -EINVAL;
+
mutex_lock(&qpnp_pin_chips_lock);
list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) {
- if (strncmp(q_chip->gpio_chip.label, name,
- Q_MAX_CHIP_NAME) != 0)
+ if (strcmp(q_chip->gpio_chip.label, name) != 0)
continue;
if (q_chip->pmic_pin_lowest <= pmic_pin &&
q_chip->pmic_pin_highest >= pmic_pin) {
@@ -778,7 +779,7 @@ int qpnp_pin_map(const char *name, uint32_t pmic_pin)
}
EXPORT_SYMBOL(qpnp_pin_map);
-static int qpnp_pin_to_irq(struct gpio_chip *gpio_chip, unsigned offset)
+static int qpnp_pin_to_irq(struct gpio_chip *gpio_chip, unsigned int offset)
{
struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
struct qpnp_pin_spec *q_spec;
@@ -811,14 +812,13 @@ static int qpnp_pin_to_irq(struct gpio_chip *gpio_chip, unsigned offset)
return q_spec->irq;
}
-static int qpnp_pin_get(struct gpio_chip *gpio_chip, unsigned offset)
+static int qpnp_pin_get(struct gpio_chip *gpio_chip, unsigned int offset)
{
- int rc, ret_val;
struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
struct qpnp_pin_spec *q_spec = NULL;
- u8 buf[1], en_mask;
- u8 shift, mask, reg;
- int val;
+ u8 buf, en_mask, shift, mask, reg;
+ unsigned int val;
+ int rc;
if (WARN_ON(!q_chip))
return -ENODEV;
@@ -840,7 +840,9 @@ static int qpnp_pin_get(struct gpio_chip *gpio_chip, unsigned offset)
== QPNP_PIN_MODE_DIG_IN) {
rc = regmap_read(q_chip->regmap,
Q_REG_ADDR(q_spec, Q_REG_STATUS1), &val);
- buf[0] = (u8)val;
+ if (rc)
+ return rc;
+ buf = val;
if (q_spec->type == Q_GPIO_TYPE && q_spec->dig_major_rev == 0)
en_mask = Q_REG_STATUS1_GPIO_EN_REV0_MASK;
@@ -850,26 +852,23 @@ static int qpnp_pin_get(struct gpio_chip *gpio_chip, unsigned offset)
else /* MPP */
en_mask = Q_REG_STATUS1_MPP_EN_MASK;
- if (!(buf[0] & en_mask))
+ if (!(buf & en_mask))
return -EPERM;
- return buf[0] & Q_REG_STATUS1_VAL_MASK;
- } else {
- if (is_gpio_lv_mv(q_spec)) {
- shift = Q_REG_DIG_OUT_SRC_INVERT_SHIFT;
- mask = Q_REG_DIG_OUT_SRC_INVERT_MASK;
- reg = q_spec->regs[Q_REG_I_DIG_OUT_SRC_CTL];
- } else {
- shift = Q_REG_OUT_INVERT_SHIFT;
- mask = Q_REG_OUT_INVERT_MASK;
- reg = q_spec->regs[Q_REG_I_MODE_CTL];
- }
+ return buf & Q_REG_STATUS1_VAL_MASK;
+ }
- ret_val = (reg & mask) >> shift;
- return ret_val;
+ if (is_gpio_lv_mv(q_spec)) {
+ shift = Q_REG_DIG_OUT_SRC_INVERT_SHIFT;
+ mask = Q_REG_DIG_OUT_SRC_INVERT_MASK;
+ reg = q_spec->regs[Q_REG_I_DIG_OUT_SRC_CTL];
+ } else {
+ shift = Q_REG_OUT_INVERT_SHIFT;
+ mask = Q_REG_OUT_INVERT_MASK;
+ reg = q_spec->regs[Q_REG_I_MODE_CTL];
}
- return 0;
+ return (reg & mask) >> shift;
}
static int __qpnp_pin_set(struct qpnp_pin_chip *q_chip,
@@ -905,7 +904,7 @@ static int __qpnp_pin_set(struct qpnp_pin_chip *q_chip,
static void qpnp_pin_set(struct gpio_chip *gpio_chip,
- unsigned offset, int value)
+ unsigned int offset, int value)
{
struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
struct qpnp_pin_spec *q_spec;
@@ -950,7 +949,7 @@ static int qpnp_pin_set_mode(struct qpnp_pin_chip *q_chip,
}
static int qpnp_pin_direction_input(struct gpio_chip *gpio_chip,
- unsigned offset)
+ unsigned int offset)
{
struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
struct qpnp_pin_spec *q_spec;
@@ -966,8 +965,7 @@ static int qpnp_pin_direction_input(struct gpio_chip *gpio_chip,
}
static int qpnp_pin_direction_output(struct gpio_chip *gpio_chip,
- unsigned offset,
- int val)
+ unsigned int offset, int val)
{
int rc;
struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
@@ -1343,7 +1341,7 @@ struct qpnp_pin_debugfs_args {
const char *filename;
};
-static struct qpnp_pin_debugfs_args dfs_args[] = {
+static struct qpnp_pin_debugfs_args dfs_args[Q_NUM_PARAMS] = {
{ Q_PIN_CFG_MODE, "mode" },
{ Q_PIN_CFG_OUTPUT_TYPE, "output_type" },
{ Q_PIN_CFG_INVERT, "invert" },
@@ -1371,8 +1369,6 @@ static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
struct dentry *dfs, *dfs_io_dir;
int i, j, rc;
- BUG_ON(Q_NUM_PARAMS != ARRAY_SIZE(dfs_args));
-
q_chip->dfs_dir = debugfs_create_dir(q_chip->gpio_chip.label,
driver_dfs_dir);
if (q_chip->dfs_dir == NULL) {
@@ -1403,12 +1399,8 @@ static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
continue;
params[type] = type;
- dfs = debugfs_create_file(
- filename,
- S_IRUGO | S_IWUSR,
- dfs_io_dir,
- &q_spec->params[type],
- &qpnp_pin_fops);
+ dfs = debugfs_create_file(filename, 0644, dfs_io_dir,
+ &q_spec->params[type], &qpnp_pin_fops);
if (dfs == NULL)
goto dfs_err;
}
@@ -1674,7 +1666,7 @@ static int qpnp_pin_remove(struct platform_device *pdev)
return qpnp_pin_free_chip(q_chip);
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = "qcom,qpnp-pin",
},
{}
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/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index f1439381d781..4ec04001ae7e 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -299,4 +299,20 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
.num_protected_regs = 0x20,
.busy_mask = 0xFFFFFFFE,
},
+ {
+ .gpurev = ADRENO_REV_A508,
+ .core = 5,
+ .major = 0,
+ .minor = 8,
+ .patchid = ANY_ID,
+ .features = ADRENO_PREEMPTION | ADRENO_64BIT |
+ ADRENO_CONTENT_PROTECTION | ADRENO_CPZ_RETENTION,
+ .pm4fw_name = "a530_pm4.fw",
+ .pfpfw_name = "a530_pfp.fw",
+ .zap_name = "a508_zap",
+ .gpudev = &adreno_a5xx_gpudev,
+ .gmem_size = (SZ_128K + SZ_8K),
+ .num_protected_regs = 0x20,
+ .busy_mask = 0xFFFFFFFE,
+ },
};
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index f8c9b00d3f39..33fdb9ae11fa 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -169,6 +169,7 @@ enum adreno_gpurev {
ADRENO_REV_A430 = 430,
ADRENO_REV_A505 = 505,
ADRENO_REV_A506 = 506,
+ ADRENO_REV_A508 = 508,
ADRENO_REV_A510 = 510,
ADRENO_REV_A512 = 512,
ADRENO_REV_A530 = 530,
@@ -1002,6 +1003,7 @@ static inline int adreno_is_a5xx(struct adreno_device *adreno_dev)
ADRENO_TARGET(a505, ADRENO_REV_A505)
ADRENO_TARGET(a506, ADRENO_REV_A506)
+ADRENO_TARGET(a508, ADRENO_REV_A508)
ADRENO_TARGET(a510, ADRENO_REV_A510)
ADRENO_TARGET(a512, ADRENO_REV_A512)
ADRENO_TARGET(a530, ADRENO_REV_A530)
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 7e2e3aa91fce..973884c2c5e7 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -59,6 +59,7 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = {
{ adreno_is_a530, a530_vbif },
{ adreno_is_a512, a540_vbif },
{ adreno_is_a510, a530_vbif },
+ { adreno_is_a508, a530_vbif },
{ adreno_is_a505, a530_vbif },
{ adreno_is_a506, a530_vbif },
};
@@ -182,7 +183,7 @@ static void a5xx_platform_setup(struct adreno_device *adreno_dev)
uint64_t addr;
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
- if (adreno_is_a505_or_a506(adreno_dev)) {
+ if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) {
gpudev->snapshot_data->sect_sizes->cp_meq = 32;
gpudev->snapshot_data->sect_sizes->cp_merciu = 1024;
gpudev->snapshot_data->sect_sizes->roq = 256;
@@ -537,7 +538,7 @@ static void a5xx_regulator_disable(struct adreno_device *adreno_dev)
unsigned int reg;
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- if (adreno_is_a512(adreno_dev))
+ if (adreno_is_a512(adreno_dev) || adreno_is_a508(adreno_dev))
return;
/* If feature is not supported or not enabled */
@@ -1195,6 +1196,7 @@ static const struct {
{ adreno_is_a510, a510_hwcg_regs, ARRAY_SIZE(a510_hwcg_regs) },
{ adreno_is_a505, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) },
{ adreno_is_a506, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) },
+ { adreno_is_a508, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) },
};
void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on)
@@ -1640,7 +1642,8 @@ static void a5xx_clk_set_options(struct adreno_device *adreno_dev,
const char *name, struct clk *clk)
{
/* Handle clock settings for GFX PSCBCs */
- if (adreno_is_a540(adreno_dev) || adreno_is_a512(adreno_dev)) {
+ if (adreno_is_a540(adreno_dev) || adreno_is_a512(adreno_dev) ||
+ adreno_is_a508(adreno_dev)) {
if (!strcmp(name, "mem_iface_clk")) {
clk_set_flags(clk, CLKFLAG_NORETAIN_PERIPH);
clk_set_flags(clk, CLKFLAG_NORETAIN_MEM);
@@ -1927,7 +1930,7 @@ static void a5xx_start(struct adreno_device *adreno_dev)
* Below CP registers are 0x0 by default, program init
* values based on a5xx flavor.
*/
- if (adreno_is_a505_or_a506(adreno_dev)) {
+ if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) {
kgsl_regwrite(device, A5XX_CP_MEQ_THRESHOLDS, 0x20);
kgsl_regwrite(device, A5XX_CP_MERCIU_SIZE, 0x400);
kgsl_regwrite(device, A5XX_CP_ROQ_THRESHOLDS_2, 0x40000030);
@@ -1953,7 +1956,7 @@ static void a5xx_start(struct adreno_device *adreno_dev)
* vtxFifo and primFifo thresholds default values
* are different.
*/
- if (adreno_is_a505_or_a506(adreno_dev))
+ if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev))
kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL,
(0x100 << 11 | 0x100 << 22));
else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev))
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/iio/adc/qcom-tadc.c b/drivers/iio/adc/qcom-tadc.c
index 4a56847a43e7..9241288c1d43 100644
--- a/drivers/iio/adc/qcom-tadc.c
+++ b/drivers/iio/adc/qcom-tadc.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
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "TADC: %s: " fmt, __func__
+
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -101,8 +103,16 @@ enum tadc_chan_id {
TADC_BATT_P,
TADC_INPUT_P,
TADC_THERM1_THR1,
+ TADC_THERM1_THR2,
+ TADC_THERM1_THR3,
+ TADC_THERM1_THR4,
TADC_THERM2_THR1,
+ TADC_THERM2_THR2,
+ TADC_THERM2_THR3,
TADC_DIE_TEMP_THR1,
+ TADC_DIE_TEMP_THR2,
+ TADC_DIE_TEMP_THR3,
+ TADC_CHAN_ID_MAX,
};
#define TADC_CHAN(_name, _type, _channel, _info_mask) \
@@ -164,19 +174,39 @@ static const struct iio_chan_spec tadc_iio_chans[] = {
[TADC_INPUT_P] = TADC_POWER_CHAN(
"input", TADC_INPUT_P),
[TADC_THERM1_THR1] = TADC_THERM_CHAN(
- "batt_hot", TADC_THERM1_THR1),
+ "batt_warm", TADC_THERM1_THR1),
+ [TADC_THERM1_THR2] = TADC_THERM_CHAN(
+ "batt_cool", TADC_THERM1_THR2),
+ [TADC_THERM1_THR3] = TADC_THERM_CHAN(
+ "batt_cold", TADC_THERM1_THR3),
+ [TADC_THERM1_THR4] = TADC_THERM_CHAN(
+ "batt_hot", TADC_THERM1_THR4),
[TADC_THERM2_THR1] = TADC_THERM_CHAN(
- "skin_hot", TADC_THERM2_THR1),
+ "skin_lb", TADC_THERM2_THR1),
+ [TADC_THERM2_THR2] = TADC_THERM_CHAN(
+ "skin_ub", TADC_THERM2_THR2),
+ [TADC_THERM2_THR3] = TADC_THERM_CHAN(
+ "skin_rst", TADC_THERM2_THR3),
[TADC_DIE_TEMP_THR1] = TADC_THERM_CHAN(
- "die_hot", TADC_DIE_TEMP_THR1),
+ "die_lb", TADC_DIE_TEMP_THR1),
+ [TADC_DIE_TEMP_THR2] = TADC_THERM_CHAN(
+ "die_ub", TADC_DIE_TEMP_THR2),
+ [TADC_DIE_TEMP_THR3] = TADC_THERM_CHAN(
+ "die_rst", TADC_DIE_TEMP_THR3),
+};
+
+struct tadc_therm_thr {
+ int addr_lo;
+ int addr_hi;
};
struct tadc_chan_data {
- s32 scale;
- s32 offset;
- u32 rbias;
- const struct tadc_pt *table;
- size_t tablesize;
+ s32 scale;
+ s32 offset;
+ u32 rbias;
+ const struct tadc_pt *table;
+ size_t tablesize;
+ struct tadc_therm_thr thr[4];
};
struct tadc_chip {
@@ -186,6 +216,7 @@ struct tadc_chip {
u32 tadc_cmp_base;
struct tadc_chan_data chans[TADC_NUM_CH];
struct completion eoc_complete;
+ struct mutex write_lock;
};
struct tadc_pt {
@@ -238,14 +269,24 @@ static const struct tadc_pt tadc_therm_3450b_68k[] = {
{ 1712127, -40000 },
};
-static int tadc_read(struct tadc_chip *chip, u16 reg, u8 *val,
- size_t val_count)
+static bool tadc_is_reg_locked(struct tadc_chip *chip, u16 reg)
+{
+ if ((reg & 0xFF00) == chip->tadc_cmp_base)
+ return true;
+
+ if (reg == TADC_HWTRIG_CONV_CH_EN_REG(chip))
+ return true;
+
+ return false;
+}
+
+static int tadc_read(struct tadc_chip *chip, u16 reg, u8 *val, size_t count)
{
int rc = 0;
- rc = regmap_bulk_read(chip->regmap, reg, val, val_count);
+ rc = regmap_bulk_read(chip->regmap, reg, val, count);
if (rc < 0)
- pr_err("Couldn't read %04x rc=%d\n", reg, rc);
+ pr_err("Couldn't read 0x%04x rc=%d\n", reg, rc);
return rc;
}
@@ -254,57 +295,108 @@ static int tadc_write(struct tadc_chip *chip, u16 reg, u8 data)
{
int rc = 0;
+ mutex_lock(&chip->write_lock);
+ if (tadc_is_reg_locked(chip, reg)) {
+ rc = regmap_write(chip->regmap, (reg & 0xFF00) | 0xD0, 0xA5);
+ if (rc < 0) {
+ pr_err("Couldn't unlock secure register rc=%d\n", rc);
+ goto unlock;
+ }
+ }
+
rc = regmap_write(chip->regmap, reg, data);
- if (rc < 0)
- pr_err("Couldn't write %02x to %04x rc=%d\n",
- data, reg, rc);
+ if (rc < 0) {
+ pr_err("Couldn't write 0x%02x to 0x%04x rc=%d\n",
+ data, reg, rc);
+ goto unlock;
+ }
+
+unlock:
+ mutex_unlock(&chip->write_lock);
+ return rc;
+}
+static int tadc_bulk_write(struct tadc_chip *chip, u16 reg, u8 *data,
+ size_t count)
+{
+ int rc = 0, i;
+
+ mutex_lock(&chip->write_lock);
+ for (i = 0; i < count; ++i, ++reg) {
+ if (tadc_is_reg_locked(chip, reg)) {
+ rc = regmap_write(chip->regmap,
+ (reg & 0xFF00) | 0xD0, 0xA5);
+ if (rc < 0) {
+ pr_err("Couldn't unlock secure register rc=%d\n",
+ rc);
+ goto unlock;
+ }
+ }
+
+ rc = regmap_write(chip->regmap, reg, data[i]);
+ if (rc < 0) {
+ pr_err("Couldn't write 0x%02x to 0x%04x rc=%d\n",
+ data[i], reg, rc);
+ goto unlock;
+ }
+ }
+unlock:
+ mutex_unlock(&chip->write_lock);
return rc;
}
-static int tadc_lerp(const struct tadc_pt *pts, size_t tablesize, s32 input,
- s32 *output)
+static int tadc_lerp(const struct tadc_pt *pts, size_t size, bool inv,
+ s32 input, s32 *output)
{
int i;
s64 temp;
+ bool ascending;
if (pts == NULL) {
pr_err("Table is NULL\n");
return -EINVAL;
}
- if (tablesize < 1) {
+ if (size < 1) {
pr_err("Table has no entries\n");
return -ENOENT;
}
- if (tablesize == 1) {
- *output = pts[0].y;
+ if (size == 1) {
+ *output = inv ? pts[0].x : pts[0].y;
return 0;
}
- if (pts[0].x > pts[1].x) {
- pr_err("Table is not in acending order\n");
- return -EINVAL;
- }
-
- if (input <= pts[0].x) {
- *output = pts[0].y;
+ ascending = inv ? (pts[0].y < pts[1].y) : (pts[0].x < pts[1].x);
+ if (ascending ? (input <= (inv ? pts[0].y : pts[0].x)) :
+ (input >= (inv ? pts[0].y : pts[0].x))) {
+ *output = inv ? pts[0].x : pts[0].y;
return 0;
}
- if (input >= pts[tablesize - 1].x) {
- *output = pts[tablesize - 1].y;
+ if (ascending ? (input >= (inv ? pts[size - 1].y : pts[size - 1].x)) :
+ (input <= (inv ? pts[size - 1].y : pts[size - 1].x))) {
+ *output = inv ? pts[size - 1].x : pts[size - 1].y;
return 0;
}
- for (i = 1; i < tablesize; i++)
- if (input <= pts[i].x)
+ for (i = 1; i < size; i++)
+ if (ascending ? (input <= (inv ? pts[i].y : pts[i].x)) :
+ (input >= (inv ? pts[i].y : pts[i].x)))
break;
- temp = (s64)(pts[i].y - pts[i - 1].y) * (s64)(input - pts[i - 1].x);
- temp = div_s64(temp, pts[i].x - pts[i - 1].x);
- *output = temp + pts[i - 1].y;
+ if (inv) {
+ temp = (s64)(pts[i].x - pts[i - 1].x) *
+ (s64)(input - pts[i - 1].y);
+ temp = div_s64(temp, pts[i].y - pts[i - 1].y);
+ *output = temp + pts[i - 1].x;
+ } else {
+ temp = (s64)(pts[i].y - pts[i - 1].y) *
+ (s64)(input - pts[i - 1].x);
+ temp = div_s64(temp, pts[i].x - pts[i - 1].x);
+ *output = temp + pts[i - 1].y;
+ }
+
return 0;
}
@@ -321,15 +413,32 @@ static int tadc_lerp(const struct tadc_pt *pts, size_t tablesize, s32 input,
* Combine these equations and solve for Rtherm
* Rtherm = (ADC * Rbias) / (1024 - ADC)
*/
-static int tadc_process_therm(const struct tadc_chan_data *chan_data,
- s16 adc, s32 *result)
+static int tadc_get_processed_therm(const struct tadc_chan_data *chan_data,
+ s16 adc, s32 *result)
{
- s64 rtherm;
+ s32 rtherm;
- rtherm = (s64)adc * (s64)chan_data->rbias;
- rtherm = div_s64(rtherm, TADC_RESOLUTION - adc);
- return tadc_lerp(chan_data->table, chan_data->tablesize, rtherm,
- result);
+ rtherm = div_s64((s64)adc * chan_data->rbias, TADC_RESOLUTION - adc);
+ return tadc_lerp(chan_data->table, chan_data->tablesize, false, rtherm,
+ result);
+}
+
+static int tadc_get_raw_therm(const struct tadc_chan_data *chan_data,
+ int mdegc, int *result)
+{
+ int rc;
+ s32 rtherm;
+
+ rc = tadc_lerp(chan_data->table, chan_data->tablesize, true, mdegc,
+ &rtherm);
+ if (rc < 0) {
+ pr_err("Couldn't interpolate %d\n rc=%d", mdegc, rc);
+ return rc;
+ }
+
+ *result = div64_s64((s64)rtherm * TADC_RESOLUTION,
+ (s64)chan_data->rbias + rtherm);
+ return 0;
}
static int tadc_read_channel(struct tadc_chip *chip, u16 address, int *adc)
@@ -339,12 +448,31 @@ static int tadc_read_channel(struct tadc_chip *chip, u16 address, int *adc)
rc = tadc_read(chip, address, val, ARRAY_SIZE(val));
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read channel rc=%d\n", rc);
+ pr_err("Couldn't read channel rc=%d\n", rc);
return rc;
}
- *adc = (s16)(val[0] | val[1] << BITS_PER_BYTE);
- return 0;
+ /* the 10th bit is the sign bit for all channels */
+ *adc = sign_extend32(val[0] | val[1] << BITS_PER_BYTE, 10);
+ return rc;
+}
+
+static int tadc_write_channel(struct tadc_chip *chip, u16 address, int adc)
+{
+ u8 val[2];
+ int rc;
+
+ /* the 10th bit is the sign bit for all channels */
+ adc = sign_extend32(adc, 10);
+ val[0] = (u8)adc;
+ val[1] = (u8)(adc >> BITS_PER_BYTE);
+ rc = tadc_bulk_write(chip, address, val, 2);
+ if (rc < 0) {
+ pr_err("Couldn't write to channel rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
}
#define CONVERSION_TIMEOUT_MS 100
@@ -356,8 +484,7 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
rc = tadc_read(chip, TADC_MBG_ERR_REG(chip), val, 1);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read mbg error status rc=%d\n",
- rc);
+ pr_err("Couldn't read mbg error status rc=%d\n", rc);
return rc;
}
@@ -368,8 +495,7 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
rc = tadc_write(chip, TADC_CONV_REQ_REG(chip), channels);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't write conversion request rc=%d\n",
- rc);
+ pr_err("Couldn't write conversion request rc=%d\n", rc);
return rc;
}
@@ -379,21 +505,19 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
if (timeleft == 0) {
rc = tadc_read(chip, TADC_SW_CH_CONV_REG(chip), val, 1);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read conversion status rc=%d\n",
- rc);
+ pr_err("Couldn't read conversion status rc=%d\n", rc);
return rc;
}
if (val[0] != channels) {
- dev_err(chip->dev, "Conversion timed out\n");
+ pr_err("Conversion timed out\n");
return -ETIMEDOUT;
}
}
rc = tadc_read(chip, TADC_CH1_ADC_LO_REG(chip), val, ARRAY_SIZE(val));
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read adc channels rc=%d\n",
- rc);
+ pr_err("Couldn't read adc channels rc=%d\n", rc);
return rc;
}
@@ -404,84 +528,102 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
}
static int tadc_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int *val, int *val2,
- long mask)
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
{
struct tadc_chip *chip = iio_priv(indio_dev);
- const struct tadc_chan_data *chan_data = &chip->chans[chan->channel];
- int rc = 0, offset = 0, scale, scale2, scale_type;
+ struct tadc_chan_data *chan_data = NULL;
+ int rc, offset = 0, scale, scale2, scale_type;
s16 adc[TADC_NUM_CH];
switch (chan->channel) {
case TADC_THERM1_THR1:
+ case TADC_THERM1_THR2:
+ case TADC_THERM1_THR3:
+ case TADC_THERM1_THR4:
chan_data = &chip->chans[TADC_THERM1];
break;
case TADC_THERM2_THR1:
+ case TADC_THERM2_THR2:
+ case TADC_THERM2_THR3:
chan_data = &chip->chans[TADC_THERM2];
break;
case TADC_DIE_TEMP_THR1:
+ case TADC_DIE_TEMP_THR2:
+ case TADC_DIE_TEMP_THR3:
chan_data = &chip->chans[TADC_DIE_TEMP];
break;
default:
+ if (chan->channel >= ARRAY_SIZE(chip->chans)) {
+ pr_err("Channel %d is out of bounds\n", chan->channel);
+ return -EINVAL;
+ }
+
+ chan_data = &chip->chans[chan->channel];
break;
}
+ if (!chan_data)
+ return -EINVAL;
+
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->channel) {
case TADC_THERM1_THR1:
+ case TADC_THERM2_THR1:
+ case TADC_DIE_TEMP_THR1:
rc = tadc_read_channel(chip,
- TADC_CMP_THR1_CH1_CMP_LO_REG(chip), val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't read THERM1 threshold rc=%d\n",
- rc);
- return rc;
- }
+ chan_data->thr[0].addr_lo, val);
break;
- case TADC_THERM2_THR1:
+ case TADC_THERM1_THR2:
+ case TADC_THERM2_THR2:
+ case TADC_DIE_TEMP_THR2:
rc = tadc_read_channel(chip,
- TADC_CMP_THR1_CH2_CMP_LO_REG(chip), val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't read THERM2 threshold rc=%d\n",
- rc);
- return rc;
- }
+ chan_data->thr[1].addr_lo, val);
break;
- case TADC_DIE_TEMP_THR1:
+ case TADC_THERM1_THR3:
+ case TADC_THERM2_THR3:
+ case TADC_DIE_TEMP_THR3:
rc = tadc_read_channel(chip,
- TADC_CMP_THR1_CH3_CMP_LO_REG(chip), val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't read DIE_TEMP threshold rc=%d\n",
- rc);
- return rc;
- }
+ chan_data->thr[2].addr_lo, val);
+ break;
+ case TADC_THERM1_THR4:
+ rc = tadc_read_channel(chip,
+ chan_data->thr[3].addr_lo, val);
break;
default:
rc = tadc_do_conversion(chip, BIT(chan->channel), adc);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't read channel %d\n",
- chan->channel);
- return rc;
- }
- *val = adc[chan->channel];
+ if (rc >= 0)
+ *val = adc[chan->channel];
break;
}
+
+ if (rc < 0) {
+ pr_err("Couldn't read channel %d\n", chan->channel);
+ return rc;
+ }
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_PROCESSED:
switch (chan->channel) {
case TADC_THERM1:
case TADC_THERM2:
case TADC_THERM1_THR1:
+ case TADC_THERM1_THR2:
+ case TADC_THERM1_THR3:
+ case TADC_THERM1_THR4:
case TADC_THERM2_THR1:
+ case TADC_THERM2_THR2:
+ case TADC_THERM2_THR3:
rc = tadc_read_raw(indio_dev, chan, val, NULL,
- IIO_CHAN_INFO_RAW);
+ IIO_CHAN_INFO_RAW);
if (rc < 0)
return rc;
- rc = tadc_process_therm(chan_data, *val, val);
+ rc = tadc_get_processed_therm(chan_data, *val, val);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't process 0x%04x from channel %d rc=%d\n",
- *val, chan->channel, rc);
+ pr_err("Couldn't process 0x%04x from channel %d rc=%d\n",
+ *val, chan->channel, rc);
return rc;
}
break;
@@ -489,7 +631,8 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
rc = tadc_do_conversion(chip,
BIT(TADC_BATT_I) | BIT(TADC_BATT_V), adc);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read battery current and voltage channels\n");
+ pr_err("Couldn't read battery current and voltage channels rc=%d\n",
+ rc);
return rc;
}
@@ -499,7 +642,8 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
rc = tadc_do_conversion(chip,
BIT(TADC_INPUT_I) | BIT(TADC_INPUT_V), adc);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read input current and voltage channels\n");
+ pr_err("Couldn't read input current and voltage channels rc=%d\n",
+ rc);
return rc;
}
@@ -507,13 +651,13 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
break;
default:
rc = tadc_read_raw(indio_dev, chan, val, NULL,
- IIO_CHAN_INFO_RAW);
+ IIO_CHAN_INFO_RAW);
if (rc < 0)
return rc;
/* offset is optional */
rc = tadc_read_raw(indio_dev, chan, &offset, NULL,
- IIO_CHAN_INFO_OFFSET);
+ IIO_CHAN_INFO_OFFSET);
if (rc < 0)
return rc;
@@ -525,18 +669,20 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
break;
case IIO_VAL_FRACTIONAL:
*val = div_s64((s64)*val * scale + offset,
- scale2);
+ scale2);
break;
default:
return -EINVAL;
}
break;
}
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case TADC_DIE_TEMP:
case TADC_DIE_TEMP_THR1:
+ case TADC_DIE_TEMP_THR2:
*val = chan_data->scale;
return IIO_VAL_INT;
case TADC_BATT_I:
@@ -548,14 +694,134 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
*val2 = TADC_RESOLUTION;
return IIO_VAL_FRACTIONAL;
}
+
return -EINVAL;
case IIO_CHAN_INFO_OFFSET:
*val = chan_data->offset;
return IIO_VAL_INT;
}
+
return -EINVAL;
}
+static int tadc_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct tadc_chip *chip = iio_priv(indio_dev);
+ const struct tadc_chan_data *chan_data;
+ int rc, raw;
+ s32 rem;
+
+ switch (chan->channel) {
+ case TADC_THERM1_THR1:
+ case TADC_THERM1_THR2:
+ case TADC_THERM1_THR3:
+ case TADC_THERM1_THR4:
+ chan_data = &chip->chans[TADC_THERM1];
+ break;
+ case TADC_THERM2_THR1:
+ case TADC_THERM2_THR2:
+ case TADC_THERM2_THR3:
+ chan_data = &chip->chans[TADC_THERM2];
+ break;
+ case TADC_DIE_TEMP_THR1:
+ case TADC_DIE_TEMP_THR2:
+ case TADC_DIE_TEMP_THR3:
+ chan_data = &chip->chans[TADC_DIE_TEMP];
+ break;
+ default:
+ if (chan->channel >= ARRAY_SIZE(chip->chans)) {
+ pr_err("Channel %d is out of bounds\n", chan->channel);
+ return -EINVAL;
+ }
+
+ chan_data = &chip->chans[chan->channel];
+ break;
+ }
+
+ if (!chan_data)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->channel) {
+ case TADC_THERM1_THR1:
+ case TADC_THERM1_THR2:
+ case TADC_THERM1_THR3:
+ case TADC_THERM1_THR4:
+ case TADC_THERM2_THR1:
+ case TADC_THERM2_THR2:
+ case TADC_THERM2_THR3:
+ rc = tadc_get_raw_therm(chan_data, val, &raw);
+ if (rc < 0) {
+ pr_err("Couldn't get raw value rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case TADC_DIE_TEMP_THR1:
+ case TADC_DIE_TEMP_THR2:
+ case TADC_DIE_TEMP_THR3:
+ /* DIV_ROUND_CLOSEST does not like negative numbers */
+ raw = div_s64_rem(val - chan_data->offset,
+ chan_data->scale, &rem);
+ if (abs(rem) >= abs(chan_data->scale / 2))
+ raw++;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = tadc_write_raw(indio_dev, chan, raw, 0,
+ IIO_CHAN_INFO_RAW);
+ if (rc < 0) {
+ pr_err("Couldn't write raw rc=%d\n", rc);
+ return rc;
+ }
+
+ break;
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->channel) {
+ case TADC_THERM1_THR1:
+ case TADC_THERM2_THR1:
+ case TADC_DIE_TEMP_THR1:
+ rc = tadc_write_channel(chip,
+ chan_data->thr[0].addr_lo, val);
+ break;
+ case TADC_THERM1_THR2:
+ case TADC_THERM2_THR2:
+ case TADC_DIE_TEMP_THR2:
+ rc = tadc_write_channel(chip,
+ chan_data->thr[1].addr_lo, val);
+ break;
+ case TADC_THERM1_THR3:
+ case TADC_THERM2_THR3:
+ case TADC_DIE_TEMP_THR3:
+ rc = tadc_write_channel(chip,
+ chan_data->thr[2].addr_lo, val);
+ break;
+ case TADC_THERM1_THR4:
+ rc = tadc_write_channel(chip,
+ chan_data->thr[3].addr_lo, val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rc < 0) {
+ pr_err("Couldn't write channel %d\n", chan->channel);
+ return rc;
+ }
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
static irqreturn_t handle_eoc(int irq, void *dev_id)
{
struct tadc_chip *chip = dev_id;
@@ -587,72 +853,144 @@ static int tadc_parse_dt(struct tadc_chip *chip)
for_each_available_child_of_node(node, child) {
rc = of_property_read_u32(child, "reg", &chan_id);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't find channel for %s rc=%d",
- child->name, rc);
+ pr_err("Couldn't find channel for %s rc=%d",
+ child->name, rc);
return rc;
}
if (chan_id > TADC_NUM_CH - 1) {
- dev_err(chip->dev, "Channel %d is out of range [0, %d]\n",
- chan_id, TADC_NUM_CH - 1);
+ pr_err("Channel %d is out of range [0, %d]\n",
+ chan_id, TADC_NUM_CH - 1);
return -EINVAL;
}
chan_data = &chip->chans[chan_id];
- switch (chan_id) {
- case TADC_THERM1:
- case TADC_THERM2:
+ if (chan_id == TADC_THERM1 || chan_id == TADC_THERM2) {
rc = of_property_read_u32(child,
"qcom,rbias", &chan_data->rbias);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read qcom,rbias rc=%d\n",
- rc);
+ pr_err("Couldn't read qcom,rbias rc=%d\n", rc);
return rc;
}
rc = of_property_read_u32(child,
"qcom,beta-coefficient", &beta);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read qcom,beta-coefficient rc=%d\n",
- rc);
+ pr_err("Couldn't read qcom,beta-coefficient rc=%d\n",
+ rc);
return rc;
}
rc = of_property_read_u32(child,
"qcom,rtherm-at-25degc", &rtherm);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read qcom,rtherm-at-25degc rc=%d\n",
+ pr_err("Couldn't read qcom,rtherm-at-25degc rc=%d\n",
rc);
return rc;
}
rc = tadc_set_therm_table(chan_data, beta, rtherm);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't set therm table rc=%d\n",
- rc);
+ pr_err("Couldn't set therm table rc=%d\n", rc);
return rc;
}
- break;
- default:
+ } else {
rc = of_property_read_s32(child, "qcom,scale",
- &chan_data->scale);
+ &chan_data->scale);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read scale rc=%d\n",
- rc);
+ pr_err("Couldn't read scale rc=%d\n", rc);
return rc;
}
of_property_read_s32(child, "qcom,offset",
- &chan_data->offset);
- break;
+ &chan_data->offset);
}
}
return rc;
}
+static int tadc_init_hw(struct tadc_chip *chip)
+{
+ int rc;
+
+ chip->chans[TADC_THERM1].thr[0].addr_lo =
+ TADC_CMP_THR1_CH1_CMP_LO_REG(chip);
+ chip->chans[TADC_THERM1].thr[0].addr_hi =
+ TADC_CMP_THR1_CH1_CMP_HI_REG(chip);
+ chip->chans[TADC_THERM1].thr[1].addr_lo =
+ TADC_CMP_THR2_CH1_CMP_LO_REG(chip);
+ chip->chans[TADC_THERM1].thr[1].addr_hi =
+ TADC_CMP_THR2_CH1_CMP_HI_REG(chip);
+ chip->chans[TADC_THERM1].thr[2].addr_lo =
+ TADC_CMP_THR3_CH1_CMP_LO_REG(chip);
+ chip->chans[TADC_THERM1].thr[2].addr_hi =
+ TADC_CMP_THR3_CH1_CMP_HI_REG(chip);
+ chip->chans[TADC_THERM1].thr[3].addr_lo =
+ TADC_CMP_THR4_CH1_CMP_LO_REG(chip);
+ chip->chans[TADC_THERM1].thr[3].addr_hi =
+ TADC_CMP_THR4_CH1_CMP_HI_REG(chip);
+
+ chip->chans[TADC_THERM2].thr[0].addr_lo =
+ TADC_CMP_THR1_CH2_CMP_LO_REG(chip);
+ chip->chans[TADC_THERM2].thr[0].addr_hi =
+ TADC_CMP_THR1_CH2_CMP_HI_REG(chip);
+ chip->chans[TADC_THERM2].thr[1].addr_lo =
+ TADC_CMP_THR2_CH2_CMP_LO_REG(chip);
+ chip->chans[TADC_THERM2].thr[1].addr_hi =
+ TADC_CMP_THR2_CH2_CMP_HI_REG(chip);
+ chip->chans[TADC_THERM2].thr[2].addr_lo =
+ TADC_CMP_THR3_CH2_CMP_LO_REG(chip);
+ chip->chans[TADC_THERM2].thr[2].addr_hi =
+ TADC_CMP_THR3_CH2_CMP_HI_REG(chip);
+
+ chip->chans[TADC_DIE_TEMP].thr[0].addr_lo =
+ TADC_CMP_THR1_CH3_CMP_LO_REG(chip);
+ chip->chans[TADC_DIE_TEMP].thr[0].addr_hi =
+ TADC_CMP_THR1_CH3_CMP_HI_REG(chip);
+ chip->chans[TADC_DIE_TEMP].thr[1].addr_lo =
+ TADC_CMP_THR2_CH3_CMP_LO_REG(chip);
+ chip->chans[TADC_DIE_TEMP].thr[1].addr_hi =
+ TADC_CMP_THR2_CH3_CMP_HI_REG(chip);
+ chip->chans[TADC_DIE_TEMP].thr[2].addr_lo =
+ TADC_CMP_THR3_CH3_CMP_LO_REG(chip);
+ chip->chans[TADC_DIE_TEMP].thr[2].addr_hi =
+ TADC_CMP_THR3_CH3_CMP_HI_REG(chip);
+
+ rc = tadc_write(chip, TADC_CMP_THR1_CMP_REG(chip), 0);
+ if (rc < 0) {
+ pr_err("Couldn't enable hardware triggers rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = tadc_write(chip, TADC_CMP_THR2_CMP_REG(chip), 0);
+ if (rc < 0) {
+ pr_err("Couldn't enable hardware triggers rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = tadc_write(chip, TADC_CMP_THR3_CMP_REG(chip), 0);
+ if (rc < 0) {
+ pr_err("Couldn't enable hardware triggers rc=%d\n", rc);
+ return rc;
+ }
+
+ /* enable all temperature hardware triggers */
+ rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip),
+ BIT(TADC_THERM1) |
+ BIT(TADC_THERM2) |
+ BIT(TADC_DIE_TEMP));
+ if (rc < 0) {
+ pr_err("Couldn't enable hardware triggers rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static const struct iio_info tadc_info = {
.read_raw = &tadc_read_raw,
+ .write_raw = &tadc_write_raw,
.driver_module = THIS_MODULE,
};
@@ -661,7 +999,7 @@ static int tadc_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
struct iio_dev *indio_dev;
struct tadc_chip *chip;
- int rc = 0, irq;
+ int rc, irq;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*chip));
if (!indio_dev)
@@ -673,11 +1011,12 @@ static int tadc_probe(struct platform_device *pdev)
rc = of_property_read_u32(node, "reg", &chip->tadc_base);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't read base address rc=%d\n", rc);
+ pr_err("Couldn't read base address rc=%d\n", rc);
return rc;
}
chip->tadc_cmp_base = chip->tadc_base + 0x100;
+ mutex_init(&chip->write_lock);
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
if (!chip->regmap) {
pr_err("Couldn't get regmap\n");
@@ -690,6 +1029,12 @@ static int tadc_probe(struct platform_device *pdev)
return rc;
}
+ rc = tadc_init_hw(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize hardware rc=%d\n", rc);
+ return rc;
+ }
+
irq = of_irq_get_byname(node, "eoc");
if (irq < 0) {
pr_err("Couldn't get eoc irq rc=%d\n", irq);
@@ -697,7 +1042,7 @@ static int tadc_probe(struct platform_device *pdev)
}
rc = devm_request_threaded_irq(chip->dev, irq, NULL, handle_eoc,
- IRQF_ONESHOT, "eoc", chip);
+ IRQF_ONESHOT, "eoc", chip);
if (rc < 0) {
pr_err("Couldn't request irq %d rc=%d\n", irq, rc);
return rc;
@@ -711,10 +1056,12 @@ static int tadc_probe(struct platform_device *pdev)
indio_dev->num_channels = ARRAY_SIZE(tadc_iio_chans);
rc = devm_iio_device_register(chip->dev, indio_dev);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't register IIO device rc=%d\n", rc);
+ if (rc < 0) {
+ pr_err("Couldn't register IIO device rc=%d\n", rc);
+ return rc;
+ }
- return rc;
+ return 0;
}
static int tadc_remove(struct platform_device *pdev)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 217e9306aa0f..407b2ef4d2e9 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -664,3 +664,21 @@ err_unlock:
return ret;
}
EXPORT_SYMBOL_GPL(iio_write_channel_raw);
+
+int iio_write_channel_processed(struct iio_channel *chan, int val)
+{
+ int ret;
+
+ mutex_lock(&chan->indio_dev->info_exist_lock);
+ if (chan->indio_dev->info == NULL) {
+ ret = -ENODEV;
+ goto err_unlock;
+ }
+
+ ret = iio_channel_write(chan, val, 0, IIO_CHAN_INFO_PROCESSED);
+err_unlock:
+ mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_processed);
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/misc/vl53L0/Makefile b/drivers/input/misc/vl53L0/Makefile
new file mode 100644
index 000000000000..4a6be55094b6
--- /dev/null
+++ b/drivers/input/misc/vl53L0/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the vl53L0 drivers.
+#
+
+# Each configuration option enables a list of files.
+#FEATURE_USE_CCI := false
+FEATURE_USE_CCI := true
+
+ifeq ($(FEATURE_USE_CCI), true)
+ccflags-y += -Idrivers/input/misc/vl53L0/inc -DCAMERA_CCI
+else
+ccflags-y += -Idrivers/input/misc/vl53L0/inc
+endif
+
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_STMVL53L0) += stmvl53l0.o
+stmvl53l0-objs := stmvl53l0_module.o stmvl53l0_module-i2c.o stmvl53l0_module-cci.o src/vl53l0_api_calibration.o src/vl53l0_api_core.o src/vl53l0_api_histogram.o src/vl53l0_api_ranging.o src/vl53l0_api_strings.o src/vl53l0_api.o src/vl53l0_platform.o src/vl53l0_i2c_platform.o src/vl53l0_port_i2c.o src/vl53l010_api.o src/vl53l010_tuning.o
diff --git a/drivers/input/misc/vl53L0/inc/vl53l010_api.h b/drivers/input/misc/vl53L0/inc/vl53l010_api.h
new file mode 100644
index 000000000000..282c65e33a93
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l010_api.h
@@ -0,0 +1,1476 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+/*
+ * @file vl53l0_api.h
+ * $Date: 2014-12-04 16:15:06 +0100 (Thu, 04 Dec 2014) $
+ * Revision: 1906
+ */
+
+
+
+#ifndef _VL53L010_API_H_
+#define _VL53L010_API_H_
+
+#include "vl53l010_device.h"
+#include "vl53l010_strings.h"
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef _MSC_VER
+# ifdef VL53L0_API_EXPORTS
+# define VL53L010_API __declspec(dllexport)
+# else
+# define VL53L010_API
+# endif
+#else
+# define VL53L010_API
+#endif
+
+
+/** @defgroup VL53L010_cut10_group VL53L010 cut1.0 Function Definition
+ * @brief VL53L010 cut1.0 Function Definition
+ * @{
+ */
+
+/** @defgroup VL53L010_general_group VL53L010 General Functions
+ * @brief VL53L010 General functions and definitions
+ * @{
+ */
+
+/**
+ * @brief Return the VL53L0 PAL Implementation Version
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param pVersion Pointer to current PAL Implementation Version
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetVersion(VL53L0_Version_t *pVersion);
+
+/**
+ * @brief Return the PAL Specification Version used for the current
+ * implementation.
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param pPalSpecVersion Pointer to current PAL Specification Version
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetPalSpecVersion(
+ VL53L0_Version_t *pPalSpecVersion);
+
+
+/**
+ * @brief Reads the Device information for given Device
+ *
+ * @note This function Access to the device.\n
+ * Use ProductRevisionMajor and ProductRevisionMinor to know the cut
+ * of the device used.
+ *
+ * @param Dev Device Handle
+ * @param pVL53L0_DeviceInfo Pointer to current device info for a given
+ * Device
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetDeviceInfo(VL53L0_DEV Dev,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo);
+
+
+/**
+ * @brief Read current status of the error register for the selected device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceErrorStatus Pointer to current error code of the device
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetDeviceErrorStatus(VL53L0_DEV Dev,
+ VL53L010_DeviceError * pDeviceErrorStatus);
+
+/**
+ * @brief Human readable error string for a given Error Code
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param ErrorCode The error code as stored on
+ * ::VL53L0_DeviceError
+ * @param pDeviceErrorString The error string corresponding to the
+ * ErrorCode
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetDeviceErrorString(
+ VL53L010_DeviceError ErrorCode,
+ char *pDeviceErrorString);
+
+
+/**
+ * @brief Human readable error string for current PAL error status
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param PalErrorCode The error code as stored on @a VL53L0_Error
+ * @param pPalErrorString The error string corresponding to the
+ * PalErrorCode
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetPalErrorString(VL53L0_Error PalErrorCode,
+ char *pPalErrorString);
+
+
+/**
+ * @brief Reads the internal state of the PAL for a given Device
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param Dev Device Handle
+ * @param pPalState Pointer to current state of the PAL for a
+ * given Device
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetPalState(VL53L0_DEV Dev,
+ VL53L0_State * pPalState);
+
+
+/**
+ * @brief Set the power mode for a given Device
+ * The power mode can be Standby or Idle. Different level of both Standby and
+ * Idle can exists.
+ * This function should not be used when device is in Ranging state.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param PowerMode The value of the power mode to set.
+ * see ::VL53L0_PowerModes Valid values are:
+ * VL53L0_POWERMODE_STANDBY_LEVEL1, VL53L0_POWERMODE_IDLE_LEVEL1
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when PowerMode
+ * is not in the supported list
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetPowerMode(VL53L0_DEV Dev,
+ VL53L0_PowerModes PowerMode);
+
+/**
+ * @brief Get the power mode for a given Device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pPowerMode Pointer to the current value of the power
+ * mode. see ::VL53L0_PowerModes. Valid values are:
+ * VL53L0_POWERMODE_STANDBY_LEVEL1, VL53L0_POWERMODE_IDLE_LEVEL1
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetPowerMode(VL53L0_DEV Dev,
+ VL53L0_PowerModes * pPowerMode);
+
+
+/**
+ * Set or over-hide part to part calibration offset
+ * \sa VL53L0_DataInit() VL53L0_GetOffsetCalibrationDataMicroMeter()
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param OffsetCalibrationDataMicroMeter Offset (in micrometer)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetOffsetCalibrationDataMicroMeter(
+ VL53L0_DEV Dev,
+ int32_t OffsetCalibrationDataMicroMeter);
+
+/**
+ * @brief Get part to part calibration offset
+ *
+ * @par Function Description
+ * Should only be used after a successful call to @a VL53L0_DataInit to backup
+ * device NVM value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pOffsetCalibrationDataMicroMeter Return part to part calibration
+ * offset from device (in micro meter)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetOffsetCalibrationDataMicroMeter(
+ VL53L0_DEV Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter);
+
+/**
+ * Set Group parameter Hold state
+ *
+ * @par Function Description
+ * Set or remove device internal group parameter hold
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param GroupParamHold Group parameter Hold state to be set (on/off)
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L010_API VL53L0_Error VL53L010_SetGroupParamHold(VL53L0_DEV Dev,
+ uint8_t GroupParamHold);
+
+/**
+ * @brief Get the maximal distance for actual setup
+ * @par Function Description
+ * Device must be initialized through @a VL53L0_SetParameters() prior calling
+ * this function.
+ *
+ * Any range value more than the value returned is to be considered as "no
+ * target detected"
+ * or "no target in detectable range"\n
+ * @warning The maximal distance depends on the setup
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pUpperLimitMilliMeter The maximal range limit for actual setup
+ * (in millimeter)
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L010_API VL53L0_Error VL53L010_GetUpperLimitMilliMeter(VL53L0_DEV Dev,
+ uint16_t *pUpperLimitMilliMeter);
+
+/** @} VL53L010_general_group */
+
+
+/** @defgroup VL53L010_init_group VL53L010 Init Functions
+ * @brief VL53L010 Init Functions
+ * @{
+ */
+
+/**
+ * @brief Set new device address
+ *
+ * After completion the device will answer to the new address programmed. This
+ * function should be called when several devices are used in parallel
+ * before start programming the sensor.
+ * When a single device us used, there is no need to call this function.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param DeviceAddress The new Device address
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetDeviceAddress(VL53L0_DEV Dev,
+ uint8_t DeviceAddress);
+
+/**
+ *
+ * @brief One time device initialization
+ *
+ * To be called once and only once after device is brought out of reset (Chip
+ * enable) and booted see @a VL53L0_WaitDeviceBooted()
+ *
+ * @par Function Description
+ * When not used after a fresh device "power up" or reset, it may return @a
+ * #VL53L0_ERROR_CALIBRATION_WARNING
+ * meaning wrong calibration data may have been fetched from device that can
+ * result in ranging offset error\n
+ * If application cannot execute device reset or need to run VL53L0_DataInit
+ * multiple time
+ * then it must ensure proper offset calibration saving and restore on its own
+ * by using @a VL53L0_GetOffsetCalibrationData() on first power up and then @a
+ * VL53L0_SetOffsetCalibrationData() in all subsequent init
+ * This function will change the VL53L0_State from VL53L0_STATE_POWERDOWN to
+ * VL53L0_STATE_WAIT_STATICINIT.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_DataInit(VL53L0_DEV Dev);
+
+/**
+ * @brief Do basic device init (and eventually patch loading)
+ * This function will change the VL53L0_State from VL53L0_STATE_WAIT_STATICINIT
+ * to VL53L0_STATE_IDLE.
+ * In this stage all defalut setting will be applied.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_StaticInit(VL53L0_DEV Dev);
+
+/**
+ * @brief Wait for device booted after chip enable (hardware standby)
+ * This function can be run only when VL53L0_State is VL53L0_STATE_POWERDOWN.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ *
+ */
+VL53L010_API VL53L0_Error VL53L010_WaitDeviceBooted(VL53L0_DEV Dev);
+
+/**
+ * @brief Do an hard reset or soft reset (depending on implementation) of the
+ * device \n
+ * After call of this function, device must be in same state as right after a
+ * power-up sequence.
+ * This function will change the VL53L0_State to VL53L0_STATE_POWERDOWN.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_ResetDevice(VL53L0_DEV Dev);
+
+/** @} VL53L010_init_group */
+
+
+/** @defgroup VL53L010_parameters_group VL53L010 Parameters Functions
+ * @brief VL53L010 Functions used to prepare and setup the device
+ * @{
+ */
+
+/**
+ * @brief Prepare device for operation
+ * @par Function Description
+ * Update device with provided parameters
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceParameters Pointer to store current device parameters.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetDeviceParameters(VL53L0_DEV Dev,
+ const VL53L0_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief Retrieve current device parameters
+ * @par Function Description
+ * Get actual parameters of the device
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceParameters Pointer to store current device parameters.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetDeviceParameters(VL53L0_DEV Dev,
+ VL53L0_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief Set a new device mode
+ * @par Function Description
+ * Set device to a new mode (ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode New device mode to apply
+ * Valid values are:
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * VL53L0_DEVICEMODE_SINGLE_HISTOGRAM
+ * (functionality not available)
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * DeviceMode is not in the supported list
+ */
+VL53L010_API VL53L0_Error VL53L010_SetDeviceMode(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode);
+
+/**
+ * @brief Get current new device mode
+ * @par Function Description
+ * Get actual mode of the device(ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceMode Pointer to current apply mode value
+ * Valid values are:
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * VL53L0_DEVICEMODE_SINGLE_HISTOGRAM
+ * (functionality not available)
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * DeviceMode is not in the supported list
+ */
+VL53L010_API VL53L0_Error VL53L010_GetDeviceMode(VL53L0_DEV Dev,
+ VL53L0_DeviceModes * pDeviceMode);
+
+/**
+ * @brief Set a new Histogram mode
+ * @par Function Description
+ * Set device to a new Histogram mode
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param HistogramMode New device mode to apply
+ * Valid values are:
+ * VL53L0_HISTOGRAMMODE_DISABLED
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * HistogramMode is not in the supported list
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes HistogramMode);
+
+/**
+ * @brief Get current new device mode
+ * @par Function Description
+ * Get current Histogram mode of a Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMode Pointer to current Histogram Mode value
+ * Valid values are:
+ * VL53L0_HISTOGRAMMODE_DISABLED
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes * pHistogramMode);
+
+/**
+ * @brief Set Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Defines the maximum time allowed by the user to the device to run a full
+ * ranging sequence
+ * for the current mode (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param MeasurementTimingBudgetMicroSeconds Max measurement time in
+ * microseconds.
+ * Valid values are:
+ * >= 17000 microseconds when
+ * wraparound is enabled
+ * >= 12000 microseconds when
+ * wraparound is disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned if
+ * MeasurementTimingBudgetMicroSeconds is out of range
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetMeasurementTimingBudgetMicroSeconds(
+ VL53L0_DEV Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds);
+
+/**
+ * @brief Get Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Returns the programmed the maximum time allowed by the user to the device to
+ * run a full ranging sequence
+ * for the current mode (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in
+ * microseconds.
+ * Valid values are:
+ * >= 17000 microseconds when
+ * wraparound is enabled
+ * >= 12000 microseconds when
+ * wraparound is disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetMeasurementTimingBudgetMicroSeconds(
+ VL53L0_DEV Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds);
+
+/**
+ * Program continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param InterMeasurementPeriodMilliSeconds Requires Inter-Measurement
+ * Period in milliseconds.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetInterMeasurementPeriodMilliSeconds(
+ VL53L0_DEV Dev,
+ uint32_t InterMeasurementPeriodMilliSeconds);
+
+/**
+ * Get continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed
+ * Inter-Measurement Period in milliseconds.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetInterMeasurementPeriodMilliSeconds(
+ VL53L0_DEV Dev,
+ uint32_t *pInterMeasurementPeriodMilliSeconds);
+
+/**
+ * @brief Enable/Disable Cross talk compensation feature
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param XTalkCompensationEnable Cross talk compensation to be set
+ * 0=disabled else = enabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetXTalkCompensationEnable(
+ VL53L0_DEV Dev, uint8_t XTalkCompensationEnable);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pXTalkCompensationEnable Pointer to the Cross talk compensation
+ * state 0=disabled or 1 = enabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetXTalkCompensationEnable(
+ VL53L0_DEV Dev, uint8_t *pXTalkCompensationEnable);
+
+/**
+ * @brief Set Cross talk compensation rate
+ *
+ * @par Function Description
+ * Set Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param XTalkCompensationRateMegaCps Compensation rate in Mega counts per
+ * second (16.16 fix point) see datasheet for details
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetXTalkCompensationRateMegaCps(
+ VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCompensationRateMegaCps);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @par Function Description
+ * Get Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pXTalkCompensationRateMegaCps Pointer to Compensation rate in Mega
+ * counts per second (16.16 fix point) see datasheet for details
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetXTalkCompensationRateMegaCps(
+ VL53L0_DEV Dev,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps);
+
+
+/**
+ * @brief Get the number of the check limit managed by a given Device
+ *
+ * @par Function Description
+ * This function give the number of the check limit managed by the Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param pNumberOfLimitCheck Pointer to the number of check limit.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetNumberOfLimitCheck(
+ uint16_t *pNumberOfLimitCheck);
+
+/**
+ * @brief Return a description string for a given limit check number
+ *
+ * @par Function Description
+ * This function returns a description string for a given limit check number.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID (0<= LimitCheckId <
+ * VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckString Pointer to the description string of
+ * the given check limit.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when
+ * LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetLimitCheckInfo(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, char *pLimitCheckString);
+
+
+/**
+ * @brief Enable/Disable a specific limit check
+ *
+ * @par Function Description
+ * This function Enable/Disable a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID (0<= LimitCheckId <
+ * VL53L0_GetNumberOfLimitCheck() ).
+ * @param LimitCheckEnable if 1 the check limit corresponding to
+ * LimitCheckId is Enabled
+ * if 0 the check limit corresponding to
+ * LimitCheckId is disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when
+ * LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetLimitCheckEnable(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, uint8_t LimitCheckEnable);
+
+
+/**
+ * @brief Get specific limit check enable state
+ *
+ * @par Function Description
+ * This function get the enable state of a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID (0<= LimitCheckId <
+ * VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckEnable Pointer to the check limit enable
+ * value.
+ * if 1 the check limit corresponding to
+ * LimitCheckId is Enabled
+ * if 0 the check limit corresponding to
+ * LimitCheckId is disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when
+ * LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetLimitCheckEnable(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckEnable);
+
+/**
+ * @brief Set a specific limit check value
+ *
+ * @par Function Description
+ * This function set a specific limit check value.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID (0<= LimitCheckId <
+ * VL53L0_GetNumberOfLimitCheck() ).
+ * @param LimitCheckValue Limit check Value for a given
+ * LimitCheckId
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when either
+ * LimitCheckId or LimitCheckValue value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetLimitCheckValue(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, FixPoint1616_t LimitCheckValue);
+
+/**
+ * @brief Get a specific limit check value
+ *
+ * @par Function Description
+ * This function get a specific limit check value from device then it updates
+ * internal values and check enables.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID (0<= LimitCheckId <
+ * VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckValue Pointer to Limit check Value for a
+ * given LimitCheckId.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when
+ * LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetLimitCheckValue(VL53L0_DEV Dev,
+ uint16_t LimitCheckId,
+ FixPoint1616_t *pLimitCheckValue);
+
+
+/**
+ * @brief Get the current value of the signal used for the limit check
+ *
+ * @par Function Description
+ * This function get a the current value of the signal used for the limit check.
+ * To obtain the latest value you should run a ranging before.
+ * The value reported is linked to the limit check identified with the
+ * LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID (0<= LimitCheckId <
+ * VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckCurrent Pointer to current Value for a
+ * given LimitCheckId.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when
+ * LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetLimitCheckCurrent(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckCurrent);
+
+/**
+ * @brief Enable (or disable) Wrap around Check
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param WrapAroundCheckEnable Wrap around Check to be set 0=disabled,
+ * other = enabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetWrapAroundCheckEnable(VL53L0_DEV Dev,
+ uint8_t WrapAroundCheckEnable);
+
+/**
+ * @brief Get setup of Wrap around Check
+ *
+ * @par Function Description
+ * This function get the wrapAround check enable parameters
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pWrapAroundCheckEnable Pointer to the Wrap around Check state
+ * 0=disabled or 1 = enabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetWrapAroundCheckEnable(VL53L0_DEV Dev,
+ uint8_t *pWrapAroundCheckEnable);
+
+/** @} VL53L010_parameters_group */
+
+
+/** @defgroup VL53L010_measurement_group VL53L010 Measurement Functions
+ * @brief VL53L010 Functions used for the measurements
+ * @{
+ */
+
+/**
+ * @brief Single shot measurement.
+ *
+ * @par Function Description
+ * Perform simple measurement sequence (Start measure, Wait measure to end, and
+ * returns when measurement is done).
+ * Once function returns, user can get valid data by calling
+ * VL53L0_GetRangingMeasurement or VL53L0_GetHistogramMeasurement depending on
+ * defined measurement mode
+ * User should Clear the interrupt in case this are enabled by using the
+ * function VL53L0_ClearInterruptMask().
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_PerformSingleMeasurement(VL53L0_DEV Dev);
+
+/**
+ * @brief Perform Reference Calibration
+ *
+ * @details Perform a reference calibration of the Device.
+ * This function should be run from time to time before doing a ranging
+ * measurement.
+ * This function will launch a special ranging measurement, so if interrupt are
+ * enable an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_PerformRefCalibration(VL53L0_DEV Dev);
+
+/**
+ * @brief Perform XTalk Calibration
+ *
+ * @details Perform a XTalk calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts are enabled
+ * an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the XTalk compensation and it
+ * will enable the cross talk before exit.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param XTalkCalDistance XTalkCalDistance value used for the
+ * XTalk computation.
+ * @param pXTalkCompensationRateMegaCps Pointer to new XTalkCompensation
+ * value.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_PerformXTalkCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCalDistance,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps);
+
+/**
+ * @brief Perform Offset Calibration
+ *
+ * @details Perform a Offset calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts are
+ * enabled an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the Offset calibration value and
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function does not change the device mode.
+ *
+ * @param Dev Device Handle
+ * @param CalDistanceMilliMeter Calibration distance value used for the
+ * offset compensation.
+ * @param pOffsetMicroMeter Pointer to new Offset value computed by the
+ * function.
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_PerformOffsetCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t CalDistanceMilliMeter, int32_t *pOffsetMicroMeter);
+
+/**
+ * @brief Start device measurement
+ *
+ * @details Started measurement will depend on device parameters set through @a
+ * VL53L0_SetParameters()
+ * This is a non-blocking function
+ * This function will change the VL53L0_State from VL53L0_STATE_IDLE to
+ * VL53L0_STATE_RUNNING.
+ *
+ * @note This function Access to the device
+ *
+
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * DeviceMode programmed with @a VL53L0_SetDeviceMode is not in the supported
+ * list:
+ * Supported mode are:
+ * VL53L0_DEVICEMODE_SINGLE_RANGING, VL53L0_DEVICEMODE_CONTINUOUS_RANGING,
+ * VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * @return VL53L0_ERROR_TIME_OUT Time out on start measurement
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_StartMeasurement(VL53L0_DEV Dev);
+
+/**
+ * @brief Stop device measurement
+ *
+ * @details Will set the device in standby mode at end of current measurement \n
+ * Not necessary in single mode as device shall return automatically
+ * in standby mode at end of measurement.
+ * This function will change the VL53L0_State from
+ * VL53L0_STATE_RUNNING to VL53L0_STATE_IDLE.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_StopMeasurement(VL53L0_DEV Dev);
+
+/**
+ * @brief Return Measurement Data Ready
+ *
+ * @par Function Description
+ * This function indicate that a measurement data is ready.
+ * This function check if interrupt mode is used then check is done accordingly.
+ * If perform function clear the interrupt, this function will not work, like
+ * in case of @a VL53L0_PerformSingleRangingMeasurement().
+ * The previous function is blocking function, VL53L0_GetMeasurementDataReady
+ * is used for non-blocking capture.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementDataReady Pointer to Measurement Data Ready. 0=data
+ * not ready, 1 = data ready
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetMeasurementDataReady(VL53L0_DEV Dev,
+ uint8_t *pMeasurementDataReady);
+
+/**
+ * @brief Wait for device ready for a new measurement command. Blocking
+ * function.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param MaxLoop Max Number of polling loop (timeout).
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L010_API VL53L0_Error VL53L010_WaitDeviceReadyForNewMeasurement(
+ VL53L0_DEV Dev,
+ uint32_t MaxLoop);
+
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement
+ * @warning USER should take care about @a VL53L0_GetNumberOfROIZones() before
+ * get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data structure used
+ * in the measurement function.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pRangingMeasurementData Pointer to the data structure to fill up.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetRangingMeasurementData(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Histogram measurement
+ * @warning USER should take care about @a VL53L0_GetNumberOfROIZones() before
+ * get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data structure used
+ * in the measurement function.
+ * @note This function is not Implemented
+ * @param Dev Device Handle
+ * @param pHistogramMeasurementData Pointer to the data structure to fill
+ * up.
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L010_API VL53L0_Error VL53L010_GetHistogramMeasurementData(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+/**
+ * @brief Performs a single ranging measurement and retrieve the ranging
+ * measurement data
+ *
+ * @par Function Description
+ * This function will change the device mode to
+ * VL53L0_DEVICEMODE_SINGLE_RANGING with @a VL53L0_SetDeviceMode(),
+ * It performs measurement with @a VL53L0_PerformSingleMeasurement()
+ * It get data from last successful Ranging measurement with @a
+ * VL53L0_GetRangingMeasurementData.
+ * Finally it clear the interrupt with @a VL53L0_ClearInterruptMask().
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param pRangingMeasurementData Pointer to the data structure to fill up.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_PerformSingleRangingMeasurement(
+ VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Performs a single histogram measurement and retrieve the histogram
+ * measurement data
+ * Is equivalent to VL53L0_PerformSingleMeasurement +
+ * VL53L0_GetHistogramMeasurementData
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement.
+ * This function will clear the interrupt in case of these are enabled.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMeasurementData Pointer to the data structure to fill
+ * up.
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L010_API VL53L0_Error VL53L010_PerformSingleHistogramMeasurement(
+ VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+
+
+/**
+ * @brief Set the number of ROI Zones to be used for a specific Device
+ *
+ * @par Function Description
+ * Set the number of ROI Zones to be used for a specific Device.
+ * The programmed value should be less than the max number of ROI Zones given
+ * with @a VL53L0_GetMaxNumberOfROIZones().
+ * This version of API manage only one zone.
+ *
+ * @param Dev Device Handle
+ * @param NumberOfROIZones Number of ROI Zones to be used for a
+ * specific Device.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned if
+ * NumberOfROIZones != 1
+ */
+VL53L010_API VL53L0_Error VL53L010_SetNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t NumberOfROIZones);
+
+/**
+ * @brief Get the number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get number of ROI Zones managed by the Device
+ * USER should take care about @a VL53L0_GetNumberOfROIZones() before get data
+ * after a perform measurement.
+ * PAL will fill a NumberOfROIZones times the corresponding data structure used
+ * in the measurement function.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pNumberOfROIZones Pointer to the Number of ROI Zones
+ * value.
+ * @return VL53L0_ERROR_NONE Success
+ */
+VL53L010_API VL53L0_Error VL53L010_GetNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t *pNumberOfROIZones);
+
+/**
+ * @brief Get the Maximum number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get Maximum number of ROI Zones managed by the Device.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMaxNumberOfROIZones Pointer to the Maximum Number of ROI
+ * Zones value.
+ * @return VL53L0_ERROR_NONE Success
+ */
+VL53L010_API VL53L0_Error VL53L010_GetMaxNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t *pMaxNumberOfROIZones);
+
+
+/** @} VL53L010_measurement_group */
+
+
+/** @defgroup VL53L010_interrupt_group VL53L010 Interrupt Functions
+ * @brief VL53L010 Functions used for interrupt managements
+ * @{
+ */
+
+/**
+ * @brief Set the configuration of GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param Pin ID of the GPIO Pin
+ * @param Functionality Select Pin functionality. Refer to
+ * ::VL53L0_GpioFunctionality
+ * @param DeviceMode Device Mode associated to the Gpio.
+ * @param Polarity Set interrupt polarity. Active high or active
+ * low see ::VL53L0_InterruptPolarity
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_GPIO_NOT_EXISTING Only Pin=0 is
+ * accepted.
+ * @return VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs
+ * when Functionality programmed is not in the supported list:
+ * Supported value
+ * are:
+ *
+ * VL53L0_GPIOFUNCTIONALITY_OFF, VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ *
+ * VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes DeviceMode,
+ VL53L0_GpioFunctionality Functionality,
+ VL53L0_InterruptPolarity Polarity);
+
+
+/**
+ * @brief Get current configuration for GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param Pin ID of the GPIO Pin
+ * @param pDeviceMode Pointer to Device Mode associated to the Gpio.
+ * @param pFunctionality Pointer to Pin functionality.
+ * Refer to ::VL53L0_GpioFunctionality
+ * @param pPolarity Pointer to interrupt polarity. Active high or
+ * active low see ::VL53L0_InterruptPolarity
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted.
+ * @return VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs
+ * when Functionality programmed is not in the supported list:
+ * Supported value are:
+ * VL53L0_GPIOFUNCTIONALITY_OFF, VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ * VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes * pDeviceMode,
+ VL53L0_GpioFunctionality * pFunctionality,
+ VL53L0_InterruptPolarity * pPolarity);
+
+/**
+ * @brief Set low and high Interrupt thresholds for a given mode (ranging, ALS,
+ * ...) for a given device
+ *
+ * @par Function Description
+ * Set low and high Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode Device Mode for which change thresholds
+ * @param ThresholdLow Low threshold (mm, lux ..., depending on the
+ * mode)
+ * @param ThresholdHigh High threshold (mm, lux ..., depending on the
+ * mode)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetInterruptThresholds(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode,
+ FixPoint1616_t ThresholdLow,
+ FixPoint1616_t ThresholdHigh);
+
+/**
+ * @brief Get high and low Interrupt thresholds for a given mode (ranging,
+ * ALS, ...) for a given device
+ *
+ * @par Function Description
+ * Get high and low Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode Device Mode from which read thresholds
+ * @param pThresholdLow Low threshold (mm, lux ..., depending on the
+ * mode)
+ * @param pThresholdHigh High threshold (mm, lux ..., depending on the
+ * mode)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetInterruptThresholds(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode,
+ FixPoint1616_t *pThresholdLow,
+ FixPoint1616_t *pThresholdHigh);
+
+/**
+ * @brief Clear given system interrupt condition
+ *
+ * @par Function Description
+ * Clear given interrupt(s).
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param InterruptMask Mask of interrupts to clear
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_ClearInterruptMask(VL53L0_DEV Dev,
+ uint32_t InterruptMask);
+
+/**
+ * @brief Return device interrupt status
+ *
+ * @par Function Description
+ * Returns currently raised interrupts by the device.
+ * User shall be able to activate/deactivate interrupts through
+ * @a VL53L0_SetGpioConfig()
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pInterruptMaskStatus Pointer to status variable to update
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetInterruptMaskStatus(VL53L0_DEV Dev,
+ uint32_t *pInterruptMaskStatus);
+
+
+/**
+ * @brief Configure ranging interrupt reported to system
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param InterruptMask Mask of interrupt to Enable/disable
+ * (0:interrupt disabled or 1: interrupt enabled)
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L010_API VL53L0_Error VL53L010_EnableInterruptMask(VL53L0_DEV Dev,
+ uint32_t InterruptMask);
+
+
+/** @} VL53L010_interrupt_group */
+
+
+/** @defgroup VL53L010_SPADfunctions_group VL53L010 SPAD Functions
+ * @brief VL53L010 Functions used for SPAD managements
+ * @{
+ */
+
+
+
+/**
+ * @brief Set the SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param SpadAmbientDamperThreshold SPAD Ambient Damper Threshold value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetSpadAmbientDamperThreshold(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperThreshold);
+
+/**
+ * @brief Get the current SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pSpadAmbientDamperThreshold Pointer to programmed SPAD Ambient
+ * Damper Threshold value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetSpadAmbientDamperThreshold(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperThreshold);
+
+
+/**
+ * @brief Set the SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param SpadAmbientDamperFactor SPAD Ambient Damper Factor value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_SetSpadAmbientDamperFactor(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperFactor);
+
+/**
+ * @brief Get the current SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pSpadAmbientDamperFactor Pointer to programmed SPAD Ambient
+ * Damper Factor value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L010_API VL53L0_Error VL53L010_GetSpadAmbientDamperFactor(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperFactor);
+
+
+/** @} VL53L010_SPADfunctions_group */
+
+/** @} VL53L010_cut10_group */
+#define VL53L010_EXTERNAL
+
+
+/* Internal functions declaration */
+VL53L010_EXTERNAL VL53L0_Error VL53L010_get_vcsel_pulse_period(VL53L0_DEV Dev,
+ uint8_t *pVCSELPulsePeriod,
+ uint8_t RangeIndex);
+VL53L010_EXTERNAL uint8_t VL53L010_encode_vcsel_period(
+ uint8_t vcsel_period_pclks);
+VL53L010_EXTERNAL uint8_t VL53L010_decode_vcsel_period(uint8_t
+ vcsel_period_reg);
+VL53L010_EXTERNAL uint16_t VL53L010_calc_encoded_timeout(VL53L0_DEV Dev,
+ uint32_t
+ timeout_period_us,
+ uint8_t vcsel_period);
+VL53L010_EXTERNAL uint32_t VL53L010_calc_ranging_wait_us(VL53L0_DEV Dev,
+ uint16_t
+ timeout_overall_periods,
+ uint8_t vcsel_period);
+VL53L010_EXTERNAL VL53L0_Error VL53L010_load_additional_settings1(VL53L0_DEV
+ Dev);
+VL53L010_EXTERNAL VL53L0_Error VL53L010_load_additional_settings3(VL53L0_DEV
+ Dev);
+VL53L010_EXTERNAL VL53L0_Error VL53L010_check_part_used(VL53L0_DEV Dev,
+ uint8_t *Revision,
+ VL53L0_DeviceInfo_t *
+ pVL53L0_DeviceInfo);
+VL53L010_EXTERNAL VL53L0_Error VL53L010_get_info_from_device(VL53L0_DEV Dev);
+VL53L010_EXTERNAL VL53L0_Error VL53L010_device_read_strobe(VL53L0_DEV Dev);
+VL53L010_EXTERNAL VL53L0_Error VL53L010_get_pal_range_status(VL53L0_DEV Dev,
+ uint8_t
+ DeviceRangeStatus,
+ FixPoint1616_t
+ SignalRate,
+ FixPoint1616_t
+ CrosstalkCompensation,
+ uint16_t
+ EffectiveSpadRtnCount,
+ VL53L0_RangingMeasurementData_t
+ *
+ pRangingMeasurementData,
+ uint8_t *
+ pPalRangeStatus);
+
+
+VL53L010_EXTERNAL uint32_t VL53L010_calc_macro_period_ps(VL53L0_DEV Dev,
+ uint8_t vcsel_period);
+VL53L010_EXTERNAL uint16_t VL53L010_encode_timeout(uint32_t timeout_mclks);
+VL53L010_EXTERNAL uint32_t VL53L010_decode_timeout(uint16_t encoded_timeout);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L010_API_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l010_device.h b/drivers/input/misc/vl53L0/inc/vl53l010_device.h
new file mode 100644
index 000000000000..5d36ab0f65e4
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l010_device.h
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**
+ * Device specific defines. To be adapted by implementer for the targeted
+ * device.
+ */
+
+#ifndef _VL53L010_DEVICE_H_
+#define _VL53L010_DEVICE_H_
+
+#include "vl53l0_types.h"
+
+/** @defgroup VL53L010_SpecDefines_group VL53L010 cut1.0 Device Specific Defines
+ * @brief VL53L010 cut1.0 Device Specific Defines
+ * @{
+ */
+
+/** @defgroup VL53L010_DeviceError_group Device Error
+ * @brief Device Error code
+ *
+ * This enum is Device specific it should be updated in the implementation
+ * Use @a VL53L010_GetStatusErrorString() to get the string.
+ * It is related to Status Register of the Device.
+ * @{
+ */
+typedef uint8_t VL53L010_DeviceError;
+
+#define VL53L010_DEVICEERROR_NONE ((VL53L010_DeviceError) 0)
+#define VL53L010_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \
+ ((VL53L010_DeviceError) 1)
+#define VL53L010_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \
+ ((VL53L010_DeviceError) 2)
+#define VL53L010_DEVICEERROR_NOVHVVALUEFOUND \
+ ((VL53L010_DeviceError) 3)
+#define VL53L010_DEVICEERROR_MSRCNOTARGET \
+ ((VL53L010_DeviceError) 4)
+#define VL53L010_DEVICEERROR_MSRCMINIMUMSNR \
+ ((VL53L010_DeviceError) 5)
+#define VL53L010_DEVICEERROR_MSRCWRAPAROUND \
+ ((VL53L010_DeviceError) 6)
+#define VL53L010_DEVICEERROR_TCC \
+ ((VL53L010_DeviceError) 7)
+#define VL53L010_DEVICEERROR_RANGEAWRAPAROUND ((VL53L010_DeviceError)8)
+#define VL53L010_DEVICEERROR_RANGEBWRAPAROUND ((VL53L010_DeviceError)9)
+#define VL53L010_DEVICEERROR_MINCLIP ((VL53L010_DeviceError) 10)
+#define VL53L010_DEVICEERROR_RANGECOMPLETE ((VL53L010_DeviceError) 11)
+#define VL53L010_DEVICEERROR_ALGOUNDERFLOW ((VL53L010_DeviceError) 12)
+#define VL53L010_DEVICEERROR_ALGOOVERFLOW ((VL53L010_DeviceError) 13)
+#define VL53L010_DEVICEERROR_FINALSNRLIMIT ((VL53L010_DeviceError) 14)
+#define VL53L010_DEVICEERROR_NOTARGETIGNORE ((VL53L010_DeviceError) 15)
+
+/** @} VL53L010_DeviceError_group */
+
+/** @defgroup VL53L010_CheckEnable_group Check Enable list
+ * @brief Check Enable code
+ *
+ * Define used to specify the LimitCheckId.
+ * Use @a VL53L010_GetLimitCheckInfo() to get the string.
+ * @{
+ */
+
+#define VL53L010_CHECKENABLE_SIGMA_FINAL_RANGE 0
+#define VL53L010_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1
+#define VL53L010_CHECKENABLE_NUMBER_OF_CHECKS 2
+
+/** @} VL53L010_CheckEnable_group */
+
+/** @defgroup VL53L010_GpioFunctionality_group Gpio Functionality
+ * @brief Defines the different functionalities for the device GPIO(s)
+ * @{
+ */
+typedef uint8_t VL53L010_GpioFunctionality;
+
+#define VL53L010_GPIOFUNCTIONALITY_OFF \
+ ((VL53L010_GpioFunctionality) 0)/*!< NO Interrupt */
+#define VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW \
+ ((VL53L010_GpioFunctionality) 1)/*!< Level Low (value < thresh_low) */
+#define VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH \
+ ((VL53L010_GpioFunctionality) 2)/*!< Level High (value>thresh_high) */
+/*!< Out Of Window (value < thresh_low OR value > thresh_high) */
+#define VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT \
+ ((VL53L010_GpioFunctionality) 3)
+#define VL53L010_GPIOFUNCTIONALITY_NEW_MEASURE_READY \
+ ((VL53L010_GpioFunctionality) 4) /*!< New Sample Ready */
+
+/** @} VL53L010_GpioFunctionality_group */
+
+/* Device register map */
+
+/** @defgroup VL53L010_DefineRegisters_group Define Registers
+ * @brief List of all the defined registers
+ * @{
+ */
+#define VL53L010_REG_SYSRANGE_START 0x000
+ /** mask existing bit in #VL53L010_REG_SYSRANGE_START*/
+#define VL53L010_REG_SYSRANGE_MODE_MASK 0x0F
+ /** bit 0 in #VL53L010_REG_SYSRANGE_START write 1 toggle state in
+ * continuous mode and arm next shot in single shot mode
+ */
+#define VL53L010_REG_SYSRANGE_MODE_START_STOP 0x01
+ /** bit 1 write 0 in #VL53L010_REG_SYSRANGE_START set single shot mode */
+#define VL53L010_REG_SYSRANGE_MODE_SINGLESHOT 0x00
+ /** bit 1 write 1 in #VL53L010_REG_SYSRANGE_START set back-to-back
+ * operation mode
+ */
+#define VL53L010_REG_SYSRANGE_MODE_BACKTOBACK 0x02
+ /** bit 2 write 1 in #VL53L010_REG_SYSRANGE_START set timed operation
+ * mode
+ */
+#define VL53L010_REG_SYSRANGE_MODE_TIMED 0x04
+ /** bit 3 write 1 in #VL53L010_REG_SYSRANGE_START set histogram
+ * operation mode
+ */
+#define VL53L010_REG_SYSRANGE_MODE_HISTOGRAM 0x08
+
+#define VL53L010_REG_SYSTEM_THRESH_HIGH 0x000C /* NOSLC 2 bytes */
+#define VL53L010_REG_SYSTEM_THRESH_LOW 0x000E /* NOSLC 2 bytes */
+
+/* FPGA bitstream */
+#define VL53L010_REG_SYSTEM_SEQUENCE_CONFIG 0x0001
+#define VL53L010_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x0004
+
+#define VL53L010_REG_SYSTEM_REPORT_REQUEST 0x0009
+#define VL53L010_REG_SYSTEM_RANGEA_DATA 0x04
+#define VL53L010_REG_SYSTEM_RANGEB_DATA 0x05
+
+#define VL53L010_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x000A
+#define VL53L010_REG_SYSTEM_INTERRUPT_GPIO_DISABLED 0x00
+#define VL53L010_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_LOW 0x01
+#define VL53L010_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_HIGH 0x02
+#define VL53L010_REG_SYSTEM_INTERRUPT_GPIO_OUT_OF_WINDOW 0x03
+#define VL53L010_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY 0x04
+
+#define VL53L010_REG_GPIO_HV_MUX_ACTIVE_HIGH 0x0084
+
+#define VL53L010_REG_SYSTEM_INTERRUPT_CLEAR 0x000B
+
+/* Result registers */
+#define VL53L010_REG_RESULT_INTERRUPT_STATUS 0x0013
+#define VL53L010_REG_RESULT_RANGE_STATUS 0x0014
+
+#define VL53L010_REG_RESULT_SIGNAL_COUNT_RATE_RET 0x001A
+#define VL53L010_REG_RESULT_AMBIENT_COUNT_RATE_RET 0x001C
+#define VL53L010_REG_RESULT_FINAL_RANGE 0x001E
+
+/* Algo register */
+#define VL53L010_REG_ALGO_CROSSTALK_COMPENSATION_RATE 0x0020
+#define VL53L010_REG_ALGO_RANGE_IGNORE_VALID_HEIGHT 0x0025
+#define VL53L010_REG_ALGO_RANGE_IGNORE_THRESHOLD 0x0026
+#define VL53L010_REG_ALGO_SNR_RATIO 0x0027
+#define VL53L010_REG_ALGO_RANGE_CHECK_ENABLES 0x0028
+
+#define VL53L010_REG_ALGO_PART_TO_PART_RANGE_OFFSET 0x0029
+
+#define VL53L010_REG_I2C_SLAVE_DEVICE_ADDRESS 0x008a
+
+/* MSRC registers */
+#define VL53L010_REG_MSRC_CONFIG_COUNT 0x0044
+#define VL53L010_REG_MSRC_CONFIG_TIMEOUT 0x0046
+#define VL53L010_REG_MSRC_CONFIG_MIN_SNR 0x0055
+#define VL53L010_REG_MSRC_CONFIG_VALID_PHASE_LOW 0x0047
+#define VL53L010_REG_MSRC_CONFIG_VALID_PHASE_HIGH 0x0048
+
+/* RANGE A registers */
+#define VL53L010_REG_RNGA_CONFIG_VCSEL_PERIOD 0x0050
+#define VL53L010_REG_RNGA_TIMEOUT_MSB 0x0051
+#define VL53L010_REG_RNGA_TIMEOUT_LSB 0x0052
+#define VL53L010_REG_RNGA_CONFIG_VALID_PHASE_LOW 0x0056
+#define VL53L010_REG_RNGA_CONFIG_VALID_PHASE_HIGH 0x0057
+
+/* RANGE B1 registers */
+#define VL53L010_REG_RNGB1_CONFIG_VCSEL_PERIOD 0x0060
+#define VL53L010_REG_RNGB1_TIMEOUT_MSB 0x0061
+#define VL53L010_REG_RNGB1_TIMEOUT_LSB 0x0062
+#define VL53L010_REG_RNGB1_CONFIG_VALID_PHASE_LOW 0x0066
+#define VL53L010_REG_RNGB1_CONFIG_VALID_PHASE_HIGH 0x0067
+
+/* RANGE B2 registers */
+#define VL53L010_REG_RNGB2_CONFIG_VCSEL_PERIOD 0x0070
+#define VL53L010_REG_RNGB2_TIMEOUT_MSB 0x0071
+#define VL53L010_REG_RNGB2_TIMEOUT_LSB 0x0072
+#define VL53L010_REG_RNGB2_CONFIG_VALID_PHASE_LOW 0x0076
+#define VL53L010_REG_RNGB2_CONFIG_VALID_PHASE_HIGH 0x0077
+
+#define VL53L010_REG_SOFT_RESET_GO2_SOFT_RESET_N 0x00bf
+#define VL53L010_REG_IDENTIFICATION_MODEL_ID 0x00c0
+#define VL53L010_REG_IDENTIFICATION_REVISION_ID 0x00c2
+#define VL53L010_REG_IDENTIFICATION_MODULE_ID 0x00c3
+
+#define VL53L010_REG_OSC_CALIBRATE_VAL 0x00f8
+
+#define VL53L010_REG_FIRMWARE_MODE_STATUS 0x00C5
+
+#define VL53L010_REG_DYNAMIC_SPAD_ACTUAL_RTN_SPADS_INT 0x0016
+
+#define VL53L010_SIGMA_ESTIMATE_MAX_VALUE 65535
+/*equivalent to a range sigma of 655.35mm */
+
+/*
+ * Speed of light in um per 1E-10 Seconds
+ */
+
+#define VL53L010_SPEED_OF_LIGHT_IN_AIR 2997
+
+/** @} VL53L010_DefineRegisters_group */
+
+/** @} VL53L010_SpecDefines_group */
+
+#endif
+
+/* _VL53L010_DEVICE_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l010_strings.h b/drivers/input/misc/vl53L0/inc/vl53l010_strings.h
new file mode 100644
index 000000000000..714a0f1c479f
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l010_strings.h
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef VL53L010_STRINGS_H_
+#define VL53L010_STRINGS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ #define VL53L010_STRING_DEVICE_INFO_NAME \
+ "VL53L0 cut1.0"
+ #define VL53L010_STRING_DEVICE_INFO_NAME_TS0 \
+ "VL53L0 TS0"
+ #define VL53L010_STRING_DEVICE_INFO_NAME_TS1 \
+ "VL53L0 TS1"
+ #define VL53L010_STRING_DEVICE_INFO_NAME_TS2 \
+ "VL53L0 TS2"
+ #define VL53L010_STRING_DEVICE_INFO_NAME_ES1 \
+ "VL53L0 ES1 or later"
+ #define VL53L010_STRING_DEVICE_INFO_TYPE \
+ "VL53L0"
+
+ /* PAL ERROR strings */
+ #define VL53L010_STRING_ERROR_NONE \
+ "No Error"
+ #define VL53L010_STRING_ERROR_CALIBRATION_WARNING \
+ "Calibration Warning Error"
+ #define VL53L010_STRING_ERROR_MIN_CLIPPED \
+ "Min clipped error"
+ #define VL53L010_STRING_ERROR_UNDEFINED \
+ "Undefined error"
+ #define VL53L010_STRING_ERROR_INVALID_PARAMS \
+ "Invalid parameters error"
+ #define VL53L010_STRING_ERROR_NOT_SUPPORTED \
+ "Not supported error"
+ #define VL53L010_STRING_ERROR_RANGE_ERROR \
+ "Range error"
+ #define VL53L010_STRING_ERROR_TIME_OUT \
+ "Time out error"
+ #define VL53L010_STRING_ERROR_MODE_NOT_SUPPORTED \
+ "Mode not supported error"
+ #define VL53L010_STRING_ERROR_NOT_IMPLEMENTED \
+ "Not implemented error"
+
+ #define VL53L010_STRING_UNKNOW_ERROR_CODE \
+ "Unknow Error Code"
+ #define VL53L010_STRING_ERROR_BUFFER_TOO_SMALL \
+ "Buffer too small"
+
+ #define VL53L010_STRING_ERROR_GPIO_NOT_EXISTING \
+ "GPIO not existing"
+ #define VL53L010_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \
+ "GPIO functionality not supported"
+ #define VL53L010_STRING_ERROR_CONTROL_INTERFACE \
+ "Control Interface Error"
+
+
+ /* Device Specific */
+ #define VL53L010_STRING_DEVICEERROR_NONE \
+ "No Update"
+ #define VL53L010_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \
+ "VCSEL Continuity Test Failure"
+ #define VL53L010_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \
+ "VCSEL Watchdog Test Failure"
+ #define VL53L010_STRING_DEVICEERROR_NOVHVVALUEFOUND \
+ "No VHV Value found"
+ #define VL53L010_STRING_DEVICEERROR_MSRCNOTARGET \
+ "MSRC No Target Error"
+ #define VL53L010_STRING_DEVICEERROR_MSRCMINIMUMSNR \
+ "MSRC Minimum SNR Error"
+ #define VL53L010_STRING_DEVICEERROR_MSRCWRAPAROUND \
+ "MSRC Wraparound Error"
+ #define VL53L010_STRING_DEVICEERROR_TCC \
+ "TCC Error"
+ #define VL53L010_STRING_DEVICEERROR_RANGEAWRAPAROUND \
+ "Range A Wraparound Error"
+ #define VL53L010_STRING_DEVICEERROR_RANGEBWRAPAROUND \
+ "Range B Wraparound Error"
+ #define VL53L010_STRING_DEVICEERROR_MINCLIP \
+ "Min Clip Error"
+ #define VL53L010_STRING_DEVICEERROR_RANGECOMPLETE \
+ "Range Complete"
+ #define VL53L010_STRING_DEVICEERROR_ALGOUNDERFLOW \
+ "Range Algo Underflow Error"
+ #define VL53L010_STRING_DEVICEERROR_ALGOOVERFLOW \
+ "Range Algo Overlow Error"
+ #define VL53L010_STRING_DEVICEERROR_FINALSNRLIMIT \
+ "Final Minimum SNR Error"
+ #define VL53L010_STRING_DEVICEERROR_NOTARGETIGNORE \
+ "No Target Ignore Error"
+ #define VL53L010_STRING_DEVICEERROR_UNKNOWN \
+ "Unknown error code"
+
+
+ /* Check Enable */
+ #define VL53L010_STRING_CHECKENABLE_SIGMA \
+ "SIGMA"
+ #define VL53L010_STRING_CHECKENABLE_SIGNAL_RATE \
+ "SIGNAL RATE"
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/input/misc/vl53L0/inc/vl53l010_tuning.h b/drivers/input/misc/vl53L0/inc/vl53l010_tuning.h
new file mode 100644
index 000000000000..fe7906044feb
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l010_tuning.h
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _VL53L010_TUNING_H_
+#define _VL53L010_TUNING_H_
+
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @brief Internal function used to Program the default tuning settings
+ *
+ * @ingroup VL53L0_general_group
+ * @note This function access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L010_load_tuning_settings(VL53L0_DEV Dev);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L010_TUNING_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_api.h b/drivers/input/misc/vl53L0/inc/vl53l0_api.h
new file mode 100644
index 000000000000..4f6f8020de49
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_api.h
@@ -0,0 +1,1950 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef _VL53L0_API_H_
+#define _VL53L0_API_H_
+
+#include "vl53l0_api_strings.h"
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef _MSC_VER
+# ifdef VL53L0_API_EXPORTS
+# define VL53L0_API __declspec(dllexport)
+# else
+# define VL53L0_API
+# endif
+#else
+# define VL53L0_API
+#endif
+
+/** @defgroup VL53L0_cut11_group VL53L0 cut1.1 Function Definition
+ * @brief VL53L0 cut1.1 Function Definition
+ * @{
+ */
+
+/** @defgroup VL53L0_general_group VL53L0 General Functions
+ * @brief General functions and definitions
+ * @{
+ */
+
+/**
+ * @brief Return the VL53L0 PAL Implementation Version
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param pVersion Pointer to current PAL Implementation Version
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetVersion(VL53L0_Version_t *pVersion);
+
+/**
+ * @brief Return the PAL Specification Version used for the current
+ * implementation.
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param pPalSpecVersion Pointer to current PAL Specification Version
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetPalSpecVersion(
+ VL53L0_Version_t *pPalSpecVersion);
+
+/**
+ * @brief Reads the Product Revision for a for given Device
+ * This function can be used to distinguish cut1.0 from cut1.1.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pProductRevisionMajor Pointer to Product Revision Major
+ * for a given Device
+ * @param pProductRevisionMinor Pointer to Product Revision Minor
+ * for a given Device
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetProductRevision(VL53L0_DEV Dev,
+ uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor);
+
+/**
+ * @brief Reads the Device information for given Device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pVL53L0_DeviceInfo Pointer to current device info for a given
+ * Device
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetDeviceInfo(VL53L0_DEV Dev,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo);
+
+/**
+ * @brief Read current status of the error register for the selected device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceErrorStatus Pointer to current error code of the device
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetDeviceErrorStatus(VL53L0_DEV Dev,
+ VL53L0_DeviceError * pDeviceErrorStatus);
+
+/**
+ * @brief Human readable Range Status string for a given RangeStatus
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param RangeStatus The RangeStatus code as stored on
+ * @a VL53L0_RangingMeasurementData_t
+ * @param pRangeStatusString The returned RangeStatus string.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetRangeStatusString(uint8_t RangeStatus,
+ char *pRangeStatusString);
+
+/**
+ * @brief Human readable error string for a given Error Code
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param ErrorCode The error code as stored on ::VL53L0_DeviceError
+ * @param pDeviceErrorString The error string corresponding to the ErrorCode
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetDeviceErrorString(
+ VL53L0_DeviceError ErrorCode, char *pDeviceErrorString);
+
+/**
+ * @brief Human readable error string for current PAL error status
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param PalErrorCode The error code as stored on @a VL53L0_Error
+ * @param pPalErrorString The error string corresponding to the
+ * PalErrorCode
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetPalErrorString(VL53L0_Error PalErrorCode,
+ char *pPalErrorString);
+
+/**
+ * @brief Human readable PAL State string
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param PalStateCode The State code as stored on @a VL53L0_State
+ * @param pPalStateString The State string corresponding to the
+ * PalStateCode
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetPalStateString(VL53L0_State PalStateCode,
+ char *pPalStateString);
+
+/**
+ * @brief Reads the internal state of the PAL for a given Device
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param Dev Device Handle
+ * @param pPalState Pointer to current state of the PAL for a
+ * given Device
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetPalState(VL53L0_DEV Dev,
+ VL53L0_State * pPalState);
+
+/**
+ * @brief Set the power mode for a given Device
+ * The power mode can be Standby or Idle. Different level of both Standby and
+ * Idle can exists.
+ * This function should not be used when device is in Ranging state.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param PowerMode The value of the power mode to set.
+ * see ::VL53L0_PowerModes
+ * Valid values are:
+ * VL53L0_POWERMODE_STANDBY_LEVEL1,
+ * VL53L0_POWERMODE_IDLE_LEVEL1
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when PowerMode
+ * is not in the supported list
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetPowerMode(VL53L0_DEV Dev,
+ VL53L0_PowerModes PowerMode);
+
+/**
+ * @brief Get the power mode for a given Device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pPowerMode Pointer to the current value of the power
+ * mode. see ::VL53L0_PowerModes
+ * Valid values are:
+ * VL53L0_POWERMODE_STANDBY_LEVEL1,
+ * VL53L0_POWERMODE_IDLE_LEVEL1
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetPowerMode(VL53L0_DEV Dev,
+ VL53L0_PowerModes * pPowerMode);
+
+/**
+ * Set or over-hide part to part calibration offset
+ * \sa VL53L0_DataInit() VL53L0_GetOffsetCalibrationDataMicroMeter()
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param OffsetCalibrationDataMicroMeter Offset (microns)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetOffsetCalibrationDataMicroMeter(
+ VL53L0_DEV Dev, int32_t OffsetCalibrationDataMicroMeter);
+
+/**
+ * @brief Get part to part calibration offset
+ *
+ * @par Function Description
+ * Should only be used after a successful call to @a VL53L0_DataInit to backup
+ * device NVM value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pOffsetCalibrationDataMicroMeter Return part to part
+ * calibration offset from device (microns)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetOffsetCalibrationDataMicroMeter(
+ VL53L0_DEV Dev, int32_t *pOffsetCalibrationDataMicroMeter);
+
+/**
+ * Set the linearity corrective gain
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LinearityCorrectiveGain Linearity corrective
+ * gain in x1000
+ * if value is 1000 then no modification is applied.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetLinearityCorrectiveGain(VL53L0_DEV Dev,
+ int16_t LinearityCorrectiveGain);
+
+/**
+ * @brief Get the linearity corrective gain
+ *
+ * @par Function Description
+ * Should only be used after a successful call to @a VL53L0_DataInit to backup
+ * device NVM value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pLinearityCorrectiveGain Pointer to the linearity
+ * corrective gain in x1000
+ * if value is 1000 then no modification is applied.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetLinearityCorrectiveGain(VL53L0_DEV Dev,
+ uint16_t *pLinearityCorrectiveGain);
+
+/**
+ * Set Group parameter Hold state
+ *
+ * @par Function Description
+ * Set or remove device internal group parameter hold
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param GroupParamHold Group parameter Hold state to be set (on/off)
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_SetGroupParamHold(VL53L0_DEV Dev,
+ uint8_t GroupParamHold);
+
+/**
+ * @brief Get the maximal distance for actual setup
+ * @par Function Description
+ * Device must be initialized through @a VL53L0_SetParameters() prior calling
+ * this function.
+ *
+ * Any range value more than the value returned is to be considered as
+ * "no target detected" or
+ * "no target in detectable range"\n
+ * @warning The maximal distance depends on the setup
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pUpperLimitMilliMeter The maximal range limit for actual setup
+ * (in millimeter)
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_GetUpperLimitMilliMeter(VL53L0_DEV Dev,
+ uint16_t *pUpperLimitMilliMeter);
+
+
+/**
+ * @brief Get the Total Signal Rate
+ * @par Function Description
+ * This function will return the Total Signal Rate after a good ranging is done.
+ *
+ * @note This function access to Device
+ *
+ * @param Dev Device Handle
+ * @param pTotalSignalRate Total Signal Rate value in Mega count per second
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_GetTotalSignalRate(VL53L0_DEV Dev,
+ FixPoint1616_t *pTotalSignalRate);
+
+/** @} VL53L0_general_group */
+
+/** @defgroup VL53L0_init_group VL53L0 Init Functions
+ * @brief VL53L0 Init Functions
+ * @{
+ */
+
+/**
+ * @brief Set new device address
+ *
+ * After completion the device will answer to the new address programmed.
+ * This function should be called when several devices are used in parallel
+ * before start programming the sensor.
+ * When a single device us used, there is no need to call this function.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param DeviceAddress The new Device address
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetDeviceAddress(VL53L0_DEV Dev,
+ uint8_t DeviceAddress);
+
+/**
+ *
+ * @brief One time device initialization
+ *
+ * To be called once and only once after device is brought out of reset
+ * (Chip enable) and booted see @a VL53L0_WaitDeviceBooted()
+ *
+ * @par Function Description
+ * When not used after a fresh device "power up" or reset, it may return
+ * @a #VL53L0_ERROR_CALIBRATION_WARNING meaning wrong calibration data
+ * may have been fetched from device that can result in ranging offset error\n
+ * If application cannot execute device reset or need to run VL53L0_DataInit
+ * multiple time then it must ensure proper offset calibration saving and
+ * restore on its own by using @a VL53L0_GetOffsetCalibrationData() on first
+ * power up and then @a VL53L0_SetOffsetCalibrationData() in all subsequent init
+ * This function will change the VL53L0_State from VL53L0_STATE_POWERDOWN to
+ * VL53L0_STATE_WAIT_STATICINIT.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_DataInit(VL53L0_DEV Dev);
+
+/**
+ * @brief Set the tuning settings pointer
+ *
+ * This function is used to specify the Tuning settings buffer to be used
+ * for a given device. The buffer contains all the necessary data to permit
+ * the API to write tuning settings.
+ * This function permit to force the usage of either external or internal
+ * tuning settings.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pTuningSettingBuffer Pointer to tuning settings buffer.
+ * @param UseInternalTuningSettings Use internal tuning settings value.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetTuningSettingBuffer(VL53L0_DEV Dev,
+ uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings);
+
+/**
+ * @brief Get the tuning settings pointer and the internal external switch
+ * value.
+ *
+ * This function is used to get the Tuning settings buffer pointer and the
+ * value.
+ * of the switch to select either external or internal tuning settings.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param ppTuningSettingBuffer Pointer to tuning settings buffer.
+ * @param pUseInternalTuningSettings Pointer to store Use internal tuning
+ * settings value.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetTuningSettingBuffer(VL53L0_DEV Dev,
+ uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings);
+
+/**
+ * @brief Do basic device init (and eventually patch loading)
+ * This function will change the VL53L0_State from
+ * VL53L0_STATE_WAIT_STATICINIT to VL53L0_STATE_IDLE.
+ * In this stage all default setting will be applied.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_StaticInit(VL53L0_DEV Dev);
+
+/**
+ * @brief Wait for device booted after chip enable (hardware standby)
+ * This function can be run only when VL53L0_State is VL53L0_STATE_POWERDOWN.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ *
+ */
+VL53L0_API VL53L0_Error VL53L0_WaitDeviceBooted(VL53L0_DEV Dev);
+
+/**
+ * @brief Do an hard reset or soft reset (depending on implementation) of the
+ * device \nAfter call of this function, device must be in same state as right
+ * after a power-up sequence.This function will change the VL53L0_State to
+ * VL53L0_STATE_POWERDOWN.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_ResetDevice(VL53L0_DEV Dev);
+
+/** @} VL53L0_init_group */
+
+/** @defgroup VL53L0_parameters_group VL53L0 Parameters Functions
+ * @brief Functions used to prepare and setup the device
+ * @{
+ */
+
+/**
+ * @brief Prepare device for operation
+ * @par Function Description
+ * Update device with provided parameters
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceParameters Pointer to store current device parameters.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetDeviceParameters(VL53L0_DEV Dev,
+ const VL53L0_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief Retrieve current device parameters
+ * @par Function Description
+ * Get actual parameters of the device
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceParameters Pointer to store current device parameters.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetDeviceParameters(VL53L0_DEV Dev,
+ VL53L0_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief Set a new device mode
+ * @par Function Description
+ * Set device to a new mode (ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode New device mode to apply
+ * Valid values are:
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * VL53L0_DEVICEMODE_SINGLE_HISTOGRAM
+ * VL53L0_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL53L0_HISTOGRAMMODE_RETURN_ONLY
+ * VL53L0_HISTOGRAMMODE_BOTH
+ *
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when DeviceMode is
+ * not in the supported list
+ */
+VL53L0_API VL53L0_Error VL53L0_SetDeviceMode(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode);
+
+/**
+ * @brief Get current new device mode
+ * @par Function Description
+ * Get actual mode of the device(ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceMode Pointer to current apply mode value
+ * Valid values are:
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_RANGING
+ * VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * VL53L0_DEVICEMODE_SINGLE_HISTOGRAM
+ * VL53L0_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL53L0_HISTOGRAMMODE_RETURN_ONLY
+ * VL53L0_HISTOGRAMMODE_BOTH
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * DeviceMode is not in the supported list
+ */
+VL53L0_API VL53L0_Error VL53L0_GetDeviceMode(VL53L0_DEV Dev,
+ VL53L0_DeviceModes * pDeviceMode);
+
+/**
+ * @brief Sets the resolution of range measurements.
+ * @par Function Description
+ * Set resolution of range measurements to either 0.25mm if
+ * fraction enabled or 1mm if not enabled.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param Enable Enable high resolution
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetRangeFractionEnable(VL53L0_DEV Dev,
+ uint8_t Enable);
+
+/**
+ * @brief Gets the fraction enable parameter indicating the resolution of
+ * range measurements.
+ *
+ * @par Function Description
+ * Gets the fraction enable state, which translates to the resolution of
+ * range measurements as follows :Enabled:=0.25mm resolution,
+ * Not Enabled:=1mm resolution.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param pEnable Output Parameter reporting the fraction enable state.
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetFractionEnable(VL53L0_DEV Dev,
+ uint8_t *pEnable);
+
+/**
+ * @brief Set a new Histogram mode
+ * @par Function Description
+ * Set device to a new Histogram mode
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param HistogramMode New device mode to apply
+ * Valid values are:
+ * VL53L0_HISTOGRAMMODE_DISABLED
+ * VL53L0_DEVICEMODE_SINGLE_HISTOGRAM
+ * VL53L0_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL53L0_HISTOGRAMMODE_RETURN_ONLY
+ * VL53L0_HISTOGRAMMODE_BOTH
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * HistogramMode is not in the supported list
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes HistogramMode);
+
+/**
+ * @brief Get current new device mode
+ * @par Function Description
+ * Get current Histogram mode of a Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMode Pointer to current Histogram Mode value
+ * Valid values are:
+ * VL53L0_HISTOGRAMMODE_DISABLED
+ * VL53L0_DEVICEMODE_SINGLE_HISTOGRAM
+ * VL53L0_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL53L0_HISTOGRAMMODE_RETURN_ONLY
+ * VL53L0_HISTOGRAMMODE_BOTH
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes * pHistogramMode);
+
+/**
+ * @brief Set Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Defines the maximum time allowed by the user to the device to run a
+ * full ranging sequence for the current mode (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param MeasurementTimingBudgetMicroSeconds Max measurement time in
+ * microseconds.
+ * Valid values are:
+ * >= 17000 microsecs when wraparound enabled
+ * >= 12000 microsecs when wraparound disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned if
+ MeasurementTimingBudgetMicroSeconds out of range
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetMeasurementTimingBudgetMicroSeconds(
+ VL53L0_DEV Dev, uint32_t MeasurementTimingBudgetMicroSeconds);
+
+/**
+ * @brief Get Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Returns the programmed the maximum time allowed by the user to the
+ * device to run a full ranging sequence for the current mode
+ * (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in
+ * microseconds.
+ * Valid values are:
+ * >= 17000 microsecs when wraparound enabled
+ * >= 12000 microsecs when wraparound disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetMeasurementTimingBudgetMicroSeconds(
+ VL53L0_DEV Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds);
+
+/**
+ * @brief Gets the VCSEL pulse period.
+ *
+ * @par Function Description
+ * This function retrieves the VCSEL pulse period for the given period type.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param VcselPeriodType VCSEL period identifier (pre-range|final).
+ * @param pVCSELPulsePeriod Pointer to VCSEL period value.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not
+ * supported.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetVcselPulsePeriod(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t *pVCSELPulsePeriod);
+
+/**
+ * @brief Sets the VCSEL pulse period.
+ *
+ * @par Function Description
+ * This function retrieves the VCSEL pulse period for the given period type.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param VcselPeriodType VCSEL period identifier (pre-range|final).
+ * @param VCSELPulsePeriod VCSEL period value
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not
+ * supported.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetVcselPulsePeriod(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t VCSELPulsePeriod);
+
+/**
+ * @brief Sets the (on/off) state of a requested sequence step.
+ *
+ * @par Function Description
+ * This function enables/disables a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param SequenceStepEnabled Demanded state {0=Off,1=On}
+ * is enabled.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetSequenceStepEnable(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled);
+
+/**
+ * @brief Gets the (on/off) state of a requested sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the state of a requested sequence step, i.e. on/off.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param pSequenceStepEnabled Out parameter reporting if the sequence step
+ * is enabled {0=Off,1=On}.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetSequenceStepEnable(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled);
+
+/**
+ * @brief Gets the (on/off) state of all sequence steps.
+ *
+ * @par Function Description
+ * This function retrieves the state of all sequence step in the scheduler.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param pSchedulerSequenceSteps Pointer to struct containing result.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetSequenceStepEnables(VL53L0_DEV Dev,
+ VL53L0_SchedulerSequenceSteps_t *pSchedulerSequenceSteps);
+
+/**
+ * @brief Sets the timeout of a requested sequence step.
+ *
+ * @par Function Description
+ * This function sets the timeout of a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param TimeOutMilliSecs Demanded timeout
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetSequenceStepTimeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, FixPoint1616_t TimeOutMilliSecs);
+
+/**
+ * @brief Gets the timeout of a requested sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the timeout of a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param pTimeOutMilliSecs Timeout value.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetSequenceStepTimeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ FixPoint1616_t *pTimeOutMilliSecs);
+
+/**
+ * @brief Gets number of sequence steps managed by the API.
+ *
+ * @par Function Description
+ * This function retrieves the number of sequence steps currently managed
+ * by the API
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param pNumberOfSequenceSteps Out parameter reporting the number of
+ * sequence steps.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetNumberOfSequenceSteps(VL53L0_DEV Dev,
+ uint8_t *pNumberOfSequenceSteps);
+
+/**
+ * @brief Gets the name of a given sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the name of sequence steps corresponding to
+ * SequenceStepId.
+ *
+ * @note This function doesn't Accesses the device
+ *
+ * @param SequenceStepId Sequence step identifier.
+ * @param pSequenceStepsString Pointer to Info string
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetSequenceStepsInfo(
+ VL53L0_SequenceStepId SequenceStepId, char *pSequenceStepsString);
+
+/**
+ * Program continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetInterMeasurementPeriodMilliSeconds(
+ VL53L0_DEV Dev, uint32_t InterMeasurementPeriodMilliSeconds);
+
+/**
+ * Get continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed
+ * Inter-Measurement Period in milliseconds.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetInterMeasurementPeriodMilliSeconds(
+ VL53L0_DEV Dev, uint32_t *pInterMeasurementPeriodMilliSeconds);
+
+/**
+ * @brief Enable/Disable Cross talk compensation feature
+ *
+ * @note This function is not Implemented.
+ * Enable/Disable Cross Talk by set to zero the Cross Talk value
+ * by using @a VL53L0_SetXTalkCompensationRateMegaCps().
+ *
+ * @param Dev Device Handle
+ * @param XTalkCompensationEnable Cross talk compensation
+ * to be set 0=disabled else = enabled
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_SetXTalkCompensationEnable(VL53L0_DEV Dev,
+ uint8_t XTalkCompensationEnable);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @note This function is not Implemented.
+ * Enable/Disable Cross Talk by set to zero the Cross Talk value by
+ * using @a VL53L0_SetXTalkCompensationRateMegaCps().
+ *
+ * @param Dev Device Handle
+ * @param pXTalkCompensationEnable Pointer to the Cross talk compensation
+ * state 0=disabled or 1 = enabled
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_GetXTalkCompensationEnable(VL53L0_DEV Dev,
+ uint8_t *pXTalkCompensationEnable);
+
+/**
+ * @brief Set Cross talk compensation rate
+ *
+ * @par Function Description
+ * Set Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param XTalkCompensationRateMegaCps Compensation rate in
+ * Mega counts per second (16.16 fix point) see datasheet for details
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetXTalkCompensationRateMegaCps(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCompensationRateMegaCps);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @par Function Description
+ * Get Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pXTalkCompensationRateMegaCps Pointer to Compensation rate
+ in Mega counts per second (16.16 fix point) see datasheet for details
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetXTalkCompensationRateMegaCps(VL53L0_DEV Dev,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps);
+
+/**
+ * @brief Set Reference Calibration Parameters
+ *
+ * @par Function Description
+ * Set Reference Calibration Parameters.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param VhvSettings Parameter for VHV
+ * @param PhaseCal Parameter for PhaseCal
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetRefCalibration(VL53L0_DEV Dev,
+ uint8_t VhvSettings, uint8_t PhaseCal);
+
+/**
+ * @brief Get Reference Calibration Parameters
+ *
+ * @par Function Description
+ * Get Reference Calibration Parameters.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pVhvSettings Pointer to VHV parameter
+ * @param pPhaseCal Pointer to PhaseCal Parameter
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetRefCalibration(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+/**
+ * @brief Get the number of the check limit managed by a given Device
+ *
+ * @par Function Description
+ * This function give the number of the check limit managed by the Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param pNumberOfLimitCheck Pointer to the number of check limit.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetNumberOfLimitCheck(
+ uint16_t *pNumberOfLimitCheck);
+
+/**
+ * @brief Return a description string for a given limit check number
+ *
+ * @par Function Description
+ * This function returns a description string for a given limit check number.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ (0<= LimitCheckId < VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckString Pointer to the
+ description string of the given check limit.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is
+ returned when LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetLimitCheckInfo(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, char *pLimitCheckString);
+
+/**
+ * @brief Return a the Status of the specified check limit
+ *
+ * @par Function Description
+ * This function returns the Status of the specified check limit.
+ * The value indicate if the check is fail or not.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ (0<= LimitCheckId < VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckStatus Pointer to the
+ Limit Check Status of the given check limit.
+ * LimitCheckStatus :
+ * 0 the check is not fail
+ * 1 the check if fail or not enabled
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is
+ returned when LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetLimitCheckStatus(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckStatus);
+
+/**
+ * @brief Enable/Disable a specific limit check
+ *
+ * @par Function Description
+ * This function Enable/Disable a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL53L0_GetNumberOfLimitCheck() ).
+ * @param LimitCheckEnable if 1 the check limit
+ * corresponding to LimitCheckId is Enabled
+ * if 0 the check limit
+ * corresponding to LimitCheckId is disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned
+ * when LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetLimitCheckEnable(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, uint8_t LimitCheckEnable);
+
+/**
+ * @brief Get specific limit check enable state
+ *
+ * @par Function Description
+ * This function get the enable state of a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckEnable Pointer to the check limit enable
+ * value.
+ * if 1 the check limit
+ * corresponding to LimitCheckId is Enabled
+ * if 0 the check limit
+ * corresponding to LimitCheckId is disabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned
+ * when LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetLimitCheckEnable(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckEnable);
+
+/**
+ * @brief Set a specific limit check value
+ *
+ * @par Function Description
+ * This function set a specific limit check value.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL53L0_GetNumberOfLimitCheck() ).
+ * @param LimitCheckValue Limit check Value for a given
+ * LimitCheckId
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when either
+ * LimitCheckId or LimitCheckValue value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetLimitCheckValue(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, FixPoint1616_t LimitCheckValue);
+
+/**
+ * @brief Get a specific limit check value
+ *
+ * @par Function Description
+ * This function get a specific limit check value from device then it updates
+ * internal values and check enables.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckValue Pointer to Limit
+ * check Value for a given LimitCheckId.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned
+ * when LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetLimitCheckValue(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckValue);
+
+/**
+ * @brief Get the current value of the signal used for the limit check
+ *
+ * @par Function Description
+ * This function get a the current value of the signal used for the limit check.
+ * To obtain the latest value you should run a ranging before.
+ * The value reported is linked to the limit check identified with the
+ * LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL53L0_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckCurrent Pointer to current Value for a
+ * given LimitCheckId.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned when
+ * LimitCheckId value is out of range.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetLimitCheckCurrent(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckCurrent);
+
+/**
+ * @brief Enable (or disable) Wrap around Check
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param WrapAroundCheckEnable Wrap around Check to be set
+ * 0=disabled, other = enabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetWrapAroundCheckEnable(VL53L0_DEV Dev,
+ uint8_t WrapAroundCheckEnable);
+
+/**
+ * @brief Get setup of Wrap around Check
+ *
+ * @par Function Description
+ * This function get the wrapAround check enable parameters
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pWrapAroundCheckEnable Pointer to the Wrap around Check state
+ * 0=disabled or 1 = enabled
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetWrapAroundCheckEnable(VL53L0_DEV Dev,
+ uint8_t *pWrapAroundCheckEnable);
+
+/**
+ * @brief Set Dmax Calibration Parameters for a given device
+ * When one of the parameter is zero, this function will get parameter
+ * from NVM.
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param RangeMilliMeter Calibration Distance
+ * @param SignalRateRtnMegaCps Signal rate return read at CalDistance
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetDmaxCalParameters(VL53L0_DEV Dev,
+ uint16_t RangeMilliMeter, FixPoint1616_t SignalRateRtnMegaCps);
+
+/**
+ * @brief Get Dmax Calibration Parameters for a given device
+ *
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pRangeMilliMeter Pointer to Calibration Distance
+ * @param pSignalRateRtnMegaCps Pointer to Signal rate return
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetDmaxCalParameters(VL53L0_DEV Dev,
+ uint16_t *pRangeMilliMeter, FixPoint1616_t *pSignalRateRtnMegaCps);
+
+/** @} VL53L0_parameters_group */
+
+/** @defgroup VL53L0_measurement_group VL53L0 Measurement Functions
+ * @brief Functions used for the measurements
+ * @{
+ */
+
+/**
+ * @brief Single shot measurement.
+ *
+ * @par Function Description
+ * Perform simple measurement sequence (Start measure, Wait measure to end,
+ * and returns when measurement is done).
+ * Once function returns, user can get valid data by calling
+ * VL53L0_GetRangingMeasurement or VL53L0_GetHistogramMeasurement
+ * depending on defined measurement mode
+ * User should Clear the interrupt in case this are enabled by using the
+ * function VL53L0_ClearInterruptMask().
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformSingleMeasurement(VL53L0_DEV Dev);
+
+/**
+ * @brief Perform Reference Calibration
+ *
+ * @details Perform a reference calibration of the Device.
+ * This function should be run from time to time before doing
+ * a ranging measurement.
+ * This function will launch a special ranging measurement, so
+ * if interrupt are enable an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pVhvSettings Pointer to vhv settings parameter.
+ * @param pPhaseCal Pointer to PhaseCal parameter.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformRefCalibration(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+/**
+ * @brief Perform XTalk Measurement
+ *
+ * @details Measures the current cross talk from glass in front
+ * of the sensor.
+ * This functions performs a histogram measurement and uses the results
+ * to measure the crosstalk. For the function to be successful, there
+ * must be no target in front of the sensor.
+ *
+ * @warning This function is a blocking function
+ *
+ * @warning This function is not supported when the final range
+ * vcsel clock period is set below 10 PCLKS.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param TimeoutMs Histogram measurement duration.
+ * @param pXtalkPerSpad Output parameter containing the crosstalk
+ * measurement result, in MCPS/Spad. Format fixpoint 16:16.
+ * @param pAmbientTooHigh Output parameter which indicate that
+ * pXtalkPerSpad is not good if the Ambient is too high.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS vcsel clock period not supported
+ * for this operation. Must not be less than 10PCLKS.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformXTalkMeasurement(VL53L0_DEV Dev,
+ uint32_t TimeoutMs, FixPoint1616_t *pXtalkPerSpad,
+ uint8_t *pAmbientTooHigh);
+
+/**
+ * @brief Perform XTalk Calibration
+ *
+ * @details Perform a XTalk calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts
+ * are enabled an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the XTalk compensation
+ * and it will enable the cross talk before exit.
+ * This function will disable the VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param XTalkCalDistance XTalkCalDistance value used for the XTalk
+ * computation.
+ * @param pXTalkCompensationRateMegaCps Pointer to new
+ * XTalkCompensation value.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformXTalkCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCalDistance,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps);
+
+/**
+ * @brief Perform Offset Calibration
+ *
+ * @details Perform a Offset calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts are
+ * enabled an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the Offset calibration value
+ * This function will disable the VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function does not change the device mode.
+ *
+ * @param Dev Device Handle
+ * @param CalDistanceMilliMeter Calibration distance value used for the
+ * offset compensation.
+ * @param pOffsetMicroMeter Pointer to new Offset value computed by the
+ * function.
+ *
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformOffsetCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t CalDistanceMilliMeter, int32_t *pOffsetMicroMeter);
+
+/**
+ * @brief Start device measurement
+ *
+ * @details Started measurement will depend on device parameters set through
+ * @a VL53L0_SetParameters()
+ * This is a non-blocking function.
+ * This function will change the VL53L0_State from VL53L0_STATE_IDLE to
+ * VL53L0_STATE_RUNNING.
+ *
+ * @note This function Access to the device
+ *
+
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * DeviceMode programmed with @a VL53L0_SetDeviceMode is not in the supported
+ * list:
+ * Supported mode are:
+ * VL53L0_DEVICEMODE_SINGLE_RANGING,
+ * VL53L0_DEVICEMODE_CONTINUOUS_RANGING,
+ * VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * @return VL53L0_ERROR_TIME_OUT Time out on start measurement
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_StartMeasurement(VL53L0_DEV Dev);
+
+/**
+ * @brief Stop device measurement
+ *
+ * @details Will set the device in standby mode at end of current measurement\n
+ * Not necessary in single mode as device shall return automatically
+ * in standby mode at end of measurement.
+ * This function will change the VL53L0_State from VL53L0_STATE_RUNNING
+ * to VL53L0_STATE_IDLE.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_StopMeasurement(VL53L0_DEV Dev);
+
+/**
+ * @brief Return Measurement Data Ready
+ *
+ * @par Function Description
+ * This function indicate that a measurement data is ready.
+ * This function check if interrupt mode is used then check is done accordingly.
+ * If perform function clear the interrupt, this function will not work,
+ * like in case of @a VL53L0_PerformSingleRangingMeasurement().
+ * The previous function is blocking function, VL53L0_GetMeasurementDataReady
+ * is used for non-blocking capture.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementDataReady Pointer to Measurement Data Ready.
+ * 0=data not ready, 1 = data ready
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetMeasurementDataReady(VL53L0_DEV Dev,
+ uint8_t *pMeasurementDataReady);
+
+/**
+ * @brief Wait for device ready for a new measurement command.
+ * Blocking function.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param MaxLoop Max Number of polling loop (timeout).
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_WaitDeviceReadyForNewMeasurement(VL53L0_DEV Dev,
+ uint32_t MaxLoop);
+
+/**
+ * @brief Retrieve the Reference Signal after a measurements
+ *
+ * @par Function Description
+ * Get Reference Signal from last successful Ranging measurement
+ * This function return a valid value after that you call the
+ * @a VL53L0_GetRangingMeasurementData().
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementRefSignal Pointer to the Ref Signal to fill up.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetMeasurementRefSignal(VL53L0_DEV Dev,
+ FixPoint1616_t *pMeasurementRefSignal);
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement
+ * @warning USER should take care about @a VL53L0_GetNumberOfROIZones()
+ * before get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data
+ * structure used in the measurement function.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pRangingMeasurementData Pointer to the data structure to fill up.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetRangingMeasurementData(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Histogram measurement
+ * @warning USER should take care about @a VL53L0_GetNumberOfROIZones()
+ * before get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data structure
+ * used in the measurement function.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMeasurementData Pointer to the histogram data structure.
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_GetHistogramMeasurementData(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+/**
+ * @brief Performs a single ranging measurement and retrieve the ranging
+ * measurement data
+ *
+ * @par Function Description
+ * This function will change the device mode to VL53L0_DEVICEMODE_SINGLE_RANGING
+ * with @a VL53L0_SetDeviceMode(),
+ * It performs measurement with @a VL53L0_PerformSingleMeasurement()
+ * It get data from last successful Ranging measurement with
+ * @a VL53L0_GetRangingMeasurementData.
+ * Finally it clear the interrupt with @a VL53L0_ClearInterruptMask().
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param pRangingMeasurementData Pointer to the data structure to fill up.
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformSingleRangingMeasurement(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Performs a single histogram measurement and retrieve the histogram
+ * measurement data
+ * Is equivalent to VL53L0_PerformSingleMeasurement +
+ * VL53L0_GetHistogramMeasurementData
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement.
+ * This function will clear the interrupt in case of these are enabled.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMeasurementData Pointer to the data structure to fill up.
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformSingleHistogramMeasurement(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+/**
+ * @brief Set the number of ROI Zones to be used for a specific Device
+ *
+ * @par Function Description
+ * Set the number of ROI Zones to be used for a specific Device.
+ * The programmed value should be less than the max number of ROI Zones given
+ * with @a VL53L0_GetMaxNumberOfROIZones().
+ * This version of API manage only one zone.
+ *
+ * @param Dev Device Handle
+ * @param NumberOfROIZones Number of ROI Zones to be used for a
+ * specific Device.
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INVALID_PARAMS This error is returned if
+ * NumberOfROIZones != 1
+ */
+VL53L0_API VL53L0_Error VL53L0_SetNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t NumberOfROIZones);
+
+/**
+ * @brief Get the number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get number of ROI Zones managed by the Device
+ * USER should take care about @a VL53L0_GetNumberOfROIZones()
+ * before get data after a perform measurement.
+ * PAL will fill a NumberOfROIZones times the corresponding data
+ * structure used in the measurement function.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pNumberOfROIZones Pointer to the Number of ROI Zones value.
+ * @return VL53L0_ERROR_NONE Success
+ */
+VL53L0_API VL53L0_Error VL53L0_GetNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t *pNumberOfROIZones);
+
+/**
+ * @brief Get the Maximum number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get Maximum number of ROI Zones managed by the Device.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMaxNumberOfROIZones Pointer to the Maximum Number
+ * of ROI Zones value.
+ * @return VL53L0_ERROR_NONE Success
+ */
+VL53L0_API VL53L0_Error VL53L0_GetMaxNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t *pMaxNumberOfROIZones);
+
+/** @} VL53L0_measurement_group */
+
+/** @defgroup VL53L0_interrupt_group VL53L0 Interrupt Functions
+ * @brief Functions used for interrupt managements
+ * @{
+ */
+
+/**
+ * @brief Set the configuration of GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param Pin ID of the GPIO Pin
+ * @param Functionality Select Pin functionality.
+ * Refer to ::VL53L0_GpioFunctionality
+ * @param DeviceMode Device Mode associated to the Gpio.
+ * @param Polarity Set interrupt polarity. Active high
+ * or active low see ::VL53L0_InterruptPolarity
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted.
+ * @return VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs
+ * when Functionality programmed is not in the supported list:
+ * Supported value are:
+ * VL53L0_GPIOFUNCTIONALITY_OFF,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ * VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes DeviceMode, VL53L0_GpioFunctionality Functionality,
+ VL53L0_InterruptPolarity Polarity);
+
+/**
+ * @brief Get current configuration for GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param Pin ID of the GPIO Pin
+ * @param pDeviceMode Pointer to Device Mode associated to the Gpio.
+ * @param pFunctionality Pointer to Pin functionality.
+ * Refer to ::VL53L0_GpioFunctionality
+ * @param pPolarity Pointer to interrupt polarity.
+ * Active high or active low see ::VL53L0_InterruptPolarity
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted.
+ * @return VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs
+ * when Functionality programmed is not in the supported list:
+ * Supported value are:
+ * VL53L0_GPIOFUNCTIONALITY_OFF,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ * VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ * VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes * pDeviceMode,
+ VL53L0_GpioFunctionality * pFunctionality,
+ VL53L0_InterruptPolarity * pPolarity);
+
+/**
+ * @brief Set low and high Interrupt thresholds for a given mode
+ * (ranging, ALS, ...) for a given device
+ *
+ * @par Function Description
+ * Set low and high Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode Device Mode for which change thresholds
+ * @param ThresholdLow Low threshold (mm, lux ..., depending on the mode)
+ * @param ThresholdHigh High threshold (mm, lux ..., depending on the mode)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetInterruptThresholds(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode, FixPoint1616_t ThresholdLow,
+ FixPoint1616_t ThresholdHigh);
+
+/**
+ * @brief Get high and low Interrupt thresholds for a given mode
+ * (ranging, ALS, ...) for a given device
+ *
+ * @par Function Description
+ * Get high and low Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode Device Mode from which read thresholds
+ * @param pThresholdLow Low threshold (mm, lux ..., depending on the mode)
+ * @param pThresholdHigh High threshold (mm, lux ..., depending on the mode)
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetInterruptThresholds(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode, FixPoint1616_t *pThresholdLow,
+ FixPoint1616_t *pThresholdHigh);
+
+/**
+ * @brief Return device stop completion status
+ *
+ * @par Function Description
+ * Returns stop completiob status.
+ * User shall call this function after a stop command
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pStopStatus Pointer to status variable to update
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetStopCompletedStatus(VL53L0_DEV Dev,
+ uint32_t *pStopStatus);
+
+
+/**
+ * @brief Clear given system interrupt condition
+ *
+ * @par Function Description
+ * Clear given interrupt(s).
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param InterruptMask Mask of interrupts to clear
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_INTERRUPT_NOT_CLEARED Cannot clear interrupts
+ *
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_ClearInterruptMask(VL53L0_DEV Dev,
+ uint32_t InterruptMask);
+
+/**
+ * @brief Return device interrupt status
+ *
+ * @par Function Description
+ * Returns currently raised interrupts by the device.
+ * User shall be able to activate/deactivate interrupts through
+ * @a VL53L0_SetGpioConfig()
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pInterruptMaskStatus Pointer to status variable to update
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetInterruptMaskStatus(VL53L0_DEV Dev,
+ uint32_t *pInterruptMaskStatus);
+
+/**
+ * @brief Configure ranging interrupt reported to system
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param InterruptMask Mask of interrupt to Enable/disable
+ * (0:interrupt disabled or 1: interrupt enabled)
+ * @return VL53L0_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL53L0_API VL53L0_Error VL53L0_EnableInterruptMask(VL53L0_DEV Dev,
+ uint32_t InterruptMask);
+
+/** @} VL53L0_interrupt_group */
+
+/** @defgroup VL53L0_SPADfunctions_group VL53L0 SPAD Functions
+ * @brief Functions used for SPAD managements
+ * @{
+ */
+
+/**
+ * @brief Set the SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param SpadAmbientDamperThreshold SPAD Ambient Damper Threshold value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetSpadAmbientDamperThreshold(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperThreshold);
+
+/**
+ * @brief Get the current SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pSpadAmbientDamperThreshold Pointer to programmed
+ * SPAD Ambient Damper Threshold value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetSpadAmbientDamperThreshold(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperThreshold);
+
+/**
+ * @brief Set the SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param SpadAmbientDamperFactor SPAD Ambient Damper Factor value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetSpadAmbientDamperFactor(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperFactor);
+
+/**
+ * @brief Get the current SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pSpadAmbientDamperFactor Pointer to programmed SPAD Ambient
+ * Damper Factor value
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetSpadAmbientDamperFactor(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperFactor);
+
+/**
+ * @brief Performs Reference Spad Management
+ *
+ * @par Function Description
+ * The reference SPAD initialization procedure determines the minimum amount
+ * of reference spads to be enables to achieve a target reference signal rate
+ * and should be performed once during initialization.
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * VL53L0_DEVICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param refSpadCount Reports ref Spad Count
+ * @param isApertureSpads Reports if spads are of type
+ * aperture or non-aperture.
+ * 1:=aperture, 0:=Non-Aperture
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_REF_SPAD_INIT Error in the Ref Spad procedure.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_PerformRefSpadManagement(VL53L0_DEV Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+/**
+ * @brief Applies Reference SPAD configuration
+ *
+ * @par Function Description
+ * This function applies a given number of reference spads, identified as
+ * either Aperture or Non-Aperture.
+ * The requested spad count and type are stored within the device specific
+ * parameters data for access by the host.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param refSpadCount Number of ref spads.
+ * @param isApertureSpads Defines if spads are of type
+ * aperture or non-aperture.
+ * 1:=aperture, 0:=Non-Aperture
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_REF_SPAD_INIT Error in the in the reference
+ * spad configuration.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_SetReferenceSpads(VL53L0_DEV Dev,
+ uint32_t refSpadCount, uint8_t isApertureSpads);
+
+/**
+ * @brief Retrieves SPAD configuration
+ *
+ * @par Function Description
+ * This function retrieves the current number of applied reference spads
+ * and also their type : Aperture or Non-Aperture.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param refSpadCount Number ref Spad Count
+ * @param isApertureSpads Reports if spads are of type
+ * aperture or non-aperture.
+ * 1:=aperture, 0:=Non-Aperture
+ * @return VL53L0_ERROR_NONE Success
+ * @return VL53L0_ERROR_REF_SPAD_INIT Error in the in the reference
+ * spad configuration.
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_API VL53L0_Error VL53L0_GetReferenceSpads(VL53L0_DEV Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+/** @} VL53L0_SPADfunctions_group */
+
+/** @} VL53L0_cut11_group */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L0_API_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_api_calibration.h b/drivers/input/misc/vl53L0/inc/vl53l0_api_calibration.h
new file mode 100644
index 000000000000..df9b43987eb5
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_api_calibration.h
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _VL53L0_API_CALIBRATION_H_
+#define _VL53L0_API_CALIBRATION_H_
+
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+VL53L0_Error VL53L0_perform_xtalk_calibration(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCalDistance,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps);
+
+VL53L0_Error VL53L0_perform_offset_calibration(VL53L0_DEV Dev,
+ FixPoint1616_t CalDistanceMilliMeter,
+ int32_t *pOffsetMicroMeter);
+
+VL53L0_Error VL53L0_set_offset_calibration_data_micro_meter(VL53L0_DEV Dev,
+ int32_t OffsetCalibrationDataMicroMeter);
+
+VL53L0_Error VL53L0_get_offset_calibration_data_micro_meter(VL53L0_DEV Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter);
+
+VL53L0_Error VL53L0_apply_offset_adjustment(VL53L0_DEV Dev);
+
+VL53L0_Error VL53L0_perform_ref_spad_management(VL53L0_DEV Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+VL53L0_Error VL53L0_set_reference_spads(VL53L0_DEV Dev,
+ uint32_t count, uint8_t isApertureSpads);
+
+VL53L0_Error VL53L0_get_reference_spads(VL53L0_DEV Dev,
+ uint32_t *pSpadCount, uint8_t *pIsApertureSpads);
+
+VL53L0_Error VL53L0_perform_phase_calibration(VL53L0_DEV Dev,
+ uint8_t *pPhaseCal, const uint8_t get_data_enable,
+ const uint8_t restore_config);
+
+VL53L0_Error VL53L0_perform_ref_calibration(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable);
+
+VL53L0_Error VL53L0_set_ref_calibration(VL53L0_DEV Dev,
+ uint8_t VhvSettings, uint8_t PhaseCal);
+
+VL53L0_Error VL53L0_get_ref_calibration(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L0_API_CALIBRATION_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_api_core.h b/drivers/input/misc/vl53L0/inc/vl53l0_api_core.h
new file mode 100644
index 000000000000..21cf9edec0e0
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_api_core.h
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _VL53L0_API_CORE_H_
+#define _VL53L0_API_CORE_H_
+
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+VL53L0_Error VL53L0_reverse_bytes(uint8_t *data, uint32_t size);
+
+VL53L0_Error VL53L0_measurement_poll_for_completion(VL53L0_DEV Dev);
+
+uint8_t VL53L0_encode_vcsel_period(uint8_t vcsel_period_pclks);
+
+uint8_t VL53L0_decode_vcsel_period(uint8_t vcsel_period_reg);
+
+uint32_t VL53L0_isqrt(uint32_t num);
+
+uint32_t VL53L0_quadrature_sum(uint32_t a, uint32_t b);
+
+VL53L0_Error VL53L0_get_info_from_device(VL53L0_DEV Dev, uint8_t option);
+
+VL53L0_Error VL53L0_set_vcsel_pulse_period(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t VCSELPulsePeriodPCLK);
+
+VL53L0_Error VL53L0_get_vcsel_pulse_period(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK);
+
+uint32_t VL53L0_decode_timeout(uint16_t encoded_timeout);
+
+VL53L0_Error get_sequence_step_timeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ uint32_t *pTimeOutMicroSecs);
+
+VL53L0_Error set_sequence_step_timeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ uint32_t TimeOutMicroSecs);
+
+VL53L0_Error VL53L0_set_measurement_timing_budget_micro_seconds(VL53L0_DEV Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds);
+
+VL53L0_Error VL53L0_get_measurement_timing_budget_micro_seconds(VL53L0_DEV Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds);
+
+VL53L0_Error VL53L0_load_tuning_settings(VL53L0_DEV Dev,
+ uint8_t *pTuningSettingBuffer);
+
+VL53L0_Error VL53L0_calc_sigma_estimate(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ FixPoint1616_t *pSigmaEstimate, uint32_t *pDmax_mm);
+
+VL53L0_Error VL53L0_get_total_xtalk_rate(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ FixPoint1616_t *ptotal_xtalk_rate_mcps);
+
+VL53L0_Error VL53L0_get_total_signal_rate(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ FixPoint1616_t *ptotal_signal_rate_mcps);
+
+VL53L0_Error VL53L0_get_pal_range_status(VL53L0_DEV Dev,
+ uint8_t DeviceRangeStatus,
+ FixPoint1616_t SignalRate,
+ uint16_t EffectiveSpadRtnCount,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ uint8_t *pPalRangeStatus);
+
+uint32_t VL53L0_calc_timeout_mclks(VL53L0_DEV Dev,
+ uint32_t timeout_period_us, uint8_t vcsel_period_pclks);
+
+uint16_t VL53L0_encode_timeout(uint32_t timeout_macro_clks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L0_API_CORE_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_api_histogram.h b/drivers/input/misc/vl53L0/inc/vl53l0_api_histogram.h
new file mode 100644
index 000000000000..c2438a8cd79b
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_api_histogram.h
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _VL53L0_API_HISTOGRAM_H_
+#define _VL53L0_API_HISTOGRAM_H_
+
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+VL53L0_Error VL53L0_confirm_measurement_start(VL53L0_DEV Dev);
+
+VL53L0_Error VL53L0_set_histogram_mode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes HistogramMode);
+
+VL53L0_Error VL53L0_get_histogram_mode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes *pHistogramMode);
+
+VL53L0_Error VL53L0_start_histogram_measurement(VL53L0_DEV Dev,
+ VL53L0_HistogramModes histoMode,
+ uint32_t count);
+
+VL53L0_Error VL53L0_perform_single_histogram_measurement(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+VL53L0_Error VL53L0_get_histogram_measurement_data(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+VL53L0_Error VL53L0_read_histo_measurement(VL53L0_DEV Dev,
+ uint32_t *histoData, uint32_t offset, VL53L0_HistogramModes histoMode);
+
+VL53L0_Error VL53L0_perform_xtalk_measurement(VL53L0_DEV dev,
+ uint32_t timeout_ms, FixPoint1616_t *pxtalk_per_spad,
+ uint8_t *pambient_too_high);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L0_API_HISTOGRAM_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_api_ranging.h b/drivers/input/misc/vl53L0/inc/vl53l0_api_ranging.h
new file mode 100644
index 000000000000..ba0bd03fe71f
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_api_ranging.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _VL53L0_API_RANGING_H_
+#define _VL53L0_API_RANGING_H_
+
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L0_API_RANGING_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_api_strings.h b/drivers/input/misc/vl53L0/inc/vl53l0_api_strings.h
new file mode 100644
index 000000000000..2bb6a1e8ea33
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_api_strings.h
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef VL53L0_API_STRINGS_H_
+#define VL53L0_API_STRINGS_H_
+
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+VL53L0_Error VL53L0_get_device_info(VL53L0_DEV Dev,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo);
+
+VL53L0_Error VL53L0_get_device_error_string(VL53L0_DeviceError ErrorCode,
+ char *pDeviceErrorString);
+
+VL53L0_Error VL53L0_get_range_status_string(uint8_t RangeStatus,
+ char *pRangeStatusString);
+
+VL53L0_Error VL53L0_get_pal_error_string(VL53L0_Error PalErrorCode,
+ char *pPalErrorString);
+
+VL53L0_Error VL53L0_get_pal_state_string(VL53L0_State PalStateCode,
+ char *pPalStateString);
+
+VL53L0_Error VL53L0_get_sequence_steps_info(
+ VL53L0_SequenceStepId SequenceStepId,
+ char *pSequenceStepsString);
+
+VL53L0_Error VL53L0_get_limit_check_info(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ char *pLimitCheckString);
+
+
+#ifdef USE_EMPTY_STRING
+ #define VL53L0_STRING_DEVICE_INFO_NAME ""
+ #define VL53L0_STRING_DEVICE_INFO_NAME_TS0 ""
+ #define VL53L0_STRING_DEVICE_INFO_NAME_TS1 ""
+ #define VL53L0_STRING_DEVICE_INFO_NAME_TS2 ""
+ #define VL53L0_STRING_DEVICE_INFO_NAME_ES1 ""
+ #define VL53L0_STRING_DEVICE_INFO_TYPE ""
+
+ /* PAL ERROR strings */
+ #define VL53L0_STRING_ERROR_NONE ""
+ #define VL53L0_STRING_ERROR_CALIBRATION_WARNING ""
+ #define VL53L0_STRING_ERROR_MIN_CLIPPED ""
+ #define VL53L0_STRING_ERROR_UNDEFINED ""
+ #define VL53L0_STRING_ERROR_INVALID_PARAMS ""
+ #define VL53L0_STRING_ERROR_NOT_SUPPORTED ""
+ #define VL53L0_STRING_ERROR_RANGE_ERROR ""
+ #define VL53L0_STRING_ERROR_TIME_OUT ""
+ #define VL53L0_STRING_ERROR_MODE_NOT_SUPPORTED ""
+ #define VL53L0_STRING_ERROR_BUFFER_TOO_SMALL ""
+ #define VL53L0_STRING_ERROR_GPIO_NOT_EXISTING ""
+ #define VL53L0_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ""
+ #define VL53L0_STRING_ERROR_CONTROL_INTERFACE ""
+ #define VL53L0_STRING_ERROR_INVALID_COMMAND ""
+ #define VL53L0_STRING_ERROR_DIVISION_BY_ZERO ""
+ #define VL53L0_STRING_ERROR_REF_SPAD_INIT ""
+ #define VL53L0_STRING_ERROR_NOT_IMPLEMENTED ""
+
+ #define VL53L0_STRING_UNKNOW_ERROR_CODE ""
+
+
+
+ /* Range Status */
+ #define VL53L0_STRING_RANGESTATUS_NONE ""
+ #define VL53L0_STRING_RANGESTATUS_RANGEVALID ""
+ #define VL53L0_STRING_RANGESTATUS_SIGMA ""
+ #define VL53L0_STRING_RANGESTATUS_SIGNAL ""
+ #define VL53L0_STRING_RANGESTATUS_MINRANGE ""
+ #define VL53L0_STRING_RANGESTATUS_PHASE ""
+ #define VL53L0_STRING_RANGESTATUS_HW ""
+
+
+ /* Range Status */
+ #define VL53L0_STRING_STATE_POWERDOWN ""
+ #define VL53L0_STRING_STATE_WAIT_STATICINIT ""
+ #define VL53L0_STRING_STATE_STANDBY ""
+ #define VL53L0_STRING_STATE_IDLE ""
+ #define VL53L0_STRING_STATE_RUNNING ""
+ #define VL53L0_STRING_STATE_UNKNOWN ""
+ #define VL53L0_STRING_STATE_ERROR ""
+
+
+ /* Device Specific */
+ #define VL53L0_STRING_DEVICEERROR_NONE ""
+ #define VL53L0_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE ""
+ #define VL53L0_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE ""
+ #define VL53L0_STRING_DEVICEERROR_NOVHVVALUEFOUND ""
+ #define VL53L0_STRING_DEVICEERROR_MSRCNOTARGET ""
+ #define VL53L0_STRING_DEVICEERROR_SNRCHECK ""
+ #define VL53L0_STRING_DEVICEERROR_RANGEPHASECHECK ""
+ #define VL53L0_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK ""
+ #define VL53L0_STRING_DEVICEERROR_TCC ""
+ #define VL53L0_STRING_DEVICEERROR_PHASECONSISTENCY ""
+ #define VL53L0_STRING_DEVICEERROR_MINCLIP ""
+ #define VL53L0_STRING_DEVICEERROR_RANGECOMPLETE ""
+ #define VL53L0_STRING_DEVICEERROR_ALGOUNDERFLOW ""
+ #define VL53L0_STRING_DEVICEERROR_ALGOOVERFLOW ""
+ #define VL53L0_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD ""
+ #define VL53L0_STRING_DEVICEERROR_UNKNOWN ""
+
+ /* Check Enable */
+ #define VL53L0_STRING_CHECKENABLE_SIGMA_FINAL_RANGE ""
+ #define VL53L0_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE ""
+ #define VL53L0_STRING_CHECKENABLE_SIGNAL_REF_CLIP ""
+ #define VL53L0_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD ""
+
+ /* Sequence Step */
+ #define VL53L0_STRING_SEQUENCESTEP_TCC ""
+ #define VL53L0_STRING_SEQUENCESTEP_DSS ""
+ #define VL53L0_STRING_SEQUENCESTEP_MSRC ""
+ #define VL53L0_STRING_SEQUENCESTEP_PRE_RANGE ""
+ #define VL53L0_STRING_SEQUENCESTEP_FINAL_RANGE ""
+#else
+ #define VL53L0_STRING_DEVICE_INFO_NAME "VL53L0 cut1.0"
+ #define VL53L0_STRING_DEVICE_INFO_NAME_TS0 "VL53L0 TS0"
+ #define VL53L0_STRING_DEVICE_INFO_NAME_TS1 "VL53L0 TS1"
+ #define VL53L0_STRING_DEVICE_INFO_NAME_TS2 "VL53L0 TS2"
+ #define VL53L0_STRING_DEVICE_INFO_NAME_ES1 "VL53L0 ES1 or later"
+ #define VL53L0_STRING_DEVICE_INFO_TYPE "VL53L0"
+
+ /* PAL ERROR strings */
+ #define VL53L0_STRING_ERROR_NONE \
+ "No Error"
+ #define VL53L0_STRING_ERROR_CALIBRATION_WARNING \
+ "Calibration Warning Error"
+ #define VL53L0_STRING_ERROR_MIN_CLIPPED \
+ "Min clipped error"
+ #define VL53L0_STRING_ERROR_UNDEFINED \
+ "Undefined error"
+ #define VL53L0_STRING_ERROR_INVALID_PARAMS \
+ "Invalid parameters error"
+ #define VL53L0_STRING_ERROR_NOT_SUPPORTED \
+ "Not supported error"
+ #define VL53L0_STRING_ERROR_RANGE_ERROR \
+ "Range error"
+ #define VL53L0_STRING_ERROR_TIME_OUT \
+ "Time out error"
+ #define VL53L0_STRING_ERROR_MODE_NOT_SUPPORTED \
+ "Mode not supported error"
+ #define VL53L0_STRING_ERROR_BUFFER_TOO_SMALL \
+ "Buffer too small"
+ #define VL53L0_STRING_ERROR_GPIO_NOT_EXISTING \
+ "GPIO not existing"
+ #define VL53L0_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \
+ "GPIO funct not supported"
+ #define VL53L0_STRING_ERROR_INTERRUPT_NOT_CLEARED \
+ "Interrupt not Cleared"
+ #define VL53L0_STRING_ERROR_CONTROL_INTERFACE \
+ "Control Interface Error"
+ #define VL53L0_STRING_ERROR_INVALID_COMMAND \
+ "Invalid Command Error"
+ #define VL53L0_STRING_ERROR_DIVISION_BY_ZERO \
+ "Division by zero Error"
+ #define VL53L0_STRING_ERROR_REF_SPAD_INIT \
+ "Reference Spad Init Error"
+ #define VL53L0_STRING_ERROR_NOT_IMPLEMENTED \
+ "Not implemented error"
+
+ #define VL53L0_STRING_UNKNOW_ERROR_CODE \
+ "Unknown Error Code"
+
+
+
+ /* Range Status */
+ #define VL53L0_STRING_RANGESTATUS_NONE "No Update"
+ #define VL53L0_STRING_RANGESTATUS_RANGEVALID "Range Valid"
+ #define VL53L0_STRING_RANGESTATUS_SIGMA "Sigma Fail"
+ #define VL53L0_STRING_RANGESTATUS_SIGNAL "Signal Fail"
+ #define VL53L0_STRING_RANGESTATUS_MINRANGE "Min Range Fail"
+ #define VL53L0_STRING_RANGESTATUS_PHASE "Phase Fail"
+ #define VL53L0_STRING_RANGESTATUS_HW "Hardware Fail"
+
+
+ /* Range Status */
+ #define VL53L0_STRING_STATE_POWERDOWN "POWERDOWN State"
+ #define VL53L0_STRING_STATE_WAIT_STATICINIT \
+ "Wait for staticinit State"
+ #define VL53L0_STRING_STATE_STANDBY "STANDBY State"
+ #define VL53L0_STRING_STATE_IDLE "IDLE State"
+ #define VL53L0_STRING_STATE_RUNNING "RUNNING State"
+ #define VL53L0_STRING_STATE_UNKNOWN "UNKNOWN State"
+ #define VL53L0_STRING_STATE_ERROR "ERROR State"
+
+
+ /* Device Specific */
+ #define VL53L0_STRING_DEVICEERROR_NONE "No Update"
+ #define VL53L0_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \
+ "VCSEL Continuity Test Failure"
+ #define VL53L0_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \
+ "VCSEL Watchdog Test Failure"
+ #define VL53L0_STRING_DEVICEERROR_NOVHVVALUEFOUND \
+ "No VHV Value found"
+ #define VL53L0_STRING_DEVICEERROR_MSRCNOTARGET \
+ "MSRC No Target Error"
+ #define VL53L0_STRING_DEVICEERROR_SNRCHECK \
+ "SNR Check Exit"
+ #define VL53L0_STRING_DEVICEERROR_RANGEPHASECHECK \
+ "Range Phase Check Error"
+ #define VL53L0_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK \
+ "Sigma Threshold Check Error"
+ #define VL53L0_STRING_DEVICEERROR_TCC \
+ "TCC Error"
+ #define VL53L0_STRING_DEVICEERROR_PHASECONSISTENCY \
+ "Phase Consistency Error"
+ #define VL53L0_STRING_DEVICEERROR_MINCLIP \
+ "Min Clip Error"
+ #define VL53L0_STRING_DEVICEERROR_RANGECOMPLETE \
+ "Range Complete"
+ #define VL53L0_STRING_DEVICEERROR_ALGOUNDERFLOW \
+ "Range Algo Underflow Error"
+ #define VL53L0_STRING_DEVICEERROR_ALGOOVERFLOW \
+ "Range Algo Overlow Error"
+ #define VL53L0_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD \
+ "Range Ignore Threshold Error"
+ #define VL53L0_STRING_DEVICEERROR_UNKNOWN \
+ "Unknown error code"
+
+ /* Check Enable */
+ #define VL53L0_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \
+ "SIGMA FINAL RANGE"
+ #define VL53L0_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \
+ "SIGNAL RATE FINAL RANGE"
+ #define VL53L0_STRING_CHECKENABLE_SIGNAL_REF_CLIP \
+ "SIGNAL REF CLIP"
+ #define VL53L0_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \
+ "RANGE IGNORE THRESHOLD"
+ #define VL53L0_STRING_CHECKENABLE_SIGNAL_RATE_MSRC \
+ "SIGNAL RATE MSRC"
+ #define VL53L0_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE \
+ "SIGNAL RATE PRE RANGE"
+
+ /* Sequence Step */
+ #define VL53L0_STRING_SEQUENCESTEP_TCC "TCC"
+ #define VL53L0_STRING_SEQUENCESTEP_DSS "DSS"
+ #define VL53L0_STRING_SEQUENCESTEP_MSRC "MSRC"
+ #define VL53L0_STRING_SEQUENCESTEP_PRE_RANGE "PRE RANGE"
+ #define VL53L0_STRING_SEQUENCESTEP_FINAL_RANGE "FINAL RANGE"
+#endif /* USE_EMPTY_STRING */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_def.h b/drivers/input/misc/vl53L0/inc/vl53l0_def.h
new file mode 100644
index 000000000000..009715a5924f
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_def.h
@@ -0,0 +1,663 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**
+ * @file VL53L0_def.h
+ *
+ * @brief Type definitions for VL53L0 API.
+ *
+ */
+
+
+#ifndef _VL53L0_DEF_H_
+#define _VL53L0_DEF_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup VL53L0_globaldefine_group VL53L0 Defines
+ * @brief VL53L0 Defines
+ * @{
+ */
+
+
+/** PAL SPECIFICATION major version */
+#define VL53L010_SPECIFICATION_VER_MAJOR 1
+/** PAL SPECIFICATION minor version */
+#define VL53L010_SPECIFICATION_VER_MINOR 2
+/** PAL SPECIFICATION sub version */
+#define VL53L010_SPECIFICATION_VER_SUB 7
+/** PAL SPECIFICATION sub version */
+#define VL53L010_SPECIFICATION_VER_REVISION 1440
+
+/** VL53L0 PAL IMPLEMENTATION major version */
+#define VL53L010_IMPLEMENTATION_VER_MAJOR 1
+/** VL53L0 PAL IMPLEMENTATION minor version */
+#define VL53L010_IMPLEMENTATION_VER_MINOR 0
+/** VL53L0 PAL IMPLEMENTATION sub version */
+#define VL53L010_IMPLEMENTATION_VER_SUB 9
+/** VL53L0 PAL IMPLEMENTATION sub version */
+#define VL53L010_IMPLEMENTATION_VER_REVISION 3673
+
+/** PAL SPECIFICATION major version */
+#define VL53L0_SPECIFICATION_VER_MAJOR 1
+/** PAL SPECIFICATION minor version */
+#define VL53L0_SPECIFICATION_VER_MINOR 2
+/** PAL SPECIFICATION sub version */
+#define VL53L0_SPECIFICATION_VER_SUB 7
+/** PAL SPECIFICATION sub version */
+#define VL53L0_SPECIFICATION_VER_REVISION 1440
+
+/** VL53L0 PAL IMPLEMENTATION major version */
+#define VL53L0_IMPLEMENTATION_VER_MAJOR 1
+/** VL53L0 PAL IMPLEMENTATION minor version */
+#define VL53L0_IMPLEMENTATION_VER_MINOR 1
+/** VL53L0 PAL IMPLEMENTATION sub version */
+#define VL53L0_IMPLEMENTATION_VER_SUB 20
+/** VL53L0 PAL IMPLEMENTATION sub version */
+#define VL53L0_IMPLEMENTATION_VER_REVISION 4606
+#define VL53L0_DEFAULT_MAX_LOOP 200
+#define VL53L0_MAX_STRING_LENGTH 32
+
+
+#include "vl53l0_device.h"
+#include "vl53l0_types.h"
+
+
+/****************************************
+ * PRIVATE define do not edit
+ ****************************************/
+
+/** @brief Defines the parameters of the Get Version Functions
+ */
+typedef struct {
+ uint32_t revision; /*!< revision number */
+ uint8_t major; /*!< major number */
+ uint8_t minor; /*!< minor number */
+ uint8_t build; /*!< build number */
+} VL53L0_Version_t;
+
+
+/** @brief Defines the parameters of the Get Device Info Functions
+ */
+typedef struct {
+ char Name[VL53L0_MAX_STRING_LENGTH];
+ /*!< Name of the Device e.g. Left_Distance */
+ char Type[VL53L0_MAX_STRING_LENGTH];
+ /*!< Type of the Device e.g VL53L0 */
+ char ProductId[VL53L0_MAX_STRING_LENGTH];
+ /*!< Product Identifier String */
+ uint8_t ProductType;
+ /*!< Product Type, VL53L0 = 1, VL53L1 = 2 */
+ uint8_t ProductRevisionMajor;
+ /*!< Product revision major */
+ uint8_t ProductRevisionMinor;
+ /*!< Product revision minor */
+} VL53L0_DeviceInfo_t;
+
+
+/** @defgroup VL53L0_define_Error_group Error and Warning code returned by API
+ * The following DEFINE are used to identify the PAL ERROR
+ * @{
+ */
+
+typedef int8_t VL53L0_Error;
+
+#define VL53L0_ERROR_NONE ((VL53L0_Error) 0)
+#define VL53L0_ERROR_CALIBRATION_WARNING ((VL53L0_Error) - 1)
+ /*!< Warning invalid calibration data may be in used
+ * \a VL53L0_InitData()
+ * \a VL53L0_GetOffsetCalibrationData
+ * \a VL53L0_SetOffsetCalibrationData
+ */
+#define VL53L0_ERROR_MIN_CLIPPED ((VL53L0_Error) - 2)
+ /*!< Warning parameter passed was clipped to min before to be applied */
+
+#define VL53L0_ERROR_UNDEFINED ((VL53L0_Error) - 3)
+ /*!< Unqualified error */
+#define VL53L0_ERROR_INVALID_PARAMS ((VL53L0_Error) - 4)
+ /*!< Parameter passed is invalid or out of range */
+#define VL53L0_ERROR_NOT_SUPPORTED ((VL53L0_Error) - 5)
+ /*!< Function is not supported in current mode or configuration */
+#define VL53L0_ERROR_RANGE_ERROR ((VL53L0_Error) - 6)
+ /*!< Device report a ranging error interrupt status */
+#define VL53L0_ERROR_TIME_OUT ((VL53L0_Error) - 7)
+ /*!< Aborted due to time out */
+#define VL53L0_ERROR_MODE_NOT_SUPPORTED ((VL53L0_Error) - 8)
+ /*!< Asked mode is not supported by the device */
+#define VL53L0_ERROR_BUFFER_TOO_SMALL ((VL53L0_Error) - 9)
+ /*!< ... */
+#define VL53L0_ERROR_GPIO_NOT_EXISTING ((VL53L0_Error) - 10)
+ /*!< User tried to setup a non-existing GPIO pin */
+#define VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((VL53L0_Error) - 11)
+ /*!< unsupported GPIO functionality */
+#define VL53L0_ERROR_INTERRUPT_NOT_CLEARED ((VL53L0_Error) - 12)
+ /*!< Error during interrupt clear */
+#define VL53L0_ERROR_CONTROL_INTERFACE ((VL53L0_Error) - 20)
+ /*!< error reported from IO functions */
+#define VL53L0_ERROR_INVALID_COMMAND ((VL53L0_Error) - 30)
+ /*!< The command is not allowed in the current device state
+ * (power down)
+ */
+#define VL53L0_ERROR_DIVISION_BY_ZERO ((VL53L0_Error) - 40)
+ /*!< In the function a division by zero occurs */
+#define VL53L0_ERROR_REF_SPAD_INIT ((VL53L0_Error) - 50)
+ /*!< Error during reference SPAD initialization */
+#define VL53L0_ERROR_NOT_IMPLEMENTED ((VL53L0_Error) - 99)
+ /*!< Tells requested functionality has not been implemented yet or
+ * not compatible with the device
+ */
+/** @} VL53L0_define_Error_group */
+
+
+/** @defgroup VL53L0_define_DeviceModes_group Defines Device modes
+ * Defines all possible modes for the device
+ * @{
+ */
+typedef uint8_t VL53L0_DeviceModes;
+
+#define VL53L0_DEVICEMODE_SINGLE_RANGING ((VL53L0_DeviceModes) 0)
+#define VL53L0_DEVICEMODE_CONTINUOUS_RANGING ((VL53L0_DeviceModes) 1)
+#define VL53L0_DEVICEMODE_SINGLE_HISTOGRAM ((VL53L0_DeviceModes) 2)
+#define VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING ((VL53L0_DeviceModes) 3)
+#define VL53L0_DEVICEMODE_SINGLE_ALS ((VL53L0_DeviceModes) 10)
+#define VL53L0_DEVICEMODE_GPIO_DRIVE ((VL53L0_DeviceModes) 20)
+#define VL53L0_DEVICEMODE_GPIO_OSC ((VL53L0_DeviceModes) 21)
+ /* ... Modes to be added depending on device */
+/** @} VL53L0_define_DeviceModes_group */
+
+
+
+/** @defgroup VL53L0_define_HistogramModes_group Defines Histogram modes
+ * Defines all possible Histogram modes for the device
+ * @{
+ */
+typedef uint8_t VL53L0_HistogramModes;
+
+#define VL53L0_HISTOGRAMMODE_DISABLED ((VL53L0_HistogramModes) 0)
+ /*!< Histogram Disabled */
+#define VL53L0_HISTOGRAMMODE_REFERENCE_ONLY ((VL53L0_HistogramModes) 1)
+ /*!< Histogram Reference array only */
+#define VL53L0_HISTOGRAMMODE_RETURN_ONLY ((VL53L0_HistogramModes) 2)
+ /*!< Histogram Return array only */
+#define VL53L0_HISTOGRAMMODE_BOTH ((VL53L0_HistogramModes) 3)
+ /*!< Histogram both Reference and Return Arrays */
+ /* ... Modes to be added depending on device */
+/** @} VL53L0_define_HistogramModes_group */
+
+
+/** @defgroup VL53L0_define_PowerModes_group List of available Power Modes
+ * List of available Power Modes
+ * @{
+ */
+
+typedef uint8_t VL53L0_PowerModes;
+
+#define VL53L0_POWERMODE_STANDBY_LEVEL1 ((VL53L0_PowerModes) 0)
+ /*!< Standby level 1 */
+#define VL53L0_POWERMODE_STANDBY_LEVEL2 ((VL53L0_PowerModes) 1)
+ /*!< Standby level 2 */
+#define VL53L0_POWERMODE_IDLE_LEVEL1 ((VL53L0_PowerModes) 2)
+ /*!< Idle level 1 */
+#define VL53L0_POWERMODE_IDLE_LEVEL2 ((VL53L0_PowerModes) 3)
+ /*!< Idle level 2 */
+
+/** @} VL53L0_define_PowerModes_group */
+
+
+/** @brief Defines all parameters for the device
+ */
+typedef struct {
+ VL53L0_DeviceModes DeviceMode;
+ /*!< Defines type of measurement to be done for the next measure */
+ VL53L0_HistogramModes HistogramMode;
+ /*!< Defines type of histogram measurement to be done for the next
+ * measure
+ */
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+ /*!< Defines the allowed total time for a single measurement */
+ uint32_t InterMeasurementPeriodMilliSeconds;
+ /*!< Defines time between two consecutive measurements (between two
+ * measurement starts). If set to 0 means back-to-back mode
+ */
+ uint8_t XTalkCompensationEnable;
+ /*!< Tells if Crosstalk compensation shall be enable or not */
+ uint16_t XTalkCompensationRangeMilliMeter;
+ /*!< CrossTalk compensation range in millimeter */
+ FixPoint1616_t XTalkCompensationRateMegaCps;
+ /*!< CrossTalk compensation rate in Mega counts per seconds.
+ * Expressed in 16.16 fixed point format.
+ */
+ int32_t RangeOffsetMicroMeters;
+ /*!< Range offset adjustment (mm). */
+
+ uint8_t LimitChecksEnable[VL53L0_CHECKENABLE_NUMBER_OF_CHECKS];
+ /*!< This Array store all the Limit Check enable for this device. */
+ uint8_t LimitChecksStatus[VL53L0_CHECKENABLE_NUMBER_OF_CHECKS];
+ /*!< This Array store all the Status of the check linked to last
+ * measurement.
+ */
+ FixPoint1616_t LimitChecksValue[VL53L0_CHECKENABLE_NUMBER_OF_CHECKS];
+ /*!< This Array store all the Limit Check value for this device */
+
+ uint8_t WrapAroundCheckEnable;
+ /*!< Tells if Wrap Around Check shall be enable or not */
+} VL53L0_DeviceParameters_t;
+
+
+/** @defgroup VL53L0_define_State_group Defines the current status of the device
+ * Defines the current status of the device
+ * @{
+ */
+
+typedef uint8_t VL53L0_State;
+
+#define VL53L0_STATE_POWERDOWN ((VL53L0_State) 0)
+ /*!< Device is in HW reset */
+#define VL53L0_STATE_WAIT_STATICINIT ((VL53L0_State) 1)
+ /*!< Device is initialized and wait for static initialization */
+#define VL53L0_STATE_STANDBY ((VL53L0_State) 2)
+ /*!< Device is in Low power Standby mode */
+#define VL53L0_STATE_IDLE ((VL53L0_State) 3)
+ /*!< Device has been initialized and ready to do measurements */
+#define VL53L0_STATE_RUNNING ((VL53L0_State) 4)
+ /*!< Device is performing measurement */
+#define VL53L0_STATE_UNKNOWN ((VL53L0_State) 98)
+ /*!< Device is in unknown state and need to be rebooted */
+#define VL53L0_STATE_ERROR ((VL53L0_State) 99)
+ /*!< Device is in error state and need to be rebooted */
+
+/** @} VL53L0_define_State_group */
+
+
+/** @brief Structure containing the Dmax computation parameters and data
+ */
+typedef struct {
+ int32_t AmbTuningWindowFactor_K;
+ /*!< internal algo tuning (*1000) */
+ int32_t RetSignalAt0mm;
+ /*!< intermediate dmax computation value caching */
+} VL53L0_DMaxData_t;
+
+/**
+ * @struct VL53L0_RangeData_t
+ * @brief Range measurement data.
+ */
+typedef struct {
+ uint32_t TimeStamp; /*!< 32-bit time stamp. */
+ uint32_t MeasurementTimeUsec;
+ /*!< Give the Measurement time needed by the device to do the
+ * measurement.
+ */
+
+
+ uint16_t RangeMilliMeter; /*!< range distance in millimeter. */
+
+ uint16_t RangeDMaxMilliMeter;
+ /*!< Tells what is the maximum detection distance of the device
+ * in current setup and environment conditions (Filled when
+ * applicable)
+ */
+
+ FixPoint1616_t SignalRateRtnMegaCps;
+ /*!< Return signal rate (MCPS)\n these is a 16.16 fix point
+ * value, which is effectively a measure of target
+ * reflectance.
+ */
+ FixPoint1616_t AmbientRateRtnMegaCps;
+ /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point
+ * value, which is effectively a measure of the ambien
+ * t light.
+ */
+
+ uint16_t EffectiveSpadRtnCount;
+ /*!< Return the effective SPAD count for the return signal.
+ * To obtain Real value it should be divided by 256
+ */
+
+ uint8_t ZoneId;
+ /*!< Denotes which zone and range scheduler stage the range
+ * data relates to.
+ */
+ uint8_t RangeFractionalPart;
+ /*!< Fractional part of range distance. Final value is a
+ * FixPoint168 value.
+ */
+ uint8_t RangeStatus;
+ /*!< Range Status for the current measurement. This is device
+ * dependent. Value = 0 means value is valid.
+ * See \ref RangeStatusPage
+ */
+} VL53L0_RangingMeasurementData_t;
+
+
+#define VL53L0_HISTOGRAM_BUFFER_SIZE 24
+
+/**
+ * @struct VL53L0_HistogramData_t
+ * @brief Histogram measurement data.
+ */
+typedef struct {
+ /* Histogram Measurement data */
+ uint32_t HistogramData[VL53L0_HISTOGRAM_BUFFER_SIZE];
+ /*!< Histogram data */
+ /*!< Indicate the types of histogram data :
+ *Return only, Reference only, both Return and Reference
+ */
+ uint8_t HistogramType;
+ uint8_t FirstBin; /*!< First Bin value */
+ uint8_t BufferSize; /*!< Buffer Size - Set by the user.*/
+ uint8_t NumberOfBins;
+ /*!< Number of bins filled by the histogram measurement */
+
+ VL53L0_DeviceError ErrorStatus;
+ /*!< Error status of the current measurement. \n
+ * see @a ::VL53L0_DeviceError @a VL53L0_GetStatusErrorString()
+ */
+} VL53L0_HistogramMeasurementData_t;
+
+#define VL53L0_REF_SPAD_BUFFER_SIZE 6
+
+/**
+ * @struct VL53L0_SpadData_t
+ * @brief Spad Configuration Data.
+ */
+typedef struct {
+ uint8_t RefSpadEnables[VL53L0_REF_SPAD_BUFFER_SIZE];
+ /*!< Reference Spad Enables */
+ uint8_t RefGoodSpadMap[VL53L0_REF_SPAD_BUFFER_SIZE];
+ /*!< Reference Spad Good Spad Map */
+} VL53L0_SpadData_t;
+
+typedef struct {
+ FixPoint1616_t OscFrequencyMHz; /* Frequency used */
+
+ uint16_t LastEncodedTimeout;
+ /* last encoded Time out used for timing budget*/
+
+ VL53L0_GpioFunctionality Pin0GpioFunctionality;
+ /* store the functionality of the GPIO: pin0 */
+
+ uint32_t FinalRangeTimeoutMicroSecs;
+ /*!< Execution time of the final range*/
+ uint8_t FinalRangeVcselPulsePeriod;
+ /*!< Vcsel pulse period (pll clocks) for the final range measurement*/
+ uint32_t PreRangeTimeoutMicroSecs;
+ /*!< Execution time of the final range*/
+ uint8_t PreRangeVcselPulsePeriod;
+ /*!< Vcsel pulse period (pll clocks) for the pre-range measurement*/
+
+ uint16_t SigmaEstRefArray;
+ /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */
+ uint16_t SigmaEstEffPulseWidth;
+ /*!< Effective Pulse width for sigma estimate in 1/100th
+ * of ns e.g. 900 = 9.0ns
+ */
+ uint16_t SigmaEstEffAmbWidth;
+ /*!< Effective Ambient width for sigma estimate in 1/100th of ns
+ * e.g. 500 = 5.0ns
+ */
+
+
+ /* Indicate if read from device has been done (==1) or not (==0) */
+ uint8_t ReadDataFromDeviceDone;
+ uint8_t ModuleId; /* Module ID */
+ uint8_t Revision; /* test Revision */
+ char ProductId[VL53L0_MAX_STRING_LENGTH];
+ /* Product Identifier String */
+ uint8_t ReferenceSpadCount; /* used for ref spad management */
+ uint8_t ReferenceSpadType; /* used for ref spad management */
+ uint8_t RefSpadsInitialised; /* reports if ref spads are initialised. */
+ uint32_t PartUIDUpper; /*!< Unique Part ID Upper */
+ uint32_t PartUIDLower; /*!< Unique Part ID Lower */
+ /*!< Peek Signal rate at 400 mm*/
+ FixPoint1616_t SignalRateMeasFixed400mm;
+
+} VL53L0_DeviceSpecificParameters_t;
+
+/**
+ * @struct VL53L0_DevData_t
+ *
+ * @brief VL53L0 PAL device ST private data structure \n
+ * End user should never access any of these field directly
+ *
+ * These must never access directly but only via macro
+ */
+typedef struct {
+ VL53L0_DMaxData_t DMaxData;
+ /*!< Dmax Data */
+ int32_t Part2PartOffsetNVMMicroMeter;
+ /*!< backed up NVM value */
+ int32_t Part2PartOffsetAdjustmentNVMMicroMeter;
+ /*!< backed up NVM value representing additional offset adjustment */
+ VL53L0_DeviceParameters_t CurrentParameters;
+ /*!< Current Device Parameter */
+ VL53L0_RangingMeasurementData_t LastRangeMeasure;
+ /*!< Ranging Data */
+ VL53L0_HistogramMeasurementData_t LastHistogramMeasure;
+ /*!< Histogram Data */
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+ /*!< Parameters specific to the device */
+ VL53L0_SpadData_t SpadData;
+ /*!< Spad Data */
+ uint8_t SequenceConfig;
+ /*!< Internal value for the sequence config */
+ uint8_t RangeFractionalEnable;
+ /*!< Enable/Disable fractional part of ranging data */
+ VL53L0_State PalState;
+ /*!< Current state of the PAL for this device */
+ VL53L0_PowerModes PowerMode;
+ /*!< Current Power Mode */
+ uint16_t SigmaEstRefArray;
+ /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */
+ uint16_t SigmaEstEffPulseWidth;
+ /*!< Effective Pulse width for sigma estimate in 1/100th
+ * of ns e.g. 900 = 9.0ns
+ */
+ uint16_t SigmaEstEffAmbWidth;
+ /*!< Effective Ambient width for sigma estimate in 1/100th of ns
+ * e.g. 500 = 5.0ns
+ */
+ uint8_t StopVariable;
+ /*!< StopVariable used during the stop sequence */
+ uint16_t targetRefRate;
+ /*!< Target Ambient Rate for Ref spad management */
+ FixPoint1616_t SigmaEstimate;
+ /*!< Sigma Estimate - based on ambient & VCSEL rates and
+ * signal_total_events
+ */
+ FixPoint1616_t SignalEstimate;
+ /*!< Signal Estimate - based on ambient & VCSEL rates and cross talk */
+ FixPoint1616_t LastSignalRefMcps;
+ /*!< Latest Signal ref in Mcps */
+ uint8_t *pTuningSettingsPointer;
+ /*!< Pointer for Tuning Settings table */
+ uint8_t UseInternalTuningSettings;
+ /*!< Indicate if we use Tuning Settings table */
+ uint16_t LinearityCorrectiveGain;
+ /*!< Linearity Corrective Gain value in x1000 */
+ uint16_t DmaxCalRangeMilliMeter;
+ /*!< Dmax Calibration Range millimeter */
+ FixPoint1616_t DmaxCalSignalRateRtnMegaCps;
+ /*!< Dmax Calibration Signal Rate Return MegaCps */
+
+} VL53L0_DevData_t;
+
+
+/** @defgroup VL53L0_define_InterruptPolarity_group Defines the Polarity
+ * of the Interrupt
+ * Defines the Polarity of the Interrupt
+ * @{
+ */
+typedef uint8_t VL53L0_InterruptPolarity;
+
+#define VL53L0_INTERRUPTPOLARITY_LOW ((VL53L0_InterruptPolarity) 0)
+/*!< Set active low polarity best setup for falling edge. */
+#define VL53L0_INTERRUPTPOLARITY_HIGH ((VL53L0_InterruptPolarity) 1)
+/*!< Set active high polarity best setup for rising edge. */
+
+/** @} VL53L0_define_InterruptPolarity_group */
+
+
+/** @defgroup VL53L0_define_VcselPeriod_group Vcsel Period Defines
+ * Defines the range measurement for which to access the vcsel period.
+ * @{
+ */
+typedef uint8_t VL53L0_VcselPeriod;
+
+#define VL53L0_VCSEL_PERIOD_PRE_RANGE ((VL53L0_VcselPeriod) 0)
+/*!<Identifies the pre-range vcsel period. */
+#define VL53L0_VCSEL_PERIOD_FINAL_RANGE ((VL53L0_VcselPeriod) 1)
+/*!<Identifies the final range vcsel period. */
+
+/** @} VL53L0_define_VcselPeriod_group */
+
+/** @defgroup VL53L0_define_SchedulerSequence_group Defines the steps
+ * carried out by the scheduler during a range measurement.
+ * @{
+ * Defines the states of all the steps in the scheduler
+ * i.e. enabled/disabled.
+ */
+typedef struct {
+ uint8_t TccOn; /*!<Reports if Target Centre Check On */
+ uint8_t MsrcOn; /*!<Reports if MSRC On */
+ uint8_t DssOn; /*!<Reports if DSS On */
+ uint8_t PreRangeOn; /*!<Reports if Pre-Range On */
+ uint8_t FinalRangeOn; /*!<Reports if Final-Range On */
+} VL53L0_SchedulerSequenceSteps_t;
+
+/** @} VL53L0_define_SchedulerSequence_group */
+
+/** @defgroup VL53L0_define_SequenceStepId_group Defines the Polarity
+ * of the Interrupt
+ * Defines the the sequence steps performed during ranging..
+ * @{
+ */
+typedef uint8_t VL53L0_SequenceStepId;
+
+#define VL53L0_SEQUENCESTEP_TCC ((VL53L0_VcselPeriod) 0)
+/*!<Target CentreCheck identifier. */
+#define VL53L0_SEQUENCESTEP_DSS ((VL53L0_VcselPeriod) 1)
+/*!<Dynamic Spad Selection function Identifier. */
+#define VL53L0_SEQUENCESTEP_MSRC ((VL53L0_VcselPeriod) 2)
+/*!<Minimum Signal Rate Check function Identifier. */
+#define VL53L0_SEQUENCESTEP_PRE_RANGE ((VL53L0_VcselPeriod) 3)
+/*!<Pre-Range check Identifier. */
+#define VL53L0_SEQUENCESTEP_FINAL_RANGE ((VL53L0_VcselPeriod) 4)
+/*!<Final Range Check Identifier. */
+
+#define VL53L0_SEQUENCESTEP_NUMBER_OF_CHECKS 5
+/*!<Number of Sequence Step Managed by the API. */
+
+/** @} VL53L0_define_SequenceStepId_group */
+
+
+/* MACRO Definitions */
+/** @defgroup VL53L0_define_GeneralMacro_group General Macro Defines
+ * General Macro Defines
+ * @{
+ */
+
+/* Defines */
+#define VL53L0_SETPARAMETERFIELD(Dev, field, value) \
+ PALDevDataSet(Dev, CurrentParameters.field, value)
+
+#define VL53L0_GETPARAMETERFIELD(Dev, field, variable) \
+ (variable = ((PALDevDataGet(Dev, CurrentParameters)).field))
+
+
+#define VL53L0_SETARRAYPARAMETERFIELD(Dev, field, index, value) \
+ PALDevDataSet(Dev, CurrentParameters.field[index], value)
+
+#define VL53L0_GETARRAYPARAMETERFIELD(Dev, field, index, variable) \
+ (variable = (PALDevDataGet(Dev, CurrentParameters)).field[index])
+
+
+#define VL53L0_SETDEVICESPECIFICPARAMETER(Dev, field, value) \
+ PALDevDataSet(Dev, DeviceSpecificParameters.field, value)
+
+#define VL53L0_GETDEVICESPECIFICPARAMETER(Dev, field) \
+ PALDevDataGet(Dev, DeviceSpecificParameters).field
+
+
+#define VL53L0_FIXPOINT1616TOFIXPOINT97(Value) \
+ (uint16_t)((Value>>9)&0xFFFF)
+#define VL53L0_FIXPOINT97TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value<<9)
+
+#define VL53L0_FIXPOINT1616TOFIXPOINT88(Value) \
+ (uint16_t)((Value>>8)&0xFFFF)
+#define VL53L0_FIXPOINT88TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value<<8)
+
+#define VL53L0_FIXPOINT1616TOFIXPOINT412(Value) \
+ (uint16_t)((Value>>4)&0xFFFF)
+#define VL53L0_FIXPOINT412TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value<<4)
+
+#define VL53L0_FIXPOINT1616TOFIXPOINT313(Value) \
+ (uint16_t)((Value>>3)&0xFFFF)
+#define VL53L0_FIXPOINT313TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value<<3)
+
+#define VL53L0_FIXPOINT1616TOFIXPOINT08(Value) \
+ (uint8_t)((Value>>8)&0x00FF)
+#define VL53L0_FIXPOINT08TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value<<8)
+
+#define VL53L0_FIXPOINT1616TOFIXPOINT53(Value) \
+ (uint8_t)((Value>>13)&0x00FF)
+#define VL53L0_FIXPOINT53TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value<<13)
+
+#define VL53L0_FIXPOINT1616TOFIXPOINT102(Value) \
+ (uint16_t)((Value>>14)&0x0FFF)
+#define VL53L0_FIXPOINT102TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value<<12)
+
+#define VL53L0_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \
+ (uint16_t)lsb)
+
+/** @} VL53L0_define_GeneralMacro_group */
+
+/** @} VL53L0_globaldefine_group */
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _VL53L0_DEF_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_device.h b/drivers/input/misc/vl53L0/inc/vl53l0_device.h
new file mode 100644
index 000000000000..b69b9cf72279
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_device.h
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**
+ * Device specific defines. To be adapted by implementer for the targeted
+ * device.
+ */
+
+#ifndef _VL53L0_DEVICE_H_
+#define _VL53L0_DEVICE_H_
+
+#include "vl53l0_types.h"
+
+
+/** @defgroup VL53L0_DevSpecDefines_group VL53L0 cut1.1 Device Specific Defines
+ * @brief VL53L0 cut1.1 Device Specific Defines
+ * @{
+ */
+
+
+/** @defgroup VL53L0_DeviceError_group Device Error
+ * @brief Device Error code
+ *
+ * This enum is Device specific it should be updated in the implementation
+ * Use @a VL53L0_GetStatusErrorString() to get the string.
+ * It is related to Status Register of the Device.
+ * @{
+ */
+typedef uint8_t VL53L0_DeviceError;
+
+#define VL53L0_DEVICEERROR_NONE ((VL53L0_DeviceError) 0)
+ /*!< 0 NoError */
+#define VL53L0_DEVICEERROR_VCSELCONTINUITYTESTFAILURE ((VL53L0_DeviceError) 1)
+#define VL53L0_DEVICEERROR_VCSELWATCHDOGTESTFAILURE ((VL53L0_DeviceError) 2)
+#define VL53L0_DEVICEERROR_NOVHVVALUEFOUND ((VL53L0_DeviceError) 3)
+#define VL53L0_DEVICEERROR_MSRCNOTARGET ((VL53L0_DeviceError) 4)
+#define VL53L0_DEVICEERROR_SNRCHECK ((VL53L0_DeviceError) 5)
+#define VL53L0_DEVICEERROR_RANGEPHASECHECK ((VL53L0_DeviceError) 6)
+#define VL53L0_DEVICEERROR_SIGMATHRESHOLDCHECK ((VL53L0_DeviceError) 7)
+#define VL53L0_DEVICEERROR_TCC ((VL53L0_DeviceError) 8)
+#define VL53L0_DEVICEERROR_PHASECONSISTENCY ((VL53L0_DeviceError) 9)
+#define VL53L0_DEVICEERROR_MINCLIP ((VL53L0_DeviceError) 10)
+#define VL53L0_DEVICEERROR_RANGECOMPLETE ((VL53L0_DeviceError) 11)
+#define VL53L0_DEVICEERROR_ALGOUNDERFLOW ((VL53L0_DeviceError) 12)
+#define VL53L0_DEVICEERROR_ALGOOVERFLOW ((VL53L0_DeviceError) 13)
+#define VL53L0_DEVICEERROR_RANGEIGNORETHRESHOLD ((VL53L0_DeviceError) 14)
+
+/** @} end of VL53L0_DeviceError_group */
+
+
+/** @defgroup VL53L0_CheckEnable_group Check Enable list
+ * @brief Check Enable code
+ *
+ * Define used to specify the LimitCheckId.
+ * Use @a VL53L0_GetLimitCheckInfo() to get the string.
+ * @{
+ */
+
+#define VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE 0
+#define VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1
+#define VL53L0_CHECKENABLE_SIGNAL_REF_CLIP 2
+#define VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD 3
+#define VL53L0_CHECKENABLE_SIGNAL_RATE_MSRC 4
+#define VL53L0_CHECKENABLE_SIGNAL_RATE_PRE_RANGE 5
+
+#define VL53L0_CHECKENABLE_NUMBER_OF_CHECKS 6
+
+/** @} end of VL53L0_CheckEnable_group */
+
+
+/** @defgroup VL53L0_GpioFunctionality_group Gpio Functionality
+ * @brief Defines the different functionalities for the device GPIO(s)
+ * @{
+ */
+typedef uint8_t VL53L0_GpioFunctionality;
+
+#define VL53L0_GPIOFUNCTIONALITY_OFF \
+ ((VL53L0_GpioFunctionality) 0) /*!< NO Interrupt */
+#define VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW \
+ ((VL53L0_GpioFunctionality) 1) /*!< Level Low (value < thresh_low) */
+#define VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH \
+ ((VL53L0_GpioFunctionality) 2) /*!< Level High (value > thresh_high) */
+#define VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT \
+ ((VL53L0_GpioFunctionality) 3)
+ /*!< Out Of Window (value < thresh_low OR value > thresh_high) */
+#define VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY \
+ ((VL53L0_GpioFunctionality) 4) /*!< New Sample Ready */
+
+/** @} end of VL53L0_GpioFunctionality_group */
+
+
+/* Device register map */
+
+/** @defgroup VL53L0_DefineRegisters_group Define Registers
+ * @brief List of all the defined registers
+ * @{
+ */
+#define VL53L0_REG_SYSRANGE_START 0x000
+ /** mask existing bit in #VL53L0_REG_SYSRANGE_START*/
+ #define VL53L0_REG_SYSRANGE_MODE_MASK 0x0F
+ /** bit 0 in #VL53L0_REG_SYSRANGE_START write 1 toggle state in
+ * continuous mode and arm next shot in single shot mode
+ */
+ #define VL53L0_REG_SYSRANGE_MODE_START_STOP 0x01
+ /** bit 1 write 0 in #VL53L0_REG_SYSRANGE_START set single shot mode */
+ #define VL53L0_REG_SYSRANGE_MODE_SINGLESHOT 0x00
+ /** bit 1 write 1 in #VL53L0_REG_SYSRANGE_START set back-to-back
+ * operation mode
+ */
+ #define VL53L0_REG_SYSRANGE_MODE_BACKTOBACK 0x02
+ /** bit 2 write 1 in #VL53L0_REG_SYSRANGE_START set timed operation
+ * mode
+ */
+ #define VL53L0_REG_SYSRANGE_MODE_TIMED 0x04
+ /** bit 3 write 1 in #VL53L0_REG_SYSRANGE_START set histogram operation
+ * mode
+ */
+ #define VL53L0_REG_SYSRANGE_MODE_HISTOGRAM 0x08
+
+
+#define VL53L0_REG_SYSTEM_THRESH_HIGH 0x000C
+#define VL53L0_REG_SYSTEM_THRESH_LOW 0x000E
+
+
+#define VL53L0_REG_SYSTEM_SEQUENCE_CONFIG 0x0001
+#define VL53L0_REG_SYSTEM_RANGE_CONFIG 0x0009
+#define VL53L0_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x0004
+
+
+#define VL53L0_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x000A
+ #define VL53L0_REG_SYSTEM_INTERRUPT_GPIO_DISABLED 0x00
+ #define VL53L0_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_LOW 0x01
+ #define VL53L0_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_HIGH 0x02
+ #define VL53L0_REG_SYSTEM_INTERRUPT_GPIO_OUT_OF_WINDOW 0x03
+ #define VL53L0_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY 0x04
+
+#define VL53L0_REG_GPIO_HV_MUX_ACTIVE_HIGH 0x0084
+
+
+#define VL53L0_REG_SYSTEM_INTERRUPT_CLEAR 0x000B
+
+/* Result registers */
+#define VL53L0_REG_RESULT_INTERRUPT_STATUS 0x0013
+#define VL53L0_REG_RESULT_RANGE_STATUS 0x0014
+
+#define VL53L0_REG_RESULT_CORE_PAGE 1
+#define VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN 0x00BC
+#define VL53L0_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN 0x00C0
+#define VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF 0x00D0
+#define VL53L0_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF 0x00D4
+#define VL53L0_REG_RESULT_PEAK_SIGNAL_RATE_REF 0x00B6
+
+/* Algo register */
+
+#define VL53L0_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM 0x0028
+
+#define VL53L0_REG_I2C_SLAVE_DEVICE_ADDRESS 0x008a
+
+/* Check Limit registers */
+#define VL53L0_REG_MSRC_CONFIG_CONTROL 0x0060
+
+#define VL53L0_REG_PRE_RANGE_CONFIG_MIN_SNR 0X0027
+#define VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW 0x0056
+#define VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH 0x0057
+#define VL53L0_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT 0x0064
+
+#define VL53L0_REG_FINAL_RANGE_CONFIG_MIN_SNR 0X0067
+#define VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW 0x0047
+#define VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH 0x0048
+#define VL53L0_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT 0x0044
+
+
+#define VL53L0_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_HI 0X0061
+#define VL53L0_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_LO 0X0062
+
+/* PRE RANGE registers */
+#define VL53L0_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x0050
+#define VL53L0_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0051
+#define VL53L0_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0052
+
+#define VL53L0_REG_SYSTEM_HISTOGRAM_BIN 0x0081
+#define VL53L0_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT 0x0033
+#define VL53L0_REG_HISTOGRAM_CONFIG_READOUT_CTRL 0x0055
+
+#define VL53L0_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x0070
+#define VL53L0_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0071
+#define VL53L0_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0072
+#define VL53L0_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS 0x0020
+
+#define VL53L0_REG_MSRC_CONFIG_TIMEOUT_MACROP 0x0046
+
+
+#define VL53L0_REG_SOFT_RESET_GO2_SOFT_RESET_N 0x00bf
+#define VL53L0_REG_IDENTIFICATION_MODEL_ID 0x00c0
+#define VL53L0_REG_IDENTIFICATION_REVISION_ID 0x00c2
+
+#define VL53L0_REG_OSC_CALIBRATE_VAL 0x00f8
+
+
+#define VL53L0_SIGMA_ESTIMATE_MAX_VALUE 65535
+/* equivalent to a range sigma of 655.35mm */
+
+#define VL53L0_REG_GLOBAL_CONFIG_VCSEL_WIDTH 0x032
+#define VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 0x0B0
+#define VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 0x0B1
+#define VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 0x0B2
+#define VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 0x0B3
+#define VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 0x0B4
+#define VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 0x0B5
+
+#define VL53L0_REG_GLOBAL_CONFIG_REF_EN_START_SELECT 0xB6
+#define VL53L0_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD 0x4E /* 0x14E */
+#define VL53L0_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET 0x4F /* 0x14F */
+#define VL53L0_REG_POWER_MANAGEMENT_GO1_POWER_FORCE 0x80
+
+/*
+ * Speed of light in um per 1E-10 Seconds
+ */
+
+#define VL53L0_SPEED_OF_LIGHT_IN_AIR 2997
+
+#define VL53L0_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV 0x0089
+
+#define VL53L0_REG_ALGO_PHASECAL_LIM 0x0030 /* 0x130 */
+#define VL53L0_REG_ALGO_PHASECAL_CONFIG_TIMEOUT 0x0030
+
+/** @} VL53L0_DefineRegisters_group */
+
+/** @} VL53L0_DevSpecDefines_group */
+
+
+#endif
+
+/* _VL53L0_DEVICE_H_ */
+
+
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_i2c_platform.h b/drivers/input/misc/vl53L0/inc/vl53l0_i2c_platform.h
new file mode 100644
index 000000000000..9b1bdd7f3c54
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_i2c_platform.h
@@ -0,0 +1,402 @@
+/*
+ * vl53l0_i2c_platform.h - Linux kernel modules for STM VL53L0 FlightSense TOF
+ * sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/**
+ * @file VL53L0_i2c_platform.h
+ * @brief Function prototype definitions for EWOK Platform layer.
+ *
+ */
+
+
+#ifndef _VL53L0_I2C_PLATFORM_H_
+#define _VL53L0_I2C_PLATFORM_H_
+
+#include "vl53l0_def.h"
+
+
+/** Maximum buffer size to be used in i2c */
+#define VL53L0_MAX_I2C_XFER_SIZE 64
+
+/**
+ * @brief Typedef defining .\n
+ * The developer should modify this to suit the platform being deployed.
+ *
+ */
+
+/**
+ * @brief Typedef defining 8 bit unsigned char type.\n
+ * The developer should modify this to suit the platform being deployed.
+ *
+ */
+
+#ifndef bool_t
+typedef unsigned char bool_t;
+#endif
+
+
+#define I2C 0x01
+#define SPI 0x00
+
+#define COMMS_BUFFER_SIZE 64
+/*MUST be the same size as the SV task buffer */
+
+#define BYTES_PER_WORD 2
+#define BYTES_PER_DWORD 4
+
+#define VL53L0_MAX_STRING_LENGTH_PLT 256
+
+/**
+ * @brief Initialise platform comms.
+ *
+ * @param comms_type - selects between I2C and SPI
+ * @param comms_speed_khz - unsigned short containing the I2C speed in kHz
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_comms_initialise(uint8_t comms_type,
+ uint16_t comms_speed_khz);
+
+/**
+ * @brief Close platform comms.
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_comms_close(void);
+
+/**
+ * @brief Cycle Power to Device
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_cycle_power(void);
+
+int32_t VL53L0_set_page(VL53L0_DEV dev, uint8_t page_data);
+
+/**
+ * @brief Writes the supplied byte buffer to the device
+ *
+ * Wrapper for SystemVerilog Write Multi task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t *spad_enables;
+ *
+ * int status = VL53L0_write_multi(RET_SPAD_EN_0, spad_enables, 36);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint8_t buffer containing the data to be written
+ * @param count - number of bytes in the supplied byte buffer
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_write_multi(VL53L0_DEV dev, uint8_t index, uint8_t *pdata,
+ int32_t count);
+
+
+/**
+ * @brief Reads the requested number of bytes from the device
+ *
+ * Wrapper for SystemVerilog Read Multi task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t buffer[COMMS_BUFFER_SIZE];
+ *
+ * int status = status = VL53L0_read_multi(DEVICE_ID, buffer, 2)
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to the uint8_t buffer to store read data
+ * @param count - number of uint8_t's to read
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_read_multi(VL53L0_DEV dev, uint8_t index, uint8_t *pdata,
+ int32_t count);
+
+
+/**
+ * @brief Writes a single byte to the device
+ *
+ * Wrapper for SystemVerilog Write Byte task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t page_number = MAIN_SELECT_PAGE;
+ *
+ * int status = VL53L0_write_byte(PAGE_SELECT, page_number);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param data - uint8_t data value to write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_write_byte(VL53L0_DEV dev, uint8_t index, uint8_t data);
+
+
+/**
+ * @brief Writes a single word (16-bit unsigned) to the device
+ *
+ * Manages the big-endian nature of the device (first byte written is the
+ * MS byte).
+ * Uses SystemVerilog Write Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint16_t nvm_ctrl_pulse_width = 0x0004;
+ *
+ * int status = VL53L0_write_word(NVM_CTRL__PULSE_WIDTH_MSB,
+ * nvm_ctrl_pulse_width);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param data - uin16_t data value write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_write_word(VL53L0_DEV dev, uint8_t index, uint16_t data);
+
+
+/**
+ * @brief Writes a single dword (32-bit unsigned) to the device
+ *
+ * Manages the big-endian nature of the device (first byte written is the
+ * MS byte).
+ * Uses SystemVerilog Write Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint32_t nvm_data = 0x0004;
+ *
+ * int status = VL53L0_write_dword(NVM_CTRL__DATAIN_MMM, nvm_data);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param data - uint32_t data value to write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_write_dword(VL53L0_DEV dev, uint8_t index, uint32_t data);
+
+
+
+/**
+ * @brief Reads a single byte from the device
+ *
+ * Uses SystemVerilog Read Byte task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t device_status = 0;
+ *
+ * int status = VL53L0_read_byte(STATUS, &device_status);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint8_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_read_byte(VL53L0_DEV dev, uint8_t index, uint8_t *pdata);
+
+
+/**
+ * @brief Reads a single word (16-bit unsigned) from the device
+ *
+ * Manages the big-endian nature of the device (first byte read is the MS byte).
+ * Uses SystemVerilog Read Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint16_t timeout = 0;
+ *
+ * int status = VL53L0_read_word(TIMEOUT_OVERALL_PERIODS_MSB, &timeout);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint16_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_read_word(VL53L0_DEV dev, uint8_t index, uint16_t *pdata);
+
+
+/**
+ * @brief Reads a single dword (32-bit unsigned) from the device
+ *
+ * Manages the big-endian nature of the device (first byte read is the MS byte).
+ * Uses SystemVerilog Read Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint32_t range_1 = 0;
+ *
+ * int status = VL53L0_read_dword(RANGE_1_MMM, &range_1);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint32_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_read_dword(VL53L0_DEV dev, uint8_t index, uint32_t *pdata);
+
+
+/**
+ * @brief Implements a programmable wait in us
+ *
+ * Wrapper for SystemVerilog Wait in micro seconds task
+ *
+ * @param wait_us - integer wait in micro seconds
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_platform_wait_us(int32_t wait_us);
+
+
+/**
+ * @brief Implements a programmable wait in ms
+ *
+ * Wrapper for SystemVerilog Wait in milli seconds task
+ *
+ * @param wait_ms - integer wait in milli seconds
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_wait_ms(int32_t wait_ms);
+
+
+/**
+ * @brief Set GPIO value
+ *
+ * @param level - input level - either 0 or 1
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_set_gpio(uint8_t level);
+
+
+/**
+ * @brief Get GPIO value
+ *
+ * @param plevel - uint8_t pointer to store GPIO level (0 or 1)
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_get_gpio(uint8_t *plevel);
+
+/**
+ * @brief Release force on GPIO
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL53L0_release_gpio(void);
+
+
+/**
+* @brief Get the frequency of the timer used for ranging results time stamps
+*
+* @param[out] ptimer_freq_hz : pointer for timer frequency
+*
+* @return status : 0 = ok, 1 = error
+*
+*/
+
+int32_t VL53L0_get_timer_frequency(int32_t *ptimer_freq_hz);
+
+/**
+* @brief Get the timer value in units of timer_freq_hz
+* (see VL53L0_get_timestamp_frequency())
+*
+* @param[out] ptimer_count : pointer for timer count value
+*
+* @return status : 0 = ok, 1 = error
+*
+*/
+
+int32_t VL53L0_get_timer_value(int32_t *ptimer_count);
+int VL53L0_I2CWrite(VL53L0_DEV dev, uint8_t *buff, uint8_t len);
+int VL53L0_I2CRead(VL53L0_DEV dev, uint8_t *buff, uint8_t len);
+
+#endif /* _VL53L0_I2C_PLATFORM_H_ */
+
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_interrupt_threshold_settings.h b/drivers/input/misc/vl53L0/inc/vl53l0_interrupt_threshold_settings.h
new file mode 100644
index 000000000000..35acd8eb42e3
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_interrupt_threshold_settings.h
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+
+#ifndef _VL53L0_INTERRUPT_THRESHOLD_SETTINGS_H_
+#define _VL53L0_INTERRUPT_THRESHOLD_SETTINGS_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint8_t InterruptThresholdSettings[] = {
+
+ /* Start of Interrupt Threshold Settings */
+ 0x1, 0xff, 0x00,
+ 0x1, 0x80, 0x01,
+ 0x1, 0xff, 0x01,
+ 0x1, 0x00, 0x00,
+ 0x1, 0xff, 0x01,
+ 0x1, 0x4f, 0x02,
+ 0x1, 0xFF, 0x0E,
+ 0x1, 0x00, 0x03,
+ 0x1, 0x01, 0x84,
+ 0x1, 0x02, 0x0A,
+ 0x1, 0x03, 0x03,
+ 0x1, 0x04, 0x08,
+ 0x1, 0x05, 0xC8,
+ 0x1, 0x06, 0x03,
+ 0x1, 0x07, 0x8D,
+ 0x1, 0x08, 0x08,
+ 0x1, 0x09, 0xC6,
+ 0x1, 0x0A, 0x01,
+ 0x1, 0x0B, 0x02,
+ 0x1, 0x0C, 0x00,
+ 0x1, 0x0D, 0xD5,
+ 0x1, 0x0E, 0x18,
+ 0x1, 0x0F, 0x12,
+ 0x1, 0x10, 0x01,
+ 0x1, 0x11, 0x82,
+ 0x1, 0x12, 0x00,
+ 0x1, 0x13, 0xD5,
+ 0x1, 0x14, 0x18,
+ 0x1, 0x15, 0x13,
+ 0x1, 0x16, 0x03,
+ 0x1, 0x17, 0x86,
+ 0x1, 0x18, 0x0A,
+ 0x1, 0x19, 0x09,
+ 0x1, 0x1A, 0x08,
+ 0x1, 0x1B, 0xC2,
+ 0x1, 0x1C, 0x03,
+ 0x1, 0x1D, 0x8F,
+ 0x1, 0x1E, 0x0A,
+ 0x1, 0x1F, 0x06,
+ 0x1, 0x20, 0x01,
+ 0x1, 0x21, 0x02,
+ 0x1, 0x22, 0x00,
+ 0x1, 0x23, 0xD5,
+ 0x1, 0x24, 0x18,
+ 0x1, 0x25, 0x22,
+ 0x1, 0x26, 0x01,
+ 0x1, 0x27, 0x82,
+ 0x1, 0x28, 0x00,
+ 0x1, 0x29, 0xD5,
+ 0x1, 0x2A, 0x18,
+ 0x1, 0x2B, 0x0B,
+ 0x1, 0x2C, 0x28,
+ 0x1, 0x2D, 0x78,
+ 0x1, 0x2E, 0x28,
+ 0x1, 0x2F, 0x91,
+ 0x1, 0x30, 0x00,
+ 0x1, 0x31, 0x0B,
+ 0x1, 0x32, 0x00,
+ 0x1, 0x33, 0x0B,
+ 0x1, 0x34, 0x00,
+ 0x1, 0x35, 0xA1,
+ 0x1, 0x36, 0x00,
+ 0x1, 0x37, 0xA0,
+ 0x1, 0x38, 0x00,
+ 0x1, 0x39, 0x04,
+ 0x1, 0x3A, 0x28,
+ 0x1, 0x3B, 0x30,
+ 0x1, 0x3C, 0x0C,
+ 0x1, 0x3D, 0x04,
+ 0x1, 0x3E, 0x0F,
+ 0x1, 0x3F, 0x79,
+ 0x1, 0x40, 0x28,
+ 0x1, 0x41, 0x1E,
+ 0x1, 0x42, 0x2F,
+ 0x1, 0x43, 0x87,
+ 0x1, 0x44, 0x00,
+ 0x1, 0x45, 0x0B,
+ 0x1, 0x46, 0x00,
+ 0x1, 0x47, 0x0B,
+ 0x1, 0x48, 0x00,
+ 0x1, 0x49, 0xA7,
+ 0x1, 0x4A, 0x00,
+ 0x1, 0x4B, 0xA6,
+ 0x1, 0x4C, 0x00,
+ 0x1, 0x4D, 0x04,
+ 0x1, 0x4E, 0x01,
+ 0x1, 0x4F, 0x00,
+ 0x1, 0x50, 0x00,
+ 0x1, 0x51, 0x80,
+ 0x1, 0x52, 0x09,
+ 0x1, 0x53, 0x08,
+ 0x1, 0x54, 0x01,
+ 0x1, 0x55, 0x00,
+ 0x1, 0x56, 0x0F,
+ 0x1, 0x57, 0x79,
+ 0x1, 0x58, 0x09,
+ 0x1, 0x59, 0x05,
+ 0x1, 0x5A, 0x00,
+ 0x1, 0x5B, 0x60,
+ 0x1, 0x5C, 0x05,
+ 0x1, 0x5D, 0xD1,
+ 0x1, 0x5E, 0x0C,
+ 0x1, 0x5F, 0x3C,
+ 0x1, 0x60, 0x00,
+ 0x1, 0x61, 0xD0,
+ 0x1, 0x62, 0x0B,
+ 0x1, 0x63, 0x03,
+ 0x1, 0x64, 0x28,
+ 0x1, 0x65, 0x10,
+ 0x1, 0x66, 0x2A,
+ 0x1, 0x67, 0x39,
+ 0x1, 0x68, 0x0B,
+ 0x1, 0x69, 0x02,
+ 0x1, 0x6A, 0x28,
+ 0x1, 0x6B, 0x10,
+ 0x1, 0x6C, 0x2A,
+ 0x1, 0x6D, 0x61,
+ 0x1, 0x6E, 0x0C,
+ 0x1, 0x6F, 0x00,
+ 0x1, 0x70, 0x0F,
+ 0x1, 0x71, 0x79,
+ 0x1, 0x72, 0x00,
+ 0x1, 0x73, 0x0B,
+ 0x1, 0x74, 0x00,
+ 0x1, 0x75, 0x0B,
+ 0x1, 0x76, 0x00,
+ 0x1, 0x77, 0xA1,
+ 0x1, 0x78, 0x00,
+ 0x1, 0x79, 0xA0,
+ 0x1, 0x7A, 0x00,
+ 0x1, 0x7B, 0x04,
+ 0x1, 0xFF, 0x04,
+ 0x1, 0x79, 0x1D,
+ 0x1, 0x7B, 0x27,
+ 0x1, 0x96, 0x0E,
+ 0x1, 0x97, 0xFE,
+ 0x1, 0x98, 0x03,
+ 0x1, 0x99, 0xEF,
+ 0x1, 0x9A, 0x02,
+ 0x1, 0x9B, 0x44,
+ 0x1, 0x73, 0x07,
+ 0x1, 0x70, 0x01,
+ 0x1, 0xff, 0x01,
+ 0x1, 0x00, 0x01,
+ 0x1, 0xff, 0x00,
+ 0x00, 0x00, 0x00
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L0_INTERRUPT_THRESHOLD_SETTINGS_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_platform.h b/drivers/input/misc/vl53L0/inc/vl53l0_platform.h
new file mode 100644
index 000000000000..f723a552a7f1
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_platform.h
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright © 2015, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+
+#ifndef _VL53L0_PLATFORM_H_
+#define _VL53L0_PLATFORM_H_
+
+#include <linux/delay.h>
+#include "vl53l0_def.h"
+#include "vl53l0_platform_log.h"
+
+#include "stmvl53l0-i2c.h"
+#include "stmvl53l0-cci.h"
+#include "stmvl53l0.h"
+
+/**
+ * @file vl53l0_platform.h
+ *
+ * @brief All end user OS/platform/application porting
+ */
+
+/**
+ * @defgroup VL53L0_platform_group VL53L0 Platform Functions
+ * @brief VL53L0 Platform Functions
+ * @{
+ */
+
+/**
+ * @struct VL53L0_Dev_t
+ * @brief Generic PAL device type that does link between API and platform
+ * abstraction layer
+ *
+ */
+typedef struct stmvl53l0_data *VL53L0_DEV;
+
+/**
+ * @def PALDevDataGet
+ * @brief Get ST private structure @a VL53L0_DevData_t data access
+ *
+ * @param Dev Device Handle
+ * @param field ST structure field name
+ * It maybe used and as real data "ref" not just as "get" for sub-structure item
+ * like PALDevDataGet(FilterData.field)[i] or
+ * PALDevDataGet(FilterData.MeasurementIndex)++
+ */
+#define PALDevDataGet(Dev, field) (Dev->Data.field)
+
+/**
+ * @def PALDevDataSet(Dev, field, data)
+ * @brief Set ST private structure @a VL53L0_DevData_t data field
+ * @param Dev Device Handle
+ * @param field ST structure field na*me
+ * @param data Data to be set
+ */
+#define PALDevDataSet(Dev, field, data) ((Dev->Data.field) = (data))
+
+
+/**
+ * @defgroup VL53L0_registerAccess_group PAL Register Access Functions
+ * @brief PAL Register Access Functions
+ * @{
+ */
+
+/**
+ * Lock comms interface to serialize all commands to a shared I2C interface
+ * for a specific device
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_LockSequenceAccess(VL53L0_DEV Dev);
+
+/**
+ * Unlock comms interface to serialize all commands to a shared I2C interface
+ * for a specific device
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_UnlockSequenceAccess(VL53L0_DEV Dev);
+
+
+/**
+ * Writes the supplied byte buffer to the device
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param pdata Pointer to uint8_t buffer containing the data to be written
+ * @param count Number of bytes in the supplied byte buffer
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_WriteMulti(VL53L0_DEV Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count);
+
+/**
+ * Reads the requested number of bytes from the device
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param pdata Pointer to the uint8_t buffer to store read data
+ * @param count Number of uint8_t's to read
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_ReadMulti(VL53L0_DEV Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count);
+
+/**
+ * Write single byte register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data 8 bit register data
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_WrByte(VL53L0_DEV Dev, uint8_t index, uint8_t data);
+
+/**
+ * Write word register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data 16 bit register data
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_WrWord(VL53L0_DEV Dev, uint8_t index, uint16_t data);
+
+/**
+ * Write double word (4 byte) register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data 32 bit register data
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_WrDWord(VL53L0_DEV Dev, uint8_t index, uint32_t data);
+
+/**
+ * Read single byte register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data pointer to 8 bit data
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_RdByte(VL53L0_DEV Dev, uint8_t index, uint8_t *data);
+
+/**
+ * Read word (2byte) register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data pointer to 16 bit data
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_RdWord(VL53L0_DEV Dev, uint8_t index, uint16_t *data);
+
+/**
+ * Read dword (4byte) register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data pointer to 32 bit data
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_RdDWord(VL53L0_DEV Dev, uint8_t index, uint32_t *data);
+
+/**
+ * Threat safe Update (read/modify/write) single byte register
+ *
+ * Final_reg = (Initial_reg & and_data) |or_data
+ *
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param AndData 8 bit and data
+ * @param OrData 8 bit or data
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_UpdateByte(VL53L0_DEV Dev, uint8_t index,
+ uint8_t AndData, uint8_t OrData);
+
+/** @} end of VL53L0_registerAccess_group */
+
+
+/**
+ * @brief execute delay in all polling API call
+ *
+ * A typical multi-thread or RTOs implementation is to sleep the task for
+ * some 5ms (with 100Hz max rate faster polling is not needed)
+ * if nothing specific is need you can define it as an empty/void macro
+ * @code
+ * #define VL53L0_PollingDelay(...) (void)0
+ * @endcode
+ * @param Dev Device Handle
+ * @return VL53L0_ERROR_NONE Success
+ * @return "Other error code" See ::VL53L0_Error
+ */
+VL53L0_Error VL53L0_PollingDelay(VL53L0_DEV Dev);
+/* usually best implemented as a real function */
+
+/** @} end of VL53L0_platform_group */
+
+#endif /* _VL53L0_PLATFORM_H_ */
+
+
+
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_platform_log.h b/drivers/input/misc/vl53L0/inc/vl53l0_platform_log.h
new file mode 100644
index 000000000000..8c38615239ad
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_platform_log.h
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright © 2015, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+
+#ifndef _VL53L0_PLATFORM_LOG_H_
+#define _VL53L0_PLATFORM_LOG_H_
+
+#include <linux/string.h>
+/* LOG Functions */
+
+
+/**
+ * @file vl53l0_platform_log.h
+ *
+ * @brief platform log function definition
+ */
+
+/* #define VL53L0_LOG_ENABLE */
+
+enum {
+ TRACE_LEVEL_NONE,
+ TRACE_LEVEL_ERRORS,
+ TRACE_LEVEL_WARNING,
+ TRACE_LEVEL_INFO,
+ TRACE_LEVEL_DEBUG,
+ TRACE_LEVEL_ALL,
+ TRACE_LEVEL_IGNORE
+};
+
+enum {
+ TRACE_FUNCTION_NONE = 0,
+ TRACE_FUNCTION_I2C = 1,
+ TRACE_FUNCTION_ALL = 0x7fffffff /* all bits except sign */
+};
+
+enum {
+ TRACE_MODULE_NONE = 0x0,
+ TRACE_MODULE_API = 0x1,
+ TRACE_MODULE_PLATFORM = 0x2,
+ TRACE_MODULE_ALL = 0x7fffffff /* all bits except sign */
+};
+
+
+#ifdef VL53L0_LOG_ENABLE
+
+#include <linux/module.h>
+
+
+extern uint32_t _trace_level;
+
+
+
+int32_t VL53L0_trace_config(char *filename, uint32_t modules,
+ uint32_t level, uint32_t functions);
+
+#if 0
+void trace_print_module_function(uint32_t module, uint32_t level,
+ uint32_t function, const char *format, ...);
+#else
+#define trace_print_module_function(...)
+#endif
+
+#define LOG_GET_TIME() (int)0
+/*
+ * #define _LOG_FUNCTION_START(module, fmt, ...) \
+ printk(KERN_INFO"beg %s start @%d\t" fmt "\n", \
+ __func__, LOG_GET_TIME(), ##__VA_ARGS__)
+
+ * #define _LOG_FUNCTION_END(module, status, ...)\
+ printk(KERN_INFO"end %s @%d %d\n", \
+ __func__, LOG_GET_TIME(), (int)status)
+
+ * #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...)\
+ printk(KERN_INFO"End %s @%d %d\t"fmt"\n" , \
+ __func__, LOG_GET_TIME(), (int)status, ##__VA_ARGS__)
+*/
+#define _LOG_FUNCTION_START(module, fmt, ...) \
+ pr_err("beg %s start @%d\t" fmt "\n", \
+ __func__, LOG_GET_TIME(), ##__VA_ARGS__)
+
+#define _LOG_FUNCTION_END(module, status, ...)\
+ pr_err("end %s start @%d Status %d\n", \
+ __func__, LOG_GET_TIME(), (int)status)
+
+#define _LOG_FUNCTION_END_FMT(module, status, fmt, ...)\
+ pr_err("End %s @%d %d\t"fmt"\n", \
+ __func__, LOG_GET_TIME(), (int)status, ##__VA_ARGS__)
+
+
+#else /* VL53L0_LOG_ENABLE no logging */
+ #define VL53L0_ErrLog(...) (void)0
+ #define _LOG_FUNCTION_START(module, fmt, ...) (void)0
+ #define _LOG_FUNCTION_END(module, status, ...) (void)0
+ #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) (void)0
+#endif /* else */
+
+#define VL53L0_COPYSTRING(str, ...) strlcpy(str, ##__VA_ARGS__, sizeof(str))
+
+
+#endif /* _VL53L0_PLATFORM_LOG_H_ */
+
+
+
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_tuning.h b/drivers/input/misc/vl53L0/inc/vl53l0_tuning.h
new file mode 100644
index 000000000000..a9f7ca70b5ac
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_tuning.h
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+
+#ifndef _VL53L0_TUNING_H_
+#define _VL53L0_TUNING_H_
+
+#include "vl53l0_def.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint8_t DefaultTuningSettings[] = {
+
+ /* update 02/11/2015_v36 */
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x00, 0x00,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x09, 0x00,
+ 0x01, 0x10, 0x00,
+ 0x01, 0x11, 0x00,
+
+ 0x01, 0x24, 0x01,
+ 0x01, 0x25, 0xff,
+ 0x01, 0x75, 0x00,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x4e, 0x2c,
+ 0x01, 0x48, 0x00,
+ 0x01, 0x30, 0x20,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x30, 0x09, /* mja changed from 0x64. */
+ 0x01, 0x54, 0x00,
+ 0x01, 0x31, 0x04,
+ 0x01, 0x32, 0x03,
+ 0x01, 0x40, 0x83,
+ 0x01, 0x46, 0x25,
+ 0x01, 0x60, 0x00,
+ 0x01, 0x27, 0x00,
+ 0x01, 0x50, 0x06,
+ 0x01, 0x51, 0x00,
+ 0x01, 0x52, 0x96,
+ 0x01, 0x56, 0x08,
+ 0x01, 0x57, 0x30,
+ 0x01, 0x61, 0x00,
+ 0x01, 0x62, 0x00,
+ 0x01, 0x64, 0x00,
+ 0x01, 0x65, 0x00,
+ 0x01, 0x66, 0xa0,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x22, 0x32,
+ 0x01, 0x47, 0x14,
+ 0x01, 0x49, 0xff,
+ 0x01, 0x4a, 0x00,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x7a, 0x0a,
+ 0x01, 0x7b, 0x00,
+ 0x01, 0x78, 0x21,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x23, 0x34,
+ 0x01, 0x42, 0x00,
+ 0x01, 0x44, 0xff,
+ 0x01, 0x45, 0x26,
+ 0x01, 0x46, 0x05,
+ 0x01, 0x40, 0x40,
+ 0x01, 0x0E, 0x06,
+ 0x01, 0x20, 0x1a,
+ 0x01, 0x43, 0x40,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x34, 0x03,
+ 0x01, 0x35, 0x44,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x31, 0x04,
+ 0x01, 0x4b, 0x09,
+ 0x01, 0x4c, 0x05,
+ 0x01, 0x4d, 0x04,
+
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x44, 0x00,
+ 0x01, 0x45, 0x20,
+ 0x01, 0x47, 0x08,
+ 0x01, 0x48, 0x28,
+ 0x01, 0x67, 0x00,
+ 0x01, 0x70, 0x04,
+ 0x01, 0x71, 0x01,
+ 0x01, 0x72, 0xfe,
+ 0x01, 0x76, 0x00,
+ 0x01, 0x77, 0x00,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x0d, 0x01,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x80, 0x01,
+ 0x01, 0x01, 0xF8,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x8e, 0x01,
+ 0x01, 0x00, 0x01,
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x80, 0x00,
+
+ 0x00, 0x00, 0x00
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL53L0_TUNING_H_ */
diff --git a/drivers/input/misc/vl53L0/inc/vl53l0_types.h b/drivers/input/misc/vl53L0/inc/vl53l0_types.h
new file mode 100644
index 000000000000..c509913146ed
--- /dev/null
+++ b/drivers/input/misc/vl53L0/inc/vl53l0_types.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef VL53L0_TYPES_H_
+#define VL53L0_TYPES_H_
+
+#include <linux/types.h>
+
+#ifndef NULL
+#error "TODO review NULL definition or add required include "
+#define NULL 0
+#endif
+/** use where fractional values are expected
+ *
+ * Given a floating point value f it's .16 bit point is (int)(f*(1<<16))
+ */
+typedef unsigned int FixPoint1616_t;
+
+#if !defined(STDINT_H) && !defined(_GCC_STDINT_H) \
+ && !defined(_STDINT_H) && !defined(_LINUX_TYPES_H)
+
+#pragma message("Please review type definition of STDINT define for your" \
+"platform and add to list above ")
+
+/*
+* target platform do not provide stdint or use a different #define than above
+* to avoid seeing the message below addapt the #define list above or implement
+* all type and delete these pragma
+*/
+
+typedef unsigned int uint32_t;
+typedef int int32_t;
+
+typedef unsigned short uint16_t;
+typedef short int16_t;
+
+typedef unsigned char uint8_t;
+
+typedef signed char int8_t;
+
+
+#endif /* VL53L0_TYPES_H_ */
+
+#endif /* VL6180x_TYPES_H_ */
diff --git a/drivers/input/misc/vl53L0/src/vl53l010_api.c b/drivers/input/misc/vl53L0/src/vl53l010_api.c
new file mode 100644
index 000000000000..6c706bd0fe3b
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l010_api.c
@@ -0,0 +1,4175 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l010_api.h"
+#include "vl53l010_device.h"
+#include "vl53l010_tuning.h"
+
+/* use macro for abs */
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+
+
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#ifdef VL53L0_LOG_ENABLE
+#define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_API, \
+ level, TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#endif
+
+/* Defines */
+#define VL53L010_SETPARAMETERFIELD(Dev, field, value) \
+ do { \
+ if (Status == VL53L0_ERROR_NONE) {\
+ CurrentParameters = \
+ PALDevDataGet(Dev, CurrentParameters); \
+ CurrentParameters.field = value; \
+ CurrentParameters = \
+ PALDevDataSet(Dev, CurrentParameters, \
+ CurrentParameters); \
+ } \
+ } while (0)
+#define VL53L010_SETARRAYPARAMETERFIELD(Dev, field, index, value) \
+ do { \
+ if (Status == VL53L0_ERROR_NONE) {\
+ CurrentParameters = \
+ PALDevDataGet(Dev, CurrentParameters); \
+ CurrentParameters.field[index] = value; \
+ CurrentParameters = \
+ PALDevDataSet(Dev, CurrentParameters, \
+ CurrentParameters); \
+ } \
+ } while (0)
+
+#define VL53L010_GETPARAMETERFIELD(Dev, field, variable) \
+ do { \
+ if (Status == VL53L0_ERROR_NONE) { \
+ CurrentParameters = \
+ PALDevDataGet(Dev, CurrentParameters); \
+ variable = CurrentParameters.field; \
+ } \
+ } while (0)
+
+#define VL53L010_GETARRAYPARAMETERFIELD(Dev, field, index, variable) \
+ do { \
+ if (Status == VL53L0_ERROR_NONE) { \
+ CurrentParameters = \
+ PALDevDataGet(Dev, CurrentParameters); \
+ variable = CurrentParameters.field[index]; \
+ } \
+ } while (0)
+
+#define VL53L010_SETDEVICESPECIFICPARAMETER(Dev, field, value) \
+ do { \
+ if (Status == VL53L0_ERROR_NONE) { \
+ DeviceSpecificParameters = \
+ PALDevDataGet(Dev, DeviceSpecificParameters); \
+ DeviceSpecificParameters.field = value; \
+ DeviceSpecificParameters = \
+ PALDevDataSet(Dev, DeviceSpecificParameters, \
+ DeviceSpecificParameters); \
+ } \
+ } while (0)
+
+#define VL53L010_GETDEVICESPECIFICPARAMETER(Dev, field) \
+ PALDevDataGet(Dev, DeviceSpecificParameters).field
+
+#define VL53L010_FIXPOINT1616TOFIXPOINT97(Value) \
+ (uint16_t)((Value >> 9) & 0xFFFF)
+#define VL53L010_FIXPOINT97TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value << 9)
+#define VL53L010_FIXPOINT1616TOFIXPOINT412(Value) \
+ (uint16_t)((Value >> 4) & 0xFFFF)
+#define VL53L010_FIXPOINT412TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value << 4)
+#define VL53L010_FIXPOINT1616TOFIXPOINT08(Value) \
+ (uint8_t)((Value >> 8) & 0x00FF)
+#define VL53L010_FIXPOINT08TOFIXPOINT1616(Value) \
+ (FixPoint1616_t)(Value << 8)
+#define VL53L010_MAKEUINT16(lsb, msb) \
+ (uint16_t)((((uint16_t)msb) << 8) + (uint16_t)lsb)
+
+
+
+/* Group PAL General Functions */
+VL53L0_Error VL53L010_GetVersion(VL53L0_Version_t *pVersion)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ pVersion->major = VL53L010_IMPLEMENTATION_VER_MAJOR;
+ pVersion->minor = VL53L010_IMPLEMENTATION_VER_MINOR;
+ pVersion->build = VL53L010_IMPLEMENTATION_VER_SUB;
+
+ pVersion->revision = VL53L0_IMPLEMENTATION_VER_REVISION;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetPalSpecVersion(VL53L0_Version_t *pPalSpecVersion)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ pPalSpecVersion->major = VL53L010_SPECIFICATION_VER_MAJOR;
+ pPalSpecVersion->minor = VL53L010_SPECIFICATION_VER_MINOR;
+ pPalSpecVersion->build = VL53L010_SPECIFICATION_VER_SUB;
+
+ pPalSpecVersion->revision = VL53L010_SPECIFICATION_VER_REVISION;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetDeviceInfo(VL53L0_DEV Dev,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t model_id;
+ uint8_t Revision;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L010_check_part_used(Dev, &Revision, pVL53L0_DeviceInfo);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Revision == 0) {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L010_STRING_DEVICE_INFO_NAME_TS0);
+ } else if ((Revision <= 34) && (Revision != 32)) {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L010_STRING_DEVICE_INFO_NAME_TS1);
+ } else if (Revision < 39) {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L010_STRING_DEVICE_INFO_NAME_TS2);
+ } else {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L010_STRING_DEVICE_INFO_NAME_ES1);
+ }
+
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Type,
+ VL53L010_STRING_DEVICE_INFO_TYPE);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status =
+ VL53L0_RdByte(Dev, VL53L010_REG_IDENTIFICATION_MODEL_ID,
+ &pVL53L0_DeviceInfo->ProductType);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status =
+ VL53L0_RdByte(Dev, VL53L010_REG_IDENTIFICATION_REVISION_ID,
+ &model_id);
+ pVL53L0_DeviceInfo->ProductRevisionMajor = 1;
+ pVL53L0_DeviceInfo->ProductRevisionMinor =
+ (model_id & 0xF0) >> 4;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetDeviceErrorStatus(VL53L0_DEV Dev,
+ VL53L010_DeviceError *
+ pDeviceErrorStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t RangeStatus;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L010_REG_RESULT_RANGE_STATUS,
+ &RangeStatus);
+
+ *pDeviceErrorStatus = (VL53L0_DeviceError) ((RangeStatus & 0x78) >> 3);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+#define VL53L010_BUILDSTATUSERRORSTRING(BUFFER, ERRORCODE, STRINGVALUE) do {\
+ case ERRORCODE: \
+ VL53L0_COPYSTRING(BUFFER, STRINGVALUE);\
+ break;\
+ } while (0)
+
+VL53L0_Error VL53L010_GetDeviceErrorString(VL53L0_DeviceError ErrorCode,
+ char *pDeviceErrorString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (ErrorCode) {
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_NONE,
+ VL53L010_STRING_DEVICEERROR_NONE);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_VCSELCONTINUITYTESTFAILURE,
+ VL53L010_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_VCSELWATCHDOGTESTFAILURE,
+ VL53L010_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_NOVHVVALUEFOUND,
+ VL53L010_STRING_DEVICEERROR_NOVHVVALUEFOUND);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_MSRCNOTARGET,
+ VL53L010_STRING_DEVICEERROR_MSRCNOTARGET);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_MSRCMINIMUMSNR,
+ VL53L010_STRING_DEVICEERROR_MSRCMINIMUMSNR);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_MSRCWRAPAROUND,
+ VL53L010_STRING_DEVICEERROR_MSRCWRAPAROUND);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_TCC,
+ VL53L010_STRING_DEVICEERROR_TCC);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_RANGEAWRAPAROUND,
+ VL53L010_STRING_DEVICEERROR_RANGEAWRAPAROUND);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_RANGEBWRAPAROUND,
+ VL53L010_STRING_DEVICEERROR_RANGEBWRAPAROUND);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_MINCLIP,
+ VL53L010_STRING_DEVICEERROR_MINCLIP);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_RANGECOMPLETE,
+ VL53L010_STRING_DEVICEERROR_RANGECOMPLETE);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_ALGOUNDERFLOW,
+ VL53L010_STRING_DEVICEERROR_ALGOUNDERFLOW);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_ALGOOVERFLOW,
+ VL53L010_STRING_DEVICEERROR_ALGOOVERFLOW);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_FINALSNRLIMIT,
+ VL53L010_STRING_DEVICEERROR_FINALSNRLIMIT);
+ VL53L010_BUILDSTATUSERRORSTRING(pDeviceErrorString,
+ VL53L010_DEVICEERROR_NOTARGETIGNORE,
+ VL53L010_STRING_DEVICEERROR_NOTARGETIGNORE);
+ default:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L010_STRING_UNKNOW_ERROR_CODE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetPalErrorString(VL53L0_Error PalErrorCode,
+ char *pPalErrorString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (PalErrorCode) {
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_NONE,
+ VL53L010_STRING_ERROR_NONE);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_CALIBRATION_WARNING,
+ VL53L010_STRING_ERROR_CALIBRATION_WARNING);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_MIN_CLIPPED,
+ VL53L010_STRING_ERROR_MIN_CLIPPED);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_UNDEFINED,
+ VL53L010_STRING_ERROR_UNDEFINED);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_INVALID_PARAMS,
+ VL53L010_STRING_ERROR_INVALID_PARAMS);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_NOT_SUPPORTED,
+ VL53L010_STRING_ERROR_NOT_SUPPORTED);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_RANGE_ERROR,
+ VL53L010_STRING_ERROR_RANGE_ERROR);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_TIME_OUT,
+ VL53L010_STRING_ERROR_TIME_OUT);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_MODE_NOT_SUPPORTED,
+ VL53L010_STRING_ERROR_MODE_NOT_SUPPORTED);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_NOT_IMPLEMENTED,
+ VL53L010_STRING_ERROR_NOT_IMPLEMENTED);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_BUFFER_TOO_SMALL,
+ VL53L010_STRING_ERROR_BUFFER_TOO_SMALL);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_GPIO_NOT_EXISTING,
+ VL53L010_STRING_ERROR_GPIO_NOT_EXISTING);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED,
+ VL53L010_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED);
+ VL53L010_BUILDSTATUSERRORSTRING(pPalErrorString,
+ VL53L0_ERROR_CONTROL_INTERFACE,
+ VL53L010_STRING_ERROR_CONTROL_INTERFACE);
+ default:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L010_STRING_UNKNOW_ERROR_CODE);
+ break;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetPalState(VL53L0_DEV Dev, VL53L0_State *pPalState)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pPalState = PALDevDataGet(Dev, PalState);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetPowerMode(VL53L0_DEV Dev, VL53L0_PowerModes PowerMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* Only level1 of Power mode exists */
+ if ((PowerMode != VL53L0_POWERMODE_STANDBY_LEVEL1) &&
+ (PowerMode != VL53L0_POWERMODE_IDLE_LEVEL1)) {
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ } else if (PowerMode == VL53L0_POWERMODE_STANDBY_LEVEL1) {
+ /* set the standby level1 of power mode */
+ Status = VL53L0_WrByte(Dev, 0x80, 0x00);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to standby */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_STANDBY);
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_STANDBY_LEVEL1);
+ }
+
+ } else {
+ /* VL53L0_POWERMODE_IDLE_LEVEL1 */
+ Status = VL53L0_WrByte(Dev, 0x80, 0x01);
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_StaticInit(Dev);
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_IDLE_LEVEL1);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetPowerMode(VL53L0_DEV Dev,
+ VL53L0_PowerModes *pPowerMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* Only level1 of Power mode exists */
+ Status = VL53L0_RdByte(Dev, 0x80, &Byte);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Byte == 1)
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_IDLE_LEVEL1);
+ else
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_STANDBY_LEVEL1);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetOffsetCalibrationDataMicroMeter(VL53L0_DEV Dev,
+ int32_t
+ OffsetCalibrationDataMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t OffsetCalibrationData;
+
+ LOG_FUNCTION_START("");
+
+ OffsetCalibrationData = (uint8_t) (OffsetCalibrationDataMicroMeter
+ / 1000);
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_ALGO_PART_TO_PART_RANGE_OFFSET,
+ *(uint8_t *) &OffsetCalibrationData);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetOffsetCalibrationDataMicroMeter(VL53L0_DEV Dev,
+ int32_t *
+ pOffsetCalibrationDataMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t RangeOffsetRegister;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L010_REG_ALGO_PART_TO_PART_RANGE_OFFSET,
+ &RangeOffsetRegister);
+ if (Status == VL53L0_ERROR_NONE) {
+ *pOffsetCalibrationDataMicroMeter =
+ (*((int8_t *) (&RangeOffsetRegister))) * 1000;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetGroupParamHold(VL53L0_DEV Dev, uint8_t GroupParamHold)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetUpperLimitMilliMeter(VL53L0_DEV Dev,
+ uint16_t *pUpperLimitMilliMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL General Functions */
+
+/* Group PAL Init Functions */
+VL53L0_Error VL53L010_SetDeviceAddress(VL53L0_DEV Dev, uint8_t DeviceAddress)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_I2C_SLAVE_DEVICE_ADDRESS,
+ DeviceAddress / 2);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_DataInit(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+ int32_t OffsetCalibrationData;
+
+ LOG_FUNCTION_START("");
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* read device info */
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone,
+ 0);
+
+ Status = VL53L010_get_info_from_device(Dev);
+ }
+
+ /* Set Default static parameters */
+ /* set first temporary values 11.3999MHz * 65536 = 748421 */
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, 748421);
+ /* 11.3999MHz * 65536 = 748421 */
+
+ /* Get default parameters */
+ Status = VL53L010_GetDeviceParameters(Dev, &CurrentParameters);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* initialize PAL values */
+ CurrentParameters.DeviceMode = VL53L0_DEVICEMODE_SINGLE_RANGING;
+ CurrentParameters.HistogramMode = VL53L0_HISTOGRAMMODE_DISABLED;
+ PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+ }
+
+ /* Sigma estimator variable */
+ PALDevDataSet(Dev, SigmaEstRefArray, 100);
+ PALDevDataSet(Dev, SigmaEstEffPulseWidth, 900);
+ PALDevDataSet(Dev, SigmaEstEffAmbWidth, 500);
+
+ /* Set Signal and Sigma check */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetLimitCheckEnable(Dev,
+ VL53L010_CHECKENABLE_SIGMA_FINAL_RANGE,
+ 0);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetLimitCheckEnable(Dev,
+ VL53L010_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ 0);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetLimitCheckValue(Dev,
+ VL53L010_CHECKENABLE_SIGMA_FINAL_RANGE,
+ (FixPoint1616_t) (32 <<
+ 16));
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetLimitCheckValue(Dev,
+ VL53L010_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ (FixPoint1616_t) (25 * 65536 / 100));
+ /* 0.25 * 65538 */
+ }
+
+ /* Read back NVM offset */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetOffsetCalibrationDataMicroMeter(Dev,
+ &OffsetCalibrationData);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter,
+ OffsetCalibrationData);
+
+ PALDevDataSet(Dev, SequenceConfig, 0xFF);
+
+ /* Set PAL state to tell that we are waiting for call
+ * to VL53L010_StaticInit
+ */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_WAIT_STATICINIT);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_StaticInit(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint16_t TempWord;
+ uint8_t TempByte;
+ uint8_t localBuffer[32];
+ uint8_t i;
+ uint8_t Revision;
+
+ LOG_FUNCTION_START("");
+
+ /* Set I2C standard mode */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, 0x88, 0x00);
+
+ /* this function do nothing if it has been called before */
+ Status = VL53L010_get_info_from_device(Dev);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Revision = VL53L010_GETDEVICESPECIFICPARAMETER(Dev, Revision);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Revision == 0)
+ Status = VL53L010_load_additional_settings1(Dev);
+ }
+
+ /* update13_05_15 */
+ if (Status == VL53L0_ERROR_NONE) {
+ if ((Revision <= 34) && (Revision != 32)) {
+
+ for (i = 0; i < 32; i++)
+ localBuffer[i] = 0xff;
+
+ Status = VL53L0_WriteMulti(Dev, 0x90, localBuffer, 32);
+
+ Status |= VL53L0_WrByte(Dev, 0xb6, 16);
+ Status |= VL53L0_WrByte(Dev, 0xb0, 0x0);
+ Status |= VL53L0_WrByte(Dev, 0xb1, 0x0);
+ Status |= VL53L0_WrByte(Dev, 0xb2, 0xE0);
+ Status |= VL53L0_WrByte(Dev, 0xb3, 0xE0);
+ Status |= VL53L0_WrByte(Dev, 0xb4, 0xE0);
+ Status |= VL53L0_WrByte(Dev, 0xb5, 0xE0);
+ }
+ }
+
+ /* update 17_06_15_v10 */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_load_tuning_settings(Dev);
+
+ /* check if GO1 power is ON after load default tuning */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev, 0x80, &TempByte);
+ if ((TempByte != 0) && (Status == VL53L0_ERROR_NONE)) {
+ /* update 07_05_15 */
+ Status = VL53L010_load_additional_settings3(Dev);
+ }
+ }
+
+ /* Set interrupt config to new sample ready */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetGpioConfig(Dev, 0, 0,
+ VL53L010_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY,
+ VL53L0_INTERRUPTPOLARITY_LOW);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_RdWord(Dev, 0x84, &TempWord);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz,
+ VL53L010_FIXPOINT412TOFIXPOINT1616
+ (TempWord));
+ }
+
+ /* After static init, some device parameters may be changed,
+ * so update them
+ */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_GetDeviceParameters(Dev, &CurrentParameters);
+
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+
+ /* read the sequence config and save it */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev, VL53L010_REG_SYSTEM_SEQUENCE_CONFIG,
+ &TempByte);
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, TempByte);
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_PerformRefCalibration(Dev);
+
+ /* Set PAL State to standby */
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_IDLE);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_WaitDeviceBooted(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_ResetDevice(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* Set reset bit */
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+ 0x00);
+
+ /* Wait for some time */
+ if (Status == VL53L0_ERROR_NONE) {
+ do {
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_IDENTIFICATION_MODEL_ID,
+ &Byte);
+ } while (Byte != 0x00);
+ }
+
+ /* Release reset */
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+ 0x01);
+
+ /* Wait until correct boot-up of the device */
+ if (Status == VL53L0_ERROR_NONE) {
+ do {
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_IDENTIFICATION_MODEL_ID,
+ &Byte);
+ } while (Byte == 0x00);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Init Functions */
+
+/* Group PAL Parameters Functions */
+VL53L0_Error VL53L010_SetDeviceParameters(VL53L0_DEV Dev,
+ const VL53L0_DeviceParameters_t *
+ pDeviceParameters)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int i;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L010_SetDeviceMode(Dev, pDeviceParameters->DeviceMode);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetHistogramMode(Dev,
+ pDeviceParameters->
+ HistogramMode);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetInterMeasurementPeriodMilliSeconds(Dev,
+ pDeviceParameters->InterMeasurementPeriodMilliSeconds);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetXTalkCompensationEnable(Dev,
+ pDeviceParameters->
+ XTalkCompensationEnable);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetXTalkCompensationRateMegaCps(Dev,
+ pDeviceParameters->
+ XTalkCompensationRateMegaCps);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetOffsetCalibrationDataMicroMeter(Dev,
+ pDeviceParameters->
+ RangeOffsetMicroMeters);
+ }
+
+ for (i = 0; i < VL53L010_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ if (Status == VL53L0_ERROR_NONE) {
+ Status |= VL53L010_SetLimitCheckEnable(Dev, i,
+ pDeviceParameters->
+ LimitChecksEnable
+ [i]);
+ } else {
+ break;
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status |= VL53L010_SetLimitCheckValue(Dev, i,
+ pDeviceParameters->
+ LimitChecksValue
+ [i]);
+ } else {
+ break;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetWrapAroundCheckEnable(Dev,
+ pDeviceParameters->
+ WrapAroundCheckEnable);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ pDeviceParameters->MeasurementTimingBudgetMicroSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetDeviceParameters(VL53L0_DEV Dev,
+ VL53L0_DeviceParameters_t *
+ pDeviceParameters)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int i;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L010_GetDeviceMode(Dev, &(pDeviceParameters->DeviceMode));
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetHistogramMode(Dev,
+ &(pDeviceParameters->
+ HistogramMode));
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetInterMeasurementPeriodMilliSeconds(Dev,
+ &(pDeviceParameters->InterMeasurementPeriodMilliSeconds));
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetXTalkCompensationEnable(Dev,
+ &
+ (pDeviceParameters->
+ XTalkCompensationEnable));
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetXTalkCompensationRateMegaCps(Dev,
+ &(pDeviceParameters->XTalkCompensationRateMegaCps));
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetOffsetCalibrationDataMicroMeter(Dev,
+ &
+ (pDeviceParameters->
+ RangeOffsetMicroMeters));
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ for (i = 0; i < VL53L010_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ /* get first the values, then the enables.
+ *VL53L0_GetLimitCheckValue will modify the enable flags
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status |= VL53L010_GetLimitCheckValue(Dev, i,
+ &
+ (pDeviceParameters->
+ LimitChecksValue
+ [i]));
+ } else {
+ break;
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status |= VL53L010_GetLimitCheckEnable(Dev, i,
+ &
+ (pDeviceParameters->
+ LimitChecksEnable
+ [i]));
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetWrapAroundCheckEnable(Dev,
+ &(pDeviceParameters->
+ WrapAroundCheckEnable));
+ }
+
+ /* Need to be done at the end as it uses VCSELPulsePeriod */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetMeasurementTimingBudgetMicroSeconds(Dev,
+ &(pDeviceParameters->MeasurementTimingBudgetMicroSeconds));
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetDeviceMode(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("%d", (int)DeviceMode);
+
+ switch (DeviceMode) {
+ case VL53L0_DEVICEMODE_SINGLE_RANGING:
+ case VL53L0_DEVICEMODE_CONTINUOUS_RANGING:
+ case VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+ case VL53L0_DEVICEMODE_SINGLE_HISTOGRAM:
+ case VL53L0_DEVICEMODE_GPIO_DRIVE:
+ case VL53L0_DEVICEMODE_GPIO_OSC:
+ /* Supported mode */
+ VL53L010_SETPARAMETERFIELD(Dev, DeviceMode, DeviceMode);
+ break;
+ default:
+ /* Unsupported mode */
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetDeviceMode(VL53L0_DEV Dev,
+ VL53L0_DeviceModes *pDeviceMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ VL53L010_GETPARAMETERFIELD(Dev, DeviceMode, *pDeviceMode);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes HistogramMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("%d", (int)HistogramMode);
+
+ switch (HistogramMode) {
+ case VL53L0_HISTOGRAMMODE_DISABLED:
+ /* Supported mode */
+ VL53L010_SETPARAMETERFIELD(Dev, HistogramMode, HistogramMode);
+ break;
+ case VL53L0_HISTOGRAMMODE_REFERENCE_ONLY:
+ case VL53L0_HISTOGRAMMODE_RETURN_ONLY:
+ case VL53L0_HISTOGRAMMODE_BOTH:
+ default:
+ /* Unsupported mode */
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes *pHistogramMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ VL53L010_GETPARAMETERFIELD(Dev, HistogramMode, *pHistogramMode);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetMeasurementTimingBudgetMicroSeconds(VL53L0_DEV Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+ uint8_t CurrentVCSELPulsePeriod;
+ uint8_t CurrentVCSELPulsePeriodPClk;
+ uint8_t Byte;
+ uint32_t NewTimingBudgetMicroSeconds;
+ uint16_t encodedTimeOut;
+
+ LOG_FUNCTION_START("");
+
+ /* check if rangeB is done: */
+ Status = VL53L010_GetWrapAroundCheckEnable(Dev, &Byte);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (((Byte == 1) && (MeasurementTimingBudgetMicroSeconds <
+ 17000)) ||
+ ((Byte == 0) && (MeasurementTimingBudgetMicroSeconds <
+ 12000))) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ NewTimingBudgetMicroSeconds =
+ MeasurementTimingBudgetMicroSeconds - 7000;
+ if (Byte == 1) {
+ NewTimingBudgetMicroSeconds =
+ (uint32_t) (NewTimingBudgetMicroSeconds >> 1);
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_get_vcsel_pulse_period(Dev,
+ &CurrentVCSELPulsePeriodPClk,
+ 0);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ CurrentVCSELPulsePeriod =
+ VL53L010_encode_vcsel_period(CurrentVCSELPulsePeriodPClk);
+ encodedTimeOut =
+ VL53L010_calc_encoded_timeout(Dev,
+ NewTimingBudgetMicroSeconds,
+ (uint8_t)
+ CurrentVCSELPulsePeriod);
+ VL53L010_SETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev, LastEncodedTimeout,
+ encodedTimeOut);
+ }
+
+ /* Program in register */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrWord(Dev, VL53L010_REG_RNGA_TIMEOUT_MSB,
+ encodedTimeOut);
+ }
+
+ /* Temp: program same value for rangeB1 and rangeB2 */
+ /* Range B1 */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_get_vcsel_pulse_period(Dev,
+ &CurrentVCSELPulsePeriodPClk,
+ 1);
+ if (Status == VL53L0_ERROR_NONE) {
+ CurrentVCSELPulsePeriod =
+ VL53L010_encode_vcsel_period
+ (CurrentVCSELPulsePeriodPClk);
+ encodedTimeOut =
+ VL53L010_calc_encoded_timeout(Dev,
+ NewTimingBudgetMicroSeconds,
+ (uint8_t)
+ CurrentVCSELPulsePeriod);
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrWord(Dev, VL53L010_REG_RNGB1_TIMEOUT_MSB,
+ encodedTimeOut);
+ }
+
+ /* Range B2 */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_get_vcsel_pulse_period(Dev,
+ &CurrentVCSELPulsePeriodPClk,
+ 2);
+ if (Status == VL53L0_ERROR_NONE) {
+ CurrentVCSELPulsePeriod =
+ VL53L010_encode_vcsel_period
+ (CurrentVCSELPulsePeriodPClk);
+ encodedTimeOut =
+ VL53L010_calc_encoded_timeout(Dev,
+ NewTimingBudgetMicroSeconds,
+ (uint8_t)
+ CurrentVCSELPulsePeriod);
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrWord(Dev, VL53L010_REG_RNGB2_TIMEOUT_MSB,
+ encodedTimeOut);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetMeasurementTimingBudgetMicroSeconds(VL53L0_DEV Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint8_t CurrentVCSELPulsePeriod;
+ uint8_t CurrentVCSELPulsePeriodPClk;
+ uint16_t encodedTimeOut;
+ uint32_t RangATimingBudgetMicroSeconds = 0;
+ uint32_t RangBTimingBudgetMicroSeconds = 0;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* check if rangeB is done: */
+ Status = VL53L010_GetWrapAroundCheckEnable(Dev, &Byte);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_get_vcsel_pulse_period(Dev,
+ &CurrentVCSELPulsePeriodPClk,
+ 0);
+ CurrentVCSELPulsePeriod =
+ VL53L010_encode_vcsel_period(CurrentVCSELPulsePeriodPClk);
+
+ /* Read from register */
+ Status = VL53L0_RdWord(Dev, VL53L010_REG_RNGA_TIMEOUT_MSB,
+ &encodedTimeOut);
+ if (Status == VL53L0_ERROR_NONE) {
+ RangATimingBudgetMicroSeconds =
+ VL53L010_calc_ranging_wait_us(Dev,
+ encodedTimeOut,
+ CurrentVCSELPulsePeriod);
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Byte == 0) {
+ *pMeasurementTimingBudgetMicroSeconds =
+ RangATimingBudgetMicroSeconds + 7000;
+ VL53L010_SETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ *pMeasurementTimingBudgetMicroSeconds);
+ } else {
+ VL53L010_get_vcsel_pulse_period(Dev,
+ &CurrentVCSELPulsePeriodPClk,
+ 1);
+ CurrentVCSELPulsePeriod =
+ VL53L010_encode_vcsel_period
+ (CurrentVCSELPulsePeriodPClk);
+
+ /* Read from register */
+ Status = VL53L0_RdWord(Dev,
+ VL53L010_REG_RNGB1_TIMEOUT_MSB,
+ &encodedTimeOut);
+ if (Status == VL53L0_ERROR_NONE) {
+ RangBTimingBudgetMicroSeconds =
+ VL53L010_calc_ranging_wait_us(Dev,
+ encodedTimeOut,
+ CurrentVCSELPulsePeriod);
+ }
+
+ *pMeasurementTimingBudgetMicroSeconds =
+ RangATimingBudgetMicroSeconds +
+ RangBTimingBudgetMicroSeconds + 7000;
+ VL53L010_SETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ *pMeasurementTimingBudgetMicroSeconds);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetInterMeasurementPeriodMilliSeconds(VL53L0_DEV Dev,
+ uint32_t
+ InterMeasurementPeriodMilliSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint16_t osc_calibrate_val;
+ uint32_t IMPeriodMilliSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdWord(Dev, VL53L010_REG_OSC_CALIBRATE_VAL,
+ &osc_calibrate_val);
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ if (osc_calibrate_val != 0) {
+
+ IMPeriodMilliSeconds =
+ InterMeasurementPeriodMilliSeconds *
+ osc_calibrate_val;
+ } else {
+ IMPeriodMilliSeconds =
+ InterMeasurementPeriodMilliSeconds;
+ }
+ Status = VL53L0_WrDWord(Dev,
+ VL53L010_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+ IMPeriodMilliSeconds);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETPARAMETERFIELD(Dev,
+ InterMeasurementPeriodMilliSeconds,
+ InterMeasurementPeriodMilliSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetInterMeasurementPeriodMilliSeconds(VL53L0_DEV Dev,
+ uint32_t *
+ pInterMeasurementPeriodMilliSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint16_t osc_calibrate_val;
+ uint32_t IMPeriodMilliSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdWord(Dev, VL53L010_REG_OSC_CALIBRATE_VAL,
+ &osc_calibrate_val);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdDWord(Dev,
+ VL53L010_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+ &IMPeriodMilliSeconds);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (osc_calibrate_val != 0)
+ *pInterMeasurementPeriodMilliSeconds =
+ IMPeriodMilliSeconds / osc_calibrate_val;
+
+ VL53L010_SETPARAMETERFIELD(Dev,
+ InterMeasurementPeriodMilliSeconds,
+ *pInterMeasurementPeriodMilliSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetXTalkCompensationEnable(VL53L0_DEV Dev,
+ uint8_t
+ XTalkCompensationEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint8_t XTalkCompensationEnableValue;
+
+ LOG_FUNCTION_START("");
+
+ if (XTalkCompensationEnable == 0) {
+ /* Disable the crosstalk compensation */
+ XTalkCompensationEnableValue = 0x00;
+ } else {
+ /* Enable the crosstalk compensation */
+ XTalkCompensationEnableValue = 0x01;
+ }
+ Status = VL53L0_UpdateByte(Dev, VL53L010_REG_ALGO_RANGE_CHECK_ENABLES,
+ 0xFE, XTalkCompensationEnableValue);
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ XTalkCompensationEnableValue);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetXTalkCompensationEnable(VL53L0_DEV Dev, uint8_t *
+ pXTalkCompensationEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint8_t data;
+ uint8_t Temp;
+
+ LOG_FUNCTION_START("");
+
+ Status =
+ VL53L0_RdByte(Dev, VL53L010_REG_ALGO_RANGE_CHECK_ENABLES, &data);
+ if (Status == VL53L0_ERROR_NONE) {
+ if (data & 0x01)
+ Temp = 0x01;
+ else
+ Temp = 0x00;
+
+ *pXTalkCompensationEnable = Temp;
+ }
+ if (Status == VL53L0_ERROR_NONE)
+ VL53L010_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetXTalkCompensationRateMegaCps(VL53L0_DEV Dev,
+ FixPoint1616_t
+ XTalkCompensationRateMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ Status =
+ VL53L0_WrWord(Dev, VL53L010_REG_ALGO_CROSSTALK_COMPENSATION_RATE,
+ VL53L010_FIXPOINT1616TOFIXPOINT412
+ (XTalkCompensationRateMegaCps));
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ XTalkCompensationRateMegaCps);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetXTalkCompensationRateMegaCps(VL53L0_DEV Dev,
+ FixPoint1616_t *
+ pXTalkCompensationRateMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t Value;
+ FixPoint1616_t TempFix1616;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ Status =
+ VL53L0_RdWord(Dev, VL53L010_REG_ALGO_CROSSTALK_COMPENSATION_RATE,
+ (uint16_t *) &Value);
+ if (Status == VL53L0_ERROR_NONE) {
+ TempFix1616 = VL53L010_FIXPOINT412TOFIXPOINT1616(Value);
+ *pXTalkCompensationRateMegaCps = TempFix1616;
+ VL53L010_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ TempFix1616);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/*
+ * CHECK LIMIT FUNCTIONS
+ */
+
+VL53L0_Error VL53L010_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfLimitCheck = VL53L010_CHECKENABLE_NUMBER_OF_CHECKS;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+#define VL53L010_BUILDCASESTRING(BUFFER, CODE, STRINGVALUE) \
+ do { \
+ case CODE: \
+ VL53L0_COPYSTRING(BUFFER, STRINGVALUE); \
+ break; \
+ } while (0)
+
+VL53L0_Error VL53L010_GetLimitCheckInfo(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ char *pLimitCheckString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (LimitCheckId) {
+ VL53L010_BUILDCASESTRING(pLimitCheckString,
+ VL53L010_CHECKENABLE_SIGMA_FINAL_RANGE,
+ VL53L010_STRING_CHECKENABLE_SIGMA);
+ VL53L010_BUILDCASESTRING(pLimitCheckString,
+ VL53L010_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ VL53L010_STRING_CHECKENABLE_SIGNAL_RATE);
+
+ default:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L010_STRING_UNKNOW_ERROR_CODE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetLimitCheckEnable(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ uint8_t LimitCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L010_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+ if (LimitCheckEnable == 0) {
+ VL53L010_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, 0);
+ } else {
+ VL53L010_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetLimitCheckEnable(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ uint8_t *pLimitCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L010_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+ VL53L010_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, Temp8);
+ *pLimitCheckEnable = Temp8;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetLimitCheckValue(VL53L0_DEV Dev,
+ uint16_t LimitCheckId,
+ FixPoint1616_t LimitCheckValue)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L010_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+ VL53L010_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId, LimitCheckValue);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetLimitCheckValue(VL53L0_DEV Dev,
+ uint16_t LimitCheckId,
+ FixPoint1616_t *pLimitCheckValue)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L010_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+ VL53L010_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId,
+ *pLimitCheckValue);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+VL53L0_Error VL53L010_GetLimitCheckCurrent(VL53L0_DEV Dev,
+ uint16_t LimitCheckId,
+ FixPoint1616_t *pLimitCheckCurrent)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L010_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+ switch (LimitCheckId) {
+ case VL53L010_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* Need to run a ranging to have the latest values */
+ *pLimitCheckCurrent = PALDevDataGet(Dev, SigmaEstimate);
+
+ break;
+
+ case VL53L010_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+ /* Need to run a ranging to have the latest values */
+ *pLimitCheckCurrent =
+ PALDevDataGet(Dev, SignalEstimate);
+
+ break;
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+/*
+ * WRAPAROUND LIMIT
+ */
+VL53L0_Error VL53L010_SetWrapAroundCheckEnable(VL53L0_DEV Dev, uint8_t
+ WrapAroundCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+ uint8_t WrapAroundCheckEnableInt;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L010_REG_SYSTEM_SEQUENCE_CONFIG, &Byte);
+ if (WrapAroundCheckEnable == 0) {
+ /* Disable wraparound */
+ Byte = Byte & 0x7F;
+ WrapAroundCheckEnableInt = 0;
+ } else {
+ /* Enable wraparound */
+ Byte = Byte | 0x80;
+ WrapAroundCheckEnableInt = 1;
+ }
+
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSTEM_SEQUENCE_CONFIG, Byte);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ PALDevDataSet(Dev, SequenceConfig, Byte);
+ VL53L010_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+ WrapAroundCheckEnableInt);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetWrapAroundCheckEnable(VL53L0_DEV Dev,
+ uint8_t *pWrapAroundCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t data;
+ VL53L0_DeviceParameters_t CurrentParameters;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L010_REG_SYSTEM_SEQUENCE_CONFIG, &data);
+ if (Status == VL53L0_ERROR_NONE) {
+ PALDevDataSet(Dev, SequenceConfig, data);
+ if (data & (0x01 << 7))
+ *pWrapAroundCheckEnable = 0x01;
+ else
+ *pWrapAroundCheckEnable = 0x00;
+
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+ *pWrapAroundCheckEnable);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Parameters Functions */
+
+/* Group PAL Measurement Functions */
+VL53L0_Error VL53L010_PerformSingleMeasurement(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceModes DeviceMode;
+ uint8_t NewDatReady = 0;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ /* Get Current DeviceMode */
+ Status = VL53L010_GetDeviceMode(Dev, &DeviceMode);
+
+ /* Start immediately to run a single ranging measurement in case of
+ * single ranging or single histogram
+ */
+ if ((Status == VL53L0_ERROR_NONE) &&
+ ((DeviceMode == VL53L0_DEVICEMODE_SINGLE_RANGING) ||
+ (DeviceMode == VL53L0_DEVICEMODE_SINGLE_HISTOGRAM))) {
+ Status = VL53L010_StartMeasurement(Dev);
+ }
+
+ /* Wait until it finished
+ * use timeout to avoid deadlock
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+ LoopNb = 0;
+ do {
+ Status = VL53L010_GetMeasurementDataReady(Dev,
+ &NewDatReady);
+ if ((NewDatReady == 0x01) || Status !=
+ VL53L0_ERROR_NONE) {
+ break;
+ }
+ LoopNb = LoopNb + 1;
+ VL53L0_PollingDelay(Dev);
+ } while (LoopNb < VL53L0_DEFAULT_MAX_LOOP);
+
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP)
+ Status = VL53L0_ERROR_TIME_OUT;
+
+ }
+
+ /* Change PAL State in case of single ranging or single histogram
+ */
+ if ((Status == VL53L0_ERROR_NONE) &&
+ ((DeviceMode == VL53L0_DEVICEMODE_SINGLE_RANGING) ||
+ (DeviceMode == VL53L0_DEVICEMODE_SINGLE_HISTOGRAM))) {
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_IDLE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_PerformRefCalibration(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t NewDatReady = 0;
+ uint8_t Byte = 0;
+ uint8_t SequenceConfig = 0;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSTEM_SEQUENCE_CONFIG, 0x03);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ PALDevDataSet(Dev, SequenceConfig, 0x03);
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSRANGE_START,
+ VL53L010_REG_SYSRANGE_MODE_START_STOP);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Wait until start bit has been cleared */
+ LoopNb = 0;
+ do {
+ if (LoopNb > 0)
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_SYSRANGE_START,
+ &Byte);
+ LoopNb = LoopNb + 1;
+ } while (((Byte & VL53L010_REG_SYSRANGE_MODE_START_STOP) ==
+ VL53L010_REG_SYSRANGE_MODE_START_STOP) &&
+ (Status == VL53L0_ERROR_NONE) &&
+ (LoopNb < VL53L0_DEFAULT_MAX_LOOP));
+ }
+
+ /* Wait until it finished
+ * use timeout to avoid deadlock
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+ LoopNb = 0;
+ do {
+ Status = VL53L010_GetMeasurementDataReady(Dev,
+ &NewDatReady);
+ if ((NewDatReady == 0x01) || Status !=
+ VL53L0_ERROR_NONE) {
+ break;
+ }
+ LoopNb = LoopNb + 1;
+ VL53L0_PollingDelay(Dev);
+ } while (LoopNb < VL53L0_DEFAULT_MAX_LOOP);
+
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP)
+ Status = VL53L0_ERROR_TIME_OUT;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x04);
+ Status |= VL53L0_RdByte(Dev, 0x30, &Byte);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x31, Byte);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_ClearInterruptMask(Dev, 0);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* restore the previous Sequence Config */
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ }
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L010_API VL53L0_Error VL53L010_PerformXTalkCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t
+ XTalkCalDistance,
+ FixPoint1616_t *
+ pXTalkCompensationRateMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t sum_ranging = 0;
+ uint16_t sum_spads = 0;
+ FixPoint1616_t sum_signalRate = 0;
+ FixPoint1616_t total_count = 0;
+ uint8_t xtalk_meas = 0;
+ VL53L0_RangingMeasurementData_t RangingMeasurementData;
+ FixPoint1616_t xTalkStoredMeanSignalRate;
+ FixPoint1616_t xTalkStoredMeanRange;
+ FixPoint1616_t xTalkStoredMeanRtnSpads;
+ uint32_t signalXTalkTotalPerSpad;
+ uint32_t xTalkStoredMeanRtnSpadsAsInt;
+ uint32_t xTalkCalDistanceAsInt;
+ FixPoint1616_t XTalkCompensationRateMegaCps;
+
+ LOG_FUNCTION_START("");
+
+ if (XTalkCalDistance <= 0)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ /* Disable the XTalk compensation */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_SetXTalkCompensationEnable(Dev, 0);
+
+ /* Perform 50 measurements and compute the averages */
+ if (Status == VL53L0_ERROR_NONE) {
+ sum_ranging = 0;
+ sum_spads = 0;
+ sum_signalRate = 0;
+ total_count = 0;
+ for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) {
+ Status = VL53L010_PerformSingleRangingMeasurement(Dev,
+ &RangingMeasurementData);
+
+ if (Status != VL53L0_ERROR_NONE)
+ break;
+
+ /* The range is valid when RangeStatus = 0 */
+ if (RangingMeasurementData.RangeStatus == 0) {
+ sum_ranging = sum_ranging +
+ RangingMeasurementData.RangeMilliMeter;
+ sum_signalRate = sum_signalRate +
+ RangingMeasurementData.SignalRateRtnMegaCps;
+ sum_spads = sum_spads +
+ RangingMeasurementData.EffectiveSpadRtnCount
+ / 32;
+ total_count = total_count + 1;
+ }
+ }
+
+ if (total_count == 0) {
+ /* no valid values found */
+ Status = VL53L0_ERROR_DIVISION_BY_ZERO;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* FixPoint1616_t / uint16_t = FixPoint1616_t */
+ xTalkStoredMeanSignalRate = sum_signalRate / total_count;
+ xTalkStoredMeanRange =
+ (FixPoint1616_t) ((uint32_t) (sum_ranging << 16) /
+ total_count);
+ xTalkStoredMeanRtnSpads =
+ (FixPoint1616_t) ((uint32_t) (sum_spads << 16) /
+ total_count);
+
+ /* Round Mean Spads to Whole Number.
+ * Typically the calculated mean SPAD count is a whole number or
+ * very close to a whole
+ * number, therefore any truncation will not result in a
+ * significant loss in accuracy.
+ * Also, for a grey target at a typical distance of
+ * around 400mm, around 220 SPADs will
+ * be enabled, therefore, any truncation will result in a loss
+ * of accuracy of less than 0.5%.
+ */
+ xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads +
+ 0x8000) >> 16;
+
+ /* Round Cal Distance to Whole Number.
+ * Note that the cal distance is in mm,
+ * therefore no resolution is lost.
+ */
+ xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16;
+
+ if (xTalkStoredMeanRtnSpadsAsInt == 0 || xTalkCalDistanceAsInt
+ == 0 || xTalkStoredMeanRange >= XTalkCalDistance) {
+ XTalkCompensationRateMegaCps = 0;
+ } else {
+ /* Round Cal Distance to Whole Number.
+ * Note that the cal distance is in mm, therefore no
+ * resolution is lost.
+ */
+ xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >>
+ 16;
+
+ /* Apply division by mean spad count early in the
+ * calculation to keep the numbers small.
+ * This ensures we can maintain a 32bit calculation.
+ * Fixed1616 / int := Fixed1616
+ */
+ signalXTalkTotalPerSpad =
+ (xTalkStoredMeanSignalRate) /
+ xTalkStoredMeanRtnSpadsAsInt;
+
+ /* Complete the calculation for total Signal XTalk per
+ * SPAD Fixed1616 * (Fixed1616 - Fixed1616/int)
+ * := (2^16 * Fixed1616)
+ */
+ signalXTalkTotalPerSpad *= ((1 << 16) -
+ (xTalkStoredMeanRange /
+ xTalkCalDistanceAsInt));
+
+ /* Round from 2^16 * Fixed1616, to Fixed1616. */
+ XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad
+ + 0x8000) >> 16;
+ }
+
+ *pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps;
+
+ /* Enable the XTalk compensation */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_SetXTalkCompensationEnable(Dev, 1);
+
+ /* Enable the XTalk compensation */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_SetXTalkCompensationRateMegaCps(Dev,
+ XTalkCompensationRateMegaCps);
+ }
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L010_API VL53L0_Error VL53L010_PerformOffsetCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t
+ CalDistanceMilliMeter,
+ int32_t *
+ pOffsetMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t sum_ranging = 0;
+ FixPoint1616_t total_count = 0;
+ VL53L0_RangingMeasurementData_t RangingMeasurementData;
+ FixPoint1616_t StoredMeanRange;
+ uint32_t StoredMeanRangeAsInt;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ uint32_t CalDistanceAsInt_mm;
+ int meas = 0;
+
+ LOG_FUNCTION_START("");
+
+ if (CalDistanceMilliMeter <= 0)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ if (Status == VL53L0_ERROR_NONE)
+ VL53L010_SetOffsetCalibrationDataMicroMeter(Dev, 0);
+
+ /* Perform 50 measurements and compute the averages */
+ if (Status == VL53L0_ERROR_NONE) {
+ sum_ranging = 0;
+ total_count = 0;
+ for (meas = 0; meas < 50; meas++) {
+ Status =
+ VL53L010_PerformSingleRangingMeasurement(Dev,
+ &RangingMeasurementData);
+
+ if (Status != VL53L0_ERROR_NONE)
+ break;
+
+ /* The range is valid when RangeStatus = 0 */
+ if (RangingMeasurementData.RangeStatus == 0) {
+ sum_ranging =
+ sum_ranging +
+ RangingMeasurementData.RangeMilliMeter;
+ total_count = total_count + 1;
+ }
+ }
+
+ if (total_count == 0) {
+ /* no valid values found */
+ Status = VL53L0_ERROR_RANGE_ERROR;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* FixPoint1616_t / uint16_t = FixPoint1616_t */
+ StoredMeanRange =
+ (FixPoint1616_t) ((uint32_t) (sum_ranging << 16) /
+ total_count);
+
+ StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16;
+
+ /* Round Cal Distance to Whole Number.
+ * Note that the cal distance is in mm,
+ * therefore no resolution is lost.
+ */
+ CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16;
+
+ *pOffsetMicroMeter =
+ (CalDistanceAsInt_mm - StoredMeanRangeAsInt) * 1000;
+
+ /* Apply the calculated offset */
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
+ *pOffsetMicroMeter);
+ Status =
+ VL53L010_SetOffsetCalibrationDataMicroMeter(Dev,
+ *pOffsetMicroMeter);
+ }
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_StartMeasurement(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceModes DeviceMode;
+ uint8_t Byte = 0;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ /* Get Current DeviceMode */
+ VL53L010_GetDeviceMode(Dev, &DeviceMode);
+
+ switch (DeviceMode) {
+ case VL53L0_DEVICEMODE_SINGLE_RANGING:
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSRANGE_START,
+ VL53L010_REG_SYSRANGE_MODE_SINGLESHOT |
+ VL53L010_REG_SYSRANGE_MODE_START_STOP);
+ break;
+ case VL53L0_DEVICEMODE_CONTINUOUS_RANGING:
+ /* Back-to-back mode */
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSRANGE_START,
+ VL53L010_REG_SYSRANGE_MODE_BACKTOBACK |
+ VL53L010_REG_SYSRANGE_MODE_START_STOP);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to Running */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_RUNNING);
+ }
+ break;
+ case VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+ /* Continuous mode */
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSRANGE_START,
+ VL53L010_REG_SYSRANGE_MODE_TIMED |
+ VL53L010_REG_SYSRANGE_MODE_START_STOP);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to Running */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_RUNNING);
+ }
+ break;
+ default:
+ /* Selected mode not supported */
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Wait until start bit has been cleared */
+ LoopNb = 0;
+ do {
+ if (LoopNb > 0)
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_SYSRANGE_START,
+ &Byte);
+ LoopNb = LoopNb + 1;
+ } while (((Byte & VL53L010_REG_SYSRANGE_MODE_START_STOP) ==
+ VL53L010_REG_SYSRANGE_MODE_START_STOP) &&
+ (Status == VL53L0_ERROR_NONE) &&
+ (LoopNb < VL53L0_DEFAULT_MAX_LOOP));
+
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP)
+ Status = VL53L0_ERROR_TIME_OUT;
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_StopMeasurement(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSRANGE_START,
+ VL53L010_REG_SYSRANGE_MODE_SINGLESHOT);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to Idle */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_IDLE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetMeasurementDataReady(VL53L0_DEV Dev, uint8_t
+ *pMeasurementDataReady)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SysRangeStatusRegister;
+ uint8_t InterruptConfig;
+ uint32_t InterruptMask;
+
+ LOG_FUNCTION_START("");
+
+ InterruptConfig = VL53L010_GETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality);
+
+ if (InterruptConfig ==
+ VL53L010_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) {
+ VL53L010_GetInterruptMaskStatus(Dev, &InterruptMask);
+ if (InterruptMask ==
+ VL53L010_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) {
+ *pMeasurementDataReady = 1;
+ } else {
+ *pMeasurementDataReady = 0;
+ }
+ } else {
+ Status = VL53L0_RdByte(Dev, VL53L010_REG_RESULT_RANGE_STATUS,
+ &SysRangeStatusRegister);
+ if (Status == VL53L0_ERROR_NONE) {
+ if (SysRangeStatusRegister & 0x01)
+ *pMeasurementDataReady = 1;
+ else
+ *pMeasurementDataReady = 0;
+
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_WaitDeviceReadyForNewMeasurement(VL53L0_DEV Dev, uint32_t
+ MaxLoop)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented for VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetRangingMeasurementData(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t
+ *pRangingMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t DeviceRangeStatus;
+ uint8_t PalRangeStatus;
+ uint16_t AmbientRate;
+ FixPoint1616_t SignalRate;
+ FixPoint1616_t CrosstalkCompensation;
+ uint16_t EffectiveSpadRtnCount;
+ uint8_t localBuffer[14];
+ VL53L0_RangingMeasurementData_t LastRangeDataBuffer;
+
+ LOG_FUNCTION_START("");
+
+ /* use multi read even if some registers are not useful, result will be
+ * more efficient
+ * start reading at 0x14 dec20
+ * end reading at 0x21 dec33 total 14 bytes to read
+ */
+ Status = VL53L0_ReadMulti(Dev, 0x14, localBuffer, 14);
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ pRangingMeasurementData->ZoneId = 0; /* Only one zone */
+ pRangingMeasurementData->TimeStamp = 0; /* Not Implemented */
+
+ pRangingMeasurementData->RangeMilliMeter =
+ VL53L010_MAKEUINT16(localBuffer[11], localBuffer[10]);
+
+ pRangingMeasurementData->RangeDMaxMilliMeter = 0;
+ pRangingMeasurementData->RangeFractionalPart = 0;
+ pRangingMeasurementData->MeasurementTimeUsec = 0;
+
+ SignalRate =
+ VL53L010_FIXPOINT97TOFIXPOINT1616(VL53L010_MAKEUINT16
+ (localBuffer[7],
+ localBuffer[6]));
+ pRangingMeasurementData->SignalRateRtnMegaCps = SignalRate;
+
+ AmbientRate =
+ VL53L010_MAKEUINT16(localBuffer[9], localBuffer[8]);
+ pRangingMeasurementData->AmbientRateRtnMegaCps =
+ VL53L010_FIXPOINT97TOFIXPOINT1616(AmbientRate);
+
+ EffectiveSpadRtnCount = VL53L010_MAKEUINT16(localBuffer[3],
+ localBuffer[2]);
+ pRangingMeasurementData->EffectiveSpadRtnCount =
+ EffectiveSpadRtnCount;
+
+ DeviceRangeStatus = localBuffer[0];
+
+ /* initial format = 4.12, when pass to 16.16 from 9.7 we shift
+ * 5 bit more this will be absorbed in the further computation
+ */
+ CrosstalkCompensation =
+ VL53L010_FIXPOINT97TOFIXPOINT1616(VL53L010_MAKEUINT16
+ (localBuffer[13],
+ localBuffer[12]));
+
+ /*
+ * For a standard definition of RangeStatus, this should return
+ * 0 in case of good result after a ranging
+ * The range status depends on the device so call a device
+ * specific function to obtain the right Status.
+ */
+ Status = VL53L010_get_pal_range_status(Dev, DeviceRangeStatus,
+ SignalRate,
+ CrosstalkCompensation,
+ EffectiveSpadRtnCount,
+ pRangingMeasurementData,
+ &PalRangeStatus);
+
+ if (Status == VL53L0_ERROR_NONE)
+ pRangingMeasurementData->RangeStatus = PalRangeStatus;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Copy last read data into Dev buffer */
+ LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure);
+
+ LastRangeDataBuffer.RangeMilliMeter =
+ pRangingMeasurementData->RangeMilliMeter;
+ LastRangeDataBuffer.RangeFractionalPart =
+ pRangingMeasurementData->RangeFractionalPart;
+ LastRangeDataBuffer.RangeDMaxMilliMeter =
+ pRangingMeasurementData->RangeDMaxMilliMeter;
+ LastRangeDataBuffer.MeasurementTimeUsec =
+ pRangingMeasurementData->MeasurementTimeUsec;
+ LastRangeDataBuffer.SignalRateRtnMegaCps =
+ pRangingMeasurementData->SignalRateRtnMegaCps;
+ LastRangeDataBuffer.AmbientRateRtnMegaCps =
+ pRangingMeasurementData->AmbientRateRtnMegaCps;
+ LastRangeDataBuffer.EffectiveSpadRtnCount =
+ pRangingMeasurementData->EffectiveSpadRtnCount;
+ LastRangeDataBuffer.RangeStatus =
+ pRangingMeasurementData->RangeStatus;
+
+ PALDevDataSet(Dev, LastRangeMeasure, LastRangeDataBuffer);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetHistogramMeasurementData(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t
+ *pHistogramMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_PerformSingleRangingMeasurement(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t
+ *pRangingMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* This function will do a complete single ranging
+ * Here we fix the mode!
+ */
+ Status = VL53L010_SetDeviceMode(Dev, VL53L0_DEVICEMODE_SINGLE_RANGING);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_PerformSingleMeasurement(Dev);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetRangingMeasurementData(Dev,
+ pRangingMeasurementData);
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_ClearInterruptMask(Dev, 0);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_PerformSingleHistogramMeasurement(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t
+ *
+ pHistogramMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetNumberOfROIZones(VL53L0_DEV Dev, uint8_t
+ NumberOfROIZones)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if (NumberOfROIZones != 1)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetNumberOfROIZones(VL53L0_DEV Dev, uint8_t *
+ pNumberOfROIZones)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfROIZones = 1;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetMaxNumberOfROIZones(VL53L0_DEV Dev, uint8_t
+ *pMaxNumberOfROIZones)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pMaxNumberOfROIZones = 1;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Measurement Functions */
+
+VL53L0_Error VL53L010_SetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes DeviceMode,
+ VL53L0_GpioFunctionality Functionality,
+ VL53L0_InterruptPolarity Polarity)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ if (Pin != 0) {
+ Status = VL53L0_ERROR_GPIO_NOT_EXISTING;
+ } else if (DeviceMode == VL53L0_DEVICEMODE_GPIO_DRIVE) {
+ if (Polarity == VL53L0_INTERRUPTPOLARITY_LOW)
+ data = 0x10;
+ else
+ data = 1;
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L010_REG_GPIO_HV_MUX_ACTIVE_HIGH,
+ data);
+
+ } else if (DeviceMode == VL53L0_DEVICEMODE_GPIO_OSC) {
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x85, 0x02);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xcd, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xcc, 0x11);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0xbe, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x06);
+ Status |= VL53L0_WrByte(Dev, 0xcc, 0x09);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ } else {
+
+ if (Status == VL53L0_ERROR_NONE) {
+ switch (Functionality) {
+ case VL53L010_GPIOFUNCTIONALITY_OFF:
+ data = 0x00;
+ break;
+ case VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW:
+ data = 0x01;
+ break;
+ case VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH:
+ data = 0x02;
+ break;
+ case VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT:
+ data = 0x03;
+ break;
+ case VL53L010_GPIOFUNCTIONALITY_NEW_MEASURE_READY:
+ data = 0x04;
+ break;
+ default:
+ Status =
+ VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrByte(Dev,
+ VL53L010_REG_SYSTEM_INTERRUPT_CONFIG_GPIO,
+ data);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Polarity == VL53L0_INTERRUPTPOLARITY_LOW)
+ data = 0;
+ else
+ data = (uint8_t) (1 << 4);
+
+ Status = VL53L0_UpdateByte(Dev,
+ VL53L010_REG_GPIO_HV_MUX_ACTIVE_HIGH,
+ 0xEF, data);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality,
+ Functionality);
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L010_ClearInterruptMask(Dev, 0);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes *DeviceMode,
+ VL53L0_GpioFunctionality *pFunctionality,
+ VL53L0_InterruptPolarity *pPolarity)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+ VL53L0_GpioFunctionality GpioFunctionality;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ if (Pin != 0) {
+ Status = VL53L0_ERROR_GPIO_NOT_EXISTING;
+ } else {
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_SYSTEM_INTERRUPT_CONFIG_GPIO,
+ &data);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ switch (data & 0x07) {
+ case 0x00:
+ GpioFunctionality = VL53L010_GPIOFUNCTIONALITY_OFF;
+ break;
+ case 0x01:
+ GpioFunctionality =
+ VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW;
+ break;
+ case 0x02:
+ GpioFunctionality =
+ VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH;
+ break;
+ case 0x03:
+ GpioFunctionality =
+ VL53L010_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT;
+ break;
+ case 0x04:
+ GpioFunctionality =
+ VL53L010_GPIOFUNCTIONALITY_NEW_MEASURE_READY;
+ break;
+ default:
+ Status = VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_GPIO_HV_MUX_ACTIVE_HIGH,
+ &data);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if ((data & (uint8_t) (1 << 4)) == 0)
+ *pPolarity = VL53L0_INTERRUPTPOLARITY_LOW;
+ else
+ *pPolarity = VL53L0_INTERRUPTPOLARITY_HIGH;
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ *pFunctionality = GpioFunctionality;
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev, Pin0GpioFunctionality,
+ GpioFunctionality);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetInterruptThresholds(VL53L0_DEV Dev, VL53L0_DeviceModes
+ DeviceMode,
+ FixPoint1616_t ThresholdLow,
+ FixPoint1616_t ThresholdHigh)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t Threshold16;
+
+ LOG_FUNCTION_START("");
+
+ /* no dependency on DeviceMode for Ewok */
+ /* Need to divide by 2 because the FW will apply a x2 */
+ Threshold16 = (uint16_t) ((ThresholdLow >> 17) & 0x00fff);
+ Status =
+ VL53L0_WrWord(Dev, VL53L010_REG_SYSTEM_THRESH_LOW, Threshold16);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Need to divide by 2 because the FW will apply a x2 */
+ Threshold16 = (uint16_t) ((ThresholdHigh >> 17) & 0x00fff);
+ Status = VL53L0_WrWord(Dev, VL53L010_REG_SYSTEM_THRESH_HIGH,
+ Threshold16);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetInterruptThresholds(VL53L0_DEV Dev, VL53L0_DeviceModes
+ DeviceMode,
+ FixPoint1616_t *pThresholdLow,
+ FixPoint1616_t *pThresholdHigh)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t Threshold16;
+
+ LOG_FUNCTION_START("");
+
+ /* no dependency on DeviceMode for Ewok */
+
+ Status =
+ VL53L0_RdWord(Dev, VL53L010_REG_SYSTEM_THRESH_LOW, &Threshold16);
+ /* Need to multiply by 2 because the FW will apply a x2 */
+ *pThresholdLow = (FixPoint1616_t) ((0x00fff & Threshold16) << 17);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev, VL53L010_REG_SYSTEM_THRESH_HIGH,
+ &Threshold16);
+ /* Need to multiply by 2 because the FW will apply a x2 */
+ *pThresholdHigh =
+ (FixPoint1616_t) ((0x00fff & Threshold16) << 17);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* Group PAL Interrupt Functions */
+VL53L0_Error VL53L010_ClearInterruptMask(VL53L0_DEV Dev, uint32_t InterruptMask)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t LoopCount;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* clear bit 0 range interrupt, bit 1 error interrupt */
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSTEM_INTERRUPT_CLEAR, 0x01);
+ LoopCount = 0;
+ do {
+ VL53L0_RdByte(Dev, VL53L010_REG_RESULT_INTERRUPT_STATUS, &Byte);
+ LoopCount++;
+ } while (((Byte & 0x07) != 0x00) && (LoopCount < 8));
+ Status = VL53L0_WrByte(Dev, VL53L010_REG_SYSTEM_INTERRUPT_CLEAR, 0x00);
+ /* clear all */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetInterruptMaskStatus(VL53L0_DEV Dev, uint32_t
+ *pInterruptMaskStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Status =
+ VL53L0_RdByte(Dev, VL53L010_REG_RESULT_INTERRUPT_STATUS, &Byte);
+ *pInterruptMaskStatus = Byte & 0x07;
+
+ /* check if some error occurs */
+ if (Byte & 0x18)
+ Status = VL53L0_ERROR_RANGE_ERROR;
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_EnableInterruptMask(VL53L0_DEV Dev,
+ uint32_t InterruptMask)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented for VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Interrupt Functions */
+
+/* Group SPAD functions */
+
+VL53L0_Error VL53L010_SetSpadAmbientDamperThreshold(VL53L0_DEV Dev, uint16_t
+ SpadAmbientDamperThreshold)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status = VL53L0_WrWord(Dev, 0x40, SpadAmbientDamperThreshold);
+ VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetSpadAmbientDamperThreshold(VL53L0_DEV Dev, uint16_t
+ *
+ pSpadAmbientDamperThreshold)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status = VL53L0_RdWord(Dev, 0x40, pSpadAmbientDamperThreshold);
+ VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_SetSpadAmbientDamperFactor(VL53L0_DEV Dev, uint16_t
+ SpadAmbientDamperFactor)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Byte = (uint8_t) (SpadAmbientDamperFactor & 0x00FF);
+
+ VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status = VL53L0_WrByte(Dev, 0x42, Byte);
+ VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_GetSpadAmbientDamperFactor(VL53L0_DEV Dev, uint16_t
+ *pSpadAmbientDamperFactor)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status = VL53L0_RdByte(Dev, 0x42, &Byte);
+ VL53L0_WrByte(Dev, 0xFF, 0x00);
+ *pSpadAmbientDamperFactor = (uint16_t) Byte;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* END Group SPAD functions */
+
+/*
+ * Internal functions
+ */
+
+
+
+VL53L010_EXTERNAL VL53L0_Error VL53L010_get_vcsel_pulse_period(VL53L0_DEV Dev,
+ uint8_t *
+ pVCSELPulsePeriod,
+ uint8_t
+ RangeIndex)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t vcsel_period_reg;
+
+ LOG_FUNCTION_START("");
+
+ switch (RangeIndex) {
+ case 0:
+ Status =
+ VL53L0_RdByte(Dev, VL53L010_REG_RNGA_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ break;
+ case 1:
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_RNGB1_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ break;
+ case 2:
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_RNGB2_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ break;
+ default:
+ Status =
+ VL53L0_RdByte(Dev, VL53L010_REG_RNGA_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ *pVCSELPulsePeriod =
+ VL53L010_decode_vcsel_period(vcsel_period_reg);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* To convert ms into register value */
+VL53L010_EXTERNAL uint16_t VL53L010_calc_encoded_timeout(VL53L0_DEV Dev,
+ uint32_t
+ timeout_period_us,
+ uint8_t vcsel_period)
+{
+ uint32_t macro_period_ps;
+ uint32_t macro_period_ns;
+ uint32_t timeout_period_mclks = 0;
+ uint16_t timeout_overall_periods = 0;
+
+ macro_period_ps = VL53L010_calc_macro_period_ps(Dev, vcsel_period);
+ macro_period_ns = macro_period_ps / 1000;
+
+ timeout_period_mclks = (uint32_t) (((timeout_period_us * 1000) +
+ (macro_period_ns / 2)) /
+ macro_period_ns);
+ timeout_overall_periods = VL53L010_encode_timeout(timeout_period_mclks);
+
+ return timeout_overall_periods;
+}
+
+/* To convert register value into us */
+VL53L010_EXTERNAL uint32_t VL53L010_calc_ranging_wait_us(VL53L0_DEV Dev,
+ uint16_t
+ timeout_overall_periods,
+ uint8_t vcsel_period)
+{
+ uint32_t macro_period_ps;
+ uint32_t macro_period_ns;
+ uint32_t timeout_period_mclks = 0;
+ uint32_t actual_timeout_period_us = 0;
+
+ macro_period_ps = VL53L010_calc_macro_period_ps(Dev, vcsel_period);
+ macro_period_ns = macro_period_ps / 1000;
+
+ timeout_period_mclks = VL53L010_decode_timeout(timeout_overall_periods);
+ actual_timeout_period_us = ((timeout_period_mclks * macro_period_ns) +
+ (macro_period_ns / 2)) / 1000;
+
+ return actual_timeout_period_us;
+}
+
+VL53L010_EXTERNAL uint32_t VL53L010_calc_macro_period_ps(VL53L0_DEV Dev,
+ uint8_t vcsel_period)
+{
+ uint32_t PLL_multiplier;
+ uint64_t PLL_period_ps;
+ uint8_t vcsel_period_pclks;
+ uint32_t macro_period_vclks;
+ uint32_t macro_period_ps;
+ FixPoint1616_t OscFrequencyMHz;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+
+ LOG_FUNCTION_START("");
+
+ PLL_multiplier = 65536 / 64; /* PLL multiplier is 64 */
+
+ OscFrequencyMHz = VL53L010_GETDEVICESPECIFICPARAMETER(Dev,
+ OscFrequencyMHz);
+
+ if (OscFrequencyMHz == 0) {
+ /* Use default one */
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz,
+ 748421);
+ OscFrequencyMHz = 748421;
+ }
+ PLL_period_ps = (1000 * 1000 * PLL_multiplier) / OscFrequencyMHz;
+
+ vcsel_period_pclks = VL53L010_decode_vcsel_period(vcsel_period);
+
+ macro_period_vclks = 2304;
+ macro_period_ps = (uint32_t) (macro_period_vclks * vcsel_period_pclks *
+ PLL_period_ps);
+
+ LOG_FUNCTION_END("");
+ return macro_period_ps;
+}
+
+VL53L010_EXTERNAL uint8_t VL53L010_decode_vcsel_period(uint8_t vcsel_period_reg)
+{
+
+ /*!
+ * Converts the encoded VCSEL period register value into the real
+ * period in PLL clocks
+ */
+
+ uint8_t vcsel_period_pclks = 0;
+
+ vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
+
+ return vcsel_period_pclks;
+}
+
+VL53L010_EXTERNAL uint8_t VL53L010_encode_vcsel_period(uint8_t
+ vcsel_period_pclks)
+{
+
+ /*!
+ * Converts the encoded VCSEL period register value into the real
+ * period in PLL clocks
+ */
+
+ uint8_t vcsel_period_reg = 0;
+
+ vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
+
+ return vcsel_period_reg;
+}
+
+VL53L010_EXTERNAL uint16_t VL53L010_encode_timeout(uint32_t timeout_mclks)
+{
+ /*!
+ * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
+ *
+ */
+
+ uint16_t encoded_timeout = 0;
+ uint32_t ls_byte = 0;
+ uint16_t ms_byte = 0;
+
+ if (timeout_mclks > 0) {
+ ls_byte = timeout_mclks - 1;
+
+ while ((ls_byte & 0xFFFFFF00) > 0) {
+ ls_byte = ls_byte >> 1;
+ ms_byte++;
+ }
+
+ encoded_timeout = (ms_byte << 8) + (uint16_t) (ls_byte &
+ 0x000000FF);
+
+ }
+
+ return encoded_timeout;
+
+}
+
+VL53L010_EXTERNAL uint32_t VL53L010_decode_timeout(uint16_t encoded_timeout)
+{
+ /*!
+ * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1
+ *
+ */
+
+ uint32_t timeout_mclks = 0;
+
+ timeout_mclks = ((uint32_t) (encoded_timeout & 0x00FF) << (uint32_t)
+ ((encoded_timeout & 0xFF00) >> 8)) + 1;
+
+ return timeout_mclks;
+
+}
+
+VL53L010_EXTERNAL VL53L0_Error VL53L010_load_additional_settings1(VL53L0_DEV
+ Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* update 12_05_15_v6 */
+ /* OSCT */
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x14, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xCD, 0x6C);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x86, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x87, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ /* update 12_05_15_v6 */
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xcd, 0x6c);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x90, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x91, 0x3f);
+ Status |= VL53L0_WrByte(Dev, 0x92, 0x3f);
+ Status |= VL53L0_WrByte(Dev, 0x88, 0x2b);
+ Status |= VL53L0_WrByte(Dev, 0x89, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xcd, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ /* update 12_05_15 */
+ Status |= VL53L0_WrByte(Dev, 0xb0, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xb1, 0xfc);
+ Status |= VL53L0_WrByte(Dev, 0xb2, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xb3, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xb4, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xb5, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xb6, 0xb0);
+
+ Status |= VL53L0_WrByte(Dev, 0x32, 0x03);
+
+ Status |= VL53L0_WrByte(Dev, 0x41, 0xff);
+ Status |= VL53L0_WrByte(Dev, 0x42, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x43, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0x01, 0x01);
+
+ if (Status != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L010_EXTERNAL VL53L0_Error VL53L010_load_additional_settings3(VL53L0_DEV
+ Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* update 150624_b */
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x4f, 0x0B);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x0E);
+
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0x01, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0x02, 0x0A);
+ Status |= VL53L0_WrByte(Dev, 0x03, 0x0D);
+ Status |= VL53L0_WrByte(Dev, 0x04, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x05, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x06, 0x06);
+ Status |= VL53L0_WrByte(Dev, 0x07, 0x47);
+ Status |= VL53L0_WrByte(Dev, 0x08, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x09, 0x20);
+ Status |= VL53L0_WrByte(Dev, 0x0A, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x0B, 0x49);
+ Status |= VL53L0_WrByte(Dev, 0x0C, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x0D, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x0E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x0F, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x10, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x11, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0x12, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x13, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x14, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x15, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x16, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x17, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x18, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x19, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x1A, 0x11);
+ Status |= VL53L0_WrByte(Dev, 0x1B, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x1C, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x1D, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x1E, 0x11);
+ Status |= VL53L0_WrByte(Dev, 0x1F, 0x08);
+ Status |= VL53L0_WrByte(Dev, 0x20, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x21, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x22, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0x23, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x24, 0x0A);
+ Status |= VL53L0_WrByte(Dev, 0x25, 0x0D);
+ Status |= VL53L0_WrByte(Dev, 0x26, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x27, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x28, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x29, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x2A, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x2B, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x2C, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x2D, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x2E, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x2F, 0x92);
+ Status |= VL53L0_WrByte(Dev, 0x30, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x31, 0x64);
+ Status |= VL53L0_WrByte(Dev, 0x32, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x33, 0x8A);
+ Status |= VL53L0_WrByte(Dev, 0x34, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x35, 0xE0);
+ Status |= VL53L0_WrByte(Dev, 0x36, 0x0F);
+ Status |= VL53L0_WrByte(Dev, 0x37, 0xAA);
+ Status |= VL53L0_WrByte(Dev, 0x38, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x39, 0xE4);
+ Status |= VL53L0_WrByte(Dev, 0x3A, 0x0F);
+ Status |= VL53L0_WrByte(Dev, 0x3B, 0xAE);
+ Status |= VL53L0_WrByte(Dev, 0x3C, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x3D, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x3E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x3F, 0x54);
+ Status |= VL53L0_WrByte(Dev, 0x40, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x41, 0x88);
+ Status |= VL53L0_WrByte(Dev, 0x42, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x43, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x44, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0x45, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x46, 0x06);
+ Status |= VL53L0_WrByte(Dev, 0x47, 0x87);
+ Status |= VL53L0_WrByte(Dev, 0x48, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x49, 0x38);
+ Status |= VL53L0_WrByte(Dev, 0x4A, 0x2B);
+ Status |= VL53L0_WrByte(Dev, 0x4B, 0x89);
+ Status |= VL53L0_WrByte(Dev, 0x4C, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x4D, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x4E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x4F, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x50, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x51, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0x52, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x53, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x54, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x55, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x56, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x57, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x58, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x59, 0x0D);
+ Status |= VL53L0_WrByte(Dev, 0x5A, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x5B, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x5C, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x5D, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x5E, 0x0D);
+ Status |= VL53L0_WrByte(Dev, 0x5F, 0x67);
+ Status |= VL53L0_WrByte(Dev, 0x60, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x61, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x62, 0x0D);
+ Status |= VL53L0_WrByte(Dev, 0x63, 0xB0);
+ Status |= VL53L0_WrByte(Dev, 0x64, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x65, 0x20);
+ Status |= VL53L0_WrByte(Dev, 0x66, 0x29);
+ Status |= VL53L0_WrByte(Dev, 0x67, 0xC1);
+ Status |= VL53L0_WrByte(Dev, 0x68, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x69, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x6A, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x6B, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x6C, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x6D, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x6E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x6F, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x70, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x71, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0x72, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x73, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x74, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x75, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x76, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x77, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x78, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x79, 0x0D);
+ Status |= VL53L0_WrByte(Dev, 0x7A, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x7B, 0x1B);
+ Status |= VL53L0_WrByte(Dev, 0x7C, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x7D, 0x82);
+ Status |= VL53L0_WrByte(Dev, 0x7E, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x7F, 0x24);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x81, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x82, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x83, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x84, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x85, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x86, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x87, 0x21);
+ Status |= VL53L0_WrByte(Dev, 0x88, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x89, 0x58);
+ Status |= VL53L0_WrByte(Dev, 0x8A, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x8B, 0xCC);
+ Status |= VL53L0_WrByte(Dev, 0x8C, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x8D, 0xC3);
+ Status |= VL53L0_WrByte(Dev, 0x8E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x8F, 0x94);
+ Status |= VL53L0_WrByte(Dev, 0x90, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x91, 0x53);
+ Status |= VL53L0_WrByte(Dev, 0x92, 0x1E);
+ Status |= VL53L0_WrByte(Dev, 0x93, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x95, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x96, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x97, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x98, 0x20);
+ Status |= VL53L0_WrByte(Dev, 0x99, 0x20);
+ Status |= VL53L0_WrByte(Dev, 0x9A, 0x08);
+ Status |= VL53L0_WrByte(Dev, 0x9B, 0x10);
+ Status |= VL53L0_WrByte(Dev, 0x9C, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x9D, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x9E, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x9F, 0x50);
+ Status |= VL53L0_WrByte(Dev, 0xA0, 0x2B);
+ Status |= VL53L0_WrByte(Dev, 0xA1, 0xB1);
+ Status |= VL53L0_WrByte(Dev, 0xA2, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xA3, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0xA4, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0xA5, 0x50);
+ Status |= VL53L0_WrByte(Dev, 0xA6, 0x2C);
+ Status |= VL53L0_WrByte(Dev, 0xA7, 0x11);
+ Status |= VL53L0_WrByte(Dev, 0xA8, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xA9, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xAA, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xAB, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xAC, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xAD, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0xAE, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xAF, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0xB0, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xB1, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xB2, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0xB3, 0x4E);
+ Status |= VL53L0_WrByte(Dev, 0xB4, 0x2D);
+ Status |= VL53L0_WrByte(Dev, 0xB5, 0x47);
+ Status |= VL53L0_WrByte(Dev, 0xB6, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xB7, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xB8, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xB9, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xBA, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xBB, 0xA7);
+ Status |= VL53L0_WrByte(Dev, 0xBC, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xBD, 0xA6);
+ Status |= VL53L0_WrByte(Dev, 0xBE, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xBF, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0xC0, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xC1, 0x30);
+ Status |= VL53L0_WrByte(Dev, 0xC2, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xC3, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xC4, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0xC5, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0xC6, 0x2D);
+ Status |= VL53L0_WrByte(Dev, 0xC7, 0x89);
+ Status |= VL53L0_WrByte(Dev, 0xC8, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xC9, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xCA, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xCB, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xCC, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xCD, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0xCE, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xCF, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0xD0, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xD1, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xD2, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xD3, 0x25);
+ Status |= VL53L0_WrByte(Dev, 0xD4, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xD5, 0x2E);
+ Status |= VL53L0_WrByte(Dev, 0xD6, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xD7, 0x25);
+ Status |= VL53L0_WrByte(Dev, 0xD8, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xD9, 0x2E);
+ Status |= VL53L0_WrByte(Dev, 0xDA, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0xDB, 0xF3);
+ Status |= VL53L0_WrByte(Dev, 0xDC, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0xDD, 0xEA);
+ Status |= VL53L0_WrByte(Dev, 0xDE, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0xDF, 0x58);
+ Status |= VL53L0_WrByte(Dev, 0xE0, 0x2C);
+ Status |= VL53L0_WrByte(Dev, 0xE1, 0xD9);
+ Status |= VL53L0_WrByte(Dev, 0xE2, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xE3, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xE4, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xE5, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xE6, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xE7, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0xE8, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xE9, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0xEA, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xEB, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xEC, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xED, 0x26);
+ Status |= VL53L0_WrByte(Dev, 0xEE, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xEF, 0xDC);
+ Status |= VL53L0_WrByte(Dev, 0xF0, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0xF1, 0x58);
+ Status |= VL53L0_WrByte(Dev, 0xF2, 0x2F);
+ Status |= VL53L0_WrByte(Dev, 0xF3, 0x21);
+ Status |= VL53L0_WrByte(Dev, 0xF4, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xF5, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xF6, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xF7, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xF8, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xF9, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0xFA, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFB, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0xFC, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFD, 0x04);
+ Status |= VL53L0_WrWord(Dev, 0xFE, 0x01E3);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x0F);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x01, 0x48);
+ Status |= VL53L0_WrByte(Dev, 0x02, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x03, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x04, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x05, 0xA4);
+ Status |= VL53L0_WrByte(Dev, 0x06, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x07, 0xB8);
+ Status |= VL53L0_WrByte(Dev, 0x08, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x09, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x0A, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x0B, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x0C, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x0D, 0x6B);
+ Status |= VL53L0_WrByte(Dev, 0x0E, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x0F, 0x64);
+ Status |= VL53L0_WrByte(Dev, 0x10, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x11, 0x3C);
+ Status |= VL53L0_WrByte(Dev, 0x12, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x13, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x14, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x15, 0x74);
+ Status |= VL53L0_WrByte(Dev, 0x16, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x17, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x18, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x19, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x1A, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x1B, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x1C, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x1D, 0xA2);
+ Status |= VL53L0_WrByte(Dev, 0x1E, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x1F, 0x8E);
+ Status |= VL53L0_WrByte(Dev, 0x20, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x21, 0x50);
+ Status |= VL53L0_WrByte(Dev, 0x22, 0x2E);
+ Status |= VL53L0_WrByte(Dev, 0x23, 0xC9);
+ Status |= VL53L0_WrByte(Dev, 0x24, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x25, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x26, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x27, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x28, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x29, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0x2A, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x2B, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x2C, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x2D, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x2E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x2F, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x30, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x31, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x32, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x33, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x34, 0x11);
+ Status |= VL53L0_WrByte(Dev, 0x35, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x36, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x37, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x38, 0x11);
+ Status |= VL53L0_WrByte(Dev, 0x39, 0x08);
+ Status |= VL53L0_WrByte(Dev, 0x3A, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x3B, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x3C, 0x11);
+ Status |= VL53L0_WrByte(Dev, 0x3D, 0x18);
+ Status |= VL53L0_WrByte(Dev, 0x3E, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x3F, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x40, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x41, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x42, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0x43, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x44, 0x0A);
+ Status |= VL53L0_WrByte(Dev, 0x45, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x46, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0x47, 0x08);
+ Status |= VL53L0_WrByte(Dev, 0x48, 0x0A);
+ Status |= VL53L0_WrByte(Dev, 0x49, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x4A, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x4B, 0x40);
+ Status |= VL53L0_WrByte(Dev, 0x4C, 0x2F);
+ Status |= VL53L0_WrByte(Dev, 0x4D, 0xD1);
+ Status |= VL53L0_WrByte(Dev, 0x4E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x4F, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x50, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x51, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x52, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x53, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0x54, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x55, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x56, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x57, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x58, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x59, 0x11);
+ Status |= VL53L0_WrByte(Dev, 0x5A, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x5B, 0x48);
+ Status |= VL53L0_WrByte(Dev, 0x5C, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x5D, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x5E, 0x0A);
+ Status |= VL53L0_WrByte(Dev, 0x5F, 0xA2);
+ Status |= VL53L0_WrByte(Dev, 0x60, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x61, 0x60);
+ Status |= VL53L0_WrByte(Dev, 0x62, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x63, 0x3E);
+ Status |= VL53L0_WrByte(Dev, 0x64, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x65, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x66, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x67, 0x54);
+ Status |= VL53L0_WrByte(Dev, 0x68, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x69, 0x80);
+ Status |= VL53L0_WrByte(Dev, 0x6A, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x6B, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x6C, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x6D, 0x38);
+ Status |= VL53L0_WrByte(Dev, 0x6E, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x6F, 0xE1);
+ Status |= VL53L0_WrByte(Dev, 0x70, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x71, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x72, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x73, 0x38);
+ Status |= VL53L0_WrByte(Dev, 0x74, 0x29);
+ Status |= VL53L0_WrByte(Dev, 0x75, 0x21);
+ Status |= VL53L0_WrByte(Dev, 0x76, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x77, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x78, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x79, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x7A, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x7B, 0xA1);
+ Status |= VL53L0_WrByte(Dev, 0x7C, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x7D, 0xA0);
+ Status |= VL53L0_WrByte(Dev, 0x7E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x7F, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x81, 0x33);
+ Status |= VL53L0_WrByte(Dev, 0x82, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x83, 0x6A);
+ Status |= VL53L0_WrByte(Dev, 0x84, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x85, 0x61);
+ Status |= VL53L0_WrByte(Dev, 0x86, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x87, 0xF9);
+ Status |= VL53L0_WrByte(Dev, 0x88, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x89, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x8A, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x8B, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x8C, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x8D, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0x8E, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x8F, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x90, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x91, 0x66);
+ Status |= VL53L0_WrByte(Dev, 0x92, 0x2A);
+ Status |= VL53L0_WrByte(Dev, 0x93, 0x67);
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x95, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x96, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x97, 0x66);
+ Status |= VL53L0_WrByte(Dev, 0x98, 0x2A);
+ Status |= VL53L0_WrByte(Dev, 0x99, 0xAF);
+ Status |= VL53L0_WrByte(Dev, 0x9A, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x9B, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x9C, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x9D, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x9E, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x9F, 0xA7);
+ Status |= VL53L0_WrByte(Dev, 0xA0, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xA1, 0xA6);
+ Status |= VL53L0_WrByte(Dev, 0xA2, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xA3, 0x04);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x04);
+
+ Status |= VL53L0_WrByte(Dev, 0x79, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0x7B, 0x16);
+ Status |= VL53L0_WrByte(Dev, 0x7D, 0x2B);
+ Status |= VL53L0_WrByte(Dev, 0x7F, 0x3B);
+ Status |= VL53L0_WrByte(Dev, 0x81, 0x59);
+ Status |= VL53L0_WrByte(Dev, 0x83, 0x62);
+ Status |= VL53L0_WrByte(Dev, 0x85, 0x69);
+ Status |= VL53L0_WrByte(Dev, 0x87, 0x76);
+ Status |= VL53L0_WrByte(Dev, 0x89, 0x7F);
+ Status |= VL53L0_WrByte(Dev, 0x8B, 0x98);
+ Status |= VL53L0_WrByte(Dev, 0x8D, 0xAC);
+ Status |= VL53L0_WrByte(Dev, 0x8F, 0xC0);
+ Status |= VL53L0_WrByte(Dev, 0x90, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0x91, 0x30);
+ Status |= VL53L0_WrByte(Dev, 0x92, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0x93, 0x02);
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x37);
+ Status |= VL53L0_WrByte(Dev, 0x95, 0x62);
+
+ Status |= VL53L0_WrByte(Dev, 0x96, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x97, 0x08);
+ Status |= VL53L0_WrByte(Dev, 0x98, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x99, 0x18);
+ Status |= VL53L0_WrByte(Dev, 0x9A, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x9B, 0x6F);
+ Status |= VL53L0_WrByte(Dev, 0x9C, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x9D, 0xD4);
+ Status |= VL53L0_WrByte(Dev, 0x9E, 0x0A);
+ Status |= VL53L0_WrByte(Dev, 0x9F, 0x6E);
+ Status |= VL53L0_WrByte(Dev, 0xA0, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0xA1, 0xA2);
+ Status |= VL53L0_WrByte(Dev, 0xA2, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0xA3, 0xAA);
+ Status |= VL53L0_WrByte(Dev, 0xA4, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xA5, 0x97);
+ Status |= VL53L0_WrByte(Dev, 0xA6, 0x0B);
+ Status |= VL53L0_WrByte(Dev, 0xA7, 0xD8);
+ Status |= VL53L0_WrByte(Dev, 0xA8, 0x0A);
+ Status |= VL53L0_WrByte(Dev, 0xA9, 0xD7);
+ Status |= VL53L0_WrByte(Dev, 0xAA, 0x08);
+ Status |= VL53L0_WrByte(Dev, 0xAB, 0xF6);
+ Status |= VL53L0_WrByte(Dev, 0xAC, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0xAD, 0x1A);
+ Status |= VL53L0_WrByte(Dev, 0xAE, 0x0C);
+ Status |= VL53L0_WrByte(Dev, 0xAF, 0x49);
+ Status |= VL53L0_WrByte(Dev, 0xB0, 0x09);
+ Status |= VL53L0_WrByte(Dev, 0xB1, 0x17);
+ Status |= VL53L0_WrByte(Dev, 0xB2, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0xB3, 0xCD);
+ Status |= VL53L0_WrByte(Dev, 0xB4, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xB5, 0x55);
+
+ Status |= VL53L0_WrByte(Dev, 0x72, 0xFF);
+ Status |= VL53L0_WrByte(Dev, 0x73, 0xFF);
+
+ Status |= VL53L0_WrByte(Dev, 0x74, 0xE0);
+
+ Status |= VL53L0_WrByte(Dev, 0x70, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+
+ if (Status != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L010_EXTERNAL VL53L0_Error VL53L010_check_part_used(VL53L0_DEV Dev,
+ uint8_t *Revision,
+ VL53L0_DeviceInfo_t *
+ pVL53L0_DeviceInfo)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t ModuleIdInt;
+ char *ProductId_tmp;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L010_get_info_from_device(Dev);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ ModuleIdInt =
+ VL53L010_GETDEVICESPECIFICPARAMETER(Dev, ModuleId);
+
+ if (ModuleIdInt == 0) {
+ *Revision = 0;
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->ProductId, "");
+ } else {
+ *Revision =
+ VL53L010_GETDEVICESPECIFICPARAMETER(Dev, Revision);
+ ProductId_tmp =
+ VL53L010_GETDEVICESPECIFICPARAMETER(Dev, ProductId);
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->ProductId,
+ ProductId_tmp);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L010_EXTERNAL VL53L0_Error VL53L010_get_info_from_device(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t byte;
+ uint32_t TmpDWord;
+ VL53L0_DeviceSpecificParameters_t DeviceSpecificParameters;
+ uint8_t ModuleId;
+ uint8_t Revision;
+ uint8_t ReferenceSpadCount;
+ uint8_t ReferenceSpadType;
+ char ProductId[19];
+ char *ProductId_tmp;
+ uint8_t ReadDataFromDeviceDone;
+
+ LOG_FUNCTION_START("");
+
+ ReadDataFromDeviceDone = VL53L010_GETDEVICESPECIFICPARAMETER(Dev,
+ ReadDataFromDeviceDone);
+
+ /* This access is done only once after that a GetDeviceInfo or
+ * datainit is done
+ */
+ if (ReadDataFromDeviceDone == 0) {
+
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x06);
+ Status |= VL53L0_RdByte(Dev, 0x83, &byte);
+ Status |= VL53L0_WrByte(Dev, 0x83, byte | 4);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x81, 0x01);
+
+ Status |= VL53L0_PollingDelay(Dev);
+
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x6b);
+ Status |= VL53L010_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ReferenceSpadCount = (uint8_t) ((TmpDWord >> 8) & 0x07f);
+ ReferenceSpadType = (uint8_t) ((TmpDWord >> 15) & 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x02);
+ Status |= VL53L010_device_read_strobe(Dev);
+ Status |= VL53L0_RdByte(Dev, 0x90, &ModuleId);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x7B);
+ Status |= VL53L010_device_read_strobe(Dev);
+ Status |= VL53L0_RdByte(Dev, 0x90, &Revision);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x77);
+ Status |= VL53L010_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[0] = (char)((TmpDWord >> 25) & 0x07f);
+ ProductId[1] = (char)((TmpDWord >> 18) & 0x07f);
+ ProductId[2] = (char)((TmpDWord >> 11) & 0x07f);
+ ProductId[3] = (char)((TmpDWord >> 4) & 0x07f);
+
+ byte = (uint8_t) ((TmpDWord & 0x00f) << 3);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x78);
+ Status |= VL53L010_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[4] = (char)(byte + ((TmpDWord >> 29) & 0x07f));
+ ProductId[5] = (char)((TmpDWord >> 22) & 0x07f);
+ ProductId[6] = (char)((TmpDWord >> 15) & 0x07f);
+ ProductId[7] = (char)((TmpDWord >> 8) & 0x07f);
+ ProductId[8] = (char)((TmpDWord >> 1) & 0x07f);
+
+ byte = (uint8_t) ((TmpDWord & 0x001) << 6);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x79);
+
+ Status |= VL53L010_device_read_strobe(Dev);
+
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[9] = (char)(byte + ((TmpDWord >> 26) & 0x07f));
+ ProductId[10] = (char)((TmpDWord >> 19) & 0x07f);
+ ProductId[11] = (char)((TmpDWord >> 12) & 0x07f);
+ ProductId[12] = (char)((TmpDWord >> 5) & 0x07f);
+
+ byte = (uint8_t) ((TmpDWord & 0x01f) << 2);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x80);
+
+ Status |= VL53L010_device_read_strobe(Dev);
+
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[13] = (char)(byte + ((TmpDWord >> 30) & 0x07f));
+ ProductId[14] = (char)((TmpDWord >> 23) & 0x07f);
+ ProductId[15] = (char)((TmpDWord >> 16) & 0x07f);
+ ProductId[16] = (char)((TmpDWord >> 9) & 0x07f);
+ ProductId[17] = (char)((TmpDWord >> 2) & 0x07f);
+ ProductId[18] = '\0';
+
+ Status |= VL53L0_WrByte(Dev, 0x81, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x06);
+ Status |= VL53L0_RdByte(Dev, 0x83, &byte);
+ Status |= VL53L0_WrByte(Dev, 0x83, byte & 0xfb);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev,
+ ModuleId, ModuleId);
+
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev,
+ Revision, Revision);
+
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount,
+ ReferenceSpadCount);
+
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType,
+ ReferenceSpadType);
+
+ ProductId_tmp = VL53L010_GETDEVICESPECIFICPARAMETER(Dev,
+ ProductId);
+ VL53L0_COPYSTRING(ProductId_tmp, ProductId);
+
+ VL53L010_SETDEVICESPECIFICPARAMETER(Dev,
+ ReadDataFromDeviceDone,
+ 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+uint32_t VL53L010_isqrt(uint32_t num)
+{
+
+ /*
+ * Implements an integer square root
+ *
+ * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
+ */
+
+ uint32_t res = 0;
+ uint32_t bit = 1 << 30;
+ /* The second-to-top bit is set: 1 << 14 for
+ * 16-bits, 1 << 30 for 32 bits
+ */
+ /* "bit" starts at the highest power of four <= the argument. */
+ while (bit > num)
+ bit >>= 2;
+
+ while (bit != 0) {
+ if (num >= res + bit) {
+ num -= res + bit;
+ res = (res >> 1) + bit;
+ } else
+ res >>= 1;
+
+ bit >>= 2;
+ }
+
+ return res;
+}
+
+VL53L0_Error VL53L010_device_read_strobe(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t strobe;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ Status |= VL53L0_WrByte(Dev, 0x83, 0x00);
+
+ /* polling use timeout to avoid deadlock */
+ if (Status == VL53L0_ERROR_NONE) {
+ LoopNb = 0;
+ do {
+ Status = VL53L0_RdByte(Dev, 0x83, &strobe);
+ if ((strobe != 0x00) || Status != VL53L0_ERROR_NONE)
+ break;
+
+ LoopNb = LoopNb + 1;
+ } while (LoopNb < VL53L0_DEFAULT_MAX_LOOP);
+
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP)
+ Status = VL53L0_ERROR_TIME_OUT;
+
+ }
+
+ Status |= VL53L0_WrByte(Dev, 0x83, 0x01);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+uint32_t VL53L010_quadrature_sum(uint32_t a, uint32_t b)
+{
+ /*
+ * Implements a quadrature sum
+ *
+ * rea = sqrt(a^2 + b^2)
+ *
+ * Trap overflow case max input value is 65535 (16-bit value)
+ * as internal calc are 32-bit wide
+ *
+ * If overflow then seta output to maximum
+ */
+ uint32_t res = 0;
+
+ if (a > 65535 || b > 65535)
+ res = 65535;
+ else
+ res = VL53L010_isqrt(a * a + b * b);
+
+ return res;
+}
+
+VL53L0_Error VL53L010_get_jmp_vcsel_ambient_rate(VL53L0_DEV Dev,
+ uint32_t *pAmbient_rate_kcps,
+ uint32_t *pVcsel_rate_kcps,
+ uint32_t *
+ pSignalTotalEventsRtn)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t encodedTimeOut;
+
+ uint32_t total_periods_elapsed_rtn__macrop = 0;
+ uint32_t result_core__total_periods_elapsed_rtn = 0;
+ uint32_t rngb1_config__timeout__macrop = 0;
+ uint32_t rngb2_config__timeout__macrop = 0;
+ uint32_t result_core__ambient_window_events_rtn = 0;
+ uint32_t result_core__signal_total_events_rtn = 0;
+ uint8_t last_woi_period;
+ uint8_t rnga_config__vcsel_period;
+ uint8_t rngb1_config__vcsel_period;
+ uint8_t rngb2_config__vcsel_period;
+ uint8_t global_config__vcsel_width;
+
+ uint32_t ambient_duration_us = 0;
+ uint32_t vcsel_duration_us = 0;
+
+ uint32_t pll_period_us = 0;
+
+ LOG_FUNCTION_START("");
+
+ /* read the following */
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_RdDWord(Dev, 0xC8,
+ &result_core__total_periods_elapsed_rtn);
+ Status |= VL53L0_RdDWord(Dev, 0xF0, &pll_period_us);
+ Status |= VL53L0_RdDWord(Dev, 0xbc,
+ &result_core__ambient_window_events_rtn);
+ Status |= VL53L0_RdDWord(Dev, 0xc4,
+ &result_core__signal_total_events_rtn);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ result_core__total_periods_elapsed_rtn =
+ (int32_t) (result_core__total_periods_elapsed_rtn &
+ 0x00ffffff);
+ pll_period_us = (int32_t) (pll_period_us & 0x3ffff);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev, VL53L010_REG_RNGB1_TIMEOUT_MSB,
+ &encodedTimeOut);
+ if (Status == VL53L0_ERROR_NONE)
+ rngb1_config__timeout__macrop =
+ VL53L010_decode_timeout(encodedTimeOut) - 1;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status =
+ VL53L0_RdByte(Dev, VL53L010_REG_RNGA_CONFIG_VCSEL_PERIOD,
+ &rnga_config__vcsel_period);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_RNGB1_CONFIG_VCSEL_PERIOD,
+ &rngb1_config__vcsel_period);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev,
+ VL53L010_REG_RNGB2_CONFIG_VCSEL_PERIOD,
+ &rngb2_config__vcsel_period);
+ }
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_RdByte(Dev, 0x32, &global_config__vcsel_width);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev, VL53L010_REG_RNGB2_TIMEOUT_MSB,
+ &encodedTimeOut);
+ if (Status == VL53L0_ERROR_NONE)
+ rngb2_config__timeout__macrop =
+ VL53L010_decode_timeout(encodedTimeOut) - 1;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ total_periods_elapsed_rtn__macrop =
+ result_core__total_periods_elapsed_rtn + 1;
+
+ if (result_core__total_periods_elapsed_rtn ==
+ rngb1_config__timeout__macrop) {
+ last_woi_period = rngb1_config__vcsel_period;
+ } else if (result_core__total_periods_elapsed_rtn ==
+ rngb2_config__timeout__macrop) {
+ last_woi_period = rngb2_config__vcsel_period;
+ } else {
+ last_woi_period = rnga_config__vcsel_period;
+
+ }
+ /* 512 = 1<<9 ==> 24-9=15 */
+ ambient_duration_us = last_woi_period *
+ total_periods_elapsed_rtn__macrop * pll_period_us;
+ ambient_duration_us = ambient_duration_us / 1000;
+
+ if (ambient_duration_us != 0) {
+ *pAmbient_rate_kcps = ((1 << 15) *
+ result_core__ambient_window_events_rtn)
+ / ambient_duration_us;
+ } else {
+ Status = VL53L0_ERROR_DIVISION_BY_ZERO;
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ /* 2048 = 1<<11 ==> 24-11=13 */
+ vcsel_duration_us =
+ (10 * global_config__vcsel_width + 4)
+ * total_periods_elapsed_rtn__macrop * pll_period_us;
+ vcsel_duration_us = vcsel_duration_us / 10000;
+
+ if (vcsel_duration_us != 0) {
+ *pVcsel_rate_kcps = ((1 << 13) *
+ result_core__signal_total_events_rtn)
+ / vcsel_duration_us;
+ *pSignalTotalEventsRtn =
+ result_core__signal_total_events_rtn;
+ } else {
+ Status = VL53L0_ERROR_DIVISION_BY_ZERO;
+ }
+
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+VL53L0_Error VL53L010_calc_sigma_estimate(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t
+ *pRangingMeasurementData,
+ FixPoint1616_t *pSigmaEstimate)
+{
+ /* Expressed in 100ths of a ns, i.e. centi-ns */
+ const uint32_t cPulseEffectiveWidth_centi_ns = 800;
+ /* Expressed in 100ths of a ns, i.e. centi-ns */
+ const uint32_t cAmbientEffectiveWidth_centi_ns = 600;
+ const FixPoint1616_t cSigmaEstRef = 0x00000042;
+ /* pico secs */
+ const uint32_t cVcselPulseWidth_ps = 4700;
+ const FixPoint1616_t cSigmaEstMax = 0x028F87AE;
+ /* Time Of Flight per mm (6.6 pico secs) */
+ const FixPoint1616_t cTOF_per_mm_ps = 0x0006999A;
+ const uint32_t c16BitRoundingParam = 0x00008000;
+ const FixPoint1616_t cMaxXTalk_kcps = 0x00320000;
+
+ uint32_t signalTotalEventsRtn;
+ FixPoint1616_t sigmaEstimateP1;
+ FixPoint1616_t sigmaEstimateP2;
+ FixPoint1616_t sigmaEstimateP3;
+ FixPoint1616_t deltaT_ps;
+ FixPoint1616_t pwMult;
+ FixPoint1616_t sigmaEstRtn;
+ FixPoint1616_t sigmaEstimate;
+ FixPoint1616_t xTalkCorrection;
+ uint32_t signalTotalEventsRtnRawVal;
+ FixPoint1616_t ambientRate_kcps;
+ FixPoint1616_t vcselRate_kcps;
+ FixPoint1616_t xTalkCompRate_mcps;
+ uint32_t xTalkCompRate_kcps;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ FixPoint1616_t diff1_mcps;
+ FixPoint1616_t diff2_mcps;
+ FixPoint1616_t sqr1;
+ FixPoint1616_t sqr2;
+ FixPoint1616_t sqrSum;
+ FixPoint1616_t sqrtResult_centi_ns;
+ FixPoint1616_t sqrtResult;
+
+ /*! \addtogroup calc_sigma_estimate
+ * @{
+ *
+ * Estimates the range sigma based on the
+ *
+ * - vcsel_rate_kcps
+ * - ambient_rate_kcps
+ * - signal_total_events
+ * - xtalk_rate
+ *
+ * and the following parameters
+ *
+ * - SigmaEstRefArray
+ * - SigmaEstEffPulseWidth
+ * - SigmaEstEffAmbWidth
+ */
+
+ LOG_FUNCTION_START("");
+
+ VL53L010_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ xTalkCompRate_mcps);
+ /*
+ * We work in kcps rather than mcps as this helps keep
+ * within the confines of the 32 Fix1616 type.
+ */
+
+ xTalkCompRate_kcps = xTalkCompRate_mcps * 1000;
+ if (xTalkCompRate_kcps > cMaxXTalk_kcps)
+ xTalkCompRate_kcps = cMaxXTalk_kcps;
+
+ Status = VL53L010_get_jmp_vcsel_ambient_rate(Dev,
+ &ambientRate_kcps,
+ &vcselRate_kcps,
+ &signalTotalEventsRtnRawVal);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (vcselRate_kcps == 0) {
+ Status = VL53L0_ERROR_DIVISION_BY_ZERO;
+ } else {
+ signalTotalEventsRtn = signalTotalEventsRtnRawVal;
+ if (signalTotalEventsRtn < 1)
+ signalTotalEventsRtn = 1;
+
+ /*
+ * Calculate individual components of the main
+ * equation - replicating the equation implemented in
+ * the script OpenAll_Ewok_ranging_data.jsl.
+ *
+ * sigmaEstimateP1 represents the effective pulse width,
+ * which is a tuning parameter, rather than a real
+ * value.
+ *
+ * sigmaEstimateP2 represents the ambient/signal rate
+ * ratio expressed as a multiple of the effective
+ * ambient width (tuning parameter).
+ *
+ * sigmaEstimateP3 provides the signal event component,
+ * with the knowledge that
+ * - Noise of a square pulse is 1/sqrt(12) of the
+ * pulse width.
+ * - at 0Lux, sigma is proportional to
+ * effectiveVcselPulseWidth /
+ * sqrt(12 * signalTotalEvents)
+ *
+ * deltaT_ps represents the time of flight in pico secs
+ * for the current range measurement, using the
+ * "TOF per mm" constant (in ps).
+ */
+
+ sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns;
+
+ /*
+ * ((FixPoint1616 << 16)* uint32)/FixPoint1616 =
+ * FixPoint1616
+ */
+ sigmaEstimateP2 = (ambientRate_kcps << 16) /
+ vcselRate_kcps;
+ sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns;
+
+ sigmaEstimateP3 = 2 *
+ VL53L010_isqrt(signalTotalEventsRtn * 12);
+
+ /* uint32 * FixPoint1616 = FixPoint1616 */
+ deltaT_ps =
+ pRangingMeasurementData->RangeMilliMeter *
+ cTOF_per_mm_ps;
+
+ /*
+ * vcselRate - xtalkCompRate
+ * (uint32 << 16) - FixPoint1616 = FixPoint1616.
+ * Divide result by 1000 to convert to mcps.
+ * 500 is added to ensure rounding when integer
+ * division truncates.
+ */
+ diff1_mcps = (((vcselRate_kcps << 16) -
+ xTalkCompRate_kcps) + 500) / 1000;
+
+ /* vcselRate + xtalkCompRate */
+ diff2_mcps = (((vcselRate_kcps << 16) +
+ xTalkCompRate_kcps) + 500) / 1000;
+
+ /* Shift by 12 bits to increase resolution prior to the
+ * division
+ */
+ diff1_mcps <<= 12;
+
+ /* FixPoint0428/FixPoint1616 = FixPoint2012 */
+ xTalkCorrection = abs(diff1_mcps / diff2_mcps);
+
+ /* FixPoint2012 << 4 = FixPoint1616 */
+ xTalkCorrection <<= 4;
+
+ /* FixPoint1616/uint32 = FixPoint1616 */
+ pwMult = deltaT_ps / cVcselPulseWidth_ps;
+ /* smaller than 1.0f */
+
+ /*
+ * FixPoint1616 * FixPoint1616 = FixPoint3232, however
+ * both values are small enough such that32 bits will
+ * not be exceeded.
+ */
+ pwMult *= ((1 << 16) - xTalkCorrection);
+
+ /* (FixPoint3232 >> 16) = FixPoint1616 */
+ pwMult = (pwMult + c16BitRoundingParam) >> 16;
+
+ /* FixPoint1616 + FixPoint1616 = FixPoint1616 */
+ pwMult += (1 << 16);
+
+ /*
+ * At this point the value will be 1.xx, therefore if we
+ * square the value this will exceed 32 bits. To address
+ * this perform a single shift to the right before the
+ * multiplication.
+ */
+ pwMult >>= 1;
+ /* FixPoint1715 * FixPoint1715 = FixPoint3430 */
+ pwMult = pwMult * pwMult;
+
+ /* (FixPoint3430 >> 14) = Fix1616 */
+ pwMult >>= 14;
+
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sqr1 = pwMult * sigmaEstimateP1;
+
+ /* (FixPoint1616 >> 12) = FixPoint2804 */
+ sqr1 = (sqr1 + 0x800) >> 12;
+
+ /* FixPoint2804 * FixPoint2804 = FixPoint5608 */
+ sqr1 *= sqr1;
+
+ sqr2 = sigmaEstimateP2;
+
+ /* (FixPoint1616 >> 12) = FixPoint2804 */
+ sqr2 = (sqr2 + 0x800) >> 12;
+
+ /* FixPoint2804 * FixPoint2804 = FixPoint5608 */
+ sqr2 *= sqr2;
+
+ /* FixPoint5608 + FixPoint5608 = FixPoint5608 */
+ sqrSum = sqr1 + sqr2;
+
+ /* SQRT(FixPoint5608) = FixPoint2804 */
+ sqrtResult_centi_ns = VL53L010_isqrt(sqrSum);
+
+ /* (FixPoint2804 << 12) = FixPoint1616 */
+ sqrtResult_centi_ns <<= 12;
+
+ /*
+ * Note that the Speed Of Light is expressed in um
+ * per 1E-10 seconds (2997). Therefore to get mm/ns
+ * we have to divide by 10000
+ */
+ sigmaEstRtn =
+ ((sqrtResult_centi_ns + 50) / 100 *
+ VL53L010_SPEED_OF_LIGHT_IN_AIR);
+ sigmaEstRtn /= (sigmaEstimateP3);
+ /* Add 5000 before dividing by 10000 to ensure
+ * rounding.
+ */
+ sigmaEstRtn += 5000;
+ sigmaEstRtn /= 10000;
+
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sqr1 = sigmaEstRtn * sigmaEstRtn;
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sqr2 = cSigmaEstRef * cSigmaEstRef;
+
+ /* sqrt(FixPoint3232 << 12) = FixPoint1022 */
+ sqrtResult = VL53L010_isqrt((sqr1 + sqr2) << 12);
+ sqrtResult = (sqrtResult + 0x20) >> 6;
+ /*
+ * Note that the Shift by 12bits increases resolution
+ * prior to the sqrt, therefore the result must be
+ * shifted by 6bits to the right to revert back to the
+ * FixPoint1616 format.
+ */
+
+ sigmaEstimate = 1000 * sqrtResult;
+
+ if ((vcselRate_kcps < 1) ||
+ (signalTotalEventsRtn < 1) ||
+ (sigmaEstimate > cSigmaEstMax)) {
+ sigmaEstimate = cSigmaEstMax;
+ }
+
+ *pSigmaEstimate = (uint32_t) (sigmaEstimate);
+ PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L010_get_pal_range_status(VL53L0_DEV Dev,
+ uint8_t DeviceRangeStatus,
+ FixPoint1616_t SignalRate,
+ FixPoint1616_t CrosstalkCompensation,
+ uint16_t EffectiveSpadRtnCount,
+ VL53L0_RangingMeasurementData_t *
+ pRangingMeasurementData,
+ uint8_t *pPalRangeStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t tmpByte;
+ uint8_t SigmaLimitCheckEnable;
+ uint8_t SignalLimitCheckEnable;
+ FixPoint1616_t SigmaEstimate;
+ FixPoint1616_t SignalEstimate;
+ FixPoint1616_t SigmaLimitValue;
+ FixPoint1616_t SignalLimitValue;
+ uint8_t DeviceRangeStatusInternal = 0;
+
+ LOG_FUNCTION_START("");
+
+ /*
+ * VL53L0 has a good ranging when the value of the
+ * DeviceRangeStatus = 11. This function will replace
+ * the value 0 with the value 11 in the DeviceRangeStatus.
+ * In addition, the SigmaEstimator is not included in the
+ * VL53L0 DeviceRangeStatus, this will be added in the
+ * PalRangeStatus.
+ */
+
+ DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3);
+
+ if (DeviceRangeStatusInternal == 11)
+ tmpByte = 0;
+ else if (DeviceRangeStatusInternal == 0)
+ tmpByte = 11;
+ else
+ tmpByte = DeviceRangeStatusInternal;
+
+ /*
+ * Check if Sigma limit is enabled, if yes then do comparison with
+ * limit value and put the result back into pPalRangeStatus.
+ */
+ Status = VL53L010_GetLimitCheckEnable(Dev,
+ VL53L010_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &SigmaLimitCheckEnable);
+
+ if ((SigmaLimitCheckEnable != 0) && (Status == VL53L0_ERROR_NONE)) {
+ /*
+ * compute the Sigma and check with limit
+ */
+ Status = VL53L010_calc_sigma_estimate(Dev,
+ pRangingMeasurementData,
+ &SigmaEstimate);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L010_GetLimitCheckValue(Dev,
+ VL53L010_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &SigmaLimitValue);
+
+ if ((SigmaLimitValue > 0) &&
+ (SigmaEstimate > SigmaLimitValue)) {
+ /* Limit Fail add 2^4 to range status */
+ tmpByte += 16;
+ }
+ }
+ }
+
+ /*
+ * Check if Signal limit is enabled, if yes then do comparison with
+ * limit value and put the result back into pPalRangeStatus.
+ */
+ Status = VL53L010_GetLimitCheckEnable(Dev,
+ VL53L010_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ &SignalLimitCheckEnable);
+
+ if ((SignalLimitCheckEnable != 0) && (Status == VL53L0_ERROR_NONE)) {
+ /*
+ * compute the Signal and check with limit
+ */
+
+ SignalEstimate = (FixPoint1616_t) (SignalRate -
+ (FixPoint1616_t)
+ ((EffectiveSpadRtnCount * CrosstalkCompensation) >> 1));
+
+ PALDevDataSet(Dev, SignalEstimate, SignalEstimate);
+
+ Status = VL53L010_GetLimitCheckValue(Dev,
+ VL53L010_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ &SignalLimitValue);
+
+ if ((SignalLimitValue > 0) && (SignalEstimate <
+ SignalLimitValue)) {
+ /* Limit Fail add 2^5 to range status */
+ tmpByte += 32;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ *pPalRangeStatus = tmpByte;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l010_tuning.c b/drivers/input/misc/vl53L0/src/vl53l010_tuning.c
new file mode 100644
index 000000000000..ee3f57872ffc
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l010_tuning.c
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l010_tuning.h"
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#ifdef VL53L0_LOG_ENABLE
+#define trace_print(level, ...) \
+ trace_print_module_function(TRACE_MODULE_API,\
+ level, TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#endif
+
+/*
+ * //////////////////////////////////////////////////////
+ * //// DEFAULT TUNING SETTINGS ////
+ * //////////////////////////////////////////////////////
+ */
+VL53L0_Error VL53L010_load_tuning_settings(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* update 14_12_15_v11 */
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x91, 0x3C);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x54, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x33, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x32, 0x03);
+ Status |= VL53L0_WrByte(Dev, 0x30, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x50, 0x05);
+ Status |= VL53L0_WrByte(Dev, 0x60, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x70, 0x06);
+
+ Status |= VL53L0_WrByte(Dev, 0x46, 0x1a);
+ Status |= VL53L0_WrWord(Dev, 0x51, 0x01a3);
+ Status |= VL53L0_WrWord(Dev, 0x61, 0x01c4);
+ Status |= VL53L0_WrWord(Dev, 0x71, 0x018c);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x31, 0x0f);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x66, 0x38);
+
+ Status |= VL53L0_WrByte(Dev, 0x47, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x48, 0xff);
+ Status |= VL53L0_WrByte(Dev, 0x57, 0x4c);
+ Status |= VL53L0_WrByte(Dev, 0x67, 0x3c);
+ Status |= VL53L0_WrByte(Dev, 0x77, 0x5c);
+
+ Status |= VL53L0_WrWord(Dev, 0x44, 0x0000);
+
+ Status |= VL53L0_WrByte(Dev, 0x27, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x55, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x30, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0x10, 0x0f);
+ Status |= VL53L0_WrByte(Dev, 0x11, 0xff);
+ Status |= VL53L0_WrByte(Dev, 0x40, 0x82);
+ Status |= VL53L0_WrByte(Dev, 0x41, 0xff);
+ Status |= VL53L0_WrByte(Dev, 0x42, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x43, 0x12);
+
+ Status |= VL53L0_WrByte(Dev, 0x20, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x21, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0x28, 0x06);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x48, 0x28);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0x7a, 0x0a);
+ Status |= VL53L0_WrByte(Dev, 0x7b, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x78, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x44, 0xff);
+ Status |= VL53L0_WrByte(Dev, 0x45, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x46, 0x10);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0x04, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x05, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x06, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x07, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x0d, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x01, 0xF8);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x8e, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_api.c b/drivers/input/misc/vl53L0/src/vl53l0_api.c
new file mode 100644
index 000000000000..f9c2c2a4b7b7
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_api.c
@@ -0,0 +1,3109 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l0_api.h"
+#include "vl53l0_tuning.h"
+#include "vl53l0_interrupt_threshold_settings.h"
+#include "vl53l0_api_core.h"
+#include "vl53l0_api_histogram.h"
+#include "vl53l0_api_calibration.h"
+#include "vl53l0_api_strings.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#ifdef VL53L0_LOG_ENABLE
+#define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_API, \
+ level, TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#endif
+
+/* Group PAL General Functions */
+
+VL53L0_Error VL53L0_GetVersion(VL53L0_Version_t *pVersion)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ pVersion->major = VL53L0_IMPLEMENTATION_VER_MAJOR;
+ pVersion->minor = VL53L0_IMPLEMENTATION_VER_MINOR;
+ pVersion->build = VL53L0_IMPLEMENTATION_VER_SUB;
+
+ pVersion->revision = VL53L0_IMPLEMENTATION_VER_REVISION;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetPalSpecVersion(VL53L0_Version_t *pPalSpecVersion)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ pPalSpecVersion->major = VL53L0_SPECIFICATION_VER_MAJOR;
+ pPalSpecVersion->minor = VL53L0_SPECIFICATION_VER_MINOR;
+ pPalSpecVersion->build = VL53L0_SPECIFICATION_VER_SUB;
+
+ pPalSpecVersion->revision = VL53L0_SPECIFICATION_VER_REVISION;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetProductRevision(VL53L0_DEV Dev,
+ uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t revision_id;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_IDENTIFICATION_REVISION_ID,
+ &revision_id);
+ *pProductRevisionMajor = 1;
+ *pProductRevisionMinor = (revision_id & 0xF0) >> 4;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+VL53L0_Error VL53L0_GetDeviceInfo(VL53L0_DEV Dev,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_device_info(Dev, pVL53L0_DeviceInfo);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetDeviceErrorStatus(VL53L0_DEV Dev,
+ VL53L0_DeviceError *pDeviceErrorStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t RangeStatus;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_RESULT_RANGE_STATUS,
+ &RangeStatus);
+
+ *pDeviceErrorStatus = (VL53L0_DeviceError)((RangeStatus & 0x78) >> 3);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_GetDeviceErrorString(VL53L0_DeviceError ErrorCode,
+ char *pDeviceErrorString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_device_error_string(ErrorCode, pDeviceErrorString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetRangeStatusString(uint8_t RangeStatus,
+ char *pRangeStatusString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_range_status_string(RangeStatus,
+ pRangeStatusString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetPalErrorString(VL53L0_Error PalErrorCode,
+ char *pPalErrorString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_pal_error_string(PalErrorCode, pPalErrorString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetPalStateString(VL53L0_State PalStateCode,
+ char *pPalStateString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_pal_state_string(PalStateCode, pPalStateString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetPalState(VL53L0_DEV Dev, VL53L0_State *pPalState)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pPalState = PALDevDataGet(Dev, PalState);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetPowerMode(VL53L0_DEV Dev, VL53L0_PowerModes PowerMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* Only level1 of Power mode exists */
+ if ((PowerMode != VL53L0_POWERMODE_STANDBY_LEVEL1)
+ && (PowerMode != VL53L0_POWERMODE_IDLE_LEVEL1)) {
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ } else if (PowerMode == VL53L0_POWERMODE_STANDBY_LEVEL1) {
+ /* set the standby level1 of power mode */
+ Status = VL53L0_WrByte(Dev, 0x80, 0x00);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to standby */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_STANDBY);
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_STANDBY_LEVEL1);
+ }
+
+ } else {
+ /* VL53L0_POWERMODE_IDLE_LEVEL1 */
+ Status = VL53L0_WrByte(Dev, 0x80, 0x00);
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_StaticInit(Dev);
+
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_IDLE_LEVEL1);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetPowerMode(VL53L0_DEV Dev, VL53L0_PowerModes *pPowerMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* Only level1 of Power mode exists */
+ Status = VL53L0_RdByte(Dev, 0x80, &Byte);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Byte == 1) {
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_IDLE_LEVEL1);
+ } else {
+ PALDevDataSet(Dev, PowerMode,
+ VL53L0_POWERMODE_STANDBY_LEVEL1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetOffsetCalibrationDataMicroMeter(VL53L0_DEV Dev,
+ int32_t OffsetCalibrationDataMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_set_offset_calibration_data_micro_meter(Dev,
+ OffsetCalibrationDataMicroMeter);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetOffsetCalibrationDataMicroMeter(VL53L0_DEV Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_offset_calibration_data_micro_meter(Dev,
+ pOffsetCalibrationDataMicroMeter);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetLinearityCorrectiveGain(VL53L0_DEV Dev,
+ int16_t LinearityCorrectiveGain)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if ((LinearityCorrectiveGain < 0) || (LinearityCorrectiveGain > 1000))
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ else {
+ PALDevDataSet(Dev, LinearityCorrectiveGain,
+ LinearityCorrectiveGain);
+
+ if (LinearityCorrectiveGain != 1000) {
+ /* Disable FW Xtalk */
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, 0);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetLinearityCorrectiveGain(VL53L0_DEV Dev,
+ uint16_t *pLinearityCorrectiveGain)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pLinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetGroupParamHold(VL53L0_DEV Dev, uint8_t GroupParamHold)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetUpperLimitMilliMeter(VL53L0_DEV Dev,
+ uint16_t *pUpperLimitMilliMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetTotalSignalRate(VL53L0_DEV Dev,
+ FixPoint1616_t *pTotalSignalRate)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_RangingMeasurementData_t LastRangeDataBuffer;
+
+ LOG_FUNCTION_START("");
+
+ LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure);
+
+ Status = VL53L0_get_total_signal_rate(
+ Dev, &LastRangeDataBuffer, pTotalSignalRate);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL General Functions */
+
+/* Group PAL Init Functions */
+VL53L0_Error VL53L0_SetDeviceAddress(VL53L0_DEV Dev, uint8_t DeviceAddress)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_I2C_SLAVE_DEVICE_ADDRESS,
+ DeviceAddress / 2);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_DataInit(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters;
+ int i;
+ uint8_t StopVariable;
+
+ LOG_FUNCTION_START("");
+
+ /* by default the I2C is running at 1V8 if you want to change it you
+ * need to include this define at compilation level.
+ */
+#ifdef USE_I2C_2V8
+ Status = VL53L0_UpdateByte(Dev,
+ VL53L0_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
+ 0xFE,
+ 0x01);
+#endif
+
+ /* Set I2C standard mode */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, 0x88, 0x00);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone, 0);
+
+#ifdef USE_IQC_STATION
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_apply_offset_adjustment(Dev);
+#endif
+
+ /* Default value is 1000 for Linearity Corrective Gain */
+ PALDevDataSet(Dev, LinearityCorrectiveGain, 1000);
+
+ /* Dmax default Parameter */
+ PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400);
+ PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+ (FixPoint1616_t)((0x00016B85))); /* 1.42 No Cover Glass*/
+
+ /* Set Default static parameters
+ *set first temporary values 9.44MHz * 65536 = 618660
+ */
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, 618660);
+
+ /* Set Default XTalkCompensationRateMegaCps to 0 */
+ VL53L0_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, 0);
+
+ /* Get default parameters */
+ Status = VL53L0_GetDeviceParameters(Dev, &CurrentParameters);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* initialize PAL values */
+ CurrentParameters.DeviceMode = VL53L0_DEVICEMODE_SINGLE_RANGING;
+ CurrentParameters.HistogramMode = VL53L0_HISTOGRAMMODE_DISABLED;
+ PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+ }
+
+ /* Sigma estimator variable */
+ PALDevDataSet(Dev, SigmaEstRefArray, 100);
+ PALDevDataSet(Dev, SigmaEstEffPulseWidth, 900);
+ PALDevDataSet(Dev, SigmaEstEffAmbWidth, 500);
+ PALDevDataSet(Dev, targetRefRate, 0x0A00); /* 20 MCPS in 9:7 format */
+
+ /* Use internal default settings */
+ PALDevDataSet(Dev, UseInternalTuningSettings, 1);
+
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status |= VL53L0_RdByte(Dev, 0x91, &StopVariable);
+ PALDevDataSet(Dev, StopVariable, StopVariable);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x00);
+
+ /* Enable all check */
+ for (i = 0; i < VL53L0_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ if (Status == VL53L0_ERROR_NONE)
+ Status |= VL53L0_SetLimitCheckEnable(Dev, i, 1);
+ else
+ break;
+
+ }
+
+ /* Disable the following checks */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP, 0);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_MSRC, 0);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_PRE_RANGE, 0);
+
+ /* Limit default values */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_SetLimitCheckValue(Dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ (FixPoint1616_t)(18 * 65536));
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_SetLimitCheckValue(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ (FixPoint1616_t)(25 * 65536 / 100));
+ /* 0.25 * 65536 */
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_SetLimitCheckValue(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP,
+ (FixPoint1616_t)(35 * 65536));
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_SetLimitCheckValue(Dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ (FixPoint1616_t)(0 * 65536));
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ PALDevDataSet(Dev, SequenceConfig, 0xFF);
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ 0xFF);
+
+ /* Set PAL state to tell that we are waiting for call to
+ * VL53L0_StaticInit
+ */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_WAIT_STATICINIT);
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 0);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetTuningSettingBuffer(VL53L0_DEV Dev,
+ uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if (UseInternalTuningSettings == 1) {
+ /* Force use internal settings */
+ PALDevDataSet(Dev, UseInternalTuningSettings, 1);
+ } else {
+
+ /* check that the first byte is not 0 */
+ if (*pTuningSettingBuffer != 0) {
+ PALDevDataSet(Dev, pTuningSettingsPointer,
+ pTuningSettingBuffer);
+ PALDevDataSet(Dev, UseInternalTuningSettings, 0);
+
+ } else {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetTuningSettingBuffer(VL53L0_DEV Dev,
+ uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *ppTuningSettingBuffer = PALDevDataGet(Dev, pTuningSettingsPointer);
+ *pUseInternalTuningSettings = PALDevDataGet(Dev,
+ UseInternalTuningSettings);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_StaticInit(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceParameters_t CurrentParameters = {0};
+ uint8_t *pTuningSettingBuffer;
+ uint16_t tempword = 0;
+ uint8_t tempbyte = 0;
+ uint8_t UseInternalTuningSettings = 0;
+ uint32_t count = 0;
+ uint8_t isApertureSpads = 0;
+ uint32_t refSpadCount = 0;
+ uint8_t ApertureSpads = 0;
+ uint8_t vcselPulsePeriodPCLK;
+ FixPoint1616_t seqTimeoutMilliSecs;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_info_from_device(Dev, 1);
+
+ /* set the ref spad from NVM */
+ count = (uint32_t)VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount);
+ ApertureSpads = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType);
+
+ /* NVM value invalid */
+ if ((ApertureSpads > 1) ||
+ ((ApertureSpads == 1) && (count > 32)) ||
+ ((ApertureSpads == 0) && (count > 12)))
+ Status = VL53L0_perform_ref_spad_management(Dev, &refSpadCount,
+ &isApertureSpads);
+ else
+ Status = VL53L0_set_reference_spads(Dev, count, ApertureSpads);
+
+
+ /* Initialize tuning settings buffer to prevent compiler warning. */
+ pTuningSettingBuffer = DefaultTuningSettings;
+
+ if (Status == VL53L0_ERROR_NONE) {
+ UseInternalTuningSettings = PALDevDataGet(Dev,
+ UseInternalTuningSettings);
+
+ if (UseInternalTuningSettings == 0)
+ pTuningSettingBuffer = PALDevDataGet(Dev,
+ pTuningSettingsPointer);
+ else
+ pTuningSettingBuffer = DefaultTuningSettings;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_load_tuning_settings(Dev, pTuningSettingBuffer);
+
+
+ /* Set interrupt config to new sample ready */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_SetGpioConfig(Dev, 0, 0,
+ VL53L0_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY,
+ VL53L0_INTERRUPTPOLARITY_LOW);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_RdWord(Dev, 0x84, &tempword);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz,
+ VL53L0_FIXPOINT412TOFIXPOINT1616(tempword));
+ }
+
+ /* After static init, some device parameters may be changed,
+ * so update them
+ */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetDeviceParameters(Dev, &CurrentParameters);
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetFractionEnable(Dev, &tempbyte);
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, RangeFractionalEnable, tempbyte);
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+
+
+ /* read the sequence config and save it */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, &tempbyte);
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, tempbyte);
+
+ }
+
+ /* Disable MSRC and TCC by default */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_TCC, 0);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_MSRC, 0);
+
+
+ /* Set PAL State to standby */
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_IDLE);
+
+
+
+ /* Store pre-range vcsel period */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetVcselPulsePeriod(
+ Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &vcselPulsePeriodPCLK);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ PreRangeVcselPulsePeriod,
+ vcselPulsePeriodPCLK);
+ }
+
+ /* Store final-range vcsel period */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetVcselPulsePeriod(
+ Dev,
+ VL53L0_VCSEL_PERIOD_FINAL_RANGE,
+ &vcselPulsePeriodPCLK);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ FinalRangeVcselPulsePeriod,
+ vcselPulsePeriodPCLK);
+ }
+
+ /* Store pre-range timeout */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetSequenceStepTimeout(
+ Dev,
+ VL53L0_SEQUENCESTEP_PRE_RANGE,
+ &seqTimeoutMilliSecs);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ PreRangeTimeoutMicroSecs,
+ seqTimeoutMilliSecs);
+ }
+
+ /* Store final-range timeout */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetSequenceStepTimeout(
+ Dev,
+ VL53L0_SEQUENCESTEP_FINAL_RANGE,
+ &seqTimeoutMilliSecs);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ FinalRangeTimeoutMicroSecs,
+ seqTimeoutMilliSecs);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_WaitDeviceBooted(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_ResetDevice(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* Set reset bit */
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+ 0x00);
+
+ /* Wait for some time */
+ if (Status == VL53L0_ERROR_NONE) {
+ do {
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_IDENTIFICATION_MODEL_ID, &Byte);
+ } while (Byte != 0x00);
+ }
+
+ /* Release reset */
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+ 0x01);
+
+ /* Wait until correct boot-up of the device */
+ if (Status == VL53L0_ERROR_NONE) {
+ do {
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_IDENTIFICATION_MODEL_ID, &Byte);
+ } while (Byte == 0x00);
+ }
+
+ /* Set PAL State to VL53L0_STATE_POWERDOWN */
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_POWERDOWN);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+/* End Group PAL Init Functions */
+
+/* Group PAL Parameters Functions */
+VL53L0_Error VL53L0_SetDeviceParameters(VL53L0_DEV Dev,
+ const VL53L0_DeviceParameters_t *pDeviceParameters)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int i;
+
+ LOG_FUNCTION_START("");
+ Status = VL53L0_SetDeviceMode(Dev, pDeviceParameters->DeviceMode);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetHistogramMode(Dev,
+ pDeviceParameters->HistogramMode);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetInterMeasurementPeriodMilliSeconds(Dev,
+ pDeviceParameters->InterMeasurementPeriodMilliSeconds);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetXTalkCompensationRateMegaCps(Dev,
+ pDeviceParameters->XTalkCompensationRateMegaCps);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetOffsetCalibrationDataMicroMeter(Dev,
+ pDeviceParameters->RangeOffsetMicroMeters);
+
+
+ for (i = 0; i < VL53L0_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ if (Status == VL53L0_ERROR_NONE)
+ Status |= VL53L0_SetLimitCheckEnable(Dev, i,
+ pDeviceParameters->LimitChecksEnable[i]);
+ else
+ break;
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status |= VL53L0_SetLimitCheckValue(Dev, i,
+ pDeviceParameters->LimitChecksValue[i]);
+ else
+ break;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetWrapAroundCheckEnable(Dev,
+ pDeviceParameters->WrapAroundCheckEnable);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ pDeviceParameters->MeasurementTimingBudgetMicroSeconds);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetDeviceParameters(VL53L0_DEV Dev,
+ VL53L0_DeviceParameters_t *pDeviceParameters)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int i;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_GetDeviceMode(Dev, &(pDeviceParameters->DeviceMode));
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetHistogramMode(Dev,
+ &(pDeviceParameters->HistogramMode));
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetInterMeasurementPeriodMilliSeconds(Dev,
+ &(pDeviceParameters->InterMeasurementPeriodMilliSeconds));
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ pDeviceParameters->XTalkCompensationEnable = 0;
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetXTalkCompensationRateMegaCps(Dev,
+ &(pDeviceParameters->XTalkCompensationRateMegaCps));
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetOffsetCalibrationDataMicroMeter(Dev,
+ &(pDeviceParameters->RangeOffsetMicroMeters));
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ for (i = 0; i < VL53L0_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ /* get first the values, then the enables.
+ * VL53L0_GetLimitCheckValue will modify the enable
+ * flags
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status |= VL53L0_GetLimitCheckValue(Dev, i,
+ &(pDeviceParameters->LimitChecksValue[i]));
+ } else {
+ break;
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status |= VL53L0_GetLimitCheckEnable(Dev, i,
+ &(pDeviceParameters->LimitChecksEnable[i]));
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetWrapAroundCheckEnable(Dev,
+ &(pDeviceParameters->WrapAroundCheckEnable));
+ }
+
+ /* Need to be done at the end as it uses VCSELPulsePeriod */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetMeasurementTimingBudgetMicroSeconds(Dev,
+ &(pDeviceParameters->MeasurementTimingBudgetMicroSeconds));
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetDeviceMode(VL53L0_DEV Dev, VL53L0_DeviceModes DeviceMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("%d", (int)DeviceMode);
+
+ switch (DeviceMode) {
+ case VL53L0_DEVICEMODE_SINGLE_RANGING:
+ case VL53L0_DEVICEMODE_CONTINUOUS_RANGING:
+ case VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+ case VL53L0_DEVICEMODE_SINGLE_HISTOGRAM:
+ case VL53L0_DEVICEMODE_GPIO_DRIVE:
+ case VL53L0_DEVICEMODE_GPIO_OSC:
+ /* Supported modes */
+ VL53L0_SETPARAMETERFIELD(Dev, DeviceMode, DeviceMode);
+ break;
+ default:
+ /* Unsupported mode */
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetDeviceMode(VL53L0_DEV Dev,
+ VL53L0_DeviceModes *pDeviceMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_GETPARAMETERFIELD(Dev, DeviceMode, *pDeviceMode);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetRangeFractionEnable(VL53L0_DEV Dev, uint8_t Enable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("%d", (int)Enable);
+
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_RANGE_CONFIG, Enable);
+
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, RangeFractionalEnable, Enable);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetFractionEnable(VL53L0_DEV Dev, uint8_t *pEnabled)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_SYSTEM_RANGE_CONFIG, pEnabled);
+
+ if (Status == VL53L0_ERROR_NONE)
+ *pEnabled = (*pEnabled & 1);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes HistogramMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("%d", (int)HistogramMode);
+
+ Status = VL53L0_set_histogram_mode(Dev, HistogramMode);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetHistogramMode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes *pHistogramMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_histogram_mode(Dev, pHistogramMode);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetMeasurementTimingBudgetMicroSeconds(VL53L0_DEV Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_set_measurement_timing_budget_micro_seconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetMeasurementTimingBudgetMicroSeconds(VL53L0_DEV Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_measurement_timing_budget_micro_seconds(Dev,
+ pMeasurementTimingBudgetMicroSeconds);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetVcselPulsePeriod(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_set_vcsel_pulse_period(Dev, VcselPeriodType,
+ VCSELPulsePeriodPCLK);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetVcselPulsePeriod(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_vcsel_pulse_period(Dev, VcselPeriodType,
+ pVCSELPulsePeriodPCLK);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetSequenceStepEnable(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+ uint8_t SequenceConfigNew = 0;
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ &SequenceConfig);
+
+ SequenceConfigNew = SequenceConfig;
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (SequenceStepEnabled == 1) {
+
+ /* Enable requested sequence step
+ */
+ switch (SequenceStepId) {
+ case VL53L0_SEQUENCESTEP_TCC:
+ SequenceConfigNew |= 0x10;
+ break;
+ case VL53L0_SEQUENCESTEP_DSS:
+ SequenceConfigNew |= 0x28;
+ break;
+ case VL53L0_SEQUENCESTEP_MSRC:
+ SequenceConfigNew |= 0x04;
+ break;
+ case VL53L0_SEQUENCESTEP_PRE_RANGE:
+ SequenceConfigNew |= 0x40;
+ break;
+ case VL53L0_SEQUENCESTEP_FINAL_RANGE:
+ SequenceConfigNew |= 0x80;
+ break;
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ } else {
+ /* Disable requested sequence step
+ */
+ switch (SequenceStepId) {
+ case VL53L0_SEQUENCESTEP_TCC:
+ SequenceConfigNew &= 0xef;
+ break;
+ case VL53L0_SEQUENCESTEP_DSS:
+ SequenceConfigNew &= 0xd7;
+ break;
+ case VL53L0_SEQUENCESTEP_MSRC:
+ SequenceConfigNew &= 0xfb;
+ break;
+ case VL53L0_SEQUENCESTEP_PRE_RANGE:
+ SequenceConfigNew &= 0xbf;
+ break;
+ case VL53L0_SEQUENCESTEP_FINAL_RANGE:
+ SequenceConfigNew &= 0x7f;
+ break;
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+ }
+
+ if (SequenceConfigNew != SequenceConfig) {
+ /* Apply New Setting */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, SequenceConfigNew);
+ }
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfigNew);
+
+
+ /* Recalculate timing budget */
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_GETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+
+ VL53L0_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+VL53L0_Error sequence_step_enabled(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, uint8_t SequenceConfig,
+ uint8_t *pSequenceStepEnabled)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ *pSequenceStepEnabled = 0;
+ LOG_FUNCTION_START("");
+
+ switch (SequenceStepId) {
+ case VL53L0_SEQUENCESTEP_TCC:
+ *pSequenceStepEnabled = (SequenceConfig & 0x10) >> 4;
+ break;
+ case VL53L0_SEQUENCESTEP_DSS:
+ *pSequenceStepEnabled = (SequenceConfig & 0x08) >> 3;
+ break;
+ case VL53L0_SEQUENCESTEP_MSRC:
+ *pSequenceStepEnabled = (SequenceConfig & 0x04) >> 2;
+ break;
+ case VL53L0_SEQUENCESTEP_PRE_RANGE:
+ *pSequenceStepEnabled = (SequenceConfig & 0x40) >> 6;
+ break;
+ case VL53L0_SEQUENCESTEP_FINAL_RANGE:
+ *pSequenceStepEnabled = (SequenceConfig & 0x80) >> 7;
+ break;
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetSequenceStepEnable(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ &SequenceConfig);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev, SequenceStepId,
+ SequenceConfig, pSequenceStepEnabled);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetSequenceStepEnables(VL53L0_DEV Dev,
+ VL53L0_SchedulerSequenceSteps_t *pSchedulerSequenceSteps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ &SequenceConfig);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL53L0_SEQUENCESTEP_TCC, SequenceConfig,
+ &pSchedulerSequenceSteps->TccOn);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL53L0_SEQUENCESTEP_DSS, SequenceConfig,
+ &pSchedulerSequenceSteps->DssOn);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL53L0_SEQUENCESTEP_MSRC, SequenceConfig,
+ &pSchedulerSequenceSteps->MsrcOn);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL53L0_SEQUENCESTEP_PRE_RANGE, SequenceConfig,
+ &pSchedulerSequenceSteps->PreRangeOn);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL53L0_SEQUENCESTEP_FINAL_RANGE, SequenceConfig,
+ &pSchedulerSequenceSteps->FinalRangeOn);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetNumberOfSequenceSteps(VL53L0_DEV Dev,
+ uint8_t *pNumberOfSequenceSteps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfSequenceSteps = VL53L0_SEQUENCESTEP_NUMBER_OF_CHECKS;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetSequenceStepsInfo(VL53L0_SequenceStepId SequenceStepId,
+ char *pSequenceStepsString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_sequence_steps_info(
+ SequenceStepId,
+ pSequenceStepsString);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetSequenceStepTimeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, FixPoint1616_t TimeOutMilliSecs)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_Error Status1 = VL53L0_ERROR_NONE;
+ uint32_t TimeoutMicroSeconds = ((TimeOutMilliSecs * 1000) + 0x8000)
+ >> 16;
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+ FixPoint1616_t OldTimeOutMicroSeconds;
+
+ LOG_FUNCTION_START("");
+
+ /* Read back the current value in case we need to revert back to this.
+ */
+ Status = get_sequence_step_timeout(Dev, SequenceStepId,
+ &OldTimeOutMicroSeconds);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = set_sequence_step_timeout(Dev, SequenceStepId,
+ TimeoutMicroSeconds);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_GETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+
+ /* At this point we don't know if the requested value is valid,
+ * therefore proceed to update the entire timing budget and
+ * if this fails, revert back to the previous value.
+ */
+ Status = VL53L0_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+
+ if (Status != VL53L0_ERROR_NONE) {
+ Status1 = set_sequence_step_timeout(Dev, SequenceStepId,
+ OldTimeOutMicroSeconds);
+
+ if (Status1 == VL53L0_ERROR_NONE) {
+ Status1 =
+ VL53L0_SetMeasurementTimingBudgetMicroSeconds(
+ Dev,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+
+ Status = Status1;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetSequenceStepTimeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId, FixPoint1616_t *pTimeOutMilliSecs)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint32_t TimeoutMicroSeconds;
+ uint32_t WholeNumber_ms = 0;
+ uint32_t Fraction_ms = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = get_sequence_step_timeout(Dev, SequenceStepId,
+ &TimeoutMicroSeconds);
+ if (Status == VL53L0_ERROR_NONE) {
+ WholeNumber_ms = TimeoutMicroSeconds / 1000;
+ Fraction_ms = TimeoutMicroSeconds - (WholeNumber_ms * 1000);
+ *pTimeOutMilliSecs = (WholeNumber_ms << 16)
+ + (((Fraction_ms * 0xffff) + 500) / 1000);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetInterMeasurementPeriodMilliSeconds(VL53L0_DEV Dev,
+ uint32_t InterMeasurementPeriodMilliSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t osc_calibrate_val;
+ uint32_t IMPeriodMilliSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdWord(Dev, VL53L0_REG_OSC_CALIBRATE_VAL,
+ &osc_calibrate_val);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (osc_calibrate_val != 0) {
+ IMPeriodMilliSeconds =
+ InterMeasurementPeriodMilliSeconds
+ * osc_calibrate_val;
+ } else {
+ IMPeriodMilliSeconds =
+ InterMeasurementPeriodMilliSeconds;
+ }
+ Status = VL53L0_WrDWord(Dev,
+ VL53L0_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+ IMPeriodMilliSeconds);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETPARAMETERFIELD(Dev,
+ InterMeasurementPeriodMilliSeconds,
+ InterMeasurementPeriodMilliSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetInterMeasurementPeriodMilliSeconds(VL53L0_DEV Dev,
+ uint32_t *pInterMeasurementPeriodMilliSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t osc_calibrate_val;
+ uint32_t IMPeriodMilliSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdWord(Dev, VL53L0_REG_OSC_CALIBRATE_VAL,
+ &osc_calibrate_val);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdDWord(Dev,
+ VL53L0_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+ &IMPeriodMilliSeconds);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (osc_calibrate_val != 0) {
+ *pInterMeasurementPeriodMilliSeconds =
+ IMPeriodMilliSeconds / osc_calibrate_val;
+ }
+ VL53L0_SETPARAMETERFIELD(Dev,
+ InterMeasurementPeriodMilliSeconds,
+ *pInterMeasurementPeriodMilliSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetXTalkCompensationEnable(VL53L0_DEV Dev,
+ uint8_t XTalkCompensationEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ FixPoint1616_t TempFix1616;
+ uint16_t LinearityCorrectiveGain;
+
+ LOG_FUNCTION_START("");
+
+ LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+ if ((XTalkCompensationEnable == 0)
+ || (LinearityCorrectiveGain != 1000)) {
+ TempFix1616 = 0;
+ } else {
+ VL53L0_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ TempFix1616);
+ }
+
+ /* the following register has a format 3.13 */
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS,
+ VL53L0_FIXPOINT1616TOFIXPOINT313(TempFix1616));
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (XTalkCompensationEnable == 0) {
+ VL53L0_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 0);
+ } else {
+ VL53L0_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetXTalkCompensationEnable(VL53L0_DEV Dev,
+ uint8_t *pXTalkCompensationEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8);
+ *pXTalkCompensationEnable = Temp8;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetXTalkCompensationRateMegaCps(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCompensationRateMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Temp8;
+ uint16_t LinearityCorrectiveGain;
+ uint16_t data;
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8);
+ LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+ if (Temp8 == 0) { /* disabled write only internal value */
+ VL53L0_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ XTalkCompensationRateMegaCps);
+ } else {
+ /* the following register has a format 3.13 */
+ if (LinearityCorrectiveGain == 1000) {
+ data = VL53L0_FIXPOINT1616TOFIXPOINT313(
+ XTalkCompensationRateMegaCps);
+ } else {
+ data = 0;
+ }
+
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, data);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps,
+ XTalkCompensationRateMegaCps);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetXTalkCompensationRateMegaCps(VL53L0_DEV Dev,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t Value;
+ FixPoint1616_t TempFix1616;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, (uint16_t *)&Value);
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Value == 0) {
+ /* the Xtalk is disabled return value from memory */
+ VL53L0_GETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps, TempFix1616);
+ *pXTalkCompensationRateMegaCps = TempFix1616;
+ VL53L0_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 0);
+ } else {
+ TempFix1616 = VL53L0_FIXPOINT313TOFIXPOINT1616(Value);
+ *pXTalkCompensationRateMegaCps = TempFix1616;
+ VL53L0_SETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps, TempFix1616);
+ VL53L0_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetRefCalibration(VL53L0_DEV Dev, uint8_t VhvSettings,
+ uint8_t PhaseCal)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_set_ref_calibration(Dev, VhvSettings, PhaseCal);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetRefCalibration(VL53L0_DEV Dev, uint8_t *pVhvSettings,
+ uint8_t *pPhaseCal)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_ref_calibration(Dev, pVhvSettings, pPhaseCal);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/*
+ * CHECK LIMIT FUNCTIONS
+ */
+
+VL53L0_Error VL53L0_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfLimitCheck = VL53L0_CHECKENABLE_NUMBER_OF_CHECKS;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetLimitCheckInfo(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ char *pLimitCheckString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_limit_check_info(Dev, LimitCheckId,
+ pLimitCheckString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetLimitCheckStatus(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ uint8_t *pLimitCheckStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L0_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+
+ VL53L0_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ LimitCheckId, Temp8);
+
+ *pLimitCheckStatus = Temp8;
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetLimitCheckEnable(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ uint8_t LimitCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ FixPoint1616_t TempFix1616 = 0;
+ uint8_t LimitCheckEnableInt = 0;
+ uint8_t LimitCheckDisable = 0;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L0_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+ if (LimitCheckEnable == 0) {
+ TempFix1616 = 0;
+ LimitCheckEnableInt = 0;
+ LimitCheckDisable = 1;
+
+ } else {
+ VL53L0_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId, TempFix1616);
+ LimitCheckDisable = 0;
+ /* this to be sure to have either 0 or 1 */
+ LimitCheckEnableInt = 1;
+ }
+
+ switch (LimitCheckId) {
+
+ case VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* internal computation: */
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ LimitCheckEnableInt);
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+ VL53L0_FIXPOINT1616TOFIXPOINT97(TempFix1616));
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_REF_CLIP:
+
+ /* internal computation: */
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP,
+ LimitCheckEnableInt);
+
+ break;
+
+ case VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+
+ /* internal computation: */
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ LimitCheckEnableInt);
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_MSRC:
+
+ Temp8 = (uint8_t)(LimitCheckDisable << 1);
+ Status = VL53L0_UpdateByte(Dev,
+ VL53L0_REG_MSRC_CONFIG_CONTROL,
+ 0xFE, Temp8);
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+
+ Temp8 = (uint8_t)(LimitCheckDisable << 4);
+ Status = VL53L0_UpdateByte(Dev,
+ VL53L0_REG_MSRC_CONFIG_CONTROL,
+ 0xEF, Temp8);
+
+ break;
+
+
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ }
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (LimitCheckEnable == 0) {
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, 0);
+ } else {
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetLimitCheckEnable(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ uint8_t *pLimitCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L0_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ *pLimitCheckEnable = 0;
+ } else {
+ VL53L0_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, Temp8);
+ *pLimitCheckEnable = Temp8;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetLimitCheckValue(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ FixPoint1616_t LimitCheckValue)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, LimitCheckId,
+ Temp8);
+
+ if (Temp8 == 0) { /* disabled write only internal value */
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId, LimitCheckValue);
+ } else {
+
+ switch (LimitCheckId) {
+
+ case VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* internal computation: */
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ LimitCheckValue);
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+ VL53L0_FIXPOINT1616TOFIXPOINT97(
+ LimitCheckValue));
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_REF_CLIP:
+
+ /* internal computation: */
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP,
+ LimitCheckValue);
+
+ break;
+
+ case VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+
+ /* internal computation: */
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ LimitCheckValue);
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_MSRC:
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
+ VL53L0_FIXPOINT1616TOFIXPOINT97(
+ LimitCheckValue));
+
+ break;
+
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId, LimitCheckValue);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetLimitCheckValue(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ FixPoint1616_t *pLimitCheckValue)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t EnableZeroValue = 0;
+ uint16_t Temp16;
+ FixPoint1616_t TempFix1616;
+
+ LOG_FUNCTION_START("");
+
+ switch (LimitCheckId) {
+
+ case VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* internal computation: */
+ VL53L0_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE, TempFix1616);
+ EnableZeroValue = 0;
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+ &Temp16);
+ if (Status == VL53L0_ERROR_NONE)
+ TempFix1616 = VL53L0_FIXPOINT97TOFIXPOINT1616(Temp16);
+
+
+ EnableZeroValue = 1;
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_REF_CLIP:
+ /* internal computation: */
+ VL53L0_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP, TempFix1616);
+ EnableZeroValue = 0;
+ break;
+
+ case VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+ /* internal computation: */
+ VL53L0_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD, TempFix1616);
+ EnableZeroValue = 0;
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_MSRC:
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
+ &Temp16);
+ if (Status == VL53L0_ERROR_NONE)
+ TempFix1616 = VL53L0_FIXPOINT97TOFIXPOINT1616(Temp16);
+
+
+ EnableZeroValue = 0;
+ break;
+
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ if (EnableZeroValue == 1) {
+
+ if (TempFix1616 == 0) {
+ /* disabled: return value from memory */
+ VL53L0_GETARRAYPARAMETERFIELD(Dev,
+ LimitChecksValue, LimitCheckId,
+ TempFix1616);
+ *pLimitCheckValue = TempFix1616;
+ VL53L0_SETARRAYPARAMETERFIELD(Dev,
+ LimitChecksEnable, LimitCheckId, 0);
+ } else {
+ *pLimitCheckValue = TempFix1616;
+ VL53L0_SETARRAYPARAMETERFIELD(Dev,
+ LimitChecksValue, LimitCheckId,
+ TempFix1616);
+ VL53L0_SETARRAYPARAMETERFIELD(Dev,
+ LimitChecksEnable, LimitCheckId, 1);
+ }
+ } else {
+ *pLimitCheckValue = TempFix1616;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+VL53L0_Error VL53L0_GetLimitCheckCurrent(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ FixPoint1616_t *pLimitCheckCurrent)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_RangingMeasurementData_t LastRangeDataBuffer;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL53L0_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else {
+ switch (LimitCheckId) {
+ case VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* Need to run a ranging to have the latest values */
+ *pLimitCheckCurrent = PALDevDataGet(Dev, SigmaEstimate);
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_REF_CLIP:
+ /* Need to run a ranging to have the latest values */
+ *pLimitCheckCurrent = PALDevDataGet(Dev,
+ LastSignalRefMcps);
+
+ break;
+
+ case VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_MSRC:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+/*
+ * WRAPAROUND Check
+ */
+VL53L0_Error VL53L0_SetWrapAroundCheckEnable(VL53L0_DEV Dev,
+ uint8_t WrapAroundCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+ uint8_t WrapAroundCheckEnableInt;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, &Byte);
+ if (WrapAroundCheckEnable == 0) {
+ /* Disable wraparound */
+ Byte = Byte & 0x7F;
+ WrapAroundCheckEnableInt = 0;
+ } else {
+ /*Enable wraparound */
+ Byte = Byte | 0x80;
+ WrapAroundCheckEnableInt = 1;
+ }
+
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, Byte);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ PALDevDataSet(Dev, SequenceConfig, Byte);
+ VL53L0_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+ WrapAroundCheckEnableInt);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetWrapAroundCheckEnable(VL53L0_DEV Dev,
+ uint8_t *pWrapAroundCheckEnable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, &data);
+ if (Status == VL53L0_ERROR_NONE) {
+ PALDevDataSet(Dev, SequenceConfig, data);
+ if (data & (0x01 << 7))
+ *pWrapAroundCheckEnable = 0x01;
+ else
+ *pWrapAroundCheckEnable = 0x00;
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+ *pWrapAroundCheckEnable);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetDmaxCalParameters(VL53L0_DEV Dev,
+ uint16_t RangeMilliMeter, FixPoint1616_t SignalRateRtnMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ FixPoint1616_t SignalRateRtnMegaCpsTemp = 0;
+
+ LOG_FUNCTION_START("");
+
+ /* Check if one of input parameter is zero, in that case the
+ * value are get from NVM
+ */
+ if ((RangeMilliMeter == 0) || (SignalRateRtnMegaCps == 0)) {
+ /* NVM parameters */
+ /* Run VL53L0_get_info_from_device wit option 4 to get
+ * signal rate at 400 mm if the value have been already
+ * get this function will return with no access to device
+ */
+ VL53L0_get_info_from_device(Dev, 4);
+
+ SignalRateRtnMegaCpsTemp = VL53L0_GETDEVICESPECIFICPARAMETER(
+ Dev, SignalRateMeasFixed400mm);
+
+ PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400);
+ PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+ SignalRateRtnMegaCpsTemp);
+ } else {
+ /* User parameters */
+ PALDevDataSet(Dev, DmaxCalRangeMilliMeter, RangeMilliMeter);
+ PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+ SignalRateRtnMegaCps);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetDmaxCalParameters(VL53L0_DEV Dev,
+ uint16_t *pRangeMilliMeter, FixPoint1616_t *pSignalRateRtnMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pRangeMilliMeter = PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
+ *pSignalRateRtnMegaCps = PALDevDataGet(Dev,
+ DmaxCalSignalRateRtnMegaCps);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Parameters Functions */
+
+/* Group PAL Measurement Functions */
+VL53L0_Error VL53L0_PerformSingleMeasurement(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceModes DeviceMode;
+
+ LOG_FUNCTION_START("");
+
+ /* Get Current DeviceMode */
+ Status = VL53L0_GetDeviceMode(Dev, &DeviceMode);
+
+ /* Start immediately to run a single ranging measurement in case of
+ * single ranging or single histogram
+ */
+ if (Status == VL53L0_ERROR_NONE
+ && DeviceMode == VL53L0_DEVICEMODE_SINGLE_RANGING)
+ Status = VL53L0_StartMeasurement(Dev);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_measurement_poll_for_completion(Dev);
+
+
+ /* Change PAL State in case of single ranging or single histogram */
+ if (Status == VL53L0_ERROR_NONE
+ && DeviceMode == VL53L0_DEVICEMODE_SINGLE_RANGING)
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_IDLE);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_PerformSingleHistogramMeasurement(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_perform_single_histogram_measurement(Dev,
+ pHistogramMeasurementData);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_PerformRefCalibration(VL53L0_DEV Dev, uint8_t *pVhvSettings,
+ uint8_t *pPhaseCal)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_perform_ref_calibration(Dev, pVhvSettings,
+ pPhaseCal, 1);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_PerformXTalkMeasurement(VL53L0_DEV Dev,
+ uint32_t TimeoutMs, FixPoint1616_t *pXtalkPerSpad,
+ uint8_t *pAmbientTooHigh)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_perform_xtalk_measurement(Dev, TimeoutMs,
+ pXtalkPerSpad, pAmbientTooHigh);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_PerformXTalkCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCalDistance,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_perform_xtalk_calibration(Dev, XTalkCalDistance,
+ pXTalkCompensationRateMegaCps);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_PerformOffsetCalibration(VL53L0_DEV Dev,
+ FixPoint1616_t CalDistanceMilliMeter, int32_t *pOffsetMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_perform_offset_calibration(Dev, CalDistanceMilliMeter,
+ pOffsetMicroMeter);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_CheckAndLoadInterruptSettings(VL53L0_DEV Dev,
+ uint8_t StartNotStopFlag)
+{
+ uint8_t InterruptConfig;
+ FixPoint1616_t ThresholdLow;
+ FixPoint1616_t ThresholdHigh;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ InterruptConfig = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality);
+
+ if ((InterruptConfig ==
+ VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW) ||
+ (InterruptConfig ==
+ VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH) ||
+ (InterruptConfig ==
+ VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT)) {
+
+ Status = VL53L0_GetInterruptThresholds(Dev,
+ VL53L0_DEVICEMODE_CONTINUOUS_RANGING,
+ &ThresholdLow, &ThresholdHigh);
+
+ if (((ThresholdLow > 255*65536) ||
+ (ThresholdHigh > 255*65536)) &&
+ (Status == VL53L0_ERROR_NONE)) {
+
+ if (StartNotStopFlag != 0) {
+ Status = VL53L0_load_tuning_settings(Dev,
+ InterruptThresholdSettings);
+ } else {
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0x70, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x00);
+ }
+
+ }
+
+
+ }
+
+ return Status;
+
+}
+
+
+VL53L0_Error VL53L0_StartMeasurement(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceModes DeviceMode;
+ uint8_t Byte;
+ uint8_t StartStopByte = VL53L0_REG_SYSRANGE_MODE_START_STOP;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ /* Get Current DeviceMode */
+ VL53L0_GetDeviceMode(Dev, &DeviceMode);
+
+ Status = VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status = VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status = VL53L0_WrByte(Dev, 0x91, PALDevDataGet(Dev, StopVariable));
+ Status = VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status = VL53L0_WrByte(Dev, 0x80, 0x00);
+
+ switch (DeviceMode) {
+ case VL53L0_DEVICEMODE_SINGLE_RANGING:
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSRANGE_START, 0x01);
+
+ Byte = StartStopByte;
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Wait until start bit has been cleared */
+ LoopNb = 0;
+ do {
+ if (LoopNb > 0)
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_SYSRANGE_START, &Byte);
+ LoopNb = LoopNb + 1;
+ } while (((Byte & StartStopByte) == StartStopByte)
+ && (Status == VL53L0_ERROR_NONE)
+ && (LoopNb < VL53L0_DEFAULT_MAX_LOOP));
+
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP)
+ Status = VL53L0_ERROR_TIME_OUT;
+
+ }
+
+ break;
+ case VL53L0_DEVICEMODE_CONTINUOUS_RANGING:
+ /* Back-to-back mode */
+
+ /* Check if need to apply interrupt settings */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_CheckAndLoadInterruptSettings(Dev, 1);
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_SYSRANGE_START,
+ VL53L0_REG_SYSRANGE_MODE_BACKTOBACK);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to Running */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_RUNNING);
+ }
+ break;
+ case VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+ /* Continuous mode */
+ /* Check if need to apply interrupt settings */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_CheckAndLoadInterruptSettings(Dev, 1);
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_SYSRANGE_START,
+ VL53L0_REG_SYSRANGE_MODE_TIMED);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to Running */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_RUNNING);
+ }
+ break;
+ default:
+ /* Selected mode not supported */
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_StopMeasurement(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSRANGE_START,
+ VL53L0_REG_SYSRANGE_MODE_SINGLESHOT);
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status = VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status = VL53L0_WrByte(Dev, 0x91, 0x00);
+ Status = VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to Idle */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_IDLE);
+ }
+
+ /* Check if need to apply interrupt settings */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_CheckAndLoadInterruptSettings(Dev, 0);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetMeasurementDataReady(VL53L0_DEV Dev,
+ uint8_t *pMeasurementDataReady)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SysRangeStatusRegister;
+ uint8_t InterruptConfig;
+ uint32_t InterruptMask;
+
+ LOG_FUNCTION_START("");
+
+ InterruptConfig = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality);
+
+ if (InterruptConfig ==
+ VL53L0_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) {
+ Status = VL53L0_GetInterruptMaskStatus(Dev, &InterruptMask);
+ if (InterruptMask ==
+ VL53L0_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY)
+ *pMeasurementDataReady = 1;
+ else
+ *pMeasurementDataReady = 0;
+ } else {
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_RESULT_RANGE_STATUS,
+ &SysRangeStatusRegister);
+ if (Status == VL53L0_ERROR_NONE) {
+ if (SysRangeStatusRegister & 0x01)
+ *pMeasurementDataReady = 1;
+ else
+ *pMeasurementDataReady = 0;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_WaitDeviceReadyForNewMeasurement(VL53L0_DEV Dev,
+ uint32_t MaxLoop)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented for VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_GetRangingMeasurementData(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t DeviceRangeStatus;
+ uint8_t RangeFractionalEnable;
+ uint8_t PalRangeStatus;
+ uint8_t XTalkCompensationEnable;
+ uint16_t AmbientRate;
+ FixPoint1616_t SignalRate;
+ uint16_t XTalkCompensationRateMegaCps;
+ uint16_t EffectiveSpadRtnCount;
+ uint16_t tmpuint16;
+ uint16_t XtalkRangeMilliMeter;
+ uint16_t LinearityCorrectiveGain;
+ uint8_t localBuffer[12];
+ VL53L0_RangingMeasurementData_t LastRangeDataBuffer;
+
+ LOG_FUNCTION_START("");
+
+ /*
+ * use multi read even if some registers are not useful, result will
+ * be more efficient
+ * start reading at 0x14 dec20
+ * end reading at 0x21 dec33 total 14 bytes to read
+ */
+ Status = VL53L0_ReadMulti(Dev, 0x14, localBuffer, 12);
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ pRangingMeasurementData->ZoneId = 0; /* Only one zone */
+ pRangingMeasurementData->TimeStamp = 0; /* Not Implemented */
+
+ tmpuint16 = VL53L0_MAKEUINT16(localBuffer[11], localBuffer[10]);
+ /* cut1.1 if SYSTEM__RANGE_CONFIG if 1 range is 2bits fractional
+ *(format 11.2) else no fractional
+ */
+
+ pRangingMeasurementData->MeasurementTimeUsec = 0;
+
+ SignalRate = VL53L0_FIXPOINT97TOFIXPOINT1616(
+ VL53L0_MAKEUINT16(localBuffer[7], localBuffer[6]));
+ /* peak_signal_count_rate_rtn_mcps */
+ pRangingMeasurementData->SignalRateRtnMegaCps = SignalRate;
+
+ AmbientRate = VL53L0_MAKEUINT16(localBuffer[9], localBuffer[8]);
+ pRangingMeasurementData->AmbientRateRtnMegaCps =
+ VL53L0_FIXPOINT97TOFIXPOINT1616(AmbientRate);
+
+ EffectiveSpadRtnCount = VL53L0_MAKEUINT16(localBuffer[3],
+ localBuffer[2]);
+ /* EffectiveSpadRtnCount is 8.8 format */
+ pRangingMeasurementData->EffectiveSpadRtnCount =
+ EffectiveSpadRtnCount;
+
+ DeviceRangeStatus = localBuffer[0];
+
+ /* Get Linearity Corrective Gain */
+ LinearityCorrectiveGain = PALDevDataGet(Dev,
+ LinearityCorrectiveGain);
+
+ /* Get ranging configuration */
+ RangeFractionalEnable = PALDevDataGet(Dev,
+ RangeFractionalEnable);
+
+ if (LinearityCorrectiveGain != 1000) {
+
+ tmpuint16 = (uint16_t)((LinearityCorrectiveGain
+ * tmpuint16 + 500) / 1000);
+
+ /* Implement Xtalk */
+ VL53L0_GETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps,
+ XTalkCompensationRateMegaCps);
+ VL53L0_GETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ XTalkCompensationEnable);
+
+ if (XTalkCompensationEnable) {
+
+ if ((SignalRate
+ - ((XTalkCompensationRateMegaCps
+ * EffectiveSpadRtnCount) >> 8))
+ <= 0) {
+ if (RangeFractionalEnable)
+ XtalkRangeMilliMeter = 8888;
+ else
+ XtalkRangeMilliMeter = 8888
+ << 2;
+ } else {
+ XtalkRangeMilliMeter =
+ (tmpuint16 * SignalRate)
+ / (SignalRate
+ - ((XTalkCompensationRateMegaCps
+ * EffectiveSpadRtnCount)
+ >> 8));
+ }
+
+ tmpuint16 = XtalkRangeMilliMeter;
+ }
+
+ }
+
+ if (RangeFractionalEnable) {
+ pRangingMeasurementData->RangeMilliMeter =
+ (uint16_t)((tmpuint16) >> 2);
+ pRangingMeasurementData->RangeFractionalPart =
+ (uint8_t)((tmpuint16 & 0x03) << 6);
+ } else {
+ pRangingMeasurementData->RangeMilliMeter = tmpuint16;
+ pRangingMeasurementData->RangeFractionalPart = 0;
+ }
+
+ /*
+ * For a standard definition of RangeStatus, this should
+ * return 0 in case of good result after a ranging
+ * The range status depends on the device so call a device
+ * specific function to obtain the right Status.
+ */
+ Status |= VL53L0_get_pal_range_status(Dev, DeviceRangeStatus,
+ SignalRate, EffectiveSpadRtnCount,
+ pRangingMeasurementData, &PalRangeStatus);
+
+ if (Status == VL53L0_ERROR_NONE)
+ pRangingMeasurementData->RangeStatus = PalRangeStatus;
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Copy last read data into Dev buffer */
+ LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure);
+
+ LastRangeDataBuffer.RangeMilliMeter =
+ pRangingMeasurementData->RangeMilliMeter;
+ LastRangeDataBuffer.RangeFractionalPart =
+ pRangingMeasurementData->RangeFractionalPart;
+ LastRangeDataBuffer.RangeDMaxMilliMeter =
+ pRangingMeasurementData->RangeDMaxMilliMeter;
+ LastRangeDataBuffer.MeasurementTimeUsec =
+ pRangingMeasurementData->MeasurementTimeUsec;
+ LastRangeDataBuffer.SignalRateRtnMegaCps =
+ pRangingMeasurementData->SignalRateRtnMegaCps;
+ LastRangeDataBuffer.AmbientRateRtnMegaCps =
+ pRangingMeasurementData->AmbientRateRtnMegaCps;
+ LastRangeDataBuffer.EffectiveSpadRtnCount =
+ pRangingMeasurementData->EffectiveSpadRtnCount;
+ LastRangeDataBuffer.RangeStatus =
+ pRangingMeasurementData->RangeStatus;
+
+ PALDevDataSet(Dev, LastRangeMeasure, LastRangeDataBuffer);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetMeasurementRefSignal(VL53L0_DEV Dev,
+ FixPoint1616_t *pMeasurementRefSignal)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pMeasurementRefSignal = PALDevDataGet(Dev, LastSignalRefMcps);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+VL53L0_Error VL53L0_GetHistogramMeasurementData(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_PerformSingleRangingMeasurement(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* This function will do a complete single ranging
+ * Here we fix the mode!
+ */
+ Status = VL53L0_SetDeviceMode(Dev, VL53L0_DEVICEMODE_SINGLE_RANGING);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_PerformSingleMeasurement(Dev);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetRangingMeasurementData(Dev,
+ pRangingMeasurementData);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_ClearInterruptMask(Dev, 0);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t NumberOfROIZones)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if (NumberOfROIZones != 1)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t *pNumberOfROIZones)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfROIZones = 1;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetMaxNumberOfROIZones(VL53L0_DEV Dev,
+ uint8_t *pMaxNumberOfROIZones)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pMaxNumberOfROIZones = 1;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Measurement Functions */
+
+VL53L0_Error VL53L0_SetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes DeviceMode, VL53L0_GpioFunctionality Functionality,
+ VL53L0_InterruptPolarity Polarity)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ if (Pin != 0) {
+ Status = VL53L0_ERROR_GPIO_NOT_EXISTING;
+ } else if (DeviceMode == VL53L0_DEVICEMODE_GPIO_DRIVE) {
+ if (Polarity == VL53L0_INTERRUPTPOLARITY_LOW)
+ data = 0x10;
+ else
+ data = 1;
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_GPIO_HV_MUX_ACTIVE_HIGH, data);
+
+ } else if (DeviceMode == VL53L0_DEVICEMODE_GPIO_OSC) {
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x85, 0x02);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x04);
+ Status |= VL53L0_WrByte(Dev, 0xcd, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xcc, 0x11);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0xbe, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x06);
+ Status |= VL53L0_WrByte(Dev, 0xcc, 0x09);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ } else {
+
+ if (Status == VL53L0_ERROR_NONE) {
+ switch (Functionality) {
+ case VL53L0_GPIOFUNCTIONALITY_OFF:
+ data = 0x00;
+ break;
+ case VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW:
+ data = 0x01;
+ break;
+ case VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH:
+ data = 0x02;
+ break;
+ case VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT:
+ data = 0x03;
+ break;
+ case VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY:
+ data = 0x04;
+ break;
+ default:
+ Status =
+ VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, data);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Polarity == VL53L0_INTERRUPTPOLARITY_LOW)
+ data = 0;
+ else
+ data = (uint8_t)(1 << 4);
+
+ Status = VL53L0_UpdateByte(Dev,
+ VL53L0_REG_GPIO_HV_MUX_ACTIVE_HIGH, 0xEF, data);
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality, Functionality);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_ClearInterruptMask(Dev, 0);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetGpioConfig(VL53L0_DEV Dev, uint8_t Pin,
+ VL53L0_DeviceModes *pDeviceMode,
+ VL53L0_GpioFunctionality *pFunctionality,
+ VL53L0_InterruptPolarity *pPolarity)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_GpioFunctionality GpioFunctionality;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ /* pDeviceMode not managed by Ewok it return the current mode */
+
+ Status = VL53L0_GetDeviceMode(Dev, pDeviceMode);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Pin != 0) {
+ Status = VL53L0_ERROR_GPIO_NOT_EXISTING;
+ } else {
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, &data);
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ switch (data & 0x07) {
+ case 0x00:
+ GpioFunctionality = VL53L0_GPIOFUNCTIONALITY_OFF;
+ break;
+ case 0x01:
+ GpioFunctionality =
+ VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW;
+ break;
+ case 0x02:
+ GpioFunctionality =
+ VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH;
+ break;
+ case 0x03:
+ GpioFunctionality =
+ VL53L0_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT;
+ break;
+ case 0x04:
+ GpioFunctionality =
+ VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY;
+ break;
+ default:
+ Status = VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_GPIO_HV_MUX_ACTIVE_HIGH,
+ &data);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if ((data & (uint8_t)(1 << 4)) == 0)
+ *pPolarity = VL53L0_INTERRUPTPOLARITY_LOW;
+ else
+ *pPolarity = VL53L0_INTERRUPTPOLARITY_HIGH;
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ *pFunctionality = GpioFunctionality;
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, Pin0GpioFunctionality,
+ GpioFunctionality);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetInterruptThresholds(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode, FixPoint1616_t ThresholdLow,
+ FixPoint1616_t ThresholdHigh)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t Threshold16;
+
+ LOG_FUNCTION_START("");
+
+ /* no dependency on DeviceMode for Ewok */
+ /* Need to divide by 2 because the FW will apply a x2 */
+ Threshold16 = (uint16_t)((ThresholdLow >> 17) & 0x00fff);
+ Status = VL53L0_WrWord(Dev, VL53L0_REG_SYSTEM_THRESH_LOW, Threshold16);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Need to divide by 2 because the FW will apply a x2 */
+ Threshold16 = (uint16_t)((ThresholdHigh >> 17) & 0x00fff);
+ Status = VL53L0_WrWord(Dev, VL53L0_REG_SYSTEM_THRESH_HIGH,
+ Threshold16);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetInterruptThresholds(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode, FixPoint1616_t *pThresholdLow,
+ FixPoint1616_t *pThresholdHigh)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t Threshold16;
+
+ LOG_FUNCTION_START("");
+
+ /* no dependency on DeviceMode for Ewok */
+
+ Status = VL53L0_RdWord(Dev, VL53L0_REG_SYSTEM_THRESH_LOW, &Threshold16);
+ /* Need to multiply by 2 because the FW will apply a x2 */
+ *pThresholdLow = (FixPoint1616_t)((0x00fff & Threshold16) << 17);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev, VL53L0_REG_SYSTEM_THRESH_HIGH,
+ &Threshold16);
+ /* Need to multiply by 2 because the FW will apply a x2 */
+ *pThresholdHigh =
+ (FixPoint1616_t)((0x00fff & Threshold16) << 17);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetStopCompletedStatus(VL53L0_DEV Dev,
+ uint32_t *pStopStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_RdByte(Dev, 0x04, &Byte);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x0);
+
+ *pStopStatus = Byte;
+
+ if (Byte == 0) {
+ Status = VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status = VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status = VL53L0_WrByte(Dev, 0x91,
+ PALDevDataGet(Dev, StopVariable));
+ Status = VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status = VL53L0_WrByte(Dev, 0x80, 0x00);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* Group PAL Interrupt Functions */
+VL53L0_Error VL53L0_ClearInterruptMask(VL53L0_DEV Dev, uint32_t InterruptMask)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t LoopCount;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* clear bit 0 range interrupt, bit 1 error interrupt */
+ LoopCount = 0;
+ do {
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_SYSTEM_INTERRUPT_CLEAR, 0x01);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_SYSTEM_INTERRUPT_CLEAR, 0x00);
+ Status |= VL53L0_RdByte(Dev,
+ VL53L0_REG_RESULT_INTERRUPT_STATUS, &Byte);
+ LoopCount++;
+ } while (((Byte & 0x07) != 0x00)
+ && (LoopCount < 3)
+ && (Status == VL53L0_ERROR_NONE));
+
+
+ if (LoopCount >= 3)
+ Status = VL53L0_ERROR_INTERRUPT_NOT_CLEARED;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetInterruptMaskStatus(VL53L0_DEV Dev,
+ uint32_t *pInterruptMaskStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_RESULT_INTERRUPT_STATUS, &Byte);
+ *pInterruptMaskStatus = Byte & 0x07;
+
+ if (Byte & 0x18)
+ Status = VL53L0_ERROR_RANGE_ERROR;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_EnableInterruptMask(VL53L0_DEV Dev, uint32_t InterruptMask)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented for VL53L0 */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Interrupt Functions */
+
+/* Group SPAD functions */
+
+VL53L0_Error VL53L0_SetSpadAmbientDamperThreshold(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperThreshold)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrWord(Dev, 0x40, SpadAmbientDamperThreshold);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetSpadAmbientDamperThreshold(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperThreshold)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_RdWord(Dev, 0x40, pSpadAmbientDamperThreshold);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_SetSpadAmbientDamperFactor(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperFactor)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Byte = (uint8_t)(SpadAmbientDamperFactor & 0x00FF);
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x42, Byte);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetSpadAmbientDamperFactor(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperFactor)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_RdByte(Dev, 0x42, &Byte);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ *pSpadAmbientDamperFactor = (uint16_t)Byte;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* END Group SPAD functions */
+
+/*****************************************************************************
+ * Internal functions
+ *****************************************************************************/
+
+VL53L0_Error VL53L0_SetReferenceSpads(VL53L0_DEV Dev, uint32_t count,
+ uint8_t isApertureSpads)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_set_reference_spads(Dev, count, isApertureSpads);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_GetReferenceSpads(VL53L0_DEV Dev, uint32_t *pSpadCount,
+ uint8_t *pIsApertureSpads)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_reference_spads(Dev, pSpadCount, pIsApertureSpads);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_PerformRefSpadManagement(VL53L0_DEV Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_perform_ref_spad_management(Dev, refSpadCount,
+ isApertureSpads);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_api_calibration.c b/drivers/input/misc/vl53L0/src/vl53l0_api_calibration.c
new file mode 100644
index 000000000000..fa7e579ddc17
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_api_calibration.c
@@ -0,0 +1,1284 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l0_api.h"
+#include "vl53l0_api_core.h"
+#include "vl53l0_api_calibration.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#define REF_ARRAY_SPAD_0 0
+#define REF_ARRAY_SPAD_5 5
+#define REF_ARRAY_SPAD_10 10
+
+uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5,
+ REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5 };
+
+VL53L0_Error VL53L0_perform_xtalk_calibration(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCalDistance,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t sum_ranging = 0;
+ uint16_t sum_spads = 0;
+ FixPoint1616_t sum_signalRate = 0;
+ FixPoint1616_t total_count = 0;
+ uint8_t xtalk_meas = 0;
+ VL53L0_RangingMeasurementData_t RangingMeasurementData;
+ FixPoint1616_t xTalkStoredMeanSignalRate;
+ FixPoint1616_t xTalkStoredMeanRange;
+ FixPoint1616_t xTalkStoredMeanRtnSpads;
+ uint32_t signalXTalkTotalPerSpad;
+ uint32_t xTalkStoredMeanRtnSpadsAsInt;
+ uint32_t xTalkCalDistanceAsInt;
+ FixPoint1616_t XTalkCompensationRateMegaCps;
+
+ if (XTalkCalDistance <= 0)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ /* Disable the XTalk compensation */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetXTalkCompensationEnable(Dev, 0);
+
+ /* Disable the RIT */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_SetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+ }
+
+ /* Perform 50 measurements and compute the averages */
+ if (Status == VL53L0_ERROR_NONE) {
+ sum_ranging = 0;
+ sum_spads = 0;
+ sum_signalRate = 0;
+ total_count = 0;
+ for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) {
+ Status = VL53L0_PerformSingleRangingMeasurement(Dev,
+ &RangingMeasurementData);
+
+ if (Status != VL53L0_ERROR_NONE)
+ break;
+
+ /* The range is valid when RangeStatus = 0 */
+ if (RangingMeasurementData.RangeStatus == 0) {
+ sum_ranging = sum_ranging +
+ RangingMeasurementData.RangeMilliMeter;
+ sum_signalRate = sum_signalRate +
+ RangingMeasurementData.SignalRateRtnMegaCps;
+ sum_spads = sum_spads +
+ RangingMeasurementData.EffectiveSpadRtnCount
+ / 256;
+ total_count = total_count + 1;
+ }
+ }
+
+ /* no valid values found */
+ if (total_count == 0)
+ Status = VL53L0_ERROR_RANGE_ERROR;
+
+ }
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* FixPoint1616_t / uint16_t = FixPoint1616_t */
+ xTalkStoredMeanSignalRate = sum_signalRate / total_count;
+ xTalkStoredMeanRange = (FixPoint1616_t)((uint32_t)(
+ sum_ranging << 16) / total_count);
+ xTalkStoredMeanRtnSpads = (FixPoint1616_t)((uint32_t)(
+ sum_spads << 16) / total_count);
+
+ /* Round Mean Spads to Whole Number.
+ * Typically the calculated mean SPAD count is a whole number
+ * or very close to a whole
+ * number, therefore any truncation will not result in a
+ * significant loss in accuracy.
+ * Also, for a grey target at a typical distance of around
+ * 400mm, around 220 SPADs will
+ * be enabled, therefore, any truncation will result in a loss
+ * of accuracy of less than
+ * 0.5%.
+ */
+ xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads +
+ 0x8000) >> 16;
+
+ /* Round Cal Distance to Whole Number.
+ * Note that the cal distance is in mm, therefore no resolution
+ * is lost.
+ */
+ xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16;
+
+ if (xTalkStoredMeanRtnSpadsAsInt == 0 ||
+ xTalkCalDistanceAsInt == 0 ||
+ xTalkStoredMeanRange >= XTalkCalDistance) {
+ XTalkCompensationRateMegaCps = 0;
+ } else {
+ /* Round Cal Distance to Whole Number.
+ * Note that the cal distance is in mm, therefore no
+ * resolution is lost.
+ */
+ xTalkCalDistanceAsInt = (XTalkCalDistance +
+ 0x8000) >> 16;
+
+ /* Apply division by mean spad count early in the
+ * calculation to keep the numbers small.
+ * This ensures we can maintain a 32bit calculation.
+ * Fixed1616 / int := Fixed1616
+ */
+ signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) /
+ xTalkStoredMeanRtnSpadsAsInt;
+
+ /* Complete the calculation for total Signal XTalk per
+ * SPAD
+ * Fixed1616 * (Fixed1616 - Fixed1616/int) :=
+ * (2^16 * Fixed1616)
+ */
+ signalXTalkTotalPerSpad *= ((1 << 16) -
+ (xTalkStoredMeanRange / xTalkCalDistanceAsInt));
+
+ /* Round from 2^16 * Fixed1616, to Fixed1616. */
+ XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad
+ + 0x8000) >> 16;
+ }
+
+ *pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps;
+
+ /* Enable the XTalk compensation */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetXTalkCompensationEnable(Dev, 1);
+
+ /* Enable the XTalk compensation */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetXTalkCompensationRateMegaCps(Dev,
+ XTalkCompensationRateMegaCps);
+
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_perform_offset_calibration(VL53L0_DEV Dev,
+ FixPoint1616_t CalDistanceMilliMeter,
+ int32_t *pOffsetMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t sum_ranging = 0;
+ FixPoint1616_t total_count = 0;
+ VL53L0_RangingMeasurementData_t RangingMeasurementData;
+ FixPoint1616_t StoredMeanRange;
+ uint32_t StoredMeanRangeAsInt;
+ uint32_t CalDistanceAsInt_mm;
+ uint8_t SequenceStepEnabled;
+ int meas = 0;
+
+ if (CalDistanceMilliMeter <= 0)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetOffsetCalibrationDataMicroMeter(Dev, 0);
+
+
+ /* Get the value of the TCC */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_TCC, &SequenceStepEnabled);
+
+
+ /* Disable the TCC */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_TCC, 0);
+
+
+ /* Disable the RIT */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_SetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+
+ /* Perform 50 measurements and compute the averages */
+ if (Status == VL53L0_ERROR_NONE) {
+ sum_ranging = 0;
+ total_count = 0;
+ for (meas = 0; meas < 50; meas++) {
+ Status = VL53L0_PerformSingleRangingMeasurement(Dev,
+ &RangingMeasurementData);
+
+ if (Status != VL53L0_ERROR_NONE)
+ break;
+
+ /* The range is valid when RangeStatus = 0 */
+ if (RangingMeasurementData.RangeStatus == 0) {
+ sum_ranging = sum_ranging +
+ RangingMeasurementData.RangeMilliMeter;
+ total_count = total_count + 1;
+ }
+ }
+
+ /* no valid values found */
+ if (total_count == 0)
+ Status = VL53L0_ERROR_RANGE_ERROR;
+ }
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* FixPoint1616_t / uint16_t = FixPoint1616_t */
+ StoredMeanRange = (FixPoint1616_t)((uint32_t)(sum_ranging << 16)
+ / total_count);
+
+ StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16;
+
+ /* Round Cal Distance to Whole Number.
+ * Note that the cal distance is in mm, therefore no resolution
+ * is lost.
+ */
+ CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16;
+
+ *pOffsetMicroMeter = (CalDistanceAsInt_mm -
+ StoredMeanRangeAsInt) * 1000;
+
+ /* Apply the calculated offset */
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
+ *pOffsetMicroMeter);
+ Status = VL53L0_SetOffsetCalibrationDataMicroMeter(Dev,
+ *pOffsetMicroMeter);
+ }
+
+ }
+
+ /* Restore the TCC */
+ if (Status == VL53L0_ERROR_NONE) {
+ if (SequenceStepEnabled != 0)
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_TCC, 1);
+ }
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_set_offset_calibration_data_micro_meter(VL53L0_DEV Dev,
+ int32_t OffsetCalibrationDataMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t cMaxOffsetMicroMeter = 511000;
+ int32_t cMinOffsetMicroMeter = -512000;
+ int16_t cOffsetRange = 4096;
+ uint32_t encodedOffsetVal;
+
+ LOG_FUNCTION_START("");
+
+ if (OffsetCalibrationDataMicroMeter > cMaxOffsetMicroMeter)
+ OffsetCalibrationDataMicroMeter = cMaxOffsetMicroMeter;
+ else if (OffsetCalibrationDataMicroMeter < cMinOffsetMicroMeter)
+ OffsetCalibrationDataMicroMeter = cMinOffsetMicroMeter;
+
+ /* The offset register is 10.2 format and units are mm
+ * therefore conversion is applied by a division of
+ * 250.
+ */
+ if (OffsetCalibrationDataMicroMeter >= 0) {
+ encodedOffsetVal =
+ OffsetCalibrationDataMicroMeter/250;
+ } else {
+ encodedOffsetVal =
+ cOffsetRange +
+ OffsetCalibrationDataMicroMeter/250;
+ }
+
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
+ encodedOffsetVal);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_offset_calibration_data_micro_meter(VL53L0_DEV Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint16_t RangeOffsetRegister;
+ int16_t cMaxOffset = 2047;
+ int16_t cOffsetRange = 4096;
+
+ /* Note that offset has 10.2 format */
+
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
+ &RangeOffsetRegister);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ RangeOffsetRegister = (RangeOffsetRegister & 0x0fff);
+
+ /* Apply 12 bit 2's compliment conversion */
+ if (RangeOffsetRegister > cMaxOffset)
+ *pOffsetCalibrationDataMicroMeter =
+ (int16_t)(RangeOffsetRegister - cOffsetRange)
+ * 250;
+ else
+ *pOffsetCalibrationDataMicroMeter =
+ (int16_t)RangeOffsetRegister * 250;
+
+ }
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_apply_offset_adjustment(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t CorrectedOffsetMicroMeters;
+ int32_t CurrentOffsetMicroMeters;
+
+ /* if we run on this function we can read all the NVM info
+ * used by the API
+ */
+ Status = VL53L0_get_info_from_device(Dev, 7);
+
+ /* Read back current device offset */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetOffsetCalibrationDataMicroMeter(Dev,
+ &CurrentOffsetMicroMeters);
+ }
+
+ /* Apply Offset Adjustment derived from 400mm measurements */
+ if (Status == VL53L0_ERROR_NONE) {
+
+ /* Store initial device offset */
+ PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter,
+ CurrentOffsetMicroMeters);
+
+ CorrectedOffsetMicroMeters = CurrentOffsetMicroMeters +
+ (int32_t)PALDevDataGet(Dev,
+ Part2PartOffsetAdjustmentNVMMicroMeter);
+
+ Status = VL53L0_SetOffsetCalibrationDataMicroMeter(Dev,
+ CorrectedOffsetMicroMeters);
+
+ /* store current, adjusted offset */
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
+ CorrectedOffsetMicroMeters);
+ }
+ }
+
+ return Status;
+}
+
+void get_next_good_spad(uint8_t goodSpadArray[], uint32_t size,
+ uint32_t curr, int32_t *next)
+{
+ uint32_t startIndex;
+ uint32_t fineOffset;
+ uint32_t cSpadsPerByte = 8;
+ uint32_t coarseIndex;
+ uint32_t fineIndex;
+ uint8_t dataByte;
+ uint8_t success = 0;
+
+ /*
+ * Starting with the current good spad, loop through the array to find
+ * the next. i.e. the next bit set in the sequence.
+ *
+ * The coarse index is the byte index of the array and the fine index is
+ * the index of the bit within each byte.
+ */
+
+ *next = -1;
+
+ startIndex = curr / cSpadsPerByte;
+ fineOffset = curr % cSpadsPerByte;
+
+ for (coarseIndex = startIndex; ((coarseIndex < size) && !success);
+ coarseIndex++) {
+ fineIndex = 0;
+ dataByte = goodSpadArray[coarseIndex];
+
+ if (coarseIndex == startIndex) {
+ /* locate the bit position of the provided current
+ * spad bit before iterating
+ */
+ dataByte >>= fineOffset;
+ fineIndex = fineOffset;
+ }
+
+ while (fineIndex < cSpadsPerByte) {
+ if ((dataByte & 0x1) == 1) {
+ success = 1;
+ *next = coarseIndex * cSpadsPerByte + fineIndex;
+ break;
+ }
+ dataByte >>= 1;
+ fineIndex++;
+ }
+ }
+}
+
+
+uint8_t is_aperture(uint32_t spadIndex)
+{
+ /*
+ * This function reports if a given spad index is an aperture SPAD by
+ * deriving the quadrant.
+ */
+ uint32_t quadrant;
+ uint8_t isAperture = 1;
+
+ quadrant = spadIndex >> 6;
+ if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0)
+ isAperture = 0;
+
+ return isAperture;
+}
+
+
+VL53L0_Error enable_spad_bit(uint8_t spadArray[], uint32_t size,
+ uint32_t spadIndex)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ uint32_t cSpadsPerByte = 8;
+ uint32_t coarseIndex;
+ uint32_t fineIndex;
+
+ coarseIndex = spadIndex / cSpadsPerByte;
+ fineIndex = spadIndex % cSpadsPerByte;
+ if (coarseIndex >= size)
+ status = VL53L0_ERROR_REF_SPAD_INIT;
+ else
+ spadArray[coarseIndex] |= (1 << fineIndex);
+
+ return status;
+}
+
+VL53L0_Error count_enabled_spads(uint8_t spadArray[],
+ uint32_t byteCount, uint32_t maxSpads,
+ uint32_t *pTotalSpadsEnabled, uint8_t *pIsAperture)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ uint32_t cSpadsPerByte = 8;
+ uint32_t lastByte;
+ uint32_t lastBit;
+ uint32_t byteIndex = 0;
+ uint32_t bitIndex = 0;
+ uint8_t tempByte;
+ uint8_t spadTypeIdentified = 0;
+
+ /* The entire array will not be used for spads, therefore the last
+ * byte and last bit is determined from the max spads value.
+ */
+
+ lastByte = maxSpads / cSpadsPerByte;
+ lastBit = maxSpads % cSpadsPerByte;
+
+ /* Check that the max spads value does not exceed the array bounds. */
+ if (lastByte >= byteCount)
+ status = VL53L0_ERROR_REF_SPAD_INIT;
+
+ *pTotalSpadsEnabled = 0;
+
+ /* Count the bits enabled in the whole bytes */
+ for (byteIndex = 0; byteIndex <= (lastByte - 1); byteIndex++) {
+ tempByte = spadArray[byteIndex];
+
+ for (bitIndex = 0; bitIndex <= cSpadsPerByte; bitIndex++) {
+ if ((tempByte & 0x01) == 1) {
+ (*pTotalSpadsEnabled)++;
+
+ if (!spadTypeIdentified) {
+ *pIsAperture = 1;
+ if ((byteIndex < 2) && (bitIndex < 4))
+ *pIsAperture = 0;
+ spadTypeIdentified = 1;
+ }
+ }
+ tempByte >>= 1;
+ }
+ }
+
+ /* Count the number of bits enabled in the last byte accounting
+ * for the fact that not all bits in the byte may be used.
+ */
+ tempByte = spadArray[lastByte];
+
+ for (bitIndex = 0; bitIndex <= lastBit; bitIndex++) {
+ if ((tempByte & 0x01) == 1)
+ (*pTotalSpadsEnabled)++;
+ }
+
+ return status;
+}
+
+VL53L0_Error set_ref_spad_map(VL53L0_DEV Dev, uint8_t *refSpadArray)
+{
+ VL53L0_Error status = VL53L0_WriteMulti(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
+ refSpadArray, 6);
+ return status;
+}
+
+VL53L0_Error get_ref_spad_map(VL53L0_DEV Dev, uint8_t *refSpadArray)
+{
+ VL53L0_Error status = VL53L0_ReadMulti(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
+ refSpadArray,
+ 6);
+ return status;
+}
+
+VL53L0_Error enable_ref_spads(VL53L0_DEV Dev,
+ uint8_t apertureSpads,
+ uint8_t goodSpadArray[],
+ uint8_t spadArray[],
+ uint32_t size,
+ uint32_t start,
+ uint32_t offset,
+ uint32_t spadCount,
+ uint32_t *lastSpad)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ uint32_t index;
+ uint32_t i;
+ int32_t nextGoodSpad = offset;
+ uint32_t currentSpad;
+ uint8_t checkSpadArray[6];
+
+ /*
+ * This function takes in a spad array which may or may not have SPADS
+ * already enabled and appends from a given offset a requested number
+ * of new SPAD enables. The 'good spad map' is applied to
+ * determine the next SPADs to enable.
+ *
+ * This function applies to only aperture or only non-aperture spads.
+ * Checks are performed to ensure this.
+ */
+
+ currentSpad = offset;
+ for (index = 0; index < spadCount; index++) {
+ get_next_good_spad(goodSpadArray, size, currentSpad,
+ &nextGoodSpad);
+
+ if (nextGoodSpad == -1) {
+ status = VL53L0_ERROR_REF_SPAD_INIT;
+ break;
+ }
+
+ /* Confirm that the next good SPAD is non-aperture */
+ if (is_aperture(start + nextGoodSpad) != apertureSpads) {
+ /* if we can't get the required number of good aperture
+ * spads from the current quadrant then this is an error
+ */
+ status = VL53L0_ERROR_REF_SPAD_INIT;
+ break;
+ }
+ currentSpad = (uint32_t)nextGoodSpad;
+ enable_spad_bit(spadArray, size, currentSpad);
+ currentSpad++;
+ }
+ *lastSpad = currentSpad;
+
+ if (status == VL53L0_ERROR_NONE)
+ status = set_ref_spad_map(Dev, spadArray);
+
+
+ if (status == VL53L0_ERROR_NONE) {
+ status = get_ref_spad_map(Dev, checkSpadArray);
+
+ i = 0;
+
+ /* Compare spad maps. If not equal report error. */
+ while (i < size) {
+ if (spadArray[i] != checkSpadArray[i]) {
+ status = VL53L0_ERROR_REF_SPAD_INIT;
+ break;
+ }
+ i++;
+ }
+ }
+ return status;
+}
+
+
+VL53L0_Error perform_ref_signal_measurement(VL53L0_DEV Dev,
+ uint16_t *refSignalRate)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ VL53L0_RangingMeasurementData_t rangingMeasurementData;
+
+ uint8_t SequenceConfig = 0;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /*
+ * This function performs a reference signal rate measurement.
+ */
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_WrByte(Dev,
+ VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_PerformSingleRangingMeasurement(Dev,
+ &rangingMeasurementData);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_RdWord(Dev,
+ VL53L0_REG_RESULT_PEAK_SIGNAL_RATE_REF,
+ refSignalRate);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (status == VL53L0_ERROR_NONE) {
+ /* restore the previous Sequence Config */
+ status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+ }
+
+ return status;
+}
+
+VL53L0_Error VL53L0_perform_ref_spad_management(VL53L0_DEV Dev,
+ uint32_t *refSpadCount,
+ uint8_t *isApertureSpads)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t lastSpadArray[6];
+ uint8_t startSelect = 0xB4;
+ uint32_t minimumSpadCount = 3;
+ uint32_t maxSpadCount = 44;
+ uint32_t currentSpadIndex = 0;
+ uint32_t lastSpadIndex = 0;
+ int32_t nextGoodSpad = 0;
+ uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */
+ uint16_t peakSignalRateRef;
+ uint32_t needAptSpads = 0;
+ uint32_t index = 0;
+ uint32_t spadArraySize = 6;
+ uint32_t signalRateDiff = 0;
+ uint32_t lastSignalRateDiff = 0;
+ uint8_t complete = 0;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+ uint32_t refSpadCount_int = 0;
+ uint8_t isApertureSpads_int = 0;
+
+ /*
+ * The reference SPAD initialization procedure determines the minimum
+ * amount of reference spads to be enables to achieve a target reference
+ * signal rate and should be performed once during initialization.
+ *
+ * Either aperture or non-aperture spads are applied but never both.
+ * Firstly non-aperture spads are set, begining with 5 spads, and
+ * increased one spad at a time until the closest measurement to the
+ * target rate is achieved.
+ *
+ * If the target rate is exceeded when 5 non-aperture spads are enabled,
+ * initialization is performed instead with aperture spads.
+ *
+ * When setting spads, a 'Good Spad Map' is applied.
+ *
+ * This procedure operates within a SPAD window of interest of a maximum
+ * 44 spads.
+ * The start point is currently fixed to 180, which lies towards the end
+ * of the non-aperture quadrant and runs in to the adjacent aperture
+ * quadrant.
+ */
+
+
+ targetRefRate = PALDevDataGet(Dev, targetRefRate);
+
+ /*
+ * Initialize Spad arrays.
+ * Currently the good spad map is initialised to 'All good'.
+ * This is a short term implementation. The good spad map will be
+ * provided as an input.
+ * Note that there are 6 bytes. Only the first 44 bits will be used to
+ * represent spads.
+ */
+ for (index = 0; index < spadArraySize; index++)
+ Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
+ startSelect);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0);
+
+ /* Perform ref calibration */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_perform_ref_calibration(Dev, &VhvSettings,
+ &PhaseCal, 0);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Enable Minimum NON-APERTURE Spads */
+ currentSpadIndex = 0;
+ lastSpadIndex = currentSpadIndex;
+ needAptSpads = 0;
+ Status = enable_ref_spads(Dev,
+ needAptSpads,
+ Dev->Data.SpadData.RefGoodSpadMap,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize,
+ startSelect,
+ currentSpadIndex,
+ minimumSpadCount,
+ &lastSpadIndex);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ currentSpadIndex = lastSpadIndex;
+
+ Status = perform_ref_signal_measurement(Dev,
+ &peakSignalRateRef);
+ if ((Status == VL53L0_ERROR_NONE) &&
+ (peakSignalRateRef > targetRefRate)) {
+ /* Signal rate measurement too high,
+ * switch to APERTURE SPADs
+ */
+
+ for (index = 0; index < spadArraySize; index++)
+ Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+
+ /* Increment to the first APERTURE spad */
+ while ((is_aperture(startSelect + currentSpadIndex)
+ == 0) && (currentSpadIndex < maxSpadCount)) {
+ currentSpadIndex++;
+ }
+
+ needAptSpads = 1;
+
+ Status = enable_ref_spads(Dev,
+ needAptSpads,
+ Dev->Data.SpadData.RefGoodSpadMap,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize,
+ startSelect,
+ currentSpadIndex,
+ minimumSpadCount,
+ &lastSpadIndex);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ currentSpadIndex = lastSpadIndex;
+ Status = perform_ref_signal_measurement(Dev,
+ &peakSignalRateRef);
+
+ if ((Status == VL53L0_ERROR_NONE) &&
+ (peakSignalRateRef > targetRefRate)) {
+ /* Signal rate still too high after
+ * setting the minimum number of
+ * APERTURE spads. Can do no more
+ * therefore set the min number of
+ * aperture spads as the result.
+ */
+ isApertureSpads_int = 1;
+ refSpadCount_int = minimumSpadCount;
+ }
+ }
+ } else {
+ needAptSpads = 0;
+ }
+ }
+
+ if ((Status == VL53L0_ERROR_NONE) &&
+ (peakSignalRateRef < targetRefRate)) {
+ /* At this point, the minimum number of either aperture
+ * or non-aperture spads have been set. Proceed to add
+ * spads and perform measurements until the target
+ * reference is reached.
+ */
+ isApertureSpads_int = needAptSpads;
+ refSpadCount_int = minimumSpadCount;
+
+ memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize);
+ lastSignalRateDiff = abs(peakSignalRateRef -
+ targetRefRate);
+ complete = 0;
+
+ while (!complete) {
+ get_next_good_spad(
+ Dev->Data.SpadData.RefGoodSpadMap,
+ spadArraySize, currentSpadIndex,
+ &nextGoodSpad);
+
+ if (nextGoodSpad == -1) {
+ Status = VL53L0_ERROR_REF_SPAD_INIT;
+ break;
+ }
+
+ (refSpadCount_int)++;
+
+ /* Cannot combine Aperture and Non-Aperture spads, so
+ * ensure the current spad is of the correct type.
+ */
+ if (is_aperture((uint32_t)startSelect + nextGoodSpad) !=
+ needAptSpads) {
+ Status = VL53L0_ERROR_REF_SPAD_INIT;
+ break;
+ }
+
+ currentSpadIndex = nextGoodSpad;
+ Status = enable_spad_bit(
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize, currentSpadIndex);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ currentSpadIndex++;
+ /* Proceed to apply the additional spad and
+ * perform measurement.
+ */
+ Status = set_ref_spad_map(Dev,
+ Dev->Data.SpadData.RefSpadEnables);
+ }
+
+ if (Status != VL53L0_ERROR_NONE)
+ break;
+
+ Status = perform_ref_signal_measurement(Dev,
+ &peakSignalRateRef);
+
+ if (Status != VL53L0_ERROR_NONE)
+ break;
+
+ signalRateDiff = abs(peakSignalRateRef - targetRefRate);
+
+ if (peakSignalRateRef > targetRefRate) {
+ /* Select the spad map that provides the
+ * measurement closest to the target rate,
+ * either above or below it.
+ */
+ if (signalRateDiff > lastSignalRateDiff) {
+ /* Previous spad map produced a closer
+ * measurement, so choose this.
+ */
+ Status = set_ref_spad_map(Dev,
+ lastSpadArray);
+ memcpy(
+ Dev->Data.SpadData.RefSpadEnables,
+ lastSpadArray, spadArraySize);
+
+ (refSpadCount_int)--;
+ }
+ complete = 1;
+ } else {
+ /* Continue to add spads */
+ lastSignalRateDiff = signalRateDiff;
+ memcpy(lastSpadArray,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize);
+ }
+
+ } /* while */
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ *refSpadCount = refSpadCount_int;
+ *isApertureSpads = isApertureSpads_int;
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount, (uint8_t)(*refSpadCount));
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, *isApertureSpads);
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_set_reference_spads(VL53L0_DEV Dev,
+ uint32_t count, uint8_t isApertureSpads)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint32_t currentSpadIndex = 0;
+ uint8_t startSelect = 0xB4;
+ uint32_t spadArraySize = 6;
+ uint32_t maxSpadCount = 44;
+ uint32_t lastSpadIndex;
+ uint32_t index;
+
+ /*
+ * This function applies a requested number of reference spads, either
+ * aperture or
+ * non-aperture, as requested.
+ * The good spad map will be applied.
+ */
+
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
+ startSelect);
+
+ for (index = 0; index < spadArraySize; index++)
+ Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+ if (isApertureSpads) {
+ /* Increment to the first APERTURE spad */
+ while ((is_aperture(startSelect + currentSpadIndex) == 0) &&
+ (currentSpadIndex < maxSpadCount)) {
+ currentSpadIndex++;
+ }
+ }
+ Status = enable_ref_spads(Dev,
+ isApertureSpads,
+ Dev->Data.SpadData.RefGoodSpadMap,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize,
+ startSelect,
+ currentSpadIndex,
+ count,
+ &lastSpadIndex);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount, (uint8_t)(count));
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, isApertureSpads);
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_reference_spads(VL53L0_DEV Dev,
+ uint32_t *pSpadCount, uint8_t *pIsApertureSpads)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t refSpadsInitialised;
+ uint8_t refSpadArray[6];
+ uint32_t cMaxSpadCount = 44;
+ uint32_t cSpadArraySize = 6;
+ uint32_t spadsEnabled;
+ uint8_t isApertureSpads = 0;
+
+ refSpadsInitialised = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ RefSpadsInitialised);
+
+ if (refSpadsInitialised == 1) {
+
+ *pSpadCount = (uint32_t)VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount);
+ *pIsApertureSpads = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType);
+ } else {
+
+ /* obtain spad info from device.*/
+ Status = get_ref_spad_map(Dev, refSpadArray);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* count enabled spads within spad map array and
+ * determine if Aperture or Non-Aperture.
+ */
+ Status = count_enabled_spads(refSpadArray,
+ cSpadArraySize,
+ cMaxSpadCount,
+ &spadsEnabled,
+ &isApertureSpads);
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ *pSpadCount = spadsEnabled;
+ *pIsApertureSpads = isApertureSpads;
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ RefSpadsInitialised, 1);
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount,
+ (uint8_t)spadsEnabled);
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, isApertureSpads);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_perform_single_ref_calibration(VL53L0_DEV Dev,
+ uint8_t vhv_init_byte)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSRANGE_START,
+ VL53L0_REG_SYSRANGE_MODE_START_STOP |
+ vhv_init_byte);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_measurement_poll_for_completion(Dev);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_ClearInterruptMask(Dev, 0);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSRANGE_START, 0x00);
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_ref_calibration_io(VL53L0_DEV Dev, uint8_t read_not_write,
+ uint8_t VhvSettings, uint8_t PhaseCal,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal,
+ const uint8_t vhv_enable, const uint8_t phase_enable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t PhaseCalint = 0;
+
+ /* Read VHV from device */
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (read_not_write) {
+ if (vhv_enable)
+ Status |= VL53L0_RdByte(Dev, 0xCB, pVhvSettings);
+ if (phase_enable)
+ Status |= VL53L0_RdByte(Dev, 0xEE, &PhaseCalint);
+ } else {
+ if (vhv_enable)
+ Status |= VL53L0_WrByte(Dev, 0xCB, VhvSettings);
+ if (phase_enable)
+ Status |= VL53L0_UpdateByte(Dev, 0xEE, 0x80, PhaseCal);
+ }
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ *pPhaseCal = (uint8_t)(PhaseCalint&0xEF);
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_perform_vhv_calibration(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, const uint8_t get_data_enable,
+ const uint8_t restore_config)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+ uint8_t PhaseCalInt = 0;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ if (restore_config)
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /* Run VHV */
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, 0x01);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_perform_single_ref_calibration(Dev, 0x40);
+
+ /* Read VHV from device */
+ if ((Status == VL53L0_ERROR_NONE) && (get_data_enable == 1)) {
+ Status = VL53L0_ref_calibration_io(Dev, 1,
+ VhvSettings, PhaseCal, /* Not used here */
+ pVhvSettings, &PhaseCalInt,
+ 1, 0);
+ } else
+ *pVhvSettings = 0;
+
+
+ if ((Status == VL53L0_ERROR_NONE) && restore_config) {
+ /* restore the previous Sequence Config */
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_perform_phase_calibration(VL53L0_DEV Dev,
+ uint8_t *pPhaseCal, const uint8_t get_data_enable,
+ const uint8_t restore_config)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+ uint8_t VhvSettingsint;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ if (restore_config)
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /* Run PhaseCal */
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG, 0x02);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_perform_single_ref_calibration(Dev, 0x0);
+
+ /* Read PhaseCal from device */
+ if ((Status == VL53L0_ERROR_NONE) && (get_data_enable == 1)) {
+ Status = VL53L0_ref_calibration_io(Dev, 1,
+ VhvSettings, PhaseCal, /* Not used here */
+ &VhvSettingsint, pPhaseCal,
+ 0, 1);
+ } else
+ *pPhaseCal = 0;
+
+
+ if ((Status == VL53L0_ERROR_NONE) && restore_config) {
+ /* restore the previous Sequence Config */
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_perform_ref_calibration(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /* In the following function we don't save the config to optimize
+ * writes on device. Config is saved and restored only once.
+ */
+ Status = VL53L0_perform_vhv_calibration(
+ Dev, pVhvSettings, get_data_enable, 0);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_perform_phase_calibration(
+ Dev, pPhaseCal, get_data_enable, 0);
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* restore the previous Sequence Config */
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_set_ref_calibration(VL53L0_DEV Dev,
+ uint8_t VhvSettings, uint8_t PhaseCal)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t pVhvSettings;
+ uint8_t pPhaseCal;
+
+ Status = VL53L0_ref_calibration_io(Dev, 0,
+ VhvSettings, PhaseCal,
+ &pVhvSettings, &pPhaseCal,
+ 1, 1);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_ref_calibration(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+
+ Status = VL53L0_ref_calibration_io(Dev, 1,
+ VhvSettings, PhaseCal,
+ pVhvSettings, pPhaseCal,
+ 1, 1);
+
+ return Status;
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_api_core.c b/drivers/input/misc/vl53L0/src/vl53l0_api_core.c
new file mode 100644
index 000000000000..a04d0c4f5915
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_api_core.c
@@ -0,0 +1,2270 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l0_api.h"
+#include "vl53l0_api_core.h"
+#include "vl53l0_api_calibration.h"
+
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+VL53L0_Error VL53L0_reverse_bytes(uint8_t *data, uint32_t size)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t tempData;
+ uint32_t mirrorIndex;
+ uint32_t middle = size/2;
+ uint32_t index;
+
+ for (index = 0; index < middle; index++) {
+ mirrorIndex = size - index - 1;
+ tempData = data[index];
+ data[index] = data[mirrorIndex];
+ data[mirrorIndex] = tempData;
+ }
+ return Status;
+}
+
+VL53L0_Error VL53L0_measurement_poll_for_completion(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t NewDataReady = 0;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ LoopNb = 0;
+
+ do {
+ Status = VL53L0_GetMeasurementDataReady(Dev, &NewDataReady);
+ if (Status != 0)
+ break; /* the error is set */
+
+ if (NewDataReady == 1)
+ break; /* done note that status == 0 */
+
+ LoopNb++;
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP) {
+ Status = VL53L0_ERROR_TIME_OUT;
+ break;
+ }
+
+ VL53L0_PollingDelay(Dev);
+ } while (1);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+uint8_t VL53L0_decode_vcsel_period(uint8_t vcsel_period_reg)
+{
+ /*!
+ * Converts the encoded VCSEL period register value into the real
+ * period in PLL clocks
+ */
+
+ uint8_t vcsel_period_pclks = 0;
+
+ vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
+
+ return vcsel_period_pclks;
+}
+
+uint8_t VL53L0_encode_vcsel_period(uint8_t vcsel_period_pclks)
+{
+ /*!
+ * Converts the encoded VCSEL period register value into the real period
+ * in PLL clocks
+ */
+
+ uint8_t vcsel_period_reg = 0;
+
+ vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
+
+ return vcsel_period_reg;
+}
+
+
+uint32_t VL53L0_isqrt(uint32_t num)
+{
+ /*
+ * Implements an integer square root
+ *
+ * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
+ */
+
+ uint32_t res = 0;
+ uint32_t bit = 1 << 30;
+ /* The second-to-top bit is set:
+ * 1 << 14 for 16-bits, 1 << 30 for 32 bits
+ */
+
+ /* "bit" starts at the highest power of four <= the argument. */
+ while (bit > num)
+ bit >>= 2;
+
+
+ while (bit != 0) {
+ if (num >= res + bit) {
+ num -= res + bit;
+ res = (res >> 1) + bit;
+ } else
+ res >>= 1;
+
+ bit >>= 2;
+ }
+
+ return res;
+}
+
+
+uint32_t VL53L0_quadrature_sum(uint32_t a, uint32_t b)
+{
+ /*
+ * Implements a quadrature sum
+ *
+ * rea = sqrt(a^2 + b^2)
+ *
+ * Trap overflow case max input value is 65535 (16-bit value)
+ * as internal calc are 32-bit wide
+ *
+ * If overflow then seta output to maximum
+ */
+ uint32_t res = 0;
+
+ if (a > 65535 || b > 65535)
+ res = 65535;
+ else
+ res = VL53L0_isqrt(a * a + b * b);
+
+ return res;
+}
+
+
+VL53L0_Error VL53L0_device_read_strobe(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t strobe;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ Status |= VL53L0_WrByte(Dev, 0x83, 0x00);
+
+ /* polling
+ * use timeout to avoid deadlock
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+ LoopNb = 0;
+ do {
+ Status = VL53L0_RdByte(Dev, 0x83, &strobe);
+ if ((strobe != 0x00) || Status != VL53L0_ERROR_NONE)
+ break;
+
+ LoopNb = LoopNb + 1;
+ } while (LoopNb < VL53L0_DEFAULT_MAX_LOOP);
+
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP)
+ Status = VL53L0_ERROR_TIME_OUT;
+
+ }
+
+ Status |= VL53L0_WrByte(Dev, 0x83, 0x01);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+VL53L0_Error VL53L0_get_info_from_device(VL53L0_DEV Dev, uint8_t option)
+{
+
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t byte;
+ uint32_t TmpDWord;
+ uint8_t ModuleId;
+ uint8_t Revision;
+ uint8_t ReferenceSpadCount = 0;
+ uint8_t ReferenceSpadType = 0;
+ uint32_t PartUIDUpper = 0;
+ uint32_t PartUIDLower = 0;
+ uint32_t OffsetFixed1104_mm = 0;
+ int16_t OffsetMicroMeters = 0;
+ uint32_t DistMeasTgtFixed1104_mm = 400 << 4;
+ uint32_t DistMeasFixed1104_400_mm = 0;
+ uint32_t SignalRateMeasFixed1104_400_mm = 0;
+ char ProductId[19];
+ char *ProductId_tmp;
+ uint8_t ReadDataFromDeviceDone;
+ FixPoint1616_t SignalRateMeasFixed400mmFix = 0;
+ uint8_t NvmRefGoodSpadMap[VL53L0_REF_SPAD_BUFFER_SIZE];
+ int i;
+
+
+ LOG_FUNCTION_START("");
+
+ ReadDataFromDeviceDone = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ ReadDataFromDeviceDone);
+
+ /* This access is done only once after that a GetDeviceInfo or
+ * datainit is done
+ */
+ if (ReadDataFromDeviceDone != 7) {
+
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x06);
+ Status |= VL53L0_RdByte(Dev, 0x83, &byte);
+ Status |= VL53L0_WrByte(Dev, 0x83, byte|4);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x07);
+ Status |= VL53L0_WrByte(Dev, 0x81, 0x01);
+
+ Status |= VL53L0_PollingDelay(Dev);
+
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x01);
+
+ if (((option & 1) == 1) &&
+ ((ReadDataFromDeviceDone & 1) == 0)) {
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x6b);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ReferenceSpadCount = (uint8_t)((TmpDWord >> 8) & 0x07f);
+ ReferenceSpadType = (uint8_t)((TmpDWord >> 15) & 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x24);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+
+ NvmRefGoodSpadMap[0] = (uint8_t)((TmpDWord >> 24)
+ & 0xff);
+ NvmRefGoodSpadMap[1] = (uint8_t)((TmpDWord >> 16)
+ & 0xff);
+ NvmRefGoodSpadMap[2] = (uint8_t)((TmpDWord >> 8)
+ & 0xff);
+ NvmRefGoodSpadMap[3] = (uint8_t)(TmpDWord & 0xff);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x25);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ NvmRefGoodSpadMap[4] = (uint8_t)((TmpDWord >> 24)
+ & 0xff);
+ NvmRefGoodSpadMap[5] = (uint8_t)((TmpDWord >> 16)
+ & 0xff);
+ }
+
+ if (((option & 2) == 2) &&
+ ((ReadDataFromDeviceDone & 2) == 0)) {
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x02);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdByte(Dev, 0x90, &ModuleId);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x7B);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdByte(Dev, 0x90, &Revision);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x77);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[0] = (char)((TmpDWord >> 25) & 0x07f);
+ ProductId[1] = (char)((TmpDWord >> 18) & 0x07f);
+ ProductId[2] = (char)((TmpDWord >> 11) & 0x07f);
+ ProductId[3] = (char)((TmpDWord >> 4) & 0x07f);
+
+ byte = (uint8_t)((TmpDWord & 0x00f) << 3);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x78);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[4] = (char)(byte +
+ ((TmpDWord >> 29) & 0x07f));
+ ProductId[5] = (char)((TmpDWord >> 22) & 0x07f);
+ ProductId[6] = (char)((TmpDWord >> 15) & 0x07f);
+ ProductId[7] = (char)((TmpDWord >> 8) & 0x07f);
+ ProductId[8] = (char)((TmpDWord >> 1) & 0x07f);
+
+ byte = (uint8_t)((TmpDWord & 0x001) << 6);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x79);
+
+ Status |= VL53L0_device_read_strobe(Dev);
+
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[9] = (char)(byte +
+ ((TmpDWord >> 26) & 0x07f));
+ ProductId[10] = (char)((TmpDWord >> 19) & 0x07f);
+ ProductId[11] = (char)((TmpDWord >> 12) & 0x07f);
+ ProductId[12] = (char)((TmpDWord >> 5) & 0x07f);
+
+ byte = (uint8_t)((TmpDWord & 0x01f) << 2);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x7A);
+
+ Status |= VL53L0_device_read_strobe(Dev);
+
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[13] = (char)(byte +
+ ((TmpDWord >> 30) & 0x07f));
+ ProductId[14] = (char)((TmpDWord >> 23) & 0x07f);
+ ProductId[15] = (char)((TmpDWord >> 16) & 0x07f);
+ ProductId[16] = (char)((TmpDWord >> 9) & 0x07f);
+ ProductId[17] = (char)((TmpDWord >> 2) & 0x07f);
+ ProductId[18] = '\0';
+
+ }
+
+ if (((option & 4) == 4) &&
+ ((ReadDataFromDeviceDone & 4) == 0)) {
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x7B);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &PartUIDUpper);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x7C);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &PartUIDLower);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x73);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ SignalRateMeasFixed1104_400_mm = (TmpDWord &
+ 0x0000000ff) << 8;
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x74);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ SignalRateMeasFixed1104_400_mm |= ((TmpDWord &
+ 0xff000000) >> 24);
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x75);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ DistMeasFixed1104_400_mm = (TmpDWord & 0x0000000ff)
+ << 8;
+
+ Status |= VL53L0_WrByte(Dev, 0x94, 0x76);
+ Status |= VL53L0_device_read_strobe(Dev);
+ Status |= VL53L0_RdDWord(Dev, 0x90, &TmpDWord);
+
+ DistMeasFixed1104_400_mm |= ((TmpDWord & 0xff000000)
+ >> 24);
+ }
+
+ Status |= VL53L0_WrByte(Dev, 0x81, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x06);
+ Status |= VL53L0_RdByte(Dev, 0x83, &byte);
+ Status |= VL53L0_WrByte(Dev, 0x83, byte&0xfb);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL53L0_WrByte(Dev, 0x00, 0x01);
+
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL53L0_WrByte(Dev, 0x80, 0x00);
+ }
+
+ if ((Status == VL53L0_ERROR_NONE) &&
+ (ReadDataFromDeviceDone != 7)) {
+ /* Assign to variable if status is ok */
+ if (((option & 1) == 1) &&
+ ((ReadDataFromDeviceDone & 1) == 0)) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount, ReferenceSpadCount);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, ReferenceSpadType);
+
+ for (i = 0; i < VL53L0_REF_SPAD_BUFFER_SIZE; i++) {
+ Dev->Data.SpadData.RefGoodSpadMap[i] =
+ NvmRefGoodSpadMap[i];
+ }
+ }
+
+ if (((option & 2) == 2) &&
+ ((ReadDataFromDeviceDone & 2) == 0)) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ ModuleId, ModuleId);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ Revision, Revision);
+
+ ProductId_tmp = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ ProductId);
+ VL53L0_COPYSTRING(ProductId_tmp, ProductId);
+
+ }
+
+ if (((option & 4) == 4) &&
+ ((ReadDataFromDeviceDone & 4) == 0)) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ PartUIDUpper, PartUIDUpper);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ PartUIDLower, PartUIDLower);
+
+ SignalRateMeasFixed400mmFix =
+ VL53L0_FIXPOINT97TOFIXPOINT1616(
+ SignalRateMeasFixed1104_400_mm);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ SignalRateMeasFixed400mm,
+ SignalRateMeasFixed400mmFix);
+
+ OffsetMicroMeters = 0;
+ if (DistMeasFixed1104_400_mm != 0) {
+ OffsetFixed1104_mm =
+ DistMeasFixed1104_400_mm -
+ DistMeasTgtFixed1104_mm;
+ OffsetMicroMeters = (OffsetFixed1104_mm
+ * 1000) >> 4;
+ OffsetMicroMeters *= -1;
+ }
+
+ PALDevDataSet(Dev,
+ Part2PartOffsetAdjustmentNVMMicroMeter,
+ OffsetMicroMeters);
+ }
+ byte = (uint8_t)(ReadDataFromDeviceDone|option);
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone,
+ byte);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+uint32_t VL53L0_calc_macro_period_ps(VL53L0_DEV Dev, uint8_t vcsel_period_pclks)
+{
+ uint64_t PLL_period_ps;
+ uint32_t macro_period_vclks;
+ uint32_t macro_period_ps;
+
+ LOG_FUNCTION_START("");
+
+ /* The above calculation will produce rounding errors,
+ * therefore set fixed value
+ */
+ PLL_period_ps = 1655;
+
+ macro_period_vclks = 2304;
+ macro_period_ps = (uint32_t)(macro_period_vclks
+ * vcsel_period_pclks * PLL_period_ps);
+
+ LOG_FUNCTION_END("");
+ return macro_period_ps;
+}
+
+uint16_t VL53L0_encode_timeout(uint32_t timeout_macro_clks)
+{
+ /*!
+ * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
+ */
+
+ uint16_t encoded_timeout = 0;
+ uint32_t ls_byte = 0;
+ uint16_t ms_byte = 0;
+
+ if (timeout_macro_clks > 0) {
+ ls_byte = timeout_macro_clks - 1;
+
+ while ((ls_byte & 0xFFFFFF00) > 0) {
+ ls_byte = ls_byte >> 1;
+ ms_byte++;
+ }
+
+ encoded_timeout = (ms_byte << 8)
+ + (uint16_t) (ls_byte & 0x000000FF);
+ }
+
+ return encoded_timeout;
+
+}
+
+uint32_t VL53L0_decode_timeout(uint16_t encoded_timeout)
+{
+ /*!
+ * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1
+ */
+
+ uint32_t timeout_macro_clks = 0;
+
+ timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF)
+ << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1;
+
+ return timeout_macro_clks;
+}
+
+
+/* To convert ms into register value */
+uint32_t VL53L0_calc_timeout_mclks(VL53L0_DEV Dev,
+ uint32_t timeout_period_us,
+ uint8_t vcsel_period_pclks)
+{
+ uint32_t macro_period_ps;
+ uint32_t macro_period_ns;
+ uint32_t timeout_period_mclks = 0;
+
+ macro_period_ps = VL53L0_calc_macro_period_ps(Dev, vcsel_period_pclks);
+ macro_period_ns = (macro_period_ps + 500) / 1000;
+
+ timeout_period_mclks =
+ (uint32_t) (((timeout_period_us * 1000)
+ + (macro_period_ns / 2)) / macro_period_ns);
+
+ return timeout_period_mclks;
+}
+
+/* To convert register value into us */
+uint32_t VL53L0_calc_timeout_us(VL53L0_DEV Dev,
+ uint16_t timeout_period_mclks,
+ uint8_t vcsel_period_pclks)
+{
+ uint32_t macro_period_ps;
+ uint32_t macro_period_ns;
+ uint32_t actual_timeout_period_us = 0;
+
+ macro_period_ps = VL53L0_calc_macro_period_ps(Dev, vcsel_period_pclks);
+ macro_period_ns = (macro_period_ps + 500) / 1000;
+
+ actual_timeout_period_us =
+ ((timeout_period_mclks * macro_period_ns)
+ + (macro_period_ns / 2)) / 1000;
+
+ return actual_timeout_period_us;
+}
+
+
+VL53L0_Error get_sequence_step_timeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ uint32_t *pTimeOutMicroSecs)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t CurrentVCSELPulsePeriodPClk;
+ uint8_t EncodedTimeOutByte = 0;
+ uint32_t TimeoutMicroSeconds = 0;
+ uint16_t PreRangeEncodedTimeOut = 0;
+ uint16_t MsrcTimeOutMClks;
+ uint16_t PreRangeTimeOutMClks;
+ uint16_t FinalRangeTimeOutMClks = 0;
+ uint16_t FinalRangeEncodedTimeOut;
+ VL53L0_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+
+ if ((SequenceStepId == VL53L0_SEQUENCESTEP_TCC) ||
+ (SequenceStepId == VL53L0_SEQUENCESTEP_DSS) ||
+ (SequenceStepId == VL53L0_SEQUENCESTEP_MSRC)) {
+
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_MSRC_CONFIG_TIMEOUT_MACROP,
+ &EncodedTimeOutByte);
+ }
+ MsrcTimeOutMClks = VL53L0_decode_timeout(EncodedTimeOutByte);
+
+ TimeoutMicroSeconds = VL53L0_calc_timeout_us(Dev,
+ MsrcTimeOutMClks,
+ CurrentVCSELPulsePeriodPClk);
+ } else if (SequenceStepId == VL53L0_SEQUENCESTEP_PRE_RANGE) {
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ /* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */
+ if (Status == VL53L0_ERROR_NONE) {
+
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ &PreRangeEncodedTimeOut);
+ }
+
+ PreRangeTimeOutMClks = VL53L0_decode_timeout(
+ PreRangeEncodedTimeOut);
+
+ TimeoutMicroSeconds = VL53L0_calc_timeout_us(Dev,
+ PreRangeTimeOutMClks,
+ CurrentVCSELPulsePeriodPClk);
+ }
+ } else if (SequenceStepId == VL53L0_SEQUENCESTEP_FINAL_RANGE) {
+
+ VL53L0_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+ PreRangeTimeOutMClks = 0;
+
+ if (SchedulerSequenceSteps.PreRangeOn) {
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ /* Retrieve PRE-RANGE Timeout in Macro periods
+ * (MCLKS)
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ &PreRangeEncodedTimeOut);
+ PreRangeTimeOutMClks = VL53L0_decode_timeout(
+ PreRangeEncodedTimeOut);
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Retrieve FINAL-RANGE VCSEL Period */
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_FINAL_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ }
+
+ /* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ &FinalRangeEncodedTimeOut);
+ FinalRangeTimeOutMClks = VL53L0_decode_timeout(
+ FinalRangeEncodedTimeOut);
+ }
+
+ FinalRangeTimeOutMClks -= PreRangeTimeOutMClks;
+ TimeoutMicroSeconds = VL53L0_calc_timeout_us(Dev,
+ FinalRangeTimeOutMClks,
+ CurrentVCSELPulsePeriodPClk);
+ }
+
+ *pTimeOutMicroSecs = TimeoutMicroSeconds;
+
+ return Status;
+}
+
+
+VL53L0_Error set_sequence_step_timeout(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ uint32_t TimeOutMicroSecs)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t CurrentVCSELPulsePeriodPClk;
+ uint8_t MsrcEncodedTimeOut;
+ uint16_t PreRangeEncodedTimeOut;
+ uint16_t PreRangeTimeOutMClks;
+ uint16_t MsrcRangeTimeOutMClks;
+ uint16_t FinalRangeTimeOutMClks;
+ uint16_t FinalRangeEncodedTimeOut;
+ VL53L0_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+
+ if ((SequenceStepId == VL53L0_SEQUENCESTEP_TCC) ||
+ (SequenceStepId == VL53L0_SEQUENCESTEP_DSS) ||
+ (SequenceStepId == VL53L0_SEQUENCESTEP_MSRC)) {
+
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ MsrcRangeTimeOutMClks = VL53L0_calc_timeout_mclks(Dev,
+ TimeOutMicroSecs,
+ (uint8_t)CurrentVCSELPulsePeriodPClk);
+
+ if (MsrcRangeTimeOutMClks > 256)
+ MsrcEncodedTimeOut = 255;
+ else
+ MsrcEncodedTimeOut =
+ (uint8_t)MsrcRangeTimeOutMClks - 1;
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ LastEncodedTimeout,
+ MsrcEncodedTimeOut);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_MSRC_CONFIG_TIMEOUT_MACROP,
+ MsrcEncodedTimeOut);
+ }
+ } else {
+
+ if (SequenceStepId == VL53L0_SEQUENCESTEP_PRE_RANGE) {
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ PreRangeTimeOutMClks =
+ VL53L0_calc_timeout_mclks(Dev,
+ TimeOutMicroSecs,
+ (uint8_t)CurrentVCSELPulsePeriodPClk);
+ PreRangeEncodedTimeOut = VL53L0_encode_timeout(
+ PreRangeTimeOutMClks);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(Dev,
+ LastEncodedTimeout,
+ PreRangeEncodedTimeOut);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrWord(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ PreRangeEncodedTimeOut);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ PreRangeTimeoutMicroSecs,
+ TimeOutMicroSecs);
+ }
+ } else if (SequenceStepId == VL53L0_SEQUENCESTEP_FINAL_RANGE) {
+
+ /* For the final range timeout, the pre-range timeout
+ * must be added. To do this both final and pre-range
+ * timeouts must be expressed in macro periods MClks
+ * because they have different vcsel periods.
+ */
+
+ VL53L0_GetSequenceStepEnables(Dev,
+ &SchedulerSequenceSteps);
+ PreRangeTimeOutMClks = 0;
+ if (SchedulerSequenceSteps.PreRangeOn) {
+
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ /* Retrieve PRE-RANGE Timeout in Macro periods
+ * (MCLKS)
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdWord(Dev, 0x51,
+ &PreRangeEncodedTimeOut);
+ PreRangeTimeOutMClks =
+ VL53L0_decode_timeout(
+ PreRangeEncodedTimeOut);
+ }
+ }
+
+ /* Calculate FINAL RANGE Timeout in Macro Periods
+ * (MCLKS) and add PRE-RANGE value
+ */
+ if (Status == VL53L0_ERROR_NONE) {
+
+ Status = VL53L0_GetVcselPulsePeriod(Dev,
+ VL53L0_VCSEL_PERIOD_FINAL_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ }
+ if (Status == VL53L0_ERROR_NONE) {
+
+ FinalRangeTimeOutMClks =
+ VL53L0_calc_timeout_mclks(Dev,
+ TimeOutMicroSecs,
+ (uint8_t) CurrentVCSELPulsePeriodPClk);
+
+ FinalRangeTimeOutMClks += PreRangeTimeOutMClks;
+
+ FinalRangeEncodedTimeOut =
+ VL53L0_encode_timeout(FinalRangeTimeOutMClks);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_WrWord(Dev, 0x71,
+ FinalRangeEncodedTimeOut);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ FinalRangeTimeoutMicroSecs,
+ TimeOutMicroSecs);
+ }
+ }
+ } else
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+ }
+ return Status;
+}
+
+VL53L0_Error VL53L0_set_vcsel_pulse_period(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t vcsel_period_reg;
+ uint8_t MinPreVcselPeriodPCLK = 12;
+ uint8_t MaxPreVcselPeriodPCLK = 18;
+ uint8_t MinFinalVcselPeriodPCLK = 8;
+ uint8_t MaxFinalVcselPeriodPCLK = 14;
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+ uint32_t FinalRangeTimeoutMicroSeconds;
+ uint32_t PreRangeTimeoutMicroSeconds;
+ uint32_t MsrcTimeoutMicroSeconds;
+ uint8_t PhaseCalInt = 0;
+
+ /* Check if valid clock period requested */
+
+ if ((VCSELPulsePeriodPCLK % 2) != 0) {
+ /* Value must be an even number */
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else if (VcselPeriodType == VL53L0_VCSEL_PERIOD_PRE_RANGE &&
+ (VCSELPulsePeriodPCLK < MinPreVcselPeriodPCLK ||
+ VCSELPulsePeriodPCLK > MaxPreVcselPeriodPCLK)) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ } else if (VcselPeriodType == VL53L0_VCSEL_PERIOD_FINAL_RANGE &&
+ (VCSELPulsePeriodPCLK < MinFinalVcselPeriodPCLK ||
+ VCSELPulsePeriodPCLK > MaxFinalVcselPeriodPCLK)) {
+
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+
+ /* Apply specific settings for the requested clock period */
+
+ if (Status != VL53L0_ERROR_NONE)
+ return Status;
+
+
+ if (VcselPeriodType == VL53L0_VCSEL_PERIOD_PRE_RANGE) {
+
+ /* Set phase check limits */
+ if (VCSELPulsePeriodPCLK == 12) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x18);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ } else if (VCSELPulsePeriodPCLK == 14) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x30);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ } else if (VCSELPulsePeriodPCLK == 16) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x40);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ } else if (VCSELPulsePeriodPCLK == 18) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x50);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ }
+ } else if (VcselPeriodType == VL53L0_VCSEL_PERIOD_FINAL_RANGE) {
+
+ if (VCSELPulsePeriodPCLK == 8) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x10);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_LIM,
+ 0x30);
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ } else if (VCSELPulsePeriodPCLK == 10) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x28);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_LIM,
+ 0x20);
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ } else if (VCSELPulsePeriodPCLK == 12) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x38);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_LIM,
+ 0x20);
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ } else if (VCSELPulsePeriodPCLK == 14) {
+
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x048);
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
+
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x01);
+ Status |= VL53L0_WrByte(Dev,
+ VL53L0_REG_ALGO_PHASECAL_LIM,
+ 0x20);
+ Status |= VL53L0_WrByte(Dev, 0xff, 0x00);
+ }
+ }
+
+
+ /* Re-calculate and apply timeouts, in macro periods */
+
+ if (Status == VL53L0_ERROR_NONE) {
+ vcsel_period_reg = VL53L0_encode_vcsel_period((uint8_t)
+ VCSELPulsePeriodPCLK);
+
+ /* When the VCSEL period for the pre or final range is changed,
+ * the corresponding timeout must be read from the device using
+ * the current VCSEL period, then the new VCSEL period can be
+ * applied. The timeout then must be written back to the device
+ * using the new VCSEL period.
+ *
+ * For the MSRC timeout, the same applies - this timeout being
+ * dependant on the pre-range vcsel period.
+ */
+ switch (VcselPeriodType) {
+ case VL53L0_VCSEL_PERIOD_PRE_RANGE:
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_PRE_RANGE,
+ &PreRangeTimeoutMicroSeconds);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_MSRC,
+ &MsrcTimeoutMicroSeconds);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
+ vcsel_period_reg);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = set_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_PRE_RANGE,
+ PreRangeTimeoutMicroSeconds);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = set_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_MSRC,
+ MsrcTimeoutMicroSeconds);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ PreRangeVcselPulsePeriod,
+ VCSELPulsePeriodPCLK);
+ break;
+ case VL53L0_VCSEL_PERIOD_FINAL_RANGE:
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_FINAL_RANGE,
+ &FinalRangeTimeoutMicroSeconds);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
+ vcsel_period_reg);
+
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = set_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_FINAL_RANGE,
+ FinalRangeTimeoutMicroSeconds);
+
+ VL53L0_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ FinalRangeVcselPulsePeriod,
+ VCSELPulsePeriodPCLK);
+ break;
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ /* Finally, the timing budget must be re-applied */
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_GETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+
+ Status = VL53L0_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+
+ /* Perform the phase calibration. This is needed after changing on
+ * vcsel period.
+ * get_data_enable = 0, restore_config = 1
+ */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_perform_phase_calibration(
+ Dev, &PhaseCalInt, 0, 1);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_vcsel_pulse_period(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t vcsel_period_reg;
+
+ switch (VcselPeriodType) {
+ case VL53L0_VCSEL_PERIOD_PRE_RANGE:
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ break;
+ case VL53L0_VCSEL_PERIOD_FINAL_RANGE:
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ break;
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ *pVCSELPulsePeriodPCLK =
+ VL53L0_decode_vcsel_period(vcsel_period_reg);
+
+ return Status;
+}
+
+
+
+VL53L0_Error VL53L0_set_measurement_timing_budget_micro_seconds(VL53L0_DEV Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint32_t FinalRangeTimingBudgetMicroSeconds;
+ VL53L0_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+ uint32_t MsrcDccTccTimeoutMicroSeconds = 2000;
+ uint32_t StartOverheadMicroSeconds = 1320;
+ uint32_t EndOverheadMicroSeconds = 960;
+ uint32_t MsrcOverheadMicroSeconds = 660;
+ uint32_t TccOverheadMicroSeconds = 590;
+ uint32_t DssOverheadMicroSeconds = 690;
+ uint32_t PreRangeOverheadMicroSeconds = 660;
+ uint32_t FinalRangeOverheadMicroSeconds = 550;
+ uint32_t PreRangeTimeoutMicroSeconds = 0;
+ uint32_t cMinTimingBudgetMicroSeconds = 20000;
+ uint32_t SubTimeout = 0;
+
+ LOG_FUNCTION_START("");
+
+ if (MeasurementTimingBudgetMicroSeconds
+ < cMinTimingBudgetMicroSeconds) {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ return Status;
+ }
+
+ FinalRangeTimingBudgetMicroSeconds =
+ MeasurementTimingBudgetMicroSeconds -
+ (StartOverheadMicroSeconds + EndOverheadMicroSeconds);
+
+ Status = VL53L0_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+
+ if (Status == VL53L0_ERROR_NONE &&
+ (SchedulerSequenceSteps.TccOn ||
+ SchedulerSequenceSteps.MsrcOn ||
+ SchedulerSequenceSteps.DssOn)) {
+
+ /* TCC, MSRC and DSS all share the same timeout */
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_MSRC,
+ &MsrcDccTccTimeoutMicroSeconds);
+
+ /* Subtract the TCC, MSRC and DSS timeouts if they are
+ * enabled.
+ */
+
+ if (Status != VL53L0_ERROR_NONE)
+ return Status;
+
+ /* TCC */
+ if (SchedulerSequenceSteps.TccOn) {
+
+ SubTimeout = MsrcDccTccTimeoutMicroSeconds
+ + TccOverheadMicroSeconds;
+
+ if (SubTimeout <
+ FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds -=
+ SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ if (Status != VL53L0_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+ /* DSS */
+ if (SchedulerSequenceSteps.DssOn) {
+
+ SubTimeout = 2 * (MsrcDccTccTimeoutMicroSeconds +
+ DssOverheadMicroSeconds);
+
+ if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds
+ -= SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ } else if (SchedulerSequenceSteps.MsrcOn) {
+ /* MSRC */
+ SubTimeout = MsrcDccTccTimeoutMicroSeconds +
+ MsrcOverheadMicroSeconds;
+
+ if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds
+ -= SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ }
+
+ if (Status != VL53L0_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+ if (SchedulerSequenceSteps.PreRangeOn) {
+
+ /* Subtract the Pre-range timeout if enabled. */
+
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_PRE_RANGE,
+ &PreRangeTimeoutMicroSeconds);
+
+ SubTimeout = PreRangeTimeoutMicroSeconds +
+ PreRangeOverheadMicroSeconds;
+
+ if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds -= SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+
+ if (Status == VL53L0_ERROR_NONE &&
+ SchedulerSequenceSteps.FinalRangeOn) {
+
+ FinalRangeTimingBudgetMicroSeconds -=
+ FinalRangeOverheadMicroSeconds;
+
+ /* Final Range Timeout
+ * Note that the final range timeout is determined by the timing
+ * budget and the sum of all other timeouts within the sequence.
+ * If there is no room for the final range timeout, then an error
+ * will be set. Otherwise the remaining time will be applied to
+ * the final range.
+ */
+ Status = set_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_FINAL_RANGE,
+ FinalRangeTimingBudgetMicroSeconds);
+
+ VL53L0_SETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_measurement_timing_budget_micro_seconds(VL53L0_DEV Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+ uint32_t FinalRangeTimeoutMicroSeconds;
+ uint32_t MsrcDccTccTimeoutMicroSeconds = 2000;
+ uint32_t StartOverheadMicroSeconds = 1910;
+ uint32_t EndOverheadMicroSeconds = 960;
+ uint32_t MsrcOverheadMicroSeconds = 660;
+ uint32_t TccOverheadMicroSeconds = 590;
+ uint32_t DssOverheadMicroSeconds = 690;
+ uint32_t PreRangeOverheadMicroSeconds = 660;
+ uint32_t FinalRangeOverheadMicroSeconds = 550;
+ uint32_t PreRangeTimeoutMicroSeconds = 0;
+
+ LOG_FUNCTION_START("");
+
+ /* Start and end overhead times always present */
+ *pMeasurementTimingBudgetMicroSeconds
+ = StartOverheadMicroSeconds + EndOverheadMicroSeconds;
+
+ Status = VL53L0_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+
+ if (Status != VL53L0_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+
+ if (SchedulerSequenceSteps.TccOn ||
+ SchedulerSequenceSteps.MsrcOn ||
+ SchedulerSequenceSteps.DssOn) {
+
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_MSRC,
+ &MsrcDccTccTimeoutMicroSeconds);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (SchedulerSequenceSteps.TccOn) {
+ *pMeasurementTimingBudgetMicroSeconds +=
+ MsrcDccTccTimeoutMicroSeconds +
+ TccOverheadMicroSeconds;
+ }
+
+ if (SchedulerSequenceSteps.DssOn) {
+ *pMeasurementTimingBudgetMicroSeconds +=
+ 2 * (MsrcDccTccTimeoutMicroSeconds +
+ DssOverheadMicroSeconds);
+ } else if (SchedulerSequenceSteps.MsrcOn) {
+ *pMeasurementTimingBudgetMicroSeconds +=
+ MsrcDccTccTimeoutMicroSeconds +
+ MsrcOverheadMicroSeconds;
+ }
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (SchedulerSequenceSteps.PreRangeOn) {
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_PRE_RANGE,
+ &PreRangeTimeoutMicroSeconds);
+ *pMeasurementTimingBudgetMicroSeconds +=
+ PreRangeTimeoutMicroSeconds +
+ PreRangeOverheadMicroSeconds;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (SchedulerSequenceSteps.FinalRangeOn) {
+ Status = get_sequence_step_timeout(Dev,
+ VL53L0_SEQUENCESTEP_FINAL_RANGE,
+ &FinalRangeTimeoutMicroSeconds);
+ *pMeasurementTimingBudgetMicroSeconds +=
+ (FinalRangeTimeoutMicroSeconds +
+ FinalRangeOverheadMicroSeconds);
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_SETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ *pMeasurementTimingBudgetMicroSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+
+VL53L0_Error VL53L0_load_tuning_settings(VL53L0_DEV Dev,
+ uint8_t *pTuningSettingBuffer)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int i;
+ int Index;
+ uint8_t msb;
+ uint8_t lsb;
+ uint8_t SelectParam;
+ uint8_t NumberOfWrites;
+ uint8_t Address;
+ uint8_t localBuffer[4]; /* max */
+ uint16_t Temp16;
+
+ LOG_FUNCTION_START("");
+
+ Index = 0;
+
+ while ((*(pTuningSettingBuffer + Index) != 0) &&
+ (Status == VL53L0_ERROR_NONE)) {
+ NumberOfWrites = *(pTuningSettingBuffer + Index);
+ Index++;
+ if (NumberOfWrites == 0xFF) {
+ /* internal parameters */
+ SelectParam = *(pTuningSettingBuffer + Index);
+ Index++;
+ switch (SelectParam) {
+ case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL53L0_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, SigmaEstRefArray, Temp16);
+ break;
+ case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL53L0_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, SigmaEstEffPulseWidth,
+ Temp16);
+ break;
+ case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL53L0_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, SigmaEstEffAmbWidth, Temp16);
+ break;
+ case 3: /* uint16_t targetRefRate -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL53L0_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, targetRefRate, Temp16);
+ break;
+ default: /* invalid parameter */
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+
+ } else if (NumberOfWrites <= 4) {
+ Address = *(pTuningSettingBuffer + Index);
+ Index++;
+
+ for (i = 0; i < NumberOfWrites; i++) {
+ localBuffer[i] = *(pTuningSettingBuffer +
+ Index);
+ Index++;
+ }
+
+ Status = VL53L0_WriteMulti(Dev, Address, localBuffer,
+ NumberOfWrites);
+
+ } else {
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_total_xtalk_rate(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ FixPoint1616_t *ptotal_xtalk_rate_mcps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ uint8_t xtalkCompEnable;
+ FixPoint1616_t totalXtalkMegaCps;
+ FixPoint1616_t xtalkPerSpadMegaCps;
+
+ *ptotal_xtalk_rate_mcps = 0;
+
+ Status = VL53L0_GetXTalkCompensationEnable(Dev, &xtalkCompEnable);
+ if (Status == VL53L0_ERROR_NONE) {
+
+ if (xtalkCompEnable) {
+
+ VL53L0_GETPARAMETERFIELD(
+ Dev,
+ XTalkCompensationRateMegaCps,
+ xtalkPerSpadMegaCps);
+
+ /* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */
+ totalXtalkMegaCps =
+ pRangingMeasurementData->EffectiveSpadRtnCount *
+ xtalkPerSpadMegaCps;
+
+ /* FixPoint0824 >> 8 = FixPoint1616 */
+ *ptotal_xtalk_rate_mcps =
+ (totalXtalkMegaCps + 0x80) >> 8;
+ }
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_total_signal_rate(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ FixPoint1616_t *ptotal_signal_rate_mcps)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ FixPoint1616_t totalXtalkMegaCps;
+
+ LOG_FUNCTION_START("");
+
+ *ptotal_signal_rate_mcps =
+ pRangingMeasurementData->SignalRateRtnMegaCps;
+
+ Status = VL53L0_get_total_xtalk_rate(
+ Dev, pRangingMeasurementData, &totalXtalkMegaCps);
+
+ if (Status == VL53L0_ERROR_NONE)
+ *ptotal_signal_rate_mcps += totalXtalkMegaCps;
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_calc_dmax(
+ VL53L0_DEV Dev,
+ FixPoint1616_t totalSignalRate_mcps,
+ FixPoint1616_t totalCorrSignalRate_mcps,
+ FixPoint1616_t pwMult,
+ uint32_t sigmaEstimateP1,
+ FixPoint1616_t sigmaEstimateP2,
+ uint32_t peakVcselDuration_us,
+ uint32_t *pdmax_mm)
+{
+ const uint32_t cSigmaLimit = 18;
+ const FixPoint1616_t cSignalLimit = 0x4000; /* 0.25 */
+ const FixPoint1616_t cSigmaEstRef = 0x00000042; /* 0.001 */
+ const uint32_t cAmbEffWidthSigmaEst_ns = 6;
+ const uint32_t cAmbEffWidthDMax_ns = 7;
+ uint32_t dmaxCalRange_mm;
+ FixPoint1616_t dmaxCalSignalRateRtn_mcps;
+ FixPoint1616_t minSignalNeeded;
+ FixPoint1616_t minSignalNeeded_p1;
+ FixPoint1616_t minSignalNeeded_p2;
+ FixPoint1616_t minSignalNeeded_p3;
+ FixPoint1616_t minSignalNeeded_p4;
+ FixPoint1616_t sigmaLimitTmp;
+ FixPoint1616_t sigmaEstSqTmp;
+ FixPoint1616_t signalLimitTmp;
+ FixPoint1616_t SignalAt0mm;
+ FixPoint1616_t dmaxDark;
+ FixPoint1616_t dmaxAmbient;
+ FixPoint1616_t dmaxDarkTmp;
+ FixPoint1616_t sigmaEstP2Tmp;
+ uint32_t signalRateTemp_mcps;
+
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ dmaxCalRange_mm =
+ PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
+
+ dmaxCalSignalRateRtn_mcps =
+ PALDevDataGet(Dev, DmaxCalSignalRateRtnMegaCps);
+
+ /* uint32 * FixPoint1616 = FixPoint1616 */
+ SignalAt0mm = dmaxCalRange_mm * dmaxCalSignalRateRtn_mcps;
+
+ /* FixPoint1616 >> 8 = FixPoint2408 */
+ SignalAt0mm = (SignalAt0mm + 0x80) >> 8;
+ SignalAt0mm *= dmaxCalRange_mm;
+
+ minSignalNeeded_p1 = 0;
+ if (totalCorrSignalRate_mcps > 0) {
+
+ /* Shift by 10 bits to increase resolution prior to the
+ * division
+ */
+ signalRateTemp_mcps = totalSignalRate_mcps << 10;
+
+ /* Add rounding value prior to division */
+ minSignalNeeded_p1 = signalRateTemp_mcps +
+ (totalCorrSignalRate_mcps/2);
+
+ /* FixPoint0626/FixPoint1616 = FixPoint2210 */
+ minSignalNeeded_p1 /= totalCorrSignalRate_mcps;
+
+ /* Apply a factored version of the speed of light.
+ * Correction to be applied at the end
+ */
+ minSignalNeeded_p1 *= 3;
+
+ /* FixPoint2210 * FixPoint2210 = FixPoint1220 */
+ minSignalNeeded_p1 *= minSignalNeeded_p1;
+
+ /* FixPoint1220 >> 16 = FixPoint2804 */
+ minSignalNeeded_p1 = (minSignalNeeded_p1 + 0x8000) >> 16;
+ }
+
+ minSignalNeeded_p2 = pwMult * sigmaEstimateP1;
+
+ /* FixPoint1616 >> 16 = uint32 */
+ minSignalNeeded_p2 = (minSignalNeeded_p2 + 0x8000) >> 16;
+
+ /* uint32 * uint32 = uint32 */
+ minSignalNeeded_p2 *= minSignalNeeded_p2;
+
+ /* Check sigmaEstimateP2
+ * If this value is too high there is not enough signal rate
+ * to calculate dmax value so set a suitable value to ensure
+ * a very small dmax.
+ */
+ sigmaEstP2Tmp = (sigmaEstimateP2 + 0x8000) >> 16;
+ sigmaEstP2Tmp = (sigmaEstP2Tmp + cAmbEffWidthSigmaEst_ns/2)/
+ cAmbEffWidthSigmaEst_ns;
+ sigmaEstP2Tmp *= cAmbEffWidthDMax_ns;
+
+ if (sigmaEstP2Tmp > 0xffff) {
+ minSignalNeeded_p3 = 0xfff00000;
+ } else {
+
+ /* DMAX uses a different ambient width from sigma, so apply
+ * correction.
+ * Perform division before multiplication to prevent overflow.
+ */
+ sigmaEstimateP2 = (sigmaEstimateP2 + cAmbEffWidthSigmaEst_ns/2)/
+ cAmbEffWidthSigmaEst_ns;
+ sigmaEstimateP2 *= cAmbEffWidthDMax_ns;
+
+ /* FixPoint1616 >> 16 = uint32 */
+ minSignalNeeded_p3 = (sigmaEstimateP2 + 0x8000) >> 16;
+
+ minSignalNeeded_p3 *= minSignalNeeded_p3;
+
+ }
+
+ /* FixPoint1814 / uint32 = FixPoint1814 */
+ sigmaLimitTmp = ((cSigmaLimit << 14) + 500) / 1000;
+
+ /* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */
+ sigmaLimitTmp *= sigmaLimitTmp;
+
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sigmaEstSqTmp = cSigmaEstRef * cSigmaEstRef;
+
+ /* FixPoint3232 >> 4 = FixPoint0428 */
+ sigmaEstSqTmp = (sigmaEstSqTmp + 0x08) >> 4;
+
+ /* FixPoint0428 - FixPoint0428 = FixPoint0428 */
+ sigmaLimitTmp -= sigmaEstSqTmp;
+
+ /* uint32_t * FixPoint0428 = FixPoint0428 */
+ minSignalNeeded_p4 = 4 * 12 * sigmaLimitTmp;
+
+ /* FixPoint0428 >> 14 = FixPoint1814 */
+ minSignalNeeded_p4 = (minSignalNeeded_p4 + 0x2000) >> 14;
+
+ /* uint32 + uint32 = uint32 */
+ minSignalNeeded = (minSignalNeeded_p2 + minSignalNeeded_p3);
+
+ /* uint32 / uint32 = uint32 */
+ minSignalNeeded += (peakVcselDuration_us/2);
+ minSignalNeeded /= peakVcselDuration_us;
+
+ /* uint32 << 14 = FixPoint1814 */
+ minSignalNeeded <<= 14;
+
+ /* FixPoint1814 / FixPoint1814 = uint32 */
+ minSignalNeeded += (minSignalNeeded_p4/2);
+ minSignalNeeded /= minSignalNeeded_p4;
+
+ /* FixPoint3200 * FixPoint2804 := FixPoint2804*/
+ minSignalNeeded *= minSignalNeeded_p1;
+
+ /* Apply correction by dividing by 1000000.
+ * This assumes 10E16 on the numerator of the equation
+ * and 10E-22 on the denominator.
+ * We do this because 32bit fix point calculation can't
+ * handle the larger and smaller elements of this equation,
+ * i.e. speed of light and pulse widths.
+ */
+ minSignalNeeded = (minSignalNeeded + 500) / 1000;
+ minSignalNeeded <<= 4;
+
+ minSignalNeeded = (minSignalNeeded + 500) / 1000;
+
+ /* FixPoint1616 >> 8 = FixPoint2408 */
+ signalLimitTmp = (cSignalLimit + 0x80) >> 8;
+
+ /* FixPoint2408/FixPoint2408 = uint32 */
+ if (signalLimitTmp != 0)
+ dmaxDarkTmp = (SignalAt0mm + (signalLimitTmp / 2))
+ / signalLimitTmp;
+ else
+ dmaxDarkTmp = 0;
+
+ dmaxDark = VL53L0_isqrt(dmaxDarkTmp);
+
+ /* FixPoint2408/FixPoint2408 = uint32 */
+ if (minSignalNeeded != 0)
+ dmaxAmbient = (SignalAt0mm + minSignalNeeded/2)
+ / minSignalNeeded;
+ else
+ dmaxAmbient = 0;
+
+ dmaxAmbient = VL53L0_isqrt(dmaxAmbient);
+
+ *pdmax_mm = dmaxDark;
+ if (dmaxDark > dmaxAmbient)
+ *pdmax_mm = dmaxAmbient;
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_calc_sigma_estimate(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ FixPoint1616_t *pSigmaEstimate,
+ uint32_t *pDmax_mm)
+{
+ /* Expressed in 100ths of a ns, i.e. centi-ns */
+ const uint32_t cPulseEffectiveWidth_centi_ns = 800;
+ /* Expressed in 100ths of a ns, i.e. centi-ns */
+ const uint32_t cAmbientEffectiveWidth_centi_ns = 600;
+ const FixPoint1616_t cSigmaEstRef = 0x00000042; /* 0.001 */
+ const uint32_t cVcselPulseWidth_ps = 4700; /* pico secs */
+ const FixPoint1616_t cSigmaEstMax = 0x028F87AE;
+ const FixPoint1616_t cSigmaEstRtnMax = 0xF000;
+ const FixPoint1616_t cAmbToSignalRatioMax = 0xF0000000/
+ cAmbientEffectiveWidth_centi_ns;
+ /* Time Of Flight per mm (6.6 pico secs) */
+ const FixPoint1616_t cTOF_per_mm_ps = 0x0006999A;
+ const uint32_t c16BitRoundingParam = 0x00008000;
+ const FixPoint1616_t cMaxXTalk_kcps = 0x00320000;
+ const uint32_t cPllPeriod_ps = 1655;
+
+ uint32_t vcselTotalEventsRtn;
+ uint32_t finalRangeTimeoutMicroSecs;
+ uint32_t preRangeTimeoutMicroSecs;
+ FixPoint1616_t sigmaEstimateP1;
+ FixPoint1616_t sigmaEstimateP2;
+ FixPoint1616_t sigmaEstimateP3;
+ FixPoint1616_t deltaT_ps;
+ FixPoint1616_t pwMult;
+ FixPoint1616_t sigmaEstRtn;
+ FixPoint1616_t sigmaEstimate;
+ FixPoint1616_t xTalkCorrection;
+ FixPoint1616_t ambientRate_kcps;
+ FixPoint1616_t peakSignalRate_kcps;
+ FixPoint1616_t xTalkCompRate_mcps;
+ uint32_t xTalkCompRate_kcps;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ FixPoint1616_t diff1_mcps;
+ FixPoint1616_t diff2_mcps;
+ FixPoint1616_t sqr1;
+ FixPoint1616_t sqr2;
+ FixPoint1616_t sqrSum;
+ FixPoint1616_t sqrtResult_centi_ns;
+ FixPoint1616_t sqrtResult;
+ FixPoint1616_t totalSignalRate_mcps;
+ FixPoint1616_t correctedSignalRate_mcps;
+ uint32_t vcselWidth;
+ uint32_t finalRangeMacroPCLKS;
+ uint32_t preRangeMacroPCLKS;
+ uint32_t peakVcselDuration_us;
+ uint8_t finalRangeVcselPCLKS;
+ uint8_t preRangeVcselPCLKS;
+ /*! \addtogroup calc_sigma_estimate
+ * @{
+ *
+ * Estimates the range sigma based on the
+ *
+ * - vcsel_rate_kcps
+ * - ambient_rate_kcps
+ * - signal_total_events
+ * - xtalk_rate
+ *
+ * and the following parameters
+ *
+ * - SigmaEstRefArray
+ * - SigmaEstEffPulseWidth
+ * - SigmaEstEffAmbWidth
+ */
+
+ LOG_FUNCTION_START("");
+
+ VL53L0_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ xTalkCompRate_mcps);
+
+ /*
+ * We work in kcps rather than mcps as this helps keep within the
+ * confines of the 32 Fix1616 type.
+ */
+
+ ambientRate_kcps =
+ (pRangingMeasurementData->AmbientRateRtnMegaCps * 1000) >> 16;
+
+ correctedSignalRate_mcps =
+ pRangingMeasurementData->SignalRateRtnMegaCps;
+
+
+ Status = VL53L0_get_total_signal_rate(
+ Dev, pRangingMeasurementData, &totalSignalRate_mcps);
+ Status = VL53L0_get_total_xtalk_rate(
+ Dev, pRangingMeasurementData, &xTalkCompRate_mcps);
+
+
+ /* Signal rate measurement provided by device is the
+ * peak signal rate, not average.
+ */
+ peakSignalRate_kcps = (totalSignalRate_mcps * 1000);
+ peakSignalRate_kcps = (peakSignalRate_kcps + 0x8000) >> 16;
+
+ xTalkCompRate_kcps = xTalkCompRate_mcps * 1000;
+
+ if (xTalkCompRate_kcps > cMaxXTalk_kcps)
+ xTalkCompRate_kcps = cMaxXTalk_kcps;
+
+ if (Status == VL53L0_ERROR_NONE) {
+
+ /* Calculate final range macro periods */
+ finalRangeTimeoutMicroSecs = VL53L0_GETDEVICESPECIFICPARAMETER(
+ Dev, FinalRangeTimeoutMicroSecs);
+
+ finalRangeVcselPCLKS = VL53L0_GETDEVICESPECIFICPARAMETER(
+ Dev, FinalRangeVcselPulsePeriod);
+
+ finalRangeMacroPCLKS = VL53L0_calc_timeout_mclks(
+ Dev, finalRangeTimeoutMicroSecs, finalRangeVcselPCLKS);
+
+ /* Calculate pre-range macro periods */
+ preRangeTimeoutMicroSecs = VL53L0_GETDEVICESPECIFICPARAMETER(
+ Dev, PreRangeTimeoutMicroSecs);
+
+ preRangeVcselPCLKS = VL53L0_GETDEVICESPECIFICPARAMETER(
+ Dev, PreRangeVcselPulsePeriod);
+
+ preRangeMacroPCLKS = VL53L0_calc_timeout_mclks(
+ Dev, preRangeTimeoutMicroSecs, preRangeVcselPCLKS);
+
+ vcselWidth = 3;
+ if (finalRangeVcselPCLKS == 8)
+ vcselWidth = 2;
+
+
+ peakVcselDuration_us = vcselWidth * 2048 *
+ (preRangeMacroPCLKS + finalRangeMacroPCLKS);
+ peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
+ peakVcselDuration_us *= cPllPeriod_ps;
+ peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
+
+ /* Fix1616 >> 8 = Fix2408 */
+ totalSignalRate_mcps = (totalSignalRate_mcps + 0x80) >> 8;
+
+ /* Fix2408 * uint32 = Fix2408 */
+ vcselTotalEventsRtn = totalSignalRate_mcps *
+ peakVcselDuration_us;
+
+ /* Fix2408 >> 8 = uint32 */
+ vcselTotalEventsRtn = (vcselTotalEventsRtn + 0x80) >> 8;
+
+ /* Fix2408 << 8 = Fix1616 = */
+ totalSignalRate_mcps <<= 8;
+ }
+
+ if (Status != VL53L0_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+ if (peakSignalRate_kcps == 0) {
+ *pSigmaEstimate = cSigmaEstMax;
+ PALDevDataSet(Dev, SigmaEstimate, cSigmaEstMax);
+ *pDmax_mm = 0;
+ } else {
+ if (vcselTotalEventsRtn < 1)
+ vcselTotalEventsRtn = 1;
+
+ /*
+ * Calculate individual components of the main equation -
+ * replicating the equation implemented in the script
+ * OpenAll_Ewok_ranging_data.jsl.
+ *
+ * sigmaEstimateP1 represents the effective pulse width, which
+ * is a tuning parameter, rather than a real value.
+ *
+ * sigmaEstimateP2 represents the ambient/signal rate ratio
+ * expressed as a multiple of the effective ambient width
+ * (tuning parameter).
+ *
+ * sigmaEstimateP3 provides the signal event component, with the
+ * knowledge that
+ * - Noise of a square pulse is 1/sqrt(12) of the pulse
+ * width.
+ * - at 0Lux, sigma is proportional to
+ * effectiveVcselPulseWidth/sqrt(12 * signalTotalEvents)
+ *
+ * deltaT_ps represents the time of flight in pico secs for the
+ * current range measurement, using the "TOF per mm" constant
+ * (in ps).
+ */
+
+ sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns;
+
+ /* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */
+ sigmaEstimateP2 = (ambientRate_kcps << 16)/peakSignalRate_kcps;
+ if (sigmaEstimateP2 > cAmbToSignalRatioMax) {
+ /* Clip to prevent overflow. Will ensure safe
+ * max result.
+ */
+ sigmaEstimateP2 = cAmbToSignalRatioMax;
+ }
+ sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns;
+
+ sigmaEstimateP3 = 2 * VL53L0_isqrt(vcselTotalEventsRtn * 12);
+
+ /* uint32 * FixPoint1616 = FixPoint1616 */
+ deltaT_ps = pRangingMeasurementData->RangeMilliMeter *
+ cTOF_per_mm_ps;
+
+ /*
+ * vcselRate - xtalkCompRate
+ * (uint32 << 16) - FixPoint1616 = FixPoint1616.
+ * Divide result by 1000 to convert to mcps.
+ * 500 is added to ensure rounding when integer division
+ * truncates.
+ */
+ diff1_mcps = (((peakSignalRate_kcps << 16) -
+ xTalkCompRate_kcps) + 500)/1000;
+
+ /* vcselRate + xtalkCompRate */
+ diff2_mcps = (((peakSignalRate_kcps << 16) +
+ xTalkCompRate_kcps) + 500)/1000;
+
+ /* Shift by 8 bits to increase resolution prior to the
+ * division
+ */
+ diff1_mcps <<= 8;
+
+ /* FixPoint0824/FixPoint1616 = FixPoint2408 */
+ xTalkCorrection = abs(diff1_mcps/diff2_mcps);
+
+ /* FixPoint2408 << 8 = FixPoint1616 */
+ xTalkCorrection <<= 8;
+
+ /* FixPoint1616/uint32 = FixPoint1616 */
+ pwMult = deltaT_ps/cVcselPulseWidth_ps; /* smaller than 1.0f */
+
+ /*
+ * FixPoint1616 * FixPoint1616 = FixPoint3232, however both
+ * values are small enough such that32 bits will not be
+ * exceeded.
+ */
+ pwMult *= ((1 << 16) - xTalkCorrection);
+
+ /* (FixPoint3232 >> 16) = FixPoint1616 */
+ pwMult = (pwMult + c16BitRoundingParam) >> 16;
+
+ /* FixPoint1616 + FixPoint1616 = FixPoint1616 */
+ pwMult += (1 << 16);
+
+ /*
+ * At this point the value will be 1.xx, therefore if we square
+ * the value this will exceed 32 bits. To address this perform
+ * a single shift to the right before the multiplication.
+ */
+ pwMult >>= 1;
+ /* FixPoint1715 * FixPoint1715 = FixPoint3430 */
+ pwMult = pwMult * pwMult;
+
+ /* (FixPoint3430 >> 14) = Fix1616 */
+ pwMult >>= 14;
+
+ /* FixPoint1616 * uint32 = FixPoint1616 */
+ sqr1 = pwMult * sigmaEstimateP1;
+
+ /* (FixPoint1616 >> 16) = FixPoint3200 */
+ sqr1 = (sqr1 + 0x8000) >> 16;
+
+ /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
+ sqr1 *= sqr1;
+
+ sqr2 = sigmaEstimateP2;
+
+ /* (FixPoint1616 >> 16) = FixPoint3200 */
+ sqr2 = (sqr2 + 0x8000) >> 16;
+
+ /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
+ sqr2 *= sqr2;
+
+ /* FixPoint64000 + FixPoint6400 = FixPoint6400 */
+ sqrSum = sqr1 + sqr2;
+
+ /* SQRT(FixPoin6400) = FixPoint3200 */
+ sqrtResult_centi_ns = VL53L0_isqrt(sqrSum);
+
+ /* (FixPoint3200 << 16) = FixPoint1616 */
+ sqrtResult_centi_ns <<= 16;
+
+ /*
+ * Note that the Speed Of Light is expressed in um per 1E-10
+ * seconds (2997) Therefore to get mm/ns we have to divide by
+ * 10000
+ */
+ sigmaEstRtn = (((sqrtResult_centi_ns+50)/100) /
+ sigmaEstimateP3);
+ sigmaEstRtn *= VL53L0_SPEED_OF_LIGHT_IN_AIR;
+
+ /* Add 5000 before dividing by 10000 to ensure rounding. */
+ sigmaEstRtn += 5000;
+ sigmaEstRtn /= 10000;
+
+ if (sigmaEstRtn > cSigmaEstRtnMax) {
+ /* Clip to prevent overflow. Will ensure safe
+ * max result.
+ */
+ sigmaEstRtn = cSigmaEstRtnMax;
+ }
+
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sqr1 = sigmaEstRtn * sigmaEstRtn;
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sqr2 = cSigmaEstRef * cSigmaEstRef;
+
+ /* sqrt(FixPoint3232) = FixPoint1616 */
+ sqrtResult = VL53L0_isqrt((sqr1 + sqr2));
+ /*
+ * Note that the Shift by 4 bits increases resolution prior to
+ * the sqrt, therefore the result must be shifted by 2 bits to
+ * the right to revert back to the FixPoint1616 format.
+ */
+
+ sigmaEstimate = 1000 * sqrtResult;
+
+ if ((peakSignalRate_kcps < 1) || (vcselTotalEventsRtn < 1) ||
+ (sigmaEstimate > cSigmaEstMax)) {
+ sigmaEstimate = cSigmaEstMax;
+ }
+
+ *pSigmaEstimate = (uint32_t)(sigmaEstimate);
+ PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate);
+ Status = VL53L0_calc_dmax(
+ Dev,
+ totalSignalRate_mcps,
+ correctedSignalRate_mcps,
+ pwMult,
+ sigmaEstimateP1,
+ sigmaEstimateP2,
+ peakVcselDuration_us,
+ pDmax_mm);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_pal_range_status(VL53L0_DEV Dev,
+ uint8_t DeviceRangeStatus,
+ FixPoint1616_t SignalRate,
+ uint16_t EffectiveSpadRtnCount,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData,
+ uint8_t *pPalRangeStatus)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t NoneFlag;
+ uint8_t SigmaLimitflag = 0;
+ uint8_t SignalRefClipflag = 0;
+ uint8_t RangeIgnoreThresholdflag = 0;
+ uint8_t SigmaLimitCheckEnable = 0;
+ uint8_t SignalRateFinalRangeLimitCheckEnable = 0;
+ uint8_t SignalRefClipLimitCheckEnable = 0;
+ uint8_t RangeIgnoreThresholdLimitCheckEnable = 0;
+ FixPoint1616_t SigmaEstimate;
+ FixPoint1616_t SigmaLimitValue;
+ FixPoint1616_t SignalRefClipValue;
+ FixPoint1616_t RangeIgnoreThresholdValue;
+ FixPoint1616_t SignalRatePerSpad;
+ uint8_t DeviceRangeStatusInternal = 0;
+ uint16_t tmpWord = 0;
+ uint8_t Temp8;
+ uint32_t Dmax_mm = 0;
+ FixPoint1616_t LastSignalRefMcps;
+
+ LOG_FUNCTION_START("");
+
+
+ /*
+ * VL53L0 has a good ranging when the value of the
+ * DeviceRangeStatus = 11. This function will replace the value 0 with
+ * the value 11 in the DeviceRangeStatus.
+ * In addition, the SigmaEstimator is not included in the VL53L0
+ * DeviceRangeStatus, this will be added in the PalRangeStatus.
+ */
+
+ DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3);
+
+ if (DeviceRangeStatusInternal == 0 ||
+ DeviceRangeStatusInternal == 5 ||
+ DeviceRangeStatusInternal == 7 ||
+ DeviceRangeStatusInternal == 12 ||
+ DeviceRangeStatusInternal == 13 ||
+ DeviceRangeStatusInternal == 14 ||
+ DeviceRangeStatusInternal == 15
+ ) {
+ NoneFlag = 1;
+ } else {
+ NoneFlag = 0;
+ }
+
+ /* LastSignalRefMcps */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_RdWord(Dev,
+ VL53L0_REG_RESULT_PEAK_SIGNAL_RATE_REF,
+ &tmpWord);
+
+ LastSignalRefMcps = VL53L0_FIXPOINT97TOFIXPOINT1616(tmpWord);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ PALDevDataSet(Dev, LastSignalRefMcps, LastSignalRefMcps);
+
+ /*
+ * Check if Sigma limit is enabled, if yes then do comparison with limit
+ * value and put the result back into pPalRangeStatus.
+ */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &SigmaLimitCheckEnable);
+
+ if ((SigmaLimitCheckEnable != 0) && (Status == VL53L0_ERROR_NONE)) {
+ /*
+ * compute the Sigma and check with limit
+ */
+ Status = VL53L0_calc_sigma_estimate(
+ Dev,
+ pRangingMeasurementData,
+ &SigmaEstimate,
+ &Dmax_mm);
+ if (Status == VL53L0_ERROR_NONE)
+ pRangingMeasurementData->RangeDMaxMilliMeter = Dmax_mm;
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_GetLimitCheckValue(Dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &SigmaLimitValue);
+
+ if ((SigmaLimitValue > 0) &&
+ (SigmaEstimate > SigmaLimitValue))
+ /* Limit Fail */
+ SigmaLimitflag = 1;
+ }
+ }
+
+ /*
+ * Check if Signal ref clip limit is enabled, if yes then do comparison
+ * with limit value and put the result back into pPalRangeStatus.
+ */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP,
+ &SignalRefClipLimitCheckEnable);
+
+ if ((SignalRefClipLimitCheckEnable != 0) &&
+ (Status == VL53L0_ERROR_NONE)) {
+
+ Status = VL53L0_GetLimitCheckValue(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP,
+ &SignalRefClipValue);
+
+ if ((SignalRefClipValue > 0) &&
+ (LastSignalRefMcps > SignalRefClipValue)) {
+ /* Limit Fail */
+ SignalRefClipflag = 1;
+ }
+ }
+
+ /*
+ * Check if Signal ref clip limit is enabled, if yes then do comparison
+ * with limit value and put the result back into pPalRangeStatus.
+ * EffectiveSpadRtnCount has a format 8.8
+ * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL
+ */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ &RangeIgnoreThresholdLimitCheckEnable);
+
+ if ((RangeIgnoreThresholdLimitCheckEnable != 0) &&
+ (Status == VL53L0_ERROR_NONE)) {
+
+ /* Compute the signal rate per spad */
+ if (EffectiveSpadRtnCount == 0) {
+ SignalRatePerSpad = 0;
+ } else {
+ SignalRatePerSpad = (FixPoint1616_t)((256 * SignalRate)
+ / EffectiveSpadRtnCount);
+ }
+
+ Status = VL53L0_GetLimitCheckValue(Dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ &RangeIgnoreThresholdValue);
+
+ if ((RangeIgnoreThresholdValue > 0) &&
+ (SignalRatePerSpad < RangeIgnoreThresholdValue)) {
+ /* Limit Fail add 2^6 to range status */
+ RangeIgnoreThresholdflag = 1;
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (NoneFlag == 1) {
+ *pPalRangeStatus = 255; /* NONE */
+ } else if (DeviceRangeStatusInternal == 1 ||
+ DeviceRangeStatusInternal == 2 ||
+ DeviceRangeStatusInternal == 3) {
+ *pPalRangeStatus = 5; /* HW fail */
+ } else if (DeviceRangeStatusInternal == 6 ||
+ DeviceRangeStatusInternal == 9) {
+ *pPalRangeStatus = 4; /* Phase fail */
+ } else if (DeviceRangeStatusInternal == 8 ||
+ DeviceRangeStatusInternal == 10 ||
+ SignalRefClipflag == 1) {
+ *pPalRangeStatus = 3; /* Min range */
+ } else if (DeviceRangeStatusInternal == 4 ||
+ RangeIgnoreThresholdflag == 1) {
+ *pPalRangeStatus = 2; /* Signal Fail */
+ } else if (SigmaLimitflag == 1) {
+ *pPalRangeStatus = 1; /* Sigma Fail */
+ } else {
+ *pPalRangeStatus = 0; /* Range Valid */
+ }
+ }
+
+ /* DMAX only relevant during range error */
+ if (*pPalRangeStatus == 0)
+ pRangingMeasurementData->RangeDMaxMilliMeter = 0;
+
+ /* fill the Limit Check Status */
+
+ Status = VL53L0_GetLimitCheckEnable(Dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ &SignalRateFinalRangeLimitCheckEnable);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if ((SigmaLimitCheckEnable == 0) || (SigmaLimitflag == 1))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8);
+
+ if ((DeviceRangeStatusInternal == 4) ||
+ (SignalRateFinalRangeLimitCheckEnable == 0))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ Temp8);
+
+ if ((SignalRefClipLimitCheckEnable == 0) ||
+ (SignalRefClipflag == 1))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP, Temp8);
+
+ if ((RangeIgnoreThresholdLimitCheckEnable == 0) ||
+ (RangeIgnoreThresholdflag == 1))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+
+ VL53L0_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ Temp8);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_api_histogram.c b/drivers/input/misc/vl53L0/src/vl53l0_api_histogram.c
new file mode 100644
index 000000000000..21b0410dd6ae
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_api_histogram.c
@@ -0,0 +1,750 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l0_api.h"
+#include "vl53l0_api_core.h"
+#include "vl53l0_api_histogram.h"
+
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+
+typedef uint32_t WindowSelection;
+#define VL53L0_AMBIENT_WINDOW_ONLY ((WindowSelection) 0)
+ /*!< Measure Ambient Signal only */
+#define VL53L0_AMBIENT_AND_SIGNAL_WINDOW ((WindowSelection) 1)
+ /*!< Measure Combined Ambient and Signal Rate. */
+
+
+VL53L0_Error VL53L0_start_histogram_measurement(VL53L0_DEV Dev,
+ VL53L0_HistogramModes histoMode,
+ uint32_t count)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t dataByte;
+
+ LOG_FUNCTION_START("");
+
+
+ dataByte = VL53L0_REG_SYSRANGE_MODE_SINGLESHOT |
+ VL53L0_REG_SYSRANGE_MODE_START_STOP;
+
+ /* First histogram measurement must have bit 5 set */
+ if (count == 0)
+ dataByte |= (1 << 5);
+
+ switch (histoMode) {
+ case VL53L0_HISTOGRAMMODE_DISABLED:
+ /* Selected mode not supported */
+ Status = VL53L0_ERROR_INVALID_COMMAND;
+ break;
+
+ case VL53L0_HISTOGRAMMODE_REFERENCE_ONLY:
+ case VL53L0_HISTOGRAMMODE_RETURN_ONLY:
+ case VL53L0_HISTOGRAMMODE_BOTH:
+ dataByte |= (histoMode << 3);
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSRANGE_START,
+ dataByte);
+ if (Status == VL53L0_ERROR_NONE) {
+ /* Set PAL State to Running */
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_RUNNING);
+ }
+ break;
+
+ default:
+ /* Selected mode not supported */
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_confirm_measurement_start(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t NewDataReady = 0;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ LoopNb = 0;
+ do {
+ Status = VL53L0_GetMeasurementDataReady(Dev, &NewDataReady);
+ if ((NewDataReady == 0x01) || Status != VL53L0_ERROR_NONE)
+ break;
+
+ LoopNb = LoopNb + 1;
+ VL53L0_PollingDelay(Dev);
+ } while (LoopNb < VL53L0_DEFAULT_MAX_LOOP);
+
+ if (LoopNb >= VL53L0_DEFAULT_MAX_LOOP)
+ Status = VL53L0_ERROR_TIME_OUT;
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_set_histogram_mode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes HistogramMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ switch (HistogramMode) {
+ case VL53L0_HISTOGRAMMODE_DISABLED:
+ case VL53L0_HISTOGRAMMODE_REFERENCE_ONLY:
+ case VL53L0_HISTOGRAMMODE_RETURN_ONLY:
+ case VL53L0_HISTOGRAMMODE_BOTH:
+ /* Supported mode */
+ VL53L0_SETPARAMETERFIELD(Dev, HistogramMode, HistogramMode);
+ break;
+ default:
+ /* Unsupported mode */
+ Status = VL53L0_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_histogram_mode(VL53L0_DEV Dev,
+ VL53L0_HistogramModes *pHistogramMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ VL53L0_GETPARAMETERFIELD(Dev, HistogramMode, *pHistogramMode);
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_perform_single_histogram_measurement(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceModes DeviceMode;
+ VL53L0_HistogramModes HistogramMode = VL53L0_HISTOGRAMMODE_DISABLED;
+ uint32_t MeasCount;
+ uint32_t Measurements;
+
+ /* Get Current DeviceMode */
+ Status = VL53L0_GetHistogramMode(Dev, &HistogramMode);
+
+
+ if (Status != VL53L0_ERROR_NONE)
+ return Status;
+
+
+ if (HistogramMode == VL53L0_HISTOGRAMMODE_BOTH) {
+ if (pHistogramMeasurementData->BufferSize <
+ VL53L0_HISTOGRAM_BUFFER_SIZE) {
+ Status = VL53L0_ERROR_BUFFER_TOO_SMALL;
+ }
+ } else {
+ if (pHistogramMeasurementData->BufferSize <
+ VL53L0_HISTOGRAM_BUFFER_SIZE/2) {
+ Status = VL53L0_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+ pHistogramMeasurementData->HistogramType = (uint8_t)HistogramMode;
+ pHistogramMeasurementData->ErrorStatus = VL53L0_DEVICEERROR_NONE;
+ pHistogramMeasurementData->FirstBin = 0;
+ pHistogramMeasurementData->NumberOfBins = 0;
+
+
+ /* Get Current DeviceMode */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetDeviceMode(Dev, &DeviceMode);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev, VL53L0_REG_SYSTEM_HISTOGRAM_BIN,
+ 0x00);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_WrByte(Dev,
+ VL53L0_REG_HISTOGRAM_CONFIG_READOUT_CTRL, 0x01);
+
+ if (Status != VL53L0_ERROR_NONE)
+ return Status;
+
+ Measurements = 3;
+ if (HistogramMode == VL53L0_HISTOGRAMMODE_BOTH)
+ Measurements = 6;
+
+ if (DeviceMode != VL53L0_DEVICEMODE_SINGLE_HISTOGRAM) {
+ Status = VL53L0_ERROR_INVALID_COMMAND;
+ return Status;
+ }
+
+ /* DeviceMode == VL53L0_DEVICEMODE_SINGLE_HISTOGRAM */
+ MeasCount = 0;
+ while ((MeasCount < Measurements) && (Status == VL53L0_ERROR_NONE)) {
+ Status = VL53L0_start_histogram_measurement(Dev, HistogramMode,
+ MeasCount);
+
+ if (Status == VL53L0_ERROR_NONE)
+ VL53L0_confirm_measurement_start(Dev);
+
+ if (Status == VL53L0_ERROR_NONE)
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_RUNNING);
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_measurement_poll_for_completion(Dev);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_read_histo_measurement(Dev,
+ pHistogramMeasurementData->HistogramData,
+ MeasCount,
+ HistogramMode);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ /*
+ * When reading both rtn and ref arrays,
+ * histograms are read two bins at a time.
+ * For rtn or ref only, histograms are read four
+ * bins at a time.
+ */
+ if (HistogramMode == VL53L0_HISTOGRAMMODE_BOTH)
+ pHistogramMeasurementData->NumberOfBins
+ += 2;
+ else
+ pHistogramMeasurementData->NumberOfBins
+ += 4;
+
+ }
+ }
+
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_ClearInterruptMask(Dev, 0);
+
+ MeasCount++;
+ }
+
+ /* Change PAL State in case of single ranging or single histogram */
+ if (Status == VL53L0_ERROR_NONE) {
+ pHistogramMeasurementData->NumberOfBins = 12;
+ PALDevDataSet(Dev, PalState, VL53L0_STATE_IDLE);
+ }
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_get_histogram_measurement_data(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_read_histo_measurement(VL53L0_DEV Dev,
+ uint32_t *histoData,
+ uint32_t offset,
+ VL53L0_HistogramModes histoMode)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t localBuffer[28];
+ uint32_t cDataSize = 4;
+ uint32_t offset1;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_WrByte(Dev, 0xFF, VL53L0_REG_RESULT_CORE_PAGE);
+ Status = VL53L0_ReadMulti(Dev,
+ (uint8_t)VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN,
+ localBuffer,
+ 28);
+ Status |= VL53L0_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ VL53L0_reverse_bytes(&localBuffer[0], cDataSize);
+ VL53L0_reverse_bytes(&localBuffer[4], cDataSize);
+ VL53L0_reverse_bytes(&localBuffer[20], cDataSize);
+ VL53L0_reverse_bytes(&localBuffer[24], cDataSize);
+
+ offset1 = offset * cDataSize;
+ if (histoMode == VL53L0_HISTOGRAMMODE_BOTH) {
+ /*
+ * When reading both return and ref data, each
+ * measurement reads two ref values and two return
+ * values. Data is stored in an interleaved sequence,
+ * starting with the return histogram.
+ *
+ * Some result Core registers are reused for the
+ * histogram measurements
+ *
+ * The bin values are retrieved in the following order
+ * VL53L0_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN
+ * VL53L0_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF
+ * VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN
+ * VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF
+ */
+
+ memcpy(&histoData[offset1], &localBuffer[4],
+ cDataSize); /* rtn */
+ memcpy(&histoData[offset1 + 1], &localBuffer[24],
+ cDataSize); /* ref */
+ memcpy(&histoData[offset1 + 2], &localBuffer[0],
+ cDataSize); /* rtn */
+ memcpy(&histoData[offset1 + 3], &localBuffer[20],
+ cDataSize); /* ref */
+
+ } else {
+ /*
+ * When reading either return and ref data, each
+ * measurement reads four bin values.
+ *
+ * The bin values are retrieved in the following order
+ * VL53L0_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN
+ * VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN
+ * VL53L0_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF
+ * VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF
+ */
+
+ memcpy(&histoData[offset1], &localBuffer[24],
+ cDataSize);
+ memcpy(&histoData[offset1 + 1], &localBuffer[20],
+ cDataSize);
+ memcpy(&histoData[offset1 + 2], &localBuffer[4],
+ cDataSize);
+ memcpy(&histoData[offset1 + 3], &localBuffer[0],
+ cDataSize);
+
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_get_max_spads(VL53L0_DEV Dev,
+ uint32_t *pmax_spads, uint8_t *pambient_too_high)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t TCC_Enabled;
+ uint8_t MSRC_Enabled;
+ VL53L0_RangingMeasurementData_t RangingMeasurementData;
+ FixPoint1616_t ratio = 0;
+ uint32_t max_spads = 0;
+
+ /* Get the value of the TCC */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_TCC, &TCC_Enabled);
+
+ /* Get the value of the MSRC */
+ if (Status == VL53L0_ERROR_NONE)
+ Status = VL53L0_GetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_MSRC, &MSRC_Enabled);
+
+ /* Disable the TCC */
+ if ((Status == VL53L0_ERROR_NONE) && (TCC_Enabled != 0))
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_TCC, 0);
+
+ /* Disable the MSRC */
+ if ((Status == VL53L0_ERROR_NONE) && (MSRC_Enabled != 0))
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_MSRC, 0);
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_PerformSingleRangingMeasurement(Dev,
+ &RangingMeasurementData);
+ max_spads = (RangingMeasurementData.EffectiveSpadRtnCount +
+ 128)/256;
+ *pmax_spads = max_spads;
+ }
+
+ /* Check Ambient per spad > 10 Kcps */
+ if (Status == VL53L0_ERROR_NONE) {
+ if (max_spads <= 0) {
+ *pambient_too_high = 1;
+ Status = VL53L0_ERROR_DIVISION_BY_ZERO;
+ } else {
+ ratio = RangingMeasurementData.AmbientRateRtnMegaCps /
+ max_spads;
+
+ /* ratio is given in mega count per second and
+ * FixPoint1616_t
+ */
+ if (ratio > 65536/100)
+ *pambient_too_high = 1;
+ else
+ *pambient_too_high = 0;
+
+ }
+ }
+
+
+ /* Restore the TCC */
+ if (Status == VL53L0_ERROR_NONE) {
+ if (TCC_Enabled != 0)
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_TCC, 1);
+ }
+
+ /* Restore the MSRC */
+ if (Status == VL53L0_ERROR_NONE) {
+ if (MSRC_Enabled != 0)
+ Status = VL53L0_SetSequenceStepEnable(Dev,
+ VL53L0_SEQUENCESTEP_MSRC, 1);
+ }
+
+ return Status;
+
+}
+
+
+VL53L0_Error calc_xtalk_mcps_per_spad(
+ uint32_t rtn_signal_events,
+ uint32_t timeout_ms,
+ uint32_t max_spads,
+ uint8_t vcsel_pulse_period_pclk,
+ FixPoint1616_t *pxtalk_mcps_per_spad)
+{
+ /* Calculate the X-Talk per Spad based on given inputs.
+ *
+ * To calculate x-talk, only a portion of the vcsel pulse period is
+ * used, therefore we use the ratio between vcsel_width_pclk and
+ * vcsel_pulse_period_pclks to determine the integration time.
+ *
+ * With the rtn signal events, and the integration time,
+ * the x-talk rate per spad is then determined.
+ */
+
+ const FixPoint1616_t cmin_xtalk_per_spad = 8; /* 0.000122 */
+ const FixPoint1616_t ccompensation2 = 13;/* 0.0002 */
+ const FixPoint1616_t ccompensation1 = 7; /* 0.0001; */
+ const FixPoint1616_t ctalk_thresh = 66; /* 0.001 */
+ const uint32_t c16BitRoundingParam = 0x00008000;
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ FixPoint1616_t xtalk_mcps;
+ FixPoint1616_t vcsel_width_to_period_ratio;
+ FixPoint1616_t integration_time_us;
+ uint32_t integration_time_us_int;
+ uint8_t vcsel_width_pclk = 3;
+
+ LOG_FUNCTION_START("");
+
+ if (vcsel_pulse_period_pclk == 0 || timeout_ms == 0)
+ status = VL53L0_ERROR_DIVISION_BY_ZERO;
+
+
+ if (status == VL53L0_ERROR_NONE) {
+
+ /* (FixPoint1616 + uint32)/uint32 = FixPoint1616 */
+ vcsel_width_to_period_ratio =
+ ((vcsel_width_pclk << 16) +
+ (vcsel_pulse_period_pclk/2))/vcsel_pulse_period_pclk;
+
+ /* uint32_t * FixPoint1616 = FixPoint1616 */
+ integration_time_us = timeout_ms * vcsel_width_to_period_ratio
+ * 1000;
+
+ /*FixPoint1616 >>16 = uint32_t */
+ integration_time_us_int = (integration_time_us +
+ c16BitRoundingParam) >> 16;
+
+ /* (uint32_t << 16)/uint32_t = FixPoint1616 */
+ xtalk_mcps = rtn_signal_events << 16;
+ xtalk_mcps = (xtalk_mcps +
+ (integration_time_us_int/2))/integration_time_us_int;
+
+ /* (FixPoint1616 + uint32)/uint32 = FixPoint1616 */
+ *pxtalk_mcps_per_spad = (xtalk_mcps + (max_spads/2))/max_spads;
+
+ /* Apply compensation to prevent overshoot.
+ */
+ if (*pxtalk_mcps_per_spad < ctalk_thresh)
+ *pxtalk_mcps_per_spad = *pxtalk_mcps_per_spad
+ - ccompensation2;
+ else
+ *pxtalk_mcps_per_spad = *pxtalk_mcps_per_spad
+ - ccompensation1;
+
+ if (*pxtalk_mcps_per_spad < cmin_xtalk_per_spad)
+ *pxtalk_mcps_per_spad = cmin_xtalk_per_spad;
+
+ }
+ LOG_FUNCTION_END("");
+
+ return status;
+}
+
+
+uint32_t bytes_to_int(uint8_t *data_bytes)
+{
+ /* Convert an array of 4 bytes to an integer.
+ */
+ uint32_t data = (uint32_t)data_bytes[0] << 24;
+
+ data += ((uint32_t)data_bytes[1] << 16);
+ data += ((uint32_t)data_bytes[2] << 8);
+ data += ((uint32_t)data_bytes[3]);
+ return data;
+}
+
+VL53L0_Error perform_histo_signal_meas(VL53L0_DEV dev,
+ WindowSelection window_select,
+ uint32_t *psignal_events)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ uint8_t data[8];
+ uint8_t readout_ctrl_val;
+ uint32_t bin_width = 3;
+
+ LOG_FUNCTION_START("");
+
+ /* Select Ambient or Total Signal Measurement
+ */
+ if (status == VL53L0_ERROR_NONE) {
+ readout_ctrl_val = bin_width;
+ if (window_select == VL53L0_AMBIENT_WINDOW_ONLY)
+ readout_ctrl_val += 0x80;
+
+ status = VL53L0_WrByte(
+ dev, VL53L0_REG_HISTOGRAM_CONFIG_READOUT_CTRL,
+ readout_ctrl_val);
+ }
+
+ /* Perform Measurement.
+ */
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_start_histogram_measurement(
+ dev, VL53L0_HISTOGRAMMODE_RETURN_ONLY, 0);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_measurement_poll_for_completion(dev);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_ClearInterruptMask(dev, 0);
+
+ /* Read Measurement Data.
+ */
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_WrByte(dev, 0xFF, VL53L0_REG_RESULT_CORE_PAGE);
+
+
+ if (status == VL53L0_ERROR_NONE) {
+ status = VL53L0_ReadMulti(dev,
+ (uint8_t)VL53L0_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN,
+ data,
+ 8);
+ }
+
+ if (status == VL53L0_ERROR_NONE)
+ status |= VL53L0_WrByte(dev, 0xFF, 0x00);
+
+
+ /* Take the sum of the Ambient and Signal Window Event readings.
+ */
+ if (status == VL53L0_ERROR_NONE)
+ *psignal_events = bytes_to_int(data) +
+ bytes_to_int(&(data[4]));
+
+
+ LOG_FUNCTION_END(status);
+
+ return status;
+}
+
+VL53L0_Error set_final_range_timeout_us(
+ VL53L0_DEV dev, uint32_t timeout_microSecs,
+ uint16_t final_range_vcsel_period_pclks)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ uint16_t final_range_timeout_mclks;
+ uint16_t final_range_encoded_timeOut;
+
+ LOG_FUNCTION_START("");
+
+ /* Calculate FINAL RANGE Timeout in Macro Periods (MCLKS)
+ */
+
+ /* convert timeout to mclks. */
+ final_range_timeout_mclks = VL53L0_calc_timeout_mclks(dev,
+ timeout_microSecs, (uint8_t) final_range_vcsel_period_pclks);
+
+ /* Encode timeout */
+ final_range_encoded_timeOut = VL53L0_encode_timeout(
+ final_range_timeout_mclks);
+
+ /* Write to device */
+ status = VL53L0_WrWord(dev,
+ VL53L0_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ final_range_encoded_timeOut);
+
+ LOG_FUNCTION_END(status);
+
+ return status;
+}
+
+
+VL53L0_Error perform_histogram_config(VL53L0_DEV dev,
+ uint32_t timeout_ms, uint16_t final_range_vcsel_period_pclks)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ uint8_t phaseSelect = 1;
+
+ LOG_FUNCTION_START("");
+
+ if (status == VL53L0_ERROR_NONE)
+ status = set_final_range_timeout_us(
+ dev, timeout_ms * 1000, final_range_vcsel_period_pclks);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_SetDeviceMode(dev,
+ VL53L0_DEVICEMODE_SINGLE_HISTOGRAM);
+
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_SetHistogramMode(dev,
+ VL53L0_HISTOGRAMMODE_BOTH);
+
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_WrByte(dev, VL53L0_REG_SYSTEM_HISTOGRAM_BIN,
+ 0x00);
+
+
+ /* Apply specific phase select for x-talk measurement */
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_WrByte(dev,
+ VL53L0_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT,
+ phaseSelect);
+
+
+ LOG_FUNCTION_END(status);
+
+ return status;
+}
+
+
+VL53L0_Error VL53L0_perform_xtalk_measurement(VL53L0_DEV dev,
+ uint32_t timeout_ms, FixPoint1616_t *pxtalk_per_spad,
+ uint8_t *pambient_too_high)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+ uint32_t signal_events = 0;
+ uint32_t amb_events = 0;
+ uint32_t meas_timing_budget_us;
+ VL53L0_DeviceModes device_mode;
+ uint8_t final_range_vcsel_period_pclks;
+ uint32_t max_spads;
+
+ /* Get Current DeviceMode */
+ status = VL53L0_GetDeviceMode(dev, &device_mode);
+
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_get_max_spads(dev, &max_spads,
+ pambient_too_high);
+
+ if (status != VL53L0_ERROR_NONE)
+ return status;
+
+
+ if (status == VL53L0_ERROR_NONE) {
+ status = VL53L0_GetVcselPulsePeriod(
+ dev,
+ VL53L0_VCSEL_PERIOD_FINAL_RANGE,
+ &final_range_vcsel_period_pclks);
+ }
+
+ if (status == VL53L0_ERROR_NONE) {
+ if (final_range_vcsel_period_pclks < 10)
+ status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+
+ if (status == VL53L0_ERROR_NONE) {
+ perform_histogram_config(
+ dev, timeout_ms, final_range_vcsel_period_pclks);
+ }
+
+ if (status == VL53L0_ERROR_NONE) {
+ status = perform_histo_signal_meas(
+ dev,
+ VL53L0_AMBIENT_WINDOW_ONLY,
+ &amb_events);
+ }
+
+ if (status == VL53L0_ERROR_NONE) {
+ status = perform_histo_signal_meas(
+ dev,
+ VL53L0_AMBIENT_AND_SIGNAL_WINDOW,
+ &signal_events);
+ }
+
+ if (status == VL53L0_ERROR_NONE) {
+ status = calc_xtalk_mcps_per_spad(
+ (signal_events - amb_events),
+ timeout_ms,
+ max_spads,
+ final_range_vcsel_period_pclks,
+ pxtalk_per_spad);
+ }
+
+ /* Revert previous device mode. */
+ if (status == VL53L0_ERROR_NONE)
+ status = VL53L0_SetDeviceMode(dev, device_mode);
+
+ /* Revert previous timing budget, to ensure previous final range vcsel
+ * period is applied.
+ */
+ if (status == VL53L0_ERROR_NONE) {
+ VL53L0_GETPARAMETERFIELD(
+ dev,
+ MeasurementTimingBudgetMicroSeconds,
+ meas_timing_budget_us);
+
+ status = VL53L0_SetMeasurementTimingBudgetMicroSeconds(
+ dev, meas_timing_budget_us);
+ }
+
+ return status;
+}
+
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_api_ranging.c b/drivers/input/misc/vl53L0/src/vl53l0_api_ranging.c
new file mode 100644
index 000000000000..f575aec7c5ed
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_api_ranging.c
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l0_api.h"
+#include "vl53l0_api_core.h"
+
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_api_strings.c b/drivers/input/misc/vl53L0/src/vl53l0_api_strings.c
new file mode 100644
index 000000000000..a5f2bbadd290
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_api_strings.c
@@ -0,0 +1,463 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+ NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+ IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+#include "vl53l0_api.h"
+#include "vl53l0_api_core.h"
+#include "vl53l0_api_strings.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+
+VL53L0_Error VL53L0_check_part_used(VL53L0_DEV Dev,
+ uint8_t *Revision,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t ModuleIdInt;
+ char *ProductId_tmp;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL53L0_get_info_from_device(Dev, 2);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ ModuleIdInt = VL53L0_GETDEVICESPECIFICPARAMETER(Dev, ModuleId);
+
+ if (ModuleIdInt == 0) {
+ *Revision = 0;
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->ProductId, "");
+ } else {
+ *Revision = VL53L0_GETDEVICESPECIFICPARAMETER(Dev, Revision);
+ ProductId_tmp = VL53L0_GETDEVICESPECIFICPARAMETER(Dev,
+ ProductId);
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->ProductId, ProductId_tmp);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_get_device_info(VL53L0_DEV Dev,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint8_t revision_id;
+ uint8_t Revision;
+
+ Status = VL53L0_check_part_used(Dev, &Revision, pVL53L0_DeviceInfo);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ if (Revision == 0) {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L0_STRING_DEVICE_INFO_NAME_TS0);
+ } else if ((Revision <= 34) && (Revision != 32)) {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L0_STRING_DEVICE_INFO_NAME_TS1);
+ } else if (Revision < 39) {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L0_STRING_DEVICE_INFO_NAME_TS2);
+ } else {
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Name,
+ VL53L0_STRING_DEVICE_INFO_NAME_ES1);
+ }
+
+ VL53L0_COPYSTRING(pVL53L0_DeviceInfo->Type,
+ VL53L0_STRING_DEVICE_INFO_TYPE);
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev, VL53L0_REG_IDENTIFICATION_MODEL_ID,
+ &pVL53L0_DeviceInfo->ProductType);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = VL53L0_RdByte(Dev,
+ VL53L0_REG_IDENTIFICATION_REVISION_ID,
+ &revision_id);
+ pVL53L0_DeviceInfo->ProductRevisionMajor = 1;
+ pVL53L0_DeviceInfo->ProductRevisionMinor =
+ (revision_id & 0xF0) >> 4;
+ }
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_get_device_error_string(VL53L0_DeviceError ErrorCode,
+ char *pDeviceErrorString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (ErrorCode) {
+ case VL53L0_DEVICEERROR_NONE:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_NONE);
+ break;
+ case VL53L0_DEVICEERROR_VCSELCONTINUITYTESTFAILURE:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE);
+ break;
+ case VL53L0_DEVICEERROR_VCSELWATCHDOGTESTFAILURE:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE);
+ break;
+ case VL53L0_DEVICEERROR_NOVHVVALUEFOUND:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_NOVHVVALUEFOUND);
+ break;
+ case VL53L0_DEVICEERROR_MSRCNOTARGET:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_MSRCNOTARGET);
+ break;
+ case VL53L0_DEVICEERROR_SNRCHECK:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_SNRCHECK);
+ break;
+ case VL53L0_DEVICEERROR_RANGEPHASECHECK:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_RANGEPHASECHECK);
+ break;
+ case VL53L0_DEVICEERROR_SIGMATHRESHOLDCHECK:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK);
+ break;
+ case VL53L0_DEVICEERROR_TCC:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_TCC);
+ break;
+ case VL53L0_DEVICEERROR_PHASECONSISTENCY:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_PHASECONSISTENCY);
+ break;
+ case VL53L0_DEVICEERROR_MINCLIP:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_MINCLIP);
+ break;
+ case VL53L0_DEVICEERROR_RANGECOMPLETE:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_RANGECOMPLETE);
+ break;
+ case VL53L0_DEVICEERROR_ALGOUNDERFLOW:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_ALGOUNDERFLOW);
+ break;
+ case VL53L0_DEVICEERROR_ALGOOVERFLOW:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_ALGOOVERFLOW);
+ break;
+ case VL53L0_DEVICEERROR_RANGEIGNORETHRESHOLD:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD);
+ break;
+
+ default:
+ VL53L0_COPYSTRING(pDeviceErrorString,
+ VL53L0_STRING_UNKNOW_ERROR_CODE);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_range_status_string(uint8_t RangeStatus,
+ char *pRangeStatusString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (RangeStatus) {
+ case 0:
+ VL53L0_COPYSTRING(pRangeStatusString,
+ VL53L0_STRING_RANGESTATUS_RANGEVALID);
+ break;
+ case 1:
+ VL53L0_COPYSTRING(pRangeStatusString,
+ VL53L0_STRING_RANGESTATUS_SIGMA);
+ break;
+ case 2:
+ VL53L0_COPYSTRING(pRangeStatusString,
+ VL53L0_STRING_RANGESTATUS_SIGNAL);
+ break;
+ case 3:
+ VL53L0_COPYSTRING(pRangeStatusString,
+ VL53L0_STRING_RANGESTATUS_MINRANGE);
+ break;
+ case 4:
+ VL53L0_COPYSTRING(pRangeStatusString,
+ VL53L0_STRING_RANGESTATUS_PHASE);
+ break;
+ case 5:
+ VL53L0_COPYSTRING(pRangeStatusString,
+ VL53L0_STRING_RANGESTATUS_HW);
+ break;
+
+ default: /**/
+ VL53L0_COPYSTRING(pRangeStatusString,
+ VL53L0_STRING_RANGESTATUS_NONE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_pal_error_string(VL53L0_Error PalErrorCode,
+ char *pPalErrorString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (PalErrorCode) {
+ case VL53L0_ERROR_NONE:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_NONE);
+ break;
+ case VL53L0_ERROR_CALIBRATION_WARNING:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_CALIBRATION_WARNING);
+ break;
+ case VL53L0_ERROR_MIN_CLIPPED:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_MIN_CLIPPED);
+ break;
+ case VL53L0_ERROR_UNDEFINED:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_UNDEFINED);
+ break;
+ case VL53L0_ERROR_INVALID_PARAMS:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_INVALID_PARAMS);
+ break;
+ case VL53L0_ERROR_NOT_SUPPORTED:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_NOT_SUPPORTED);
+ break;
+ case VL53L0_ERROR_INTERRUPT_NOT_CLEARED:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_INTERRUPT_NOT_CLEARED);
+ break;
+ case VL53L0_ERROR_RANGE_ERROR:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_RANGE_ERROR);
+ break;
+ case VL53L0_ERROR_TIME_OUT:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_TIME_OUT);
+ break;
+ case VL53L0_ERROR_MODE_NOT_SUPPORTED:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_MODE_NOT_SUPPORTED);
+ break;
+ case VL53L0_ERROR_BUFFER_TOO_SMALL:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_BUFFER_TOO_SMALL);
+ break;
+ case VL53L0_ERROR_GPIO_NOT_EXISTING:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_GPIO_NOT_EXISTING);
+ break;
+ case VL53L0_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED);
+ break;
+ case VL53L0_ERROR_CONTROL_INTERFACE:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_CONTROL_INTERFACE);
+ break;
+ case VL53L0_ERROR_INVALID_COMMAND:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_INVALID_COMMAND);
+ break;
+ case VL53L0_ERROR_DIVISION_BY_ZERO:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_DIVISION_BY_ZERO);
+ break;
+ case VL53L0_ERROR_REF_SPAD_INIT:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_REF_SPAD_INIT);
+ break;
+ case VL53L0_ERROR_NOT_IMPLEMENTED:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_ERROR_NOT_IMPLEMENTED);
+ break;
+
+ default:
+ VL53L0_COPYSTRING(pPalErrorString,
+ VL53L0_STRING_UNKNOW_ERROR_CODE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_pal_state_string(VL53L0_State PalStateCode,
+ char *pPalStateString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (PalStateCode) {
+ case VL53L0_STATE_POWERDOWN:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_POWERDOWN);
+ break;
+ case VL53L0_STATE_WAIT_STATICINIT:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_WAIT_STATICINIT);
+ break;
+ case VL53L0_STATE_STANDBY:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_STANDBY);
+ break;
+ case VL53L0_STATE_IDLE:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_IDLE);
+ break;
+ case VL53L0_STATE_RUNNING:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_RUNNING);
+ break;
+ case VL53L0_STATE_UNKNOWN:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_UNKNOWN);
+ break;
+ case VL53L0_STATE_ERROR:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_ERROR);
+ break;
+
+ default:
+ VL53L0_COPYSTRING(pPalStateString,
+ VL53L0_STRING_STATE_UNKNOWN);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+VL53L0_Error VL53L0_get_sequence_steps_info(
+ VL53L0_SequenceStepId SequenceStepId,
+ char *pSequenceStepsString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (SequenceStepId) {
+ case VL53L0_SEQUENCESTEP_TCC:
+ VL53L0_COPYSTRING(pSequenceStepsString,
+ VL53L0_STRING_SEQUENCESTEP_TCC);
+ break;
+ case VL53L0_SEQUENCESTEP_DSS:
+ VL53L0_COPYSTRING(pSequenceStepsString,
+ VL53L0_STRING_SEQUENCESTEP_DSS);
+ break;
+ case VL53L0_SEQUENCESTEP_MSRC:
+ VL53L0_COPYSTRING(pSequenceStepsString,
+ VL53L0_STRING_SEQUENCESTEP_MSRC);
+ break;
+ case VL53L0_SEQUENCESTEP_PRE_RANGE:
+ VL53L0_COPYSTRING(pSequenceStepsString,
+ VL53L0_STRING_SEQUENCESTEP_PRE_RANGE);
+ break;
+ case VL53L0_SEQUENCESTEP_FINAL_RANGE:
+ VL53L0_COPYSTRING(pSequenceStepsString,
+ VL53L0_STRING_SEQUENCESTEP_FINAL_RANGE);
+ break;
+
+ default:
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_get_limit_check_info(VL53L0_DEV Dev, uint16_t LimitCheckId,
+ char *pLimitCheckString)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (LimitCheckId) {
+ case VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L0_STRING_CHECKENABLE_SIGMA_FINAL_RANGE);
+ break;
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L0_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE);
+ break;
+ case VL53L0_CHECKENABLE_SIGNAL_REF_CLIP:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L0_STRING_CHECKENABLE_SIGNAL_REF_CLIP);
+ break;
+ case VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L0_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD);
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_MSRC:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L0_STRING_CHECKENABLE_SIGNAL_RATE_MSRC);
+ break;
+
+ case VL53L0_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L0_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE);
+ break;
+
+ default:
+ VL53L0_COPYSTRING(pLimitCheckString,
+ VL53L0_STRING_UNKNOW_ERROR_CODE);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_i2c_platform.c b/drivers/input/misc/vl53L0/src/vl53l0_i2c_platform.c
new file mode 100644
index 000000000000..e4097e1ccdd5
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_i2c_platform.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*!
+ * \file VL53L0_i2c_platform.c
+ * \brief Code function defintions for EWOK Platform Layer
+ *
+ */
+
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "stmvl53l0-i2c.h"
+#include "stmvl53l0-cci.h"
+
+#include "vl53l0_platform.h"
+#include "vl53l0_i2c_platform.h"
+#include "vl53l0_def.h"
+
+#include "vl53l0_platform_log.h"
+
+#ifdef VL53L0_LOG_ENABLE
+#define trace_print(level, ...) \
+ trace_print_module_function(TRACE_MODULE_PLATFORM, level,\
+ TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#define trace_i2c(...) \
+ trace_print_module_function(TRACE_MODULE_NONE, \
+ TRACE_LEVEL_NONE, TRACE_FUNCTION_I2C, ##__VA_ARGS__)
+#endif
+
+/**
+ * @def I2C_BUFFER_CONFIG
+ *
+ * @brief Configure Device register I2C access
+ *
+ * @li 0 : one GLOBAL buffer \n
+ * Use one global buffer of MAX_I2C_XFER_SIZE byte in data space \n
+ * This solution is not multi-Device compliant nor multi-thread cpu safe \n
+ * It can be the best option for small 8/16 bit MCU without stack and limited
+ * ram (STM8s, 80C51 ...)
+ *
+ * @li 1 : ON_STACK/local \n
+ * Use local variable (on stack) buffer \n
+ * This solution is multi-thread with use of i2c resource lock or mutex see
+ * VL6180x_GetI2CAccess() \n
+ *
+ * @li 2 : User defined \n
+ * Per Device potentially dynamic allocated. Requires VL6180x_GetI2cBuffer()
+ * to be implemented.
+ * @ingroup Configuration
+ */
+#define I2C_BUFFER_CONFIG 1
+
+#if I2C_BUFFER_CONFIG == 0
+ /* GLOBAL config buffer */
+ uint8_t i2c_global_buffer[VL53L0_MAX_I2C_XFER_SIZE];
+
+ #define DECL_I2C_BUFFER
+ #define VL53L0_GetLocalBuffer(Dev, n_byte) i2c_global_buffer
+
+#elif I2C_BUFFER_CONFIG == 1
+ /* ON STACK */
+ uint8_t LocBuffer[VL53L0_MAX_I2C_XFER_SIZE];
+ #define VL53L0_GetLocalBuffer(Dev, n_byte) LocBuffer
+#elif I2C_BUFFER_CONFIG == 2
+ /* user define buffer type declare DECL_I2C_BUFFER as access via
+ * VL53L0_GetLocalBuffer
+ */
+ #define DECL_I2C_BUFFER
+#else
+#error "invalid I2C_BUFFER_CONFIG "
+#endif
+
+
+/* none but could be for a flag var to
+ * get/pass to mutex interruptible return flags and try again
+ */
+#define VL53L0_I2C_USER_VAR
+#define VL53L0_GetI2CAccess(Dev) /* todo mutex acquire */
+#define VL53L0_DoneI2CAcces(Dev) /* todo mutex release */
+
+
+char debug_string[VL53L0_MAX_STRING_LENGTH_PLT];
+
+
+#define MIN_COMMS_VERSION_MAJOR 1
+#define MIN_COMMS_VERSION_MINOR 8
+#define MIN_COMMS_VERSION_BUILD 1
+#define MIN_COMMS_VERSION_REVISION 0
+
+#define STATUS_OK 0x00
+#define STATUS_FAIL 0x01
+
+bool_t _check_min_version(void)
+{
+ bool_t min_version_comms_dll = false;
+
+ min_version_comms_dll = true;
+
+ return min_version_comms_dll;
+}
+
+int32_t VL53L0_comms_initialise(uint8_t comms_type, uint16_t comms_speed_khz)
+{
+ int32_t status = STATUS_OK;
+
+ return status;
+}
+
+int32_t VL53L0_comms_close(void)
+{
+ int32_t status = STATUS_OK;
+
+
+ return status;
+}
+
+int32_t VL53L0_set_page(VL53L0_DEV dev, uint8_t page_data)
+{
+ int32_t status = STATUS_OK;
+ uint16_t page_index = 0xFF;
+ uint8_t *buffer;
+
+ buffer = VL53L0_GetLocalBuffer(dev, 3);
+ buffer[0] = page_index >> 8;
+ buffer[1] = page_index & 0xff;
+ buffer[2] = page_data;
+
+ status = VL53L0_I2CWrite(dev, buffer, (uint8_t) 3);
+ return status;
+}
+
+int32_t VL53L0_write_multi(VL53L0_DEV dev, uint8_t index, uint8_t *pdata,
+ int32_t count)
+{
+ int32_t status = STATUS_OK;
+ uint8_t *buffer;
+
+#ifdef VL53L0_LOG_ENABLE
+ int32_t i = 0;
+ char value_as_str[VL53L0_MAX_STRING_LENGTH_PLT];
+ char *pvalue_as_str;
+
+ pvalue_as_str = value_as_str;
+
+ for (i = 0 ; i < count ; i++) {
+ snprintf(pvalue_as_str, sizeof(pvalue_as_str),
+ "%02X", *(pdata + i));
+
+ pvalue_as_str += 2;
+ }
+ trace_i2c("Write reg : 0x%04X, Val : 0x%s\n", index, value_as_str);
+#endif
+ if ((count + 1) > VL53L0_MAX_I2C_XFER_SIZE)
+ return STATUS_FAIL;
+ buffer = VL53L0_GetLocalBuffer(dev, (count+1));
+ buffer[0] = index;
+ memcpy(&buffer[1], pdata, count);
+ status = VL53L0_I2CWrite(dev, buffer, (count+1));
+
+ return status;
+}
+
+int32_t VL53L0_read_multi(VL53L0_DEV dev, uint8_t index, uint8_t *pdata,
+ int32_t count)
+{
+ int32_t status = STATUS_OK;
+ uint8_t *buffer;
+
+#ifdef VL53L0_LOG_ENABLE
+ int32_t i = 0;
+ char value_as_str[VL53L0_MAX_STRING_LENGTH_PLT];
+ char *pvalue_as_str;
+#endif
+
+ if ((count + 1) > VL53L0_MAX_I2C_XFER_SIZE)
+ return STATUS_FAIL;
+
+ buffer = VL53L0_GetLocalBuffer(dev, 1);
+ buffer[0] = index;
+ status = VL53L0_I2CWrite(dev, (uint8_t *)buffer, (uint8_t)1);
+ if (!status) {
+ pdata[0] = index;
+ status = VL53L0_I2CRead(dev, pdata, count);
+ }
+
+#ifdef VL53L0_LOG_ENABLE
+ pvalue_as_str = value_as_str;
+
+ for (i = 0 ; i < count ; i++) {
+ snprintf(pvalue_as_str, sizeof(value_as_str),
+ "%02X", *(pdata+i));
+ pvalue_as_str += 2;
+ }
+
+ trace_i2c("Read reg : 0x%04X, Val : 0x%s\n", index, value_as_str);
+#endif
+
+ return status;
+}
+
+
+int32_t VL53L0_write_byte(VL53L0_DEV dev, uint8_t index, uint8_t data)
+{
+ int32_t status = STATUS_OK;
+ const int32_t cbyte_count = 1;
+
+ status = VL53L0_write_multi(dev, index, &data, cbyte_count);
+
+ return status;
+
+}
+
+
+int32_t VL53L0_write_word(VL53L0_DEV dev, uint8_t index, uint16_t data)
+{
+ int32_t status = STATUS_OK;
+
+ uint8_t buffer[BYTES_PER_WORD];
+
+ /* Split 16-bit word into MS and LS uint8_t */
+ buffer[0] = (uint8_t)(data >> 8);
+ buffer[1] = (uint8_t)(data & 0x00FF);
+
+ status = VL53L0_write_multi(dev, index, buffer, BYTES_PER_WORD);
+
+ return status;
+
+}
+
+
+int32_t VL53L0_write_dword(VL53L0_DEV dev, uint8_t index, uint32_t data)
+{
+ int32_t status = STATUS_OK;
+ uint8_t buffer[BYTES_PER_DWORD];
+
+ /* Split 32-bit word into MS ... LS bytes */
+ buffer[0] = (uint8_t) (data >> 24);
+ buffer[1] = (uint8_t)((data & 0x00FF0000) >> 16);
+ buffer[2] = (uint8_t)((data & 0x0000FF00) >> 8);
+ buffer[3] = (uint8_t) (data & 0x000000FF);
+
+ status = VL53L0_write_multi(dev, index, buffer, BYTES_PER_DWORD);
+
+ return status;
+
+}
+
+
+int32_t VL53L0_read_byte(VL53L0_DEV dev, uint8_t index, uint8_t *pdata)
+{
+ int32_t status = STATUS_OK;
+ int32_t cbyte_count = 1;
+
+ status = VL53L0_read_multi(dev, index, pdata, cbyte_count);
+
+ return status;
+
+}
+
+
+int32_t VL53L0_read_word(VL53L0_DEV dev, uint8_t index, uint16_t *pdata)
+{
+ int32_t status = STATUS_OK;
+ uint8_t buffer[BYTES_PER_WORD];
+
+ status = VL53L0_read_multi(dev, index, buffer, BYTES_PER_WORD);
+ *pdata = ((uint16_t)buffer[0]<<8) + (uint16_t)buffer[1];
+
+ return status;
+
+}
+
+int32_t VL53L0_read_dword(VL53L0_DEV dev, uint8_t index, uint32_t *pdata)
+{
+ int32_t status = STATUS_OK;
+ uint8_t buffer[BYTES_PER_DWORD];
+
+ status = VL53L0_read_multi(dev, index, buffer, BYTES_PER_DWORD);
+ *pdata = ((uint32_t)buffer[0]<<24) + ((uint32_t)buffer[1]<<16) +
+ ((uint32_t)buffer[2]<<8) + (uint32_t)buffer[3];
+
+ return status;
+
+}
+
+int32_t VL53L0_platform_wait_us(int32_t wait_us)
+{
+ int32_t status = STATUS_OK;
+
+ msleep((wait_us/1000));
+
+#ifdef VL53L0_LOG_ENABLE
+ trace_i2c("Wait us : %6d\n", wait_us);
+#endif
+
+ return status;
+
+}
+
+
+int32_t VL53L0_wait_ms(int32_t wait_ms)
+{
+ int32_t status = STATUS_OK;
+
+ msleep(wait_ms);
+
+#ifdef VL53L0_LOG_ENABLE
+ trace_i2c("Wait ms : %6d\n", wait_ms);
+#endif
+
+ return status;
+
+}
+
+
+int32_t VL53L0_set_gpio(uint8_t level)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL53L0_LOG_ENABLE
+ trace_i2c("// Set GPIO = %d;\n", level);
+#endif
+
+ return status;
+
+}
+
+
+int32_t VL53L0_get_gpio(uint8_t *plevel)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL53L0_LOG_ENABLE
+ trace_i2c("// Get GPIO = %d;\n", *plevel);
+#endif
+ return status;
+}
+
+
+int32_t VL53L0_release_gpio(void)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL53L0_LOG_ENABLE
+ trace_i2c("// Releasing force on GPIO\n");
+#endif
+ return status;
+
+}
+
+int32_t VL53L0_cycle_power(void)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL53L0_LOG_ENABLE
+ trace_i2c("// cycle sensor power\n");
+#endif
+
+ return status;
+}
+
+
+int32_t VL53L0_get_timer_frequency(int32_t *ptimer_freq_hz)
+{
+ *ptimer_freq_hz = 0;
+ return STATUS_FAIL;
+}
+
+
+int32_t VL53L0_get_timer_value(int32_t *ptimer_count)
+{
+ *ptimer_count = 0;
+ return STATUS_FAIL;
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_platform.c b/drivers/input/misc/vl53L0/src/vl53l0_platform.c
new file mode 100644
index 000000000000..f7292ab6f8f2
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_platform.c
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright © 2016, STMicroelectronics International N.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of STMicroelectronics nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
+NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
+IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**
+ * @file VL53L0_i2c.c
+ *
+ * Copyright (C) 2014 ST MicroElectronics
+ *
+ * provide variable word size byte/Word/dword VL6180x register access via i2c
+ *
+ */
+#include "vl53l0_platform.h"
+#include "vl53l0_i2c_platform.h"
+#include "vl53l0_api.h"
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_PLATFORM, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_PLATFORM, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...)\
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_PLATFORM, status,\
+ fmt, ##__VA_ARGS__)
+
+
+
+VL53L0_Error VL53L0_LockSequenceAccess(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_UnlockSequenceAccess(VL53L0_DEV Dev)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ return Status;
+}
+
+/* the ranging_sensor_comms.dll will take care of the page selection */
+VL53L0_Error VL53L0_WriteMulti(VL53L0_DEV Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count)
+{
+
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int = 0;
+ uint8_t deviceAddress;
+
+ if (count >= VL53L0_MAX_I2C_XFER_SIZE)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_write_multi(Dev, index, pdata, count);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+/* the ranging_sensor_comms.dll will take care of the page selection */
+VL53L0_Error VL53L0_ReadMulti(VL53L0_DEV Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ if (count >= VL53L0_MAX_I2C_XFER_SIZE)
+ Status = VL53L0_ERROR_INVALID_PARAMS;
+
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_read_multi(Dev, index, pdata, count);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+
+VL53L0_Error VL53L0_WrByte(VL53L0_DEV Dev, uint8_t index, uint8_t data)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_write_byte(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_WrWord(VL53L0_DEV Dev, uint8_t index, uint16_t data)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_write_word(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_WrDWord(VL53L0_DEV Dev, uint8_t index, uint32_t data)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_write_dword(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_UpdateByte(VL53L0_DEV Dev, uint8_t index,
+ uint8_t AndData, uint8_t OrData)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+ uint8_t data;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_read_byte(Dev, index, &data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ if (Status == VL53L0_ERROR_NONE) {
+ data = (data & AndData) | OrData;
+ status_int = VL53L0_write_byte(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+ }
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_RdByte(VL53L0_DEV Dev, uint8_t index, uint8_t *data)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_read_byte(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_RdWord(VL53L0_DEV Dev, uint8_t index, uint16_t *data)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_read_word(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+VL53L0_Error VL53L0_RdDWord(VL53L0_DEV Dev, uint8_t index, uint32_t *data)
+{
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL53L0_read_dword(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL53L0_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+#define VL53L0_POLLINGDELAY_LOOPNB 250
+VL53L0_Error VL53L0_PollingDelay(VL53L0_DEV Dev)
+{
+ VL53L0_Error status = VL53L0_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+ usleep_range(950, 1000);
+ LOG_FUNCTION_END(status);
+ return status;
+}
diff --git a/drivers/input/misc/vl53L0/src/vl53l0_port_i2c.c b/drivers/input/misc/vl53L0/src/vl53l0_port_i2c.c
new file mode 100644
index 000000000000..3dc085f60326
--- /dev/null
+++ b/drivers/input/misc/vl53L0/src/vl53l0_port_i2c.c
@@ -0,0 +1,155 @@
+/*
+ * vl53l0_port_i2c.c
+ *
+ * Created on: July, 2015
+ * Author: Teresa Tao
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include "stmvl53l0-i2c.h"
+#include "stmvl53l0-cci.h"
+#include "vl53l0_platform.h"
+#include "vl53l0_i2c_platform.h"
+#include "stmvl53l0.h"
+
+#define I2C_M_WR 0x00
+#define STATUS_OK 0x00
+#define STATUS_FAIL (-1)
+/** int VL53L0_I2CWrite(VL53L0_Dev_t dev, void *buff, uint8_t len);
+ * @brief Write data buffer to VL53L0 device via i2c
+ * @param dev The device to write to
+ * @param buff The data buffer
+ * @param len The length of the transaction in byte
+ * @return 0 on success
+ */
+int VL53L0_I2CWrite(VL53L0_DEV dev, uint8_t *buff, uint8_t len)
+{
+ int err = 0;
+
+ if (dev->bus_type == CCI_BUS) {
+#ifdef CAMERA_CCI
+ uint16_t index;
+ struct cci_data *cci_client_obj =
+ (struct cci_data *)dev->client_object;
+ struct msm_camera_i2c_client *client = cci_client_obj->client;
+
+ index = buff[0];
+ /*pr_err("%s: index: %d len: %d\n", __func__, index, len); */
+
+ if (len == 2) {
+ uint8_t data;
+
+ data = buff[1];
+ /* for byte access */
+ err = client->i2c_func_tbl->i2c_write(client, index,
+ data, MSM_CAMERA_I2C_BYTE_DATA);
+ if (err < 0) {
+ pr_err("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+ } else if (len == 3) {
+ uint16_t data;
+
+ data = ((uint16_t)buff[1] << 8) | (uint16_t)buff[2];
+ err = client->i2c_func_tbl->i2c_write(client, index,
+ data, MSM_CAMERA_I2C_WORD_DATA);
+ if (err < 0) {
+ pr_err("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+ } else if (len >= 5) {
+ err = client->i2c_func_tbl->i2c_write_seq(client,
+ index, &buff[1], (len-1));
+ if (err < 0) {
+ pr_err("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+
+ }
+#endif
+#ifndef CAMERA_CCI
+ } else {
+ struct i2c_msg msg[1];
+ struct i2c_data *i2c_client_obj =
+ (struct i2c_data *)dev->client_object;
+ struct i2c_client *client =
+ (struct i2c_client *)i2c_client_obj->client;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = I2C_M_WR;
+ msg[0].buf = buff;
+ msg[0].len = len;
+
+ err = i2c_transfer(client->adapter, msg, 1);
+ /* return the actual messages transfer */
+ if (err != 1) {
+ pr_err("%s: i2c_transfer err:%d, addr:0x%x, reg:0x%x\n",
+ __func__, err, client->addr,
+ (buff[0] << 8 | buff[1]));
+ return STATUS_FAIL;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+
+/** int VL53L0_I2CRead(VL53L0_Dev_t dev, void *buff, uint8_t len);
+ * @brief Read data buffer from VL53L0 device via i2c
+ * @param dev The device to read from
+ * @param buff The data buffer to fill
+ * @param len The length of the transaction in byte
+ * @return transaction status
+ */
+int VL53L0_I2CRead(VL53L0_DEV dev, uint8_t *buff, uint8_t len)
+{
+
+ int err = 0;
+
+ if (dev->bus_type == CCI_BUS) {
+#ifdef CAMERA_CCI
+ uint16_t index;
+ struct cci_data *cci_client_obj =
+ (struct cci_data *)dev->client_object;
+ struct msm_camera_i2c_client *client = cci_client_obj->client;
+
+ index = buff[0];
+ /* pr_err("%s: index: %d\n", __func__, index); */
+ err = client->i2c_func_tbl->i2c_read_seq(client,
+ index, buff, len);
+ if (err < 0) {
+ pr_err("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+#endif
+ } else {
+#ifndef CAMERA_CCI
+ struct i2c_msg msg[1];
+ struct i2c_data *i2c_client_obj =
+ (struct i2c_data *)dev->client_object;
+ struct i2c_client *client =
+ (struct i2c_client *) i2c_client_obj->client;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = I2C_M_RD|client->flags;
+ msg[0].buf = buff;
+ msg[0].len = len;
+
+ err = i2c_transfer(client->adapter, &msg[0], 1);
+ /* return the actual mesage transfer */
+ if (err != 1) {
+ pr_err("%s: Read i2c_transfer err:%d, addr:0x%x\n",
+ __func__, err, client->addr);
+ return STATUS_FAIL;
+ }
+#endif
+ }
+
+ return 0;
+}
diff --git a/drivers/input/misc/vl53L0/stmvl53l0-cci.h b/drivers/input/misc/vl53L0/stmvl53l0-cci.h
new file mode 100644
index 000000000000..51477701cb1d
--- /dev/null
+++ b/drivers/input/misc/vl53L0/stmvl53l0-cci.h
@@ -0,0 +1,61 @@
+/*
+ * stmvl53l0-cci.h - Linux kernel modules for STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+/*
+ * Defines
+ */
+#ifndef STMVL53L0_CCI_H
+#define STMVL53L0_CCI_H
+#include <linux/types.h>
+
+#ifdef CAMERA_CCI
+#include <soc/qcom/camera2.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+#include "msm_cci.h"
+
+#define MSM_TOF_MAX_VREGS (10)
+
+struct msm_tof_vreg {
+ struct camera_vreg_t *cam_vreg;
+ void *data[MSM_TOF_MAX_VREGS];
+ int num_vreg;
+};
+
+struct cci_data {
+ struct msm_camera_i2c_client g_client;
+ struct msm_camera_i2c_client *client;
+ struct platform_device *pdev;
+ enum msm_camera_device_type_t device_type;
+ enum cci_i2c_master_t cci_master;
+ struct msm_tof_vreg vreg_cfg;
+ struct msm_sd_subdev msm_sd;
+ struct v4l2_subdev sdev;
+ struct v4l2_subdev_ops *subdev_ops;
+ char subdev_initialized;
+ uint32_t subdev_id;
+ uint8_t power_up;
+ struct msm_camera_gpio_conf *gconf;
+ struct msm_pinctrl_info pinctrl_info;
+ uint8_t cam_pinctrl_status;
+
+};
+int stmvl53l0_init_cci(void);
+void stmvl53l0_exit_cci(void *);
+int stmvl53l0_power_down_cci(void *);
+int stmvl53l0_power_up_cci(void *, unsigned int *);
+#endif /* CAMERA_CCI */
+#endif /* STMVL53L0_CCI_H */
diff --git a/drivers/input/misc/vl53L0/stmvl53l0-i2c.h b/drivers/input/misc/vl53L0/stmvl53l0-i2c.h
new file mode 100644
index 000000000000..51a02c60802b
--- /dev/null
+++ b/drivers/input/misc/vl53L0/stmvl53l0-i2c.h
@@ -0,0 +1,35 @@
+/*
+ * stmvl53l0-i2c.h - Linux kernel modules for STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+/*
+ * Defines
+ */
+#ifndef STMVL53L0_I2C_H
+#define STMVL53L0_I2C_H
+#include <linux/types.h>
+
+#ifndef CAMERA_CCI
+struct i2c_data {
+ struct i2c_client *client;
+ struct regulator *vana;
+ uint8_t power_up;
+};
+int stmvl53l0_init_i2c(void);
+void stmvl53l0_exit_i2c(void *);
+int stmvl53l0_power_up_i2c(void *, unsigned int *);
+int stmvl53l0_power_down_i2c(void *);
+
+#endif /* NOT CAMERA_CCI */
+#endif /* STMVL53L0_I2C_H */
diff --git a/drivers/input/misc/vl53L0/stmvl53l0.h b/drivers/input/misc/vl53L0/stmvl53l0.h
new file mode 100644
index 000000000000..ae517ebe461a
--- /dev/null
+++ b/drivers/input/misc/vl53L0/stmvl53l0.h
@@ -0,0 +1,217 @@
+/*
+ * stmvl53l0.h - Linux kernel modules for STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+/*
+ * Defines
+ */
+#ifndef STMVL53L0_H
+#define STMVL53L0_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+
+
+#define STMVL53L0_DRV_NAME "stmvl53l0"
+#define STMVL53L0_SLAVE_ADDR (0x52>>1)
+
+#define DRIVER_VERSION "1.0.5"
+#define I2C_M_WR 0x00
+/* #define INT_POLLING_DELAY 20 */
+
+/* if don't want to have output from vl53l0_dbgmsg, comment out #DEBUG macro */
+#define DEBUG
+#define vl53l0_dbgmsg(str, args...) \
+ pr_err("%s: " str, __func__, ##args)
+#define vl53l0_errmsg(str, args...) \
+ pr_err("%s: " str, __func__, ##args)
+
+#define VL53L0_VDD_MIN 2600000
+#define VL53L0_VDD_MAX 3000000
+
+typedef enum {
+ NORMAL_MODE = 0,
+ OFFSETCALIB_MODE = 1,
+ XTALKCALIB_MODE = 2,
+} init_mode_e;
+
+typedef enum {
+ OFFSET_PAR = 0,
+ XTALKRATE_PAR = 1,
+ XTALKENABLE_PAR = 2,
+ GPIOFUNC_PAR = 3,
+ LOWTHRESH_PAR = 4,
+ HIGHTHRESH_PAR = 5,
+ DEVICEMODE_PAR = 6,
+ INTERMEASUREMENT_PAR = 7,
+ REFERENCESPADS_PAR = 8,
+ REFCALIBRATION_PAR = 9,
+} parameter_name_e;
+
+enum {
+ CCI_BUS = 0,
+ I2C_BUS = 1,
+};
+
+/*
+ * IOCTL register data structs
+ */
+struct stmvl53l0_register {
+ uint32_t is_read; /*1: read 0: write*/
+ uint32_t reg_index;
+ uint32_t reg_bytes;
+ uint32_t reg_data;
+ int32_t status;
+};
+
+/*
+ * IOCTL parameter structs
+ */
+struct stmvl53l0_parameter {
+ uint32_t is_read; /*1: Get 0: Set*/
+ parameter_name_e name;
+ int32_t value;
+ int32_t value2;
+ int32_t status;
+};
+
+/*
+ * IOCTL Custom Use Case
+ */
+struct stmvl53l0_custom_use_case {
+ FixPoint1616_t signalRateLimit;
+ FixPoint1616_t sigmaLimit;
+ uint32_t preRangePulsePeriod;
+ uint32_t finalRangePulsePeriod;
+ uint32_t timingBudget;
+};
+
+
+/*
+ * driver data structs
+ */
+struct stmvl53l0_data {
+
+ /* !<embed ST VL53L0 Dev data as "dev_data" */
+ VL53L0_DevData_t Data;
+ /*!< i2c device address user specific field*/
+ uint8_t I2cDevAddr;
+ /*!< Type of comms : VL53L0_COMMS_I2C or VL53L0_COMMS_SPI */
+ uint8_t comms_type;
+ /*!< Comms speed [kHz] : typically 400kHz for I2C */
+ uint16_t comms_speed_khz;
+ /* CCI_BUS; I2C_BUS */
+ uint8_t bus_type;
+
+ void *client_object; /* cci or i2c client */
+
+ struct mutex update_lock;
+ struct delayed_work dwork; /* for PS work handler */
+ struct input_dev *input_dev_ps;
+ struct kobject *range_kobj;
+
+ const char *dev_name;
+ /* function pointer */
+
+ /* misc device */
+ struct miscdevice miscdev;
+
+ int irq;
+ unsigned int reset;
+
+ /* control flag from HAL */
+ unsigned int enable_ps_sensor;
+
+ /* PS parameters */
+ unsigned int ps_data; /* to store PS data */
+
+ /* Calibration parameters */
+ unsigned int offsetCalDistance;
+ unsigned int xtalkCalDistance;
+
+ /* Calibration values */
+ uint32_t refSpadCount;
+ uint8_t isApertureSpads;
+ uint8_t VhvSettings;
+ uint8_t PhaseCal;
+ int32_t OffsetMicroMeter;
+ FixPoint1616_t XTalkCompensationRateMegaCps;
+ uint32_t setCalibratedValue;
+
+ /* Custom values set by app */
+ FixPoint1616_t signalRateLimit;
+ FixPoint1616_t sigmaLimit;
+ uint32_t preRangePulsePeriod;
+ uint32_t finalRangePulsePeriod;
+
+
+ /* Range Data */
+ VL53L0_RangingMeasurementData_t rangeData;
+
+ /* Device parameters */
+ VL53L0_DeviceModes deviceMode;
+ uint32_t interMeasurems;
+ VL53L0_GpioFunctionality gpio_function;
+ VL53L0_InterruptPolarity gpio_polarity;
+ FixPoint1616_t low_threshold;
+ FixPoint1616_t high_threshold;
+
+ /* delay time in miniseconds*/
+ uint8_t delay_ms;
+
+ /* Timing Budget */
+ uint32_t timingBudget;
+ /* Use this threshold to force restart ranging */
+ uint32_t noInterruptCount;
+ /* Use this flag to denote use case*/
+ uint8_t useCase;
+ /* Use this flag to indicate an update of use case */
+ uint8_t updateUseCase;
+ /* Polling thread */
+ struct task_struct *poll_thread;
+ /* Wait Queue on which the poll thread blocks */
+ wait_queue_head_t poll_thread_wq;
+
+ /* Recent interrupt status */
+ uint32_t interruptStatus;
+
+ struct mutex work_mutex;
+
+ struct timer_list timer;
+ uint32_t flushCount;
+
+ /* Debug */
+ unsigned int enableDebug;
+ uint8_t interrupt_received;
+};
+
+/*
+ * function pointer structs
+ */
+struct stmvl53l0_module_fn_t {
+ int (*init)(void);
+ void (*deinit)(void *);
+ int (*power_up)(void *, unsigned int *);
+ int (*power_down)(void *);
+};
+
+
+
+int stmvl53l0_setup(struct stmvl53l0_data *data);
+void stmvl53l0_cleanup(struct stmvl53l0_data *data);
+
+#endif /* STMVL53L0_H */
diff --git a/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c b/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c
new file mode 100644
index 000000000000..e08edbcc73f9
--- /dev/null
+++ b/drivers/input/misc/vl53L0/stmvl53l0_module-cci.c
@@ -0,0 +1,509 @@
+/*
+ * stmvl53l0_module-cci.c - Linux kernel modules for STM VL53L0 FlightSense TOF
+ * sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+/*
+ * power specific includes
+ */
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/clk.h>
+#include <linux/of_gpio.h>
+/*
+ * API includes
+ */
+#include "vl53l0_api.h"
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+#include "stmvl53l0-cci.h"
+#include "stmvl53l0-i2c.h"
+#include "stmvl53l0.h"
+
+#ifdef CAMERA_CCI
+/*
+ * Global data
+ */
+static struct v4l2_file_operations msm_tof_v4l2_subdev_fops;
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+ .i2c_read = msm_camera_cci_i2c_read,
+ .i2c_read_seq = msm_camera_cci_i2c_read_seq,
+ .i2c_write = msm_camera_cci_i2c_write,
+ .i2c_write_seq = msm_camera_cci_i2c_write_seq,
+ .i2c_write_table = msm_camera_cci_i2c_write_table,
+ .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+ .i2c_write_table_w_microdelay =
+ msm_camera_cci_i2c_write_table_w_microdelay,
+ .i2c_util = msm_sensor_cci_i2c_util,
+ .i2c_poll = msm_camera_cci_i2c_poll,
+};
+
+static int stmvl53l0_get_dt_data(struct device *dev, struct cci_data *data);
+
+/*
+ * QCOM specific functions
+ */
+static int stmvl53l0_get_dt_data(struct device *dev, struct cci_data *data)
+{
+ int rc = 0;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ if (dev->of_node) {
+ struct device_node *of_node = dev->of_node;
+ struct msm_tof_vreg *vreg_cfg;
+
+ if (!of_node) {
+ vl53l0_errmsg("failed %d\n", __LINE__);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(of_node,
+ "cell-index", &data->pdev->id);
+ if (rc < 0) {
+ vl53l0_errmsg("failed %d\n", __LINE__);
+ return rc;
+ }
+ vl53l0_dbgmsg("cell-index: %d\n", data->pdev->id);
+ rc = of_property_read_u32(of_node, "qcom,cci-master",
+ &data->cci_master);
+ if (rc < 0) {
+ vl53l0_errmsg("failed %d\n", __LINE__);
+ /* Set default master 0 */
+ data->cci_master = MASTER_0;
+ rc = 0;
+ }
+ vl53l0_dbgmsg("cci_master: %d\n", data->cci_master);
+ if (of_find_property(of_node, "qcom,cam-vreg-name", NULL)) {
+ vreg_cfg = &data->vreg_cfg;
+ rc = msm_camera_get_dt_vreg_data(of_node,
+ &vreg_cfg->cam_vreg,
+ &vreg_cfg->num_vreg);
+ if (rc < 0) {
+ vl53l0_errmsg("failed %d\n", __LINE__);
+ return rc;
+ }
+ }
+ vl53l0_dbgmsg("vreg-name: %s min_volt: %d max_volt: %d",
+ vreg_cfg->cam_vreg->reg_name,
+ vreg_cfg->cam_vreg->min_voltage,
+ vreg_cfg->cam_vreg->max_voltage);
+
+ rc = msm_sensor_driver_get_gpio_data(&(data->gconf), of_node);
+ if ((rc < 0) || (data->gconf == NULL)) {
+ vl53l0_errmsg
+ ("No Laser Sensor GPIOs to be configured!\n");
+ }
+
+ }
+ vl53l0_dbgmsg("End rc =%d\n", rc);
+
+ return rc;
+}
+
+static int32_t stmvl53l0_vreg_control(struct cci_data *data, int config)
+{
+ int rc = 0, i, cnt;
+ struct msm_tof_vreg *vreg_cfg;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ vreg_cfg = &data->vreg_cfg;
+ cnt = vreg_cfg->num_vreg;
+ vl53l0_dbgmsg("num_vreg: %d\n", cnt);
+ if (!cnt) {
+ vl53l0_errmsg("failed %d\n", __LINE__);
+ return 0;
+ }
+
+ if (cnt >= MSM_TOF_MAX_VREGS) {
+ vl53l0_errmsg("failed %d cnt %d\n", __LINE__, cnt);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ rc = msm_camera_config_single_vreg(&(data->pdev->dev),
+ &vreg_cfg->cam_vreg[i],
+ (struct regulator **)
+ &vreg_cfg->data[i], config);
+ }
+
+ vl53l0_dbgmsg("EXIT rc =%d\n", rc);
+ return rc;
+}
+
+static int msm_tof_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ int rc = 0;
+/*
+ * struct msm_tof_ctrl_t *tof_ctrl = v4l2_get_subdevdata(sd);
+ * if (!tof_ctrl) {
+ * pr_err("failed\n");
+ * return -EINVAL;
+ * }
+ * if (tof_ctrl->tof_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+ * rc = tof_ctrl->i2c_client.i2c_func_tbl->i2c_util(
+ * &tof_ctrl->i2c_client, MSM_CCI_RELEASE);
+ * if (rc < 0)
+ * pr_err("cci_init failed\n");
+ * }
+ * tof_ctrl->i2c_state = TOF_I2C_RELEASE;
+ */
+ return rc;
+}
+
+static const struct v4l2_subdev_internal_ops msm_tof_internal_ops = {
+ .close = msm_tof_close,
+};
+
+static long msm_tof_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ vl53l0_dbgmsg("Subdev_ioctl not handled\n");
+ return 0;
+}
+
+static int32_t msm_tof_power(struct v4l2_subdev *sd, int on)
+{
+ vl53l0_dbgmsg("TOF power called\n");
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_tof_subdev_core_ops = {
+ .ioctl = msm_tof_subdev_ioctl,
+ .s_power = msm_tof_power,
+};
+
+static struct v4l2_subdev_ops msm_tof_subdev_ops = {
+ .core = &msm_tof_subdev_core_ops,
+};
+
+static int stmvl53l0_cci_init(struct cci_data *data)
+{
+ int rc = 0;
+ struct msm_camera_cci_client *cci_client = data->client->cci_client;
+
+ if (data->subdev_initialized == FALSE) {
+ data->client->i2c_func_tbl = &msm_sensor_cci_func_tbl;
+ data->client->cci_client =
+ kzalloc(sizeof(struct msm_camera_cci_client), GFP_KERNEL);
+ if (!data->client->cci_client) {
+ vl53l0_errmsg("%d, failed no memory\n", __LINE__);
+ return -ENOMEM;
+ }
+ cci_client = data->client->cci_client;
+ cci_client->cci_subdev = msm_cci_get_subdev();
+ if (cci_client->cci_subdev == NULL) {
+ vl53l0_errmsg("CCI subdev is not initialized!!\n");
+ return -ENODEV;
+ }
+ cci_client->cci_i2c_master = data->cci_master;
+ v4l2_subdev_init(&data->msm_sd.sd, data->subdev_ops);
+ v4l2_set_subdevdata(&data->msm_sd.sd, data);
+ data->msm_sd.sd.internal_ops = &msm_tof_internal_ops;
+ data->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(data->msm_sd.sd.name,
+ ARRAY_SIZE(data->msm_sd.sd.name), "msm_tof");
+ media_entity_init(&data->msm_sd.sd.entity, 0, NULL, 0);
+ data->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ data->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_TOF;
+ data->msm_sd.close_seq =
+ MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
+ msm_sd_register(&data->msm_sd);
+ msm_tof_v4l2_subdev_fops = v4l2_subdev_fops;
+ data->msm_sd.sd.devnode->fops =
+ &msm_tof_v4l2_subdev_fops;
+ data->subdev_initialized = TRUE;
+ }
+
+ cci_client->sid = 0x29;
+ cci_client->retries = 3;
+ cci_client->id_map = 0;
+ cci_client->cci_i2c_master = data->cci_master;
+ rc = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_INIT);
+ if (rc < 0) {
+ vl53l0_errmsg("%d: CCI Init failed\n", __LINE__);
+ return rc;
+ }
+ vl53l0_dbgmsg("CCI Init Succeeded\n");
+
+ data->client->addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+
+ return 0;
+}
+
+static int32_t stmvl53l0_platform_probe(struct platform_device *pdev)
+{
+ struct stmvl53l0_data *vl53l0_data = NULL;
+ struct cci_data *cci_object = NULL;
+ int32_t rc = 0;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ if (!pdev->dev.of_node) {
+ vl53l0_errmsg("of_node NULL\n");
+ return -EINVAL;
+ }
+
+ vl53l0_data = kzalloc(sizeof(struct stmvl53l0_data), GFP_KERNEL);
+ if (!vl53l0_data) {
+ rc = -ENOMEM;
+ return rc;
+ }
+ if (vl53l0_data) {
+ vl53l0_data->client_object =
+ kzalloc(sizeof(struct cci_data), GFP_KERNEL);
+ cci_object = (struct cci_data *)vl53l0_data->client_object;
+ }
+ cci_object->client =
+ (struct msm_camera_i2c_client *)&cci_object->g_client;
+
+ /* setup bus type */
+ vl53l0_data->bus_type = CCI_BUS;
+
+ /* Set platform device handle */
+ cci_object->subdev_ops = &msm_tof_subdev_ops;
+ cci_object->pdev = pdev;
+ rc = stmvl53l0_get_dt_data(&pdev->dev, cci_object);
+ if (rc < 0) {
+ vl53l0_errmsg("%d, failed rc %d\n", __LINE__, rc);
+ return rc;
+ }
+ cci_object->subdev_id = pdev->id;
+
+ /* Set device type as platform device */
+ cci_object->device_type = MSM_CAMERA_PLATFORM_DEVICE;
+ cci_object->subdev_initialized = FALSE;
+
+ /* setup device name */
+ vl53l0_data->dev_name = dev_name(&pdev->dev);
+
+ /* setup device data */
+ dev_set_drvdata(&pdev->dev, vl53l0_data);
+
+ /* setup other stuff */
+ rc = stmvl53l0_setup(vl53l0_data);
+
+ /* init default value */
+ cci_object->power_up = 0;
+
+ vl53l0_dbgmsg("End\n");
+
+ return rc;
+
+}
+
+static int32_t stmvl53l0_platform_remove(struct platform_device *pdev)
+{
+ struct stmvl53l0_data *vl53l0_data = platform_get_drvdata(pdev);
+
+ stmvl53l0_cleanup(vl53l0_data);
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(vl53l0_data->client_object);
+ kfree(vl53l0_data);
+
+ return 0;
+}
+
+static const struct of_device_id st_stmvl53l0_dt_match[] = {
+ {.compatible = "st,stmvl53l0",},
+ {},
+};
+
+static struct platform_driver stmvl53l0_platform_driver = {
+ .probe = stmvl53l0_platform_probe,
+ .remove = stmvl53l0_platform_remove,
+ .driver = {
+ .name = STMVL53L0_DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = st_stmvl53l0_dt_match,
+ },
+};
+
+int stmvl53l0_power_up_cci(void *cci_object, unsigned int *preset_flag)
+{
+ int ret = 0;
+ struct cci_data *data = (struct cci_data *)cci_object;
+ struct gpio *gpio_tbl = NULL;
+ uint8_t gpio_tbl_size = 0;
+ int i = 0;
+
+ vl53l0_dbgmsg("Enter");
+
+ /* need to init cci first */
+ ret = stmvl53l0_cci_init(data);
+ if (ret) {
+ vl53l0_errmsg("stmvl53l0_cci_init failed %d\n", __LINE__);
+ return ret;
+ }
+
+ /* Check if GPIO needs to be enabled for chip select */
+ vl53l0_dbgmsg("Get gpio table!size: %d\n",
+ data->gconf->cam_gpio_req_tbl_size);
+ gpio_tbl = data->gconf->cam_gpio_req_tbl;
+ gpio_tbl_size = data->gconf->cam_gpio_req_tbl_size;
+ if (gpio_tbl_size > 0) {
+ ret = msm_camera_pinctrl_init(&(data->pinctrl_info),
+ &(data->pdev->dev));
+ if (ret < 0) {
+ vl53l0_errmsg("Initialization of pinctrl failed\n");
+ data->cam_pinctrl_status = 0;
+ } else {
+ data->cam_pinctrl_status = 1;
+ }
+
+ for (i = 0; i < gpio_tbl_size; i++) {
+ ret = gpio_request_one(gpio_tbl[i].gpio,
+ gpio_tbl[i].flags,
+ gpio_tbl[i].label);
+ if (ret < 0) {
+ vl53l0_errmsg
+ ("Request for GPIO %d failed! Err: %d\n",
+ gpio_tbl[i].gpio, ret);
+ } else {
+ if (data->cam_pinctrl_status) {
+ ret =
+ pinctrl_select_state(
+ data->pinctrl_info.pinctrl,
+ data->pinctrl_info.gpio_state_active);
+ if (ret < 0) {
+ vl53l0_errmsg(
+ "%s: Cannot set pin to active state!\n",
+ __func__);
+ }
+ }
+ vl53l0_dbgmsg("Set pin %d value to 1!\n",
+ gpio_tbl[i].gpio);
+ gpio_set_value_cansleep(gpio_tbl[i].gpio, 1);
+ }
+ }
+ }
+
+ /* actual power up */
+ if (data && data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+ ret = stmvl53l0_vreg_control(data, 1);
+ if (ret < 0) {
+ vl53l0_errmsg("stmvl53l0_vreg_control failed %d\n",
+ __LINE__);
+ return ret;
+ }
+ }
+ data->power_up = 1;
+ *preset_flag = 1;
+ vl53l0_dbgmsg("End\n");
+
+ return ret;
+}
+
+int stmvl53l0_power_down_cci(void *cci_object)
+{
+ int ret = 0;
+ struct cci_data *data = (struct cci_data *)cci_object;
+ int i = 0;
+ struct gpio *gpio_tbl = NULL;
+ uint8_t gpio_tbl_size = 0;
+
+ vl53l0_dbgmsg("Enter\n");
+ if (data->power_up) {
+ /* need to release cci first */
+ ret = data->client->i2c_func_tbl->i2c_util(data->client,
+ MSM_CCI_RELEASE);
+ if (ret < 0)
+ vl53l0_errmsg("CCI Release failed rc %d\n", ret);
+
+ /* actual power down */
+ if (data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+ ret = stmvl53l0_vreg_control(data, 0);
+ if (ret < 0) {
+ vl53l0_errmsg
+ ("stmvl53l0_vreg_control failed %d\n",
+ __LINE__);
+ return ret;
+ }
+ }
+
+ /* reset GPIO pins */
+ gpio_tbl = data->gconf->cam_gpio_req_tbl;
+ gpio_tbl_size = data->gconf->cam_gpio_req_tbl_size;
+ if (gpio_tbl_size > 0) {
+ for (i = 0; i < gpio_tbl_size; i++)
+ gpio_set_value_cansleep(gpio_tbl[i].gpio, 0);
+ if (data->cam_pinctrl_status) {
+ ret =
+ pinctrl_select_state(data->pinctrl_info.
+ pinctrl,
+ data->pinctrl_info.
+ gpio_state_suspend);
+ if (ret < 0) {
+ vl53l0_errmsg(
+ "Error setting gpio pin to supsend state!\n");
+ }
+
+ devm_pinctrl_put(data->pinctrl_info.pinctrl);
+ data->cam_pinctrl_status = 0;
+ gpio_free_array(gpio_tbl, gpio_tbl_size);
+ }
+ }
+ }
+ data->power_up = 0;
+ vl53l0_dbgmsg("End\n");
+ return ret;
+}
+
+int stmvl53l0_init_cci(void)
+{
+ int ret = 0;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* register as a platform device */
+ ret = platform_driver_register(&stmvl53l0_platform_driver);
+ if (ret)
+ vl53l0_errmsg("%d, error ret:%d\n", __LINE__, ret);
+
+ vl53l0_dbgmsg("End\n");
+
+ return ret;
+}
+
+void stmvl53l0_exit_cci(void *cci_object)
+{
+ struct cci_data *data = (struct cci_data *)cci_object;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ if (data && data->client->cci_client)
+ kfree(data->client->cci_client);
+
+ vl53l0_dbgmsg("End\n");
+}
+#endif /* end of CAMERA_CCI */
diff --git a/drivers/input/misc/vl53L0/stmvl53l0_module-i2c.c b/drivers/input/misc/vl53L0/stmvl53l0_module-i2c.c
new file mode 100644
index 000000000000..0bff754de15b
--- /dev/null
+++ b/drivers/input/misc/vl53L0/stmvl53l0_module-i2c.c
@@ -0,0 +1,266 @@
+/*
+ * stmvl53l0_module-i2c.c - Linux kernel modules for STM VL53L0 FlightSense TOF
+ * sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+/*
+ * power specific includes
+ */
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/clk.h>
+#include <linux/of_gpio.h>
+/*
+ * API includes
+ */
+#include "vl53l0_api.h"
+#include "vl53l0_def.h"
+#include "vl53l0_platform.h"
+#include "stmvl53l0-i2c.h"
+#include "stmvl53l0-cci.h"
+#include "stmvl53l0.h"
+#ifndef CAMERA_CCI
+
+/*
+ * Global data
+ */
+static int stmvl53l0_parse_vdd(struct device *dev, struct i2c_data *data);
+
+/*
+ * QCOM specific functions
+ */
+static int stmvl53l0_parse_vdd(struct device *dev, struct i2c_data *data)
+{
+ int ret = 0;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ if (dev->of_node) {
+ data->vana = regulator_get(dev, "vdd");
+ if (IS_ERR(data->vana)) {
+ vl53l0_errmsg("vdd supply is not provided\n");
+ ret = -1;
+ }
+ }
+ vl53l0_dbgmsg("End\n");
+
+ return ret;
+}
+
+static int stmvl53l0_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct stmvl53l0_data *vl53l0_data = NULL;
+ struct i2c_data *i2c_object = NULL;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
+ rc = -EIO;
+ return rc;
+ }
+
+ vl53l0_data = kzalloc(sizeof(struct stmvl53l0_data), GFP_KERNEL);
+ if (!vl53l0_data) {
+ rc = -ENOMEM;
+ return rc;
+ }
+ if (vl53l0_data) {
+ vl53l0_data->client_object =
+ kzalloc(sizeof(struct i2c_data), GFP_KERNEL);
+ i2c_object = (struct i2c_data *)vl53l0_data->client_object;
+ }
+ i2c_object->client = client;
+
+ /* setup bus type */
+ vl53l0_data->bus_type = I2C_BUS;
+
+ /* setup regulator */
+ stmvl53l0_parse_vdd(&i2c_object->client->dev, i2c_object);
+
+ /* setup device name */
+ vl53l0_data->dev_name = dev_name(&client->dev);
+
+ /* setup device data */
+ dev_set_drvdata(&client->dev, vl53l0_data);
+
+ /* setup client data */
+ i2c_set_clientdata(client, vl53l0_data);
+
+ /* setup other stuff */
+ rc = stmvl53l0_setup(vl53l0_data);
+
+ /* init default value */
+ i2c_object->power_up = 0;
+
+ vl53l0_dbgmsg("End\n");
+ return rc;
+}
+
+static int stmvl53l0_remove(struct i2c_client *client)
+{
+ struct stmvl53l0_data *data = i2c_get_clientdata(client);
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* Power down the device */
+ stmvl53l0_power_down_i2c(data->client_object);
+ stmvl53l0_cleanup(data);
+ kfree(data->client_object);
+ kfree(data);
+ vl53l0_dbgmsg("End\n");
+ return 0;
+}
+
+static const struct i2c_device_id stmvl53l0_id[] = {
+ {STMVL53L0_DRV_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, stmvl53l0_id);
+
+static const struct of_device_id st_stmvl53l0_dt_match[] = {
+ {.compatible = "st,stmvl53l0",},
+ {},
+};
+
+static struct i2c_driver stmvl53l0_driver = {
+ .driver = {
+ .name = STMVL53L0_DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = st_stmvl53l0_dt_match,
+ },
+ .probe = stmvl53l0_probe,
+ .remove = stmvl53l0_remove,
+ .id_table = stmvl53l0_id,
+
+};
+
+int stmvl53l0_power_up_i2c(void *i2c_object, unsigned int *preset_flag)
+{
+ int ret = 0;
+#ifndef STM_TEST
+ struct i2c_data *data = (struct i2c_data *)i2c_object;
+#endif
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* actual power on */
+#ifndef STM_TEST
+ ret = regulator_set_voltage(data->vana, VL53L0_VDD_MIN, VL53L0_VDD_MAX);
+ if (ret < 0) {
+ vl53l0_errmsg("set_vol(%p) fail %d\n", data->vana, ret);
+ return ret;
+ }
+ ret = regulator_enable(data->vana);
+
+ usleep_range(2950, 3000);
+ if (ret < 0) {
+ vl53l0_errmsg("reg enable(%p) failed.rc=%d\n", data->vana, ret);
+ return ret;
+ }
+ data->power_up = 1;
+ *preset_flag = 1;
+#endif
+
+ vl53l0_dbgmsg("End\n");
+ return ret;
+}
+
+int stmvl53l0_power_down_i2c(void *i2c_object)
+{
+ int ret = 0;
+#ifndef STM_TEST
+ struct i2c_data *data = (struct i2c_data *)i2c_object;
+#endif
+
+ vl53l0_dbgmsg("Enter\n");
+#ifndef STM_TEST
+ usleep_range(2950, 3000);
+ ret = regulator_disable(data->vana);
+ if (ret < 0)
+ vl53l0_errmsg("reg disable(%p) failed.rc=%d\n",
+ data->vana, ret);
+
+ data->power_up = 0;
+#endif
+
+ vl53l0_dbgmsg("End\n");
+ return ret;
+}
+
+int stmvl53l0_init_i2c(void)
+{
+ int ret = 0;
+
+#ifdef STM_TEST
+ struct i2c_client *client = NULL;
+ struct i2c_adapter *adapter;
+ struct i2c_board_info info = {
+ .type = "stmvl53l0",
+ .addr = STMVL53L0_SLAVE_ADDR,
+ };
+#endif
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* register as a i2c client device */
+ ret = i2c_add_driver(&stmvl53l0_driver);
+ if (ret)
+ vl53l0_errmsg("%d erro ret:%d\n", __LINE__, ret);
+
+#ifdef STM_TEST
+ if (!ret) {
+ adapter = i2c_get_adapter(4);
+ if (!adapter)
+ ret = -EINVAL;
+ else
+ client = i2c_new_device(adapter, &info);
+ if (!client)
+ ret = -EINVAL;
+ }
+#endif
+
+ vl53l0_dbgmsg("End with rc:%d\n", ret);
+
+ return ret;
+}
+
+void stmvl53l0_exit_i2c(void *i2c_object)
+{
+ vl53l0_dbgmsg("Enter\n");
+ i2c_del_driver(&stmvl53l0_driver);
+
+ vl53l0_dbgmsg("End\n");
+}
+
+#endif /* end of NOT CAMERA_CCI */
diff --git a/drivers/input/misc/vl53L0/stmvl53l0_module.c b/drivers/input/misc/vl53L0/stmvl53l0_module.c
new file mode 100644
index 000000000000..f242e5f497d0
--- /dev/null
+++ b/drivers/input/misc/vl53L0/stmvl53l0_module.c
@@ -0,0 +1,2878 @@
+/*
+ * stmvl53l0_module.c - Linux kernel modules for STM VL53L0 FlightSense TOF
+ * sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/kthread.h>
+/*
+ * API includes
+ */
+#include "vl53l0_api.h"
+#include "vl53l010_api.h"
+
+/*#define USE_INT */
+#define IRQ_NUM 59
+/* #define DEBUG_TIME_LOG */
+#ifdef DEBUG_TIME_LOG
+struct timeval start_tv, stop_tv;
+#endif
+
+/*
+ * Global data
+ */
+
+#ifdef CAMERA_CCI
+static struct stmvl53l0_module_fn_t stmvl53l0_module_func_tbl = {
+ .init = stmvl53l0_init_cci,
+ .deinit = stmvl53l0_exit_cci,
+ .power_up = stmvl53l0_power_up_cci,
+ .power_down = stmvl53l0_power_down_cci,
+};
+#else
+static struct stmvl53l0_module_fn_t stmvl53l0_module_func_tbl = {
+ .init = stmvl53l0_init_i2c,
+ .deinit = stmvl53l0_exit_i2c,
+ .power_up = stmvl53l0_power_up_i2c,
+ .power_down = stmvl53l0_power_down_i2c,
+};
+#endif
+struct stmvl53l0_module_fn_t *pmodule_func_tbl;
+
+struct stmvl53l0_api_fn_t {
+ int8_t (*GetVersion)(VL53L0_Version_t *pVersion);
+ int8_t (*GetPalSpecVersion)(VL53L0_Version_t *pPalSpecVersion);
+
+ int8_t (*GetProductRevision)(VL53L0_DEV Dev,
+ uint8_t *pProductRevisionMajor,
+ uint8_t *pProductRevisionMinor);
+ int8_t (*GetDeviceInfo)(VL53L0_DEV Dev,
+ VL53L0_DeviceInfo_t *pVL53L0_DeviceInfo);
+ int8_t (*GetDeviceErrorStatus)(VL53L0_DEV Dev,
+ VL53L0_DeviceError *pDeviceErrorStatus);
+ int8_t (*GetRangeStatusString)(uint8_t RangeStatus,
+ char *pRangeStatusString);
+ int8_t (*GetDeviceErrorString)(VL53L0_DeviceError ErrorCode,
+ char *pDeviceErrorString);
+ int8_t (*GetPalErrorString)(VL53L0_Error PalErrorCode,
+ char *pPalErrorString);
+ int8_t (*GetPalStateString)(VL53L0_State PalStateCode,
+ char *pPalStateString);
+ int8_t (*GetPalState)(VL53L0_DEV Dev, VL53L0_State *pPalState);
+ int8_t (*SetPowerMode)(VL53L0_DEV Dev,
+ VL53L0_PowerModes PowerMode);
+ int8_t (*GetPowerMode)(VL53L0_DEV Dev,
+ VL53L0_PowerModes *pPowerMode);
+ int8_t (*SetOffsetCalibrationDataMicroMeter)(VL53L0_DEV Dev,
+ int32_t OffsetCalibrationDataMicroMeter);
+ int8_t (*GetOffsetCalibrationDataMicroMeter)(VL53L0_DEV Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter);
+ int8_t (*SetLinearityCorrectiveGain)(VL53L0_DEV Dev,
+ int16_t LinearityCorrectiveGain);
+ int8_t (*GetLinearityCorrectiveGain)(VL53L0_DEV Dev,
+ uint16_t *pLinearityCorrectiveGain);
+ int8_t (*SetGroupParamHold)(VL53L0_DEV Dev,
+ uint8_t GroupParamHold);
+ int8_t (*GetUpperLimitMilliMeter)(VL53L0_DEV Dev,
+ uint16_t *pUpperLimitMilliMeter);
+ int8_t (*SetDeviceAddress)(VL53L0_DEV Dev,
+ uint8_t DeviceAddress);
+ int8_t (*DataInit)(VL53L0_DEV Dev);
+ int8_t (*SetTuningSettingBuffer)(VL53L0_DEV Dev,
+ uint8_t *pTuningSettingBuffer,
+ uint8_t UseInternalTuningSettings);
+ int8_t (*GetTuningSettingBuffer)(VL53L0_DEV Dev,
+ uint8_t **pTuningSettingBuffer,
+ uint8_t *pUseInternalTuningSettings);
+ int8_t (*StaticInit)(VL53L0_DEV Dev);
+ int8_t (*WaitDeviceBooted)(VL53L0_DEV Dev);
+ int8_t (*ResetDevice)(VL53L0_DEV Dev);
+ int8_t (*SetDeviceParameters)(VL53L0_DEV Dev,
+ const VL53L0_DeviceParameters_t *pDeviceParameters);
+ int8_t (*GetDeviceParameters)(VL53L0_DEV Dev,
+ VL53L0_DeviceParameters_t *pDeviceParameters);
+ int8_t (*SetDeviceMode)(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode);
+ int8_t (*GetDeviceMode)(VL53L0_DEV Dev,
+ VL53L0_DeviceModes *pDeviceMode);
+ int8_t (*SetHistogramMode)(VL53L0_DEV Dev,
+ VL53L0_HistogramModes HistogramMode);
+ int8_t (*GetHistogramMode)(VL53L0_DEV Dev,
+ VL53L0_HistogramModes *pHistogramMode);
+ int8_t (*SetMeasurementTimingBudgetMicroSeconds)(VL53L0_DEV Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds);
+ int8_t (*GetMeasurementTimingBudgetMicroSeconds)(
+ VL53L0_DEV Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds);
+ int8_t (*GetVcselPulsePeriod)(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType,
+ uint8_t *pVCSELPulsePeriod);
+ int8_t (*SetVcselPulsePeriod)(VL53L0_DEV Dev,
+ VL53L0_VcselPeriod VcselPeriodType,
+ uint8_t VCSELPulsePeriod);
+ int8_t (*SetSequenceStepEnable)(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ uint8_t SequenceStepEnabled);
+ int8_t (*GetSequenceStepEnable)(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ uint8_t *pSequenceStepEnabled);
+ int8_t (*GetSequenceStepEnables)(VL53L0_DEV Dev,
+ VL53L0_SchedulerSequenceSteps_t *pSchedulerSequenceSteps);
+ int8_t (*SetSequenceStepTimeout)(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ FixPoint1616_t TimeOutMilliSecs);
+ int8_t (*GetSequenceStepTimeout)(VL53L0_DEV Dev,
+ VL53L0_SequenceStepId SequenceStepId,
+ FixPoint1616_t *pTimeOutMilliSecs);
+ int8_t (*GetNumberOfSequenceSteps)(VL53L0_DEV Dev,
+ uint8_t *pNumberOfSequenceSteps);
+ int8_t (*GetSequenceStepsInfo)(
+ VL53L0_SequenceStepId SequenceStepId,
+ char *pSequenceStepsString);
+ int8_t (*SetInterMeasurementPeriodMilliSeconds)(
+ VL53L0_DEV Dev,
+ uint32_t InterMeasurementPeriodMilliSeconds);
+ int8_t (*GetInterMeasurementPeriodMilliSeconds)(
+ VL53L0_DEV Dev,
+ uint32_t *pInterMeasurementPeriodMilliSeconds);
+ int8_t (*SetXTalkCompensationEnable)(VL53L0_DEV Dev,
+ uint8_t XTalkCompensationEnable);
+ int8_t (*GetXTalkCompensationEnable)(VL53L0_DEV Dev,
+ uint8_t *pXTalkCompensationEnable);
+ int8_t (*SetXTalkCompensationRateMegaCps)(
+ VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCompensationRateMegaCps);
+ int8_t (*GetXTalkCompensationRateMegaCps)(
+ VL53L0_DEV Dev,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps);
+ int8_t (*GetNumberOfLimitCheck)(
+ uint16_t *pNumberOfLimitCheck);
+ int8_t (*GetLimitCheckInfo)(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, char *pLimitCheckString);
+ int8_t (*SetLimitCheckEnable)(VL53L0_DEV Dev,
+ uint16_t LimitCheckId,
+ uint8_t LimitCheckEnable);
+ int8_t (*GetLimitCheckEnable)(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckEnable);
+ int8_t (*SetLimitCheckValue)(VL53L0_DEV Dev,
+ uint16_t LimitCheckId,
+ FixPoint1616_t LimitCheckValue);
+ int8_t (*GetLimitCheckValue)(VL53L0_DEV Dev,
+ uint16_t LimitCheckId,
+ FixPoint1616_t *pLimitCheckValue);
+ int8_t (*GetLimitCheckCurrent)(VL53L0_DEV Dev,
+ uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckCurrent);
+ int8_t (*SetWrapAroundCheckEnable)(VL53L0_DEV Dev,
+ uint8_t WrapAroundCheckEnable);
+ int8_t (*GetWrapAroundCheckEnable)(VL53L0_DEV Dev,
+ uint8_t *pWrapAroundCheckEnable);
+ int8_t (*PerformSingleMeasurement)(VL53L0_DEV Dev);
+ int8_t (*PerformRefCalibration)(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+ int8_t (*SetRefCalibration)(VL53L0_DEV Dev,
+ uint8_t VhvSettings,
+ uint8_t PhaseCal);
+ int8_t (*GetRefCalibration)(VL53L0_DEV Dev,
+ uint8_t *pVhvSettings,
+ uint8_t *pPhaseCal);
+ int8_t (*PerformXTalkCalibration)(VL53L0_DEV Dev,
+ FixPoint1616_t XTalkCalDistance,
+ FixPoint1616_t *pXTalkCompensationRateMegaCps);
+ int8_t (*PerformOffsetCalibration)(VL53L0_DEV Dev,
+ FixPoint1616_t CalDistanceMilliMeter,
+ int32_t *pOffsetMicroMeter);
+ int8_t (*StartMeasurement)(VL53L0_DEV Dev);
+ int8_t (*StopMeasurement)(VL53L0_DEV Dev);
+ int8_t (*GetMeasurementDataReady)(VL53L0_DEV Dev,
+ uint8_t *pMeasurementDataReady);
+ int8_t (*WaitDeviceReadyForNewMeasurement)(VL53L0_DEV Dev,
+ uint32_t MaxLoop);
+ int8_t (*GetRangingMeasurementData)(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData);
+ int8_t (*GetHistogramMeasurementData)(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+ int8_t (*PerformSingleRangingMeasurement)(VL53L0_DEV Dev,
+ VL53L0_RangingMeasurementData_t *pRangingMeasurementData);
+ int8_t (*PerformSingleHistogramMeasurement)(VL53L0_DEV Dev,
+ VL53L0_HistogramMeasurementData_t *pHistogramMeasurementData);
+ int8_t (*SetNumberOfROIZones)(VL53L0_DEV Dev,
+ uint8_t NumberOfROIZones);
+ int8_t (*GetNumberOfROIZones)(VL53L0_DEV Dev,
+ uint8_t *pNumberOfROIZones);
+ int8_t (*GetMaxNumberOfROIZones)(VL53L0_DEV Dev,
+ uint8_t *pMaxNumberOfROIZones);
+ int8_t (*SetGpioConfig)(VL53L0_DEV Dev,
+ uint8_t Pin,
+ VL53L0_DeviceModes DeviceMode,
+ VL53L0_GpioFunctionality Functionality,
+ VL53L0_InterruptPolarity Polarity);
+ int8_t (*GetGpioConfig)(VL53L0_DEV Dev,
+ uint8_t Pin,
+ VL53L0_DeviceModes *pDeviceMode,
+ VL53L0_GpioFunctionality *pFunctionality,
+ VL53L0_InterruptPolarity *pPolarity);
+ int8_t (*SetInterruptThresholds)(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode,
+ FixPoint1616_t ThresholdLow,
+ FixPoint1616_t ThresholdHigh);
+ int8_t (*GetInterruptThresholds)(VL53L0_DEV Dev,
+ VL53L0_DeviceModes DeviceMode,
+ FixPoint1616_t *pThresholdLow,
+ FixPoint1616_t *pThresholdHigh);
+ int8_t (*ClearInterruptMask)(VL53L0_DEV Dev,
+ uint32_t InterruptMask);
+ int8_t (*GetInterruptMaskStatus)(VL53L0_DEV Dev,
+ uint32_t *pInterruptMaskStatus);
+ int8_t (*EnableInterruptMask)(VL53L0_DEV Dev, uint32_t InterruptMask);
+ int8_t (*SetSpadAmbientDamperThreshold)(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperThreshold);
+ int8_t (*GetSpadAmbientDamperThreshold)(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperThreshold);
+ int8_t (*SetSpadAmbientDamperFactor)(VL53L0_DEV Dev,
+ uint16_t SpadAmbientDamperFactor);
+ int8_t (*GetSpadAmbientDamperFactor)(VL53L0_DEV Dev,
+ uint16_t *pSpadAmbientDamperFactor);
+ int8_t (*PerformRefSpadManagement)(VL53L0_DEV Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+ int8_t (*SetReferenceSpads)(VL53L0_DEV Dev,
+ uint32_t count, uint8_t isApertureSpads);
+ int8_t (*GetReferenceSpads)(VL53L0_DEV Dev,
+ uint32_t *pSpadCount, uint8_t *pIsApertureSpads);
+};
+
+static struct stmvl53l0_api_fn_t stmvl53l0_api_func_tbl = {
+ .GetVersion = VL53L0_GetVersion,
+ .GetPalSpecVersion = VL53L0_GetPalSpecVersion,
+ .GetProductRevision = VL53L0_GetProductRevision,
+ .GetDeviceInfo = VL53L0_GetDeviceInfo,
+ .GetDeviceErrorStatus = VL53L0_GetDeviceErrorStatus,
+ .GetRangeStatusString = VL53L0_GetRangeStatusString,
+ .GetDeviceErrorString = VL53L0_GetDeviceErrorString,
+ .GetPalErrorString = VL53L0_GetPalErrorString,
+ .GetPalState = VL53L0_GetPalState,
+ .SetPowerMode = VL53L0_SetPowerMode,
+ .GetPowerMode = VL53L0_GetPowerMode,
+ .SetOffsetCalibrationDataMicroMeter =
+ VL53L0_SetOffsetCalibrationDataMicroMeter,
+ .SetLinearityCorrectiveGain =
+ VL53L0_SetLinearityCorrectiveGain,
+ .GetLinearityCorrectiveGain =
+ VL53L0_GetLinearityCorrectiveGain,
+ .GetOffsetCalibrationDataMicroMeter =
+ VL53L0_GetOffsetCalibrationDataMicroMeter,
+ .SetGroupParamHold = VL53L0_SetGroupParamHold,
+ .GetUpperLimitMilliMeter = VL53L0_GetUpperLimitMilliMeter,
+ .SetDeviceAddress = VL53L0_SetDeviceAddress,
+ .DataInit = VL53L0_DataInit,
+ .SetTuningSettingBuffer = VL53L0_SetTuningSettingBuffer,
+ .GetTuningSettingBuffer = VL53L0_GetTuningSettingBuffer,
+ .StaticInit = VL53L0_StaticInit,
+ .WaitDeviceBooted = VL53L0_WaitDeviceBooted,
+ .ResetDevice = VL53L0_ResetDevice,
+ .SetDeviceParameters = VL53L0_SetDeviceParameters,
+ .SetDeviceMode = VL53L0_SetDeviceMode,
+ .GetDeviceMode = VL53L0_GetDeviceMode,
+ .SetHistogramMode = VL53L0_SetHistogramMode,
+ .GetHistogramMode = VL53L0_GetHistogramMode,
+ .SetMeasurementTimingBudgetMicroSeconds =
+ VL53L0_SetMeasurementTimingBudgetMicroSeconds,
+ .GetMeasurementTimingBudgetMicroSeconds =
+ VL53L0_GetMeasurementTimingBudgetMicroSeconds,
+ .GetVcselPulsePeriod = VL53L0_GetVcselPulsePeriod,
+ .SetVcselPulsePeriod = VL53L0_SetVcselPulsePeriod,
+ .SetSequenceStepEnable = VL53L0_SetSequenceStepEnable,
+ .GetSequenceStepEnable = VL53L0_GetSequenceStepEnable,
+ .GetSequenceStepEnables = VL53L0_GetSequenceStepEnables,
+ .SetSequenceStepTimeout = VL53L0_SetSequenceStepTimeout,
+ .GetSequenceStepTimeout = VL53L0_GetSequenceStepTimeout,
+ .GetNumberOfSequenceSteps = VL53L0_GetNumberOfSequenceSteps,
+ .GetSequenceStepsInfo = VL53L0_GetSequenceStepsInfo,
+ .SetInterMeasurementPeriodMilliSeconds =
+ VL53L0_SetInterMeasurementPeriodMilliSeconds,
+ .GetInterMeasurementPeriodMilliSeconds =
+ VL53L0_GetInterMeasurementPeriodMilliSeconds,
+ .SetXTalkCompensationEnable = VL53L0_SetXTalkCompensationEnable,
+ .GetXTalkCompensationEnable = VL53L0_GetXTalkCompensationEnable,
+ .SetXTalkCompensationRateMegaCps =
+ VL53L0_SetXTalkCompensationRateMegaCps,
+ .GetXTalkCompensationRateMegaCps =
+ VL53L0_GetXTalkCompensationRateMegaCps,
+ .GetNumberOfLimitCheck = VL53L0_GetNumberOfLimitCheck,
+ .GetLimitCheckInfo = VL53L0_GetLimitCheckInfo,
+ .SetLimitCheckEnable = VL53L0_SetLimitCheckEnable,
+ .GetLimitCheckEnable = VL53L0_GetLimitCheckEnable,
+ .SetLimitCheckValue = VL53L0_SetLimitCheckValue,
+ .GetLimitCheckValue = VL53L0_GetLimitCheckValue,
+ .GetLimitCheckCurrent = VL53L0_GetLimitCheckCurrent,
+ .SetWrapAroundCheckEnable = VL53L0_SetWrapAroundCheckEnable,
+ .GetWrapAroundCheckEnable = VL53L0_GetWrapAroundCheckEnable,
+ .PerformSingleMeasurement = VL53L0_PerformSingleMeasurement,
+ .PerformRefCalibration = VL53L0_PerformRefCalibration,
+ .SetRefCalibration = VL53L0_SetRefCalibration,
+ .GetRefCalibration = VL53L0_GetRefCalibration,
+ .PerformXTalkCalibration = VL53L0_PerformXTalkCalibration,
+ .PerformOffsetCalibration = VL53L0_PerformOffsetCalibration,
+ .StartMeasurement = VL53L0_StartMeasurement,
+ .StopMeasurement = VL53L0_StopMeasurement,
+ .GetMeasurementDataReady = VL53L0_GetMeasurementDataReady,
+ .WaitDeviceReadyForNewMeasurement =
+ VL53L0_WaitDeviceReadyForNewMeasurement,
+ .GetRangingMeasurementData = VL53L0_GetRangingMeasurementData,
+ .GetHistogramMeasurementData = VL53L0_GetHistogramMeasurementData,
+ .PerformSingleRangingMeasurement =
+ VL53L0_PerformSingleRangingMeasurement,
+ .PerformSingleHistogramMeasurement =
+ VL53L0_PerformSingleHistogramMeasurement,
+ .SetNumberOfROIZones = VL53L0_SetNumberOfROIZones,
+ .GetNumberOfROIZones = VL53L0_GetNumberOfROIZones,
+ .GetMaxNumberOfROIZones = VL53L0_GetMaxNumberOfROIZones,
+ .SetGpioConfig = VL53L0_SetGpioConfig,
+ .GetGpioConfig = VL53L0_GetGpioConfig,
+ .SetInterruptThresholds = VL53L0_SetInterruptThresholds,
+ .GetInterruptThresholds = VL53L0_GetInterruptThresholds,
+ .ClearInterruptMask = VL53L0_ClearInterruptMask,
+ .GetInterruptMaskStatus = VL53L0_GetInterruptMaskStatus,
+ .EnableInterruptMask = VL53L0_EnableInterruptMask,
+ .SetSpadAmbientDamperThreshold = VL53L0_SetSpadAmbientDamperThreshold,
+ .GetSpadAmbientDamperThreshold = VL53L0_GetSpadAmbientDamperThreshold,
+ .SetSpadAmbientDamperFactor = VL53L0_SetSpadAmbientDamperFactor,
+ .GetSpadAmbientDamperFactor = VL53L0_GetSpadAmbientDamperFactor,
+ .PerformRefSpadManagement = VL53L0_PerformRefSpadManagement,
+ .SetReferenceSpads = VL53L0_SetReferenceSpads,
+ .GetReferenceSpads = VL53L0_GetReferenceSpads,
+
+};
+struct stmvl53l0_api_fn_t *papi_func_tbl;
+
+/*
+ * IOCTL definitions
+ */
+#define VL53L0_IOCTL_INIT _IO('p', 0x01)
+#define VL53L0_IOCTL_XTALKCALB _IOW('p', 0x02, unsigned int)
+#define VL53L0_IOCTL_OFFCALB _IOW('p', 0x03, unsigned int)
+#define VL53L0_IOCTL_STOP _IO('p', 0x05)
+#define VL53L0_IOCTL_SETXTALK _IOW('p', 0x06, unsigned int)
+#define VL53L0_IOCTL_SETOFFSET _IOW('p', 0x07, int8_t)
+#define VL53L0_IOCTL_ACTIVATE_USE_CASE _IOW('p', 0x08, uint8_t)
+#define VL53L0_IOCTL_ACTIVATE_CUSTOM_USE_CASE \
+ _IOW('p', 0x09, struct stmvl53l0_custom_use_case)
+
+#define VL53L0_IOCTL_GETDATAS \
+ _IOR('p', 0x0b, VL53L0_RangingMeasurementData_t)
+#define VL53L0_IOCTL_REGISTER \
+ _IOWR('p', 0x0c, struct stmvl53l0_register)
+#define VL53L0_IOCTL_PARAMETER \
+ _IOWR('p', 0x0d, struct stmvl53l0_parameter)
+
+
+/* Mask fields to indicate Offset and Xtalk Comp
+ * values have been set by application
+ */
+#define SET_OFFSET_CALIB_DATA_MICROMETER_MASK 0x1
+#define SET_XTALK_COMP_RATE_MCPS_MASK 0x2
+
+/* Macros used across different functions */
+#define USE_CASE_LONG_DISTANCE 1
+#define USE_CASE_HIGH_ACCURACY 2
+#define USE_CASE_HIGH_SPEED 3
+#define USE_CASE_CUSTOM 4
+
+#define LONG_DISTANCE_TIMING_BUDGET 26000
+#define LONG_DISTANCE_SIGNAL_RATE_LIMIT (65536 / 10) /* 0.1 */
+#define LONG_DISTANCE_SIGMA_LIMIT (60*65536)
+#define LONG_DISTANCE_PRE_RANGE_PULSE_PERIOD 18
+#define LONG_DISTANCE_FINAL_RANGE_PULSE_PERIOD 14
+
+
+
+#define HIGH_ACCURACY_TIMING_BUDGET 200000
+#define HIGH_ACCURACY_SIGNAL_RATE_LIMIT (25 * 65536 / 100) /*0.25*/
+#define HIGH_ACCURACY_SIGMA_LIMIT (18*65536)
+#define HIGH_ACCURACY_PRE_RANGE_PULSE_PERIOD 14
+#define HIGH_ACCURACY_FINAL_RANGE_PULSE_PERIOD 10
+
+
+
+#define HIGH_SPEED_TIMING_BUDGET 20000
+#define HIGH_SPEED_SIGNAL_RATE_LIMIT (25 * 65536 / 100) /* 0.25 */
+#define HIGH_SPEED_SIGMA_LIMIT (32*65536)
+#define HIGH_SPEED_PRE_RANGE_PULSE_PERIOD 14
+#define HIGH_SPEED_FINAL_RANGE_PULSE_PERIOD 10
+
+
+
+
+
+static long stmvl53l0_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+/*static int stmvl53l0_flush(struct file *file, fl_owner_t id);*/
+static int stmvl53l0_open(struct inode *inode, struct file *file);
+static int stmvl53l0_init_client(struct stmvl53l0_data *data);
+static int stmvl53l0_start(struct stmvl53l0_data *data, uint8_t scaling,
+ init_mode_e mode);
+static int stmvl53l0_stop(struct stmvl53l0_data *data);
+static int stmvl53l0_config_use_case(struct stmvl53l0_data *data);
+
+#ifdef DEBUG_TIME_LOG
+static void stmvl53l0_DebugTimeGet(struct timeval *ptv)
+{
+ do_gettimeofday(ptv);
+}
+
+static void stmvl53l0_DebugTimeDuration(struct timeval *pstart_tv,
+ struct timeval *pstop_tv)
+{
+ long total_sec, total_msec;
+
+ total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec;
+ total_msec = (pstop_tv->tv_usec - pstart_tv->tv_usec)/1000;
+ total_msec += total_sec * 1000;
+ pr_err("elapsedTime:%ld\n", total_msec);
+}
+#endif
+
+static void stmvl53l0_setupAPIFunctions(struct stmvl53l0_data *data)
+{
+ uint8_t revision = 0;
+ VL53L0_DEV vl53l0_dev = data;
+
+ /* Read Revision ID */
+ VL53L0_RdByte(vl53l0_dev,
+ VL53L0_REG_IDENTIFICATION_REVISION_ID,
+ &revision);
+ vl53l0_errmsg("read REVISION_ID: 0x%x\n", revision);
+ revision = (revision & 0xF0) >> 4;
+ if (revision == 1) {
+ /*cut 1.1*/
+ vl53l0_errmsg("to setup API cut 1.1\n");
+ papi_func_tbl->GetVersion = VL53L0_GetVersion;
+ papi_func_tbl->GetPalSpecVersion = VL53L0_GetPalSpecVersion;
+ papi_func_tbl->GetProductRevision = VL53L0_GetProductRevision;
+ papi_func_tbl->GetDeviceInfo = VL53L0_GetDeviceInfo;
+ papi_func_tbl->GetDeviceErrorStatus =
+ VL53L0_GetDeviceErrorStatus;
+ papi_func_tbl->GetRangeStatusString =
+ VL53L0_GetRangeStatusString;
+ papi_func_tbl->GetDeviceErrorString =
+ VL53L0_GetDeviceErrorString;
+ papi_func_tbl->GetPalErrorString =
+ VL53L0_GetPalErrorString;
+ papi_func_tbl->GetPalState =
+ VL53L0_GetPalState;
+ papi_func_tbl->SetPowerMode =
+ VL53L0_SetPowerMode;
+ papi_func_tbl->GetPowerMode =
+ VL53L0_GetPowerMode;
+ papi_func_tbl->SetOffsetCalibrationDataMicroMeter =
+ VL53L0_SetOffsetCalibrationDataMicroMeter;
+ papi_func_tbl->GetOffsetCalibrationDataMicroMeter =
+ VL53L0_GetOffsetCalibrationDataMicroMeter;
+ papi_func_tbl->SetLinearityCorrectiveGain =
+VL53L0_SetLinearityCorrectiveGain;
+ papi_func_tbl->GetLinearityCorrectiveGain =
+VL53L0_GetLinearityCorrectiveGain;
+ papi_func_tbl->SetGroupParamHold = VL53L0_SetGroupParamHold;
+ papi_func_tbl->GetUpperLimitMilliMeter =
+ VL53L0_GetUpperLimitMilliMeter;
+ papi_func_tbl->SetDeviceAddress =
+ VL53L0_SetDeviceAddress;
+ papi_func_tbl->DataInit =
+ VL53L0_DataInit;
+ papi_func_tbl->SetTuningSettingBuffer =
+ VL53L0_SetTuningSettingBuffer;
+ papi_func_tbl->GetTuningSettingBuffer =
+ VL53L0_GetTuningSettingBuffer;
+ papi_func_tbl->StaticInit =
+ VL53L0_StaticInit;
+ papi_func_tbl->WaitDeviceBooted =
+ VL53L0_WaitDeviceBooted;
+ papi_func_tbl->ResetDevice =
+ VL53L0_ResetDevice;
+ papi_func_tbl->SetDeviceParameters =
+ VL53L0_SetDeviceParameters;
+ papi_func_tbl->SetDeviceMode = VL53L0_SetDeviceMode;
+ papi_func_tbl->GetDeviceMode = VL53L0_GetDeviceMode;
+ papi_func_tbl->SetHistogramMode = VL53L0_SetHistogramMode;
+ papi_func_tbl->GetHistogramMode = VL53L0_GetHistogramMode;
+ papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds =
+ VL53L0_SetMeasurementTimingBudgetMicroSeconds;
+ papi_func_tbl->GetMeasurementTimingBudgetMicroSeconds =
+ VL53L0_GetMeasurementTimingBudgetMicroSeconds;
+ papi_func_tbl->GetVcselPulsePeriod = VL53L0_GetVcselPulsePeriod;
+ papi_func_tbl->SetVcselPulsePeriod = VL53L0_SetVcselPulsePeriod;
+ papi_func_tbl->SetSequenceStepEnable =
+ VL53L0_SetSequenceStepEnable;
+ papi_func_tbl->GetSequenceStepEnable =
+ VL53L0_GetSequenceStepEnable;
+ papi_func_tbl->GetSequenceStepEnables =
+ VL53L0_GetSequenceStepEnables;
+ papi_func_tbl->SetSequenceStepTimeout =
+ VL53L0_SetSequenceStepTimeout;
+ papi_func_tbl->GetSequenceStepTimeout =
+ VL53L0_GetSequenceStepTimeout;
+ papi_func_tbl->GetNumberOfSequenceSteps =
+ VL53L0_GetNumberOfSequenceSteps;
+ papi_func_tbl->GetSequenceStepsInfo =
+ VL53L0_GetSequenceStepsInfo;
+ papi_func_tbl->SetInterMeasurementPeriodMilliSeconds =
+ VL53L0_SetInterMeasurementPeriodMilliSeconds;
+ papi_func_tbl->GetInterMeasurementPeriodMilliSeconds =
+ VL53L0_GetInterMeasurementPeriodMilliSeconds;
+ papi_func_tbl->SetXTalkCompensationEnable =
+ VL53L0_SetXTalkCompensationEnable;
+ papi_func_tbl->GetXTalkCompensationEnable =
+ VL53L0_GetXTalkCompensationEnable;
+ papi_func_tbl->SetXTalkCompensationRateMegaCps =
+ VL53L0_SetXTalkCompensationRateMegaCps;
+ papi_func_tbl->GetXTalkCompensationRateMegaCps =
+ VL53L0_GetXTalkCompensationRateMegaCps;
+ papi_func_tbl->GetNumberOfLimitCheck =
+ VL53L0_GetNumberOfLimitCheck;
+ papi_func_tbl->GetLimitCheckInfo =
+ VL53L0_GetLimitCheckInfo;
+ papi_func_tbl->SetLimitCheckEnable =
+ VL53L0_SetLimitCheckEnable;
+ papi_func_tbl->GetLimitCheckEnable =
+ VL53L0_GetLimitCheckEnable;
+ papi_func_tbl->SetLimitCheckValue =
+ VL53L0_SetLimitCheckValue;
+ papi_func_tbl->GetLimitCheckValue =
+ VL53L0_GetLimitCheckValue;
+ papi_func_tbl->GetLimitCheckCurrent =
+ VL53L0_GetLimitCheckCurrent;
+ papi_func_tbl->SetWrapAroundCheckEnable =
+ VL53L0_SetWrapAroundCheckEnable;
+ papi_func_tbl->GetWrapAroundCheckEnable =
+ VL53L0_GetWrapAroundCheckEnable;
+ papi_func_tbl->PerformSingleMeasurement =
+ VL53L0_PerformSingleMeasurement;
+ papi_func_tbl->PerformRefCalibration =
+ VL53L0_PerformRefCalibration;
+ papi_func_tbl->SetRefCalibration =
+ VL53L0_SetRefCalibration;
+ papi_func_tbl->GetRefCalibration =
+ VL53L0_GetRefCalibration;
+ papi_func_tbl->PerformXTalkCalibration =
+ VL53L0_PerformXTalkCalibration;
+ papi_func_tbl->PerformOffsetCalibration =
+ VL53L0_PerformOffsetCalibration;
+ papi_func_tbl->StartMeasurement =
+ VL53L0_StartMeasurement;
+ papi_func_tbl->StopMeasurement =
+ VL53L0_StopMeasurement;
+ papi_func_tbl->GetMeasurementDataReady =
+ VL53L0_GetMeasurementDataReady;
+ papi_func_tbl->WaitDeviceReadyForNewMeasurement =
+ VL53L0_WaitDeviceReadyForNewMeasurement;
+ papi_func_tbl->GetRangingMeasurementData =
+ VL53L0_GetRangingMeasurementData;
+ papi_func_tbl->GetHistogramMeasurementData =
+ VL53L0_GetHistogramMeasurementData;
+ papi_func_tbl->PerformSingleRangingMeasurement =
+ VL53L0_PerformSingleRangingMeasurement;
+ papi_func_tbl->PerformSingleHistogramMeasurement =
+ VL53L0_PerformSingleHistogramMeasurement;
+ papi_func_tbl->SetNumberOfROIZones =
+ VL53L0_SetNumberOfROIZones;
+ papi_func_tbl->GetNumberOfROIZones =
+ VL53L0_GetNumberOfROIZones;
+ papi_func_tbl->GetMaxNumberOfROIZones =
+ VL53L0_GetMaxNumberOfROIZones;
+ papi_func_tbl->SetGpioConfig =
+ VL53L0_SetGpioConfig;
+ papi_func_tbl->GetGpioConfig =
+ VL53L0_GetGpioConfig;
+ papi_func_tbl->SetInterruptThresholds =
+ VL53L0_SetInterruptThresholds;
+ papi_func_tbl->GetInterruptThresholds =
+ VL53L0_GetInterruptThresholds;
+ papi_func_tbl->ClearInterruptMask =
+ VL53L0_ClearInterruptMask;
+ papi_func_tbl->GetInterruptMaskStatus =
+ VL53L0_GetInterruptMaskStatus;
+ papi_func_tbl->EnableInterruptMask = VL53L0_EnableInterruptMask;
+ papi_func_tbl->SetSpadAmbientDamperThreshold =
+ VL53L0_SetSpadAmbientDamperThreshold;
+ papi_func_tbl->GetSpadAmbientDamperThreshold =
+ VL53L0_GetSpadAmbientDamperThreshold;
+ papi_func_tbl->SetSpadAmbientDamperFactor =
+ VL53L0_SetSpadAmbientDamperFactor;
+ papi_func_tbl->GetSpadAmbientDamperFactor =
+ VL53L0_GetSpadAmbientDamperFactor;
+ papi_func_tbl->PerformRefSpadManagement =
+ VL53L0_PerformRefSpadManagement;
+ papi_func_tbl->SetReferenceSpads = VL53L0_SetReferenceSpads;
+ papi_func_tbl->GetReferenceSpads = VL53L0_GetReferenceSpads;
+ } else if (revision == 0) {
+ /*cut 1.0*/
+ vl53l0_errmsg("to setup API cut 1.0\n");
+ papi_func_tbl->GetVersion = VL53L010_GetVersion;
+ papi_func_tbl->GetPalSpecVersion = VL53L010_GetPalSpecVersion;
+ /* papi_func_tbl->GetProductRevision = NULL;*/
+ papi_func_tbl->GetDeviceInfo = VL53L010_GetDeviceInfo;
+ papi_func_tbl->GetDeviceErrorStatus =
+ VL53L010_GetDeviceErrorStatus;
+ papi_func_tbl->GetDeviceErrorString =
+ VL53L010_GetDeviceErrorString;
+ papi_func_tbl->GetPalErrorString =
+ VL53L010_GetPalErrorString;
+ papi_func_tbl->GetPalState =
+ VL53L010_GetPalState;
+ papi_func_tbl->SetPowerMode =
+ VL53L010_SetPowerMode;
+ papi_func_tbl->GetPowerMode =
+ VL53L010_GetPowerMode;
+ papi_func_tbl->SetOffsetCalibrationDataMicroMeter =
+ VL53L010_SetOffsetCalibrationDataMicroMeter;
+ papi_func_tbl->GetOffsetCalibrationDataMicroMeter =
+ VL53L010_GetOffsetCalibrationDataMicroMeter;
+ papi_func_tbl->SetGroupParamHold =
+ VL53L010_SetGroupParamHold;
+ papi_func_tbl->GetUpperLimitMilliMeter =
+ VL53L010_GetUpperLimitMilliMeter;
+ papi_func_tbl->SetDeviceAddress =
+ VL53L010_SetDeviceAddress;
+ papi_func_tbl->DataInit = VL53L010_DataInit;
+ /*
+ *papi_func_tbl->SetTuningSettingBuffer = NULL;
+ *papi_func_tbl->GetTuningSettingBuffer = NULL;
+ */
+ papi_func_tbl->StaticInit = VL53L010_StaticInit;
+ papi_func_tbl->WaitDeviceBooted = VL53L010_WaitDeviceBooted;
+ papi_func_tbl->ResetDevice = VL53L010_ResetDevice;
+ papi_func_tbl->SetDeviceParameters =
+ VL53L010_SetDeviceParameters;
+ papi_func_tbl->SetDeviceMode = VL53L010_SetDeviceMode;
+ papi_func_tbl->GetDeviceMode = VL53L010_GetDeviceMode;
+ papi_func_tbl->SetHistogramMode = VL53L010_SetHistogramMode;
+ papi_func_tbl->GetHistogramMode = VL53L010_GetHistogramMode;
+ papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds =
+ VL53L010_SetMeasurementTimingBudgetMicroSeconds;
+ papi_func_tbl->GetMeasurementTimingBudgetMicroSeconds =
+ VL53L010_GetMeasurementTimingBudgetMicroSeconds;
+ /*
+ * papi_func_tbl->GetVcselPulsePeriod = NULL;
+ *papi_func_tbl->SetVcselPulsePeriod = NULL;
+ *papi_func_tbl->SetSequenceStepEnable = NULL;
+ *papi_func_tbl->GetSequenceStepEnable = NULL;
+ *papi_func_tbl->GetSequenceStepEnables = NULL;
+ *papi_func_tbl->SetSequenceStepTimeout = NULL;
+ *papi_func_tbl->GetSequenceStepTimeout = NULL;
+ *papi_func_tbl->GetNumberOfSequenceSteps =NULL;
+ *papi_func_tbl->GetSequenceStepsInfo = NULL;
+ */
+ papi_func_tbl->SetInterMeasurementPeriodMilliSeconds =
+ VL53L010_SetInterMeasurementPeriodMilliSeconds;
+ papi_func_tbl->GetInterMeasurementPeriodMilliSeconds =
+ VL53L010_GetInterMeasurementPeriodMilliSeconds;
+ papi_func_tbl->SetXTalkCompensationEnable =
+ VL53L010_SetXTalkCompensationEnable;
+ papi_func_tbl->GetXTalkCompensationEnable =
+ VL53L010_GetXTalkCompensationEnable;
+ papi_func_tbl->SetXTalkCompensationRateMegaCps =
+ VL53L010_SetXTalkCompensationRateMegaCps;
+ papi_func_tbl->GetXTalkCompensationRateMegaCps =
+ VL53L010_GetXTalkCompensationRateMegaCps;
+ papi_func_tbl->GetNumberOfLimitCheck =
+ VL53L010_GetNumberOfLimitCheck;
+ papi_func_tbl->GetLimitCheckInfo = VL53L010_GetLimitCheckInfo;
+ papi_func_tbl->SetLimitCheckEnable =
+ VL53L010_SetLimitCheckEnable;
+ papi_func_tbl->GetLimitCheckEnable =
+ VL53L010_GetLimitCheckEnable;
+ papi_func_tbl->SetLimitCheckValue =
+ VL53L010_SetLimitCheckValue;
+ papi_func_tbl->GetLimitCheckValue =
+ VL53L010_GetLimitCheckValue;
+ papi_func_tbl->GetLimitCheckCurrent =
+ VL53L010_GetLimitCheckCurrent;
+ papi_func_tbl->SetWrapAroundCheckEnable =
+ VL53L010_SetWrapAroundCheckEnable;
+ papi_func_tbl->GetWrapAroundCheckEnable =
+ VL53L010_GetWrapAroundCheckEnable;
+ papi_func_tbl->PerformSingleMeasurement =
+ VL53L010_PerformSingleMeasurement;
+ /*papi_func_tbl->PerformRefCalibration =
+ * VL53L010_PerformRefCalibration;
+ */
+ papi_func_tbl->PerformRefCalibration = NULL;
+ papi_func_tbl->SetRefCalibration = NULL;
+ papi_func_tbl->GetRefCalibration = NULL;
+ papi_func_tbl->PerformXTalkCalibration =
+ VL53L010_PerformXTalkCalibration;
+ papi_func_tbl->PerformOffsetCalibration =
+ VL53L010_PerformOffsetCalibration;
+ papi_func_tbl->StartMeasurement = VL53L010_StartMeasurement;
+ papi_func_tbl->StopMeasurement = VL53L010_StopMeasurement;
+ papi_func_tbl->GetMeasurementDataReady =
+ VL53L010_GetMeasurementDataReady;
+ papi_func_tbl->WaitDeviceReadyForNewMeasurement =
+ VL53L010_WaitDeviceReadyForNewMeasurement;
+ papi_func_tbl->GetRangingMeasurementData =
+ VL53L010_GetRangingMeasurementData;
+ papi_func_tbl->GetHistogramMeasurementData =
+ VL53L010_GetHistogramMeasurementData;
+ papi_func_tbl->PerformSingleRangingMeasurement =
+ VL53L010_PerformSingleRangingMeasurement;
+ papi_func_tbl->PerformSingleHistogramMeasurement =
+ VL53L010_PerformSingleHistogramMeasurement;
+ papi_func_tbl->SetNumberOfROIZones =
+ VL53L010_SetNumberOfROIZones;
+ papi_func_tbl->GetNumberOfROIZones =
+ VL53L010_GetNumberOfROIZones;
+ papi_func_tbl->GetMaxNumberOfROIZones =
+ VL53L010_GetMaxNumberOfROIZones;
+ papi_func_tbl->SetGpioConfig = VL53L010_SetGpioConfig;
+ papi_func_tbl->GetGpioConfig = VL53L010_GetGpioConfig;
+ papi_func_tbl->SetInterruptThresholds =
+ VL53L010_SetInterruptThresholds;
+ papi_func_tbl->GetInterruptThresholds =
+ VL53L010_GetInterruptThresholds;
+ papi_func_tbl->ClearInterruptMask =
+ VL53L010_ClearInterruptMask;
+ papi_func_tbl->GetInterruptMaskStatus =
+ VL53L010_GetInterruptMaskStatus;
+ papi_func_tbl->EnableInterruptMask =
+ VL53L010_EnableInterruptMask;
+ papi_func_tbl->SetSpadAmbientDamperThreshold =
+ VL53L010_SetSpadAmbientDamperThreshold;
+ papi_func_tbl->GetSpadAmbientDamperThreshold =
+ VL53L010_GetSpadAmbientDamperThreshold;
+ papi_func_tbl->SetSpadAmbientDamperFactor =
+ VL53L010_SetSpadAmbientDamperFactor;
+ papi_func_tbl->GetSpadAmbientDamperFactor =
+ VL53L010_GetSpadAmbientDamperFactor;
+ papi_func_tbl->PerformRefSpadManagement = NULL;
+ papi_func_tbl->SetReferenceSpads = NULL;
+ papi_func_tbl->GetReferenceSpads = NULL;
+ }
+
+}
+
+static void stmvl53l0_ps_read_measurement(struct stmvl53l0_data *data)
+{
+ struct timeval tv;
+ VL53L0_DEV vl53l0_dev = data;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ FixPoint1616_t LimitCheckCurrent;
+
+ do_gettimeofday(&tv);
+
+ data->ps_data = data->rangeData.RangeMilliMeter;
+ input_report_abs(data->input_dev_ps, ABS_DISTANCE,
+ (int)(data->ps_data + 5) / 10);
+ input_report_abs(data->input_dev_ps, ABS_HAT0X, tv.tv_sec);
+ input_report_abs(data->input_dev_ps, ABS_HAT0Y, tv.tv_usec);
+ input_report_abs(data->input_dev_ps, ABS_HAT1X,
+ data->rangeData.RangeMilliMeter);
+ input_report_abs(data->input_dev_ps, ABS_HAT1Y,
+ data->rangeData.RangeStatus);
+ input_report_abs(data->input_dev_ps, ABS_HAT2X,
+ data->rangeData.SignalRateRtnMegaCps);
+ input_report_abs(data->input_dev_ps, ABS_HAT2Y,
+ data->rangeData.AmbientRateRtnMegaCps);
+ input_report_abs(data->input_dev_ps, ABS_HAT3X,
+ data->rangeData.MeasurementTimeUsec);
+ input_report_abs(data->input_dev_ps, ABS_HAT3Y,
+ data->rangeData.RangeDMaxMilliMeter);
+ Status = papi_func_tbl->GetLimitCheckCurrent(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &LimitCheckCurrent);
+ if (Status == VL53L0_ERROR_NONE) {
+ input_report_abs(data->input_dev_ps, ABS_WHEEL,
+ LimitCheckCurrent);
+ }
+ input_report_abs(data->input_dev_ps, ABS_PRESSURE,
+ data->rangeData.EffectiveSpadRtnCount);
+ input_sync(data->input_dev_ps);
+
+ if (data->enableDebug)
+ vl53l0_errmsg(
+"range:%d, RtnRateMcps:%d,err:0x%x,Dmax:%d,rtnambr:%d,time:%d,Spad:%d,SigmaLimit:%d\n",
+ data->rangeData.RangeMilliMeter,
+ data->rangeData.SignalRateRtnMegaCps,
+ data->rangeData.RangeStatus,
+ data->rangeData.RangeDMaxMilliMeter,
+ data->rangeData.AmbientRateRtnMegaCps,
+ data->rangeData.MeasurementTimeUsec,
+ data->rangeData.EffectiveSpadRtnCount,
+ LimitCheckCurrent
+ );
+
+
+}
+
+static void stmvl53l0_cancel_handler(struct stmvl53l0_data *data)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&data->update_lock.wait_lock, flags);
+ /*
+ * If work is already scheduled then subsequent schedules will not
+ * change the scheduled time that's why we have to cancel it first.
+ */
+ ret = cancel_delayed_work(&data->dwork);
+ if (ret == 0)
+ vl53l0_errmsg("cancel_delayed_work return FALSE\n");
+
+ spin_unlock_irqrestore(&data->update_lock.wait_lock, flags);
+
+}
+
+void stmvl53l0_schedule_handler(struct stmvl53l0_data *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&data->update_lock.wait_lock, flags);
+ /*
+ * If work is already scheduled then subsequent schedules will not
+ * change the scheduled time that's why we have to cancel it first.
+ */
+ cancel_delayed_work(&data->dwork);
+ schedule_delayed_work(&data->dwork, 0);
+ spin_unlock_irqrestore(&data->update_lock.wait_lock, flags);
+
+}
+
+
+#ifdef USE_INT
+static irqreturn_t stmvl53l0_interrupt_handler(int vec, void *info)
+{
+
+ struct stmvl53l0_data *data = (struct stmvl53l0_data *)info;
+
+ if (data->irq == vec) {
+ data->interrupt_received = 1;
+ schedule_delayed_work(&data->dwork, 0);
+ }
+ return IRQ_HANDLED;
+}
+#else
+/* Flag used to exit the thread when kthread_stop() is invoked */
+static int poll_thread_exit;
+int stmvl53l0_poll_thread(void *data)
+{
+ VL53L0_DEV vl53l0_dev = data;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ uint32_t sleep_time = 0;
+ uint32_t interruptStatus = 0;
+
+ pr_err("%s(%d) : Starting Polling thread\n", __func__, __LINE__);
+
+ while (!kthread_should_stop()) {
+ /* Check if enable_ps_sensor is true or exit request is made.
+ * If not block
+ */
+ wait_event(vl53l0_dev->poll_thread_wq,
+ (vl53l0_dev->enable_ps_sensor || poll_thread_exit));
+ if (poll_thread_exit) {
+ pr_err(
+ "%s(%d) : Exiting the poll thread\n", __func__, __LINE__);
+ break;
+ }
+
+ mutex_lock(&vl53l0_dev->work_mutex);
+
+ sleep_time = vl53l0_dev->delay_ms;
+ Status = VL53L0_GetInterruptMaskStatus(vl53l0_dev,
+ &interruptStatus);
+ if (Status == VL53L0_ERROR_NONE &&
+ interruptStatus &&
+ interruptStatus != vl53l0_dev->interruptStatus) {
+ vl53l0_dev->interruptStatus = interruptStatus;
+ vl53l0_dev->noInterruptCount = 0;
+ stmvl53l0_schedule_handler(vl53l0_dev);
+ } else {
+ vl53l0_dev->noInterruptCount++;
+ }
+
+ /*Force Clear interrupt mask and restart if
+ *no interrupt after twice the timingBudget
+ */
+ if ((vl53l0_dev->noInterruptCount * vl53l0_dev->delay_ms) >
+ (vl53l0_dev->timingBudget * 2)) {
+ pr_err("No interrupt after (%u) msec(TimingBudget = %u) . Clear Interrupt Mask and restart\n",
+ (vl53l0_dev->noInterruptCount *
+ vl53l0_dev->delay_ms),
+ vl53l0_dev->timingBudget);
+ Status = papi_func_tbl->ClearInterruptMask(vl53l0_dev,
+ 0);
+ if (vl53l0_dev->deviceMode ==
+ VL53L0_DEVICEMODE_SINGLE_RANGING) {
+ Status = papi_func_tbl->StartMeasurement(
+ vl53l0_dev);
+ if (Status != VL53L0_ERROR_NONE) {
+ pr_err("%s(%d) : Status = %d\n",
+ __func__, __LINE__, Status);
+ }
+ }
+ }
+ mutex_unlock(&vl53l0_dev->work_mutex);
+ /* Sleep for delay_ms milliseconds */
+ msleep(sleep_time);
+ }
+
+ return 0;
+}
+#endif
+
+/* work handler */
+static void stmvl53l0_work_handler(struct work_struct *work)
+{
+ struct stmvl53l0_data *data = container_of(work, struct stmvl53l0_data,
+ dwork.work);
+ VL53L0_DEV vl53l0_dev = data;
+
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ mutex_lock(&data->work_mutex);
+ /* vl53l0_dbgmsg("Enter\n"); */
+
+
+ if (vl53l0_dev->enable_ps_sensor == 1) {
+#ifdef DEBUG_TIME_LOG
+ stmvl53l0_DebugTimeGet(&stop_tv);
+ stmvl53l0_DebugTimeDuration(&start_tv, &stop_tv);
+#endif
+ /* Check if ISR has scheduled this function */
+ if (vl53l0_dev->interrupt_received == 1) {
+ Status = papi_func_tbl->GetInterruptMaskStatus(
+ vl53l0_dev,
+ &vl53l0_dev->interruptStatus);
+ if (Status != VL53L0_ERROR_NONE)
+ pr_err("%s(%d) : Status = %d\n",
+ __func__, __LINE__, Status);
+ vl53l0_dev->interrupt_received = 0;
+ }
+ if (data->enableDebug)
+ pr_err("interruptStatus:0x%x, interrupt_received:%d\n",
+ vl53l0_dev->interruptStatus,
+ vl53l0_dev->interrupt_received);
+
+ if (vl53l0_dev->interruptStatus == vl53l0_dev->gpio_function) {
+ Status =
+ papi_func_tbl->GetRangingMeasurementData(
+ vl53l0_dev,
+ &(data->rangeData));
+ /* to push the measurement */
+ if (Status == VL53L0_ERROR_NONE)
+ stmvl53l0_ps_read_measurement(data);
+ else
+ pr_err("%s(%d) : Status = %d\n",
+ __func__, __LINE__, Status);
+
+ if (data->enableDebug)
+ pr_err("Measured range:%d\n",
+ data->rangeData.RangeMilliMeter);
+
+ Status = papi_func_tbl->ClearInterruptMask(
+ vl53l0_dev, 0);
+ if (Status != VL53L0_ERROR_NONE) {
+ pr_err("%s(%d) : Status = %d\n",
+ __func__, __LINE__, Status);
+ }
+
+ if (data->deviceMode ==
+ VL53L0_DEVICEMODE_SINGLE_RANGING) {
+ /* Before restarting measurement
+ * check if use case needs to be changed
+ */
+
+ if (data->updateUseCase) {
+ Status =
+ stmvl53l0_config_use_case(data);
+ if (Status !=
+ VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "Failed to configure Use case = %u\n",
+ vl53l0_dev->useCase);
+ } else {
+ data->updateUseCase = 0;
+ }
+ }
+ Status =
+ papi_func_tbl->StartMeasurement(
+ vl53l0_dev);
+ }
+ }
+#ifdef DEBUG_TIME_LOG
+ stmvl53l0_DebugTimeGet(&start_tv);
+#endif
+
+ }
+
+
+ vl53l0_dev->interruptStatus = 0;
+
+ mutex_unlock(&data->work_mutex);
+
+}
+
+
+/*
+ * SysFS support
+ */
+static ssize_t stmvl53l0_show_enable_ps_sensor(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 5, "%d\n", data->enable_ps_sensor);
+}
+
+static ssize_t stmvl53l0_store_enable_ps_sensor(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+ unsigned long val = 0;
+
+ int ret = kstrtoul(buf, 10, &val);
+
+ if (ret != 0)
+ return ret;
+
+ if ((val != 0) && (val != 1)) {
+ vl53l0_errmsg("store unvalid value = %lu\n", val);
+ return count;
+ }
+ mutex_lock(&data->work_mutex);
+ vl53l0_dbgmsg("Enter, enable_ps_sensor flag:%d\n",
+ data->enable_ps_sensor);
+ vl53l0_dbgmsg("enable ps senosr ( %ld)\n", val);
+
+ if (val == 1) {
+ /* turn on tof sensor */
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0_start(data, 3, NORMAL_MODE);
+ } else {
+ vl53l0_errmsg("Already enabled. Skip !");
+ }
+ } else {
+ /* turn off tof sensor */
+ if (data->enable_ps_sensor == 1) {
+ data->enable_ps_sensor = 0;
+ /* to stop */
+ stmvl53l0_stop(data);
+ }
+ }
+ vl53l0_dbgmsg("End\n");
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0_show_enable_ps_sensor,
+ stmvl53l0_store_enable_ps_sensor);
+
+static ssize_t stmvl53l0_show_enable_debug(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 5, "%d\n", data->enableDebug);
+}
+
+/* for debug */
+static ssize_t stmvl53l0_store_enable_debug(struct device *dev,
+ struct device_attribute *attr, const
+ char *buf, size_t count)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+ unsigned long on = 0;
+
+ int ret = kstrtoul(buf, 10, &on);
+
+ if (ret != 0)
+ return ret;
+
+ if ((on != 0) && (on != 1)) {
+ vl53l0_errmsg("set debug=%lu\n", on);
+ return count;
+ }
+ data->enableDebug = on;
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(enable_debug, 0660/*S_IWUSR | S_IRUGO*/,
+ stmvl53l0_show_enable_debug,
+ stmvl53l0_store_enable_debug);
+
+static ssize_t stmvl53l0_show_set_delay_ms(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 5, "%d\n", data->delay_ms);
+}
+
+/* for work handler scheduler time */
+static ssize_t stmvl53l0_store_set_delay_ms(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+ unsigned long delay_ms = 0;
+
+ int ret = kstrtoul(buf, 10, &delay_ms);
+
+ if (ret != 0)
+ return ret;
+ if (delay_ms == 0) {
+ vl53l0_errmsg("set delay_ms=%lu\n", delay_ms);
+ return count;
+ }
+ mutex_lock(&data->work_mutex);
+ data->delay_ms = delay_ms;
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0_show_set_delay_ms,
+ stmvl53l0_store_set_delay_ms);
+
+/* Timing Budget */
+static ssize_t stmvl53l0_show_timing_budget(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 10, "%d\n", data->timingBudget);
+}
+
+static ssize_t stmvl53l0_store_set_timing_budget(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+ unsigned long timingBudget = 0;
+ int ret = kstrtoul(buf, 10, &timingBudget);
+
+ if (ret != 0)
+ return ret;
+ if (timingBudget == 0) {
+ vl53l0_errmsg("set timingBudget=%lu\n", timingBudget);
+ return count;
+ }
+ mutex_lock(&data->work_mutex);
+ data->timingBudget = timingBudget;
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_timing_budget, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0_show_timing_budget,
+ stmvl53l0_store_set_timing_budget);
+
+
+/* Use case */
+static ssize_t stmvl53l0_show_use_case(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+
+ switch (data->useCase) {
+ case USE_CASE_LONG_DISTANCE:
+ return snprintf(buf, 20, "Long Distance\n");
+ case USE_CASE_HIGH_ACCURACY:
+ return snprintf(buf, 20, "High Accuracy\n");
+ case USE_CASE_HIGH_SPEED:
+ return snprintf(buf, 20, "High Speed\n");
+ default:
+ break;
+ }
+
+ return snprintf(buf, 25, "Unknown use case\n");
+}
+
+static ssize_t stmvl53l0_store_set_use_case(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+ unsigned long useCase = 0;
+ int ret = kstrtoul(buf, 10, &useCase);
+
+ if (ret != 0)
+ return ret;
+
+
+ mutex_lock(&data->work_mutex);
+
+ if (useCase == USE_CASE_LONG_DISTANCE) {
+ data->timingBudget = LONG_DISTANCE_TIMING_BUDGET;
+ } else if (useCase == USE_CASE_HIGH_SPEED) {
+ data->timingBudget = HIGH_SPEED_TIMING_BUDGET;
+ } else if (useCase == USE_CASE_HIGH_ACCURACY) {
+ data->timingBudget = HIGH_ACCURACY_TIMING_BUDGET;
+ } else {
+ count = -EINVAL;
+ mutex_unlock(&data->work_mutex);
+ return count;
+ }
+
+ data->useCase = useCase;
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_use_case, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0_show_use_case,
+ stmvl53l0_store_set_use_case);
+
+
+/* Get Current configuration info */
+static ssize_t stmvl53l0_show_current_configuration(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmvl53l0_data *vl53l0_dev = dev_get_drvdata(dev);
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ int ret = -1;
+ FixPoint1616_t LimitValue = 0;
+ uint8_t LimitEnable = 0;
+ uint32_t refSpadCount = 0;
+ uint8_t isApertureSpads = 0;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+ uint8_t pulsePeriod = 0;
+ uint32_t timingBudget = 0;
+ int32_t offsetCalibrationDataMicroMeter = -1;
+ uint8_t XTalkCompensationEnable = 0;
+ FixPoint1616_t xTalkCompensationRateMegaCps = 0;
+
+
+ ret = scnprintf(buf, PAGE_SIZE, "VL53L0 current configuration:\n");
+
+ mutex_lock(&vl53l0_dev->work_mutex);
+ pr_err("Driver Config:UseCase:%d, offsetCalDistance:%u,xtalkCalDistance:%u,setCalibratedValue:0x%X\n",
+ vl53l0_dev->useCase, vl53l0_dev->offsetCalDistance,
+ vl53l0_dev->xtalkCalDistance,
+ vl53l0_dev->setCalibratedValue);
+
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "Driver Config:UseCase:%d, offsetCalDistance:%u,xtalkCalDistance:%u,setCalibratedValue:0x%X\n",
+ vl53l0_dev->useCase,
+ vl53l0_dev->offsetCalDistance,
+ vl53l0_dev->xtalkCalDistance,
+ vl53l0_dev->setCalibratedValue);
+
+ if (vl53l0_dev->useCase == USE_CASE_CUSTOM) {
+ pr_err("CustomUseCase : Sigma=%u :Signal=%u: Pre=%u :Final=%u\n",
+ vl53l0_dev->sigmaLimit,
+ vl53l0_dev->signalRateLimit,
+ vl53l0_dev->preRangePulsePeriod,
+ vl53l0_dev->finalRangePulsePeriod);
+
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "CustomUseCase : Sigma=%u :Signal=%u: Pre=%u :Final=%u\n",
+ vl53l0_dev->sigmaLimit,
+ vl53l0_dev->signalRateLimit,
+ vl53l0_dev->preRangePulsePeriod,
+ vl53l0_dev->finalRangePulsePeriod);
+ }
+
+
+ Status = papi_func_tbl->GetLimitCheckValue(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &LimitValue);
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = papi_func_tbl->GetLimitCheckEnable(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &LimitEnable);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("Get LimitCheckValue SIGMA_FINAL_RANGE as:%d,Enable:%d\n",
+ (LimitValue>>16), LimitEnable);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "Sigma Limit:%u, Enable:%u\n",
+ (LimitValue>>16),
+ LimitEnable);
+ Status = papi_func_tbl->GetLimitCheckValue(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ &LimitValue);
+ Status = papi_func_tbl->GetLimitCheckEnable(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ &LimitEnable);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("Get LimitCheckValue SIGNAL_FINAL_RANGE as:%d(Fix1616),Enable:%d\n",
+ (LimitValue), LimitEnable);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "SIGNAL Limit:%u, Enable:%u\n",
+ LimitValue,
+ LimitEnable);
+
+ Status = papi_func_tbl->GetLimitCheckValue(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP,
+ &LimitValue);
+ Status = papi_func_tbl->GetLimitCheckEnable(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGNAL_REF_CLIP,
+ &LimitEnable);
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("Get LimitCheckValue SIGNAL_REF_CLIP as:%d(fix1616),Enable:%d\n",
+ (LimitValue), LimitEnable);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "RefClipLimit:%u, Enable:%u\n",
+ LimitValue,
+ LimitEnable);
+
+ Status = papi_func_tbl->GetLimitCheckValue(vl53l0_dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ &LimitValue);
+ Status = papi_func_tbl->GetLimitCheckEnable(vl53l0_dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ &LimitEnable);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err(
+ "Get LimitCheckValue RANGE_IGNORE_THRESHOLDas:%d(fix1616),Enable:%d\n",
+ (LimitValue),
+ LimitEnable);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "RngIgnoreThresh:%u, Enable:%u\n",
+ LimitValue,
+ LimitEnable);
+
+ Status = papi_func_tbl->GetRefCalibration(vl53l0_dev,
+ &VhvSettings, &PhaseCal); /* Ref calibration */
+
+
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("GetRefCalibration - Vhv = %u, PhaseCal = %u\n",
+ VhvSettings, PhaseCal);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "Vhv:%u, PhCal:%u\n",
+ VhvSettings,
+ PhaseCal);
+
+ /* Ref Spad Management */
+ Status = papi_func_tbl->GetReferenceSpads(vl53l0_dev,
+ &refSpadCount, &isApertureSpads);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("GetSpads - Count = %u, IsAperture = %u\n",
+ refSpadCount, isApertureSpads);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "SpadCount:%u, IsAperture:%u\n",
+ refSpadCount,
+ isApertureSpads);
+
+ Status = papi_func_tbl->GetMeasurementTimingBudgetMicroSeconds(
+ vl53l0_dev,
+ &timingBudget);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("TimingBudget = %u\n", timingBudget);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "TimBudget:%u\n",
+ timingBudget);
+ Status = papi_func_tbl->GetVcselPulsePeriod(vl53l0_dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ &pulsePeriod);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("GetVcselPulsePeriod - PRE_RANGE = %u\n",
+ pulsePeriod);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "PulsePreRange:%u\n",
+ pulsePeriod);
+
+ Status = papi_func_tbl->GetVcselPulsePeriod(vl53l0_dev,
+ VL53L0_VCSEL_PERIOD_FINAL_RANGE,
+ &pulsePeriod);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("GetVcselPulsePeriod - FINAL_RANGE = %u\n",
+ pulsePeriod);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret,
+ "PulseFinalRange:%u\n",
+ pulsePeriod);
+
+ Status = papi_func_tbl->GetOffsetCalibrationDataMicroMeter(
+ vl53l0_dev,
+ &offsetCalibrationDataMicroMeter);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("OffsetCalibrationDataMicroMeter = %d\n",
+ offsetCalibrationDataMicroMeter);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "Offset:%d\n",
+ offsetCalibrationDataMicroMeter);
+
+ Status = papi_func_tbl->GetXTalkCompensationEnable(vl53l0_dev,
+ &XTalkCompensationEnable);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("Xtalk Enable = %u\n", XTalkCompensationEnable);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "XtalkEnable:%u\n",
+ XTalkCompensationEnable);
+
+ Status = papi_func_tbl->GetXTalkCompensationRateMegaCps(
+ vl53l0_dev,
+ &xTalkCompensationRateMegaCps);
+ }
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("XtalkComp MCPS = %u\n", xTalkCompensationRateMegaCps);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "XtalkMcps:%u\n",
+ xTalkCompensationRateMegaCps);
+
+ } else {
+ pr_err("Error = %d\n", Status);
+ ret += scnprintf(buf + ret, PAGE_SIZE - ret, "Error:%d\n",
+ Status);
+
+ }
+
+ pr_err("Total Bytes returned = %d\n", ret);
+
+ mutex_unlock(&vl53l0_dev->work_mutex);
+
+
+ return ret;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(show_current_configuration, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0_show_current_configuration,
+ NULL);
+/* for work handler scheduler time */
+static ssize_t stmvl53l0_do_flush(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct stmvl53l0_data *data = dev_get_drvdata(dev);
+
+ int ret = 0;
+ /* Revisit : Avoid lock if it takes too long time */
+ mutex_lock(&data->work_mutex);
+
+ vl53l0_dbgmsg("Starting timer to fire in 1ms (%ld)\n", jiffies);
+ ret = mod_timer(&data->timer, jiffies + msecs_to_jiffies(1));
+ if (ret)
+ pr_err("Error from mod_timer = %d\n", ret);
+
+ mutex_unlock(&data->work_mutex);
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(do_flush, 0660/*S_IWUGO | S_IRUGO*/,
+ NULL,
+ stmvl53l0_do_flush);
+static struct attribute *stmvl53l0_attributes[] = {
+ &dev_attr_enable_ps_sensor.attr,
+ &dev_attr_enable_debug.attr,
+ &dev_attr_set_delay_ms.attr,
+ &dev_attr_set_timing_budget.attr,
+ &dev_attr_set_use_case.attr,
+ &dev_attr_do_flush.attr,
+ &dev_attr_show_current_configuration.attr,
+ NULL
+};
+
+
+static const struct attribute_group stmvl53l0_attr_group = {
+ .attrs = stmvl53l0_attributes,
+};
+
+/*
+ * misc device file operation functions
+ */
+static int stmvl53l0_ioctl_handler(struct file *file,
+ unsigned int cmd, unsigned long arg,
+ void __user *p)
+{
+ int rc = 0;
+ unsigned int xtalkint = 0;
+ unsigned int targetDistance = 0;
+ int8_t offsetint = 0;
+ uint8_t useCase = 0;
+ struct stmvl53l0_custom_use_case customUseCase;
+ struct stmvl53l0_data *data =
+ container_of(file->private_data,
+ struct stmvl53l0_data, miscdev);
+ struct stmvl53l0_register reg;
+ struct stmvl53l0_parameter parameter;
+ VL53L0_DEV vl53l0_dev = data;
+ VL53L0_DeviceModes deviceMode;
+ uint8_t page_num = 0;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ if (!data)
+ return -EINVAL;
+
+ vl53l0_dbgmsg("Enter enable_ps_sensor:%d\n", data->enable_ps_sensor);
+ switch (cmd) {
+ /* enable */
+ case VL53L0_IOCTL_INIT:
+ vl53l0_dbgmsg("VL53L0_IOCTL_INIT\n");
+ /* turn on tof sensor only if it's not enabled by other
+ * client
+ */
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0_start(data, 3, NORMAL_MODE);
+ } else
+ rc = -EINVAL;
+ break;
+ /* crosstalk calibration */
+ case VL53L0_IOCTL_XTALKCALB:
+ vl53l0_dbgmsg("VL53L0_IOCTL_XTALKCALB\n");
+ data->xtalkCalDistance = 100;
+ if (copy_from_user(&targetDistance, (unsigned int *)p,
+ sizeof(unsigned int))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ data->xtalkCalDistance = targetDistance;
+
+ /* turn on tof sensor only if it's not enabled by other
+ * client
+ */
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0_start(data, 3, XTALKCALIB_MODE);
+ } else
+ rc = -EINVAL;
+ break;
+ /* set up Xtalk value */
+ case VL53L0_IOCTL_SETXTALK:
+ vl53l0_dbgmsg("VL53L0_IOCTL_SETXTALK\n");
+ if (copy_from_user(&xtalkint, (unsigned int *)p,
+ sizeof(unsigned int))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ vl53l0_dbgmsg("SETXTALK as 0x%x\n", xtalkint);
+
+ /* later
+ * SetXTalkCompensationRate(vl53l0_dev, xtalkint);
+ */
+ break;
+ /* offset calibration */
+ case VL53L0_IOCTL_OFFCALB:
+ vl53l0_dbgmsg("VL53L0_IOCTL_OFFCALB\n");
+ data->offsetCalDistance = 50;
+ if (copy_from_user(&targetDistance, (unsigned int *)p,
+ sizeof(unsigned int))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ data->offsetCalDistance = targetDistance;
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0_start(data, 3, OFFSETCALIB_MODE);
+ } else
+ rc = -EINVAL;
+ break;
+ /* set up offset value */
+ case VL53L0_IOCTL_SETOFFSET:
+ vl53l0_dbgmsg("VL53L0_IOCTL_SETOFFSET\n");
+ if (copy_from_user(&offsetint, (int8_t *)p, sizeof(int8_t))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ vl53l0_dbgmsg("SETOFFSET as %d\n", offsetint);
+
+ /* later
+ * SetOffsetCalibrationData(vl53l0_dev, offsetint);
+ */
+ break;
+
+ /* Config use case */
+ case VL53L0_IOCTL_ACTIVATE_USE_CASE:
+ vl53l0_dbgmsg("VL53L0_IOCTL_ACTIVATE_USE_CASE\n");
+ if (copy_from_user(&useCase, (uint8_t *)p, sizeof(uint8_t))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+
+ /* Validate the user passed use case.
+ * Update the timingBudget value. The other
+ * parameters are updated approrpiately in config_use_case()
+ * Currently the timing budget can be updated through
+ * sysfs entry, and this needs additional steps to manage.
+ */
+ switch (useCase) {
+ case USE_CASE_LONG_DISTANCE:
+ data->timingBudget = LONG_DISTANCE_TIMING_BUDGET;
+ break;
+
+ case USE_CASE_HIGH_ACCURACY:
+ data->timingBudget = HIGH_ACCURACY_TIMING_BUDGET;
+ break;
+
+ case USE_CASE_HIGH_SPEED:
+ data->timingBudget = HIGH_SPEED_TIMING_BUDGET;
+ break;
+
+ default:
+ vl53l0_errmsg("%d, Unknown Use case = %u\n", __LINE__,
+ useCase);
+ return -EFAULT;
+ }
+ vl53l0_dbgmsg("useCase as %d\n", useCase);
+ /* record the use case */
+ data->useCase = useCase;
+
+ /* If ranging is in progress, let the work handler
+ * update the use case
+ */
+ if (data->enable_ps_sensor)
+ data->updateUseCase = 1;
+ break;
+
+ /* Config Custom use case */
+ case VL53L0_IOCTL_ACTIVATE_CUSTOM_USE_CASE:
+ vl53l0_dbgmsg("VL53L0_IOCTL_ACTIVATE_CUSTOM_USE_CASE\n");
+ if (copy_from_user(&customUseCase,
+ (struct stmvl53l0_custom_use_case *)p,
+ sizeof(struct stmvl53l0_custom_use_case))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+
+ data->sigmaLimit = customUseCase.sigmaLimit;
+ data->signalRateLimit = customUseCase.signalRateLimit;
+ data->preRangePulsePeriod = customUseCase.preRangePulsePeriod;
+ data->finalRangePulsePeriod =
+ customUseCase.finalRangePulsePeriod;
+ data->timingBudget = customUseCase.timingBudget;
+ vl53l0_dbgmsg(
+ "Sigma=%u,Signal=%u,Pre=%u,Final=%u,timingBudget=%u\n",
+ data->sigmaLimit,
+ data->signalRateLimit,
+ data->preRangePulsePeriod,
+ data->finalRangePulsePeriod,
+ data->timingBudget);
+
+ /* record the use case */
+ data->useCase = USE_CASE_CUSTOM;
+ /* If ranging is in progress,
+ * let the work handler update the use case
+ */
+ if (data->enable_ps_sensor)
+ data->updateUseCase = 1;
+
+ break;
+
+
+ /* disable */
+ case VL53L0_IOCTL_STOP:
+ vl53l0_dbgmsg("VL53L0_IOCTL_STOP\n");
+ /* turn off tof sensor only if it's enabled by other client */
+ if (data->enable_ps_sensor == 1) {
+ data->enable_ps_sensor = 0;
+ /* to stop */
+ stmvl53l0_stop(data);
+ }
+ break;
+ /* Get all range data */
+ case VL53L0_IOCTL_GETDATAS:
+ vl53l0_dbgmsg("VL53L0_IOCTL_GETDATAS\n");
+ if (copy_to_user((VL53L0_RangingMeasurementData_t *)p,
+ &(data->rangeData),
+ sizeof(VL53L0_RangingMeasurementData_t))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ break;
+ /* Register tool */
+ case VL53L0_IOCTL_REGISTER:
+ vl53l0_dbgmsg("VL53L0_IOCTL_REGISTER\n");
+ if (copy_from_user(&reg, (struct stmvl53l0_register *)p,
+ sizeof(struct stmvl53l0_register))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ reg.status = 0;
+ page_num = (uint8_t)((reg.reg_index & 0x0000ff00) >> 8);
+ vl53l0_dbgmsg(
+"VL53L0_IOCTL_REGISTER, page number:%d\n", page_num);
+ if (page_num != 0)
+ reg.status = VL53L0_WrByte(vl53l0_dev, 0xFF, page_num);
+
+ switch (reg.reg_bytes) {
+ case(4):
+ if (reg.is_read)
+ reg.status = VL53L0_RdDWord(vl53l0_dev,
+ (uint8_t)reg.reg_index,
+ &reg.reg_data);
+ else
+ reg.status = VL53L0_WrDWord(vl53l0_dev,
+ (uint8_t)reg.reg_index,
+ reg.reg_data);
+ break;
+ case(2):
+ if (reg.is_read)
+ reg.status = VL53L0_RdWord(vl53l0_dev,
+ (uint8_t)reg.reg_index,
+ (uint16_t *)&reg.reg_data);
+ else
+ reg.status = VL53L0_WrWord(vl53l0_dev,
+ (uint8_t)reg.reg_index,
+ (uint16_t)reg.reg_data);
+ break;
+ case(1):
+ if (reg.is_read)
+ reg.status = VL53L0_RdByte(vl53l0_dev,
+ (uint8_t)reg.reg_index,
+ (uint8_t *)&reg.reg_data);
+ else
+ reg.status = VL53L0_WrByte(vl53l0_dev,
+ (uint8_t)reg.reg_index,
+ (uint8_t)reg.reg_data);
+ break;
+ default:
+ reg.status = -1;
+
+ }
+ if (page_num != 0)
+ reg.status = VL53L0_WrByte(vl53l0_dev, 0xFF, 0);
+
+
+ if (copy_to_user((struct stmvl53l0_register *)p, &reg,
+ sizeof(struct stmvl53l0_register))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ break;
+ /* parameter access */
+ case VL53L0_IOCTL_PARAMETER:
+ vl53l0_dbgmsg("VL53L0_IOCTL_PARAMETER\n");
+ if (copy_from_user(&parameter, (struct stmvl53l0_parameter *)p,
+ sizeof(struct stmvl53l0_parameter))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ parameter.status = 0;
+ if (data->enableDebug)
+ vl53l0_dbgmsg(
+ "VL53L0_IOCTL_PARAMETER Name = %d\n", parameter.name);
+ switch (parameter.name) {
+ case (OFFSET_PAR):
+ if (parameter.is_read)
+ parameter.status =
+ papi_func_tbl->GetOffsetCalibrationDataMicroMeter(
+ vl53l0_dev, &parameter.value);
+ else {
+ parameter.status =
+ papi_func_tbl->SetOffsetCalibrationDataMicroMeter(
+ vl53l0_dev, parameter.value);
+ data->OffsetMicroMeter = parameter.value;
+ data->setCalibratedValue
+ |= SET_OFFSET_CALIB_DATA_MICROMETER_MASK;
+
+ }
+ vl53l0_dbgmsg("get parameter value as %d\n",
+ parameter.value);
+ break;
+
+ case (REFERENCESPADS_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetReferenceSpads(vl53l0_dev,
+ (uint32_t *)&(parameter.value),
+ (uint8_t *)&(parameter.value2));
+ if (data->enableDebug)
+ vl53l0_dbgmsg(
+ "Get RefSpad : Count:%u, Type:%u\n",
+ parameter.value,
+ (uint8_t)parameter.value2);
+ } else {
+ if (data->enableDebug)
+ vl53l0_dbgmsg(
+ "Set RefSpad : Count:%u, Type:%u\n",
+ parameter.value,
+ (uint8_t)parameter.value2);
+
+ parameter.status =
+ papi_func_tbl->SetReferenceSpads(vl53l0_dev,
+ (uint32_t)(parameter.value),
+ (uint8_t)(parameter.value2));
+
+ data->refSpadCount = parameter.value;
+ data->isApertureSpads =
+ (uint8_t)(parameter.value2);
+ }
+ break;
+
+ case (REFCALIBRATION_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetRefCalibration(vl53l0_dev,
+ (uint8_t *)&(parameter.value),
+ (uint8_t *)&(parameter.value2));
+ if (data->enableDebug)
+ vl53l0_dbgmsg(
+ "Get Ref : Vhv:%u, PhaseCal:%u\n",
+ (uint8_t)parameter.value,
+ (uint8_t)parameter.value2);
+ } else {
+ if (data->enableDebug)
+ vl53l0_dbgmsg(
+ "Set Ref : Vhv:%u, PhaseCal:%u\n",
+ (uint8_t)parameter.value,
+ (uint8_t)parameter.value2);
+ parameter.status =
+ papi_func_tbl->SetRefCalibration(
+ vl53l0_dev,
+ (uint8_t)(parameter.value),
+ (uint8_t)(parameter.value2));
+ data->VhvSettings = (uint8_t)parameter.value;
+ data->PhaseCal = (uint8_t)(parameter.value2);
+ }
+ break;
+ case (XTALKRATE_PAR):
+ if (parameter.is_read)
+ parameter.status =
+ papi_func_tbl->GetXTalkCompensationRateMegaCps(
+ vl53l0_dev,
+ (FixPoint1616_t *)
+ &parameter.value);
+ else {
+ /* Range Ignore Threshold value */
+ FixPoint1616_t ritValue = 0;
+
+ parameter.status =
+ papi_func_tbl->SetXTalkCompensationRateMegaCps(
+ vl53l0_dev,
+ (FixPoint1616_t)
+ parameter.value);
+ data->XTalkCompensationRateMegaCps =
+ parameter.value;
+ data->setCalibratedValue |=
+ SET_XTALK_COMP_RATE_MCPS_MASK;
+
+
+ /*0.7 KCps converted to MCps */
+ if (data->XTalkCompensationRateMegaCps <
+ 7*65536/10000) {
+ ritValue = 15 * 7 * 65536/100000;
+ } else {
+ ritValue = 15 *
+ vl53l0_dev->XTalkCompensationRateMegaCps
+ /10;
+ }
+
+ if (papi_func_tbl->SetLimitCheckEnable
+ != NULL) {
+ Status =
+ papi_func_tbl->SetLimitCheckEnable(
+ vl53l0_dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ 1);
+ }
+
+ if ((Status == VL53L0_ERROR_NONE) &&
+ (papi_func_tbl->SetLimitCheckValue
+ != NULL)) {
+ vl53l0_dbgmsg(
+ "Set RIT - %u\n", ritValue);
+ Status =
+ papi_func_tbl->SetLimitCheckValue(
+ vl53l0_dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ ritValue);
+ }
+
+ }
+ break;
+ case (XTALKENABLE_PAR):
+ if (parameter.is_read)
+ parameter.status =
+ papi_func_tbl->GetXTalkCompensationEnable(
+ vl53l0_dev,
+ (uint8_t *) &parameter.value);
+ else
+ parameter.status =
+ papi_func_tbl->SetXTalkCompensationEnable(
+ vl53l0_dev,
+ (uint8_t) parameter.value);
+ break;
+ case (GPIOFUNC_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetGpioConfig(
+ vl53l0_dev,
+ 0,
+ &deviceMode,
+ &data->gpio_function,
+ &data->gpio_polarity);
+ parameter.value =
+ data->gpio_function;
+ } else {
+ data->gpio_function = parameter.value;
+ parameter.status =
+ papi_func_tbl->SetGpioConfig(
+ vl53l0_dev,
+ 0,
+ 0,
+ data->gpio_function,
+ data->gpio_polarity);
+ }
+ break;
+ case (LOWTHRESH_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetInterruptThresholds(
+ vl53l0_dev,
+ 0,
+ &(data->low_threshold),
+ &(data->high_threshold));
+ parameter.value =
+ data->low_threshold >> 16;
+ } else {
+ data->low_threshold = parameter.value << 16;
+ parameter.status =
+ papi_func_tbl->SetInterruptThresholds(
+ vl53l0_dev,
+ 0,
+ data->low_threshold,
+ data->high_threshold);
+ }
+ break;
+ case (HIGHTHRESH_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetInterruptThresholds(
+ vl53l0_dev,
+ 0,
+ &(data->low_threshold),
+ &(data->high_threshold));
+ parameter.value =
+ data->high_threshold >> 16;
+ } else {
+ data->high_threshold =
+ parameter.value << 16;
+ parameter.status =
+ papi_func_tbl->SetInterruptThresholds(
+ vl53l0_dev,
+ 0,
+ data->low_threshold,
+ data->high_threshold);
+ }
+ break;
+ case (DEVICEMODE_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetDeviceMode(
+ vl53l0_dev,
+ (VL53L0_DeviceModes *)&(parameter.value));
+ } else {
+ parameter.status =
+ papi_func_tbl->SetDeviceMode(
+ vl53l0_dev,
+ (VL53L0_DeviceModes)(parameter.value));
+ data->deviceMode =
+ (VL53L0_DeviceModes)(parameter.value);
+ }
+ break;
+
+
+
+ case (INTERMEASUREMENT_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetInterMeasurementPeriodMilliSeconds(
+ vl53l0_dev,
+ (uint32_t *)&(parameter.value));
+ } else {
+ parameter.status =
+ papi_func_tbl->SetInterMeasurementPeriodMilliSeconds(
+ vl53l0_dev,
+ (uint32_t)(parameter.value));
+ data->interMeasurems = parameter.value;
+ }
+ break;
+
+ }
+
+ if (copy_to_user((struct stmvl53l0_parameter *)p, &parameter,
+ sizeof(struct stmvl53l0_parameter))) {
+ vl53l0_errmsg("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static int stmvl53l0_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+/* Flush will be invoked on close(device_fd) */
+static int stmvl53l0_flush(struct file *file, fl_owner_t id)
+{
+ struct stmvl53l0_data *data = container_of(file->private_data,
+ struct stmvl53l0_data, miscdev);
+ (void) file;
+ (void) id;
+ /* Revisit : Check if the
+ *instance are opened multiple times on some platforms
+ */
+ mutex_lock(&data->work_mutex);
+ if (data) {
+ if (data->enable_ps_sensor == 1) {
+ /* turn off tof sensor if it's enabled */
+ data->enable_ps_sensor = 0;
+ /* to stop */
+ stmvl53l0_stop(data);
+ }
+ }
+ mutex_unlock(&data->work_mutex);
+
+ return 0;
+}
+
+static long stmvl53l0_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ long ret;
+ struct stmvl53l0_data *data =
+ container_of(file->private_data,
+ struct stmvl53l0_data, miscdev);
+ mutex_lock(&data->work_mutex);
+ ret = stmvl53l0_ioctl_handler(file, cmd, arg, (void __user *)arg);
+ mutex_unlock(&data->work_mutex);
+
+ return ret;
+}
+
+/*
+ * Initialization function
+ */
+static int stmvl53l0_init_client(struct stmvl53l0_data *data)
+{
+
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ VL53L0_DeviceInfo_t DeviceInfo;
+ VL53L0_DEV vl53l0_dev = data;
+ uint32_t refSpadCount;
+ uint8_t isApertureSpads;
+ uint8_t VhvSettings;
+ uint8_t PhaseCal;
+
+
+ vl53l0_dbgmsg("Enter\n");
+
+ data->I2cDevAddr = 0x52;
+ data->comms_type = 1;
+ data->comms_speed_khz = 400;
+
+
+
+ /* Setup API functions based on revision */
+ stmvl53l0_setupAPIFunctions(data);
+
+ /* Perform Ref and RefSpad calibrations and save the values */
+
+
+ if (data->reset) {
+ pr_err("Call of VL53L0_DataInit\n");
+ /* Data initialization */
+ Status = papi_func_tbl->DataInit(vl53l0_dev);
+ /* data->reset = 0; */
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "%d- error status %d\n", __LINE__, Status);
+ return Status;
+ }
+ }
+
+ vl53l0_dbgmsg("VL53L0_GetDeviceInfo:\n");
+ Status = papi_func_tbl->GetDeviceInfo(vl53l0_dev, &DeviceInfo);
+ if (Status == VL53L0_ERROR_NONE) {
+ pr_err("Device Name : %s\n", DeviceInfo.Name);
+ pr_err("Device Type : %s\n", DeviceInfo.Type);
+ pr_err("Device ID : %s\n", DeviceInfo.ProductId);
+ pr_err("Product type: %d\n", DeviceInfo.ProductType);
+ pr_err("ProductRevisionMajor : %d\n",
+ DeviceInfo.ProductRevisionMajor);
+ pr_err("ProductRevisionMinor : %d\n",
+ DeviceInfo.ProductRevisionMinor);
+ }
+ /* Device Initialization */
+ vl53l0_dbgmsg("Call of VL53L0_StaticInit\n");
+ Status = papi_func_tbl->StaticInit(vl53l0_dev);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg("%d- error status %d\n", __LINE__, Status);
+ return Status;
+ }
+
+
+
+
+
+ if (papi_func_tbl->PerformRefCalibration != NULL && data->reset) {
+ vl53l0_dbgmsg("Call of VL53L0_PerformRefCalibration\n");
+ Status = papi_func_tbl->PerformRefCalibration(vl53l0_dev,
+ &VhvSettings, &PhaseCal); /* Ref calibration */
+ if (Status !=
+ VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "%d- error status %d\n", __LINE__, Status);
+ return Status;
+ }
+ }
+ vl53l0_dbgmsg("VHV = %u, PhaseCal = %u\n", VhvSettings, PhaseCal);
+ vl53l0_dev->VhvSettings = VhvSettings;
+ vl53l0_dev->PhaseCal = PhaseCal;
+
+ if (papi_func_tbl->PerformRefSpadManagement != NULL && data->reset) {
+ vl53l0_dbgmsg(
+ "Call of VL53L0_PerformRefSpadManagement\n");
+ Status = papi_func_tbl->PerformRefSpadManagement(vl53l0_dev,
+ &refSpadCount,
+ &isApertureSpads); /* Ref Spad Management */
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "%d- error status %d\n", __LINE__, Status);
+ return Status;
+ }
+ }
+
+ vl53l0_dbgmsg(
+ "SpadCount = %u, isAperature = %u\n",
+ refSpadCount, isApertureSpads);
+ vl53l0_dev->refSpadCount = refSpadCount;
+ vl53l0_dev->isApertureSpads = isApertureSpads;
+
+
+
+
+ if (Status == VL53L0_ERROR_NONE && data->reset) {
+ if ((papi_func_tbl->SetOffsetCalibrationDataMicroMeter
+ != NULL) &&
+ (vl53l0_dev->setCalibratedValue &
+ SET_OFFSET_CALIB_DATA_MICROMETER_MASK)) {
+ vl53l0_dbgmsg(
+ "Call of SetOffsetCalibrationDataMicroMeter\n");
+ Status =
+ papi_func_tbl->SetOffsetCalibrationDataMicroMeter(
+ vl53l0_dev,
+ vl53l0_dev->OffsetMicroMeter);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "%d- error status %d\n", __LINE__, Status);
+ return Status;
+ }
+ }
+ }
+
+
+
+ if (data->reset) {
+ if ((papi_func_tbl->SetXTalkCompensationRateMegaCps != NULL) &&
+ (vl53l0_dev->setCalibratedValue &
+ SET_XTALK_COMP_RATE_MCPS_MASK)) {
+ vl53l0_dbgmsg(
+ "Call of SetXTalkCompensationRateMegaCps\n");
+ Status = papi_func_tbl->SetXTalkCompensationRateMegaCps(
+ vl53l0_dev,
+ vl53l0_dev->XTalkCompensationRateMegaCps);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "%d- error status %d\n",
+ __LINE__, Status);
+ return Status;
+ }
+ }
+ }
+
+ if (data->reset) {
+ if (vl53l0_dev->setCalibratedValue &
+ /* Xtalk calibration done*/
+ SET_XTALK_COMP_RATE_MCPS_MASK) {
+ /* Range Ignore Threshold */
+ FixPoint1616_t ritValue = 0;
+
+ if (vl53l0_dev->XTalkCompensationRateMegaCps <
+ 7*65536/10000) {
+ /*0.7 KCps converted to MCps */
+ ritValue = 15 * 7 * 65536/100000;
+ } else {
+ ritValue = 15 *
+ vl53l0_dev->XTalkCompensationRateMegaCps/10;
+ }
+
+ if (papi_func_tbl->SetLimitCheckEnable != NULL) {
+ Status = papi_func_tbl->SetLimitCheckEnable(
+ vl53l0_dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ 1);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "%d- error status %d\n", __LINE__,
+ Status);
+ return Status;
+ }
+ }
+
+ if (papi_func_tbl->SetLimitCheckValue != NULL) {
+ vl53l0_dbgmsg("Set RIT - %u\n", ritValue);
+ Status = papi_func_tbl->SetLimitCheckValue(
+ vl53l0_dev,
+ VL53L0_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ ritValue);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "%d- error status %d\n",
+ __LINE__, Status);
+ return Status;
+ }
+ }
+ }
+ data->reset = 0;
+ }
+
+ /* Setup in single ranging mode */
+
+ pr_err("Call of VL53L0_SetDeviceMode\n");
+ Status = papi_func_tbl->SetDeviceMode(vl53l0_dev,
+ VL53L0_DEVICEMODE_SINGLE_RANGING);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg("%d- error status %d\n", __LINE__, Status);
+ return Status;
+ }
+
+
+ Status = papi_func_tbl->SetWrapAroundCheckEnable(vl53l0_dev, 1);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg("%d- error status %d\n", __LINE__, Status);
+ return Status;
+ }
+
+
+ vl53l0_dbgmsg("End\n");
+
+ return 0;
+}
+
+
+static int stmvl53l0_config_use_case(struct stmvl53l0_data *data)
+{
+ VL53L0_DEV vl53l0_dev = data;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+ FixPoint1616_t signalRateLimit;
+ FixPoint1616_t sigmaLimit;
+ uint32_t preRangePulsePeriod;
+ uint32_t finalRangePulsePeriod;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ switch (vl53l0_dev->useCase) {
+
+ case USE_CASE_LONG_DISTANCE:
+ sigmaLimit = LONG_DISTANCE_SIGMA_LIMIT;
+ signalRateLimit = LONG_DISTANCE_SIGNAL_RATE_LIMIT;
+ preRangePulsePeriod = LONG_DISTANCE_PRE_RANGE_PULSE_PERIOD;
+ finalRangePulsePeriod = LONG_DISTANCE_FINAL_RANGE_PULSE_PERIOD;
+ break;
+
+ case USE_CASE_HIGH_ACCURACY:
+ sigmaLimit = HIGH_ACCURACY_SIGMA_LIMIT;
+ signalRateLimit = HIGH_ACCURACY_SIGNAL_RATE_LIMIT;
+ preRangePulsePeriod = HIGH_ACCURACY_PRE_RANGE_PULSE_PERIOD;
+ finalRangePulsePeriod = HIGH_ACCURACY_FINAL_RANGE_PULSE_PERIOD;
+ break;
+
+ case USE_CASE_HIGH_SPEED:
+ sigmaLimit = HIGH_SPEED_SIGMA_LIMIT;
+ signalRateLimit = HIGH_SPEED_SIGNAL_RATE_LIMIT;
+ preRangePulsePeriod = HIGH_SPEED_PRE_RANGE_PULSE_PERIOD;
+ finalRangePulsePeriod = HIGH_SPEED_FINAL_RANGE_PULSE_PERIOD;
+ break;
+
+ case USE_CASE_CUSTOM:
+ /* Set by application through IOCTL interface */
+ sigmaLimit = vl53l0_dev->sigmaLimit;
+ signalRateLimit = vl53l0_dev->signalRateLimit;
+ preRangePulsePeriod = vl53l0_dev->preRangePulsePeriod;
+ finalRangePulsePeriod = vl53l0_dev->finalRangePulsePeriod;
+ break;
+
+ default:
+ vl53l0_errmsg(
+ "Invalid use case = %d\n", vl53l0_dev->useCase);
+ /* Invalid parameter, should not reach here */
+ return -EINVAL;
+ }
+
+ vl53l0_dbgmsg(
+ "Configure UseCase(%d) : Sigma=%u,Signal=%u,Pre=%u,Final=%u,timingBudget=%u\n",
+ vl53l0_dev->useCase,
+ sigmaLimit,
+ signalRateLimit,
+ preRangePulsePeriod,
+ finalRangePulsePeriod,
+ vl53l0_dev->timingBudget);
+
+ if (papi_func_tbl->SetLimitCheckEnable != NULL) {
+ Status = papi_func_tbl->SetLimitCheckEnable(
+ vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ 1);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = papi_func_tbl->SetLimitCheckEnable(
+ vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ 1);
+ } else {
+ vl53l0_errmsg(
+ "SetLimitCheckEnable(SIGMA_FINAL_RANGE) failed with errcode = %d\n",
+ Status);
+ }
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = papi_func_tbl->SetLimitCheckValue(
+ vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ signalRateLimit);
+ } else {
+ vl53l0_errmsg(
+ "SetLimitCheckEnable(SIGNAL_RATE_FINAL_RANGE) failed with errcode = %d\n",
+ Status);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = papi_func_tbl->SetLimitCheckValue(vl53l0_dev,
+ VL53L0_CHECKENABLE_SIGMA_FINAL_RANGE,
+ sigmaLimit);
+ } else {
+ vl53l0_dbgmsg(
+ "SIGNAL_RATE_FINAL_RANGE failed with errcode = %d\n",
+ Status);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status =
+ papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds(
+ vl53l0_dev,
+ vl53l0_dev->timingBudget);
+ } else {
+ vl53l0_dbgmsg(
+ "SIGMA_FINAL_RANGE failed with errcode = %d\n",
+ Status);
+ }
+
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0_dev,
+ VL53L0_VCSEL_PERIOD_PRE_RANGE,
+ preRangePulsePeriod);
+ } else {
+ vl53l0_dbgmsg(
+ "SetMeasurementTimingBudget failed with errcode = %d\n",
+ Status);
+ }
+
+ if (Status == VL53L0_ERROR_NONE) {
+ Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0_dev,
+ VL53L0_VCSEL_PERIOD_FINAL_RANGE,
+ finalRangePulsePeriod);
+ } else
+ vl53l0_dbgmsg(
+ "SetVcselPulsePeriod(PRE) failed with errcode = %d\n", Status);
+
+
+ if (Status != VL53L0_ERROR_NONE)
+ vl53l0_dbgmsg(
+ "SetVcselPulsePeriod(FINAL)failed with errcode = %d\n", Status);
+
+ vl53l0_dbgmsg("End\n");
+ return Status;
+}
+static int stmvl53l0_start(struct stmvl53l0_data *data, uint8_t scaling,
+ init_mode_e mode)
+{
+ int rc = 0;
+ VL53L0_DEV vl53l0_dev = data;
+ VL53L0_Error Status = VL53L0_ERROR_NONE;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* Power up */
+ rc = pmodule_func_tbl->power_up(data->client_object, &data->reset);
+ if (rc) {
+ vl53l0_errmsg("%d,error rc %d\n", __LINE__, rc);
+ return rc;
+ }
+
+ /* init */
+ rc = stmvl53l0_init_client(data);
+ if (rc) {
+ vl53l0_errmsg("%d, error rc %d\n", __LINE__, rc);
+ pmodule_func_tbl->power_down(data->client_object);
+ return -EINVAL;
+ }
+
+ /* check mode */
+ if (mode != NORMAL_MODE)
+ papi_func_tbl->SetXTalkCompensationEnable(vl53l0_dev, 1);
+
+ if (mode == OFFSETCALIB_MODE) {
+ /*VL53L0_SetOffsetCalibrationDataMicroMeter(vl53l0_dev, 0);*/
+ FixPoint1616_t OffsetMicroMeter;
+
+ papi_func_tbl->PerformOffsetCalibration(vl53l0_dev,
+ (data->offsetCalDistance<<16),
+ &OffsetMicroMeter);
+ pr_err("Offset calibration:%u\n", OffsetMicroMeter);
+ vl53l0_dev->OffsetMicroMeter = OffsetMicroMeter;
+ vl53l0_dev->setCalibratedValue |=
+ SET_OFFSET_CALIB_DATA_MICROMETER_MASK;
+
+ return rc;
+ } else if (mode == XTALKCALIB_MODE) {
+ FixPoint1616_t XTalkCompensationRateMegaCps;
+ /*caltarget distance : 100mm and convert to
+ * fixed point 16 16 format
+ */
+ papi_func_tbl->PerformXTalkCalibration(vl53l0_dev,
+ (data->xtalkCalDistance<<16),
+ &XTalkCompensationRateMegaCps);
+ pr_err("Xtalk calibration:%u\n",
+ XTalkCompensationRateMegaCps);
+ vl53l0_dev->XTalkCompensationRateMegaCps =
+ XTalkCompensationRateMegaCps;
+ vl53l0_dev->setCalibratedValue |=
+ SET_XTALK_COMP_RATE_MCPS_MASK;
+
+ return rc;
+ }
+ /* set up device parameters */
+ data->gpio_polarity = VL53L0_INTERRUPTPOLARITY_LOW;
+
+ /* Following two calls are made from IOCTL as well */
+ Status = papi_func_tbl->SetGpioConfig(vl53l0_dev, 0, 0,
+ data->gpio_function,
+ VL53L0_INTERRUPTPOLARITY_LOW);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg("Failed to SetGpioConfig. Error = %d\n", Status);
+ return -EPERM;
+ }
+
+
+ Status = papi_func_tbl->SetInterruptThresholds(vl53l0_dev, 0,
+ data->low_threshold,
+ data->high_threshold);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "Failed to SetInterruptThresholds. Error = %d\n", Status);
+ return -EPERM;
+ }
+
+
+ if (data->deviceMode == VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING) {
+ Status = papi_func_tbl->SetInterMeasurementPeriodMilliSeconds(
+ vl53l0_dev,
+ data->interMeasurems);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "Failed to SetInterMeasurementPeriodMilliSeconds. Error = %d\n",
+ Status);
+ return -EPERM;
+ }
+ pr_err(
+ "DeviceMode:0x%x, interMeasurems:%d==\n",
+ data->deviceMode,
+ data->interMeasurems);
+
+
+ }
+
+
+ Status = papi_func_tbl->SetDeviceMode(
+ vl53l0_dev,
+ data->deviceMode);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg("Failed to SetDeviceMode. Error = %d\n", Status);
+ return -EPERM;
+ }
+
+ Status = papi_func_tbl->ClearInterruptMask(vl53l0_dev,
+ 0);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "Failed to ClearInterruptMask. Error = %d\n", Status);
+ return -EPERM;
+ }
+
+
+
+ Status = stmvl53l0_config_use_case(vl53l0_dev);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "Failed to configure Use case = %u\n",
+ vl53l0_dev->useCase);
+ return -EPERM;
+ }
+
+ /* start the ranging */
+ Status = papi_func_tbl->StartMeasurement(vl53l0_dev);
+ if (Status != VL53L0_ERROR_NONE) {
+ vl53l0_errmsg(
+ "Failed to StartMeasurement. Error = %d\n", Status);
+ return -EPERM;
+ }
+
+ data->enable_ps_sensor = 1;
+
+#ifndef USE_INT
+ /* Unblock the thread execution */
+ wake_up(&vl53l0_dev->poll_thread_wq);
+#endif
+
+ vl53l0_dbgmsg("End\n");
+
+ return rc;
+}
+
+static int stmvl53l0_stop(struct stmvl53l0_data *data)
+{
+ int rc = 0;
+ VL53L0_DEV vl53l0_dev = data;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* stop - if continuous mode */
+ if (data->deviceMode == VL53L0_DEVICEMODE_CONTINUOUS_RANGING ||
+ data->deviceMode == VL53L0_DEVICEMODE_CONTINUOUS_TIMED_RANGING)
+ papi_func_tbl->StopMeasurement(vl53l0_dev);
+
+ /* clean interrupt */
+ papi_func_tbl->ClearInterruptMask(vl53l0_dev, 0);
+
+ /* cancel work handler */
+ stmvl53l0_cancel_handler(data);
+
+ /* Clear updateUseCase pending operation */
+ data->updateUseCase = 0;
+ /* power down */
+ rc = pmodule_func_tbl->power_down(data->client_object);
+ if (rc) {
+ vl53l0_errmsg("%d, error rc %d\n", __LINE__, rc);
+ return rc;
+ }
+ vl53l0_dbgmsg("End\n");
+
+ return rc;
+}
+static void stmvl53l0_timer_fn(unsigned long data)
+{
+
+ VL53L0_DEV vl53l0_dev = (VL53L0_DEV)data;
+
+ vl53l0_dev->flushCount++;
+
+ input_report_abs(vl53l0_dev->input_dev_ps, ABS_GAS,
+ vl53l0_dev->flushCount);
+
+
+ input_sync(vl53l0_dev->input_dev_ps);
+
+ vl53l0_dbgmsg("Sensor HAL Flush Count = %u\n", vl53l0_dev->flushCount);
+}
+
+
+
+/*
+ * I2C init/probing/exit functions
+ */
+static const struct file_operations stmvl53l0_ranging_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = stmvl53l0_ioctl,
+ .open = stmvl53l0_open,
+ .flush = stmvl53l0_flush,
+};
+
+
+
+int stmvl53l0_setup(struct stmvl53l0_data *data)
+{
+ int rc = 0;
+
+#ifdef USE_INT
+ int irq = 0;
+#endif
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* init mutex */
+ mutex_init(&data->update_lock);
+ mutex_init(&data->work_mutex);
+
+#ifdef USE_INT
+ /* init interrupt */
+ gpio_request(IRQ_NUM, "vl53l0_gpio_int");
+ gpio_direction_input(IRQ_NUM);
+ irq = gpio_to_irq(IRQ_NUM);
+ if (irq < 0) {
+ vl53l0_errmsg("filed to map GPIO: %d to interrupt:%d\n",
+ IRQ_NUM, irq);
+ } else {
+ vl53l0_dbgmsg("register_irq:%d\n", irq);
+ /* IRQF_TRIGGER_FALLING- poliarity:0 IRQF_TRIGGER_RISNG -
+ * poliarty:1
+ */
+ rc = request_threaded_irq(irq, NULL,
+ stmvl53l0_interrupt_handler,
+ IRQF_TRIGGER_FALLING|IRQF_ONESHOT,
+ "vl53l0_interrupt",
+ (void *)data);
+ if (rc) {
+ vl53l0_errmsg(
+"%d, Could not allocate STMVL53L0_INT ! result:%d\n", __LINE__, rc);
+ free_irq(irq, data);
+ goto exit_free_irq;
+ }
+ }
+ data->irq = irq;
+ vl53l0_errmsg("interrupt is hooked\n");
+#else
+
+ init_waitqueue_head(&data->poll_thread_wq);
+
+ data->poll_thread = kthread_run(&stmvl53l0_poll_thread,
+ (void *)data,
+ "STM-VL53L0");
+ if (data->poll_thread == NULL) {
+ pr_err(
+ "%s(%d) - Failed to create Polling thread\n", __func__, __LINE__);
+ goto exit_free_irq;
+ }
+#endif
+
+ /* init work handler */
+ INIT_DELAYED_WORK(&data->dwork, stmvl53l0_work_handler);
+
+ /* Register to Input Device */
+ data->input_dev_ps = input_allocate_device();
+ if (!data->input_dev_ps) {
+ rc = -ENOMEM;
+ vl53l0_errmsg("%d error:%d\n", __LINE__, rc);
+ goto exit_free_irq;
+ }
+ set_bit(EV_ABS, data->input_dev_ps->evbit);
+ /* range in cm*/
+ input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 76, 0, 0);
+ /* tv_sec */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT0X, 0, 0xffffffff,
+ 0, 0);
+ /* tv_usec */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT0Y, 0, 0xffffffff,
+ 0, 0);
+ /* range in_mm */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT1X, 0, 765, 0, 0);
+ /* error code change maximum to 0xff for more flexibility */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT1Y, 0, 0xff, 0, 0);
+ /* rtnRate */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT2X, 0, 0xffffffff,
+ 0, 0);
+ /* rtn_amb_rate */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT2Y, 0, 0xffffffff,
+ 0, 0);
+ /* rtn_conv_time */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT3X, 0, 0xffffffff,
+ 0, 0);
+ /* dmax */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT3Y, 0, 0xffffffff,
+ 0, 0);
+
+ input_set_abs_params(data->input_dev_ps, ABS_PRESSURE, 0, 0xffffffff,
+ 0, 0);
+
+ input_set_abs_params(data->input_dev_ps, ABS_WHEEL, 0, 0xffffffff,
+ 0, 0);
+
+ input_set_abs_params(data->input_dev_ps, ABS_GAS, 0, 0xffffffff,
+ 0, 0);
+ data->input_dev_ps->name = "STM VL53L0 proximity sensor";
+
+ rc = input_register_device(data->input_dev_ps);
+ if (rc) {
+ rc = -ENOMEM;
+ vl53l0_errmsg("%d error:%d\n", __LINE__, rc);
+ goto exit_free_dev_ps;
+ }
+ /* setup drv data */
+ input_set_drvdata(data->input_dev_ps, data);
+
+ /* Register sysfs hooks */
+ data->range_kobj = kobject_create_and_add("range", kernel_kobj);
+ if (!data->range_kobj) {
+ rc = -ENOMEM;
+ vl53l0_errmsg("%d error:%d\n", __LINE__, rc);
+ goto exit_unregister_dev_ps;
+ }
+ rc = sysfs_create_group(&data->input_dev_ps->dev.kobj,
+ &stmvl53l0_attr_group);
+ if (rc) {
+ rc = -ENOMEM;
+ vl53l0_errmsg("%d error:%d\n", __LINE__, rc);
+ goto exit_unregister_dev_ps_1;
+ }
+
+ setup_timer(&data->timer,
+ stmvl53l0_timer_fn,
+ (unsigned long)data);
+
+ /* to register as a misc device */
+ data->miscdev.minor = MISC_DYNAMIC_MINOR;
+ data->miscdev.name = "stmvl53l0_ranging";
+ data->miscdev.fops = &stmvl53l0_ranging_fops;
+ vl53l0_errmsg("Misc device registration name:%s\n", data->dev_name);
+ if (misc_register(&data->miscdev) != 0)
+ vl53l0_errmsg(
+"Could not register misc. dev for stmvl53l0 ranging\n");
+
+ /* init default device parameter value */
+ data->enable_ps_sensor = 0;
+ data->reset = 1;
+ data->delay_ms = 30; /* delay time to 30ms */
+ data->enableDebug = 0;
+ data->gpio_polarity = VL53L0_INTERRUPTPOLARITY_LOW;
+ data->gpio_function = VL53L0_GPIOFUNCTIONALITY_NEW_MEASURE_READY;
+ data->low_threshold = 60;
+ data->high_threshold = 200;
+ data->deviceMode = VL53L0_DEVICEMODE_SINGLE_RANGING;
+ data->interMeasurems = 30;
+ data->useCase = USE_CASE_LONG_DISTANCE;
+ data->timingBudget = LONG_DISTANCE_TIMING_BUDGET;
+
+ /* Set default values used in Custom Mode Use Case */
+ data->signalRateLimit = LONG_DISTANCE_SIGNAL_RATE_LIMIT;
+ data->sigmaLimit = LONG_DISTANCE_SIGMA_LIMIT;
+ data->preRangePulsePeriod = LONG_DISTANCE_PRE_RANGE_PULSE_PERIOD;
+ data->finalRangePulsePeriod = LONG_DISTANCE_FINAL_RANGE_PULSE_PERIOD;
+
+
+
+
+ vl53l0_dbgmsg("support ver. %s enabled\n", DRIVER_VERSION);
+ vl53l0_dbgmsg("End");
+
+ return 0;
+exit_unregister_dev_ps_1:
+ kobject_put(data->range_kobj);
+exit_unregister_dev_ps:
+ input_unregister_device(data->input_dev_ps);
+exit_free_dev_ps:
+ input_free_device(data->input_dev_ps);
+exit_free_irq:
+#ifdef USE_INT
+ free_irq(irq, data);
+#endif
+ kfree(data);
+ return rc;
+}
+
+void stmvl53l0_cleanup(struct stmvl53l0_data *data)
+{
+#ifndef USE_INT
+ pr_err("%s(%d) : Stop poll_thread\n", __func__, __LINE__);
+ poll_thread_exit = 1;
+ kthread_stop(data->poll_thread);
+#endif
+}
+static int __init stmvl53l0_init(void)
+{
+ int ret = -1;
+
+ vl53l0_dbgmsg("Enter\n");
+
+ /* assign function table */
+ pmodule_func_tbl = &stmvl53l0_module_func_tbl;
+ papi_func_tbl = &stmvl53l0_api_func_tbl;
+
+ /* client specific init function */
+ ret = pmodule_func_tbl->init();
+
+ if (ret)
+ vl53l0_errmsg("%d failed with %d\n", __LINE__, ret);
+
+ vl53l0_dbgmsg("End\n");
+
+ return ret;
+}
+
+static void __exit stmvl53l0_exit(void)
+{
+ vl53l0_dbgmsg("Enter\n");
+
+ vl53l0_dbgmsg("End\n");
+}
+
+
+MODULE_AUTHOR("STMicroelectronics Imaging Division");
+MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(stmvl53l0_init);
+module_exit(stmvl53l0_exit);
+
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/Kconfig b/drivers/leds/Kconfig
index 0fc18922801e..966227a3df1a 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -581,40 +581,6 @@ config LEDS_POWERNV
depends on LEDS_CLASS
depends on PPC_POWERNV
depends on OF
-
-config LEDS_QPNP
- tristate "Support for QPNP LEDs"
- depends on LEDS_CLASS && SPMI
- help
- This driver supports the leds functionality of Qualcomm PNP PMIC. It
- includes RGB Leds, WLED and Flash Led.
-
- To compile this driver as a module, choose M here: the module will
- be called leds-qpnp.
-
-config LEDS_QPNP_FLASH
- tristate "Support for QPNP Flash LEDs"
- depends on LEDS_CLASS && SPMI
- help
- This driver supports the leds functionality of Qualcomm Technologies
- PNP PMIC. It includes Flash Led.
-
- To compile this driver as a module, choose M here: the module will
- be called leds-qpnp-flash.
-
-config LEDS_QPNP_FLASH_V2
- tristate "Support for QPNP V2 Flash LEDs"
- depends on LEDS_CLASS && MFD_SPMI_PMIC
- help
- This driver supports the leds functionality of Qualcomm Technologies
- PNP PMIC. It includes Flash Led.
-
- To compile this driver as a module, choose M here: the module will
- be called leds-qpnp-flash-v2.
-
-config LEDS_QPNP_WLED
- tristate "Support for QPNP WLED"
- depends on LEDS_CLASS && SPMI
help
This option enables support for the system LEDs present on
PowerNV platforms. Say 'y' to enable this support in kernel.
@@ -625,31 +591,38 @@ config LEDS_QPNP
tristate "Support for QPNP LEDs"
depends on LEDS_CLASS && SPMI
help
- This driver supports the leds functionality of Qualcomm PNP PMIC. It
- includes RGB Leds, WLED and Flash Led.
-
- To compile this driver as a module, choose M here: the module will
- be called leds-qpnp.
+ This driver supports the LED functionality of Qualcomm Technologies,
+ Inc. QPNP PMICs. It primarily supports controlling tri-color RGB
+ LEDs in both PWM and light pattern generator (LPG) modes. For older
+ PMICs, it also supports WLEDs and flash LEDs.
config LEDS_QPNP_FLASH
tristate "Support for QPNP Flash LEDs"
depends on LEDS_CLASS && SPMI
help
- This driver supports the leds functionality of Qualcomm Technologies
- PNP PMIC. It includes Flash Led.
+ This driver supports the flash LED functionality of Qualcomm
+ Technologies, Inc. QPNP PMICs. This driver supports PMICs up through
+ PM8994. It can configure the flash LED target current for several
+ independent channels.
- To compile this driver as a module, choose M here: the module will
- be called leds-qpnp-flash.
+config LEDS_QPNP_FLASH_V2
+ tristate "Support for QPNP V2 Flash LEDs"
+ depends on LEDS_CLASS && MFD_SPMI_PMIC && !LEDS_QPNP_FLASH
+ help
+ This driver supports the flash V2 LED functionality of Qualcomm
+ Technologies, Inc. QPNP PMICs. This driver supports PMICs starting
+ from PMI8998. It can configure the flash LED target current for
+ several independent channels. It also supports various over current
+ and over temperature mitigation features.
config LEDS_QPNP_WLED
tristate "Support for QPNP WLED"
depends on LEDS_CLASS && SPMI
help
- This driver supports the WLED (White LED) functionality of
- Qualcomm Technologies PNP PMIC. WLED is used for display backlight.
-
- To compile this driver as a module, choose M here: the module will
- be called leds-qpnp-wled.
+ This driver supports the WLED (White LED) functionality of Qualcomm
+ Technologies, Inc. QPNP PMICs. WLED is used for LCD backlight with
+ variable brightness. It also supports outputting the Avdd supply for
+ AMOLED displays.
config LEDS_SYSCON
bool "LED support for LEDs on system controllers"
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index b6aa4a87f31d..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) {
@@ -1166,6 +1168,10 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
struct qpnp_flash_led *led = NULL;
int rc;
+ /*
+ * strncmp() must be used here since a prefix comparison is required
+ * in order to support names like led:switch_0 and led:flash_1.
+ */
if (!strncmp(led_cdev->name, "led:switch", strlen("led:switch"))) {
snode = container_of(led_cdev, struct flash_switch_data, cdev);
led = dev_get_drvdata(&snode->pdev->dev);
@@ -1214,8 +1220,7 @@ static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
/* sysfs attributes exported by flash_led */
static struct device_attribute qpnp_flash_led_attrs[] = {
- __ATTR(max_current, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_flash_led_max_current_show, NULL),
+ __ATTR(max_current, 0664, qpnp_flash_led_max_current_show, NULL),
};
static int flash_led_psy_notifier_call(struct notifier_block *nb,
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index 98dfa56add51..c27c0593cd10 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.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
@@ -608,10 +608,9 @@ qpnp_flash_led_get_max_avail_current(struct flash_node_data *flash_node,
}
/*
- * When charging is enabled, enforce this new
- * enabelment sequence to reduce fuel gauge
- * resolution reading.
- */
+ * When charging is enabled, enforce this new enablement
+ * sequence to reduce fuel gauge reading resolution.
+ */
if (led->charging_enabled) {
rc = qpnp_led_masked_write(led,
FLASH_MODULE_ENABLE_CTRL(led->base),
@@ -637,10 +636,10 @@ qpnp_flash_led_get_max_avail_current(struct flash_node_data *flash_node,
max_curr_avail_ma = (prop.intval / FLASH_LED_UA_PER_MA);
}
- /* When thermal mitigation is available, this logic
- * will execute, to derate current based on PMIC die
- * temperature.
- */
+ /*
+ * When thermal mitigation is available, this logic will execute to
+ * derate current based upon the PMIC die temperature.
+ */
if (led->pdata->die_current_derate_en) {
chg_temp_milidegc = qpnp_flash_led_get_die_temp(led);
if (chg_temp_milidegc < 0)
@@ -797,21 +796,14 @@ static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
}
static struct device_attribute qpnp_flash_led_attrs[] = {
- __ATTR(strobe, (S_IRUGO | S_IWUSR | S_IWGRP),
- NULL,
- qpnp_led_strobe_type_store),
- __ATTR(reg_dump, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_flash_led_dump_regs_show,
- NULL),
- __ATTR(enable_current_derate, (S_IRUGO | S_IWUSR | S_IWGRP),
- NULL,
- qpnp_flash_led_current_derate_store),
- __ATTR(max_allowed_current, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_flash_led_max_current_show,
- NULL),
- __ATTR(enable_die_temp_current_derate, (S_IRUGO | S_IWUSR | S_IWGRP),
- NULL,
- qpnp_flash_led_die_temp_store),
+ __ATTR(strobe, 0664, NULL, qpnp_led_strobe_type_store),
+ __ATTR(reg_dump, 0664, qpnp_flash_led_dump_regs_show, NULL),
+ __ATTR(enable_current_derate, 0664, NULL,
+ qpnp_flash_led_current_derate_store),
+ __ATTR(max_allowed_current, 0664, qpnp_flash_led_max_current_show,
+ NULL),
+ __ATTR(enable_die_temp_current_derate, 0664, NULL,
+ qpnp_flash_led_die_temp_store),
};
static int qpnp_flash_led_get_thermal_derate_rate(const char *rate)
@@ -1771,8 +1763,6 @@ error_enable_gpio:
flash_node->flash_on = false;
mutex_unlock(&led->flash_led_lock);
-
- return;
}
static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
@@ -1823,8 +1813,6 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
}
queue_work(led->ordered_workq, &flash_node->work);
-
- return;
}
static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
@@ -2359,26 +2347,24 @@ static int qpnp_flash_led_parse_common_dt(
dev_err(&led->pdev->dev, "Unable to acquire pinctrl\n");
led->pinctrl = NULL;
return 0;
- } else {
- led->gpio_state_active =
- pinctrl_lookup_state(led->pinctrl, "flash_led_enable");
- if (IS_ERR_OR_NULL(led->gpio_state_active)) {
- dev_err(&led->pdev->dev,
- "Can not lookup LED active state\n");
- devm_pinctrl_put(led->pinctrl);
- led->pinctrl = NULL;
- return PTR_ERR(led->gpio_state_active);
- }
- led->gpio_state_suspend =
- pinctrl_lookup_state(led->pinctrl,
+ }
+
+ led->gpio_state_active = pinctrl_lookup_state(led->pinctrl,
+ "flash_led_enable");
+ if (IS_ERR_OR_NULL(led->gpio_state_active)) {
+ dev_err(&led->pdev->dev, "Cannot lookup LED active state\n");
+ devm_pinctrl_put(led->pinctrl);
+ led->pinctrl = NULL;
+ return PTR_ERR(led->gpio_state_active);
+ }
+
+ led->gpio_state_suspend = pinctrl_lookup_state(led->pinctrl,
"flash_led_disable");
- if (IS_ERR_OR_NULL(led->gpio_state_suspend)) {
- dev_err(&led->pdev->dev,
- "Can not lookup LED disable state\n");
- devm_pinctrl_put(led->pinctrl);
- led->pinctrl = NULL;
- return PTR_ERR(led->gpio_state_suspend);
- }
+ if (IS_ERR_OR_NULL(led->gpio_state_suspend)) {
+ dev_err(&led->pdev->dev, "Cannot lookup LED disable state\n");
+ devm_pinctrl_put(led->pinctrl);
+ led->pinctrl = NULL;
+ return PTR_ERR(led->gpio_state_suspend);
}
return 0;
@@ -2408,13 +2394,10 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
return rc;
}
- led = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_flash_led),
- GFP_KERNEL);
- if (!led) {
- dev_err(&pdev->dev,
- "Unable to allocate memory for flash LED\n");
+ led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
+ if (!led)
return -ENOMEM;
- }
+
led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!led->regmap) {
dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
@@ -2426,13 +2409,9 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
led->current_addr = FLASH_LED0_CURRENT(led->base);
led->current2_addr = FLASH_LED1_CURRENT(led->base);
- led->pdata = devm_kzalloc(&pdev->dev,
- sizeof(struct flash_led_platform_data), GFP_KERNEL);
- if (!led->pdata) {
- dev_err(&pdev->dev,
- "Unable to allocate memory for platform data\n");
+ led->pdata = devm_kzalloc(&pdev->dev, sizeof(*led->pdata), GFP_KERNEL);
+ if (!led->pdata)
return -ENOMEM;
- }
led->peripheral_type = (u8)qpnp_flash_led_get_peripheral_type(led);
if (led->peripheral_type < 0) {
@@ -2571,21 +2550,21 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
}
led->dbgfs_root = root;
- file = debugfs_create_file("enable_debug", S_IRUSR | S_IWUSR, root,
- led, &flash_led_dfs_dbg_feature_fops);
+ file = debugfs_create_file("enable_debug", 0600, root, led,
+ &flash_led_dfs_dbg_feature_fops);
if (!file) {
pr_err("error creating 'enable_debug' entry\n");
goto error_led_debugfs;
}
- file = debugfs_create_file("latched", S_IRUSR | S_IWUSR, root, led,
+ file = debugfs_create_file("latched", 0600, root, led,
&flash_led_dfs_latched_reg_fops);
if (!file) {
pr_err("error creating 'latched' entry\n");
goto error_led_debugfs;
}
- file = debugfs_create_file("strobe", S_IRUSR | S_IWUSR, root, led,
+ file = debugfs_create_file("strobe", 0600, root, led,
&flash_led_dfs_strobe_reg_fops);
if (!file) {
pr_err("error creating 'strobe' entry\n");
@@ -2639,7 +2618,7 @@ static int qpnp_flash_led_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = "qcom,qpnp-flash-led",},
{ },
};
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index 718badb16ea1..1e24c79c3f0a 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.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
@@ -721,10 +721,11 @@ static ssize_t qpnp_wled_ramp_ms_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qpnp_wled *wled = dev_get_drvdata(dev);
- int data;
+ int data, rc;
- if (sscanf(buf, "%d", &data) != 1)
- return -EINVAL;
+ rc = kstrtoint(buf, 10, &data);
+ if (rc)
+ return rc;
wled->ramp_ms = data;
return count;
@@ -744,10 +745,11 @@ static ssize_t qpnp_wled_ramp_step_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qpnp_wled *wled = dev_get_drvdata(dev);
- int data;
+ int data, rc;
- if (sscanf(buf, "%d", &data) != 1)
- return -EINVAL;
+ rc = kstrtoint(buf, 10, &data);
+ if (rc)
+ return rc;
wled->ramp_step = data;
return count;
@@ -832,8 +834,9 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev,
int data, i, rc, temp;
u8 reg;
- if (sscanf(buf, "%d", &data) != 1)
- return -EINVAL;
+ rc = kstrtoint(buf, 10, &data);
+ if (rc)
+ return rc;
for (i = 0; i < wled->num_strings; i++) {
if (data < QPNP_WLED_FS_CURR_MIN_UA)
@@ -869,24 +872,15 @@ static ssize_t qpnp_wled_fs_curr_ua_store(struct device *dev,
/* sysfs attributes exported by wled */
static struct device_attribute qpnp_wled_attrs[] = {
- __ATTR(dump_regs, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_wled_dump_regs_show,
- NULL),
- __ATTR(dim_mode, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_wled_dim_mode_show,
- qpnp_wled_dim_mode_store),
- __ATTR(fs_curr_ua, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_wled_fs_curr_ua_show,
- qpnp_wled_fs_curr_ua_store),
- __ATTR(start_ramp, (S_IRUGO | S_IWUSR | S_IWGRP),
- NULL,
- qpnp_wled_ramp_store),
- __ATTR(ramp_ms, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_wled_ramp_ms_show,
- qpnp_wled_ramp_ms_store),
- __ATTR(ramp_step, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_wled_ramp_step_show,
- qpnp_wled_ramp_step_store),
+ __ATTR(dump_regs, 0664, qpnp_wled_dump_regs_show, NULL),
+ __ATTR(dim_mode, 0664, qpnp_wled_dim_mode_show,
+ qpnp_wled_dim_mode_store),
+ __ATTR(fs_curr_ua, 0664, qpnp_wled_fs_curr_ua_show,
+ qpnp_wled_fs_curr_ua_store),
+ __ATTR(start_ramp, 0664, NULL, qpnp_wled_ramp_store),
+ __ATTR(ramp_ms, 0664, qpnp_wled_ramp_ms_show, qpnp_wled_ramp_ms_store),
+ __ATTR(ramp_step, 0664, qpnp_wled_ramp_step_show,
+ qpnp_wled_ramp_step_store),
};
/* worker for setting wled brightness */
@@ -2196,7 +2190,7 @@ static int qpnp_wled_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = "qcom,qpnp-wled",},
{ },
};
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index d16fcc3c97ae..85a6be824485 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 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
@@ -666,7 +666,7 @@ static int qpnp_wled_set(struct qpnp_led_data *led)
return rc;
}
- usleep_range(WLED_OVP_DELAY, WLED_OVP_DELAY);
+ usleep_range(WLED_OVP_DELAY, WLED_OVP_DELAY + 10);
} else if (led->wled_cfg->pmic_version == PMIC_VER_8941) {
if (led->wled_cfg->num_physical_strings <=
WLED_THREE_STRINGS) {
@@ -696,7 +696,8 @@ static int qpnp_wled_set(struct qpnp_led_data *led)
"WLED write sink reg failed");
return rc;
}
- usleep_range(WLED_OVP_DELAY, WLED_OVP_DELAY);
+ usleep_range(WLED_OVP_DELAY,
+ WLED_OVP_DELAY + 10);
} else {
val = WLED_DISABLE_ALL_SINKS;
rc = regmap_write(led->regmap,
@@ -724,7 +725,8 @@ static int qpnp_wled_set(struct qpnp_led_data *led)
msleep(WLED_OVP_DELAY_LOOP);
tries++;
}
- usleep_range(WLED_OVP_DELAY, WLED_OVP_DELAY);
+ usleep_range(WLED_OVP_DELAY,
+ WLED_OVP_DELAY + 10);
}
}
@@ -859,9 +861,7 @@ static int qpnp_mpp_set(struct qpnp_led_data *led)
led->mpp_cfg->enable = true;
if (led->cdev.brightness < led->mpp_cfg->min_brightness) {
- dev_warn(&led->pdev->dev,
- "brightness is less than supported..." \
- "set to minimum supported\n");
+ dev_warn(&led->pdev->dev, "brightness is less than supported, set to minimum supported\n");
led->cdev.brightness = led->mpp_cfg->min_brightness;
}
@@ -940,9 +940,7 @@ static int qpnp_mpp_set(struct qpnp_led_data *led)
LED_MPP_EN_CTRL(led->base), LED_MPP_EN_MASK,
LED_MPP_EN_ENABLE);
if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to write led enable " \
- "reg\n");
+ dev_err(&led->pdev->dev, "Failed to write led enable reg\n");
goto err_mpp_reg_write;
}
} else {
@@ -1102,30 +1100,27 @@ static int qpnp_flash_regulator_operate(struct qpnp_led_data *led, bool on)
led_array[i].flash_cfg->
flash_wa_reg);
if (rc) {
- dev_err(&led->pdev->dev,
- "Flash wa regulator"
- "enable failed(%d)\n",
+ dev_err(&led->pdev->dev, "Flash wa regulator enable failed(%d)\n",
rc);
return rc;
}
}
rc = regulator_enable(
- led_array[i].flash_cfg->\
- flash_boost_reg);
+ led_array[i].flash_cfg->flash_boost_reg);
if (rc) {
if (led_array[i].flash_cfg->
flash_wa_reg_get)
- /* Disable flash wa regulator
+ /*
+ * Disable flash wa regulator
* when flash boost regulator
* enable fails
*/
regulator_disable(
led_array[i].flash_cfg->
flash_wa_reg);
- dev_err(&led->pdev->dev,
- "Flash boost regulator enable"
- "failed(%d)\n", rc);
+ dev_err(&led->pdev->dev, "Flash boost regulator enable failed(%d)\n",
+ rc);
return rc;
}
led->flash_cfg->flash_on = true;
@@ -1150,12 +1145,11 @@ regulator_turn_off:
rc);
}
- rc = regulator_disable(led_array[i].flash_cfg->\
- flash_boost_reg);
+ rc = regulator_disable(
+ led_array[i].flash_cfg->flash_boost_reg);
if (rc) {
- dev_err(&led->pdev->dev,
- "Flash boost regulator disable"
- "failed(%d)\n", rc);
+ dev_err(&led->pdev->dev, "Flash boost regulator disable failed(%d)\n",
+ rc);
return rc;
}
if (led_array[i].flash_cfg->flash_wa_reg_get) {
@@ -1163,9 +1157,7 @@ regulator_turn_off:
led_array[i].flash_cfg->
flash_wa_reg);
if (rc) {
- dev_err(&led->pdev->dev,
- "Flash_wa regulator"
- "disable failed(%d)\n",
+ dev_err(&led->pdev->dev, "Flash_wa regulator disable failed(%d)\n",
rc);
return rc;
}
@@ -1416,7 +1408,8 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
/*
* Add 1ms delay for bharger enter stable state
*/
- usleep_range(FLASH_RAMP_UP_DELAY_US, FLASH_RAMP_UP_DELAY_US);
+ usleep_range(FLASH_RAMP_UP_DELAY_US,
+ FLASH_RAMP_UP_DELAY_US + 10);
if (!led->flash_cfg->strobe_type)
led->flash_cfg->trigger_flash &=
@@ -1480,7 +1473,8 @@ static int qpnp_flash_set(struct qpnp_led_data *led)
* Disable module after ramp down complete for stable
* behavior
*/
- usleep_range(FLASH_RAMP_UP_DELAY_US, FLASH_RAMP_UP_DELAY_US);
+ usleep_range(FLASH_RAMP_UP_DELAY_US,
+ FLASH_RAMP_UP_DELAY_US + 10);
rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
@@ -1658,9 +1652,7 @@ static int qpnp_kpdbl_set(struct qpnp_led_data *led)
KPDBL_MODULE_EN_MASK,
KPDBL_MODULE_DIS);
if (rc) {
- dev_err(&led->pdev->dev,
- "Failed to write led"
- " enable reg\n");
+ dev_err(&led->pdev->dev, "Failed to write led enable reg\n");
return rc;
}
}
@@ -1854,8 +1846,6 @@ static void qpnp_led_work(struct work_struct *work)
struct qpnp_led_data, work);
__qpnp_led_work(led, led->cdev.brightness);
-
- return;
}
static int qpnp_led_set_max_brightness(struct qpnp_led_data *led)
@@ -1942,7 +1932,7 @@ static int qpnp_wled_init(struct qpnp_led_data *led)
return -EINVAL;
}
- if ((led->max_current > WLED_MAX_CURR)) {
+ if (led->max_current > WLED_MAX_CURR) {
dev_err(&led->pdev->dev, "Invalid max current\n");
return -EINVAL;
}
@@ -3048,7 +3038,7 @@ static int qpnp_get_common_configs(struct qpnp_led_data *led,
rc = of_property_read_string(node, "qcom,default-state",
&temp_string);
if (!rc) {
- if (strncmp(temp_string, "on", sizeof("on")) == 0)
+ if (strcmp(temp_string, "on") == 0)
led->default_on = true;
} else if (rc != -EINVAL)
return rc;
@@ -3075,10 +3065,8 @@ static int qpnp_get_config_wled(struct qpnp_led_data *led,
led->wled_cfg = devm_kzalloc(&led->pdev->dev,
sizeof(struct wled_config_data), GFP_KERNEL);
- if (!led->wled_cfg) {
- dev_err(&led->pdev->dev, "Unable to allocate memory\n");
+ if (!led->wled_cfg)
return -ENOMEM;
- }
rc = regmap_read(led->regmap, PMIC_VERSION_REG, &tmp);
if (rc) {
@@ -3161,10 +3149,8 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
led->flash_cfg = devm_kzalloc(&led->pdev->dev,
sizeof(struct flash_config_data), GFP_KERNEL);
- if (!led->flash_cfg) {
- dev_err(&led->pdev->dev, "Unable to allocate memory\n");
+ if (!led->flash_cfg)
return -ENOMEM;
- }
rc = regmap_read(led->regmap, FLASH_PERIPHERAL_SUBTYPE(led->base),
&tmp);
@@ -3297,23 +3283,23 @@ static int qpnp_get_config_flash(struct qpnp_led_data *led,
}
return 0;
- } else {
- rc = of_property_read_u32(node, "qcom,duration", &val);
- if (!rc)
- led->flash_cfg->duration = (u8)((val - 10) / 10);
- else if (rc == -EINVAL)
- led->flash_cfg->duration = FLASH_DURATION_200ms;
- else
- goto error_get_flash_reg;
-
- rc = of_property_read_u32(node, "qcom,current", &val);
- if (!rc)
- led->flash_cfg->current_prgm = (val *
- FLASH_MAX_LEVEL / led->max_current);
- else
- goto error_get_flash_reg;
}
+ rc = of_property_read_u32(node, "qcom,duration", &val);
+ if (!rc)
+ led->flash_cfg->duration = (u8)((val - 10) / 10);
+ else if (rc == -EINVAL)
+ led->flash_cfg->duration = FLASH_DURATION_200ms;
+ else
+ goto error_get_flash_reg;
+
+ rc = of_property_read_u32(node, "qcom,current", &val);
+ if (!rc)
+ led->flash_cfg->current_prgm = val * FLASH_MAX_LEVEL
+ / led->max_current;
+ else
+ goto error_get_flash_reg;
+
rc = of_property_read_u32(node, "qcom,headroom", &val);
if (!rc)
led->flash_cfg->headroom = (u8) val;
@@ -3512,11 +3498,11 @@ bad_lpg_params:
static int qpnp_led_get_mode(const char *mode)
{
- if (strncmp(mode, "manual", strlen(mode)) == 0)
+ if (strcmp(mode, "manual") == 0)
return MANUAL_MODE;
- else if (strncmp(mode, "pwm", strlen(mode)) == 0)
+ else if (strcmp(mode, "pwm") == 0)
return PWM_MODE;
- else if (strncmp(mode, "lpg", strlen(mode)) == 0)
+ else if (strcmp(mode, "lpg") == 0)
return LPG_MODE;
else
return -EINVAL;
@@ -3532,10 +3518,8 @@ static int qpnp_get_config_kpdbl(struct qpnp_led_data *led,
led->kpdbl_cfg = devm_kzalloc(&led->pdev->dev,
sizeof(struct kpdbl_config_data), GFP_KERNEL);
- if (!led->kpdbl_cfg) {
- dev_err(&led->pdev->dev, "Unable to allocate memory\n");
+ if (!led->kpdbl_cfg)
return -ENOMEM;
- }
rc = of_property_read_string(node, "qcom,mode", &mode);
if (!rc) {
@@ -3547,11 +3531,9 @@ static int qpnp_get_config_kpdbl(struct qpnp_led_data *led,
led->kpdbl_cfg->pwm_cfg = devm_kzalloc(&led->pdev->dev,
sizeof(struct pwm_config_data),
GFP_KERNEL);
- if (!led->kpdbl_cfg->pwm_cfg) {
- dev_err(&led->pdev->dev,
- "Unable to allocate memory\n");
+ if (!led->kpdbl_cfg->pwm_cfg)
return -ENOMEM;
- }
+
led->kpdbl_cfg->pwm_cfg->mode = led_mode;
led->kpdbl_cfg->pwm_cfg->default_mode = led_mode;
} else {
@@ -3589,10 +3571,8 @@ static int qpnp_get_config_rgb(struct qpnp_led_data *led,
led->rgb_cfg = devm_kzalloc(&led->pdev->dev,
sizeof(struct rgb_config_data), GFP_KERNEL);
- if (!led->rgb_cfg) {
- dev_err(&led->pdev->dev, "Unable to allocate memory\n");
+ if (!led->rgb_cfg)
return -ENOMEM;
- }
if (led->id == QPNP_ID_RGB_RED)
led->rgb_cfg->enable = RGB_LED_ENABLE_RED;
@@ -3641,10 +3621,8 @@ static int qpnp_get_config_mpp(struct qpnp_led_data *led,
led->mpp_cfg = devm_kzalloc(&led->pdev->dev,
sizeof(struct mpp_config_data), GFP_KERNEL);
- if (!led->mpp_cfg) {
- dev_err(&led->pdev->dev, "Unable to allocate memory\n");
+ if (!led->mpp_cfg)
return -ENOMEM;
- }
if (of_find_property(of_get_parent(node), "mpp-power-supply", NULL)) {
led->mpp_cfg->mpp_reg =
@@ -3770,11 +3748,8 @@ static int qpnp_get_config_gpio(struct qpnp_led_data *led,
led->gpio_cfg = devm_kzalloc(&led->pdev->dev,
sizeof(struct gpio_config_data), GFP_KERNEL);
- if (!led->gpio_cfg) {
- dev_err(&led->pdev->dev,
- "Unable to allocate memory gpio struct\n");
+ if (!led->gpio_cfg)
return -ENOMEM;
- }
led->gpio_cfg->source_sel = LED_GPIO_SOURCE_SEL_DEFAULT;
rc = of_property_read_u32(node, "qcom,source-sel", &val);
@@ -3823,12 +3798,10 @@ static int qpnp_leds_probe(struct platform_device *pdev)
if (!num_leds)
return -ECHILD;
- led_array = devm_kzalloc(&pdev->dev,
- (sizeof(struct qpnp_led_data) * num_leds), GFP_KERNEL);
- if (!led_array) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
+ led_array = devm_kcalloc(&pdev->dev, num_leds, sizeof(*led_array),
+ GFP_KERNEL);
+ if (!led_array)
return -ENOMEM;
- }
for_each_child_of_node(node, temp) {
led = &led_array[parsed_leds];
@@ -3881,24 +3854,22 @@ static int qpnp_leds_probe(struct platform_device *pdev)
rc = qpnp_get_common_configs(led, temp);
if (rc) {
- dev_err(&led->pdev->dev,
- "Failure reading common led configuration," \
- " rc = %d\n", rc);
+ dev_err(&led->pdev->dev, "Failure reading common led configuration, rc = %d\n",
+ rc);
goto fail_id_check;
}
led->cdev.brightness_set = qpnp_led_set;
led->cdev.brightness_get = qpnp_led_get;
- if (strncmp(led_label, "wled", sizeof("wled")) == 0) {
+ if (strcmp(led_label, "wled") == 0) {
rc = qpnp_get_config_wled(led, temp);
if (rc < 0) {
dev_err(&led->pdev->dev,
"Unable to read wled config data\n");
goto fail_id_check;
}
- } else if (strncmp(led_label, "flash", sizeof("flash"))
- == 0) {
+ } else if (strcmp(led_label, "flash") == 0) {
if (!of_find_property(node, "flash-boost-supply", NULL))
regulator_probe = true;
rc = qpnp_get_config_flash(led, temp, &regulator_probe);
@@ -3907,14 +3878,14 @@ static int qpnp_leds_probe(struct platform_device *pdev)
"Unable to read flash config data\n");
goto fail_id_check;
}
- } else if (strncmp(led_label, "rgb", sizeof("rgb")) == 0) {
+ } else if (strcmp(led_label, "rgb") == 0) {
rc = qpnp_get_config_rgb(led, temp);
if (rc < 0) {
dev_err(&led->pdev->dev,
"Unable to read rgb config data\n");
goto fail_id_check;
}
- } else if (strncmp(led_label, "mpp", sizeof("mpp")) == 0) {
+ } else if (strcmp(led_label, "mpp") == 0) {
rc = qpnp_get_config_mpp(led, temp);
if (rc < 0) {
dev_err(&led->pdev->dev,
@@ -3928,7 +3899,7 @@ static int qpnp_leds_probe(struct platform_device *pdev)
"Unable to read gpio config data\n");
goto fail_id_check;
}
- } else if (strncmp(led_label, "kpdbl", sizeof("kpdbl")) == 0) {
+ } else if (strcmp(led_label, "kpdbl") == 0) {
bitmap_zero(kpdbl_leds_in_use, NUM_KPDBL_LEDS);
is_kpdbl_master_turn_on = false;
rc = qpnp_get_config_kpdbl(led, temp);
@@ -4113,8 +4084,8 @@ static int qpnp_leds_remove(struct platform_device *pdev)
case QPNP_ID_FLASH1_LED0:
case QPNP_ID_FLASH1_LED1:
if (led_array[i].flash_cfg->flash_reg_get)
- regulator_put(led_array[i].flash_cfg-> \
- flash_boost_reg);
+ regulator_put(
+ led_array[i].flash_cfg->flash_boost_reg);
if (led_array[i].flash_cfg->torch_enable)
if (!led_array[i].flash_cfg->no_smbb_support)
regulator_put(led_array[i].
@@ -4126,49 +4097,49 @@ static int qpnp_leds_remove(struct platform_device *pdev)
case QPNP_ID_RGB_GREEN:
case QPNP_ID_RGB_BLUE:
if (led_array[i].rgb_cfg->pwm_cfg->mode == PWM_MODE)
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &pwm_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &pwm_attr_group);
if (led_array[i].rgb_cfg->pwm_cfg->use_blink) {
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &blink_attr_group);
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &lpg_attr_group);
- } else if (led_array[i].rgb_cfg->pwm_cfg->mode\
- == LPG_MODE)
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &lpg_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &blink_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &lpg_attr_group);
+ } else if (led_array[i].rgb_cfg->pwm_cfg->mode
+ == LPG_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &lpg_attr_group);
break;
case QPNP_ID_LED_MPP:
if (!led_array[i].mpp_cfg->pwm_cfg)
break;
if (led_array[i].mpp_cfg->pwm_cfg->mode == PWM_MODE)
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &pwm_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &pwm_attr_group);
if (led_array[i].mpp_cfg->pwm_cfg->use_blink) {
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &blink_attr_group);
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &lpg_attr_group);
- } else if (led_array[i].mpp_cfg->pwm_cfg->mode\
- == LPG_MODE)
- sysfs_remove_group(&led_array[i].cdev.dev->\
- kobj, &lpg_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &blink_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &lpg_attr_group);
+ } else if (led_array[i].mpp_cfg->pwm_cfg->mode
+ == LPG_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &lpg_attr_group);
if (led_array[i].mpp_cfg->mpp_reg)
regulator_put(led_array[i].mpp_cfg->mpp_reg);
break;
case QPNP_ID_KPDBL:
if (led_array[i].kpdbl_cfg->pwm_cfg->mode == PWM_MODE)
- sysfs_remove_group(&led_array[i].cdev.dev->
- kobj, &pwm_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &pwm_attr_group);
if (led_array[i].kpdbl_cfg->pwm_cfg->use_blink) {
- sysfs_remove_group(&led_array[i].cdev.dev->
- kobj, &blink_attr_group);
- sysfs_remove_group(&led_array[i].cdev.dev->
- kobj, &lpg_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &blink_attr_group);
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &lpg_attr_group);
} else if (led_array[i].kpdbl_cfg->pwm_cfg->mode
- == LPG_MODE)
- sysfs_remove_group(&led_array[i].cdev.dev->
- kobj, &lpg_attr_group);
+ == LPG_MODE)
+ sysfs_remove_group(&led_array[i].cdev.dev->kobj,
+ &lpg_attr_group);
break;
default:
dev_err(&led_array->pdev->dev,
@@ -4182,7 +4153,7 @@ static int qpnp_leds_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = "qcom,leds-qpnp",},
{ },
};
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 39688df93474..f6fabc61620d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -762,6 +762,10 @@ struct vfe_device {
uint32_t **vfe_clk_rates;
size_t num_clk;
size_t num_rates;
+ struct clk **hvx_clk;
+ struct msm_cam_clk_info *hvx_clk_info;
+ size_t num_hvx_clk;
+ size_t num_norm_clk;
enum cam_ahb_clk_vote ahb_vote;
/* Sync variables*/
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index 9747cfd6dca3..c7f3b97c83c9 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.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
@@ -1492,6 +1492,26 @@ void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev,
uint8_t is_stream_on)
{
uint32_t val;
+ int rc = 0;
+
+ if (vfe_dev->buf_mgr->secure_enable == SECURE_MODE) {
+ pr_err("%s: Cannot configure hvx, secure_mode: %d\n",
+ __func__,
+ vfe_dev->buf_mgr->secure_enable);
+ return;
+ }
+ if (!vfe_dev->hvx_clk) {
+ pr_err("%s: no stream_clk\n", __func__);
+ return;
+ }
+ rc = msm_camera_clk_enable(&vfe_dev->pdev->dev, vfe_dev->hvx_clk_info,
+ vfe_dev->hvx_clk, vfe_dev->num_hvx_clk, is_stream_on);
+ if (rc) {
+ pr_err("%s: stream_clk enable failed, enable: %u\n",
+ __func__,
+ is_stream_on);
+ return;
+ }
if (is_stream_on == 1) {
/* Enable HVX */
val = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
@@ -2472,6 +2492,8 @@ int msm_vfe47_update_bandwidth(
int msm_vfe47_get_clks(struct vfe_device *vfe_dev)
{
int i, rc;
+ struct clk *stream_clk;
+ struct msm_cam_clk_info clk_info;
rc = msm_camera_get_clk_info(vfe_dev->pdev, &vfe_dev->vfe_clk_info,
&vfe_dev->vfe_clk, &vfe_dev->num_clk);
@@ -2480,6 +2502,31 @@ int msm_vfe47_get_clks(struct vfe_device *vfe_dev)
for (i = 0; i < vfe_dev->num_clk; i++) {
if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+ "camss_vfe_stream_clk") == 0) {
+ stream_clk = vfe_dev->vfe_clk[i];
+ clk_info = vfe_dev->vfe_clk_info[i];
+ vfe_dev->num_hvx_clk = 1;
+ vfe_dev->num_norm_clk = vfe_dev->num_clk - 1;
+ break;
+ }
+ }
+ if (i >= vfe_dev->num_clk)
+ pr_err("%s: cannot find camss_vfe_stream_clk\n", __func__);
+ else {
+ /* Switch stream_clk to the last element*/
+ for (; i < vfe_dev->num_clk - 1; i++) {
+ vfe_dev->vfe_clk[i] = vfe_dev->vfe_clk[i+1];
+ vfe_dev->vfe_clk_info[i] = vfe_dev->vfe_clk_info[i+1];
+ }
+ vfe_dev->vfe_clk_info[vfe_dev->num_clk-1] = clk_info;
+ vfe_dev->vfe_clk[vfe_dev->num_clk-1] = stream_clk;
+ vfe_dev->hvx_clk_info =
+ &vfe_dev->vfe_clk_info[vfe_dev->num_clk-1];
+ vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1];
+ }
+
+ for (i = 0; i < vfe_dev->num_clk; i++) {
+ if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
"vfe_clk_src") == 0)
vfe_dev->hw_info->vfe_clk_idx = i;
}
@@ -2492,13 +2539,17 @@ void msm_vfe47_put_clks(struct vfe_device *vfe_dev)
&vfe_dev->vfe_clk, vfe_dev->num_clk);
vfe_dev->num_clk = 0;
+ vfe_dev->hvx_clk = NULL;
+ vfe_dev->hvx_clk_info = NULL;
+ vfe_dev->num_hvx_clk = 0;
+ vfe_dev->num_norm_clk = 0;
}
int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable)
{
return msm_camera_clk_enable(&vfe_dev->pdev->dev,
vfe_dev->vfe_clk_info,
- vfe_dev->vfe_clk, vfe_dev->num_clk, enable);
+ vfe_dev->vfe_clk, vfe_dev->num_norm_clk, enable);
}
int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
index 1f2db9683cd0..5b4d6aa63055 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.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
@@ -189,12 +189,18 @@ static void msm_vfe48_put_clks(struct vfe_device *vfe_dev)
vfe_dev->num_clk = 0;
vfe_dev->num_rates = 0;
+ vfe_dev->hvx_clk = NULL;
+ vfe_dev->hvx_clk_info = NULL;
+ vfe_dev->num_hvx_clk = 0;
+ vfe_dev->num_norm_clk = 0;
}
static int msm_vfe48_get_clks(struct vfe_device *vfe_dev)
{
int rc;
- int i;
+ int i, j;
+ struct clk *stream_clk;
+ struct msm_cam_clk_info clk_info;
rc = msm_camera_get_clk_info_and_rates(vfe_dev->pdev,
&vfe_dev->vfe_clk_info, &vfe_dev->vfe_clk,
@@ -204,6 +210,34 @@ static int msm_vfe48_get_clks(struct vfe_device *vfe_dev)
if (rc)
return rc;
+ vfe_dev->num_norm_clk = vfe_dev->num_clk;
+ for (i = 0; i < vfe_dev->num_clk; i++) {
+ if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
+ "camss_vfe_stream_clk") == 0) {
+ stream_clk = vfe_dev->vfe_clk[i];
+ clk_info = vfe_dev->vfe_clk_info[i];
+ vfe_dev->num_hvx_clk = 1;
+ vfe_dev->num_norm_clk = vfe_dev->num_clk - 1;
+ break;
+ }
+ }
+ if (i >= vfe_dev->num_clk)
+ pr_err("%s: cannot find camss_vfe_stream_clk\n", __func__);
+ else {
+ /* Switch stream_clk to the last element*/
+ for (; i < vfe_dev->num_clk - 1; i++) {
+ vfe_dev->vfe_clk[i] = vfe_dev->vfe_clk[i+1];
+ vfe_dev->vfe_clk_info[i] = vfe_dev->vfe_clk_info[i+1];
+ for (j = 0; j < MSM_VFE_MAX_CLK_RATES; j++)
+ vfe_dev->vfe_clk_rates[j][i] =
+ vfe_dev->vfe_clk_rates[j][i+1];
+ }
+ vfe_dev->vfe_clk_info[vfe_dev->num_clk-1] = clk_info;
+ vfe_dev->vfe_clk[vfe_dev->num_clk-1] = stream_clk;
+ vfe_dev->hvx_clk_info =
+ &vfe_dev->vfe_clk_info[vfe_dev->num_clk-1];
+ vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1];
+ }
for (i = 0; i < vfe_dev->num_clk; i++) {
if (strcmp(vfe_dev->vfe_clk_info[i].clk_name,
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/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index 1f92186feeef..92b6e8ffa92e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -79,8 +79,6 @@ u32 sde_apply_comp_ratio_factor(u32 quota,
#define RES_UHD (3840*2160)
#define RES_WQXGA (2560*1600)
#define XIN_HALT_TIMEOUT_US 0x4000
-#define MDSS_MDP_HW_REV_320 0x30020000 /* sdm660 */
-#define MDSS_MDP_HW_REV_330 0x30030000 /* sdm630 */
static int sde_mdp_wait_for_xin_halt(u32 xin_id)
{
@@ -440,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)
{
@@ -465,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 a7c1e890758e..5cbdc03ced9d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -24,6 +24,13 @@
#include "sde_rotator_smmu.h"
#include "sde_rotator_formats.h"
+#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;
@@ -164,9 +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;
@@ -175,8 +190,10 @@ struct sde_rot_data_type {
void *sde_rot_hw;
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 e9988400b729..c3ed1f39c2be 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -530,7 +530,7 @@ static int sde_rotator_import_buffer(struct sde_layer_buffer *buffer,
return ret;
}
-static int sde_rotator_secure_session_ctrl(bool enable)
+static int _sde_rotator_secure_session_ctrl(bool enable)
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
uint32_t sid_info;
@@ -603,6 +603,39 @@ static int sde_rotator_secure_session_ctrl(bool enable)
return resp;
}
+static int sde_rotator_secure_session_ctrl(bool enable)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ int ret = -EINVAL;
+
+ /**
+ * wait_for_transition and secure_session_control are filled by client
+ * callback.
+ */
+ if (mdata->wait_for_transition && mdata->secure_session_ctrl &&
+ mdata->callback_request) {
+ ret = mdata->wait_for_transition(mdata->sec_cam_en, enable);
+ if (ret) {
+ SDEROT_ERR("failed Secure wait for transition %d\n",
+ ret);
+ } else {
+ if (mdata->sec_cam_en ^ enable) {
+ mdata->sec_cam_en = enable;
+ ret = mdata->secure_session_ctrl(enable);
+ if (ret)
+ mdata->sec_cam_en = 0;
+ }
+ }
+ } else if (!mdata->callback_request) {
+ ret = _sde_rotator_secure_session_ctrl(enable);
+ }
+
+ if (ret)
+ SDEROT_ERR("failed %d sde_rotator_secure_session %d\n",
+ ret, mdata->callback_request);
+
+ return ret;
+}
static int sde_rotator_map_and_check_data(struct sde_rot_entry *entry)
{
@@ -1137,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;
}
@@ -1785,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..7ea36c85738f 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,61 @@ 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);
}
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 49a2cf112b0e..9b1175d8f4a6 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.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
@@ -45,6 +45,15 @@ struct sde_smmu_domain {
unsigned long size;
};
+int sde_smmu_set_dma_direction(int dir)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+
+ return ((mdata->mdss_version == MDSS_MDP_HW_REV_320) ||
+ (mdata->mdss_version == MDSS_MDP_HW_REV_330)) ?
+ DMA_BIDIRECTIONAL : dir;
+}
+
static inline bool sde_smmu_is_valid_domain_type(
struct sde_rot_data_type *mdata, int domain_type)
{
@@ -335,8 +344,8 @@ int sde_smmu_map_dma_buf(struct dma_buf *dma_buf,
return -EINVAL;
}
- rc = msm_dma_map_sg_lazy(sde_smmu->dev, table->sgl, table->nents, dir,
- dma_buf);
+ rc = msm_dma_map_sg_lazy(sde_smmu->dev, table->sgl, table->nents,
+ sde_smmu_set_dma_direction(dir), dma_buf);
if (rc != table->nents) {
SDEROT_ERR("dma map sg failed\n");
return -ENOMEM;
@@ -357,15 +366,52 @@ void sde_smmu_unmap_dma_buf(struct sg_table *table, int domain,
return;
}
- msm_dma_unmap_sg(sde_smmu->dev, table->sgl, table->nents, dir,
- dma_buf);
+ msm_dma_unmap_sg(sde_smmu->dev, table->sgl, table->nents,
+ sde_smmu_set_dma_direction(dir), dma_buf);
}
static DEFINE_MUTEX(sde_smmu_ref_cnt_lock);
+static void sde_smmu_callback(struct mdss_smmu_intf *smmu)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+
+ if (!smmu)
+ return;
+
+ /* 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 =
+ SDE_IOMMU_DOMAIN_ROT_SECURE;
+ } else {
+ mdata->sde_smmu[SDE_IOMMU_DOMAIN_ROT_UNSECURE].dev = smmu->dev;
+ mdata->sde_smmu[SDE_IOMMU_DOMAIN_ROT_UNSECURE].domain =
+ SDE_IOMMU_DOMAIN_ROT_UNSECURE;
+ }
+
+ SDEROT_INFO("sde_smmu_callback registered domain: %d\n",
+ smmu->is_secure);
+}
+
int sde_smmu_ctrl(int enable)
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+
+ return ((mdata->iommu_ctrl) ?
+ mdata->iommu_ctrl(enable) : -EINVAL);
+}
+
+static int _sde_smmu_ctrl(int enable)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
int rc = 0;
mutex_lock(&sde_smmu_ref_cnt_lock);
@@ -442,13 +488,24 @@ int sde_smmu_secure_ctrl(int enable)
void sde_smmu_device_create(struct device *dev)
{
struct device_node *parent, *child;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ bool child_rot_sec = false;
+ bool child_rot_nsec = false;
parent = dev->of_node;
for_each_child_of_node(parent, child) {
- if (of_device_is_compatible(child, SMMU_SDE_ROT_SEC))
+ if (of_device_is_compatible(child, SMMU_SDE_ROT_SEC)) {
of_platform_device_create(child, NULL, dev);
- else if (of_device_is_compatible(child, SMMU_SDE_ROT_UNSEC))
+ child_rot_sec = true;
+ } else if (of_device_is_compatible(child, SMMU_SDE_ROT_UNSEC)) {
of_platform_device_create(child, NULL, dev);
+ child_rot_nsec = true;
+ }
+ }
+
+ if (!child_rot_sec || !child_rot_nsec) {
+ mdss_smmu_request_mappings(sde_smmu_callback);
+ mdata->callback_request = true;
}
}
@@ -616,6 +673,8 @@ int sde_smmu_probe(struct platform_device *pdev)
sde_smmu_enable_power(sde_smmu, false);
sde_smmu->dev = dev;
+ mdata->iommu_ctrl = _sde_smmu_ctrl;
+
SDEROT_INFO(
"iommu v2 domain[%d] mapping and clk register successful!\n",
smmu_domain.domain);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.h
index 4a1c3d323143..7c274643dce2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.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
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
+#include <linux/mdss_smmu_ext.h>
#include "sde_rotator_io_util.h"
@@ -28,11 +29,6 @@ enum sde_iommu_domain_type {
int sde_smmu_init(struct device *dev);
-static inline int sde_smmu_dma_data_direction(int dir)
-{
- return dir;
-}
-
int sde_smmu_ctrl(int enable);
struct dma_buf_attachment *sde_smmu_dma_buf_attach(
@@ -47,4 +43,5 @@ void sde_smmu_unmap_dma_buf(struct sg_table *table, int domain,
int sde_smmu_secure_ctrl(int enable);
+int sde_smmu_set_dma_direction(int dir);
#endif /* SDE_ROTATOR_SMMU_H */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
index fb7bb37d52d9..0eaf1960ec27 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_util.c
@@ -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
@@ -730,7 +730,8 @@ static int sde_mdp_put_img(struct sde_mdp_img_data *data, bool rotator,
}
if (!data->skip_detach) {
dma_buf_unmap_attachment(data->srcp_attachment,
- data->srcp_table, dir);
+ data->srcp_table,
+ sde_smmu_set_dma_direction(dir));
dma_buf_detach(data->srcp_dma_buf,
data->srcp_attachment);
if (!(data->flags & SDE_ROT_EXT_DMA_BUF)) {
@@ -792,7 +793,8 @@ static int sde_mdp_get_img(struct sde_fb_data *img,
SDEROT_DBG("%d attach=%p\n", __LINE__, data->srcp_attachment);
data->srcp_table =
- dma_buf_map_attachment(data->srcp_attachment, dir);
+ dma_buf_map_attachment(data->srcp_attachment,
+ sde_smmu_set_dma_direction(dir));
if (IS_ERR(data->srcp_table)) {
SDEROT_ERR("%d Failed to map attachment\n", __LINE__);
ret = PTR_ERR(data->srcp_table);
@@ -919,7 +921,8 @@ static int sde_mdp_map_buffer(struct sde_mdp_img_data *data, bool rotator,
return ret;
err_unmap:
- dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, dir);
+ dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
+ sde_smmu_set_dma_direction(dir));
dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
if (!(data->flags & SDE_ROT_EXT_DMA_BUF)) {
dma_buf_put(data->srcp_dma_buf);
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/mfd/Kconfig b/drivers/mfd/Kconfig
index a97f5df7a7db..2346635ccff3 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1539,7 +1539,6 @@ config WCD9330_CODEC
select MFD_CORE
select WCD9XXX_CODEC_UTIL
select MSM_CDC_SUPPLY
- select REGMAP_ALLOW_WRITE_DEBUGFS
help
Enables the WCD9xxx codec core driver. The core driver provides
read/write capability to registers which are part of the
@@ -1555,7 +1554,6 @@ config WCD9335_CODEC
select WCD9XXX_CODEC_UTIL
select MSM_CDC_SUPPLY
select MSM_CDC_PINCTRL
- select REGMAP_ALLOW_WRITE_DEBUGFS
help
Enables the WCD9xxx codec core driver. The core driver provides
read/write capability to registers which are part of the
@@ -1571,7 +1569,6 @@ config WCD934X_CODEC
select WCD9XXX_CODEC_UTIL
select MSM_CDC_SUPPLY
select MSM_CDC_PINCTRL
- select REGMAP_ALLOW_WRITE_DEBUGFS
select PINCTRL_WCD
help
Enables the WCD9xxx codec core driver. The core driver provides
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 1653f7e1ae99..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: {
@@ -2135,22 +2141,24 @@ static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id)
}
/*
- * scm_call send command to a blocked TZ app will fail
- * So, first check and then wait until this apps is unblocked
+ * scm_call of send data will fail if this TA is blocked or there are more
+ * than one TA requesting listener services; So, first check to see if need
+ * to wait.
*/
static void __qseecom_reentrancy_check_if_this_app_blocked(
struct qseecom_registered_app_list *ptr_app)
{
sigset_t new_sigset, old_sigset;
if (qseecom.qsee_reentrancy_support) {
- while (ptr_app->app_blocked) {
+ while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) {
/* thread sleep until this app unblocked */
sigfillset(&new_sigset);
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
mutex_unlock(&app_access_lock);
do {
if (!wait_event_freezable(qseecom.app_block_wq,
- !ptr_app->app_blocked))
+ (!ptr_app->app_blocked &&
+ qseecom.app_block_ref_cnt <= 1)))
break;
} while (1);
mutex_lock(&app_access_lock);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index efbecb6e1dd0..52e3e9b5b778 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3855,10 +3855,6 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
mmc_get_card(card);
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
- if (mmc_bus_needs_resume(card->host))
- mmc_resume_bus(card->host);
-#endif
if (!card->host->cmdq_ctx.active_reqs && mmc_card_doing_bkops(card)) {
ret = mmc_cmdq_halt(card->host, true);
if (ret)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 152a3e3b4f47..9f5c67e850d4 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2148,6 +2148,10 @@ void mmc_get_card(struct mmc_card *card)
{
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ if (mmc_bus_needs_resume(card->host))
+ mmc_resume_bus(card->host);
+#endif
}
EXPORT_SYMBOL(mmc_get_card);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index f43f22503aa3..127a2602aa81 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -335,6 +335,9 @@ static int disable_slots;
/* root can write, others read */
module_param(disable_slots, int, S_IRUGO|S_IWUSR);
+static bool nocmdq;
+module_param(nocmdq, bool, S_IRUGO|S_IWUSR);
+
enum vdd_io_level {
/* set vdd_io_data->low_vol_level */
VDD_IO_LOW,
@@ -4135,6 +4138,11 @@ static void sdhci_msm_cmdq_init(struct sdhci_host *host,
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ if (nocmdq) {
+ dev_dbg(&pdev->dev, "CMDQ disabled via cmdline\n");
+ return;
+ }
+
host->cq_host = cmdq_pltfm_init(pdev);
if (IS_ERR(host->cq_host)) {
dev_dbg(&pdev->dev, "cmdq-pltfm init: failed: %ld\n",
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 0f25932d8855..a89face0e891 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -165,7 +165,7 @@ static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx);
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
@@ -262,10 +262,7 @@ int ecm_ipa_init(struct ecm_ipa_params *params)
ECM_IPA_DEBUG("device_ready_notify() was not supplied");
ecm_ipa_ctx->device_ready_notify = params->device_ready_notify;
- result = ecm_ipa_debugfs_init(ecm_ipa_ctx);
- if (result)
- goto fail_debugfs;
- ECM_IPA_DEBUG("debugfs entries were created\n");
+ ecm_ipa_debugfs_init(ecm_ipa_ctx);
result = ecm_ipa_set_device_ethernet_addr(net->dev_addr,
params->device_ethaddr);
@@ -314,7 +311,6 @@ fail_register_netdev:
fail_set_device_ethernet:
fail_rules_cfg:
ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
-fail_debugfs:
fail_netdev_priv:
free_netdev(net);
fail_alloc_etherdev:
@@ -1201,8 +1197,9 @@ static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
return simple_read_from_buffer(ubuf, count, ppos, atomic_str, nbytes);
}
+#ifdef CONFIG_DEBUG_FS
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
+static void ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
{
const mode_t flags_read_write = S_IRUGO | S_IWUGO;
const mode_t flags_read_only = S_IRUGO;
@@ -1211,7 +1208,7 @@ static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
ECM_IPA_LOG_ENTRY();
if (!ecm_ipa_ctx)
- return -EINVAL;
+ return;
ecm_ipa_ctx->directory = debugfs_create_dir("ecm_ipa", NULL);
if (!ecm_ipa_ctx->directory) {
@@ -1241,11 +1238,11 @@ static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
ECM_IPA_DEBUG("debugfs entries were created\n");
ECM_IPA_LOG_EXIT();
- return 0;
+ return;
fail_file:
debugfs_remove_recursive(ecm_ipa_ctx->directory);
fail_directory:
- return -EFAULT;
+ return;
}
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
@@ -1253,6 +1250,14 @@ static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
debugfs_remove_recursive(ecm_ipa_ctx->directory);
}
+#else /* !CONFIG_DEBUG_FS*/
+
+static void ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx) {}
+
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx) {}
+
+#endif /* CONFIG_DEBUG_FS */
+
/**
* ecm_ipa_ep_cfg() - configure the USB endpoints for ECM
*
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 62e72ca01929..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.*/
};
/**
@@ -255,7 +257,7 @@ static ssize_t rndis_ipa_debugfs_aggr_write(struct file *file,
static ssize_t rndis_ipa_debugfs_atomic_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
static void rndis_ipa_dump_skb(struct sk_buff *skb);
-static int rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx);
+static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx);
static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx);
static int rndis_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl,
u32 ipa_to_usb_hdl, u32 max_xfer_size_bytes_to_dev,
@@ -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;
@@ -542,10 +546,7 @@ int rndis_ipa_init(struct ipa_usb_init_params *params)
RNDIS_IPA_DEBUG("Needed headroom for RNDIS header set to %d\n",
net->needed_headroom);
- result = rndis_ipa_debugfs_init(rndis_ipa_ctx);
- if (result)
- goto fail_debugfs;
- RNDIS_IPA_DEBUG("debugfs entries were created\n");
+ rndis_ipa_debugfs_init(rndis_ipa_ctx);
result = rndis_ipa_set_device_ethernet_addr(net->dev_addr,
rndis_ipa_ctx->device_ethaddr);
@@ -602,7 +603,6 @@ fail_register_tx:
fail_set_device_ethernet:
fail_hdrs_cfg:
rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
-fail_debugfs:
fail_netdev_priv:
free_netdev(net);
fail_alloc_etherdev:
@@ -647,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();
@@ -660,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",
@@ -714,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)
@@ -751,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);
@@ -1095,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();
@@ -1136,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");
@@ -1175,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",
@@ -1214,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();
@@ -1224,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);
@@ -1252,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");
@@ -2065,10 +2122,11 @@ static void rndis_ipa_dump_skb(struct sk_buff *skb)
skb->len);
}
+#ifdef CONFIG_DEBUG_FS
/**
* Creates the root folder for the driver
*/
-static int rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
+static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
{
const mode_t flags_read_write = S_IRUGO | S_IWUGO;
const mode_t flags_read_only = S_IRUGO;
@@ -2079,7 +2137,7 @@ static int rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
RNDIS_IPA_LOG_ENTRY();
if (!rndis_ipa_ctx)
- return -EINVAL;
+ return;
rndis_ipa_ctx->directory = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
if (!rndis_ipa_ctx->directory) {
@@ -2253,13 +2311,14 @@ static int rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
goto fail_file;
}
+ RNDIS_IPA_DEBUG("debugfs entries were created\n");
RNDIS_IPA_LOG_EXIT();
- return 0;
+ return;
fail_file:
debugfs_remove_recursive(rndis_ipa_ctx->directory);
fail_directory:
- return -EFAULT;
+ return;
}
static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx)
@@ -2267,6 +2326,13 @@ static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx)
debugfs_remove_recursive(rndis_ipa_ctx->directory);
}
+#else /* !CONFIG_DEBUG_FS */
+
+static void rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx) {}
+
+static void rndis_ipa_debugfs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx) {}
+
+#endif /* CONFIG_DEBUG_FS*/
static int rndis_ipa_debugfs_aggr_open(struct inode *inode,
struct file *file)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 871329c79a46..0803a963da3c 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1298,6 +1298,14 @@ err:
static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
{
int ret;
+ struct ath10k_fw_file *fw_file;
+
+ 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_TLV;
+ fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
+ return 0;
+ }
if (ar->is_bmi) {
/* calibration file is optional, don't check for any errors */
@@ -1528,6 +1536,7 @@ static void ath10k_core_restart(struct work_struct *work)
struct ath10k *ar = container_of(work, struct ath10k, restart_work);
set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
+ ath10k_gen_set_base_mac_addr(ar, ar->base_mac_addr);
/* Place a barrier to make sure the compiler doesn't reorder
* CRASH_FLUSH and calling other functions.
@@ -1579,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;
@@ -1695,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;
@@ -1742,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/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 9310de85f2a0..f2f0338696e0 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -24,6 +24,7 @@
#include <linux/pci.h>
#include <linux/uuid.h>
#include <linux/time.h>
+#include <soc/qcom/socinfo.h>
#include "htt.h"
#include "htc.h"
@@ -708,6 +709,7 @@ struct ath10k {
struct ieee80211_ops *ops;
struct device *dev;
u8 mac_addr[ETH_ALEN];
+ u8 base_mac_addr[ETH_ALEN];
enum ath10k_hw_rev hw_rev;
u16 dev_id;
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-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index 9817c89cd76d..129859255295 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -188,6 +188,9 @@ struct wmi_ops {
u8 enable,
u32 detect_level,
u32 detect_margin);
+ struct sk_buff *(*gen_set_pdev_mac_addr)(struct ath10k *ar, u32 pdev_id,
+ u8 *mac_addr);
+
struct sk_buff *(*ext_resource_config)(struct ath10k *ar,
enum wmi_host_platform_type type,
u32 fw_feature_bitmap);
@@ -1417,4 +1420,25 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value)
return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid);
}
+static inline int
+ath10k_gen_set_base_mac_addr(struct ath10k *ar, u8 *mac)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ if (!ar->wmi.ops->gen_set_pdev_mac_addr)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_set_pdev_mac_addr(ar, 0, mac);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ret = ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_set_base_macaddr_cmdid);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index b0f3e9b9ef6f..3fef967ca1ad 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -3174,6 +3174,33 @@ ath10k_wmi_tlv_op_gen_wow_del_pattern(struct ath10k *ar, u32 vdev_id,
}
static struct sk_buff *
+ath10k_wmi_tlv_op_gen_set_base_mac_addr(struct ath10k *ar, u32 pdev_id,
+ u8 *mac_addr)
+{
+ struct wmi_tlv_mac_addr_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (struct wmi_tlv *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->pdev_id = __cpu_to_le32(pdev_id);
+ ether_addr_copy(cmd->mac_addr.addr, mac_addr);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set_base_mac addr pdev_id %d mac addr %pM\n",
+ cmd->pdev_id, cmd->mac_addr.addr);
+ return skb;
+}
+
+static struct sk_buff *
ath10k_wmi_tlv_op_gen_adaptive_qcs(struct ath10k *ar, bool enable)
{
struct wmi_tlv_adaptive_qcs *cmd;
@@ -3610,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,
@@ -3636,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 = {
@@ -3656,80 +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,
-};
-
-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 2b8318010a35..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;
@@ -1849,4 +1717,9 @@ struct wmi_tlv_mgmt_tx_cmd {
__le16 data_tag;
u8 buf[0];
} __packed;
+
+struct wmi_tlv_mac_addr_cmd {
+ __le32 pdev_id;
+ struct wmi_mac_addr mac_addr;
+} __packed;
#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index f7ada7147136..4dd60b74853d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4844,6 +4844,39 @@ static int ath10k_wmi_op_pull_echo_ev(struct ath10k *ar,
return 0;
}
+void
+ath10k_generate_mac_addr_auto(struct ath10k *ar, struct wmi_rdy_ev_arg *arg)
+{
+ unsigned int soc_serial_num;
+ u8 bdata_mac_addr[ETH_ALEN];
+ u8 udef_mac_addr[] = {0x00, 0x0A, 0xF5, 0x00, 0x00, 0x00};
+
+ soc_serial_num = socinfo_get_serial_number();
+ if (!soc_serial_num)
+ return;
+
+ if (arg->mac_addr) {
+ ether_addr_copy(ar->base_mac_addr, arg->mac_addr);
+ ether_addr_copy(bdata_mac_addr, arg->mac_addr);
+ soc_serial_num &= 0x00ffffff;
+ bdata_mac_addr[3] = (soc_serial_num >> 16) & 0xff;
+ bdata_mac_addr[4] = (soc_serial_num >> 8) & 0xff;
+ bdata_mac_addr[5] = soc_serial_num & 0xff;
+ ether_addr_copy(ar->mac_addr, bdata_mac_addr);
+ } else {
+ /* If mac address not encoded in wlan board data,
+ * Auto-generate mac address using device serial
+ * number and user defined mac address 'udef_mac_addr'.
+ */
+ udef_mac_addr[3] = (soc_serial_num >> 16) & 0xff;
+ udef_mac_addr[4] = (soc_serial_num >> 8) & 0xff;
+ udef_mac_addr[5] = soc_serial_num & 0xff;
+ ether_addr_copy(ar->base_mac_addr, udef_mac_addr);
+ udef_mac_addr[2] = (soc_serial_num >> 24) & 0xff;
+ ether_addr_copy(ar->mac_addr, udef_mac_addr);
+ }
+}
+
int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_rdy_ev_arg arg = {};
@@ -4862,7 +4895,11 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
arg.mac_addr,
__le32_to_cpu(arg.status));
- ether_addr_copy(ar->mac_addr, arg.mac_addr);
+ if (QCA_REV_WCN3990(ar))
+ ath10k_generate_mac_addr_auto(ar, &arg);
+ else
+ ether_addr_copy(ar->mac_addr, arg.mac_addr);
+
complete(&ar->wmi.unified_ready);
return 0;
}
@@ -8196,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 09595349f24b..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,16 +1747,39 @@ 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;
struct pending_wmi_event *evt, *t;
wil_dbg_wmi(wil, "%s()\n", __func__);
+ spin_lock_irqsave(&wil->wmi_ev_lock, flags);
+
list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
list_del(&evt->list);
kfree(evt);
}
+
+ spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
}
static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
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/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 9c2697dde76d..024c66ac8e57 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -5,20 +5,20 @@ config QPNP_REVID
tristate "QPNP Revision ID Peripheral"
depends on SPMI
help
- Say 'y' here to include support for the Qualcomm QPNP REVID
- peripheral. REVID prints out the PMIC type and revision numbers
- in the kernel log along with the PMIC option status. The PMIC
- type is mapped to a Qualcomm chip part number and logged as well.
+ Say 'y' here to include support for the Qualcomm Technologies, Inc.
+ QPNP REVID peripheral. REVID prints out the PMIC type and revision
+ numbers in the kernel log along with the PMIC option status. The PMIC
+ type is mapped to a QTI chip part number and logged as well.
config QPNP_COINCELL
- tristate "Qualcomm QPNP coincell charger support"
+ tristate "QPNP coincell charger support"
depends on SPMI
help
This driver supports the QPNP coincell peripheral found inside of
- Qualcomm QPNP PMIC devices. The coincell charger provides a means to
- charge a coincell battery or backup capacitor which is used to
- maintain PMIC register state when the main battery is removed from the
- mobile device.
+ Qualcomm Technologies, Inc. QPNP PMIC devices. The coincell charger
+ provides a means to charge a coincell battery or backup capacitor
+ which is used to maintain PMIC register state when the main battery is
+ removed from the mobile device.
config SPS
bool "SPS support"
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 58c1704a875c..188388bc97a0 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -1245,6 +1245,7 @@ int gsi_dealloc_evt_ring(unsigned long evt_ring_hdl)
}
mutex_lock(&gsi_ctx->mlock);
+ reinit_completion(&ctx->compl);
val = (((evt_ring_hdl << GSI_EE_n_EV_CH_CMD_CHID_SHFT) &
GSI_EE_n_EV_CH_CMD_CHID_BMSK) |
((op << GSI_EE_n_EV_CH_CMD_OPCODE_SHFT) &
@@ -1339,6 +1340,7 @@ int gsi_reset_evt_ring(unsigned long evt_ring_hdl)
}
mutex_lock(&gsi_ctx->mlock);
+ reinit_completion(&ctx->compl);
val = (((evt_ring_hdl << GSI_EE_n_EV_CH_CMD_CHID_SHFT) &
GSI_EE_n_EV_CH_CMD_CHID_BMSK) |
((op << GSI_EE_n_EV_CH_CMD_OPCODE_SHFT) &
@@ -1796,7 +1798,7 @@ int gsi_start_channel(unsigned long chan_hdl)
}
mutex_lock(&gsi_ctx->mlock);
- init_completion(&ctx->compl);
+ reinit_completion(&ctx->compl);
gsi_ctx->ch_dbg[chan_hdl].ch_start++;
val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) &
@@ -1854,7 +1856,7 @@ int gsi_stop_channel(unsigned long chan_hdl)
}
mutex_lock(&gsi_ctx->mlock);
- init_completion(&ctx->compl);
+ reinit_completion(&ctx->compl);
gsi_ctx->ch_dbg[chan_hdl].ch_stop++;
val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) &
@@ -1923,7 +1925,7 @@ int gsi_stop_db_channel(unsigned long chan_hdl)
}
mutex_lock(&gsi_ctx->mlock);
- init_completion(&ctx->compl);
+ reinit_completion(&ctx->compl);
gsi_ctx->ch_dbg[chan_hdl].ch_db_stop++;
val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) &
@@ -1989,7 +1991,7 @@ int gsi_reset_channel(unsigned long chan_hdl)
mutex_lock(&gsi_ctx->mlock);
reset:
- init_completion(&ctx->compl);
+ reinit_completion(&ctx->compl);
gsi_ctx->ch_dbg[chan_hdl].ch_reset++;
val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) &
GSI_EE_n_GSI_CH_CMD_CHID_BMSK) |
@@ -2055,7 +2057,7 @@ int gsi_dealloc_channel(unsigned long chan_hdl)
}
mutex_lock(&gsi_ctx->mlock);
- init_completion(&ctx->compl);
+ reinit_completion(&ctx->compl);
gsi_ctx->ch_dbg[chan_hdl].ch_de_alloc++;
val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) &
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 cd946fff31a9..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;
}
@@ -3715,30 +3715,49 @@ static void ipa3_destroy_flt_tbl_idrs(void)
static void ipa3_freeze_clock_vote_and_notify_modem(void)
{
int res;
- u32 ipa_clk_state;
struct ipa_active_client_logging_info log_info;
if (ipa3_ctx->smp2p_info.res_sent)
return;
+ if (ipa3_ctx->smp2p_info.out_base_id == 0) {
+ IPAERR("smp2p out gpio not assigned\n");
+ return;
+ }
+
IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log_info, "FREEZE_VOTE");
res = ipa3_inc_client_enable_clks_no_block(&log_info);
if (res)
- ipa_clk_state = 0;
+ ipa3_ctx->smp2p_info.ipa_clk_on = false;
else
- ipa_clk_state = 1;
-
- if (ipa3_ctx->smp2p_info.out_base_id) {
- gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
- IPA_GPIO_OUT_CLK_VOTE_IDX, ipa_clk_state);
- gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
- IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 1);
- ipa3_ctx->smp2p_info.res_sent = true;
- } else {
- IPAERR("smp2p out gpio not assigned\n");
- }
+ ipa3_ctx->smp2p_info.ipa_clk_on = true;
+
+ gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
+ IPA_GPIO_OUT_CLK_VOTE_IDX,
+ ipa3_ctx->smp2p_info.ipa_clk_on);
+ gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
+ IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 1);
+
+ ipa3_ctx->smp2p_info.res_sent = true;
+ IPADBG("IPA clocks are %s\n",
+ ipa3_ctx->smp2p_info.ipa_clk_on ? "ON" : "OFF");
+}
+
+void ipa3_reset_freeze_vote(void)
+{
+ if (ipa3_ctx->smp2p_info.res_sent == false)
+ return;
+
+ if (ipa3_ctx->smp2p_info.ipa_clk_on)
+ IPA_ACTIVE_CLIENTS_DEC_SPECIAL("FREEZE_VOTE");
+
+ gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
+ IPA_GPIO_OUT_CLK_VOTE_IDX, 0);
+ gpio_set_value(ipa3_ctx->smp2p_info.out_base_id +
+ IPA_GPIO_OUT_CLK_RSP_CMPLT_IDX, 0);
- IPADBG("IPA clocks are %s\n", ipa_clk_state ? "ON" : "OFF");
+ ipa3_ctx->smp2p_info.res_sent = false;
+ ipa3_ctx->smp2p_info.ipa_clk_on = false;
}
static int ipa3_panic_notifier(struct notifier_block *this,
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 7feb1c1ce178..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
@@ -1002,6 +1003,7 @@ struct ipa3cm_client_info {
struct ipa3_smp2p_info {
u32 out_base_id;
u32 in_base_id;
+ bool ipa_clk_on;
bool res_sent;
};
@@ -2045,6 +2047,7 @@ void ipa3_recycle_wan_skb(struct sk_buff *skb);
int ipa3_smmu_map_peer_reg(phys_addr_t phys_addr, bool map);
int ipa3_smmu_map_peer_buff(u64 iova, phys_addr_t phys_addr,
u32 size, bool map);
+void ipa3_reset_freeze_vote(void);
int ipa3_ntn_init(void);
int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats);
struct dentry *ipa_debugfs_get_root(void);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 24b61880f95d..57fa2465c9ea 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1356,33 +1356,6 @@ uc_timeout:
return result;
}
-static int ipa3_wait_for_prod_empty(void)
-{
- int i;
- u32 rx_door_bell_value;
-
- for (i = 0; i < IPA_UC_FINISH_MAX; i++) {
- rx_door_bell_value = ipahal_read_reg_mn(
- IPA_UC_MAILBOX_m_n,
- IPA_HW_WDI_RX_MBOX_START_INDEX / 32,
- IPA_HW_WDI_RX_MBOX_START_INDEX % 32);
- IPADBG("(%d)rx_DB(%u)rp(%u),comp_wp(%u)\n",
- i,
- rx_door_bell_value,
- *ipa3_ctx->uc_ctx.rdy_ring_rp_va,
- *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va);
- if (*ipa3_ctx->uc_ctx.rdy_ring_rp_va !=
- *ipa3_ctx->uc_ctx.rdy_comp_ring_wp_va) {
- usleep_range(IPA_UC_WAIT_MIN_SLEEP,
- IPA_UC_WAII_MAX_SLEEP);
- } else {
- return 0;
- }
- }
-
- return -ETIME;
-}
-
/**
* ipa3_disable_wdi_pipe() - WDI client disable
* @clnt_hdl: [in] opaque client handle assigned by IPA to client
@@ -1399,9 +1372,6 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl)
struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
u32 prod_hdl;
- u32 source_pipe_bitmask = 0;
- bool disable_force_clear = false;
-
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
IPAERR("bad parm, %d\n", clnt_hdl);
@@ -1456,40 +1426,6 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl)
usleep_range(IPA_UC_POLL_SLEEP_USEC * IPA_UC_POLL_SLEEP_USEC,
IPA_UC_POLL_SLEEP_USEC * IPA_UC_POLL_SLEEP_USEC);
- /*
- * checking rdy_ring_rp_pa matches the
- * rdy_comp_ring_wp_pa on WDI2.0
- */
- if (ipa3_ctx->ipa_wdi2) {
- result = ipa3_wait_for_prod_empty();
- if (result) {
- IPADBG("prod not empty\n");
- /*
- * In case ipa_uc still haven't processed all
- * pending descriptors, ask modem to drain
- */
- source_pipe_bitmask = 1 <<
- ipa3_get_ep_mapping(ep->client);
- result = ipa3_enable_force_clear(clnt_hdl,
- false, source_pipe_bitmask);
- if (result) {
- IPAERR("failed to force clear %d\n",
- result);
- } else {
- disable_force_clear = true;
- }
-
- /*
- * In case ipa_uc still haven't processed all
- * pending descriptors, we have to assert
- */
- result = ipa3_wait_for_prod_empty();
- if (result) {
- IPAERR("prod still not empty\n");
- ipa_assert();
- }
- }
- }
}
disable.params.ipa_pipe_number = clnt_hdl;
@@ -1508,8 +1444,6 @@ int ipa3_disable_wdi_pipe(u32 clnt_hdl)
memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
ep_cfg_ctrl.ipa_ep_delay = true;
ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
- if (disable_force_clear)
- ipa3_disable_force_clear(clnt_hdl);
}
IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
ep->uc_offload_state &= ~IPA_WDI_ENABLED;
@@ -1595,6 +1529,9 @@ int ipa3_suspend_wdi_pipe(u32 clnt_hdl)
struct ipa3_ep_context *ep;
union IpaHwWdiCommonChCmdData_t suspend;
struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
+ u32 source_pipe_bitmask = 0;
+ bool disable_force_clear = false;
+ struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 };
if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1619,6 +1556,31 @@ int ipa3_suspend_wdi_pipe(u32 clnt_hdl)
suspend.params.ipa_pipe_number = clnt_hdl;
if (IPA_CLIENT_IS_PROD(ep->client)) {
+ /*
+ * For WDI 2.0 need to ensure pipe will be empty before suspend
+ * as IPA uC will fail to suspend the pipe otherwise.
+ */
+ if (ipa3_ctx->ipa_wdi2) {
+ source_pipe_bitmask = 1 <<
+ ipa3_get_ep_mapping(ep->client);
+ result = ipa3_enable_force_clear(clnt_hdl,
+ false, source_pipe_bitmask);
+ if (result) {
+ /*
+ * assuming here modem SSR, AP can remove
+ * the delay in this case
+ */
+ IPAERR("failed to force clear %d\n", result);
+ IPAERR("remove delay from SCND reg\n");
+ ep_ctrl_scnd.endp_delay = false;
+ ipahal_write_reg_n_fields(
+ IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl,
+ &ep_ctrl_scnd);
+ } else {
+ disable_force_clear = true;
+ }
+ }
+
IPADBG("Post suspend event first for IPA Producer\n");
IPADBG("Client: %d clnt_hdl: %d\n", ep->client, clnt_hdl);
result = ipa3_uc_send_cmd(suspend.raw32b,
@@ -1663,6 +1625,9 @@ int ipa3_suspend_wdi_pipe(u32 clnt_hdl)
}
}
+ if (disable_force_clear)
+ ipa3_disable_force_clear(clnt_hdl);
+
ipa3_ctx->tag_process_before_gating = true;
IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
ep->uc_offload_state &= ~IPA_WDI_RESUMED;
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/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index ed0d0032af8d..3855e0d46ca9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -44,6 +44,7 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = {
__stringify(IPA_ENDP_INIT_MODE_n),
__stringify(IPA_ENDP_INIT_NAT_n),
__stringify(IPA_ENDP_INIT_CTRL_n),
+ __stringify(IPA_ENDP_INIT_CTRL_SCND_n),
__stringify(IPA_ENDP_INIT_HOL_BLOCK_EN_n),
__stringify(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n),
__stringify(IPA_ENDP_INIT_DEAGGR_n),
@@ -645,6 +646,17 @@ static void ipareg_construct_endp_init_ctrl_n(enum ipahal_reg_name reg,
IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK);
}
+static void ipareg_construct_endp_init_ctrl_scnd_n(enum ipahal_reg_name reg,
+ const void *fields, u32 *val)
+{
+ struct ipahal_ep_cfg_ctrl_scnd *ep_ctrl_scnd =
+ (struct ipahal_ep_cfg_ctrl_scnd *)fields;
+
+ IPA_SETFIELD_IN_REG(*val, ep_ctrl_scnd->endp_delay,
+ IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_SHFT,
+ IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_BMSK);
+}
+
static void ipareg_construct_endp_init_nat_n(enum ipahal_reg_name reg,
const void *fields, u32 *val)
{
@@ -1008,6 +1020,9 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = {
[IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_n] = {
ipareg_construct_endp_init_ctrl_n, ipareg_parse_dummy,
0x00000800, 0x70},
+ [IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_SCND_n] = {
+ ipareg_construct_endp_init_ctrl_scnd_n, ipareg_parse_dummy,
+ 0x00000804, 0x70 },
[IPA_HW_v3_0][IPA_ENDP_INIT_HOL_BLOCK_EN_n] = {
ipareg_construct_endp_init_hol_block_en_n,
ipareg_parse_dummy,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
index 0fc2a65f5e99..c37415f13380 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h
@@ -47,6 +47,7 @@ enum ipahal_reg_name {
IPA_ENDP_INIT_MODE_n,
IPA_ENDP_INIT_NAT_n,
IPA_ENDP_INIT_CTRL_n,
+ IPA_ENDP_INIT_CTRL_SCND_n,
IPA_ENDP_INIT_HOL_BLOCK_EN_n,
IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
IPA_ENDP_INIT_DEAGGR_n,
@@ -332,6 +333,14 @@ struct ipahal_reg_tx_cfg {
};
/*
+ * struct ipa_ep_cfg_ctrl_scnd - PA_ENDP_INIT_CTRL_SCND_n register
+ * @endp_delay: delay endpoint
+ */
+struct ipahal_ep_cfg_ctrl_scnd {
+ bool endp_delay;
+};
+
+/*
* ipahal_reg_name_str() - returns string that represent the register
* @reg_name: [in] register name
*/
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h
index 1606a2ff41c7..ac97e5ac0494 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg_i.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
@@ -122,6 +122,10 @@ int ipahal_reg_init(enum ipa_hw_type ipa_hw_type);
#define IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK 0x2
#define IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT 0x1
+/* IPA_ENDP_INIT_CTRL_SCND_n register */
+#define IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_BMSK 0x2
+#define IPA_ENDP_INIT_CTRL_SCND_n_ENDP_DELAY_SHFT 0x1
+
/* IPA_ENDP_INIT_HOL_BLOCK_EN_n register */
#define IPA_ENDP_INIT_HOL_BLOCK_EN_n_RMSK 0x1
#define IPA_ENDP_INIT_HOL_BLOCK_EN_n_MAX 19
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index f042d19f196a..6731150ce4e7 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.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
@@ -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) {
@@ -1154,8 +1155,9 @@ send:
dev->stats.tx_bytes += skb->len;
ret = NETDEV_TX_OK;
out:
- ipa_rm_inactivity_timer_release_resource(
- IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (atomic_read(&wwan_ptr->outstanding_pkts) == 0)
+ ipa_rm_inactivity_timer_release_resource(
+ IPA_RM_RESOURCE_WWAN_0_PROD);
return ret;
}
@@ -1206,10 +1208,12 @@ static void apps_ipa_tx_complete_notify(void *priv,
wwan_ptr->outstanding_low);
netif_wake_queue(wwan_ptr->net);
}
+
+ if (atomic_read(&wwan_ptr->outstanding_pkts) == 0)
+ ipa_rm_inactivity_timer_release_resource(
+ IPA_RM_RESOURCE_WWAN_0_PROD);
__netif_tx_unlock_bh(netdev_get_tx_queue(dev, 0));
dev_kfree_skb_any(skb);
- ipa_rm_inactivity_timer_release_resource(
- IPA_RM_RESOURCE_WWAN_0_PROD);
}
/**
@@ -1280,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);
@@ -1325,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");
@@ -1344,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
@@ -1504,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,
@@ -1590,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);
@@ -2260,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);
@@ -2435,6 +2477,7 @@ static int ipa3_ssr_notifier_cb(struct notifier_block *this,
ipa3_qmi_service_exit();
/*hold a proxy vote for the modem*/
ipa3_proxy_clk_vote();
+ ipa3_reset_freeze_vote();
IPAWANINFO("IPA BEFORE_POWERUP handling is complete\n");
break;
case SUBSYS_AFTER_POWERUP:
@@ -3156,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,
@@ -3171,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/platform/msm/qpnp-coincell.c b/drivers/platform/msm/qpnp-coincell.c
index 6aaa53526868..b427f43e76df 100644
--- a/drivers/platform/msm/qpnp-coincell.c
+++ b/drivers/platform/msm/qpnp-coincell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -244,7 +244,7 @@ static int qpnp_coincell_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id qpnp_coincell_match_table[] = {
+static const struct of_device_id qpnp_coincell_match_table[] = {
{ .compatible = QPNP_COINCELL_DRIVER_NAME, },
{}
};
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index 6b5db58f856a..9ea0b40304eb 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.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
@@ -70,7 +70,7 @@ struct revid_chip {
static LIST_HEAD(revid_chips);
static DEFINE_MUTEX(revid_chips_lock);
-static struct of_device_id qpnp_revid_match_table[] = {
+static const struct of_device_id qpnp_revid_match_table[] = {
{ .compatible = QPNP_REVID_DEV_NAME },
{}
};
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 3b2ea6a6a5ed..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,6 +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(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/Makefile b/drivers/power/supply/qcom/Makefile
index 912acb0c788a..a3aff858c190 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_QPNP_SMBCHARGER) += qpnp-smbcharger.o batterydata-lib.o pmic-voter.
obj-$(CONFIG_QPNP_FG) += qpnp-fg.o
obj-$(CONFIG_QPNP_FG_GEN3) += qpnp-fg-gen3.o fg-memif.o fg-util.o
obj-$(CONFIG_SMB135X_CHARGER) += smb135x-charger.o pmic-voter.o
-obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o
+obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o
obj-$(CONFIG_MSM_BCL_CTL) += msm_bcl.o
obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o
obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 34add97b55d2..35dc3842017b 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -33,6 +33,8 @@
#define TAPER_END_VOTER "TAPER_END_VOTER"
#define PL_TAPER_EARLY_BAD_VOTER "PL_TAPER_EARLY_BAD_VOTER"
#define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER"
+#define PL_HW_ABSENT_VOTER "PL_HW_ABSENT_VOTER"
+#define PL_VOTER "PL_VOTER"
struct pl_data {
int pl_mode;
@@ -44,12 +46,14 @@ struct pl_data {
struct votable *pl_disable_votable;
struct votable *pl_awake_votable;
struct work_struct status_change_work;
+ struct work_struct pl_disable_forever_work;
struct delayed_work pl_taper_work;
struct power_supply *main_psy;
struct power_supply *pl_psy;
struct power_supply *batt_psy;
- int settled_ua;
int charge_type;
+ int main_settled_ua;
+ int pl_settled_ua;
struct class qcom_batt_class;
struct wakeup_source *pl_ws;
struct notifier_block nb;
@@ -83,7 +87,7 @@ enum {
static void split_settled(struct pl_data *chip)
{
int slave_icl_pct;
- int slave_ua = 0;
+ int slave_ua = 0, main_settled_ua = 0;
union power_supply_propval pval = {0, };
int rc;
@@ -106,10 +110,11 @@ static void split_settled(struct pl_data *chip)
pr_err("Couldn't get aicl settled value rc=%d\n", rc);
return;
}
- chip->settled_ua = pval.intval;
+ main_settled_ua = pval.intval;
/* slave gets 10 percent points less for ICL */
slave_icl_pct = max(0, chip->slave_pct - 10);
- slave_ua = (chip->settled_ua * slave_icl_pct) / 100;
+ slave_ua = ((main_settled_ua + chip->pl_settled_ua)
+ * slave_icl_pct) / 100;
}
/* ICL_REDUCTION on main could be 0mA when pl is disabled */
@@ -129,6 +134,11 @@ static void split_settled(struct pl_data *chip)
pr_err("Couldn't set parallel icl, rc=%d\n", rc);
return;
}
+
+ /* main_settled_ua represents the total capability of adapter */
+ if (!chip->main_settled_ua)
+ chip->main_settled_ua = main_settled_ua;
+ chip->pl_settled_ua = slave_ua;
}
static ssize_t version_show(struct class *c, struct class_attribute *attr,
@@ -237,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,
@@ -252,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;
+
+ 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;
- input_limited_fcc_ua = div64_s64(
- (s64)aicl_settled_ua * MICRO_5V * EFFICIENCY_PCT,
- (s64)get_effective_result(chip->fv_votable)
- * 100);
+ 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);
@@ -288,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;
@@ -333,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;
@@ -340,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) {
@@ -349,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) {
@@ -361,6 +404,15 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
return 0;
}
+static void pl_disable_forever_work(struct work_struct *work)
+{
+ struct pl_data *chip = container_of(work,
+ struct pl_data, pl_disable_forever_work);
+
+ /* Disable Parallel charger forever */
+ vote(chip->pl_disable_votable, PL_HW_ABSENT_VOTER, true, 0);
+}
+
static int pl_disable_vote_callback(struct votable *votable,
void *data, int pl_disable, const char *client)
{
@@ -368,10 +420,23 @@ static int pl_disable_vote_callback(struct votable *votable,
union power_supply_propval pval = {0, };
int rc;
- chip->settled_ua = 0;
chip->taper_pct = 100;
+ chip->main_settled_ua = 0;
+ chip->pl_settled_ua = 0;
if (!pl_disable) { /* enable */
+ rc = power_supply_get_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
+ if (rc == -ENODEV) {
+ /*
+ * -ENODEV is returned only if parallel chip
+ * is not present in the system.
+ * Disable parallel charger forever.
+ */
+ schedule_work(&chip->pl_disable_forever_work);
+ return rc;
+ }
+
rerun_election(chip->fv_votable);
rerun_election(chip->fcc_votable);
/*
@@ -482,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);
@@ -538,6 +603,7 @@ static void handle_main_charge_type(struct pl_data *chip)
chip->charge_type = pval.intval;
}
+#define MIN_ICL_CHANGE_DELTA_UA 300000
static void handle_settled_aicl_split(struct pl_data *chip)
{
union power_supply_propval pval = {0, };
@@ -556,10 +622,11 @@ static void handle_settled_aicl_split(struct pl_data *chip)
pr_err("Couldn't get aicl settled value rc=%d\n", rc);
return;
}
- if (chip->settled_ua != pval.intval) {
- chip->settled_ua = pval.intval;
+
+ /* If ICL change is small skip splitting */
+ if (abs((chip->main_settled_ua - chip->pl_settled_ua)
+ - pval.intval) > MIN_ICL_CHANGE_DELTA_UA)
split_settled(chip);
- }
}
}
@@ -697,6 +764,7 @@ static int pl_init(void)
INIT_WORK(&chip->status_change_work, status_change_work);
INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
+ INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
rc = pl_register_notifier(chip);
if (rc < 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 12f3d448c891..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
@@ -167,11 +169,11 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = {
fg_decode_default),
PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
fg_decode_default),
- PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 244141,
- 1000, 0, NULL, fg_decode_voltage_15b),
- PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 244141, 1000, 0, NULL,
+ PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
+ 244141, 0, NULL, fg_decode_voltage_15b),
+ PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
fg_decode_voltage_15b),
- PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 244141, 1000, 0, NULL,
+ PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
fg_decode_value_16b),
PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
fg_decode_default),
@@ -188,8 +190,8 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = {
-2500, fg_encode_voltage, NULL),
PARAM(VBATT_LOW, VBATT_LOW_WORD, VBATT_LOW_OFFSET, 1, 100000, 390625,
-2500, fg_encode_voltage, NULL),
- PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000000,
- 244141, 0, fg_encode_voltage, NULL),
+ PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
+ 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
1000000, 122070, 0, fg_encode_current, NULL),
PARAM(CHG_TERM_CURR, CHG_TERM_CURR_WORD, CHG_TERM_CURR_OFFSET, 1,
@@ -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[] = {
@@ -227,11 +231,11 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
fg_decode_default),
PARAM(FULL_SOC, FULL_SOC_WORD, FULL_SOC_OFFSET, 2, 1, 1, 0, NULL,
fg_decode_default),
- PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 244141,
- 1000, 0, NULL, fg_decode_voltage_15b),
- PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 244141, 1000, 0, NULL,
+ PARAM(VOLTAGE_PRED, VOLTAGE_PRED_WORD, VOLTAGE_PRED_OFFSET, 2, 1000,
+ 244141, 0, NULL, fg_decode_voltage_15b),
+ PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL,
fg_decode_voltage_15b),
- PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 244141, 1000, 0, NULL,
+ PARAM(RSLOW, RSLOW_WORD, RSLOW_OFFSET, 2, 1000, 244141, 0, NULL,
fg_decode_value_16b),
PARAM(ALG_FLAGS, ALG_FLAGS_WORD, ALG_FLAGS_OFFSET, 1, 1, 1, 0, NULL,
fg_decode_default),
@@ -250,8 +254,8 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
15625, -2000, fg_encode_voltage, NULL),
PARAM(FLOAT_VOLT, FLOAT_VOLT_v2_WORD, FLOAT_VOLT_v2_OFFSET, 1, 1000,
15625, -2000, fg_encode_voltage, NULL),
- PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000000,
- 244141, 0, fg_encode_voltage, NULL),
+ PARAM(VBATT_FULL, VBATT_FULL_WORD, VBATT_FULL_OFFSET, 2, 1000,
+ 244141, 0, fg_encode_voltage, fg_decode_voltage_15b),
PARAM(SYS_TERM_CURR, SYS_TERM_CURR_WORD, SYS_TERM_CURR_OFFSET, 3,
1000000, 122070, 0, fg_encode_current, NULL),
PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1,
@@ -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[] = {
@@ -374,7 +380,7 @@ static int fg_decode_voltage_15b(struct fg_sram_param *sp,
enum fg_sram_param_id id, int value)
{
value &= VOLTAGE_15BIT_MASK;
- sp[id].value = div_u64((u64)value * sp[id].numrtr, sp[id].denmtr);
+ sp[id].value = div_u64((u64)value * sp[id].denmtr, sp[id].numrtr);
pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
sp[id].value);
return sp[id].value;
@@ -383,7 +389,7 @@ static int fg_decode_voltage_15b(struct fg_sram_param *sp,
static int fg_decode_cc_soc(struct fg_sram_param *sp,
enum fg_sram_param_id id, int value)
{
- sp[id].value = div_s64((s64)value * sp[id].numrtr, sp[id].denmtr);
+ sp[id].value = div_s64((s64)value * sp[id].denmtr, sp[id].numrtr);
sp[id].value = sign_extend32(sp[id].value, 31);
pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
sp[id].value);
@@ -393,7 +399,7 @@ static int fg_decode_cc_soc(struct fg_sram_param *sp,
static int fg_decode_value_16b(struct fg_sram_param *sp,
enum fg_sram_param_id id, int value)
{
- sp[id].value = div_u64((u64)(u16)value * sp[id].numrtr, sp[id].denmtr);
+ sp[id].value = div_u64((u64)(u16)value * sp[id].denmtr, sp[id].numrtr);
pr_debug("id: %d raw value: %x decoded value: %x\n", id, value,
sp[id].value);
return sp[id].value;
@@ -855,23 +861,50 @@ static const char *fg_get_battery_type(struct fg_chip *chip)
return DEFAULT_BATT_TYPE;
}
-static int fg_get_batt_id(struct fg_chip *chip, int *val)
+static int fg_batt_missing_config(struct fg_chip *chip, bool enable)
+{
+ int rc;
+
+ rc = fg_masked_write(chip, BATT_INFO_BATT_MISS_CFG(chip),
+ BM_FROM_BATT_ID_BIT, enable ? BM_FROM_BATT_ID_BIT : 0);
+ if (rc < 0)
+ pr_err("Error in writing to %04x, rc=%d\n",
+ BATT_INFO_BATT_MISS_CFG(chip), rc);
+ return rc;
+}
+
+static int fg_get_batt_id(struct fg_chip *chip)
{
- int rc, batt_id = -EINVAL;
+ int rc, ret, batt_id = 0;
if (!chip->batt_id_chan)
return -EINVAL;
+ rc = fg_batt_missing_config(chip, false);
+ if (rc < 0) {
+ pr_err("Error in disabling BMD, rc=%d\n", rc);
+ return rc;
+ }
+
rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id);
if (rc < 0) {
pr_err("Error in reading batt_id channel, rc:%d\n", rc);
- return rc;
+ goto out;
}
+ /* Wait for 200ms before enabling BMD again */
+ msleep(200);
+
fg_dbg(chip, FG_STATUS, "batt_id: %d\n", batt_id);
+ chip->batt_id_ohms = batt_id;
+out:
+ ret = fg_batt_missing_config(chip, true);
+ if (ret < 0) {
+ pr_err("Error in enabling BMD, ret=%d\n", ret);
+ return ret;
+ }
- *val = batt_id;
- return 0;
+ return rc;
}
static int fg_get_batt_profile(struct fg_chip *chip)
@@ -879,24 +912,16 @@ static int fg_get_batt_profile(struct fg_chip *chip)
struct device_node *node = chip->dev->of_node;
struct device_node *batt_node, *profile_node;
const char *data;
- int rc, len, batt_id;
+ int rc, len;
- rc = fg_get_batt_id(chip, &batt_id);
- if (rc < 0) {
- pr_err("Error in getting batt_id rc:%d\n", rc);
- return rc;
- }
-
- chip->batt_id_ohms = batt_id;
- batt_id /= 1000;
batt_node = of_find_node_by_name(node, "qcom,battery-data");
if (!batt_node) {
pr_err("Batterydata not available\n");
return -ENXIO;
}
- profile_node = of_batterydata_get_best_profile(batt_node, batt_id,
- NULL);
+ profile_node = of_batterydata_get_best_profile(batt_node,
+ chip->batt_id_ohms / 1000, NULL);
if (IS_ERR(profile_node))
return PTR_ERR(profile_node);
@@ -946,6 +971,7 @@ static int fg_get_batt_profile(struct fg_chip *chip)
chip->profile_available = true;
memcpy(chip->batt_profile, data, len);
+
return 0;
}
@@ -1660,6 +1686,29 @@ static int fg_rconn_config(struct fg_chip *chip)
return 0;
}
+static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
+{
+ u8 buf[2];
+ int rc;
+
+ if (volt_uv <= 0 || volt_uv > 15590000) {
+ pr_err("Invalid voltage %d\n", volt_uv);
+ return -EINVAL;
+ }
+
+ fg_encode(chip->sp, FG_SRAM_VBATT_FULL, volt_uv, buf);
+
+ rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
+ chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
+ chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing vbatt_full, rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc)
{
u8 buf;
@@ -1727,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;
@@ -1742,39 +1833,41 @@ static int fg_esr_filter_config(struct fg_chip *chip, int batt_temp)
/*
* If battery temperature is lesser than 10 C (default), then apply the
- * normal ESR tight and broad filter values to ESR low temperature tight
- * and broad filters. If battery temperature is higher than 10 C, then
- * apply back the low temperature ESR filter coefficients to ESR low
- * temperature tight and broad filters.
+ * ESR low temperature tight and broad filter values to ESR room
+ * temperature tight and broad filters. If battery temperature is higher
+ * than 10 C, then apply back the room temperature ESR filter
+ * coefficients to ESR room temperature tight and broad filters.
*/
if (batt_temp > chip->dt.esr_flt_switch_temp
&& chip->esr_flt_cold_temp_en) {
fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
- chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
+ chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
- chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
+ chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
} else if (batt_temp <= chip->dt.esr_flt_switch_temp
&& !chip->esr_flt_cold_temp_en) {
fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
- chip->dt.esr_tight_flt_upct, &esr_tight_lt_flt);
+ chip->dt.esr_tight_lt_flt_upct, &esr_tight_lt_flt);
fg_encode(chip->sp, FG_SRAM_ESR_BROAD_FILTER,
- chip->dt.esr_broad_flt_upct, &esr_broad_lt_flt);
+ chip->dt.esr_broad_lt_flt_upct, &esr_broad_lt_flt);
cold_temp = true;
} else {
return 0;
}
- rc = fg_sram_write(chip, ESR_FILTER_WORD,
- ESR_UPD_TIGHT_LOW_TEMP_OFFSET, &esr_tight_lt_flt, 1,
- FG_IMA_DEFAULT);
+ rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word,
+ chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_byte,
+ &esr_tight_lt_flt,
+ chip->sp[FG_SRAM_ESR_TIGHT_FILTER].len, FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("Error in writing ESR LT tight filter, rc=%d\n", rc);
return rc;
}
- rc = fg_sram_write(chip, ESR_FILTER_WORD,
- ESR_UPD_BROAD_LOW_TEMP_OFFSET, &esr_broad_lt_flt, 1,
- FG_IMA_DEFAULT);
+ rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_word,
+ chip->sp[FG_SRAM_ESR_BROAD_FILTER].addr_byte,
+ &esr_broad_lt_flt,
+ chip->sp[FG_SRAM_ESR_BROAD_FILTER].len, FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("Error in writing ESR LT broad filter, rc=%d\n", rc);
return rc;
@@ -1853,18 +1946,6 @@ static int fg_esr_fcc_config(struct fg_chip *chip)
return 0;
}
-static int fg_batt_missing_config(struct fg_chip *chip, bool enable)
-{
- int rc;
-
- rc = fg_masked_write(chip, BATT_INFO_BATT_MISS_CFG(chip),
- BM_FROM_BATT_ID_BIT, enable ? BM_FROM_BATT_ID_BIT : 0);
- if (rc < 0)
- pr_err("Error in writing to %04x, rc=%d\n",
- BATT_INFO_BATT_MISS_CFG(chip), rc);
- return rc;
-}
-
static void fg_batt_avg_update(struct fg_chip *chip)
{
if (chip->charge_status == chip->prev_charge_status)
@@ -1885,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");
@@ -1938,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:
@@ -2283,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) {
@@ -2292,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));
@@ -2725,6 +2817,9 @@ static int fg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_DEBUG_BATTERY:
pval->intval = is_debug_batt_id(chip);
break;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
+ break;
default:
pr_err("unsupported property %d\n", psp);
rc = -EINVAL;
@@ -2742,6 +2837,7 @@ static int fg_psy_set_property(struct power_supply *psy,
const union power_supply_propval *pval)
{
struct fg_chip *chip = power_supply_get_drvdata(psy);
+ int rc = 0;
switch (psp) {
case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
@@ -2752,12 +2848,14 @@ static int fg_psy_set_property(struct power_supply *psy,
pval->intval);
return -EINVAL;
}
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ rc = fg_set_constant_chg_voltage(chip, pval->intval);
break;
default:
break;
}
- return 0;
+ return rc;
}
static int fg_property_is_writeable(struct power_supply *psy,
@@ -2765,6 +2863,7 @@ static int fg_property_is_writeable(struct power_supply *psy,
{
switch (psp) {
case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
return 1;
default:
break;
@@ -2824,6 +2923,7 @@ static enum power_supply_property fg_psy_props[] = {
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
POWER_SUPPLY_PROP_SOC_REPORTING_READY,
POWER_SUPPLY_PROP_DEBUG_BATTERY,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
};
static const struct power_supply_desc fg_psy_desc = {
@@ -2877,15 +2977,10 @@ static int fg_hw_init(struct fg_chip *chip)
}
if (chip->bp.vbatt_full_mv > 0) {
- fg_encode(chip->sp, FG_SRAM_VBATT_FULL, chip->bp.vbatt_full_mv,
- buf);
- rc = fg_sram_write(chip, chip->sp[FG_SRAM_VBATT_FULL].addr_word,
- chip->sp[FG_SRAM_VBATT_FULL].addr_byte, buf,
- chip->sp[FG_SRAM_VBATT_FULL].len, FG_IMA_DEFAULT);
- if (rc < 0) {
- pr_err("Error in writing vbatt_full, rc=%d\n", rc);
+ rc = fg_set_constant_chg_voltage(chip,
+ chip->bp.vbatt_full_mv * 1000);
+ if (rc < 0)
return rc;
- }
}
fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
@@ -2947,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) {
@@ -3142,9 +3252,10 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
- rc = fg_batt_missing_config(chip, false);
+ rc = fg_get_batt_id(chip);
if (rc < 0) {
- pr_err("Error in disabling BMD, rc=%d\n", rc);
+ chip->soc_reporting_ready = true;
+ pr_err("Error in getting battery id, rc:%d\n", rc);
return IRQ_HANDLED;
}
@@ -3152,19 +3263,12 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data)
if (rc < 0) {
chip->soc_reporting_ready = true;
pr_err("Error in getting battery profile, rc:%d\n", rc);
- goto enable_bmd;
+ return IRQ_HANDLED;
}
clear_battery_profile(chip);
schedule_delayed_work(&chip->profile_load_work, 0);
-enable_bmd:
- /* Wait for 200ms before enabling BMD again */
- msleep(200);
- rc = fg_batt_missing_config(chip, true);
- if (rc < 0)
- pr_err("Error in enabling BMD, rc=%d\n", rc);
-
if (chip->fg_psy)
power_supply_changed(chip->fg_psy);
@@ -3188,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;
@@ -3425,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;
@@ -3571,16 +3713,6 @@ static int fg_parse_dt(struct fg_chip *chip)
return -EINVAL;
}
- chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
- if (IS_ERR(chip->batt_id_chan)) {
- if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
- pr_err("batt_id_chan unavailable %ld\n",
- PTR_ERR(chip->batt_id_chan));
- rc = PTR_ERR(chip->batt_id_chan);
- chip->batt_id_chan = NULL;
- return rc;
- }
-
if (of_get_available_child_count(node) == 0) {
dev_err(chip->dev, "No child nodes specified!\n");
return -ENXIO;
@@ -3625,13 +3757,6 @@ static int fg_parse_dt(struct fg_chip *chip)
}
chip->rradc_base = base;
- rc = fg_get_batt_profile(chip);
- if (rc < 0) {
- chip->soc_reporting_ready = true;
- pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
- chip->batt_id_ohms / 1000, rc);
- }
-
/* Read all the optional properties below */
rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage", &temp);
if (rc < 0)
@@ -3704,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;
@@ -3830,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;
}
@@ -3867,10 +4009,13 @@ static int fg_gen3_probe(struct platform_device *pdev)
return -ENXIO;
}
- rc = fg_parse_dt(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
- rc);
+ chip->batt_id_chan = iio_channel_get(chip->dev, "rradc_batt_id");
+ if (IS_ERR(chip->batt_id_chan)) {
+ if (PTR_ERR(chip->batt_id_chan) != -EPROBE_DEFER)
+ pr_err("batt_id_chan unavailable %ld\n",
+ PTR_ERR(chip->batt_id_chan));
+ rc = PTR_ERR(chip->batt_id_chan);
+ chip->batt_id_chan = NULL;
return rc;
}
@@ -3881,6 +4026,13 @@ static int fg_gen3_probe(struct platform_device *pdev)
return rc;
}
+ rc = fg_parse_dt(chip);
+ if (rc < 0) {
+ dev_err(chip->dev, "Error in reading DT parameters, rc:%d\n",
+ rc);
+ goto exit;
+ }
+
mutex_init(&chip->bus_lock);
mutex_init(&chip->sram_rw_lock);
mutex_init(&chip->cyc_ctr.lock);
@@ -3895,6 +4047,19 @@ static int fg_gen3_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
+ rc = fg_get_batt_id(chip);
+ if (rc < 0) {
+ pr_err("Error in getting battery id, rc:%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_get_batt_profile(chip);
+ if (rc < 0) {
+ chip->soc_reporting_ready = true;
+ pr_warn("profile for batt_id=%dKOhms not found..using OTP, rc:%d\n",
+ chip->batt_id_ohms / 1000, rc);
+ }
+
rc = fg_memif_init(chip);
if (rc < 0) {
dev_err(chip->dev, "Error in initializing FG_MEMIF, rc:%d\n",
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index c4cc541a0a3e..d36db8d8f3f1 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -110,8 +110,7 @@ struct qnovo_dt_props {
};
enum {
- QNOVO_ERASE_OFFSET_WA_BIT = BIT(0),
- QNOVO_NO_ERR_STS_BIT = BIT(1),
+ QNOVO_NO_ERR_STS_BIT = BIT(0),
};
struct chg_props {
@@ -149,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;
@@ -227,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)
{
@@ -234,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,
@@ -254,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;
@@ -315,7 +339,6 @@ static int qnovo_check_chg_version(struct qnovo *chip)
if ((chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE)
&& (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4)) {
- chip->wa_flags |= QNOVO_ERASE_OFFSET_WA_BIT;
chip->wa_flags |= QNOVO_NO_ERR_STS_BIT;
}
@@ -447,6 +470,8 @@ static struct param_info params[] = {
.num_regs = 1,
.reg_to_unit_multiplier = 1,
.reg_to_unit_divider = 1,
+ .min_val = 0,
+ .max_val = 255,
.units_str = "pulses",
},
[VLIM1] = {
@@ -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);
@@ -1187,7 +1209,7 @@ static int qnovo_hw_init(struct qnovo *chip)
u8 iadc_offset_external, iadc_offset_internal;
u8 iadc_gain_external, iadc_gain_internal;
u8 vadc_offset, vadc_gain;
- u8 buf[2] = {0, 0};
+ u8 val;
vote(chip->disable_votable, USER_VOTER, 1, 0);
@@ -1241,13 +1263,39 @@ static int qnovo_hw_init(struct qnovo *chip)
chip->v_gain_mega = 1000000000 + (s64)vadc_gain * GAIN_LSB_FACTOR;
chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000);
- if (chip->wa_flags & QNOVO_ERASE_OFFSET_WA_BIT) {
- rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_0, buf, 2);
- if (rc < 0) {
- pr_err("Couldn't erase offset rc = %d\n", rc);
- return rc;
- }
+ val = 0;
+ rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write iadc bitsteam control rc = %d\n", rc);
+ return rc;
+ }
+
+ rc = qnovo_read(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't read iadc offset rc = %d\n", rc);
+ return rc;
+ }
+
+ val *= -1;
+ rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write iadc offset rc = %d\n", rc);
+ return rc;
}
+
+ rc = qnovo_read(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't read iadc offset rc = %d\n", rc);
+ return rc;
+ }
+
+ val *= -1;
+ rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write iadc offset rc = %d\n", rc);
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index dea932ae37ad..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>
@@ -219,6 +218,23 @@ static struct smb_params v1_params = {
},
};
+static struct smb_params pm660_params = {
+ .freq_buck = {
+ .name = "buck switching frequency",
+ .reg = FREQ_CLK_DIV_REG,
+ .min_u = 600,
+ .max_u = 1600,
+ .set_proc = smblib_set_chg_freq,
+ },
+ .freq_boost = {
+ .name = "boost switching frequency",
+ .reg = FREQ_CLK_DIV_REG,
+ .min_u = 600,
+ .max_u = 1600,
+ .set_proc = smblib_set_chg_freq,
+ },
+};
+
#define STEP_CHARGING_MAX_STEPS 5
struct smb_dt_props {
int fcc_ua;
@@ -368,6 +384,10 @@ static int smb2_parse_dt(struct smb2 *chip)
chg->micro_usb_mode = of_property_read_bool(node, "qcom,micro-usb");
+ 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;
}
@@ -393,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,
@@ -478,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;
@@ -526,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;
@@ -539,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;
@@ -584,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,
@@ -616,11 +647,14 @@ 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;
default:
- pr_err("get prop %d is not supported in usb-main\n", psp);
+ pr_debug("get prop %d is not supported in usb-main\n", psp);
rc = -EINVAL;
break;
}
@@ -644,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);
@@ -814,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,
@@ -866,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:
@@ -890,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;
@@ -926,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 */
@@ -1297,16 +1348,31 @@ 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,
&chip->dt.dc_icl_ua);
- chg->otg_cl_ua = chip->dt.otg_cl_ua;
- chg->dcp_icl_ua = chip->dt.usb_icl_ua;
+ /* set a slower soft start setting for OTG */
+ rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG2_REG,
+ ENG_SSUPPLY_IVREF_OTG_SS_MASK, OTG_SS_SLOW);
+ if (rc < 0) {
+ pr_err("Couldn't set otg soft start rc=%d\n", rc);
+ return rc;
+ }
+
+ /* set OTG current limit */
+ rc = smblib_set_charge_param(chg, &chg->param.otg_cl,
+ chip->dt.otg_cl_ua);
+ if (rc < 0) {
+ pr_err("Couldn't set otg current limit rc=%d\n", rc);
+ return rc;
+ }
+
chg->boost_threshold_ua = chip->dt.boost_threshold_ua;
rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
@@ -1318,25 +1384,21 @@ static int smb2_init_hw(struct smb2 *chip)
smblib_rerun_apsd_if_required(chg);
/* clear the ICL override if it is set */
- if (stat & ICL_OVERRIDE_LATCH_BIT) {
- rc = smblib_write(chg, CMD_APSD_REG, ICL_OVERRIDE_BIT);
- if (rc < 0) {
- pr_err("Couldn't disable ICL override rc=%d\n", rc);
- return rc;
- }
+ if (smblib_icl_override(chg, false) < 0) {
+ pr_err("Couldn't disable ICL override rc=%d\n", rc);
+ return rc;
}
/* 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);
- vote(chg->usb_icl_votable,
- DCP_VOTER, true, chip->dt.usb_icl_ua);
vote(chg->dc_icl_votable,
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
vote(chg->hvdcp_disable_votable_indirect, DEFAULT_VOTER,
@@ -1352,6 +1414,18 @@ static int smb2_init_hw(struct smb2 *chip)
vote(chg->hvdcp_enable_votable, MICRO_USB_VOTER,
chg->micro_usb_mode, 0);
+ /*
+ * AICL configuration:
+ * start from min and AICL ADC disable
+ */
+ rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
+ USBIN_AICL_START_AT_MAX_BIT
+ | USBIN_AICL_ADC_EN_BIT, 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc);
+ return rc;
+ }
+
/* Configure charge enable for software control; active high */
rc = smblib_masked_write(chg, CHGR_CFG2_REG,
CHG_EN_POLARITY_BIT |
@@ -1515,7 +1589,7 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
-static int smb2_setup_wa_flags(struct smb2 *chip)
+static int smb2_chg_config_init(struct smb2 *chip)
{
struct smb_charger *chg = &chip->chg;
struct pmic_revid_data *pmic_rev_id;
@@ -1540,14 +1614,32 @@ static int smb2_setup_wa_flags(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;
if (pmic_rev_id->rev4 == PMI8998_V2P0_REV4) /* PMI rev 2.0 */
chg->wa_flags |= TYPEC_CC2_REMOVAL_WA_BIT;
+ chg->chg_freq.freq_5V = 600;
+ chg->chg_freq.freq_6V_8V = 800;
+ chg->chg_freq.freq_9V = 1000;
+ chg->chg_freq.freq_12V = 1200;
+ chg->chg_freq.freq_removal = 1000;
+ chg->chg_freq.freq_below_otg_threshold = 2000;
+ 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;
+ chg->chg_freq.freq_5V = 600;
+ chg->chg_freq.freq_6V_8V = 800;
+ chg->chg_freq.freq_9V = 1050;
+ chg->chg_freq.freq_12V = 1200;
+ chg->chg_freq.freq_removal = 1050;
+ chg->chg_freq.freq_below_otg_threshold = 1600;
+ chg->chg_freq.freq_above_otg_threshold = 800;
break;
default:
pr_err("PMIC subtype %d not supported\n",
@@ -1584,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},
@@ -1805,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,
@@ -1815,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);
@@ -1928,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);
@@ -1936,10 +2023,10 @@ static int smb2_probe(struct platform_device *pdev)
return -EINVAL;
}
- rc = smb2_setup_wa_flags(chip);
+ rc = smb2_chg_config_init(chip);
if (rc < 0) {
if (rc != -EPROBE_DEFER)
- pr_err("Couldn't setup wa flags rc=%d\n", rc);
+ pr_err("Couldn't setup chg_config rc=%d\n", rc);
return rc;
}
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 3e939c5ffba1..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"
@@ -39,7 +40,7 @@
static bool is_secure(struct smb_charger *chg, int addr)
{
- if (addr == SHIP_MODE_REG)
+ if (addr == SHIP_MODE_REG || addr == FREQ_CLK_DIV_REG)
return true;
/* assume everything above 0xA0 is secure */
return (bool)((addr & 0xFF) >= 0xA0);
@@ -151,6 +152,44 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
return 0;
}
+int smblib_icl_override(struct smb_charger *chg, bool override)
+{
+ int rc;
+ bool override_status;
+ u8 stat;
+ u16 reg;
+
+ 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 reg=%x rc=%d\n", reg, rc);
+ return rc;
+ }
+ override_status = (bool)(stat & ICL_OVERRIDE_LATCH_BIT);
+
+ if (override != override_status) {
+ rc = smblib_masked_write(chg, CMD_APSD_REG,
+ ICL_OVERRIDE_BIT, ICL_OVERRIDE_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
/********************
* REGISTER GETTERS *
********************/
@@ -193,34 +232,6 @@ int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend)
return rc;
}
-#define FSW_600HZ_FOR_5V 600
-#define FSW_800HZ_FOR_6V_8V 800
-#define FSW_1MHZ_FOR_REMOVAL 1000
-#define FSW_1MHZ_FOR_9V 1000
-#define FSW_1P2MHZ_FOR_12V 1200
-static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
-{
- union power_supply_propval pval = {0, };
- int rc = 0;
-
- rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
- if (rc < 0)
- dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
-
- if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
- pval.intval = fsw_khz;
- rc = power_supply_set_property(chg->pl.psy,
- POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
- if (rc < 0) {
- dev_err(chg->dev,
- "Could not set parallel buck_freq rc=%d\n", rc);
- return rc;
- }
- }
-
- return rc;
-}
-
struct apsd_result {
const char * const name;
const u8 bit;
@@ -320,11 +331,62 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
return result;
}
-
/********************
* REGISTER SETTERS *
********************/
+static int chg_freq_list[] = {
+ 9600, 9600, 6400, 4800, 3800, 3200, 2700, 2400, 2100, 1900, 1700,
+ 1600, 1500, 1400, 1300, 1200,
+};
+
+int smblib_set_chg_freq(struct smb_chg_param *param,
+ int val_u, u8 *val_raw)
+{
+ u8 i;
+
+ if (val_u > param->max_u || val_u < param->min_u)
+ return -EINVAL;
+
+ /* Charger FSW is the configured freqency / 2 */
+ val_u *= 2;
+ for (i = 0; i < ARRAY_SIZE(chg_freq_list); i++) {
+ if (chg_freq_list[i] == val_u)
+ break;
+ }
+ if (i == ARRAY_SIZE(chg_freq_list)) {
+ pr_err("Invalid frequency %d Hz\n", val_u / 2);
+ return -EINVAL;
+ }
+
+ *val_raw = i;
+
+ return 0;
+}
+
+static int smblib_set_opt_freq_buck(struct smb_charger *chg, int fsw_khz)
+{
+ union power_supply_propval pval = {0, };
+ int rc = 0;
+
+ rc = smblib_set_charge_param(chg, &chg->param.freq_buck, fsw_khz);
+ if (rc < 0)
+ dev_err(chg->dev, "Error in setting freq_buck rc=%d\n", rc);
+
+ if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
+ pval.intval = fsw_khz;
+ rc = power_supply_set_property(chg->pl.psy,
+ POWER_SUPPLY_PROP_BUCK_FREQ, &pval);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Could not set parallel buck_freq rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
int smblib_set_charge_param(struct smb_charger *chg,
struct smb_chg_param *param, int val_u)
{
@@ -417,13 +479,13 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg,
if (min_allowed_uv == MICRO_5V && max_allowed_uv == MICRO_5V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_5V;
- smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V);
+ smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
} else if (min_allowed_uv == MICRO_9V && max_allowed_uv == MICRO_9V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_9V;
- smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V);
+ smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_9V);
} else if (min_allowed_uv == MICRO_12V && max_allowed_uv == MICRO_12V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_12V;
- smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V);
+ smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_12V);
} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_9V) {
allowed_voltage = USBIN_ADAPTER_ALLOW_5V_TO_9V;
} else if (min_allowed_uv < MICRO_9V && max_allowed_uv <= MICRO_12V) {
@@ -567,6 +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_DELAY_HVDCP_VOTER, true, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -590,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)
@@ -612,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) {
@@ -619,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");
@@ -662,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)
{
@@ -686,39 +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 = (icl_ua < USBIN_25MA);
- u8 icl_options = 0;
- if (suspend)
- goto out;
- if (chg->usb_psy_desc.type != POWER_SUPPLY_TYPE_USB) {
- rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
- return rc;
- }
-
- 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) {
@@ -740,39 +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:
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
+ CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
if (rc < 0) {
- smblib_err(chg, "Couldn't set ICL opetions rc=%d\n", rc);
- return rc;
- }
-
- rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
- if (rc < 0) {
- smblib_err(chg, "Couldn't %s input rc=%d\n",
- suspend ? "suspend" : "resume", rc);
+ smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
return rc;
}
return rc;
}
-#define MICRO_250MA 250000
-static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua)
+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_set_charge_param(chg, &chg->param.otg_cl, otg_cl_ua);
+ rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0) {
- smblib_err(chg, "Couldn't set otg current limit rc=%d\n", 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);
+ 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;
}
@@ -955,22 +1058,33 @@ static int smblib_apsd_disable_vote_callback(struct votable *votable,
* VCONN REGULATOR *
* *****************/
+#define MAX_OTG_SS_TRIES 2
static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
u8 otg_stat, stat4;
- int rc = 0;
+ int rc = 0, i;
if (!chg->external_vconn) {
- rc = smblib_read(chg, OTG_STATUS_REG, &otg_stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
- return rc;
+ /*
+ * Hardware based OTG soft start should complete within 1ms, so
+ * wait for 2ms in the worst case.
+ */
+ for (i = 0; i < MAX_OTG_SS_TRIES; ++i) {
+ usleep_range(1000, 1100);
+ rc = smblib_read(chg, OTG_STATUS_REG, &otg_stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read OTG status rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (otg_stat & BOOST_SOFTSTART_DONE_BIT)
+ break;
}
- if ((otg_stat & OTG_STATE_MASK) != OTG_STATE_ENABLED) {
- smblib_err(chg, "Couldn't enable VCONN; OTG is not ready otg_stat=0x%02x\n",
- otg_stat);
+ if (!(otg_stat & BOOST_SOFTSTART_DONE_BIT)) {
+ smblib_err(chg, "Couldn't enable VCONN; OTG soft start failed\n");
return -EAGAIN;
}
}
@@ -985,6 +1099,7 @@ static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
return rc;
}
+ smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
@@ -1002,7 +1117,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int rc = 0;
- mutex_lock(&chg->otg_overcurrent_lock);
+ mutex_lock(&chg->otg_oc_lock);
if (chg->vconn_en)
goto unlock;
@@ -1011,7 +1126,7 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev)
chg->vconn_en = true;
unlock:
- mutex_unlock(&chg->otg_overcurrent_lock);
+ mutex_unlock(&chg->otg_oc_lock);
return rc;
}
@@ -1020,6 +1135,7 @@ static int _smblib_vconn_regulator_disable(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int rc = 0;
+ smblib_dbg(chg, PR_OTG, "disabling VCONN\n");
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_VALUE_BIT, 0);
if (rc < 0)
@@ -1033,7 +1149,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int rc = 0;
- mutex_lock(&chg->otg_overcurrent_lock);
+ mutex_lock(&chg->otg_oc_lock);
if (!chg->vconn_en)
goto unlock;
@@ -1042,7 +1158,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev)
chg->vconn_en = false;
unlock:
- mutex_unlock(&chg->otg_overcurrent_lock);
+ mutex_unlock(&chg->otg_oc_lock);
return rc;
}
@@ -1051,9 +1167,9 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int ret;
- mutex_lock(&chg->otg_overcurrent_lock);
+ mutex_lock(&chg->otg_oc_lock);
ret = chg->vconn_en;
- mutex_unlock(&chg->otg_overcurrent_lock);
+ mutex_unlock(&chg->otg_oc_lock);
return ret;
}
@@ -1061,14 +1177,12 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev)
* OTG REGULATOR *
*****************/
-#define MAX_SOFTSTART_TRIES 2
static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
- u8 stat;
- int rc = 0;
- int tries = MAX_SOFTSTART_TRIES;
+ int rc;
+ smblib_dbg(chg, PR_OTG, "halt 1 in 8 mode\n");
rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
ENG_BUCKBOOST_HALT1_8_MODE_BIT,
ENG_BUCKBOOST_HALT1_8_MODE_BIT);
@@ -1078,34 +1192,13 @@ static int _smblib_vbus_regulator_enable(struct regulator_dev *rdev)
return rc;
}
+ smblib_dbg(chg, PR_OTG, "enabling OTG\n");
rc = smblib_write(chg, CMD_OTG_REG, OTG_EN_BIT);
if (rc < 0) {
smblib_err(chg, "Couldn't enable OTG regulator rc=%d\n", rc);
return rc;
}
- /* waiting for boost readiness, usually ~1ms, 2ms in worst case */
- do {
- usleep_range(1000, 1100);
-
- rc = smblib_read(chg, OTG_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read OTG_STATUS_REG rc=%d\n",
- rc);
- return rc;
- }
- if (stat & BOOST_SOFTSTART_DONE_BIT) {
- smblib_otg_cl_config(chg, chg->otg_cl_ua);
- break;
- }
- } while (--tries);
-
- if (tries == 0) {
- smblib_err(chg, "Timeout waiting for boost softstart rc=%d\n",
- rc);
- return -ETIMEDOUT;
- }
-
return rc;
}
@@ -1114,7 +1207,7 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int rc = 0;
- mutex_lock(&chg->otg_overcurrent_lock);
+ mutex_lock(&chg->otg_oc_lock);
if (chg->otg_en)
goto unlock;
@@ -1123,7 +1216,7 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
chg->otg_en = true;
unlock:
- mutex_unlock(&chg->otg_overcurrent_lock);
+ mutex_unlock(&chg->otg_oc_lock);
return rc;
}
@@ -1131,32 +1224,23 @@ static int _smblib_vbus_regulator_disable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
int rc;
- u8 stat;
- if (!chg->external_vconn) {
- rc = smblib_read(chg, RID_CC_CONTROL_7_0_REG, &stat);
+ if (!chg->external_vconn && chg->vconn_en) {
+ smblib_dbg(chg, PR_OTG, "Killing VCONN before disabling OTG\n");
+ rc = _smblib_vconn_regulator_disable(rdev);
if (rc < 0)
- smblib_err(chg, "Couldn't read RID_CC_CONTROL_7_0 rc=%d\n",
- rc);
-
- /* check if VCONN is enabled on either CC pin */
- if (stat & VCONN_EN_CC_MASK) {
- smblib_dbg(chg, PR_MISC, "Killing VCONN before disabling OTG\n");
- rc = _smblib_vconn_regulator_disable(rdev);
- if (rc < 0)
- smblib_err(chg, "Couldn't disable VCONN rc=%d\n",
- rc);
- }
+ smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
}
+ smblib_dbg(chg, PR_OTG, "disabling OTG\n");
rc = smblib_write(chg, CMD_OTG_REG, 0);
if (rc < 0) {
smblib_err(chg, "Couldn't disable OTG regulator rc=%d\n", rc);
return rc;
}
- smblib_otg_cl_config(chg, MICRO_250MA);
-
+ smblib_dbg(chg, PR_OTG, "start 1 in 8 mode\n");
+ rc = smblib_write(chg, CMD_OTG_REG, 0);
rc = smblib_masked_write(chg, OTG_ENG_OTG_CFG_REG,
ENG_BUCKBOOST_HALT1_8_MODE_BIT, 0);
if (rc < 0) {
@@ -1172,7 +1256,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int rc = 0;
- mutex_lock(&chg->otg_overcurrent_lock);
+ mutex_lock(&chg->otg_oc_lock);
if (!chg->otg_en)
goto unlock;
@@ -1181,7 +1265,7 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
chg->otg_en = false;
unlock:
- mutex_unlock(&chg->otg_overcurrent_lock);
+ mutex_unlock(&chg->otg_oc_lock);
return rc;
}
@@ -1190,9 +1274,9 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
struct smb_charger *chg = rdev_get_drvdata(rdev);
int ret;
- mutex_lock(&chg->otg_overcurrent_lock);
+ mutex_lock(&chg->otg_oc_lock);
ret = chg->otg_en;
- mutex_unlock(&chg->otg_overcurrent_lock);
+ mutex_unlock(&chg->otg_oc_lock);
return ret;
}
@@ -1203,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;
}
@@ -1501,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);
@@ -1647,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;
}
@@ -1926,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)
{
@@ -1955,6 +2074,40 @@ int smblib_get_pe_start(struct smb_charger *chg,
return 0;
}
+int smblib_get_prop_die_health(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ int rc;
+ u8 stat;
+
+ rc = smblib_read(chg, TEMP_RANGE_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TEMP_RANGE_STATUS_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* 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;
+ }
+
+ return 0;
+}
+
/*******************
* USB PSY SETTERS *
* *****************/
@@ -1982,17 +2135,15 @@ int smblib_set_prop_usb_current_max(struct smb_charger *chg,
true, val->intval);
} else if (chg->system_suspend_supported) {
if (val->intval <= USBIN_25MA)
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
- true, val->intval);
+ rc = vote(chg->usb_icl_votable,
+ PD_SUSPEND_SUPPORTED_VOTER, true, val->intval);
else
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
- false, 0);
+ rc = vote(chg->usb_icl_votable,
+ PD_SUSPEND_SUPPORTED_VOTER, false, 0);
}
return rc;
}
-#define FSW_2MHZ 2000
-#define FSW_800KHZ_RESET 800
int smblib_set_prop_boost_current(struct smb_charger *chg,
const union power_supply_propval *val)
{
@@ -2000,7 +2151,8 @@ int smblib_set_prop_boost_current(struct smb_charger *chg,
rc = smblib_set_charge_param(chg, &chg->param.freq_boost,
val->intval <= chg->boost_threshold_ua ?
- FSW_2MHZ : FSW_800KHZ_RESET);
+ chg->chg_freq.freq_below_otg_threshold :
+ chg->chg_freq.freq_above_otg_threshold);
if (rc < 0) {
dev_err(chg->dev, "Error in setting freq_boost rc=%d\n", rc);
return rc;
@@ -2124,7 +2276,11 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
"Couldn't enable vconn on CC line rc=%d\n", rc);
return rc;
}
-
+ /*
+ * Enforce 500mA for PD until the real vote comes in later.
+ * It is guaranteed that pd_active is set prior to
+ * pd_current_max
+ */
rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
if (rc < 0) {
smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
@@ -2132,50 +2288,34 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
return 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 vote for USB ICL rc=%d\n",
- rc);
- return rc;
- }
-
- rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- USBIN_MODE_CHG_BIT, USBIN_MODE_CHG_BIT);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg,
- "Couldn't change USB mode rc=%d\n", rc);
- return rc;
- }
+ "Couldn't un-vote DCP from USB ICL rc=%d\n",
+ rc);
- rc = smblib_masked_write(chg, CMD_APSD_REG,
- ICL_OVERRIDE_BIT, ICL_OVERRIDE_BIT);
- if (rc < 0) {
+ /* 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 override APSD rc=%d\n", rc);
- return rc;
- }
- } else {
- rc = vote(chg->usb_icl_votable, DCP_VOTER, true,
- chg->dcp_icl_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
+ "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n",
rc);
- return rc;
- }
- rc = smblib_masked_write(chg, CMD_APSD_REG,
- ICL_OVERRIDE_BIT, 0);
+ /* remove USB_PSY_VOTER */
+ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
if (rc < 0) {
- smblib_err(chg,
- "Couldn't override APSD rc=%d\n", rc);
+ smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
return rc;
}
- rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- USBIN_MODE_CHG_BIT, 0);
+ /* 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 change USB mode rc=%d\n", rc);
+ "Couldn't unvote PL_DELAY_HVDCP_VOTER rc=%d\n",
+ rc);
return rc;
}
}
@@ -2217,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)
{
@@ -2425,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 *
************************/
@@ -2467,50 +2723,9 @@ irqreturn_t smblib_handle_otg_overcurrent(int irq, void *data)
return IRQ_HANDLED;
}
- if (!(stat & OTG_OVERCURRENT_RT_STS_BIT))
- return IRQ_HANDLED;
-
- smblib_err(chg, "over-current detected on VBUS\n");
- if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
- return IRQ_HANDLED;
+ if (stat & OTG_OVERCURRENT_RT_STS_BIT)
+ schedule_work(&chg->otg_oc_work);
- mutex_lock(&chg->otg_overcurrent_lock);
- if (!chg->external_vconn && chg->vconn_en) {
- rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
- if (rc < 0)
- smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
- }
-
- rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
- if (rc < 0)
- smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
-
- /*
- * VBUS must be disabled after OC to be ready for the next insertion.
- * If the maximum number of attempts have been reached then don't try
- * to re-enable.
- */
- if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
- smblib_err(chg, "OTG failed to enable after %d attempts\n",
- chg->otg_attempts - 1);
- goto unlock;
- }
-
- /* allow the attached device to discharge */
- msleep(250);
-
- rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
-
- if (!chg->external_vconn && chg->vconn_en) {
- rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
- }
-
-unlock:
- mutex_unlock(&chg->otg_overcurrent_lock);
return IRQ_HANDLED;
}
@@ -2616,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;
@@ -2632,7 +2862,8 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
smblib_set_opt_freq_buck(chg,
- vbus_rising ? FSW_600HZ_FOR_5V : FSW_1MHZ_FOR_REMOVAL);
+ vbus_rising ? chg->chg_freq.freq_5V :
+ chg->chg_freq.freq_removal);
/* fetch the DPDM regulator */
if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
@@ -2655,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");
@@ -2686,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;
}
@@ -2728,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) {
@@ -2738,16 +2967,20 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
switch (stat & QC_2P0_STATUS_MASK) {
case QC_5V_BIT:
- smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V);
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_5V);
break;
case QC_9V_BIT:
- smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V);
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_9V);
break;
case QC_12V_BIT:
- smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V);
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_12V);
break;
default:
- smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_REMOVAL);
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_removal);
break;
}
}
@@ -2762,24 +2995,20 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg)
pulses = (stat & QC_PULSE_COUNT_MASK);
if (pulses < QC3_PULSES_FOR_6V)
- smblib_set_opt_freq_buck(chg, FSW_600HZ_FOR_5V);
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_5V);
else if (pulses < QC3_PULSES_FOR_9V)
- smblib_set_opt_freq_buck(chg, FSW_800HZ_FOR_6V_8V);
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_6V_8V);
else if (pulses < QC3_PULSES_FOR_12V)
- smblib_set_opt_freq_buck(chg, FSW_1MHZ_FOR_9V);
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_9V);
else
- smblib_set_opt_freq_buck(chg, FSW_1P2MHZ_FOR_12V);
-
+ smblib_set_opt_freq_buck(chg,
+ chg->chg_freq.freq_12V);
}
}
-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)
@@ -2802,6 +3031,9 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
if (chg->mode == PARALLEL_MASTER)
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_DELAY_HVDCP_VOTER, false, 0);
+
/* the APSD done handler will set the USB supply type */
apsd_result = smblib_get_apsd_result(chg);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
@@ -2811,6 +3043,8 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
bool rising, bool qc_charger)
{
+ const struct apsd_result *apsd_result = smblib_update_usb_type(chg);
+
/* Hold off PD only until hvdcp 2.0 detection timeout */
if (rising) {
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
@@ -2818,6 +3052,24 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
if (get_effective_result(chg->pd_disallowed_votable_indirect))
/* could be a legacy cable, try doing hvdcp */
try_rerun_apsd_for_hvdcp(chg);
+
+ /*
+ * HVDCP detection timeout done
+ * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
+ */
+ if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
+ /* enforce DCP ICL if specified */
+ vote(chg->usb_icl_votable, DCP_VOTER,
+ chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
+ /*
+ * If adapter is not QC2.0/QC3.0 remove vote for parallel
+ * disable.
+ * Otherwise if adapter is QC2.0/QC3.0 wait for authentication
+ * to complete.
+ */
+ if (!qc_charger)
+ vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER,
+ false, 0);
}
smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
@@ -2854,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)
@@ -2898,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));
@@ -2911,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;
}
@@ -2943,12 +3203,26 @@ static void typec_source_removal(struct smb_charger *chg)
/* clear USB ICL vote for PD_VOTER */
rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
if (rc < 0)
- smblib_err(chg, "Couldn't un-vote for USB ICL rc=%d\n", rc);
+ smblib_err(chg, "Couldn't un-vote PD from USB ICL rc=%d\n", rc);
/* clear USB ICL vote for USB_PSY_VOTER */
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);
+ smblib_err(chg,
+ "Couldn't un-vote USB_PSY from 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 void typec_source_insertion(struct smb_charger *chg)
@@ -2966,7 +3240,8 @@ static void typec_sink_insertion(struct smb_charger *chg)
static void typec_sink_removal(struct smb_charger *chg)
{
- smblib_set_charge_param(chg, &chg->param.freq_boost, FSW_800KHZ_RESET);
+ smblib_set_charge_param(chg, &chg->param.freq_boost,
+ chg->chg_freq.freq_above_otg_threshold);
chg->boost_current_ua = 0;
}
@@ -2976,6 +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_DELAY_HVDCP_VOTER, true, 0);
/* reset votes from vbus_cc_short */
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
@@ -2990,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,
@@ -3094,41 +3371,6 @@ irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg)
return IRQ_HANDLED;
}
-static void smblib_handle_vconn_overcurrent(struct smb_charger *chg)
-{
- int rc;
-
- smblib_err(chg, "over-current detected on VCONN\n");
- if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
- return;
-
- mutex_lock(&chg->otg_overcurrent_lock);
- rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
- if (rc < 0)
- smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
-
- /*
- * VCONN must be disabled after OC to be ready for the next insertion.
- * If the maximum number of attempts have been reached then don't try
- * to re-enable.
- */
- if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
- smblib_err(chg, "VCONN failed to enable after %d attempts\n",
- chg->vconn_attempts - 1);
- goto unlock;
- }
-
- /* allow the attached device to discharge */
- msleep(250);
-
- rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
-
-unlock:
- mutex_unlock(&chg->otg_overcurrent_lock);
-}
-
irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
@@ -3168,7 +3410,7 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
irq_data->name);
if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT)
- smblib_handle_vconn_overcurrent(chg);
+ schedule_work(&chg->vconn_oc_work);
power_supply_changed(chg->usb_psy);
smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4);
@@ -3213,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;
@@ -3362,6 +3604,190 @@ rerun:
schedule_work(&chg->rdstd_cc2_detach_work);
}
+static void smblib_otg_oc_exit(struct smb_charger *chg, bool success)
+{
+ int rc;
+
+ chg->otg_attempts = 0;
+ if (!success) {
+ smblib_err(chg, "OTG soft start failed\n");
+ chg->otg_en = false;
+ }
+
+ smblib_dbg(chg, PR_OTG, "enabling VBUS < 1V check\n");
+ rc = smblib_masked_write(chg, OTG_CFG_REG,
+ QUICKSTART_OTG_FASTROLESWAP_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable VBUS < 1V check rc=%d\n", rc);
+
+ if (!chg->external_vconn && chg->vconn_en) {
+ chg->vconn_attempts = 0;
+ if (success) {
+ rc = _smblib_vconn_regulator_enable(
+ chg->vconn_vreg->rdev);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable VCONN rc=%d\n",
+ rc);
+ } else {
+ chg->vconn_en = false;
+ }
+ }
+}
+
+#define MAX_OC_FALLING_TRIES 10
+static void smblib_otg_oc_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ otg_oc_work);
+ int rc, i;
+ u8 stat;
+
+ if (!chg->vbus_vreg || !chg->vbus_vreg->rdev)
+ return;
+
+ smblib_err(chg, "over-current detected on VBUS\n");
+ mutex_lock(&chg->otg_oc_lock);
+ if (!chg->otg_en)
+ goto unlock;
+
+ smblib_dbg(chg, PR_OTG, "disabling VBUS < 1V check\n");
+ smblib_masked_write(chg, OTG_CFG_REG,
+ QUICKSTART_OTG_FASTROLESWAP_BIT,
+ QUICKSTART_OTG_FASTROLESWAP_BIT);
+
+ /*
+ * If 500ms has passed and another over-current interrupt has not
+ * triggered then it is likely that the software based soft start was
+ * successful and the VBUS < 1V restriction should be re-enabled.
+ */
+ schedule_delayed_work(&chg->otg_ss_done_work, msecs_to_jiffies(500));
+
+ rc = _smblib_vbus_regulator_disable(chg->vbus_vreg->rdev);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't disable VBUS rc=%d\n", rc);
+ goto unlock;
+ }
+
+ if (++chg->otg_attempts > OTG_MAX_ATTEMPTS) {
+ cancel_delayed_work_sync(&chg->otg_ss_done_work);
+ smblib_err(chg, "OTG failed to enable after %d attempts\n",
+ chg->otg_attempts - 1);
+ smblib_otg_oc_exit(chg, false);
+ goto unlock;
+ }
+
+ /*
+ * The real time status should go low within 10ms. Poll every 1-2ms to
+ * minimize the delay when re-enabling OTG.
+ */
+ for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
+ usleep_range(1000, 2000);
+ rc = smblib_read(chg, OTG_BASE + INT_RT_STS_OFFSET, &stat);
+ if (rc >= 0 && !(stat & OTG_OVERCURRENT_RT_STS_BIT))
+ break;
+ }
+
+ if (i >= MAX_OC_FALLING_TRIES) {
+ cancel_delayed_work_sync(&chg->otg_ss_done_work);
+ smblib_err(chg, "OTG OC did not fall after %dms\n",
+ 2 * MAX_OC_FALLING_TRIES);
+ smblib_otg_oc_exit(chg, false);
+ goto unlock;
+ }
+
+ smblib_dbg(chg, PR_OTG, "OTG OC fell after %dms\n", 2 * i + 1);
+ rc = _smblib_vbus_regulator_enable(chg->vbus_vreg->rdev);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't enable VBUS rc=%d\n", rc);
+ goto unlock;
+ }
+
+unlock:
+ mutex_unlock(&chg->otg_oc_lock);
+}
+
+static void smblib_vconn_oc_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ vconn_oc_work);
+ int rc, i;
+ u8 stat;
+
+ smblib_err(chg, "over-current detected on VCONN\n");
+ if (!chg->vconn_vreg || !chg->vconn_vreg->rdev)
+ return;
+
+ mutex_lock(&chg->otg_oc_lock);
+ rc = _smblib_vconn_regulator_disable(chg->vconn_vreg->rdev);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't disable VCONN rc=%d\n", rc);
+ goto unlock;
+ }
+
+ if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
+ smblib_err(chg, "VCONN failed to enable after %d attempts\n",
+ chg->otg_attempts - 1);
+ chg->vconn_en = false;
+ chg->vconn_attempts = 0;
+ goto unlock;
+ }
+
+ /*
+ * The real time status should go low within 10ms. Poll every 1-2ms to
+ * minimize the delay when re-enabling OTG.
+ */
+ for (i = 0; i < MAX_OC_FALLING_TRIES; ++i) {
+ usleep_range(1000, 2000);
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ if (rc >= 0 && !(stat & TYPEC_VCONN_OVERCURR_STATUS_BIT))
+ break;
+ }
+
+ if (i >= MAX_OC_FALLING_TRIES) {
+ smblib_err(chg, "VCONN OC did not fall after %dms\n",
+ 2 * MAX_OC_FALLING_TRIES);
+ chg->vconn_en = false;
+ chg->vconn_attempts = 0;
+ goto unlock;
+ }
+
+ smblib_dbg(chg, PR_OTG, "VCONN OC fell after %dms\n", 2 * i + 1);
+ if (++chg->vconn_attempts > VCONN_MAX_ATTEMPTS) {
+ smblib_err(chg, "VCONN failed to enable after %d attempts\n",
+ chg->vconn_attempts - 1);
+ chg->vconn_en = false;
+ goto unlock;
+ }
+
+ rc = _smblib_vconn_regulator_enable(chg->vconn_vreg->rdev);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't enable VCONN rc=%d\n", rc);
+ goto unlock;
+ }
+
+unlock:
+ mutex_unlock(&chg->otg_oc_lock);
+}
+
+static void smblib_otg_ss_done_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ otg_ss_done_work.work);
+ int rc;
+ bool success = false;
+ u8 stat;
+
+ mutex_lock(&chg->otg_oc_lock);
+ rc = smblib_read(chg, OTG_STATUS_REG, &stat);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't read OTG status rc=%d\n", rc);
+ else if (stat & BOOST_SOFTSTART_DONE_BIT)
+ success = true;
+
+ smblib_otg_oc_exit(chg, success);
+ mutex_unlock(&chg->otg_oc_lock);
+}
+
static int smblib_create_votables(struct smb_charger *chg)
{
int rc = 0;
@@ -3384,14 +3810,7 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
vote(chg->pl_disable_votable, PL_INDIRECT_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,
@@ -3401,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);
@@ -3498,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)
@@ -3541,16 +3948,21 @@ int smblib_init(struct smb_charger *chg)
int rc = 0;
mutex_init(&chg->write_lock);
- mutex_init(&chg->otg_overcurrent_lock);
+ mutex_init(&chg->otg_oc_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
+ INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work);
+ INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work);
+ INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
chg->fake_capacity = -EINVAL;
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 b3fce23c6508..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>
@@ -24,12 +25,14 @@ enum print_reason {
PR_REGISTER = BIT(1),
PR_MISC = BIT(2),
PR_PARALLEL = BIT(3),
+ PR_OTG = BIT(4),
};
#define DEFAULT_VOTER "DEFAULT_VOTER"
#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"
@@ -38,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"
@@ -51,6 +53,9 @@ enum print_reason {
#define HVDCP_INDIRECT_VOTER "HVDCP_INDIRECT_VOTER"
#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_DELAY_HVDCP_VOTER "PL_DELAY_HVDCP_VOTER"
+#define CTM_VOTER "CTM_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -74,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,
@@ -104,6 +160,16 @@ struct smb_chg_param {
u8 *val_raw);
};
+struct smb_chg_freq {
+ unsigned int freq_5V;
+ unsigned int freq_6V_8V;
+ unsigned int freq_9V;
+ unsigned int freq_12V;
+ unsigned int freq_removal;
+ unsigned int freq_below_otg_threshold;
+ unsigned int freq_above_otg_threshold;
+};
+
struct smb_params {
struct smb_chg_param fcc;
struct smb_chg_param fv;
@@ -135,6 +201,9 @@ struct smb_iio {
struct iio_channel *usbin_i_chan;
struct iio_channel *usbin_v_chan;
struct iio_channel *batt_i_chan;
+ struct iio_channel *connector_temp_thr1_chan;
+ struct iio_channel *connector_temp_thr2_chan;
+ struct iio_channel *connector_temp_thr3_chan;
};
struct reg_info {
@@ -149,16 +218,19 @@ 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;
struct mutex ps_change_lock;
- struct mutex otg_overcurrent_lock;
+ struct mutex otg_oc_lock;
/* power supplies */
struct power_supply *batt_psy;
@@ -180,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;
@@ -204,6 +274,9 @@ struct smb_charger {
struct delayed_work ps_change_timeout_work;
struct delayed_work step_soc_req_work;
struct delayed_work clear_hdc_work;
+ struct work_struct otg_oc_work;
+ struct work_struct vconn_oc_work;
+ struct delayed_work otg_ss_done_work;
/* cached status */
int voltage_min_uv;
@@ -214,7 +287,6 @@ struct smb_charger {
int system_temp_level;
int thermal_levels;
int *thermal_mitigation;
- int otg_cl_ua;
int dcp_icl_ua;
int fake_capacity;
bool step_chg_enabled;
@@ -223,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;
@@ -236,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);
@@ -258,6 +336,8 @@ int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
u8 val_raw);
int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
int val_u, u8 *val_raw);
+int smblib_set_chg_freq(struct smb_chg_param *param,
+ int val_u, u8 *val_raw);
int smblib_vbus_regulator_enable(struct regulator_dev *rdev);
int smblib_vbus_regulator_disable(struct regulator_dev *rdev);
@@ -276,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);
@@ -352,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,
@@ -360,6 +443,8 @@ 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_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);
int smblib_set_prop_usb_current_max(struct smb_charger *chg,
@@ -384,6 +469,8 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg);
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 5f74e27c7978..e005a27e8dd9 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -21,6 +21,7 @@
#define USBIN_BASE 0x1300
#define DCIN_BASE 0x1400
#define MISC_BASE 0x1600
+#define CHGR_FREQ_BASE 0x1900
#define PERPH_TYPE_OFFSET 0x04
#define TYPE_MASK GENMASK(7, 0)
@@ -366,7 +367,9 @@ enum {
#define OTG_CURRENT_LIMIT_MASK GENMASK(2, 0)
#define OTG_CFG_REG (OTG_BASE + 0x53)
-#define OTG_RESERVED_MASK GENMASK(7, 4)
+#define OTG_RESERVED_MASK GENMASK(7, 6)
+#define DIS_OTG_ON_TLIM_BIT BIT(5)
+#define QUICKSTART_OTG_FASTROLESWAP_BIT BIT(4)
#define INCREASE_DFP_TIME_BIT BIT(3)
#define ENABLE_OTG_IN_DEBUG_MODE_BIT BIT(2)
#define OTG_EN_SRC_CFG_BIT BIT(1)
@@ -793,6 +796,10 @@ enum {
ZIN_ICL_HV_MAX_MV = 11000,
};
+#define DC_ENG_SSUPPLY_CFG2_REG (DCIN_BASE + 0xC1)
+#define ENG_SSUPPLY_IVREF_OTG_SS_MASK GENMASK(2, 0)
+#define OTG_SS_SLOW 0x3
+
#define DC_ENG_SSUPPLY_CFG3_REG (DCIN_BASE + 0xC2)
#define ENG_SSUPPLY_HI_CAP_BIT BIT(6)
#define ENG_SSUPPLY_HI_RES_BIT BIT(5)
@@ -817,6 +824,7 @@ enum {
#define TEMP_RANGE_STATUS_7_BIT BIT(7)
#define THERM_REG_ACTIVE_BIT BIT(6)
#define TLIM_BIT BIT(5)
+#define TEMP_RANGE_MASK GENMASK(4, 1)
#define ALERT_LEVEL_BIT BIT(4)
#define TEMP_ABOVE_RANGE_BIT BIT(3)
#define TEMP_WITHIN_RANGE_BIT BIT(2)
@@ -1007,4 +1015,7 @@ enum {
#define CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG (MISC_BASE + 0xA0)
#define CFG_BUCKBOOST_FREQ_SELECT_BOOST_REG (MISC_BASE + 0xA1)
+/* CHGR FREQ Peripheral registers */
+#define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50)
+
#endif /* __SMB2_CHARGER_REG_H */
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index 0c2943c7f2df..d0cf37b0613a 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -461,7 +461,7 @@ struct smb1351_charger {
int parallel_pin_polarity_setting;
bool parallel_charger;
- bool parallel_charger_present;
+ bool parallel_charger_suspended;
bool bms_controlled_charging;
bool apsd_rerun;
bool usbin_ov;
@@ -873,9 +873,9 @@ static int smb1351_regulator_init(struct smb1351_charger *chip)
chip->otg_vreg.rdesc.owner = THIS_MODULE;
chip->otg_vreg.rdesc.type = REGULATOR_VOLTAGE;
chip->otg_vreg.rdesc.ops = &smb1351_chg_otg_reg_ops;
- chip->otg_vreg.rdesc.name =
+ chip->otg_vreg.rdesc.name =
chip->dev->of_node->name;
- chip->otg_vreg.rdesc.of_match =
+ chip->otg_vreg.rdesc.of_match =
chip->dev->of_node->name;
cfg.dev = chip->dev;
@@ -1409,34 +1409,27 @@ static int smb1351_battery_get_property(struct power_supply *psy,
static enum power_supply_property smb1351_parallel_properties[] = {
POWER_SUPPLY_PROP_CHARGING_ENABLED,
POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PARALLEL_MODE,
};
-static int smb1351_parallel_set_chg_present(struct smb1351_charger *chip,
- int present)
+static int smb1351_parallel_set_chg_suspend(struct smb1351_charger *chip,
+ int suspend)
{
int rc;
u8 reg, mask = 0;
- if (present == chip->parallel_charger_present) {
- pr_debug("present %d -> %d, skipping\n",
- chip->parallel_charger_present, present);
+ if (chip->parallel_charger_suspended == suspend) {
+ pr_debug("Skip same state request suspended = %d suspend=%d\n",
+ chip->parallel_charger_suspended, !suspend);
return 0;
}
- if (present) {
- /* Check if SMB1351 is present */
- rc = smb1351_read_reg(chip, CHG_REVISION_REG, &reg);
- if (rc) {
- pr_debug("Failed to detect smb1351-parallel-charger, may be absent\n");
- return -ENODEV;
- }
-
+ if (!suspend) {
rc = smb_chip_get_version(chip);
if (rc) {
pr_err("Couldn't get version rc = %d\n", rc);
@@ -1476,6 +1469,26 @@ static int smb1351_parallel_set_chg_present(struct smb1351_charger *chip,
}
}
+ /* control USB suspend via command bits */
+ rc = smb1351_masked_write(chip, VARIOUS_FUNC_REG,
+ APSD_EN_BIT | SUSPEND_MODE_CTRL_BIT,
+ SUSPEND_MODE_CTRL_BY_I2C);
+ if (rc) {
+ pr_err("Couldn't set USB suspend rc=%d\n", rc);
+ return rc;
+ }
+
+ /*
+ * When present is being set force USB suspend, start charging
+ * only when POWER_SUPPLY_PROP_CURRENT_MAX is set.
+ */
+ rc = smb1351_usb_suspend(chip, CURRENT, true);
+ if (rc) {
+ pr_err("failed to suspend rc=%d\n", rc);
+ return rc;
+ }
+ chip->usb_psy_ma = SUSPEND_CURRENT_MA;
+
/* set chg en by pin active low */
reg = chip->parallel_pin_polarity_setting | USBCS_CTRL_BY_I2C;
rc = smb1351_masked_write(chip, CHG_PIN_EN_CTRL_REG,
@@ -1485,15 +1498,6 @@ static int smb1351_parallel_set_chg_present(struct smb1351_charger *chip,
return rc;
}
- /* control USB suspend via command bits */
- rc = smb1351_masked_write(chip, VARIOUS_FUNC_REG,
- SUSPEND_MODE_CTRL_BIT,
- SUSPEND_MODE_CTRL_BY_I2C);
- if (rc) {
- pr_err("Couldn't set USB suspend rc=%d\n", rc);
- return rc;
- }
-
/*
* setup USB 2.0/3.0 detection and USB 500/100
* command polarity
@@ -1508,23 +1512,21 @@ static int smb1351_parallel_set_chg_present(struct smb1351_charger *chip,
return rc;
}
- /* set fast charging current limit */
- chip->target_fastchg_current_max_ma = SMB1351_CHG_FAST_MIN_MA;
rc = smb1351_fastchg_current_set(chip,
chip->target_fastchg_current_max_ma);
if (rc) {
pr_err("Couldn't set fastchg current rc=%d\n", rc);
return rc;
}
- }
+ chip->parallel_charger_suspended = false;
+ } else {
+ rc = smb1351_usb_suspend(chip, CURRENT, true);
+ if (rc)
+ pr_debug("failed to suspend rc=%d\n", rc);
- chip->parallel_charger_present = present;
- /*
- * When present is being set force USB suspend, start charging
- * only when POWER_SUPPLY_PROP_CURRENT_MAX is set.
- */
- chip->usb_psy_ma = SUSPEND_CURRENT_MA;
- smb1351_usb_suspend(chip, CURRENT, true);
+ chip->usb_psy_ma = SUSPEND_CURRENT_MA;
+ chip->parallel_charger_suspended = true;
+ }
return 0;
}
@@ -1564,6 +1566,31 @@ static bool smb1351_is_input_current_limited(struct smb1351_charger *chip)
return !!(reg & IRQ_IC_LIMIT_STATUS_BIT);
}
+static bool smb1351_is_usb_present(struct smb1351_charger *chip)
+{
+ int rc;
+ union power_supply_propval val = {0, };
+
+ if (!chip->usb_psy)
+ chip->usb_psy = power_supply_get_by_name("usb");
+ if (!chip->usb_psy) {
+ pr_err("USB psy not found\n");
+ return false;
+ }
+
+ rc = power_supply_get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_ONLINE, &val);
+ if (rc < 0) {
+ pr_err("Failed to get present property rc=%d\n", rc);
+ return false;
+ }
+
+ if (val.intval)
+ return true;
+
+ return false;
+}
+
static int smb1351_parallel_set_property(struct power_supply *psy,
enum power_supply_property prop,
const union power_supply_propval *val)
@@ -1577,38 +1604,30 @@ static int smb1351_parallel_set_property(struct power_supply *psy,
*CHG EN is controlled by pin in the parallel charging.
*Use suspend if disable charging by command.
*/
- if (chip->parallel_charger_present)
+ if (!chip->parallel_charger_suspended)
rc = smb1351_usb_suspend(chip, USER, !val->intval);
break;
- case POWER_SUPPLY_PROP_PRESENT:
- rc = smb1351_parallel_set_chg_present(chip, val->intval);
+ case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+ rc = smb1351_parallel_set_chg_suspend(chip, val->intval);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- if (chip->parallel_charger_present) {
- chip->target_fastchg_current_max_ma =
+ chip->target_fastchg_current_max_ma =
val->intval / 1000;
+ if (!chip->parallel_charger_suspended)
rc = smb1351_fastchg_current_set(chip,
chip->target_fastchg_current_max_ma);
- }
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- if (chip->parallel_charger_present) {
- index = smb1351_get_closest_usb_setpoint(
- val->intval / 1000);
- chip->usb_psy_ma = usb_chg_current[index];
+ index = smb1351_get_closest_usb_setpoint(val->intval / 1000);
+ chip->usb_psy_ma = usb_chg_current[index];
+ if (!chip->parallel_charger_suspended)
rc = smb1351_set_usb_chg_current(chip,
chip->usb_psy_ma);
- }
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- if (chip->parallel_charger_present &&
- (chip->vfloat_mv != val->intval)) {
+ chip->vfloat_mv = val->intval / 1000;
+ if (!chip->parallel_charger_suspended)
rc = smb1351_float_voltage_set(chip, val->intval);
- if (!rc)
- chip->vfloat_mv = val->intval;
- } else {
- chip->vfloat_mv = val->intval;
- }
break;
default:
return -EINVAL;
@@ -1638,41 +1657,49 @@ static int smb1351_parallel_get_property(struct power_supply *psy,
val->intval = !chip->usb_suspended_status;
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
- if (chip->parallel_charger_present)
+ if (!chip->parallel_charger_suspended)
val->intval = chip->usb_psy_ma * 1000;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- val->intval = chip->vfloat_mv;
+ if (!chip->parallel_charger_suspended)
+ val->intval = chip->vfloat_mv;
+ else
+ val->intval = 0;
break;
- case POWER_SUPPLY_PROP_PRESENT:
- val->intval = chip->parallel_charger_present;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ /* Check if SMB1351 is present */
+ if (smb1351_is_usb_present(chip)) {
+ val->intval = smb1351_get_prop_charge_type(chip);
+ if (val->intval == POWER_SUPPLY_CHARGE_TYPE_UNKNOWN) {
+ pr_debug("Failed to charge type, charger may be absent\n");
+ return -ENODEV;
+ }
+ }
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- if (chip->parallel_charger_present)
+ if (!chip->parallel_charger_suspended)
val->intval = chip->fastchg_current_max_ma * 1000;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_STATUS:
- if (chip->parallel_charger_present)
+ if (!chip->parallel_charger_suspended)
val->intval = smb1351_get_prop_batt_status(chip);
else
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
- if (chip->parallel_charger_present)
+ if (!chip->parallel_charger_suspended)
val->intval =
smb1351_is_input_current_limited(chip) ? 1 : 0;
else
val->intval = 0;
break;
case POWER_SUPPLY_PROP_PARALLEL_MODE:
- if (chip->parallel_charger_present)
- val->intval = POWER_SUPPLY_PARALLEL_USBIN_USBIN;
- else
- val->intval = POWER_SUPPLY_PARALLEL_NONE;
+ val->intval = POWER_SUPPLY_PARALLEL_USBIN_USBIN;
break;
default:
return -EINVAL;
@@ -3142,6 +3169,7 @@ static int smb1351_parallel_charger_probe(struct i2c_client *client,
chip->client = client;
chip->dev = &client->dev;
chip->parallel_charger = true;
+ chip->parallel_charger_suspended = true;
chip->usb_suspended_status = of_property_read_bool(node,
"qcom,charging-disabled");
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index ae15fef6c3a6..4180edc89a4c 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -10,18 +10,20 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "SMB138X: %s: " fmt, __func__
+
#include <linux/device.h>
+#include <linux/iio/consumer.h>
#include <linux/module.h>
-#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_device.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
#include <linux/regulator/driver.h>
-#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/qpnp/qpnp-revid.h>
#include "smb-reg.h"
#include "smb-lib.h"
@@ -89,6 +91,8 @@ struct smb_dt_props {
int fcc_ua;
int usb_icl_ua;
int dc_icl_ua;
+ int chg_temp_max_mdegc;
+ int connector_temp_max_mdegc;
};
struct smb138x {
@@ -103,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;
@@ -132,6 +147,18 @@ static int smb138x_parse_dt(struct smb138x *chip)
if (rc < 0)
chip->dt.dc_icl_ua = SMB138X_DEFAULT_ICL_UA;
+ rc = of_property_read_u32(node,
+ "qcom,charger-temp-max-mdegc",
+ &chip->dt.chg_temp_max_mdegc);
+ if (rc < 0)
+ chip->dt.chg_temp_max_mdegc = 80000;
+
+ rc = of_property_read_u32(node,
+ "qcom,connector-temp-max-mdegc",
+ &chip->dt.connector_temp_max_mdegc);
+ if (rc < 0)
+ chip->dt.connector_temp_max_mdegc = 105000;
+
return 0;
}
@@ -415,6 +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_HEALTH,
};
static int smb138x_parallel_get_prop(struct power_supply *psy,
@@ -467,6 +495,9 @@ 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_HEALTH:
+ rc = smblib_get_prop_die_health(chg, val);
+ break;
default:
pr_err("parallel power supply get prop %d not supported\n",
prop);
@@ -658,14 +689,144 @@ static int smb138x_init_vconn_regulator(struct smb138x *chip)
* HARDWARE INITIALIZATION *
***************************/
+#define MDEGC_3 3000
+#define MDEGC_15 15000
+static int smb138x_init_slave_hw(struct smb138x *chip)
+{
+ struct smb_charger *chg = &chip->chg;
+ int rc;
+
+ if (chip->wa_flags & OOB_COMP_WA_BIT) {
+ rc = smblib_masked_write(chg, SMB2CHG_MISC_ENG_SDCDC_CFG2,
+ ENG_SDCDC_SEL_OOB_VTH_BIT,
+ ENG_SDCDC_SEL_OOB_VTH_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't configure the OOB comp threshold rc = %d\n",
+ rc);
+ return rc;
+ }
+
+ rc = smblib_masked_write(chg, SMB2CHG_MISC_ENG_SDCDC_CFG6,
+ DEAD_TIME_MASK, HIGH_DEAD_TIME_MASK);
+ if (rc < 0) {
+ pr_err("Couldn't configure the sdcdc cfg 6 reg rc = %d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ /* enable watchdog bark and bite interrupts, and disable the watchdog */
+ rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT
+ | WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT
+ | BARK_WDOG_INT_EN_BIT,
+ BITE_WDOG_INT_EN_BIT | BARK_WDOG_INT_EN_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't configure the watchdog rc=%d\n", rc);
+ return rc;
+ }
+
+ /* disable charging when watchdog bites */
+ rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
+ BITE_WDOG_DISABLE_CHARGING_CFG_BIT,
+ BITE_WDOG_DISABLE_CHARGING_CFG_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't configure the watchdog bite rc=%d\n", rc);
+ return rc;
+ }
+
+ /* suspend parallel charging */
+ rc = smb138x_set_parallel_suspend(chip, true);
+ if (rc < 0) {
+ pr_err("Couldn't suspend parallel charging rc=%d\n", rc);
+ return rc;
+ }
+
+ /* initialize FCC to 0 */
+ rc = smblib_set_charge_param(chg, &chg->param.fcc, 0);
+ if (rc < 0) {
+ pr_err("Couldn't set 0 FCC rc=%d\n", rc);
+ return rc;
+ }
+
+ /* enable the charging path */
+ rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
+ CHARGING_ENABLE_CMD_BIT,
+ CHARGING_ENABLE_CMD_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't enable charging rc=%d\n", rc);
+ return rc;
+ }
+
+ /* configure charge enable for software control; active high */
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG,
+ CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0);
+ if (rc < 0) {
+ pr_err("Couldn't configure charge enable source rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* enable parallel current sensing */
+ rc = smblib_masked_write(chg, CFG_REG,
+ VCHG_EN_CFG_BIT, VCHG_EN_CFG_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't enable parallel current sensing rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* enable stacked diode */
+ rc = smblib_write(chg, SMB2CHG_DC_TM_SREFGEN, STACKED_DIODE_EN_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't enable stacked diode rc=%d\n", rc);
+ return rc;
+ }
+
+ /* initialize charger temperature threshold */
+ rc = iio_write_channel_processed(chg->iio.temp_max_chan,
+ chip->dt.chg_temp_max_mdegc);
+ if (rc < 0) {
+ pr_err("Couldn't set charger temp threshold rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = iio_write_channel_processed(chg->iio.connector_temp_thr1_chan,
+ chip->dt.connector_temp_max_mdegc);
+ if (rc < 0) {
+ pr_err("Couldn't set connector temp threshold1 rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = iio_write_channel_processed(chg->iio.connector_temp_thr2_chan,
+ chip->dt.connector_temp_max_mdegc + MDEGC_3);
+ if (rc < 0) {
+ pr_err("Couldn't set connector temp threshold2 rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = iio_write_channel_processed(chg->iio.connector_temp_thr3_chan,
+ chip->dt.connector_temp_max_mdegc + MDEGC_15);
+ if (rc < 0) {
+ pr_err("Couldn't set connector temp threshold3 rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = smblib_write(chg, THERMREG_SRC_CFG_REG,
+ THERMREG_SKIN_ADC_SRC_EN_BIT);
+ if (rc < 0) {
+ pr_err("Couldn't enable connector thermreg source rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int smb138x_init_hw(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
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,
@@ -681,15 +842,14 @@ static int smb138x_init_hw(struct smb138x *chip)
rc = smblib_masked_write(chg, CHGR_CFG2_REG,
CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure charge enable source rc=%d\n", rc);
+ pr_err("Couldn't configure charge enable source rc=%d\n", rc);
return rc;
}
/* enable the charging path */
rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
+ pr_err("Couldn't enable charging rc=%d\n", rc);
return rc;
}
@@ -701,8 +861,7 @@ static int smb138x_init_hw(struct smb138x *chip)
TYPEC_CCSTATE_CHANGE_INT_EN_BIT
| TYPEC_VBUS_ERROR_INT_EN_BIT);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure Type-C interrupts rc=%d\n", rc);
+ pr_err("Couldn't configure Type-C interrupts rc=%d\n", rc);
return rc;
}
@@ -711,16 +870,14 @@ static int smb138x_init_hw(struct smb138x *chip)
VCONN_EN_SRC_BIT | VCONN_EN_VALUE_BIT,
VCONN_EN_SRC_BIT);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure VCONN for SW control rc=%d\n", rc);
+ pr_err("Couldn't configure VCONN for SW control rc=%d\n", rc);
return rc;
}
/* configure VBUS for software control */
rc = smblib_masked_write(chg, OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure VBUS for SW control rc=%d\n", rc);
+ pr_err("Couldn't configure VBUS for SW control rc=%d\n", rc);
return rc;
}
@@ -728,8 +885,7 @@ static int smb138x_init_hw(struct smb138x *chip)
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
TYPEC_POWER_ROLE_CMD_MASK, 0);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure power role for DRP rc=%d\n", rc);
+ pr_err("Couldn't configure power role for DRP rc=%d\n", rc);
return rc;
}
@@ -738,16 +894,16 @@ static int smb138x_init_hw(struct smb138x *chip)
ENG_SDCDC_SEL_OOB_VTH_BIT,
ENG_SDCDC_SEL_OOB_VTH_BIT);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure the oob comp threh rc = %d\n", rc);
+ pr_err("Couldn't configure the OOB comp threshold rc = %d\n",
+ rc);
return rc;
}
rc = smblib_masked_write(chg, SMB2CHG_MISC_ENG_SDCDC_CFG6,
DEAD_TIME_MASK, HIGH_DEAD_TIME_MASK);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure the sdcdc cfg 6 reg rc = %d\n", rc);
+ pr_err("Couldn't configure the sdcdc cfg 6 reg rc = %d\n",
+ rc);
return rc;
}
}
@@ -795,6 +951,23 @@ static int smb138x_setup_wa_flags(struct smb138x *chip)
* DETERMINE INITIAL STATUS *
****************************/
+static irqreturn_t smb138x_handle_temperature_change(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb138x *chip = irq_data->parent_data;
+
+ power_supply_changed(chip->parallel_psy);
+ return IRQ_HANDLED;
+}
+
+static int smb138x_determine_initial_slave_status(struct smb138x *chip)
+{
+ struct smb_irq_data irq_data = {chip, "determine-initial-status"};
+
+ smb138x_handle_temperature_change(0, &irq_data);
+ return 0;
+}
+
static int smb138x_determine_initial_status(struct smb138x *chip)
{
struct smb_irq_data irq_data = {chip, "determine-initial-status"};
@@ -802,7 +975,6 @@ static int smb138x_determine_initial_status(struct smb138x *chip)
smblib_handle_usb_plugin(0, &irq_data);
smblib_handle_usb_typec_change(0, &irq_data);
smblib_handle_usb_source_change(0, &irq_data);
-
return 0;
}
@@ -810,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 = smblib_handle_debug,
+ .handler = smb138x_handle_temperature_change,
},
- {
+ [SWITCH_POWER_OK_IRQ] = {
.name = "switcher-power-ok",
.handler = smblib_handle_debug,
},
@@ -1021,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,
@@ -1144,95 +1311,54 @@ static int smb138x_slave_probe(struct smb138x *chip)
goto cleanup;
}
- if (chip->wa_flags & OOB_COMP_WA_BIT) {
- rc = smblib_masked_write(chg, SMB2CHG_MISC_ENG_SDCDC_CFG2,
- ENG_SDCDC_SEL_OOB_VTH_BIT,
- ENG_SDCDC_SEL_OOB_VTH_BIT);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure the oob comp threh rc = %d\n", rc);
- goto cleanup;
- }
-
- rc = smblib_masked_write(chg, SMB2CHG_MISC_ENG_SDCDC_CFG6,
- DEAD_TIME_MASK, HIGH_DEAD_TIME_MASK);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure the sdcdc cfg 6 reg rc = %d\n", rc);
- goto cleanup;
- }
- }
-
- /* enable watchdog bark and bite interrupts, and disable the watchdog */
- rc = smblib_masked_write(chg, WD_CFG_REG, WDOG_TIMER_EN_BIT
- | WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT
- | BARK_WDOG_INT_EN_BIT,
- BITE_WDOG_INT_EN_BIT | BARK_WDOG_INT_EN_BIT);
- if (rc < 0) {
- pr_err("Couldn't configure the watchdog rc=%d\n", rc);
+ chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max");
+ if (IS_ERR(chg->iio.temp_max_chan)) {
+ rc = PTR_ERR(chg->iio.temp_max_chan);
goto cleanup;
}
- /* disable charging when watchdog bites */
- rc = smblib_masked_write(chg, SNARL_BARK_BITE_WD_CFG_REG,
- BITE_WDOG_DISABLE_CHARGING_CFG_BIT,
- BITE_WDOG_DISABLE_CHARGING_CFG_BIT);
- if (rc < 0) {
- pr_err("Couldn't configure the watchdog bite rc=%d\n", rc);
+ chg->iio.connector_temp_thr1_chan = iio_channel_get(chg->dev,
+ "connector_temp_thr1");
+ if (IS_ERR(chg->iio.connector_temp_thr1_chan)) {
+ rc = PTR_ERR(chg->iio.connector_temp_thr1_chan);
goto cleanup;
}
- /* suspend parallel charging */
- rc = smb138x_set_parallel_suspend(chip, true);
- if (rc < 0) {
- pr_err("Couldn't suspend parallel charging rc=%d\n", rc);
+ chg->iio.connector_temp_thr2_chan = iio_channel_get(chg->dev,
+ "connector_temp_thr2");
+ if (IS_ERR(chg->iio.connector_temp_thr2_chan)) {
+ rc = PTR_ERR(chg->iio.connector_temp_thr2_chan);
goto cleanup;
}
- /* initialize FCC to 0 */
- rc = smblib_set_charge_param(chg, &chg->param.fcc, 0);
- if (rc < 0) {
- pr_err("Couldn't set 0 FCC rc=%d\n", rc);
+ chg->iio.connector_temp_thr3_chan = iio_channel_get(chg->dev,
+ "connector_temp_thr3");
+ if (IS_ERR(chg->iio.connector_temp_thr3_chan)) {
+ rc = PTR_ERR(chg->iio.connector_temp_thr3_chan);
goto cleanup;
}
- /* enable the charging path */
- rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG,
- CHARGING_ENABLE_CMD_BIT,
- CHARGING_ENABLE_CMD_BIT);
+ rc = smb138x_parse_dt(chip);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't enable charging rc=%d\n", rc);
+ pr_err("Couldn't parse device tree rc=%d\n", rc);
goto cleanup;
}
- /* configure charge enable for software control; active high */
- rc = smblib_masked_write(chg, CHGR_CFG2_REG,
- CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0);
+ rc = smb138x_init_slave_hw(chip);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't configure charge enable source rc=%d\n",
- rc);
+ pr_err("Couldn't initialize hardware rc=%d\n", rc);
goto cleanup;
}
- /* enable parallel current sensing */
- rc = smblib_masked_write(chg, CFG_REG,
- VCHG_EN_CFG_BIT, VCHG_EN_CFG_BIT);
+ rc = smb138x_init_parallel_psy(chip);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't enable parallel current sensing rc=%d\n",
- rc);
+ pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
goto cleanup;
}
- /* enable stacked diode */
- rc = smblib_write(chg, SMB2CHG_DC_TM_SREFGEN, STACKED_DIODE_EN_BIT);
+ rc = smb138x_determine_initial_slave_status(chip);
if (rc < 0) {
- pr_err("Couldn't enable stacked diode rc=%d\n", rc);
- return rc;
- }
-
- rc = smb138x_init_parallel_psy(chip);
- if (rc < 0) {
- pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
+ pr_err("Couldn't determine initial status rc=%d\n", rc);
goto cleanup;
}
@@ -1275,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);
@@ -1312,6 +1439,12 @@ static int smb138x_probe(struct platform_device *pdev)
goto cleanup;
}
+ if (rc < 0) {
+ if (rc != -EPROBE_DEFER)
+ pr_err("Couldn't probe SMB138X rc=%d\n", rc);
+ goto cleanup;
+ }
+
pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode);
return rc;
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/pwm/Kconfig b/drivers/pwm/Kconfig
index 40e1afdfc286..b5e44b237ed8 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -310,13 +310,14 @@ config PWM_RCAR
will be called pwm-rcar.
config PWM_QPNP
+ tristate "Qualcomm Technologies, Inc. QPNP LPG/PWM support"
depends on SPMI
- tristate "Qualcomm QPNP LPG/PWM support"
- help
- This driver supports PWM/LPG devices in Qualcomm PMIC chips which
- comply with QPNP. QPNP is a SPMI based PMIC implementation. These
- devices support Pulse Width Modulation output with user generated
- patterns. They share a lookup table with size of 64 entries.
+ help
+ This driver supports PWM/LPG devices in Qualcomm Technologies, Inc.
+ PMIC chips which comply with QPNP. QPNP is an SPMI based PMIC
+ implementation. These devices support Pulse Width Modulation output
+ with user generated patterns. They share a lookup table with size of
+ 64 entries.
config PWM_RENESAS_TPU
tristate "Renesas TPU PWM support"
diff --git a/drivers/pwm/pwm-qpnp.c b/drivers/pwm/pwm-qpnp.c
index 6d0c1fbe566b..d57bf2f3b80c 100644
--- a/drivers/pwm/pwm-qpnp.c
+++ b/drivers/pwm/pwm-qpnp.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
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
/*
- * Qualcomm QPNP Pulse Width Modulation (PWM) driver
+ * Qualcomm Technologies, Inc. QPNP Pulse Width Modulation (PWM) driver
*
* The HW module is also called LPG (Light Pattern Generator).
*/
@@ -382,6 +382,7 @@ static int qpnp_set_control(struct qpnp_pwm_chip *chip, bool pwm_hi,
bool pwm_lo, bool pwm_out, bool pwm_src, bool ramp_gen)
{
int value;
+
value = (ramp_gen << QPNP_PWM_EN_RAMP_GEN_SHIFT) |
(pwm_src << QPNP_PWM_SRC_SELECT_SHIFT) |
(pwm_lo << QPNP_EN_PWM_LO_SHIFT) |
@@ -476,7 +477,7 @@ static void qpnp_lpg_calc_period(enum time_level tm_lvl,
n = 6;
if (tm_lvl == LVL_USEC) {
- if (period_value < ((unsigned)(-1) / NSEC_PER_USEC)) {
+ if (period_value < ((unsigned int)(-1) / NSEC_PER_USEC)) {
period_n = (period_value * NSEC_PER_USEC) >> n;
} else {
if (supported_sizes == QPNP_PWM_SIZE_7_8_BIT)
@@ -499,7 +500,7 @@ static void qpnp_lpg_calc_period(enum time_level tm_lvl,
chip->channel_id, n);
}
- min_err = last_err = (unsigned)(-1);
+ min_err = last_err = (unsigned int)(-1);
best_m = 0;
best_clk = 0;
best_div = 0;
@@ -1233,7 +1234,7 @@ static int _pwm_config(struct qpnp_pwm_chip *chip,
}
pr_debug("duty/period=%u/%u %s: pwm_value=%d (of %d)\n",
- (unsigned)duty_value, (unsigned)period_value,
+ (unsigned int)duty_value, (unsigned int)period_value,
(tm_lvl == LVL_USEC) ? "usec" : "nsec",
pwm_config->pwm_value, 1 << period->pwm_size);
@@ -1290,7 +1291,7 @@ after_table_write:
QPNP_SET_PAUSE_CNT(lut_config->lut_pause_hi_cnt,
lut_params.lut_pause_hi, ramp_step_ms);
if (lut_config->lut_pause_hi_cnt > PM_PWM_MAX_PAUSE_CNT)
- lut_config->lut_pause_hi_cnt = PM_PWM_MAX_PAUSE_CNT;
+ lut_config->lut_pause_hi_cnt = PM_PWM_MAX_PAUSE_CNT;
lut_config->ramp_step_ms = ramp_step_ms;
@@ -1320,8 +1321,7 @@ static int _pwm_enable(struct qpnp_pwm_chip *chip)
chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
rc = qpnp_lpg_configure_pwm_state(chip, QPNP_PWM_ENABLE);
} else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
- rc = qpnp_lpg_configure_lut_state(chip,
- QPNP_LUT_ENABLE);
+ rc = qpnp_lpg_configure_lut_state(chip, QPNP_LUT_ENABLE);
}
if (!rc)
@@ -1368,7 +1368,7 @@ static int qpnp_pwm_config(struct pwm_chip *pwm_chip,
struct qpnp_pwm_chip *chip = qpnp_pwm_from_pwm_chip(pwm_chip);
int prev_period_us = chip->pwm_config.pwm_period;
- if ((unsigned)period_ns < PM_PWM_PERIOD_MIN * NSEC_PER_USEC) {
+ if ((unsigned int)period_ns < PM_PWM_PERIOD_MIN * NSEC_PER_USEC) {
pr_err("Invalid pwm handle or parameters\n");
return -EINVAL;
}
@@ -1403,6 +1403,7 @@ static int qpnp_pwm_enable(struct pwm_chip *pwm_chip,
{
int rc;
struct qpnp_pwm_chip *chip = qpnp_pwm_from_pwm_chip(pwm_chip);
+
rc = _pwm_enable(chip);
if (rc)
pr_err("Failed to enable PWM channel: %d\n", chip->channel_id);
@@ -1487,7 +1488,7 @@ int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode)
return rc;
}
-EXPORT_SYMBOL_GPL(pwm_change_mode);
+EXPORT_SYMBOL(pwm_change_mode);
/**
* pwm_config_period - change PWM period
@@ -1592,7 +1593,7 @@ out_unlock:
spin_unlock_irqrestore(&chip->lpg_lock, flags);
return rc;
}
-EXPORT_SYMBOL_GPL(pwm_config_pwm_value);
+EXPORT_SYMBOL(pwm_config_pwm_value);
/**
* pwm_config_us - change a PWM device configuration
@@ -1608,8 +1609,8 @@ int pwm_config_us(struct pwm_device *pwm, int duty_us, int period_us)
if (pwm == NULL || IS_ERR(pwm) ||
duty_us > period_us ||
- (unsigned)period_us > PM_PWM_PERIOD_MAX ||
- (unsigned)period_us < PM_PWM_PERIOD_MIN) {
+ (unsigned int)period_us > PM_PWM_PERIOD_MAX ||
+ (unsigned int)period_us < PM_PWM_PERIOD_MIN) {
pr_err("Invalid pwm handle or parameters\n");
return -EINVAL;
}
@@ -1622,10 +1623,11 @@ int pwm_config_us(struct pwm_device *pwm, int duty_us, int period_us)
qpnp_lpg_calc_period(LVL_USEC, period_us, chip);
qpnp_lpg_save_period(chip);
chip->pwm_config.pwm_period = period_us;
- if ((unsigned)period_us > (unsigned)(-1) / NSEC_PER_USEC)
+ if ((unsigned int)period_us >
+ (unsigned int)(-1) / NSEC_PER_USEC)
pwm->period = 0;
else
- pwm->period = (unsigned)period_us * NSEC_PER_USEC;
+ pwm->period = (unsigned int)period_us * NSEC_PER_USEC;
}
rc = _pwm_config(chip, LVL_USEC, duty_us, period_us);
@@ -1679,8 +1681,8 @@ int pwm_lut_config(struct pwm_device *pwm, int period_us,
return -EINVAL;
}
- if ((unsigned)period_us > PM_PWM_PERIOD_MAX ||
- (unsigned)period_us < PM_PWM_PERIOD_MIN) {
+ if ((unsigned int)period_us > PM_PWM_PERIOD_MAX ||
+ (unsigned int)period_us < PM_PWM_PERIOD_MIN) {
pr_err("Period out of range\n");
return -EINVAL;
}
@@ -1702,7 +1704,7 @@ int pwm_lut_config(struct pwm_device *pwm, int period_us,
return rc;
}
-EXPORT_SYMBOL_GPL(pwm_lut_config);
+EXPORT_SYMBOL(pwm_lut_config);
static int qpnp_parse_pwm_dt_config(struct device_node *of_pwm_node,
struct device_node *of_parent, struct qpnp_pwm_chip *chip)
@@ -1738,14 +1740,6 @@ static int qpnp_parse_pwm_dt_config(struct device_node *of_pwm_node,
return rc;
}
-#define qpnp_check_optional_dt_bindings(func) \
-do { \
- rc = func; \
- if (rc && rc != -EINVAL) \
- goto out; \
- rc = 0; \
-} while (0)
-
static int qpnp_parse_lpg_dt_config(struct device_node *of_lpg_node,
struct device_node *of_parent, struct qpnp_pwm_chip *chip)
{
@@ -1778,44 +1772,58 @@ static int qpnp_parse_lpg_dt_config(struct device_node *of_lpg_node,
return -EINVAL;
}
- duty_pct_list = kzalloc(sizeof(u32) * list_size, GFP_KERNEL);
-
- if (!duty_pct_list) {
- pr_err("kzalloc failed on duty_pct_list\n");
+ duty_pct_list = kcalloc(list_size, sizeof(*duty_pct_list), GFP_KERNEL);
+ if (!duty_pct_list)
return -ENOMEM;
- }
rc = of_property_read_u32_array(of_lpg_node, "qcom,duty-percents",
duty_pct_list, list_size);
if (rc) {
- pr_err("invalid or missing property:\n");
- pr_err("qcom,duty-pcts-list\n");
- kfree(duty_pct_list);
- return rc;
+ pr_err("invalid or missing property: qcom,duty-pcts-list\n");
+ goto out;
}
/* Read optional properties */
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,ramp-step-duration", &lut_config->ramp_step_ms));
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,lpg-lut-pause-hi", &lut_config->lut_pause_hi_cnt));
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,lpg-lut-pause-lo", &lut_config->lut_pause_lo_cnt));
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,lpg-lut-ramp-direction",
- (u32 *)&lut_config->ramp_direction));
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,lpg-lut-pattern-repeat",
- (u32 *)&lut_config->pattern_repeat));
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,lpg-lut-ramp-toggle",
- (u32 *)&lut_config->ramp_toggle));
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,lpg-lut-enable-pause-hi",
- (u32 *)&lut_config->enable_pause_hi));
- qpnp_check_optional_dt_bindings(of_property_read_u32(of_lpg_node,
- "qcom,lpg-lut-enable-pause-lo",
- (u32 *)&lut_config->enable_pause_lo));
+ rc = of_property_read_u32(of_lpg_node, "qcom,ramp-step-duration",
+ &lut_config->ramp_step_ms);
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ rc = of_property_read_u32(of_lpg_node, "qcom,lpg-lut-pause-hi",
+ &lut_config->lut_pause_hi_cnt);
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ rc = of_property_read_u32(of_lpg_node, "qcom,lpg-lut-pause-lo",
+ &lut_config->lut_pause_lo_cnt);
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ rc = of_property_read_u32(of_lpg_node, "qcom,lpg-lut-ramp-direction",
+ (u32 *)&lut_config->ramp_direction);
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ rc = of_property_read_u32(of_lpg_node, "qcom,lpg-lut-pattern-repeat",
+ (u32 *)&lut_config->pattern_repeat);
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ rc = of_property_read_u32(of_lpg_node, "qcom,lpg-lut-ramp-toggle",
+ (u32 *)&lut_config->ramp_toggle);
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ rc = of_property_read_u32(of_lpg_node, "qcom,lpg-lut-enable-pause-hi",
+ (u32 *)&lut_config->enable_pause_hi);
+ if (rc && rc != -EINVAL)
+ goto out;
+
+ rc = of_property_read_u32(of_lpg_node, "qcom,lpg-lut-enable-pause-lo",
+ (u32 *)&lut_config->enable_pause_lo);
+ if (rc && rc != -EINVAL)
+ goto out;
+ rc = 0;
qpnp_set_lut_params(&lut_params, lut_config, start_idx, list_size);
@@ -1877,7 +1885,7 @@ static int qpnp_parse_dt_config(struct platform_device *pdev,
struct qpnp_pwm_chip *chip)
{
int rc, enable, lut_entry_size, list_size, i;
- const char *lable;
+ const char *label;
const __be32 *prop;
u32 size;
struct device_node *node;
@@ -1992,12 +2000,10 @@ static int qpnp_parse_dt_config(struct platform_device *pdev,
lut_entry_size = sizeof(u8);
}
- lut_config->duty_pct_list = kzalloc(lpg_config->lut_size *
+ lut_config->duty_pct_list = kcalloc(lpg_config->lut_size,
lut_entry_size, GFP_KERNEL);
- if (!lut_config->duty_pct_list) {
- pr_err("can not allocate duty pct list\n");
+ if (!lut_config->duty_pct_list)
return -ENOMEM;
- }
rc = of_property_read_u32(of_node, "qcom,ramp-index",
&lut_config->ramp_index);
@@ -2038,18 +2044,18 @@ static int qpnp_parse_dt_config(struct platform_device *pdev,
}
for_each_child_of_node(of_node, node) {
- rc = of_property_read_string(node, "label", &lable);
+ rc = of_property_read_string(node, "label", &label);
if (rc) {
- dev_err(&pdev->dev, "%s: Missing lable property\n",
+ dev_err(&pdev->dev, "%s: Missing label property\n",
__func__);
goto out;
}
- if (!strncmp(lable, "pwm", 3)) {
+ if (!strcmp(label, "pwm")) {
rc = qpnp_parse_pwm_dt_config(node, of_node, chip);
if (rc)
goto out;
found_pwm_subnode = 1;
- } else if (!strncmp(lable, "lpg", 3) &&
+ } else if (!strcmp(label, "lpg") &&
!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
rc = qpnp_parse_lpg_dt_config(node, of_node, chip);
if (rc)
@@ -2102,10 +2108,9 @@ static int qpnp_pwm_probe(struct platform_device *pdev)
int rc;
pwm_chip = kzalloc(sizeof(*pwm_chip), GFP_KERNEL);
- if (pwm_chip == NULL) {
- pr_err("kzalloc() failed.\n");
+ if (pwm_chip == NULL)
return -ENOMEM;
- }
+
pwm_chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!pwm_chip->regmap) {
dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
@@ -2169,7 +2174,7 @@ static int qpnp_pwm_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = QPNP_LPG_DRIVER_NAME, },
{}
};
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8d54ece776e2..e5ba63171eba 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -807,42 +807,43 @@ config REGULATOR_RPM_SMD
application processor over SMD.
config REGULATOR_QPNP
+ tristate "Qualcomm Technologies, Inc. QPNP regulator support"
depends on SPMI
- tristate "Qualcomm QPNP regulator support"
help
- This driver supports voltage regulators in Qualcomm PMIC chips which
- comply with QPNP. QPNP is a SPMI based PMIC implementation. These
- chips provide several different varieties of LDO and switching
- regulators. They also provide voltage switches and boost regulators.
+ This driver supports voltage regulators in Qualcomm Technologies, Inc.
+ PMIC chips which comply with QPNP. QPNP is a SPMI based PMIC
+ implementation. These chips provide several different varieties of
+ LDO and switching regulators. They also provide voltage switches and
+ boost regulators.
config REGULATOR_QPNP_LABIBB
+ tristate "Qualcomm Technologies, Inc. QPNP LAB/IBB regulator support"
depends on SPMI
- tristate "Qualcomm Technologies, Inc QPNP LAB/IBB regulator support"
help
- This driver supports voltage regulators in Qualcomm Technologies, Inc
+ This driver supports voltage regulators in Qualcomm Technologies, Inc.
PMIC chips which comply with QPNP LAB/IBB regulators. QPNP LAB and IBB
- are SPMI based PMIC implementation. LAB regulator can be used as a
+ are SPMI based PMIC implementations. LAB regulator can be used as a
regular positive boost regulator. IBB can be used as a regular
negative boost regulator. LAB/IBB regulators can also be used
together for LCD or AMOLED.
config REGULATOR_QPNP_LCDB
+ tristate "Qualcomm Technologies, Inc. QPNP LCDB support"
depends on SPMI
- tristate "Qualcomm Technologies, Inc QPNP LCDB support"
help
- Supports the LCDB module in the Qualcomm Technologies, Inc
- QPNP PMIC. Exposes regulators to control the positive and
+ Supports the LCDB module in the Qualcomm Technologies, Inc.
+ QPNP PMICs. Exposes regulators to control the positive and
negative voltage bias for the LCD display panel. It also
allows configurability for the various bias-voltage parameters.
config REGULATOR_QPNP_OLEDB
+ tristate "Qualcomm Technologies, Inc. QPNP OLEDB regulator support"
depends on SPMI
- tristate "Qualcomm Technologies, Inc QPNP OLEDB regulator support"
help
- This driver supports the OLEDB(AVDD bias) signal for AMOLED panel in Qualcomm
- Technologies, Inc QPNP PMIC. It exposes the OLED voltage configuration
- via the regulator framework. The configurable range of this bias is
- 5V to 8.1V.
+ This driver supports the OLEDB (AVDD bias) signal for AMOLED panel in
+ Qualcomm Technologies, Inc. QPNP PMICs. It exposes the OLED voltage
+ configuration via the regulator framework. The configurable range of
+ this bias is 5 V to 8.1 V.
config REGULATOR_SPM
bool "SPM regulator driver"
@@ -950,19 +951,18 @@ config REGULATOR_KRYO
depends on OF
help
Some MSM designs have CPUs that can be directly powered from a common
- voltage rail via a Block Head Switch (BHS) or an LDO whose output voltage
- can be configured for use when certain power constraints are met.
- Say yes to support management of LDO and BHS modes for the clusters in the
- CPU subsystem.
+ voltage rail via a Block Head Switch (BHS) or an LDO whose output
+ voltage can be configured for use when certain power constraints are
+ met. Say yes to support management of LDO and BHS modes for the
+ clusters in the CPU subsystem.
config REGULATOR_MEM_ACC
- tristate "QTI Memory accelerator regulator driver"
- help
- Say y here to enable the memory accelerator driver for Qualcomm
- Technologies (QTI) chips. The accelerator controls delays applied
- for memory accesses.
- This driver configures the power-mode (corner) for the memory
- accelerator.
+ tristate "QTI Memory accelerator regulator driver"
+ help
+ Say y here to enable the memory accelerator driver for Qualcomm
+ Technologies, Inc. (QTI) chips. The accelerator controls delays
+ applied for memory accesses. This driver configures the power-mode
+ (corner) for the memory accelerator.
config REGULATOR_PROXY_CONSUMER
bool "Boot time regulator proxy consumer support"
diff --git a/drivers/regulator/cpr3-hmss-regulator.c b/drivers/regulator/cpr3-hmss-regulator.c
index 091780525207..77e8bf4b9895 100644
--- a/drivers/regulator/cpr3-hmss-regulator.c
+++ b/drivers/regulator/cpr3-hmss-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -1232,7 +1232,7 @@ static int cpr3_hmss_kvreg_init(struct cpr3_regulator *vreg)
scnprintf(kvreg_name_buf, MAX_VREG_NAME_SIZE,
"vdd-thread%d-ldo-supply", id);
- if (!of_find_property(ctrl->dev->of_node, kvreg_name_buf , NULL))
+ if (!of_find_property(ctrl->dev->of_node, kvreg_name_buf, NULL))
return 0;
else if (!of_find_property(node, "qcom,ldo-min-headroom-voltage", NULL))
return 0;
@@ -1675,7 +1675,7 @@ static int cpr3_hmss_regulator_resume(struct platform_device *pdev)
}
/* Data corresponds to the SoC revision */
-static struct of_device_id cpr_regulator_match_table[] = {
+static const struct of_device_id cpr_regulator_match_table[] = {
{
.compatible = "qcom,cpr3-msm8996-v1-hmss-regulator",
.data = (void *)(uintptr_t)1
diff --git a/drivers/regulator/cpr3-mmss-regulator.c b/drivers/regulator/cpr3-mmss-regulator.c
index 1070a34073e4..41032dd3c15a 100644
--- a/drivers/regulator/cpr3-mmss-regulator.c
+++ b/drivers/regulator/cpr3-mmss-regulator.c
@@ -1088,7 +1088,7 @@ static int cpr3_mmss_regulator_resume(struct platform_device *pdev)
}
/* Data corresponds to the SoC revision */
-static struct of_device_id cpr_regulator_match_table[] = {
+static const struct of_device_id cpr_regulator_match_table[] = {
{
.compatible = "qcom,cpr3-msm8996-v1-mmss-regulator",
.data = (void *)(uintptr_t)1,
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index 6775152f2623..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,
@@ -1622,8 +1633,6 @@ static void cpr3_regulator_set_target_quot(struct cpr3_thread *thread)
}
thread->last_closed_loop_aggr_corner = thread->aggr_corner;
-
- return;
}
/**
@@ -1647,8 +1656,8 @@ static void cpr3_update_vreg_closed_loop_volt(struct cpr3_regulator *vreg,
if (vreg->last_closed_loop_corner == CPR3_REGULATOR_CORNER_INVALID)
return;
- else
- corner = &vreg->corner[vreg->last_closed_loop_corner];
+
+ corner = &vreg->corner[vreg->last_closed_loop_corner];
if (vreg->thread->last_closed_loop_aggr_corner.ro_mask
== CPR3_RO_MASK || !vreg->aggregated) {
@@ -4195,7 +4204,7 @@ static int cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
* Return: 0 on success, errno on failure
*/
static int cpr3_regulator_set_voltage(struct regulator_dev *rdev,
- int corner, int corner_max, unsigned *selector)
+ int corner, int corner_max, unsigned int *selector)
{
struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
struct cpr3_controller *ctrl = vreg->thread->ctrl;
@@ -4264,7 +4273,7 @@ static int cpr3_regulator_get_voltage(struct regulator_dev *rdev)
* Return: voltage corner value offset by CPR3_CORNER_OFFSET
*/
static int cpr3_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
+ unsigned int selector)
{
struct cpr3_regulator *vreg = rdev_get_drvdata(rdev);
@@ -4964,11 +4973,11 @@ static struct dentry *debugfs_create_int(const char *name, umode_t mode,
struct dentry *parent, int *value)
{
/* if there are no write bits set, make read only */
- if (!(mode & S_IWUGO))
+ if (!(mode & 0222))
return debugfs_create_file(name, mode, parent, value,
&fops_int_ro);
/* if there are no read bits set, make write only */
- if (!(mode & S_IRUGO))
+ if (!(mode & 0444))
return debugfs_create_file(name, mode, parent, value,
&fops_int_wo);
@@ -5225,21 +5234,21 @@ static void cpr3_regulator_debugfs_corner_add(struct cpr3_regulator *vreg,
struct cpr3_debug_corner_info *info;
struct dentry *temp;
- temp = cpr3_debugfs_create_corner_int(vreg, "floor_volt", S_IRUGO,
+ temp = cpr3_debugfs_create_corner_int(vreg, "floor_volt", 0444,
corner_dir, index, offsetof(struct cpr3_corner, floor_volt));
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "floor_volt debugfs file creation failed\n");
return;
}
- temp = cpr3_debugfs_create_corner_int(vreg, "ceiling_volt", S_IRUGO,
+ temp = cpr3_debugfs_create_corner_int(vreg, "ceiling_volt", 0444,
corner_dir, index, offsetof(struct cpr3_corner, ceiling_volt));
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "ceiling_volt debugfs file creation failed\n");
return;
}
- temp = cpr3_debugfs_create_corner_int(vreg, "open_loop_volt", S_IRUGO,
+ temp = cpr3_debugfs_create_corner_int(vreg, "open_loop_volt", 0444,
corner_dir, index,
offsetof(struct cpr3_corner, open_loop_volt));
if (IS_ERR_OR_NULL(temp)) {
@@ -5247,7 +5256,7 @@ static void cpr3_regulator_debugfs_corner_add(struct cpr3_regulator *vreg,
return;
}
- temp = cpr3_debugfs_create_corner_int(vreg, "last_volt", S_IRUGO,
+ temp = cpr3_debugfs_create_corner_int(vreg, "last_volt", 0444,
corner_dir, index, offsetof(struct cpr3_corner, last_volt));
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "last_volt debugfs file creation failed\n");
@@ -5262,8 +5271,8 @@ static void cpr3_regulator_debugfs_corner_add(struct cpr3_regulator *vreg,
info->index = index;
info->corner = vreg->corner;
- temp = debugfs_create_file("target_quots", S_IRUGO, corner_dir,
- info, &cpr3_debug_quot_fops);
+ temp = debugfs_create_file("target_quots", 0444, corner_dir, info,
+ &cpr3_debug_quot_fops);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "target_quots debugfs file creation failed\n");
return;
@@ -5361,21 +5370,21 @@ static void cpr3_regulator_debugfs_vreg_add(struct cpr3_regulator *vreg,
return;
}
- temp = debugfs_create_int("speed_bin_fuse", S_IRUGO, vreg_dir,
+ temp = debugfs_create_int("speed_bin_fuse", 0444, vreg_dir,
&vreg->speed_bin_fuse);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "speed_bin_fuse debugfs file creation failed\n");
return;
}
- temp = debugfs_create_int("cpr_rev_fuse", S_IRUGO, vreg_dir,
+ temp = debugfs_create_int("cpr_rev_fuse", 0444, vreg_dir,
&vreg->cpr_rev_fuse);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "cpr_rev_fuse debugfs file creation failed\n");
return;
}
- temp = debugfs_create_int("fuse_combo", S_IRUGO, vreg_dir,
+ temp = debugfs_create_int("fuse_combo", 0444, vreg_dir,
&vreg->fuse_combo);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "fuse_combo debugfs file creation failed\n");
@@ -5383,15 +5392,15 @@ static void cpr3_regulator_debugfs_vreg_add(struct cpr3_regulator *vreg,
}
if (vreg->ldo_regulator) {
- temp = debugfs_create_file("ldo_mode", S_IRUGO, vreg_dir,
- vreg, &cpr3_debug_ldo_mode_fops);
+ temp = debugfs_create_file("ldo_mode", 0444, vreg_dir, vreg,
+ &cpr3_debug_ldo_mode_fops);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "ldo_mode debugfs file creation failed\n");
return;
}
temp = debugfs_create_file("ldo_mode_allowed",
- S_IRUGO | S_IWUSR, vreg_dir, vreg,
+ 0644, vreg_dir, vreg,
&cpr3_debug_ldo_mode_allowed_fops);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "ldo_mode_allowed debugfs file creation failed\n");
@@ -5399,7 +5408,7 @@ static void cpr3_regulator_debugfs_vreg_add(struct cpr3_regulator *vreg,
}
}
- temp = debugfs_create_int("corner_count", S_IRUGO, vreg_dir,
+ temp = debugfs_create_int("corner_count", 0444, vreg_dir,
&vreg->corner_count);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "corner_count debugfs file creation failed\n");
@@ -5412,8 +5421,8 @@ static void cpr3_regulator_debugfs_vreg_add(struct cpr3_regulator *vreg,
return;
}
- temp = debugfs_create_file("index", S_IRUGO | S_IWUSR, corner_dir,
- vreg, &cpr3_debug_corner_index_fops);
+ temp = debugfs_create_file("index", 0644, corner_dir, vreg,
+ &cpr3_debug_corner_index_fops);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "index debugfs file creation failed\n");
return;
@@ -5428,8 +5437,8 @@ static void cpr3_regulator_debugfs_vreg_add(struct cpr3_regulator *vreg,
return;
}
- temp = debugfs_create_file("index", S_IRUGO, corner_dir,
- vreg, &cpr3_debug_current_corner_index_fops);
+ temp = debugfs_create_file("index", 0444, corner_dir, vreg,
+ &cpr3_debug_current_corner_index_fops);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(vreg, "index debugfs file creation failed\n");
return;
@@ -5470,7 +5479,7 @@ static void cpr3_regulator_debugfs_thread_add(struct cpr3_thread *thread)
return;
}
- temp = debugfs_create_int("floor_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("floor_volt", 0444, aggr_dir,
&thread->aggr_corner.floor_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "thread %u aggr floor_volt debugfs file creation failed\n",
@@ -5478,7 +5487,7 @@ static void cpr3_regulator_debugfs_thread_add(struct cpr3_thread *thread)
return;
}
- temp = debugfs_create_int("ceiling_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("ceiling_volt", 0444, aggr_dir,
&thread->aggr_corner.ceiling_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "thread %u aggr ceiling_volt debugfs file creation failed\n",
@@ -5486,7 +5495,7 @@ static void cpr3_regulator_debugfs_thread_add(struct cpr3_thread *thread)
return;
}
- temp = debugfs_create_int("open_loop_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("open_loop_volt", 0444, aggr_dir,
&thread->aggr_corner.open_loop_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "thread %u aggr open_loop_volt debugfs file creation failed\n",
@@ -5494,7 +5503,7 @@ static void cpr3_regulator_debugfs_thread_add(struct cpr3_thread *thread)
return;
}
- temp = debugfs_create_int("last_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("last_volt", 0444, aggr_dir,
&thread->aggr_corner.last_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "thread %u aggr last_volt debugfs file creation failed\n",
@@ -5511,8 +5520,8 @@ static void cpr3_regulator_debugfs_thread_add(struct cpr3_thread *thread)
info->index = index;
info->corner = &thread->aggr_corner;
- temp = debugfs_create_file("target_quots", S_IRUGO, aggr_dir,
- info, &cpr3_debug_quot_fops);
+ temp = debugfs_create_file("target_quots", 0444, aggr_dir, info,
+ &cpr3_debug_quot_fops);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "thread %u target_quots debugfs file creation failed\n",
thread->thread_id);
@@ -5869,7 +5878,7 @@ static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
return;
}
- temp = debugfs_create_file("cpr_closed_loop_enable", S_IRUGO | S_IWUSR,
+ temp = debugfs_create_file("cpr_closed_loop_enable", 0644,
ctrl->debugfs, ctrl,
&cpr3_debug_closed_loop_enable_fops);
if (IS_ERR_OR_NULL(temp)) {
@@ -5878,8 +5887,8 @@ static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
}
if (ctrl->supports_hw_closed_loop) {
- temp = debugfs_create_file("use_hw_closed_loop",
- S_IRUGO | S_IWUSR, ctrl->debugfs, ctrl,
+ temp = debugfs_create_file("use_hw_closed_loop", 0644,
+ ctrl->debugfs, ctrl,
&cpr3_debug_hw_closed_loop_enable_fops);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "use_hw_closed_loop debugfs file creation failed\n");
@@ -5887,7 +5896,7 @@ static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
}
}
- temp = debugfs_create_int("thread_count", S_IRUGO, ctrl->debugfs,
+ temp = debugfs_create_int("thread_count", 0444, ctrl->debugfs,
&ctrl->thread_count);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "thread_count debugfs file creation failed\n");
@@ -5895,7 +5904,7 @@ static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
}
if (ctrl->apm) {
- temp = debugfs_create_int("apm_threshold_volt", S_IRUGO,
+ temp = debugfs_create_int("apm_threshold_volt", 0444,
ctrl->debugfs, &ctrl->apm_threshold_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "apm_threshold_volt debugfs file creation failed\n");
@@ -5905,28 +5914,28 @@ static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
if (ctrl->aging_required || ctrl->aging_succeeded
|| ctrl->aging_failed) {
- temp = debugfs_create_int("aging_adj_volt", S_IRUGO,
+ temp = debugfs_create_int("aging_adj_volt", 0444,
ctrl->debugfs, &ctrl->aging_ref_adjust_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "aging_adj_volt debugfs file creation failed\n");
return;
}
- temp = debugfs_create_file("aging_succeeded", S_IRUGO,
+ temp = debugfs_create_file("aging_succeeded", 0444,
ctrl->debugfs, &ctrl->aging_succeeded, &fops_bool_ro);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "aging_succeeded debugfs file creation failed\n");
return;
}
- temp = debugfs_create_file("aging_failed", S_IRUGO,
+ temp = debugfs_create_file("aging_failed", 0444,
ctrl->debugfs, &ctrl->aging_failed, &fops_bool_ro);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "aging_failed debugfs file creation failed\n");
return;
}
- temp = debugfs_create_file("aging_trigger", S_IWUSR,
+ temp = debugfs_create_file("aging_trigger", 0200,
ctrl->debugfs, ctrl,
&cpr3_debug_trigger_aging_measurement_fops);
if (IS_ERR_OR_NULL(temp)) {
@@ -5941,28 +5950,28 @@ static void cpr3_regulator_debugfs_ctrl_add(struct cpr3_controller *ctrl)
return;
}
- temp = debugfs_create_int("floor_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("floor_volt", 0444, aggr_dir,
&ctrl->aggr_corner.floor_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "aggr floor_volt debugfs file creation failed\n");
return;
}
- temp = debugfs_create_int("ceiling_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("ceiling_volt", 0444, aggr_dir,
&ctrl->aggr_corner.ceiling_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "aggr ceiling_volt debugfs file creation failed\n");
return;
}
- temp = debugfs_create_int("open_loop_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("open_loop_volt", 0444, aggr_dir,
&ctrl->aggr_corner.open_loop_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "aggr open_loop_volt debugfs file creation failed\n");
return;
}
- temp = debugfs_create_int("last_volt", S_IRUGO, aggr_dir,
+ temp = debugfs_create_int("last_volt", 0444, aggr_dir,
&ctrl->aggr_corner.last_volt);
if (IS_ERR_OR_NULL(temp)) {
cpr3_err(ctrl, "aggr last_volt debugfs file creation failed\n");
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index f0230b8ae2e5..1ac0f7b816b3 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -36,9 +36,9 @@ struct cpr3_thread;
* from 0 to 63. bit_start must be less than or equal to bit_end.
*/
struct cpr3_fuse_param {
- unsigned row;
- unsigned bit_start;
- unsigned bit_end;
+ unsigned int row;
+ unsigned int bit_start;
+ unsigned int bit_end;
};
/* Each CPR3 sensor has 16 ring oscillators */
@@ -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. */
@@ -1021,7 +1028,6 @@ static inline int cpr3_limit_open_loop_voltages(struct cpr3_regulator *vreg)
static inline void cpr3_open_loop_voltage_as_ceiling(
struct cpr3_regulator *vreg)
{
- return;
}
static inline int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg)
@@ -1031,7 +1037,6 @@ static inline int cpr3_limit_floor_voltages(struct cpr3_regulator *vreg)
static inline void cpr3_print_quots(struct cpr3_regulator *vreg)
{
- return;
}
static inline int cpr3_adjust_fused_open_loop_voltages(
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-apss-regulator.c b/drivers/regulator/cpr4-apss-regulator.c
index 737511e250f1..cfc09ba9f8da 100644
--- a/drivers/regulator/cpr4-apss-regulator.c
+++ b/drivers/regulator/cpr4-apss-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -1402,7 +1402,7 @@ static int cpr4_apss_regulator_remove(struct platform_device *pdev)
return cpr3_regulator_unregister(ctrl);
}
-static struct of_device_id cpr4_regulator_match_table[] = {
+static const struct of_device_id cpr4_regulator_match_table[] = {
{ .compatible = "qcom,cpr4-msm8953-apss-regulator", },
{}
};
diff --git a/drivers/regulator/cpr4-mmss-ldo-regulator.c b/drivers/regulator/cpr4-mmss-ldo-regulator.c
index f8e3ea40ddac..525f9d6fcf75 100644
--- a/drivers/regulator/cpr4-mmss-ldo-regulator.c
+++ b/drivers/regulator/cpr4-mmss-ldo-regulator.c
@@ -737,6 +737,11 @@ 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,
+ },
+ { },
};
static struct platform_driver cpr4_mmss_regulator_driver = {
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index 0472ce13197b..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)
@@ -2007,7 +2246,7 @@ static int cprh_kbss_regulator_resume(struct platform_device *pdev)
}
/* Data corresponds to the SoC revision */
-static struct of_device_id cprh_regulator_match_table[] = {
+static const struct of_device_id cprh_regulator_match_table[] = {
{
.compatible = "qcom,cprh-msm8998-v1-kbss-regulator",
.data = (void *)(uintptr_t)MSM8998_V1_SOC_ID,
@@ -2024,6 +2263,10 @@ static 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/regulator/kryo-regulator.c b/drivers/regulator/kryo-regulator.c
index cf7830469db5..fd853e7323bb 100644
--- a/drivers/regulator/kryo-regulator.c
+++ b/drivers/regulator/kryo-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -333,7 +333,7 @@ static int kryo_regulator_is_enabled(struct regulator_dev *rdev)
}
static int kryo_regulator_set_voltage(struct regulator_dev *rdev,
- int min_volt, int max_volt, unsigned *selector)
+ int min_volt, int max_volt, unsigned int *selector)
{
struct kryo_regulator *kvreg = rdev_get_drvdata(rdev);
int rc;
@@ -400,7 +400,7 @@ static int kryo_regulator_get_bypass(struct regulator_dev *rdev,
}
static int kryo_regulator_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
+ unsigned int selector)
{
struct kryo_regulator *kvreg = rdev_get_drvdata(rdev);
@@ -411,7 +411,7 @@ static int kryo_regulator_list_voltage(struct regulator_dev *rdev,
}
static int kryo_regulator_retention_set_voltage(struct regulator_dev *rdev,
- int min_volt, int max_volt, unsigned *selector)
+ int min_volt, int max_volt, unsigned int *selector)
{
struct kryo_regulator *kvreg = rdev_get_drvdata(rdev);
int rc;
@@ -499,7 +499,7 @@ static int kryo_regulator_retention_get_bypass(struct regulator_dev *rdev,
}
static int kryo_regulator_retention_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
+ unsigned int selector)
{
struct kryo_regulator *kvreg = rdev_get_drvdata(rdev);
@@ -624,7 +624,7 @@ static void kryo_debugfs_init(struct kryo_regulator *kvreg)
return;
}
- temp = debugfs_create_file("mode", S_IRUGO, kvreg->debugfs,
+ temp = debugfs_create_file("mode", 0444, kvreg->debugfs,
kvreg, &kryo_dbg_mode_fops);
if (IS_ERR_OR_NULL(temp)) {
@@ -989,10 +989,8 @@ static int kryo_regulator_probe(struct platform_device *pdev)
init_data->constraints.input_uV = init_data->constraints.max_uV;
kvreg = devm_kzalloc(dev, sizeof(*kvreg), GFP_KERNEL);
- if (!kvreg) {
- dev_err(dev, "memory allocation failed\n");
+ if (!kvreg)
return -ENOMEM;
- }
rc = kryo_regulator_init_data(pdev, kvreg);
if (rc) {
@@ -1073,7 +1071,7 @@ static int kryo_regulator_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id kryo_regulator_match_table[] = {
+static const struct of_device_id kryo_regulator_match_table[] = {
{ .compatible = "qcom,kryo-regulator", },
{}
};
diff --git a/drivers/regulator/mem-acc-regulator.c b/drivers/regulator/mem-acc-regulator.c
index c693969b19b6..4c03decda95a 100644
--- a/drivers/regulator/mem-acc-regulator.c
+++ b/drivers/regulator/mem-acc-regulator.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
@@ -269,7 +269,7 @@ static void update_acc_reg(struct mem_acc_regulator *mem_acc_vreg, int corner)
}
static int mem_acc_regulator_set_voltage(struct regulator_dev *rdev,
- int corner, int corner_max, unsigned *selector)
+ int corner, int corner_max, unsigned int *selector)
{
struct mem_acc_regulator *mem_acc_vreg = rdev_get_drvdata(rdev);
int i;
@@ -333,10 +333,8 @@ static int __mem_acc_sel_init(struct mem_acc_regulator *mem_acc_vreg,
mem_acc_vreg->acc_sel_mask[mem_type] = devm_kzalloc(mem_acc_vreg->dev,
mem_acc_vreg->num_acc_sel[mem_type] * sizeof(u32), GFP_KERNEL);
- if (!mem_acc_vreg->acc_sel_mask[mem_type]) {
- pr_err("Unable to allocate memory for mem_type=%d\n", mem_type);
+ if (!mem_acc_vreg->acc_sel_mask[mem_type])
return -ENOMEM;
- }
for (i = 0; i < mem_acc_vreg->num_acc_sel[mem_type]; i++) {
bit = mem_acc_vreg->acc_sel_bit_pos[mem_type][i];
@@ -355,8 +353,8 @@ static int mem_acc_sel_init(struct mem_acc_regulator *mem_acc_vreg)
if (mem_acc_vreg->mem_acc_supported[i]) {
rc = __mem_acc_sel_init(mem_acc_vreg, i);
if (rc) {
- pr_err("Unable to intialize mem_type=%d rc=%d\n",
- i, rc);
+ pr_err("Unable to initialize mem_type=%d rc=%d\n",
+ i, rc);
return rc;
}
}
@@ -523,15 +521,15 @@ static int mem_acc_custom_data_init(struct platform_device *pdev,
if (!res || !res->start) {
pr_debug("%s resource missing\n", custom_apc_addr_str);
return -EINVAL;
- } else {
- len = res->end - res->start + 1;
- mem_acc_vreg->acc_custom_addr[mem_type] =
- devm_ioremap(mem_acc_vreg->dev, res->start, len);
- if (!mem_acc_vreg->acc_custom_addr[mem_type]) {
- pr_err("Unable to map %s %pa\n", custom_apc_addr_str,
- &res->start);
- return -EINVAL;
- }
+ }
+
+ len = res->end - res->start + 1;
+ mem_acc_vreg->acc_custom_addr[mem_type] =
+ devm_ioremap(mem_acc_vreg->dev, res->start, len);
+ if (!mem_acc_vreg->acc_custom_addr[mem_type]) {
+ pr_err("Unable to map %s %pa\n",
+ custom_apc_addr_str, &res->start);
+ return -EINVAL;
}
rc = populate_acc_data(mem_acc_vreg, custom_apc_data_str,
@@ -1190,7 +1188,7 @@ static int mem_acc_init(struct platform_device *pdev,
rc = mem_acc_sel_init(mem_acc_vreg);
if (rc) {
- pr_err("Unable to intialize mem_acc_sel reg rc=%d\n", rc);
+ pr_err("Unable to initialize mem_acc_sel reg rc=%d\n", rc);
return rc;
}
@@ -1307,19 +1305,16 @@ static int mem_acc_regulator_probe(struct platform_device *pdev)
if (!init_data) {
pr_err("regulator init data is missing\n");
return -EINVAL;
- } else {
- init_data->constraints.input_uV
- = init_data->constraints.max_uV;
- init_data->constraints.valid_ops_mask
- |= REGULATOR_CHANGE_VOLTAGE;
}
+ init_data->constraints.input_uV = init_data->constraints.max_uV;
+ init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
+
mem_acc_vreg = devm_kzalloc(&pdev->dev, sizeof(*mem_acc_vreg),
GFP_KERNEL);
- if (!mem_acc_vreg) {
- pr_err("Can't allocate mem_acc_vreg memory\n");
+ if (!mem_acc_vreg)
return -ENOMEM;
- }
+
mem_acc_vreg->dev = &pdev->dev;
rc = mem_acc_init(pdev, mem_acc_vreg);
@@ -1361,7 +1356,7 @@ static int mem_acc_regulator_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id mem_acc_regulator_match_table[] = {
+static const struct of_device_id mem_acc_regulator_match_table[] = {
{ .compatible = "qcom,mem-acc-regulator", },
{}
};
diff --git a/drivers/regulator/msm_gfx_ldo.c b/drivers/regulator/msm_gfx_ldo.c
index 265ca9ed5258..c3e11b4caf9b 100644
--- a/drivers/regulator/msm_gfx_ldo.c
+++ b/drivers/regulator/msm_gfx_ldo.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -42,7 +42,7 @@
#define LDO_VREF_SET_REG 0x18
#define UPDATE_VREF_BIT BIT(31)
#define SEL_RST_BIT BIT(16)
-#define VREF_VAL_MASK GENMASK(6 , 0)
+#define VREF_VAL_MASK GENMASK(6, 0)
#define PWRSWITCH_CTRL_REG 0x1C
#define LDO_CLAMP_IO_BIT BIT(31)
@@ -95,9 +95,9 @@ enum voltage_handling {
};
struct fuse_param {
- unsigned row;
- unsigned bit_start;
- unsigned bit_end;
+ unsigned int row;
+ unsigned int bit_start;
+ unsigned int bit_end;
};
struct ldo_config {
@@ -186,6 +186,7 @@ static const int msm8953_fuse_ref_volt[MSM8953_LDO_FUSE_CORNERS] = {
enum {
MSM8953_SOC_ID,
SDM660_SOC_ID,
+ SDM630_SOC_ID,
};
static int convert_open_loop_voltage_fuse(int ref_volt, int step_volt,
@@ -665,7 +666,7 @@ static int switch_mode_to_bhs(struct msm_gfx_ldo *ldo_vreg)
}
static int msm_gfx_ldo_set_corner(struct regulator_dev *rdev,
- int corner, int corner_max, unsigned *selector)
+ int corner, int corner_max, unsigned int *selector)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
int rc = 0, mem_acc_corner, new_uv;
@@ -860,7 +861,7 @@ fail:
}
static int msm_gfx_ldo_set_voltage(struct regulator_dev *rdev,
- int new_uv, int max_uv, unsigned *selector)
+ int new_uv, int max_uv, unsigned int *selector)
{
struct msm_gfx_ldo *ldo_vreg = rdev_get_drvdata(rdev);
int rc = 0;
@@ -1444,22 +1445,22 @@ static void msm_gfx_ldo_debugfs_init(struct msm_gfx_ldo *ldo_vreg)
return;
}
- temp = debugfs_create_file("debug_info", S_IRUGO, ldo_vreg->debugfs,
+ temp = debugfs_create_file("debug_info", 0444, ldo_vreg->debugfs,
ldo_vreg, &msm_gfx_ldo_debug_info_fops);
if (IS_ERR_OR_NULL(temp)) {
pr_err("debug_info node creation failed\n");
return;
}
- temp = debugfs_create_file("ldo_voltage", S_IRUGO | S_IWUSR,
- ldo_vreg->debugfs, ldo_vreg, &ldo_voltage_fops);
+ temp = debugfs_create_file("ldo_voltage", 0644, ldo_vreg->debugfs,
+ ldo_vreg, &ldo_voltage_fops);
if (IS_ERR_OR_NULL(temp)) {
pr_err("ldo_voltage node creation failed\n");
return;
}
- temp = debugfs_create_file("ldo_mode_disable", S_IRUGO | S_IWUSR,
- ldo_vreg->debugfs, ldo_vreg, &ldo_mode_disable_fops);
+ temp = debugfs_create_file("ldo_mode_disable", 0644, ldo_vreg->debugfs,
+ ldo_vreg, &ldo_mode_disable_fops);
if (IS_ERR_OR_NULL(temp)) {
pr_err("ldo_mode_disable node creation failed\n");
return;
@@ -1519,6 +1520,10 @@ static const struct of_device_id msm_gfx_ldo_match_table[] = {
.compatible = "qcom,sdm660-gfx-ldo",
.data = (void *)(uintptr_t)SDM660_SOC_ID,
},
+ {
+ .compatible = "qcom,sdm630-gfx-ldo",
+ .data = (void *)(uintptr_t)SDM630_SOC_ID,
+ },
{}
};
@@ -1573,6 +1578,7 @@ static int msm_gfx_ldo_probe(struct platform_device *pdev)
}
break;
case SDM660_SOC_ID:
+ case SDM630_SOC_ID:
ldo_vreg->ldo_init_config = sdm660_ldo_config;
ldo_vreg->ops_type = VOLTAGE;
init_data->constraints.valid_ops_mask
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c
index 40c62c355188..cf8f00085a0c 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -2365,7 +2365,7 @@ static int qpnp_lab_regulator_is_enabled(struct regulator_dev *rdev)
}
static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
int rc, new_uV;
u8 val;
@@ -3282,7 +3282,7 @@ static int qpnp_ibb_regulator_is_enabled(struct regulator_dev *rdev)
}
static int qpnp_ibb_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
int rc = 0;
@@ -3648,12 +3648,10 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev)
u8 type, revision;
int rc = 0;
- labibb = devm_kzalloc(&pdev->dev,
- sizeof(struct qpnp_labibb), GFP_KERNEL);
- if (labibb == NULL) {
- pr_err("labibb allocation failed.\n");
+ labibb = devm_kzalloc(&pdev->dev, sizeof(*labibb), GFP_KERNEL);
+ if (labibb == NULL)
return -ENOMEM;
- }
+
labibb->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!labibb->regmap) {
dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
@@ -3849,7 +3847,7 @@ static int qpnp_labibb_regulator_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = QPNP_LABIBB_REGULATOR_DRIVER_NAME, },
{ },
};
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index daa4e8e74d5b..a08ade61e057 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -863,7 +863,7 @@ static int qpnp_lcdb_ldo_regulator_is_enabled(struct regulator_dev *rdev)
}
static int qpnp_lcdb_ldo_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
int rc = 0;
struct qpnp_lcdb *lcdb = rdev_get_drvdata(rdev);
@@ -934,7 +934,7 @@ static int qpnp_lcdb_ncp_regulator_is_enabled(struct regulator_dev *rdev)
}
static int qpnp_lcdb_ncp_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
int rc = 0;
struct qpnp_lcdb *lcdb = rdev_get_drvdata(rdev);
diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c
index 587538cca474..8d017fb55a3f 100644
--- a/drivers/regulator/qpnp-oledb-regulator.c
+++ b/drivers/regulator/qpnp-oledb-regulator.c
@@ -327,7 +327,7 @@ static int qpnp_oledb_regulator_is_enabled(struct regulator_dev *rdev)
}
static int qpnp_oledb_regulator_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
u8 val;
int rc = 0;
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index 17865857df03..bd706658348d 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -45,7 +45,7 @@ enum {
static int qpnp_vreg_debug_mask;
module_param_named(
- debug_mask, qpnp_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+ debug_mask, qpnp_vreg_debug_mask, int, 0600
);
#define vreg_err(vreg, fmt, ...) \
@@ -302,7 +302,7 @@ struct qpnp_voltage_range {
int step_uV;
int set_point_min_uV;
int set_point_max_uV;
- unsigned n_voltages;
+ unsigned int n_voltages;
u8 range_sel;
};
@@ -313,7 +313,7 @@ struct qpnp_voltage_range {
struct qpnp_voltage_set_points {
struct qpnp_voltage_range *range;
int count;
- unsigned n_voltages;
+ unsigned int n_voltages;
};
struct qpnp_regulator_mapping {
@@ -381,7 +381,7 @@ struct qpnp_regulator {
{ \
.range = _ranges, \
.count = ARRAY_SIZE(_ranges), \
-};
+}
/*
* These tables contain the physically available PMIC regulator voltage setpoint
@@ -730,7 +730,7 @@ static int qpnp_regulator_common_disable(struct regulator_dev *rdev)
*/
static int qpnp_regulator_select_voltage_same_range(struct qpnp_regulator *vreg,
int min_uV, int max_uV, int *range_sel, int *voltage_sel,
- unsigned *selector)
+ unsigned int *selector)
{
struct qpnp_voltage_range *range = NULL;
int uV = min_uV;
@@ -781,9 +781,9 @@ static int qpnp_regulator_select_voltage_same_range(struct qpnp_regulator *vreg,
(uV - vreg->set_points->range[i].set_point_min_uV)
/ vreg->set_points->range[i].step_uV;
break;
- } else {
- *selector += vreg->set_points->range[i].n_voltages;
}
+
+ *selector += vreg->set_points->range[i].n_voltages;
}
if (*selector >= vreg->set_points->n_voltages)
@@ -794,7 +794,7 @@ static int qpnp_regulator_select_voltage_same_range(struct qpnp_regulator *vreg,
static int qpnp_regulator_select_voltage(struct qpnp_regulator *vreg,
int min_uV, int max_uV, int *range_sel, int *voltage_sel,
- unsigned *selector)
+ unsigned int *selector)
{
struct qpnp_voltage_range *range;
int uV = min_uV;
@@ -872,7 +872,7 @@ static int qpnp_regulator_delay_for_slewing(struct qpnp_regulator *vreg,
}
static int qpnp_regulator_common_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
int rc, range_sel, voltage_sel, voltage_old = 0;
@@ -958,7 +958,7 @@ static int qpnp_regulator_common_get_voltage(struct regulator_dev *rdev)
}
static int qpnp_regulator_single_range_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
int rc, range_sel, voltage_sel;
@@ -995,7 +995,7 @@ static int qpnp_regulator_single_range_get_voltage(struct regulator_dev *rdev)
}
static int qpnp_regulator_ult_lo_smps_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
int rc, range_sel, voltage_sel;
@@ -1065,7 +1065,7 @@ static int qpnp_regulator_ult_lo_smps_get_voltage(struct regulator_dev *rdev)
}
static int qpnp_regulator_common_list_voltage(struct regulator_dev *rdev,
- unsigned selector)
+ unsigned int selector)
{
struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
int uV = 0;
@@ -1079,16 +1079,16 @@ static int qpnp_regulator_common_list_voltage(struct regulator_dev *rdev,
uV = selector * vreg->set_points->range[i].step_uV
+ vreg->set_points->range[i].set_point_min_uV;
break;
- } else {
- selector -= vreg->set_points->range[i].n_voltages;
}
+
+ selector -= vreg->set_points->range[i].n_voltages;
}
return uV;
}
static int qpnp_regulator_common2_set_voltage(struct regulator_dev *rdev,
- int min_uV, int max_uV, unsigned *selector)
+ int min_uV, int max_uV, unsigned int *selector)
{
struct qpnp_regulator *vreg = rdev_get_drvdata(rdev);
int rc, range_sel, voltage_sel, voltage_old = 0;
@@ -1280,8 +1280,6 @@ static void qpnp_regulator_vs_ocp_work(struct work_struct *work)
= container_of(dwork, struct qpnp_regulator, ocp_work);
qpnp_regulator_vs_clear_ocp(vreg);
-
- return;
}
static irqreturn_t qpnp_regulator_vs_ocp_isr(int irq, void *data)
@@ -1418,8 +1416,7 @@ static void qpnp_vreg_show_state(struct regulator_dev *rdev,
pc_mode_label[5] =
mode_reg & QPNP_COMMON_MODE_FOLLOW_HW_EN0_MASK ? '0' : '_';
- pr_info("%s %-11s: %s, v=%7d uV, mode=%s, pc_en=%s, "
- "alt_mode=%s\n",
+ pr_info("%s %-11s: %s, v=%7d uV, mode=%s, pc_en=%s, alt_mode=%s\n",
action_label, vreg->rdesc.name, enable_label, uV,
mode_label, pc_enable_label, pc_mode_label);
break;
@@ -1440,8 +1437,7 @@ static void qpnp_vreg_show_state(struct regulator_dev *rdev,
pc_mode_label[6] =
mode_reg & QPNP_COMMON_MODE_FOLLOW_HW_EN0_MASK ? '0' : '_';
- pr_info("%s %-11s: %s, v=%7d uV, mode=%s, pc_en=%s, "
- "alt_mode=%s\n",
+ pr_info("%s %-11s: %s, v=%7d uV, mode=%s, pc_en=%s, alt_mode=%s\n",
action_label, vreg->rdesc.name, enable_label, uV,
mode_label, pc_enable_label, pc_mode_label);
break;
@@ -2165,7 +2161,7 @@ static int qpnp_regulator_get_dt_config(struct platform_device *pdev,
return rc;
}
-static struct of_device_id spmi_match_table[];
+static const struct of_device_id spmi_match_table[];
#define MAX_NAME_LEN 127
@@ -2256,8 +2252,6 @@ static int qpnp_regulator_probe(struct platform_device *pdev)
reg_name = kzalloc(strnlen(pdata->init_data.constraints.name,
MAX_NAME_LEN) + 1, GFP_KERNEL);
if (!reg_name) {
- dev_err(&pdev->dev, "%s: Can't allocate regulator name\n",
- __func__);
kfree(vreg);
return -ENOMEM;
}
@@ -2362,7 +2356,7 @@ static int qpnp_regulator_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = QPNP_REGULATOR_DRIVER_NAME, },
{}
};
@@ -2422,8 +2416,7 @@ int __init qpnp_regulator_init(void)
if (has_registered)
return 0;
- else
- has_registered = true;
+ has_registered = true;
qpnp_regulator_set_point_init();
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ef3ff5e16e86..50ca3c33f942 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1592,13 +1592,13 @@ config RTC_DRV_MOXART
will be called rtc-moxart
config RTC_DRV_QPNP
- tristate "Qualcomm QPNP PMIC RTC"
- depends on SPMI && OF_SPMI && MSM_QPNP_INT
+ tristate "Qualcomm Technologies, Inc. QPNP PMIC RTC"
+ depends on SPMI
help
- Say Y here if you want to support the Qualcomm QPNP PMIC RTC.
-
- To compile this driver as a module, choose M here: the
- module will be called qpnp-rtc.
+ This enables support for the RTC found on Qualcomm Technologies, Inc.
+ QPNP PMIC chips. This driver supports using the PMIC RTC peripheral
+ to wake a mobile device up from suspend or to wake it up from power-
+ off.
config RTC_DRV_MT6397
tristate "Mediatek Real Time Clock driver"
@@ -1610,15 +1610,6 @@ config RTC_DRV_MT6397
If you want to use Mediatek(R) RTC interface, select Y or M here.
-config RTC_DRV_QPNP
- tristate "Qualcomm QPNP PMIC RTC"
- depends on SPMI
- help
- Say Y here if you want to support the Qualcomm QPNP PMIC RTC.
-
- To compile this driver as a module, choose M here: the
- module will be called qpnp-rtc.
-
config RTC_DRV_XGENE
tristate "APM X-Gene RTC"
depends on HAS_IOMEM
diff --git a/drivers/rtc/qpnp-rtc.c b/drivers/rtc/qpnp-rtc.c
index 1b74b94796ba..a2c004e0f7fd 100644
--- a/drivers/rtc/qpnp-rtc.c
+++ b/drivers/rtc/qpnp-rtc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 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
@@ -50,9 +50,9 @@
/* Module parameter to control power-on-alarm */
bool poweron_alarm;
+EXPORT_SYMBOL(poweron_alarm);
module_param(poweron_alarm, bool, 0644);
MODULE_PARM_DESC(poweron_alarm, "Enable/Disable power-on alarm");
-EXPORT_SYMBOL(poweron_alarm);
/* rtc driver internal structure */
struct qpnp_rtc {
@@ -138,7 +138,7 @@ qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)
* | BYTE[3] | BYTE[2] | BYTE[1] | BYTE[0] |
* ----------------------------------------------
*
- * RTC has four 8 bit registers for writting time in seconds:
+ * RTC has four 8 bit registers for writing time in seconds:
* WDATA[3], WDATA[2], WDATA[1], WDATA[0]
*
* Write to the RTC registers should be done in following order
@@ -149,7 +149,7 @@ qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)
*
* Write BYTE[0] of time to RTC WDATA[0] register
*
- * Clearing BYTE[0] and writting in the end will prevent any
+ * Clearing BYTE[0] and writing in the end will prevent any
* unintentional overflow from WDATA[0] to higher bytes during the
* write operation
*/
@@ -162,9 +162,8 @@ qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)
rc = qpnp_write_wrapper(rtc_dd, &rtc_ctrl_reg,
rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
if (rc) {
- dev_err(dev,
- "Disabling of RTC control reg failed"
- " with error:%d\n", rc);
+ dev_err(dev, "Disabling of RTC control reg failed with error:%d\n",
+ rc);
goto rtc_rw_fail;
}
rtc_dd->rtc_ctrl_reg = rtc_ctrl_reg;
@@ -201,9 +200,8 @@ qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)
rc = qpnp_write_wrapper(rtc_dd, &rtc_ctrl_reg,
rtc_dd->rtc_base + REG_OFFSET_RTC_CTRL, 1);
if (rc) {
- dev_err(dev,
- "Enabling of RTC control reg failed"
- " with error:%d\n", rc);
+ dev_err(dev, "Enabling of RTC control reg failed with error:%d\n",
+ rc);
goto rtc_rw_fail;
}
rtc_dd->rtc_ctrl_reg = rtc_ctrl_reg;
@@ -417,11 +415,19 @@ rtc_rw_fail:
return rc;
}
-static struct rtc_class_ops qpnp_rtc_ops = {
+static const struct rtc_class_ops qpnp_rtc_ro_ops = {
+ .read_time = qpnp_rtc_read_time,
+ .set_alarm = qpnp_rtc_set_alarm,
+ .read_alarm = qpnp_rtc_read_alarm,
+ .alarm_irq_enable = qpnp_rtc_alarm_irq_enable,
+};
+
+static const struct rtc_class_ops qpnp_rtc_rw_ops = {
.read_time = qpnp_rtc_read_time,
.set_alarm = qpnp_rtc_set_alarm,
.read_alarm = qpnp_rtc_read_alarm,
.alarm_irq_enable = qpnp_rtc_alarm_irq_enable,
+ .set_time = qpnp_rtc_set_time,
};
static irqreturn_t qpnp_alarm_trigger(int irq, void *dev_id)
@@ -465,6 +471,7 @@ rtc_alarm_handled:
static int qpnp_rtc_probe(struct platform_device *pdev)
{
+ const struct rtc_class_ops *rtc_ops = &qpnp_rtc_ro_ops;
int rc;
u8 subtype;
struct qpnp_rtc *rtc_dd;
@@ -578,13 +585,13 @@ static int qpnp_rtc_probe(struct platform_device *pdev)
}
if (rtc_dd->rtc_write_enable == true)
- qpnp_rtc_ops.set_time = qpnp_rtc_set_time;
+ rtc_ops = &qpnp_rtc_rw_ops;
dev_set_drvdata(&pdev->dev, rtc_dd);
/* Register the RTC device */
rtc_dd->rtc = rtc_device_register("qpnp_rtc", &pdev->dev,
- &qpnp_rtc_ops, THIS_MODULE);
+ rtc_ops, THIS_MODULE);
if (IS_ERR(rtc_dd->rtc)) {
dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",
__func__, PTR_ERR(rtc_dd->rtc));
@@ -676,7 +683,7 @@ fail_alarm_disable:
}
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{
.compatible = "qcom,qpnp-rtc",
},
@@ -707,4 +714,4 @@ static void __exit qpnp_rtc_exit(void)
module_exit(qpnp_rtc_exit);
MODULE_DESCRIPTION("SMPI PMIC RTC driver");
-MODULE_LICENSE("GPL V2");
+MODULE_LICENSE("GPL v2");
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 4a315d8f5534..d3f1050499f3 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -37,12 +37,14 @@ config MSM_SMEM
inter-processor communication.
config QPNP_HAPTIC
- tristate "Haptic support for QPNP PMIC"
+ tristate "Haptic support for QPNP PMIC"
depends on ARCH_QCOM
- help
- This option enables device driver support for the Haptic
- on the Qualcomm Technologies' QPNP PMICs. It uses the android
- timed-output framework.
+ help
+ This option enables device driver support for the haptic peripheral
+ found on Qualcomm Technologies, Inc. QPNP PMICs. The haptic
+ peripheral is capable of driving both LRA and ERM vibrators. This
+ module provides haptic feedback for user actions such as a long press
+ on the touch screen. It uses the Android timed-output framework.
config MSM_SMD
depends on MSM_SMEM
@@ -863,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/icnss.c b/drivers/soc/qcom/icnss.c
index 16ee98d8e4e0..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)
@@ -181,6 +162,7 @@ enum icnss_driver_event_type {
struct icnss_event_pd_service_down_data {
bool crashed;
bool fw_rejuvenate;
+ bool wdog_bite;
};
struct icnss_driver_event {
@@ -205,6 +187,7 @@ enum icnss_driver_state {
ICNSS_PD_RESTART,
ICNSS_MSA0_ASSIGNED,
ICNSS_WLFW_EXISTS,
+ ICNSS_WDOG_BITE,
};
struct ce_irq_list {
@@ -334,6 +317,7 @@ static struct icnss_priv {
struct ramdump_device *msa0_dump_dev;
bool is_wlan_mac_set;
struct icnss_wlan_mac_addr wlan_mac_addr;
+ bool bypass_s1_smmu;
} *penv;
static void icnss_pm_stay_awake(struct icnss_priv *priv)
@@ -1339,7 +1323,7 @@ static int wlfw_athdiag_read_send_sync_msg(struct icnss_priv *priv,
goto out;
}
- if (!resp->data_valid || resp->data_len <= data_len) {
+ if (!resp->data_valid || resp->data_len < data_len) {
icnss_pr_err("Athdiag read data is invalid, data_valid = %u, data_len = %u\n",
resp->data_valid, resp->data_len);
ret = -EINVAL;
@@ -1700,6 +1684,23 @@ static int icnss_driver_event_server_exit(void *data)
return 0;
}
+static int icnss_call_driver_uevent(struct icnss_priv *priv,
+ enum icnss_uevent uevent, void *data)
+{
+ struct icnss_uevent_data uevent_data;
+
+ if (!priv->ops || !priv->ops->uevent)
+ return 0;
+
+ icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n",
+ priv->state, uevent);
+
+ uevent_data.uevent = uevent;
+ uevent_data.data = data;
+
+ return priv->ops->uevent(&priv->pdev->dev, &uevent_data);
+}
+
static int icnss_call_driver_probe(struct icnss_priv *priv)
{
int ret;
@@ -1724,20 +1725,44 @@ static int icnss_call_driver_probe(struct icnss_priv *priv)
out:
icnss_hw_power_off(priv);
- penv->ops = NULL;
return ret;
}
-static int icnss_call_driver_reinit(struct icnss_priv *priv)
+static int icnss_call_driver_shutdown(struct icnss_priv *priv)
{
- int ret = 0;
+ if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
+ goto out;
- if (!priv->ops || !priv->ops->reinit)
+ if (!priv->ops || !priv->ops->shutdown)
goto out;
- if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
+ icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
+
+ priv->ops->shutdown(&priv->pdev->dev);
+
+out:
+ return 0;
+}
+
+static int icnss_pd_restart_complete(struct icnss_priv *priv)
+{
+ int ret;
+
+ icnss_pm_relax(priv);
+
+ if (test_bit(ICNSS_WDOG_BITE, &priv->state)) {
+ icnss_call_driver_shutdown(priv);
+ clear_bit(ICNSS_WDOG_BITE, &priv->state);
+ }
+
+ clear_bit(ICNSS_PD_RESTART, &priv->state);
+
+ if (!priv->ops || !priv->ops->reinit)
goto out;
+ if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
+ goto call_probe;
+
icnss_pr_dbg("Calling driver reinit state: 0x%lx\n", priv->state);
icnss_hw_power_on(priv);
@@ -1751,18 +1776,14 @@ static int icnss_call_driver_reinit(struct icnss_priv *priv)
}
out:
- clear_bit(ICNSS_PD_RESTART, &priv->state);
-
- icnss_pm_relax(priv);
-
return 0;
+call_probe:
+ return icnss_call_driver_probe(priv);
+
out_power_off:
icnss_hw_power_off(priv);
- clear_bit(ICNSS_PD_RESTART, &priv->state);
-
- icnss_pm_relax(priv);
return ret;
}
@@ -1776,6 +1797,8 @@ static int icnss_driver_event_fw_ready_ind(void *data)
set_bit(ICNSS_FW_READY, &penv->state);
+ icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_READY, NULL);
+
icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state);
icnss_hw_power_off(penv);
@@ -1787,7 +1810,7 @@ static int icnss_driver_event_fw_ready_ind(void *data)
}
if (test_bit(ICNSS_PD_RESTART, &penv->state))
- ret = icnss_call_driver_reinit(penv);
+ ret = icnss_pd_restart_complete(penv);
else
ret = icnss_call_driver_probe(penv);
@@ -1875,23 +1898,30 @@ static int icnss_call_driver_remove(struct icnss_priv *priv)
return 0;
}
-static int icnss_call_driver_shutdown(struct icnss_priv *priv)
+static int icnss_fw_crashed(struct icnss_priv *priv,
+ struct icnss_event_pd_service_down_data *event_data)
{
- icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
+ icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n",
+ priv->state, event_data->wdog_bite);
set_bit(ICNSS_PD_RESTART, &priv->state);
clear_bit(ICNSS_FW_READY, &priv->state);
icnss_pm_stay_awake(priv);
- if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
- return 0;
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
- if (!priv->ops || !priv->ops->shutdown)
- return 0;
+ if (event_data->wdog_bite) {
+ set_bit(ICNSS_WDOG_BITE, &priv->state);
+ goto out;
+ }
- priv->ops->shutdown(&priv->pdev->dev);
+ icnss_call_driver_shutdown(priv);
+ if (event_data->fw_rejuvenate)
+ wlfw_rejuvenate_ack_send_sync_msg(priv);
+
+out:
return 0;
}
@@ -1912,13 +1942,10 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
}
if (event_data->crashed)
- icnss_call_driver_shutdown(priv);
+ icnss_fw_crashed(priv, event_data);
else
icnss_call_driver_remove(priv);
- if (event_data->fw_rejuvenate)
- wlfw_rejuvenate_ack_send_sync_msg(priv);
-
out:
ret = icnss_hw_power_off(priv);
@@ -2065,7 +2092,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
if (test_bit(ICNSS_PDR_ENABLED, &priv->state))
return NOTIFY_OK;
- icnss_pr_info("Modem went down, state: %lx\n", priv->state);
+ icnss_pr_info("Modem went down, state: %lx, crashed: %d\n",
+ priv->state, notif->crashed);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
@@ -2074,6 +2102,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
event_data->crashed = notif->crashed;
+ if (notif->crashed == CRASH_STATUS_WDOG_BITE)
+ event_data->wdog_bite = true;
+
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
@@ -2138,30 +2169,41 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
enum pd_subsys_state *state = data;
struct icnss_event_pd_service_down_data *event_data;
- switch (notification) {
- case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
- icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data,
- priv->state);
- event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
+ icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
+ notification, priv->state);
- if (event_data == NULL)
- return notifier_from_errno(-ENOMEM);
+ if (notification != SERVREG_NOTIF_SERVICE_STATE_DOWN_V01)
+ goto done;
+
+ event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
- if (state == NULL || *state != SHUTDOWN)
- event_data->crashed = true;
+ if (event_data == NULL)
+ return notifier_from_errno(-ENOMEM);
- icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
- ICNSS_EVENT_SYNC, event_data);
+ if (state == NULL) {
+ event_data->crashed = true;
+ goto event_post;
+ }
+
+ icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n",
+ *state, priv->state);
+
+ switch (*state) {
+ case ROOT_PD_WDOG_BITE:
+ event_data->crashed = true;
+ event_data->wdog_bite = true;
break;
- case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
- icnss_pr_dbg("Service up, state: 0x%lx\n", priv->state);
+ case ROOT_PD_SHUTDOWN:
break;
default:
- icnss_pr_dbg("Service state Unknown, notification: 0x%lx, state: 0x%lx\n",
- notification, priv->state);
- return NOTIFY_DONE;
+ event_data->crashed = true;
+ break;
}
+event_post:
+ icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
+ ICNSS_EVENT_SYNC, event_data);
+done:
return NOTIFY_OK;
}
@@ -2916,13 +2958,15 @@ static int icnss_smmu_init(struct icnss_priv *priv)
goto map_fail;
}
- ret = iommu_domain_set_attr(mapping->domain,
- DOMAIN_ATTR_ATOMIC,
- &atomic_ctx);
- if (ret < 0) {
- icnss_pr_err("Set atomic_ctx attribute failed, err = %d\n",
- ret);
- goto set_attr_fail;
+ if (!priv->bypass_s1_smmu) {
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_ATOMIC,
+ &atomic_ctx);
+ if (ret < 0) {
+ icnss_pr_err("Set atomic_ctx attribute failed, err = %d\n",
+ ret);
+ goto set_attr_fail;
+ }
}
ret = iommu_domain_set_attr(mapping->domain,
@@ -3225,6 +3269,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_WLFW_EXISTS:
seq_puts(s, "WLAN FW EXISTS");
continue;
+ case ICNSS_WDOG_BITE:
+ seq_puts(s, "MODEM WDOG BITE");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
@@ -3668,6 +3715,11 @@ static int icnss_probe(struct platform_device *pdev)
if (ret == -EPROBE_DEFER)
goto out;
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass"))
+ priv->bypass_s1_smmu = true;
+
+ icnss_pr_dbg("SMMU S1 BYPASS = %d\n", priv->bypass_s1_smmu);
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");
if (!res) {
icnss_pr_err("Memory base not found in DT\n");
@@ -3963,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,
@@ -3990,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);
}
@@ -4000,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/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c
index 76f9ed046120..b8417513ca55 100644
--- a/drivers/soc/qcom/memshare/msm_memshare.c
+++ b/drivers/soc/qcom/memshare/msm_memshare.c
@@ -327,7 +327,7 @@ static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
int ret;
u32 source_vmlist[2] = {VMID_HLOS, VMID_MSS_MSA};
int dest_vmids[1] = {VMID_HLOS};
- int dest_perms[1] = {PERM_READ|PERM_WRITE};
+ int dest_perms[1] = {PERM_READ|PERM_WRITE|PERM_EXEC};
struct notif_data *notifdata = NULL;
mutex_lock(&memsh_drv->mem_share);
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/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/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c
index 21387568fe53..39070561d7e4 100644
--- a/drivers/soc/qcom/qpnp-haptic.c
+++ b/drivers/soc/qcom/qpnp-haptic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -918,15 +918,16 @@ static ssize_t qpnp_hap_wf_samp_store(struct device *dev,
struct timed_output_dev *timed_dev = dev_get_drvdata(dev);
struct qpnp_hap *hap = container_of(timed_dev, struct qpnp_hap,
timed_dev);
- int data;
+ int data, rc;
if (index < 0 || index >= QPNP_HAP_WAV_SAMP_LEN) {
dev_err(dev, "Invalid sample index(%d)\n", index);
return -EINVAL;
}
- if (sscanf(buf, "%x", &data) != 1)
- return -EINVAL;
+ rc = kstrtoint(buf, 16, &data);
+ if (rc)
+ return rc;
if (data < 0 || data > 0xff) {
dev_err(dev, "Invalid sample wf_%d (%d)\n", index, data);
@@ -1032,8 +1033,9 @@ static ssize_t qpnp_hap_wf_rep_store(struct device *dev,
int data, rc, temp;
u8 reg;
- if (sscanf(buf, "%d", &data) != 1)
- return -EINVAL;
+ rc = kstrtoint(buf, 10, &data);
+ if (rc)
+ return rc;
if (data < QPNP_HAP_WAV_REP_MIN)
data = QPNP_HAP_WAV_REP_MIN;
@@ -1078,8 +1080,9 @@ static ssize_t qpnp_hap_wf_s_rep_store(struct device *dev,
int data, rc, temp;
u8 reg;
- if (sscanf(buf, "%d", &data) != 1)
- return -EINVAL;
+ rc = kstrtoint(buf, 10, &data);
+ if (rc)
+ return rc;
if (data < QPNP_HAP_WAV_S_REP_MIN)
data = QPNP_HAP_WAV_S_REP_MIN;
@@ -1290,51 +1293,25 @@ static ssize_t qpnp_hap_ramp_test_data_show(struct device *dev,
/* sysfs attributes */
static struct device_attribute qpnp_hap_attrs[] = {
- __ATTR(wf_s0, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s0_show,
- qpnp_hap_wf_s0_store),
- __ATTR(wf_s1, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s1_show,
- qpnp_hap_wf_s1_store),
- __ATTR(wf_s2, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s2_show,
- qpnp_hap_wf_s2_store),
- __ATTR(wf_s3, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s3_show,
- qpnp_hap_wf_s3_store),
- __ATTR(wf_s4, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s4_show,
- qpnp_hap_wf_s4_store),
- __ATTR(wf_s5, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s5_show,
- qpnp_hap_wf_s5_store),
- __ATTR(wf_s6, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s6_show,
- qpnp_hap_wf_s6_store),
- __ATTR(wf_s7, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s7_show,
- qpnp_hap_wf_s7_store),
- __ATTR(wf_update, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_update_show,
- qpnp_hap_wf_update_store),
- __ATTR(wf_rep, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_rep_show,
- qpnp_hap_wf_rep_store),
- __ATTR(wf_s_rep, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_wf_s_rep_show,
- qpnp_hap_wf_s_rep_store),
- __ATTR(play_mode, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_play_mode_show,
- qpnp_hap_play_mode_store),
- __ATTR(dump_regs, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_dump_regs_show,
- NULL),
- __ATTR(ramp_test, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_ramp_test_data_show,
- qpnp_hap_ramp_test_data_store),
- __ATTR(min_max_test, (S_IRUGO | S_IWUSR | S_IWGRP),
- qpnp_hap_min_max_test_data_show,
- qpnp_hap_min_max_test_data_store),
+ __ATTR(wf_s0, 0664, qpnp_hap_wf_s0_show, qpnp_hap_wf_s0_store),
+ __ATTR(wf_s1, 0664, qpnp_hap_wf_s1_show, qpnp_hap_wf_s1_store),
+ __ATTR(wf_s2, 0664, qpnp_hap_wf_s2_show, qpnp_hap_wf_s2_store),
+ __ATTR(wf_s3, 0664, qpnp_hap_wf_s3_show, qpnp_hap_wf_s3_store),
+ __ATTR(wf_s4, 0664, qpnp_hap_wf_s4_show, qpnp_hap_wf_s4_store),
+ __ATTR(wf_s5, 0664, qpnp_hap_wf_s5_show, qpnp_hap_wf_s5_store),
+ __ATTR(wf_s6, 0664, qpnp_hap_wf_s6_show, qpnp_hap_wf_s6_store),
+ __ATTR(wf_s7, 0664, qpnp_hap_wf_s7_show, qpnp_hap_wf_s7_store),
+ __ATTR(wf_update, 0664, qpnp_hap_wf_update_show,
+ qpnp_hap_wf_update_store),
+ __ATTR(wf_rep, 0664, qpnp_hap_wf_rep_show, qpnp_hap_wf_rep_store),
+ __ATTR(wf_s_rep, 0664, qpnp_hap_wf_s_rep_show, qpnp_hap_wf_s_rep_store),
+ __ATTR(play_mode, 0664, qpnp_hap_play_mode_show,
+ qpnp_hap_play_mode_store),
+ __ATTR(dump_regs, 0664, qpnp_hap_dump_regs_show, NULL),
+ __ATTR(ramp_test, 0664, qpnp_hap_ramp_test_data_show,
+ qpnp_hap_ramp_test_data_store),
+ __ATTR(min_max_test, 0664, qpnp_hap_min_max_test_data_show,
+ qpnp_hap_min_max_test_data_store),
};
static void calculate_lra_code(struct qpnp_hap *hap)
@@ -1420,13 +1397,13 @@ static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer)
if (val & AUTO_RES_ERR_BIT) {
schedule_work(&hap->auto_res_err_work);
return HRTIMER_NORESTART;
- } else {
- update_lra_frequency(hap);
- currtime = ktime_get();
- hrtimer_forward(&hap->auto_res_err_poll_timer, currtime,
- ktime_set(0, POLL_TIME_AUTO_RES_ERR_NS));
- return HRTIMER_RESTART;
}
+
+ update_lra_frequency(hap);
+ currtime = ktime_get();
+ hrtimer_forward(&hap->auto_res_err_poll_timer, currtime,
+ ktime_set(0, POLL_TIME_AUTO_RES_ERR_NS));
+ return HRTIMER_RESTART;
}
static void correct_auto_res_error(struct work_struct *auto_res_err_work)
@@ -1595,19 +1572,23 @@ int qpnp_hap_play_byte(u8 data, bool on)
return rc;
if (!on) {
- /* set the pwm back to original duty for normal operations */
- /* this is not required if standard interface is not used */
+ /*
+ * Set the pwm back to original duty for normal operations.
+ * This is not required if standard interface is not used.
+ */
rc = pwm_config(hap->pwm_info.pwm_dev,
hap->pwm_info.duty_us * NSEC_PER_USEC,
hap->pwm_info.period_us * NSEC_PER_USEC);
return rc;
}
- /* pwm values range from 0x00 to 0xff. The range from 0x00 to 0x7f
- provides a postive amplitude in the sin wave form for 0 to 100%.
- The range from 0x80 to 0xff provides a negative amplitude in the
- sin wave form for 0 to 100%. Here the duty percentage is calculated
- based on the incoming data to accommodate this. */
+ /*
+ * pwm values range from 0x00 to 0xff. The range from 0x00 to 0x7f
+ * provides a postive amplitude in the sin wave form for 0 to 100%.
+ * The range from 0x80 to 0xff provides a negative amplitude in the
+ * sin wave form for 0 to 100%. Here the duty percentage is calculated
+ * based on the incoming data to accommodate this.
+ */
if (data <= QPNP_HAP_EXT_PWM_PEAK_DATA)
duty_percent = QPNP_HAP_EXT_PWM_HALF_DUTY +
((data * QPNP_HAP_EXT_PWM_DATA_FACTOR) / 100);
@@ -1675,6 +1656,7 @@ static int qpnp_hap_get_time(struct timed_output_dev *dev)
if (hrtimer_active(&hap->hap_timer)) {
ktime_t r = hrtimer_get_remaining(&hap->hap_timer);
+
return (int)ktime_to_us(r);
} else {
return 0;
@@ -1709,6 +1691,7 @@ static enum hrtimer_restart qpnp_hap_test_timer(struct hrtimer *timer)
static int qpnp_haptic_suspend(struct device *dev)
{
struct qpnp_hap *hap = dev_get_drvdata(dev);
+
hrtimer_cancel(&hap->hap_timer);
cancel_work_sync(&hap->work);
/* turn-off haptic */
@@ -1845,9 +1828,11 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
if (rc)
return rc;
- /* Configure RATE_CFG1 and RATE_CFG2 registers */
- /* Note: For ERM these registers act as play rate and
- for LRA these represent resonance period */
+ /*
+ * Configure RATE_CFG1 and RATE_CFG2 registers.
+ * Note: For ERM these registers act as play rate and
+ * for LRA these represent resonance period
+ */
if (hap->wave_play_rate_us < QPNP_HAP_WAV_PLAY_RATE_US_MIN)
hap->wave_play_rate_us = QPNP_HAP_WAV_PLAY_RATE_US_MIN;
else if (hap->wave_play_rate_us > QPNP_HAP_WAV_PLAY_RATE_US_MAX)
@@ -2314,7 +2299,7 @@ static int qpnp_haptic_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id spmi_match_table[] = {
+static const struct of_device_id spmi_match_table[] = {
{ .compatible = "qcom,qpnp-haptic", },
{ },
};
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/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index 8a501d4d0615..85ff81ff475c 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -229,6 +229,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle,
struct msg_desc ind_desc;
struct qmi_servreg_notif_state_updated_ind_msg_v01 ind_msg = {
QMI_STATE_MIN_VAL, "", 0xFFFF };
+ enum pd_subsys_state state = USER_PD_STATE_CHANGE;
int rc;
ind_desc.msg_id = SERVREG_NOTIF_STATE_UPDATED_IND_MSG;
@@ -256,7 +257,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle,
mutex_lock(&notif_add_lock);
mutex_lock(&service_list_lock);
rc = service_notif_queue_notification(service_notif,
- ind_msg.curr_state, NULL);
+ ind_msg.curr_state, &state);
if (rc & NOTIFY_STOP_MASK)
pr_err("Notifier callback aborted for %s with error %d\n",
ind_msg.service_name, rc);
@@ -373,6 +374,7 @@ static void root_service_service_arrive(struct work_struct *work)
mutex_lock(&service_list_lock);
list_for_each_entry(service_notif, &service_list, list) {
if (service_notif->instance_id == data->instance_id) {
+ enum pd_subsys_state state = ROOT_PD_UP;
rc = register_notif_listener(service_notif, data,
&curr_state);
if (rc) {
@@ -380,7 +382,7 @@ static void root_service_service_arrive(struct work_struct *work)
service_notif->service_path, rc);
} else {
rc = service_notif_queue_notification(
- service_notif, curr_state, NULL);
+ service_notif, curr_state, &state);
if (rc & NOTIFY_STOP_MASK)
pr_err("Notifier callback aborted for %s error:%d\n",
service_notif->service_path, rc);
@@ -434,7 +436,7 @@ static void root_service_exit_work(struct work_struct *work)
{
struct qmi_client_info *data = container_of(work,
struct qmi_client_info, svc_exit);
- root_service_service_exit(data, UNKNOWN);
+ root_service_service_exit(data, ROOT_PD_DOWN);
}
static int service_event_notify(struct notifier_block *this,
@@ -466,14 +468,24 @@ static int ssr_event_notify(struct notifier_block *this,
struct qmi_client_info *info = container_of(this,
struct qmi_client_info, ssr_notifier);
struct notif_data *notif = data;
+ enum pd_subsys_state state;
+
switch (code) {
case SUBSYS_BEFORE_SHUTDOWN:
- pr_debug("Root PD DOWN(SSR notification), crashed?%d\n",
+ pr_debug("Root PD DOWN(SSR notification), state:%d\n",
notif->crashed);
- if (notif->crashed)
- root_service_service_exit(info, CRASHED);
- else
- root_service_service_exit(info, SHUTDOWN);
+ switch (notif->crashed) {
+ case CRASH_STATUS_ERR_FATAL:
+ state = ROOT_PD_ERR_FATAL;
+ break;
+ case CRASH_STATUS_WDOG_BITE:
+ state = ROOT_PD_WDOG_BITE;
+ break;
+ default:
+ state = ROOT_PD_SHUTDOWN;
+ break;
+ }
+ root_service_service_exit(info, state);
break;
default:
break;
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index d91daa6a3456..35ccc57a2dea 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -276,6 +276,7 @@ static void spcom_notify_rx_abort(void *handle, const void *priv,
const void *pkt_priv);
static struct spcom_channel *spcom_find_channel_by_name(const char *name);
static int spcom_unlock_ion_buf(struct spcom_channel *ch, int fd);
+static void spcom_rx_abort_pending_server(void);
/**
* spcom_is_ready() - driver is initialized and ready.
@@ -381,6 +382,9 @@ static void spcom_link_state_notif_cb(struct glink_link_state_cb_info *cb_info,
pr_err("failed to find channel [%s].\n", ch_name);
else
spcom_unlock_ion_buf(ch, SPCOM_ION_FD_UNLOCK_ALL);
+
+ pr_debug("Rx-Abort pending servers.\n");
+ spcom_rx_abort_pending_server();
break;
default:
pr_err("unknown link_state [%d].\n", cb_info->link_state);
@@ -546,7 +550,7 @@ static void spcom_notify_rx_abort(void *handle, const void *priv,
pr_debug("ch [%s] pending rx aborted.\n", ch->name);
- if (spcom_is_channel_connected(ch) && (!ch->rx_abort)) {
+ if (spcom_is_channel_open(ch) && (!ch->rx_abort)) {
ch->rx_abort = true;
complete_all(&ch->rx_done);
}
@@ -949,6 +953,13 @@ static int spcom_get_next_request_size(struct spcom_channel *ch)
pr_debug("Wait for Rx Done, ch [%s].\n", ch->name);
wait_for_completion(&ch->rx_done);
+
+ /* Check Rx Abort on SP reset */
+ if (ch->rx_abort) {
+ pr_err("rx aborted.\n");
+ goto exit_error;
+ }
+
if (ch->actual_rx_size <= 0) {
pr_err("invalid rx size [%d] ch [%s].\n",
ch->actual_rx_size, ch->name);
@@ -974,6 +985,27 @@ exit_error:
}
+/**
+ * spcom_rx_abort_pending_server() - abort pending server rx on SSR.
+ *
+ * Server that is waiting for request, but has no client connected,
+ * will not get RX-ABORT or REMOTE-DISCONNECT notification,
+ * that should cancel the server pending rx operation.
+ */
+static void spcom_rx_abort_pending_server(void)
+{
+ int i;
+
+ for (i = 0 ; i < ARRAY_SIZE(spcom_dev->channels); i++) {
+ struct spcom_channel *ch = &spcom_dev->channels[i];
+
+ if (ch->is_server) {
+ pr_debug("rx-abort server on ch [%s].\n", ch->name);
+ spcom_notify_rx_abort(NULL, ch, NULL);
+ }
+ }
+}
+
/*======================================================================*/
/* General API for kernel drivers */
/*======================================================================*/
@@ -1944,8 +1976,8 @@ static int spcom_handle_read(struct spcom_channel *ch,
{
if (size == SPCOM_GET_NEXT_REQUEST_SIZE) {
pr_debug("get next request size, ch [%s].\n", ch->name);
- size = spcom_handle_get_req_size(ch, buf, size);
ch->is_server = true;
+ size = spcom_handle_get_req_size(ch, buf, size);
} else {
pr_debug("get request/response, ch [%s].\n", ch->name);
size = spcom_handle_read_req_resp(ch, buf, size);
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index 424ad7c57b43..63bc3961de3b 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.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
@@ -65,6 +65,8 @@ struct usecase uc[] = {
{6, 10, 7800}, /* UC15: 2*(Spkr + SB + VI) */
{2, 3, 3600}, /* UC16: Spkr + VI */
{4, 6, 7200}, /* UC17: 2*(Spkr + VI) */
+ {3, 7, 4200}, /* UC18: Spkr + Comp + VI */
+ {6, 14, 8400}, /* UC19: 2*(Spkr + Comp + VI) */
};
#define MAX_USECASE ARRAY_SIZE(uc)
@@ -179,6 +181,21 @@ struct port_params pp[MAX_USECASE][SWR_MSTR_PORT_LEN] = {
{7, 6, 0},
{15, 10, 0},
},
+ /* UC 18 */
+ {
+ {7, 1, 0},
+ {31, 2, 0},
+ {15, 7, 0},
+ },
+ /* UC 19 */
+ {
+ {7, 1, 0},
+ {31, 2, 0},
+ {15, 7, 0},
+ {7, 6, 0},
+ {31, 18, 0},
+ {15, 10, 0},
+ },
};
enum {
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/thermal/Kconfig b/drivers/thermal/Kconfig
index b8360383a6d2..aa122340c717 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -406,19 +406,18 @@ config INTEL_PCH_THERMAL
programmable trip points and other information.
config THERMAL_QPNP
- tristate "Qualcomm Plug-and-Play PMIC Temperature Alarm"
- depends on THERMAL
- depends on OF
- depends on SPMI
- help
- This enables a thermal Sysfs driver for Qualcomm plug-and-play (QPNP)
- PMIC devices. It shows up in Sysfs as a thermal zone with multiple
- trip points. The temperature reported by the thermal zone reflects the
- real time die temperature if an ADC is present or an estimate of the
- temperature based upon the over temperature stage value if no ADC is
- available. If allowed via compile time configuration; enabling the
- thermal zone device via the mode file results in shifting PMIC over
- temperature shutdown control from hardware to software.
+ tristate "Qualcomm Technologies, Inc. QPNP PMIC Temperature Alarm"
+ depends on OF && SPMI
+ help
+ This enables a thermal Sysfs driver for Qualcomm Technologies, Inc.
+ QPNP PMIC devices. It shows up in Sysfs as a thermal zone with
+ multiple trip points. The temperature reported by the thermal zone
+ reflects the real time die temperature if an ADC is present or an
+ estimate of the temperature based upon the over temperature stage
+ value if no ADC is available. If allowed via compile time
+ configuration; enabling the thermal zone device via the mode file
+ results in shifting PMIC over temperature shutdown control from
+ hardware to software.
config THERMAL_QPNP_ADC_TM
tristate "Qualcomm 8974 Thermal Monitor ADC Driver"
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 7c75f740a204..cc232ff9be9a 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -1134,6 +1134,14 @@ static void update_cpu_freq(int cpu, enum freq_limits changed)
if (ret)
pr_err("Unable to update policy for cpu:%d. err:%d\n",
cpu, ret);
+ } else if (lmh_dcvs_available) {
+ trace_thermal_pre_frequency_mit(cpu,
+ cpus[cpu].limited_max_freq,
+ cpus[cpu].limited_min_freq);
+ msm_lmh_dcvs_update(cpu);
+ trace_thermal_post_frequency_mit(cpu,
+ cpufreq_quick_get_max(cpu),
+ cpus[cpu].limited_min_freq);
}
}
@@ -1621,6 +1629,9 @@ static void update_cluster_freq(void)
changed |= FREQ_LIMIT_MIN;
cluster_ptr->limited_max_freq = max;
cluster_ptr->limited_min_freq = min;
+ if (online_cpu == -1 && lmh_dcvs_available)
+ online_cpu = cpumask_first(
+ &cluster_ptr->cluster_cores);
if (online_cpu != -1)
update_cpu_freq(online_cpu, changed);
}
@@ -3646,12 +3657,6 @@ static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb,
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
- /*
- * Apply LMH freq cap vote, which was requested when the
- * core was offline.
- */
- if (lmh_dcvs_available)
- msm_lmh_dcvs_update(cpu);
if (!cpumask_test_and_set_cpu(cpu, cpus_previously_online))
pr_debug("Total prev cores online tracked %u\n",
cpumask_weight(cpus_previously_online));
diff --git a/drivers/thermal/qpnp-temp-alarm.c b/drivers/thermal/qpnp-temp-alarm.c
index 691c6c16532d..8c516da1d9ab 100644
--- a/drivers/thermal/qpnp-temp-alarm.c
+++ b/drivers/thermal/qpnp-temp-alarm.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -773,7 +773,7 @@ static const struct dev_pm_ops qpnp_tm_pm_ops = {
#define QPNP_TM_PM_OPS NULL
#endif
-static struct of_device_id qpnp_tm_match_table[] = {
+static const struct of_device_id qpnp_tm_match_table[] = {
{ .compatible = QPNP_TM_DRIVER_NAME, },
{}
};
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/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 211e1945962c..623f3ce211aa 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -3281,6 +3281,11 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb,
pval.intval = 0;
power_supply_set_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_BOOST_CURRENT, &pval);
+
+ /* set rate back to default core clk rate */
+ clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate);
+ dev_dbg(mdwc->dev, "set core clk rate %ld\n",
+ mdwc->core_clk_rate);
mdwc->max_rh_port_speed = USB_SPEED_UNKNOWN;
}
}
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index da02ad557d34..72f22a469ff1 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -55,7 +55,7 @@ static struct usb_interface_descriptor intf_desc = {
.bNumEndpoints = 2,
.bInterfaceClass = 0xFF,
.bInterfaceSubClass = 0xFF,
- .bInterfaceProtocol = 0xFF,
+ .bInterfaceProtocol = 0x30,
};
static struct usb_endpoint_descriptor hs_bulk_in_desc = {
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 6c18a04f6c1c..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);
}
/**
@@ -402,6 +417,7 @@ static void ipa_data_connect_work(struct work_struct *w)
if (!port->port_usb) {
spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_gadget_autopm_put_async(port->gadget);
pr_err("%s(): port_usb is NULL.\n", __func__);
return;
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 2b4f3a02f7e8..098df6ced1c3 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1870,7 +1870,7 @@ int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct device *dev = xhci_to_hcd(xhci)->self.controller;
- if (intr_num > xhci->max_interrupters) {
+ if (intr_num >= xhci->max_interrupters) {
xhci_err(xhci, "invalid secondary interrupter num %d\n",
intr_num);
return -EINVAL;
@@ -1903,7 +1903,7 @@ void xhci_event_ring_cleanup(struct xhci_hcd *xhci)
struct device *dev = xhci_to_hcd(xhci)->self.controller;
/* sec event ring clean up */
- for (i = 1; i <= xhci->max_interrupters; i++)
+ for (i = 1; i < xhci->max_interrupters; i++)
xhci_sec_event_ring_cleanup(xhci_to_hcd(xhci), i);
kfree(xhci->sec_ir_set);
@@ -2552,7 +2552,7 @@ int xhci_sec_event_ring_setup(struct usb_hcd *hcd, unsigned intr_num)
if ((xhci->xhc_state & XHCI_STATE_HALTED) || !xhci->sec_ir_set
|| !xhci->sec_event_ring || !xhci->sec_erst ||
- intr_num > xhci->max_interrupters) {
+ intr_num >= xhci->max_interrupters) {
xhci_err(xhci,
"%s:state %x ir_set %pK evt_ring %pK erst %pK intr# %d\n",
__func__, xhci->xhc_state, xhci->sec_ir_set,
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6e2c2f2bcce2..8c6bb15ef51f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -35,8 +35,6 @@
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
-#define XHCI_INT_MODERATION_VAL 4000
-
#define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
/* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */
@@ -647,7 +645,7 @@ int xhci_run(struct usb_hcd *hcd)
"// Set the interrupt modulation register");
temp = readl(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
- temp |= (u32) XHCI_INT_MODERATION_VAL;
+ temp |= (u32) 160;
writel(temp, &xhci->ir_set->irq_control);
/* Set the HCD state before we enable the irqs */
@@ -4984,8 +4982,8 @@ dma_addr_t xhci_get_sec_event_ring_dma_addr(struct usb_hcd *hcd,
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- if (intr_num > xhci->max_interrupters) {
- xhci_err(xhci, "intr num %d > max intrs %d\n", intr_num,
+ if (intr_num >= xhci->max_interrupters) {
+ xhci_err(xhci, "intr num %d >= max intrs %d\n", intr_num,
xhci->max_interrupters);
return 0;
}
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/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 06e4812a8bd4..6182aa2c626e 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -22,6 +22,7 @@
#include <linux/irqreturn.h>
#include <linux/irqdomain.h>
#include <linux/mdss_io_util.h>
+#include <linux/mdss_smmu_ext.h>
#include <linux/msm-bus.h>
#include <linux/file.h>
@@ -216,14 +217,14 @@ struct reg_bus_client {
};
struct mdss_smmu_client {
- struct device *dev;
+ struct mdss_smmu_intf base;
struct dma_iommu_mapping *mmu_mapping;
struct dss_module_power mp;
struct reg_bus_client *reg_bus_clt;
bool domain_attached;
bool handoff_pending;
void __iomem *mmu_base;
- int domain;
+ struct list_head _client;
};
struct mdss_mdp_qseed3_lut_tbl {
@@ -531,6 +532,8 @@ struct mdss_data_type {
struct mdss_mdp_destination_scaler *ds;
u32 sec_disp_en;
u32 sec_cam_en;
+ u32 sec_session_cnt;
+ wait_queue_head_t secure_waitq;
};
extern struct mdss_data_type *mdss_res;
@@ -573,11 +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 af9dc7ce1730..aa74a2ec27b2 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -2339,6 +2339,11 @@ static int mdss_dp_parse_config_value(char const *buf, char const *name,
if (buf1) {
buf1 = buf1 + strlen(name);
token = strsep(&buf1, " ");
+ if (!token) {
+ pr_err("strsep failed\n");
+ ret = -EINVAL;
+ goto end;
+ }
ret = kstrtou32(token, 10, val);
if (ret) {
pr_err("kstrtoint failed. ret=%d\n", (int)ret);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 51745a9a59ac..c66d9f3b3a65 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -2183,6 +2183,21 @@ static int mdss_dsi_check_params(struct mdss_dsi_ctrl_pdata *ctrl, void *arg)
return rc;
}
+static void mdss_dsi_avr_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+ int enabled)
+{
+ u32 data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x10);
+
+ /* DSI_VIDEO_MODE_CTRL */
+ if (enabled)
+ data |= BIT(29); /* AVR_SUPPORT_ENABLED */
+ else
+ data &= ~BIT(29);
+
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x10, data);
+ MDSS_XLOG(ctrl_pdata->ndx, enabled, data);
+}
+
static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
{
int rc = 0;
@@ -2700,6 +2715,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
case MDSS_EVENT_DSI_TIMING_DB_CTRL:
mdss_dsi_timing_db_ctrl(ctrl_pdata, (int)(unsigned long)arg);
break;
+ case MDSS_EVENT_AVR_MODE:
+ mdss_dsi_avr_config(ctrl_pdata, (int)(unsigned long) arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index abc56f5f352d..5804d88e5af5 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/hdcp_qseecom.h>
#include <linux/msm_mdp.h>
+#include <linux/msm_ext_display.h>
#define REG_DUMP 0
@@ -414,7 +415,6 @@ static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_cec_device_suspend(fd, hdmi_ctrl->panel_suspend);
}
-
static inline void hdmi_tx_send_cable_notification(
struct hdmi_tx_ctrl *hdmi_ctrl, int val)
{
@@ -431,7 +431,7 @@ static inline void hdmi_tx_send_cable_notification(
}
}
-static inline void hdmi_tx_set_audio_switch_node(
+static inline void hdmi_tx_ack_state(
struct hdmi_tx_ctrl *hdmi_ctrl, int val)
{
if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.notify &&
@@ -440,47 +440,6 @@ static inline void hdmi_tx_set_audio_switch_node(
val);
}
-static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl)
-{
- u64 status = 0;
- u32 wait_for_vote = 50;
- struct dss_io_data *io = NULL;
-
- if (!hdmi_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
- return;
- }
-
- io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
- if (!io->base) {
- DEV_ERR("%s: core io not inititalized\n", __func__);
- return;
- }
-
- /*
- * wait for 5 sec max for audio engine to acknowledge if hdmi tx core
- * can be safely turned off. Sleep for a reasonable time to make sure
- * vote_hdmi_core_on variable is updated properly by audio.
- */
- while (hdmi_ctrl->vote_hdmi_core_on && --wait_for_vote)
- msleep(100);
-
-
- if (!wait_for_vote)
- DEV_ERR("%s: HDMI core still voted for power on\n", __func__);
-
- if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status,
- (status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
- AUDIO_POLL_TIMEOUT_US))
- DEV_ERR("%s: Error turning off audio packet transmission.\n",
- __func__);
-
- if (readl_poll_timeout(io->base + HDMI_AUDIO_CFG, status,
- (status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
- AUDIO_POLL_TIMEOUT_US))
- DEV_ERR("%s: Error turning off audio engine.\n", __func__);
-}
-
static struct hdmi_tx_ctrl *hdmi_tx_get_drvdata_from_panel_data(
struct mdss_panel_data *mpd)
{
@@ -900,8 +859,7 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
hdmi_tx_config_5v(hdmi_ctrl, false);
} else {
hdmi_tx_hpd_off(hdmi_ctrl);
-
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
}
break;
@@ -1589,7 +1547,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work)
if (hdmi_tx_is_panel_on(hdmi_ctrl) &&
hdmi_tx_is_stream_shareable(hdmi_ctrl)) {
rc = hdmi_tx_config_avmute(hdmi_ctrl, false);
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1);
}
if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present)
@@ -1605,7 +1562,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work)
if (hdmi_tx_is_encryption_set(hdmi_ctrl) ||
!hdmi_tx_is_stream_shareable(hdmi_ctrl)) {
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
rc = hdmi_tx_config_avmute(hdmi_ctrl, true);
}
@@ -1631,7 +1587,6 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work)
if (hdmi_tx_is_panel_on(hdmi_ctrl)) {
rc = hdmi_tx_config_avmute(hdmi_ctrl, false);
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1);
}
break;
case HDCP_STATE_AUTH_ENC_1X:
@@ -1641,9 +1596,7 @@ static void hdmi_tx_hdcp_cb_work(struct work_struct *work)
if (hdmi_tx_is_panel_on(hdmi_ctrl) &&
hdmi_tx_is_stream_shareable(hdmi_ctrl)) {
rc = hdmi_tx_config_avmute(hdmi_ctrl, false);
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1);
} else {
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
rc = hdmi_tx_config_avmute(hdmi_ctrl, true);
}
break;
@@ -2373,7 +2326,8 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
if (!hdmi_ctrl->hpd_initialized) {
DEV_DBG("hpd not initialized\n");
- goto end;
+ mutex_unlock(&hdmi_ctrl->tx_lock);
+ return;
}
DEV_DBG("%s: %s\n", __func__,
@@ -2386,16 +2340,11 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
pr_warn_ratelimited("%s: EDID read failed\n", __func__);
hdmi_tx_update_deep_color(hdmi_ctrl);
hdmi_tx_update_hdr_info(hdmi_ctrl);
-
- hdmi_tx_send_cable_notification(hdmi_ctrl, true);
- } else {
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
- hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
-
- hdmi_tx_send_cable_notification(hdmi_ctrl, false);
}
-end:
+
mutex_unlock(&hdmi_ctrl->tx_lock);
+
+ hdmi_tx_send_cable_notification(hdmi_ctrl, hdmi_ctrl->hpd_state);
} /* hdmi_tx_hpd_int_work */
static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -3239,7 +3188,6 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl)
if (hdmi_ctrl->panel.infoframe &&
!hdmi_tx_is_encryption_set(hdmi_ctrl) &&
hdmi_tx_is_stream_shareable(hdmi_ctrl)) {
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 1);
hdmi_tx_config_avmute(hdmi_ctrl, false);
}
@@ -3845,20 +3793,6 @@ static int hdmi_tx_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl)
goto end;
}
- if (hdmi_ctrl->sdev.state &&
- !hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) {
- u32 timeout;
-
- reinit_completion(&hdmi_ctrl->hpd_int_done);
- timeout = wait_for_completion_timeout(
- &hdmi_ctrl->hpd_int_done, HZ/10);
- if (!timeout && !hdmi_ctrl->hpd_state) {
- DEV_DBG("%s: cable removed during suspend\n", __func__);
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
- hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
- hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
- }
- }
end:
return rc;
}
@@ -3906,14 +3840,6 @@ static int hdmi_tx_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_ctrl->timing_gen_on = true;
- if (hdmi_ctrl->panel_suspend) {
- DEV_DBG("%s: panel suspend has triggered\n", __func__);
-
- hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
- hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
- hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
- }
-
return rc;
}
@@ -4003,6 +3929,55 @@ static int hdmi_tx_evt_handle_hdmi_ppm(struct hdmi_tx_ctrl *hdmi_ctrl)
return hdmi_tx_update_ppm(hdmi_ctrl, ppm);
}
+static int hdmi_tx_pre_evt_handle_panel_off(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ hdmi_tx_ack_state(hdmi_ctrl, false);
+ return 0;
+}
+
+static int hdmi_tx_pre_evt_handle_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ hdmi_ctrl->dynamic_fps = (u32) (unsigned long)hdmi_ctrl->evt_arg;
+ queue_work(hdmi_ctrl->workq, &hdmi_ctrl->fps_work);
+ return 0;
+}
+
+static int hdmi_tx_post_evt_handle_unblank(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ hdmi_tx_ack_state(hdmi_ctrl, true);
+ return 0;
+}
+
+static int hdmi_tx_post_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ if (!hdmi_ctrl->hpd_feature_on)
+ return 0;
+
+ if (!hdmi_tx_hw_is_cable_connected(hdmi_ctrl)) {
+ u32 timeout;
+
+ reinit_completion(&hdmi_ctrl->hpd_int_done);
+ timeout = wait_for_completion_timeout(
+ &hdmi_ctrl->hpd_int_done, HZ/10);
+ if (!timeout) {
+ pr_debug("cable removed during suspend\n");
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
+ }
+ }
+
+ return 0;
+}
+
+static int hdmi_tx_post_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ if (hdmi_ctrl->panel_suspend) {
+ pr_debug("panel suspend has triggered\n");
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
+ }
+
+ return 0;
+}
+
static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data,
int event, void *arg)
{
@@ -4012,33 +3987,52 @@ static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data,
hdmi_tx_get_drvdata_from_panel_data(panel_data);
if (!hdmi_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
- rc = -EINVAL;
- goto end;
- }
-
- /* UPDATE FPS is called from atomic context */
- if (event == MDSS_EVENT_PANEL_UPDATE_FPS) {
- hdmi_ctrl->dynamic_fps = (u32) (unsigned long)arg;
- queue_work(hdmi_ctrl->workq, &hdmi_ctrl->fps_work);
- return rc;
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
}
- mutex_lock(&hdmi_ctrl->tx_lock);
-
hdmi_ctrl->evt_arg = arg;
- DEV_DBG("%s: event = %s suspend=%d, hpd_feature=%d\n", __func__,
+ pr_debug("event = %s suspend=%d, hpd_feature=%d\n",
mdss_panel_intf_event_to_string(event),
hdmi_ctrl->panel_suspend,
hdmi_ctrl->hpd_feature_on);
+ /* event handlers prior to tx_lock */
+ handler = hdmi_ctrl->pre_evt_handler[event];
+ if (handler) {
+ rc = handler(hdmi_ctrl);
+ if (rc) {
+ pr_err("pre handler failed: event = %s, rc = %d\n",
+ mdss_panel_intf_event_to_string(event), rc);
+ return rc;
+ }
+ }
+
+ mutex_lock(&hdmi_ctrl->tx_lock);
+
handler = hdmi_ctrl->evt_handler[event];
- if (handler)
+ if (handler) {
rc = handler(hdmi_ctrl);
+ if (rc) {
+ pr_err("handler failed: event = %s, rc = %d\n",
+ mdss_panel_intf_event_to_string(event), rc);
+ mutex_unlock(&hdmi_ctrl->tx_lock);
+ return rc;
+ }
+ }
mutex_unlock(&hdmi_ctrl->tx_lock);
-end:
+
+ /* event handlers post to tx_lock */
+ handler = hdmi_ctrl->post_evt_handler[event];
+ if (handler) {
+ rc = handler(hdmi_ctrl);
+ if (rc)
+ pr_err("post handler failed: event = %s, rc = %d\n",
+ mdss_panel_intf_event_to_string(event), rc);
+ }
+
return rc;
}
@@ -4692,7 +4686,6 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl)
return -EINVAL;
handler = hdmi_ctrl->evt_handler;
-
handler[MDSS_EVENT_FB_REGISTERED] = hdmi_tx_evt_handle_register;
handler[MDSS_EVENT_CHECK_PARAMS] = hdmi_tx_evt_handle_check_param;
handler[MDSS_EVENT_RESUME] = hdmi_tx_evt_handle_resume;
@@ -4704,7 +4697,17 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl)
handler[MDSS_EVENT_PANEL_OFF] = hdmi_tx_evt_handle_panel_off;
handler[MDSS_EVENT_CLOSE] = hdmi_tx_evt_handle_close;
handler[MDSS_EVENT_DEEP_COLOR] = hdmi_tx_evt_handle_deep_color;
- handler[MDSS_EVENT_UPDATE_PANEL_PPM] = hdmi_tx_evt_handle_hdmi_ppm;
+ handler[MDSS_EVENT_UPDATE_PANEL_PPM] = hdmi_tx_evt_handle_hdmi_ppm;
+
+ handler = hdmi_ctrl->pre_evt_handler;
+ handler[MDSS_EVENT_PANEL_UPDATE_FPS] =
+ hdmi_tx_pre_evt_handle_update_fps;
+ handler[MDSS_EVENT_PANEL_OFF] = hdmi_tx_pre_evt_handle_panel_off;
+
+ handler = hdmi_ctrl->post_evt_handler;
+ handler[MDSS_EVENT_UNBLANK] = hdmi_tx_post_evt_handle_unblank;
+ handler[MDSS_EVENT_RESUME] = hdmi_tx_post_evt_handle_resume;
+ handler[MDSS_EVENT_PANEL_ON] = hdmi_tx_post_evt_handle_panel_on;
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
index 2a6a48a4e473..ca316a350238 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
@@ -98,7 +98,6 @@ struct hdmi_tx_ctrl {
struct mutex tx_lock;
struct list_head cable_notify_handlers;
struct kobject *kobj;
- struct switch_dev sdev;
struct workqueue_struct *workq;
struct hdmi_util_ds_data ds_data;
struct completion hpd_int_done;
@@ -166,7 +165,10 @@ struct hdmi_tx_ctrl {
char disp_switch_name[MAX_SWITCH_NAME_SIZE];
+ /* pre/post is done in the context without tx_lock */
+ hdmi_tx_evt_handler pre_evt_handler[MDSS_EVENT_MAX - 1];
hdmi_tx_evt_handler evt_handler[MDSS_EVENT_MAX - 1];
+ hdmi_tx_evt_handler post_evt_handler[MDSS_EVENT_MAX - 1];
};
#endif /* __MDSS_HDMI_TX_H__ */
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 37a3876d3570..d8d11f21f3b2 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -98,6 +98,7 @@ static DEFINE_SPINLOCK(mdss_mdp_intr_lock);
static DEFINE_MUTEX(mdp_clk_lock);
static DEFINE_MUTEX(mdp_iommu_ref_cnt_lock);
static DEFINE_MUTEX(mdp_fs_idle_pc_lock);
+static DEFINE_MUTEX(mdp_sec_ref_cnt_lock);
static struct mdss_panel_intf pan_types[] = {
{"dsi", MDSS_PANEL_INTF_DSI},
@@ -783,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)
{
@@ -2106,8 +2127,10 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_SEC_DETACH_SMMU, mdata->mdss_caps_map);
+ 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;
@@ -2116,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;
@@ -2146,10 +2171,10 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT);
mdss_set_quirk(mdata, MDSS_QUIRK_MMSS_GDSC_COLLAPSE);
mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE);
+ mdss_set_quirk(mdata, MDSS_QUIRK_DMA_BI_DIR);
mdata->has_wb_ubwc = true;
set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_SEC_DETACH_SMMU, mdata->mdss_caps_map);
- mdss_set_quirk(mdata, MDSS_QUIRK_HDR_SUPPORT_ENABLED);
break;
default:
mdata->max_target_zorder = 4; /* excluding base layer */
@@ -2852,6 +2877,7 @@ static int mdss_mdp_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mdata->reg_bus_clist);
atomic_set(&mdata->sd_client_count, 0);
atomic_set(&mdata->active_intf_cnt, 0);
+ init_waitqueue_head(&mdata->secure_waitq);
mdss_res->mdss_util = mdss_get_util_intf();
if (mdss_res->mdss_util == NULL) {
@@ -2866,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) {
@@ -4159,6 +4188,7 @@ static int mdss_mdp_parse_dt_prefill(struct platform_device *pdev)
static void mdss_mdp_parse_vbif_qos(struct platform_device *pdev)
{
struct mdss_data_type *mdata = platform_get_drvdata(pdev);
+ u32 npriority_lvl_nrt;
int rc;
mdata->npriority_lvl = mdss_mdp_parse_dt_prop_len(pdev,
@@ -4184,8 +4214,20 @@ static void mdss_mdp_parse_vbif_qos(struct platform_device *pdev)
return;
}
- mdata->npriority_lvl = mdss_mdp_parse_dt_prop_len(pdev,
+ npriority_lvl_nrt = mdss_mdp_parse_dt_prop_len(pdev,
"qcom,mdss-vbif-qos-nrt-setting");
+
+ if (!npriority_lvl_nrt) {
+ pr_debug("no vbif nrt priorities found rt:%d\n",
+ mdata->npriority_lvl);
+ return;
+ } else if (npriority_lvl_nrt != mdata->npriority_lvl) {
+ /* driver expects same number for both nrt and rt */
+ pr_err("invalid nrt settings nrt(%d) != rt(%d)\n",
+ npriority_lvl_nrt, mdata->npriority_lvl);
+ return;
+ }
+
if (mdata->npriority_lvl == MDSS_VBIF_QOS_REMAP_ENTRIES) {
mdata->vbif_nrt_qos = kzalloc(sizeof(u32) *
mdata->npriority_lvl, GFP_KERNEL);
@@ -4203,7 +4245,7 @@ static void mdss_mdp_parse_vbif_qos(struct platform_device *pdev)
}
} else {
mdata->npriority_lvl = 0;
- pr_debug("Invalid or no vbif qos nrt seting\n");
+ pr_debug("Invalid or no vbif qos nrt setting\n");
}
}
@@ -4837,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))
@@ -5157,6 +5200,27 @@ int mdss_mdp_secure_session_ctrl(unsigned int enable, u64 flags)
int ret = 0;
uint32_t sid_info;
struct scm_desc desc;
+ bool changed = false;
+
+ mutex_lock(&mdp_sec_ref_cnt_lock);
+
+ if (enable) {
+ if (mdata->sec_session_cnt == 0)
+ changed = true;
+ mdata->sec_session_cnt++;
+ } else {
+ if (mdata->sec_session_cnt != 0) {
+ mdata->sec_session_cnt--;
+ if (mdata->sec_session_cnt == 0)
+ changed = true;
+ } else {
+ pr_warn("%s: ref_count is not balanced\n",
+ __func__);
+ }
+ }
+
+ if (!changed)
+ goto end;
if (test_bit(MDSS_CAPS_SEC_DETACH_SMMU, mdata->mdss_caps_map)) {
/*
@@ -5180,7 +5244,8 @@ int mdss_mdp_secure_session_ctrl(unsigned int enable, u64 flags)
desc.args[3] = VMID_CP_CAMERA_PREVIEW;
mdata->sec_cam_en = 1;
} else {
- return 0;
+ ret = 0;
+ goto end;
}
/* detach smmu contexts */
@@ -5188,7 +5253,8 @@ int mdss_mdp_secure_session_ctrl(unsigned int enable, u64 flags)
if (ret) {
pr_err("Error while detaching smmu contexts ret = %d\n",
ret);
- return -EINVAL;
+ ret = -EINVAL;
+ goto end;
}
/* let the driver think smmu is still attached */
@@ -5200,7 +5266,8 @@ int mdss_mdp_secure_session_ctrl(unsigned int enable, u64 flags)
if (ret) {
pr_err("Error scm_call MEM_PROTECT_SD_CTRL(%u) ret=%dm resp=%x\n",
enable, ret, resp);
- return -EINVAL;
+ ret = -EINVAL;
+ goto end;
}
resp = desc.ret[0];
@@ -5233,7 +5300,8 @@ int mdss_mdp_secure_session_ctrl(unsigned int enable, u64 flags)
if (ret) {
pr_err("Error while attaching smmu contexts ret = %d\n",
ret);
- return -EINVAL;
+ ret = -EINVAL;
+ goto end;
}
}
MDSS_XLOG(enable);
@@ -5256,10 +5324,11 @@ int mdss_mdp_secure_session_ctrl(unsigned int enable, u64 flags)
pr_debug("scm_call MEM_PROTECT_SD_CTRL(%u): ret=%d, resp=%x\n",
enable, ret, resp);
}
- if (ret)
- return ret;
- return resp;
+end:
+ mutex_unlock(&mdp_sec_ref_cnt_lock);
+ return ret;
+
}
static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index cb9cc08140f0..5e98de043e55 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -555,6 +555,7 @@ struct mdss_mdp_ctl {
bool switch_with_handoff;
struct mdss_mdp_avr_info avr_info;
bool commit_in_progress;
+ struct mutex ds_lock;
};
struct mdss_mdp_mixer {
@@ -1298,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;
@@ -1314,10 +1317,13 @@ static inline struct clk *mdss_mdp_get_clk(u32 clk_idx)
static inline void mdss_update_sd_client(struct mdss_data_type *mdata,
bool status)
{
- if (status)
+ if (status) {
atomic_inc(&mdata->sd_client_count);
- else
+ } else {
atomic_add_unless(&mdss_res->sd_client_count, -1, 0);
+ if (!atomic_read(&mdss_res->sd_client_count))
+ wake_up_all(&mdata->secure_waitq);
+ }
}
static inline void mdss_update_sc_client(struct mdss_data_type *mdata,
@@ -1969,6 +1975,7 @@ void mdss_mdp_enable_hw_irq(struct mdss_data_type *mdata);
void mdss_mdp_disable_hw_irq(struct mdss_data_type *mdata);
void mdss_mdp_set_supported_formats(struct mdss_data_type *mdata);
+int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer);
#ifdef CONFIG_FB_MSM_MDP_NONE
struct mdss_data_type *mdss_mdp_get_mdata(void)
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index acb356fc681a..ec37cd1d5bb0 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -2407,6 +2407,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
mutex_init(&ctl->flush_lock);
mutex_init(&ctl->rsrc_lock);
spin_lock_init(&ctl->spin_lock);
+ mutex_init(&ctl->ds_lock);
BLOCKING_INIT_NOTIFIER_HEAD(&ctl->notifier_head);
pr_debug("alloc ctl_num=%d\n", ctl->num);
break;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index b7f27b818eda..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,
@@ -2031,6 +2043,19 @@ static int __mdss_mdp_wait4pingpong(struct mdss_mdp_cmd_ctx *ctx)
return rc;
}
+static void __clear_ping_pong_callback(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_cmd_ctx *ctx)
+{
+ mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
+ ctx->current_pp_num);
+ mdss_mdp_set_intr_callback_nosync(
+ MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
+ ctx->current_pp_num, NULL, NULL);
+ if (atomic_add_unless(&ctx->koff_cnt, -1, 0)
+ && mdss_mdp_cmd_do_notifier(ctx))
+ mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_TIMEOUT);
+}
+
static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
@@ -2047,7 +2072,7 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
pdata = ctl->panel_data;
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctl->roi_bkup.w,
- ctl->roi_bkup.h);
+ ctl->roi_bkup.h, pdata->panel_info.panel_dead);
pr_debug("%s: intf_num=%d ctx=%pK koff_cnt=%d\n", __func__,
ctl->intf_num, ctx, atomic_read(&ctx->koff_cnt));
@@ -2073,6 +2098,13 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
mdss_mdp_cmd_pingpong_done(ctl);
local_irq_restore(flags);
rc = 1;
+ } else if (pdata->panel_info.panel_dead) {
+ /*
+ * if panel is reported dead, no need to wait for
+ * pingpong done, and don't report timeout
+ */
+ MDSS_XLOG(0xdead);
+ __clear_ping_pong_callback(ctl, ctx);
}
rc = atomic_read(&ctx->koff_cnt) == 0;
@@ -2098,15 +2130,7 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
ctx->pp_timeout_report_cnt++;
rc = -EPERM;
- mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
- ctx->current_pp_num);
- mdss_mdp_set_intr_callback_nosync(
- MDSS_MDP_IRQ_TYPE_PING_PONG_COMP,
- ctx->current_pp_num, NULL, NULL);
- if (atomic_add_unless(&ctx->koff_cnt, -1, 0)
- && mdss_mdp_cmd_do_notifier(ctx))
- mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_TIMEOUT);
-
+ __clear_ping_pong_callback(ctl, ctx);
} else {
rc = 0;
ctx->pp_timeout_report_cnt = 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 4efa38093557..663d63092ebf 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -106,6 +106,9 @@ static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx,
static void mdss_mdp_fetch_end_config(struct mdss_mdp_video_ctx *ctx,
struct mdss_mdp_ctl *ctl);
+static void mdss_mdp_video_timegen_flush(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_video_ctx *sctx);
+
static void early_wakeup_dfps_update_work(struct work_struct *work);
static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl, bool enable);
@@ -411,6 +414,8 @@ static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_video_ctx *ctx)
{
struct mdss_data_type *mdata = ctl->mdata;
+ struct mdss_mdp_ctl *sctl = NULL;
+ struct mdss_mdp_video_ctx *sctx = NULL;
if (test_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map)) {
struct mdss_panel_data *pdata = ctl->panel_data;
@@ -435,6 +440,17 @@ static void mdss_mdp_video_avr_vtotal_setup(struct mdss_mdp_ctl *ctl,
mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_VTOTAL, avr_vtotal);
+ /*
+ * Make sure config goes through
+ */
+ wmb();
+
+ sctl = mdss_mdp_get_split_ctl(ctl);
+ if (sctl)
+ sctx = (struct mdss_mdp_video_ctx *)
+ sctl->intf_ctx[MASTER_CTX];
+ mdss_mdp_video_timegen_flush(ctl, ctx);
+
MDSS_XLOG(pinfo->min_fps, pinfo->default_fps, avr_vtotal);
}
}
@@ -461,8 +477,9 @@ static int mdss_mdp_video_avr_trigger_setup(struct mdss_mdp_ctl *ctl)
}
static void mdss_mdp_video_avr_ctrl_setup(struct mdss_mdp_video_ctx *ctx,
- struct mdss_mdp_avr_info *avr_info, bool is_master, bool enable)
+ struct mdss_mdp_ctl *ctl, bool is_master, bool enable)
{
+ struct mdss_mdp_avr_info *avr_info = &ctl->avr_info;
u32 avr_ctrl = 0;
u32 avr_mode = 0;
@@ -475,9 +492,18 @@ static void mdss_mdp_video_avr_ctrl_setup(struct mdss_mdp_video_ctx *ctx,
if (avr_mode == MDSS_MDP_AVR_ONE_SHOT)
avr_mode |= (1 << 8);
- if (is_master)
+ if (is_master) {
mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_CONTROL, avr_ctrl);
+ /*
+ * When AVR is enabled, need to setup DSI Video mode control
+ */
+ mdss_mdp_ctl_intf_event(ctl,
+ MDSS_EVENT_AVR_MODE,
+ (void *)(unsigned long) avr_ctrl,
+ CTL_INTF_EVENT_FLAG_DEFAULT);
+ }
+
mdp_video_write(ctx, MDSS_MDP_REG_INTF_AVR_MODE, avr_mode);
pr_debug("intf:%d avr_mode:%x avr_ctrl:%x\n",
@@ -1435,7 +1461,6 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
}
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
-
/*
* Need to disable AVR during DFPS update period.
* Next commit will restore the AVR settings.
@@ -1844,6 +1869,7 @@ static void mdss_mdp_handoff_programmable_fetch(struct mdss_mdp_ctl *ctl,
struct mdss_mdp_video_ctx *ctx)
{
struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
+
u32 fetch_start_handoff, v_total_handoff, h_total_handoff;
pinfo->prg_fet = 0;
if (mdp_video_read(ctx, MDSS_MDP_REG_INTF_CONFIG) & BIT(31)) {
@@ -2269,7 +2295,7 @@ static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl, bool enable)
pr_err("invalid master ctx\n");
return -EINVAL;
}
- mdss_mdp_video_avr_ctrl_setup(ctx, &ctl->avr_info, ctl->is_master,
+ mdss_mdp_video_avr_ctrl_setup(ctx, ctl, ctl->is_master,
enable);
if (is_pingpong_split(ctl->mfd)) {
@@ -2278,7 +2304,7 @@ static int mdss_mdp_video_avr_ctrl(struct mdss_mdp_ctl *ctl, bool enable)
pr_err("invalid slave ctx\n");
return -EINVAL;
}
- mdss_mdp_video_avr_ctrl_setup(sctx, &ctl->avr_info, false,
+ mdss_mdp_video_avr_ctrl_setup(sctx, ctl, false,
enable);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 0eb82dd8371d..c9e32d69d444 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -399,6 +399,7 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
ctl = mfd_to_ctl(mfd);
sctl = mdss_mdp_get_split_ctl(ctl);
+ mutex_lock(&ctl->ds_lock);
if (ctl->mixer_left)
ds_left = ctl->mixer_left->ds;
@@ -412,6 +413,7 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
case DS_DUAL_MODE:
if (!ds_left || !ds_right) {
pr_err("Cannot support DUAL mode dest scaling\n");
+ mutex_unlock(&ctl->ds_lock);
return -EINVAL;
}
@@ -457,6 +459,7 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
case DS_LEFT:
if (!ds_left) {
pr_err("LM in ctl does not support Destination Scaler\n");
+ mutex_unlock(&ctl->ds_lock);
return -EINVAL;
}
ds_left->flags &= ~(DS_DUAL_MODE|DS_RIGHT);
@@ -486,6 +489,7 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
case DS_RIGHT:
if (!ds_right) {
pr_err("Cannot setup DS_RIGHT because only single DS assigned to ctl\n");
+ mutex_unlock(&ctl->ds_lock);
return -EINVAL;
}
@@ -522,7 +526,6 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
ds_right->src_height, ds_right->flags);
break;
}
-
} else {
pr_err("NULL destionation scaler data\n");
return -EFAULT;
@@ -559,6 +562,7 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
goto reset_mixer;
}
+ mutex_unlock(&ctl->ds_lock);
return ret;
reset_mixer:
@@ -592,6 +596,7 @@ reset_mixer:
ctl->mixer_right->height);
}
+ mutex_unlock(&ctl->ds_lock);
return ret;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index c49f4f2a4ad6..1a9b09ca6988 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1471,6 +1471,23 @@ static void __unstage_pipe_and_clean_buf(struct msm_fb_data_type *mfd,
__pipe_buf_mark_cleanup(mfd, buf);
}
+static int __dest_scaler_setup(struct msm_fb_data_type *mfd)
+{
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+
+ mutex_lock(&ctl->ds_lock);
+
+ if (ctl->mixer_left)
+ mdss_mdp_dest_scaler_setup_locked(ctl->mixer_left);
+
+ if (ctl->mixer_right)
+ mdss_mdp_dest_scaler_setup_locked(ctl->mixer_right);
+
+ mutex_unlock(&ctl->ds_lock);
+
+ return 0;
+}
+
static int __overlay_queue_pipes(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -2394,6 +2411,9 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
mutex_unlock(&mdp5_data->list_lock);
mdp5_data->kickoff_released = false;
+ ATRACE_BEGIN("dest_scaler_programming");
+ ret = __dest_scaler_setup(mfd);
+ ATRACE_END("dest_scaler_programming");
if (mfd->panel.type == WRITEBACK_PANEL) {
ATRACE_BEGIN("wb_kickoff");
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index 563cb8be1a04..965a6533dfcb 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -1011,8 +1011,10 @@ static void mdss_mdp_qos_vbif_remapper_setup(struct mdss_data_type *mdata,
u32 mask, reg_val, reg_val_lvl, i, vbif_qos;
u32 reg_high;
bool is_nrt_vbif = mdss_mdp_is_nrt_vbif_client(mdata, pipe);
+ u32 *vbif_qos_ptr = is_realtime ? mdata->vbif_rt_qos :
+ mdata->vbif_nrt_qos;
- if (mdata->npriority_lvl == 0)
+ if ((mdata->npriority_lvl == 0) || !vbif_qos_ptr)
return;
if (test_bit(MDSS_QOS_REMAPPER, mdata->mdss_qos_map)) {
@@ -1028,8 +1030,7 @@ static void mdss_mdp_qos_vbif_remapper_setup(struct mdss_data_type *mdata,
is_nrt_vbif);
mask = 0x3 << (pipe->xin_id * 4);
- vbif_qos = is_realtime ?
- mdata->vbif_rt_qos[i] : mdata->vbif_nrt_qos[i];
+ vbif_qos = vbif_qos_ptr[i];
reg_val &= ~(mask);
reg_val |= vbif_qos << (pipe->xin_id * 4);
@@ -1053,8 +1054,7 @@ static void mdss_mdp_qos_vbif_remapper_setup(struct mdss_data_type *mdata,
mask = 0x3 << (pipe->xin_id * 2);
reg_val &= ~(mask);
- vbif_qos = is_realtime ?
- mdata->vbif_rt_qos[i] : mdata->vbif_nrt_qos[i];
+ vbif_qos = vbif_qos_ptr[i];
reg_val |= vbif_qos << (pipe->xin_id * 2);
MDSS_VBIF_WRITE(mdata, MDSS_VBIF_QOS_REMAP_BASE + i*4,
reg_val, is_nrt_vbif);
@@ -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 d83bedacec28..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) {
@@ -2559,7 +2560,7 @@ dspp_exit:
return ret;
}
-static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
+int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer)
{
struct mdss_mdp_ctl *ctl;
struct mdss_data_type *mdata;
@@ -2618,7 +2619,8 @@ static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
writel_relaxed(op_mode, MDSS_MDP_REG_DEST_SCALER_OP_MODE + ds_offset);
- if (ds->flags & DS_SCALE_UPDATE) {
+ if ((ds->flags & DS_SCALE_UPDATE) ||
+ (ds->flags & DS_ENHANCER_UPDATE)) {
ret = mdss_mdp_qseed3_setup(&ds->scaler,
ds->scaler_base, ds->lut_base,
&dest_scaler_fmt);
@@ -2631,11 +2633,6 @@ static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
* for each commit if there is no change.
*/
ds->flags &= ~DS_SCALE_UPDATE;
- }
-
- if (ds->flags & DS_ENHANCER_UPDATE) {
- mdss_mdp_scaler_detail_enhance_cfg(&ds->scaler.detail_enhance,
- ds->scaler_base);
ds->flags &= ~DS_ENHANCER_UPDATE;
}
@@ -2643,7 +2640,9 @@ static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
if (ds->flags & (DS_ENABLE | DS_VALIDATE)) {
pr_debug("FLUSH[%d]: flags:%X, op_mode:%x\n",
ds->num, ds->flags, op_mode);
+ mutex_lock(&ctl->flush_lock);
ctl->flush_bits |= BIT(13 + ds->num);
+ mutex_unlock(&ctl->flush_lock);
}
ds->flags &= ~DS_VALIDATE;
@@ -2760,13 +2759,11 @@ int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl)
}
if (ctl->mixer_left) {
- pp_dest_scaler_setup(ctl->mixer_left);
pp_mixer_setup(ctl->mixer_left);
pp_dspp_setup(disp_num, ctl->mixer_left);
pp_ppb_setup(ctl->mixer_left);
}
if (ctl->mixer_right) {
- pp_dest_scaler_setup(ctl->mixer_right);
pp_mixer_setup(ctl->mixer_right);
pp_dspp_setup(disp_num, ctl->mixer_right);
pp_ppb_setup(ctl->mixer_right);
@@ -7670,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_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 3fc5b2226b3e..e466c0097540 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -265,6 +265,10 @@ struct mdss_intf_recovery {
* Argument provided is bits per pixel (8/10/12)
* @MDSS_EVENT_UPDATE_PANEL_PPM: update pixel clock by input PPM.
* Argument provided is parts per million.
+ * @MDSS_EVENT_AVR_MODE: Setup DSI Video mode to support AVR based on the
+ * avr mode passed as argument
+ * 0 - disable AVR support
+ * 1 - enable AVR support
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -299,6 +303,7 @@ enum mdss_intf_events {
MDSS_EVENT_DISABLE_PANEL,
MDSS_EVENT_UPDATE_PANEL_PPM,
MDSS_EVENT_DSI_TIMING_DB_CTRL,
+ MDSS_EVENT_AVR_MODE,
MDSS_EVENT_MAX,
};
@@ -1007,13 +1012,11 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info)
case MIPI_CMD_PANEL:
frame_rate = panel_info->mipi.frame_rate;
break;
- case DP_PANEL:
- frame_rate = panel_info->edp.frame_rate;
- break;
case WRITEBACK_PANEL:
frame_rate = DEFAULT_FRAME_RATE;
break;
case DTV_PANEL:
+ case DP_PANEL:
if (panel_info->dynamic_fps) {
frame_rate = panel_info->lcdc.frame_rate / 1000;
if (panel_info->lcdc.frame_rate % 1000)
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 a08eec8e1606..6930444118b6 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2007-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
@@ -28,6 +28,8 @@
#include <linux/msm_dma_iommu_mapping.h>
#include <linux/qcom_iommu.h>
+#include <linux/mdss_smmu_ext.h>
+
#include <asm/dma-iommu.h>
#include "soc/qcom/secure_buffer.h"
@@ -40,6 +42,18 @@
static DEFINE_MUTEX(mdp_iommu_lock);
+static struct mdss_smmu_private smmu_private;
+
+struct msm_smmu_notifier_data {
+ struct list_head _user;
+ msm_smmu_handler_t callback;
+};
+
+struct mdss_smmu_private *mdss_smmu_get_private(void)
+{
+ return &smmu_private;
+}
+
void mdss_iommu_lock(void)
{
mutex_lock(&mdp_iommu_lock);
@@ -50,6 +64,111 @@ void mdss_iommu_unlock(void)
mutex_unlock(&mdp_iommu_lock);
}
+static int mdss_smmu_secure_wait(int State, int request)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ int rc = 0;
+ /**
+ * Case1: MDP in Secure Display and Rotator in Non Secure
+ */
+ if (!State && !request && mdss_get_sd_client_cnt()) {
+ rc = wait_event_timeout(mdata->secure_waitq,
+ (mdss_get_sd_client_cnt() == 0),
+ KOFF_TIMEOUT);
+ if (rc <= 0) {
+ pr_err("timed out waiting for Secure transtion: %d\n",
+ mdss_get_sd_client_cnt());
+ rc = -EINVAL;
+ }
+ }
+
+ return rc;
+}
+
+static int mdss_smmu_secure_session_ctrl(int enable)
+{
+ int rc = 0;
+ /**
+ * Currently client requests only enable/disable.
+ * TODO: Secure camera is hardcoded need to extend.
+ */
+ rc = mdss_mdp_secure_session_ctrl(enable,
+ MDP_SECURE_CAMERA_OVERLAY_SESSION);
+ if (rc)
+ pr_err("%s: mdss_mdp_secure_session_ctrl failed : %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static inline bool all_devices_probed(struct mdss_smmu_private *prv)
+{
+ struct device_node *child;
+ struct mdss_smmu_client *tmp;
+ int d_cnt = 0;
+ int p_cnt = 0;
+
+ if (!prv->pdev)
+ return 0;
+
+ for_each_child_of_node(prv->pdev, child) {
+ if (is_mdss_smmu_compatible_device(child->name))
+ d_cnt++;
+ }
+
+ list_for_each_entry(tmp, &prv->smmu_device_list, _client) {
+ p_cnt++;
+ }
+
+ return (d_cnt && (d_cnt == p_cnt) ? true : false);
+}
+
+void mdss_iommu_notify_users(struct mdss_smmu_private *prv)
+{
+ struct msm_smmu_notifier_data *notify;
+ struct mdss_smmu_client *client;
+
+ /* Initiate callbacks for all the users who registered before probe */
+ if (all_devices_probed(prv)) {
+ list_for_each_entry(notify, &prv->user_list, _user) {
+ list_for_each_entry(client,
+ &prv->smmu_device_list, _client)
+ notify->callback(&client->base);
+ }
+ }
+}
+
+int mdss_smmu_request_mappings(msm_smmu_handler_t callback)
+{
+ struct mdss_smmu_client *client;
+ struct msm_smmu_notifier_data *ndata;
+ struct mdss_smmu_private *prv = mdss_smmu_get_private();
+ int ret = 0;
+
+ mutex_lock(&prv->smmu_reg_lock);
+
+ if (!all_devices_probed(prv)) {
+ ndata = kzalloc(sizeof(struct msm_smmu_notifier_data),
+ GFP_KERNEL);
+ if (!ndata) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ndata->callback = callback;
+ list_add(&ndata->_user, &prv->user_list);
+ goto done;
+ }
+
+ /* Probe already done mappings are available */
+ list_for_each_entry(client, &prv->smmu_device_list, _client) {
+ callback(&client->base);
+ }
+
+done:
+ mutex_unlock(&prv->smmu_reg_lock);
+ return ret;
+}
+
static int mdss_smmu_util_parse_dt_clock(struct platform_device *pdev,
struct dss_module_power *mp)
{
@@ -182,7 +301,7 @@ static int mdss_smmu_attach_v2(struct mdss_data_type *mdata)
continue;
mdss_smmu = mdss_smmu_get_cb(i);
- if (mdss_smmu && mdss_smmu->dev) {
+ if (mdss_smmu && mdss_smmu->base.dev) {
if (!mdss_smmu->handoff_pending) {
rc = mdss_smmu_enable_power(mdss_smmu, true);
if (rc) {
@@ -196,8 +315,9 @@ static int mdss_smmu_attach_v2(struct mdss_data_type *mdata)
if (!mdss_smmu->domain_attached &&
mdss_smmu_is_valid_domain_condition(mdata,
i, true)) {
- rc = arm_iommu_attach_device(mdss_smmu->dev,
- mdss_smmu->mmu_mapping);
+ rc = arm_iommu_attach_device(
+ mdss_smmu->base.dev,
+ mdss_smmu->mmu_mapping);
if (rc) {
pr_err("iommu attach device failed for domain[%d] with err:%d\n",
i, rc);
@@ -219,8 +339,8 @@ static int mdss_smmu_attach_v2(struct mdss_data_type *mdata)
err:
for (i--; i >= 0; i--) {
mdss_smmu = mdss_smmu_get_cb(i);
- if (mdss_smmu && mdss_smmu->dev) {
- arm_iommu_detach_device(mdss_smmu->dev);
+ if (mdss_smmu && mdss_smmu->base.dev) {
+ arm_iommu_detach_device(mdss_smmu->base.dev);
mdss_smmu_enable_power(mdss_smmu, false);
mdss_smmu->domain_attached = false;
}
@@ -246,7 +366,7 @@ static int mdss_smmu_detach_v2(struct mdss_data_type *mdata)
continue;
mdss_smmu = mdss_smmu_get_cb(i);
- if (mdss_smmu && mdss_smmu->dev) {
+ if (mdss_smmu && mdss_smmu->base.dev) {
if (!mdss_smmu->handoff_pending &&
mdss_smmu->domain_attached &&
mdss_smmu_is_valid_domain_condition(mdata,
@@ -257,7 +377,7 @@ static int mdss_smmu_detach_v2(struct mdss_data_type *mdata)
* leave the smmu clocks on and only detach the
* smmu contexts
*/
- arm_iommu_detach_device(mdss_smmu->dev);
+ arm_iommu_detach_device(mdss_smmu->base.dev);
mdss_smmu->domain_attached = false;
pr_debug("iommu v2 domain[%i] detached\n", i);
} else {
@@ -289,7 +409,7 @@ static struct dma_buf_attachment *mdss_smmu_dma_buf_attach_v2(
return NULL;
}
- return dma_buf_attach(dma_buf, mdss_smmu->dev);
+ return dma_buf_attach(dma_buf, mdss_smmu->base.dev);
}
/*
@@ -310,8 +430,8 @@ static int mdss_smmu_map_dma_buf_v2(struct dma_buf *dma_buf,
return -EINVAL;
}
ATRACE_BEGIN("map_buffer");
- rc = msm_dma_map_sg_lazy(mdss_smmu->dev, table->sgl, table->nents, dir,
- dma_buf);
+ rc = msm_dma_map_sg_lazy(mdss_smmu->base.dev, table->sgl, table->nents,
+ dir, dma_buf);
if (rc != table->nents) {
pr_err("dma map sg failed\n");
return -ENOMEM;
@@ -332,7 +452,7 @@ static void mdss_smmu_unmap_dma_buf_v2(struct sg_table *table, int domain,
}
ATRACE_BEGIN("unmap_buffer");
- msm_dma_unmap_sg(mdss_smmu->dev, table->sgl, table->nents, dir,
+ msm_dma_unmap_sg(mdss_smmu->base.dev, table->sgl, table->nents, dir,
dma_buf);
ATRACE_END("unmap_buffer");
}
@@ -354,7 +474,7 @@ static int mdss_smmu_dma_alloc_coherent_v2(struct device *dev, size_t size,
return -EINVAL;
}
- cpu_addr = dma_alloc_coherent(mdss_smmu->dev, size, iova, gfp);
+ cpu_addr = dma_alloc_coherent(mdss_smmu->base.dev, size, iova, gfp);
if (!cpu_addr) {
pr_err("dma alloc coherent failed!\n");
return -ENOMEM;
@@ -373,7 +493,7 @@ static void mdss_smmu_dma_free_coherent_v2(struct device *dev, size_t size,
return;
}
- dma_free_coherent(mdss_smmu->dev, size, cpu_addr, iova);
+ dma_free_coherent(mdss_smmu->base.dev, size, cpu_addr, iova);
}
/*
@@ -440,7 +560,7 @@ static int mdss_smmu_dsi_map_buffer_v2(phys_addr_t phys, unsigned int domain,
return -EINVAL;
}
- *dma_addr = dma_map_single(mdss_smmu->dev, cpu_addr, size, dir);
+ *dma_addr = dma_map_single(mdss_smmu->base.dev, cpu_addr, size, dir);
if (IS_ERR_VALUE(*dma_addr)) {
pr_err("dma map single failed\n");
return -ENOMEM;
@@ -458,7 +578,7 @@ static void mdss_smmu_dsi_unmap_buffer_v2(dma_addr_t dma_addr, int domain,
}
if (is_mdss_iommu_attached())
- dma_unmap_single(mdss_smmu->dev, dma_addr, size, dir);
+ dma_unmap_single(mdss_smmu->base.dev, dma_addr, size, dir);
}
int mdss_smmu_fault_handler(struct iommu_domain *domain, struct device *dev,
@@ -497,7 +617,7 @@ static void mdss_smmu_deinit_v2(struct mdss_data_type *mdata)
for (i = 0; i < MDSS_IOMMU_MAX_DOMAIN; i++) {
mdss_smmu = mdss_smmu_get_cb(i);
- if (mdss_smmu && mdss_smmu->dev)
+ if (mdss_smmu && mdss_smmu->base.dev)
arm_iommu_release_mapping(mdss_smmu->mmu_mapping);
}
}
@@ -537,19 +657,27 @@ static void mdss_smmu_ops_init(struct mdss_data_type *mdata)
void mdss_smmu_device_create(struct device *dev)
{
struct device_node *parent, *child;
+ struct mdss_smmu_private *prv = mdss_smmu_get_private();
+
parent = dev->of_node;
for_each_child_of_node(parent, child) {
if (is_mdss_smmu_compatible_device(child->name))
of_platform_device_create(child, NULL, dev);
}
+ prv->pdev = parent;
}
int mdss_smmu_init(struct mdss_data_type *mdata, struct device *dev)
{
- mdss_smmu_device_create(dev);
- mdss_smmu_ops_init(mdata);
mdata->mdss_util->iommu_lock = mdss_iommu_lock;
mdata->mdss_util->iommu_unlock = mdss_iommu_unlock;
+ mdata->mdss_util->iommu_ctrl = mdss_iommu_ctrl;
+ mdata->mdss_util->secure_session_ctrl =
+ mdss_smmu_secure_session_ctrl;
+
+ mdss_smmu_device_create(dev);
+ mdss_smmu_ops_init(mdata);
+
return 0;
}
@@ -584,6 +712,7 @@ int mdss_smmu_probe(struct platform_device *pdev)
{
struct device *dev;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+ struct mdss_smmu_private *prv = mdss_smmu_get_private();
struct mdss_smmu_client *mdss_smmu;
int rc = 0;
struct mdss_smmu_domain smmu_domain;
@@ -625,8 +754,9 @@ int mdss_smmu_probe(struct platform_device *pdev)
}
mdss_smmu = &mdata->mdss_smmu[smmu_domain.domain];
- mdss_smmu->domain = smmu_domain.domain;
+ mdss_smmu->base.domain = smmu_domain.domain;
mp = &mdss_smmu->mp;
+ mdss_smmu->base.is_secure = false;
memset(mp, 0, sizeof(struct dss_module_power));
if (of_find_property(pdev->dev.of_node,
@@ -692,6 +822,7 @@ int mdss_smmu_probe(struct platform_device *pdev)
pr_err("couldn't set secure pixel vmid\n");
goto release_mapping;
}
+ mdss_smmu->base.is_secure = true;
}
if (!mdata->handoff_pending)
@@ -699,7 +830,7 @@ int mdss_smmu_probe(struct platform_device *pdev)
else
mdss_smmu->handoff_pending = true;
- mdss_smmu->dev = dev;
+ mdss_smmu->base.dev = dev;
address = of_get_address_by_name(pdev->dev.of_node, "mmu_cb", 0, 0);
if (address) {
@@ -713,6 +844,18 @@ int mdss_smmu_probe(struct platform_device *pdev)
pr_debug("unable to map context bank base\n");
}
+ 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);
+
+ mdss_iommu_notify_users(prv);
+
pr_info("iommu v2 domain[%d] mapping and clk register successful!\n",
smmu_domain.domain);
return 0;
@@ -736,8 +879,8 @@ int mdss_smmu_remove(struct platform_device *pdev)
for (i = 0; i < MDSS_IOMMU_MAX_DOMAIN; i++) {
mdss_smmu = mdss_smmu_get_cb(i);
- if (mdss_smmu && mdss_smmu->dev &&
- (mdss_smmu->dev == &pdev->dev))
+ if (mdss_smmu && mdss_smmu->base.dev &&
+ (mdss_smmu->base.dev == &pdev->dev))
arm_iommu_release_mapping(mdss_smmu->mmu_mapping);
}
return 0;
@@ -755,7 +898,18 @@ static struct platform_driver mdss_smmu_driver = {
static int mdss_smmu_register_driver(void)
{
- return platform_driver_register(&mdss_smmu_driver);
+ struct mdss_smmu_private *prv = mdss_smmu_get_private();
+ int ret;
+
+ INIT_LIST_HEAD(&prv->smmu_device_list);
+ INIT_LIST_HEAD(&prv->user_list);
+ mutex_init(&prv->smmu_reg_lock);
+
+ ret = platform_driver_register(&mdss_smmu_driver);
+ if (ret)
+ pr_err("mdss_smmu_register_driver() failed!\n");
+
+ return ret;
}
static int __init mdss_smmu_driver_init(void)
@@ -771,6 +925,15 @@ module_init(mdss_smmu_driver_init);
static void __exit mdss_smmu_driver_cleanup(void)
{
+ struct mdss_smmu_private *prv = mdss_smmu_get_private();
+ struct msm_smmu_notifier_data *node;
+ struct list_head *pos, *q;
+
+ list_for_each_safe(pos, q, &prv->user_list) {
+ node = list_entry(pos, struct msm_smmu_notifier_data, _user);
+ list_del(&node->_user);
+ kfree(node);
+ }
platform_driver_unregister(&mdss_smmu_driver);
}
module_exit(mdss_smmu_driver_cleanup);
diff --git a/drivers/video/fbdev/msm/mdss_smmu.h b/drivers/video/fbdev/msm/mdss_smmu.h
index 73b978b72f0e..b1ee17a01c3f 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.h
+++ b/drivers/video/fbdev/msm/mdss_smmu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2007-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,13 @@ struct mdss_smmu_domain {
unsigned long size;
};
+struct mdss_smmu_private {
+ struct device_node *pdev;
+ struct list_head smmu_device_list;
+ struct list_head user_list;
+ struct mutex smmu_reg_lock;
+};
+
void mdss_smmu_register(struct device *dev);
int mdss_smmu_init(struct mdss_data_type *mdata, struct device *dev);
@@ -135,13 +142,12 @@ static inline int mdss_smmu_get_domain_type(u64 flags, bool rotator)
if (flags & MDP_SECURE_OVERLAY_SESSION) {
type = (rotator &&
- mdata->mdss_smmu[MDSS_IOMMU_DOMAIN_ROT_SECURE].dev) ?
- MDSS_IOMMU_DOMAIN_ROT_SECURE : MDSS_IOMMU_DOMAIN_SECURE;
+ mdata->mdss_smmu[MDSS_IOMMU_DOMAIN_ROT_SECURE].base.dev) ?
+ MDSS_IOMMU_DOMAIN_ROT_SECURE : MDSS_IOMMU_DOMAIN_SECURE;
} else {
type = (rotator &&
- mdata->mdss_smmu[MDSS_IOMMU_DOMAIN_ROT_UNSECURE].dev) ?
- MDSS_IOMMU_DOMAIN_ROT_UNSECURE :
- MDSS_IOMMU_DOMAIN_UNSECURE;
+ mdata->mdss_smmu[MDSS_IOMMU_DOMAIN_ROT_UNSECURE].base.dev) ?
+ MDSS_IOMMU_DOMAIN_ROT_UNSECURE : MDSS_IOMMU_DOMAIN_UNSECURE;
}
return type;
}
diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c
index 30f8ca0487a7..d74b1432ea71 100644
--- a/drivers/video/fbdev/msm/msm_ext_display.c
+++ b/drivers/video/fbdev/msm/msm_ext_display.c
@@ -381,7 +381,7 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp,
}
reinit_completion(&ext_disp->hpd_comp);
- ret = wait_for_completion_timeout(&ext_disp->hpd_comp, HZ * 2);
+ ret = wait_for_completion_timeout(&ext_disp->hpd_comp, HZ * 5);
if (!ret) {
pr_err("display timeout\n");
ret = -EINVAL;
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm660.h b/include/dt-bindings/clock/qcom,gcc-sdm660.h
index e66633c74c0c..cd5b78e59c5b 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm660.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm660.h
@@ -99,7 +99,6 @@
#define GCC_QSPI_SER_CLK 86
#define GCC_RX0_USB2_CLKREF_CLK 87
#define GCC_RX1_USB2_CLKREF_CLK 88
-#define GCC_RX2_QLINK_CLKREF_CLK 89
#define GCC_SDCC1_AHB_CLK 90
#define GCC_SDCC1_APPS_CLK 91
#define GCC_SDCC1_ICE_CORE_CLK 92
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/iio/consumer.h b/include/linux/iio/consumer.h
index fad58671c49e..62acf17a894b 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -161,6 +161,16 @@ int iio_read_channel_processed(struct iio_channel *chan, int *val);
int iio_write_channel_raw(struct iio_channel *chan, int val);
/**
+ * iio_write_channel_processed() - write to a given channel
+ * @chan: The channel being queried.
+ * @val: Value being written.
+ *
+ * Note processed writes to iio channels are converted to raw
+ * values before being written.
+ */
+int iio_write_channel_processed(struct iio_channel *chan, int val);
+
+/**
* iio_get_channel_type() - get the type of a channel
* @channel: The channel being queried.
* @type: The type of the channel.
diff --git a/include/linux/mdss_smmu_ext.h b/include/linux/mdss_smmu_ext.h
new file mode 100644
index 000000000000..12ad4305f145
--- /dev/null
+++ b/include/linux/mdss_smmu_ext.h
@@ -0,0 +1,53 @@
+/* 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.
+ *
+ */
+
+#ifndef MDSS_SMMU_EXT_H
+#define MDSS_SMMU_EXT_H
+
+/**
+ * struct msm_smmu:interface exposed to the clients which use smmu driver.
+ * @dev: smmu device for attach/dettach
+ * @domain: domain for the context bank.
+ * @is_secure: bool variable to check for secure domain.
+ * @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;
+ int domain;
+ bool is_secure;
+ 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);
+
+/**
+ * mdss_smmu_request_mappings: function to request smmu mappings.
+ * Client driver can request smmu dev via this API.
+ * dev will be returned in the same call context
+ * if probe is not finished then dev will be
+ * returned once it is completed.
+ * @callback: callback function that is called to return smmu
+ * dev
+ */
+
+int mdss_smmu_request_mappings(msm_smmu_handler_t callback);
+
+#endif /* MDSS_SMMU_EXT_H */
diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h
index 44a04b5c2fcd..4378080da0d9 100644
--- a/include/linux/msm_ext_display.h
+++ b/include/linux/msm_ext_display.h
@@ -91,7 +91,7 @@ enum msm_ext_disp_power_state {
/**
* struct msm_ext_disp_intf_ops - operations exposed to display interface
* @hpd: updates external display interface state
- * @notify: updates audio framework with interface state
+ * @notify: acknowledgment to power on or off
*/
struct msm_ext_disp_intf_ops {
int (*hpd)(struct platform_device *pdev,
@@ -100,8 +100,7 @@ struct msm_ext_disp_intf_ops {
u32 flags);
int (*notify)(struct platform_device *pdev,
enum msm_ext_disp_cable_state state);
- int (*ack)(struct platform_device *pdev,
- u32 ack);
+ int (*ack)(struct platform_device *pdev, u32 ack);
};
/**
diff --git a/include/linux/pfk.h b/include/linux/pfk.h
index 2fc64442b8ee..82ee74199752 100644
--- a/include/linux/pfk.h
+++ b/include/linux/pfk.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
@@ -24,6 +24,7 @@ int pfk_load_key_start(const struct bio *bio,
int pfk_load_key_end(const struct bio *bio, bool *is_pfe);
int pfk_remove_key(const unsigned char *key, size_t key_size);
bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2);
+void pfk_clear_on_reset(void);
#else
static inline int pfk_load_key_start(const struct bio *bio,
@@ -48,6 +49,9 @@ static inline bool pfk_allow_merge_bio(const struct bio *bio1,
return true;
}
+static inline void pfk_clear_on_reset(void)
+{}
+
#endif /* CONFIG_PFK */
#endif /* PFK_H */
diff --git a/include/linux/pid.h b/include/linux/pid.h
index 23705a53abba..97b745ddece5 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -8,7 +8,9 @@ enum pid_type
PIDTYPE_PID,
PIDTYPE_PGID,
PIDTYPE_SID,
- PIDTYPE_MAX
+ PIDTYPE_MAX,
+ /* only valid to __task_pid_nr_ns() */
+ __PIDTYPE_TGID
};
/*
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 8f95c91c059a..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,6 +241,9 @@ enum power_supply_property {
POWER_SUPPLY_PROP_FCC_DELTA,
POWER_SUPPLY_PROP_ICL_REDUCTION,
POWER_SUPPLY_PROP_PARALLEL_MODE,
+ 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/qdsp6v2/rtac.h b/include/linux/qdsp6v2/rtac.h
index 3e5433b23a51..eeea0eb0a837 100644
--- a/include/linux/qdsp6v2/rtac.h
+++ b/include/linux/qdsp6v2/rtac.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011, 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2013-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
@@ -95,4 +96,5 @@ int rtac_clear_mapping(uint32_t cal_type);
bool rtac_make_afe_callback(uint32_t *payload, u32 payload_size);
void rtac_set_afe_handle(void *handle);
void get_rtac_adm_data(struct rtac_adm *adm_data);
+void rtac_update_afe_topology(u32 port_id);
#endif
diff --git a/include/linux/regulator/qpnp-regulator.h b/include/linux/regulator/qpnp-regulator.h
index c7afeb50f244..36288c068ac3 100644
--- a/include/linux/regulator/qpnp-regulator.h
+++ b/include/linux/regulator/qpnp-regulator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -158,8 +158,8 @@ enum qpnp_boost_current_limit {
struct qpnp_regulator_platform_data {
struct regulator_init_data init_data;
int pull_down_enable;
- unsigned pin_ctrl_enable;
- unsigned pin_ctrl_hpm;
+ unsigned int pin_ctrl_enable;
+ unsigned int pin_ctrl_hpm;
int system_load;
int enable_time;
int ocp_enable;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index aca5c5694e09..708c4284b8d9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2107,15 +2107,8 @@ static inline pid_t task_tgid_nr(struct task_struct *tsk)
return tsk->tgid;
}
-pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
-
-static inline pid_t task_tgid_vnr(struct task_struct *tsk)
-{
- return pid_vnr(task_tgid(tsk));
-}
-
-
static inline int pid_alive(const struct task_struct *p);
+static inline pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns);
static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns)
{
pid_t pid = 0;
@@ -2156,6 +2149,16 @@ static inline pid_t task_session_vnr(struct task_struct *tsk)
return __task_pid_nr_ns(tsk, PIDTYPE_SID, NULL);
}
+static inline pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
+{
+ return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, ns);
+}
+
+static inline pid_t task_tgid_vnr(struct task_struct *tsk)
+{
+ return __task_pid_nr_ns(tsk, __PIDTYPE_TGID, NULL);
+}
+
/* obsolete, do not use */
static inline pid_t task_pgrp_nr(struct task_struct *tsk)
{
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/icnss.h b/include/soc/qcom/icnss.h
index 6b567d7a08d3..731fa6970b95 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -17,6 +17,16 @@
#define ICNSS_MAX_IRQ_REGISTRATIONS 12
#define ICNSS_MAX_TIMESTAMP_LEN 32
+enum icnss_uevent {
+ ICNSS_UEVENT_FW_READY,
+ ICNSS_UEVENT_FW_CRASHED,
+};
+
+struct icnss_uevent_data {
+ enum icnss_uevent uevent;
+ void *data;
+};
+
struct icnss_driver_ops {
char *name;
int (*probe)(struct device *dev);
@@ -28,6 +38,7 @@ struct icnss_driver_ops {
int (*pm_resume)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
+ int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent);
};
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/soc/qcom/service-notifier.h b/include/soc/qcom/service-notifier.h
index 0106801fc173..740f7f644a02 100644
--- a/include/soc/qcom/service-notifier.h
+++ b/include/soc/qcom/service-notifier.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -25,9 +25,12 @@ enum qmi_servreg_notif_service_state_enum_type_v01 {
};
enum pd_subsys_state {
- CRASHED,
- SHUTDOWN,
- UNKNOWN,
+ ROOT_PD_DOWN,
+ ROOT_PD_UP,
+ ROOT_PD_ERR_FATAL,
+ ROOT_PD_WDOG_BITE,
+ ROOT_PD_SHUTDOWN,
+ USER_PD_STATE_CHANGE,
};
#if defined(CONFIG_MSM_SERVICE_NOTIFIER)
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/jack.h b/include/sound/jack.h
index 424f8fbae601..0d2a334fbeaa 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -66,12 +66,12 @@ enum snd_jack_types {
SND_JACK_MICROPHONE2,
/* Kept separate from switches to facilitate implementation */
- SND_JACK_BTN_0 = 0x4000,
- SND_JACK_BTN_1 = 0x2000,
- SND_JACK_BTN_2 = 0x1000,
- SND_JACK_BTN_3 = 0x0800,
- SND_JACK_BTN_4 = 0x0400,
- SND_JACK_BTN_5 = 0x0200,
+ SND_JACK_BTN_0 = 0x8000,
+ SND_JACK_BTN_1 = 0x4000,
+ SND_JACK_BTN_2 = 0x2000,
+ SND_JACK_BTN_3 = 0x1000,
+ SND_JACK_BTN_4 = 0x0800,
+ SND_JACK_BTN_5 = 0x0400,
};
/* Keep in sync with definitions above */
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index 25376315dd20..42d048f24e12 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -58,9 +58,9 @@ enum {
struct route_payload {
unsigned int copp_idx[MAX_COPPS_PER_PORT];
unsigned int port_id[MAX_COPPS_PER_PORT];
- int app_type;
- int acdb_dev_id;
- int sample_rate;
+ int app_type[MAX_COPPS_PER_PORT];
+ int acdb_dev_id[MAX_COPPS_PER_PORT];
+ int sample_rate[MAX_COPPS_PER_PORT];
unsigned short num_copps;
unsigned int session_id;
};
diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h
index a47d2805b9c5..b1c3b0baf4b3 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -42,6 +42,8 @@
#define AFE_CLK_VERSION_V1 1
#define AFE_CLK_VERSION_V2 2
+typedef int (*routing_cb)(int port);
+
enum {
/* IDX 0->4 */
IDX_PRIMARY_I2S_RX,
@@ -362,5 +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/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/kernel/pid.c b/kernel/pid.c
index 78b3d9f80d44..b17263be9082 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -526,8 +526,11 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
if (!ns)
ns = task_active_pid_ns(current);
if (likely(pid_alive(task))) {
- if (type != PIDTYPE_PID)
+ if (type != PIDTYPE_PID) {
+ if (type == __PIDTYPE_TGID)
+ type = PIDTYPE_PID;
task = task->group_leader;
+ }
nr = pid_nr_ns(rcu_dereference(task->pids[type].pid), ns);
}
rcu_read_unlock();
@@ -536,12 +539,6 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
}
EXPORT_SYMBOL(__task_pid_nr_ns);
-pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
-{
- return pid_nr_ns(task_tgid(tsk), ns);
-}
-EXPORT_SYMBOL(task_tgid_nr_ns);
-
struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
{
return ns_of_pid(task_pid(tsk));
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index 1b6fe3d31b64..744c60dfb4fb 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -718,7 +718,7 @@ __read_mostly unsigned int sysctl_sched_cpu_high_irqload = (10 * NSEC_PER_MSEC);
unsigned int __read_mostly sysctl_sched_enable_thread_grouping;
-__read_mostly unsigned int sysctl_sched_new_task_windows = 5;
+#define SCHED_NEW_TASK_WINDOWS 5
#define SCHED_FREQ_ACCOUNT_WAIT_TIME 0
@@ -959,8 +959,8 @@ unsigned int __read_mostly sysctl_sched_restrict_cluster_spill;
unsigned int __read_mostly sysctl_sched_short_burst;
unsigned int __read_mostly sysctl_sched_short_sleep = 1 * NSEC_PER_MSEC;
-static void
-_update_up_down_migrate(unsigned int *up_migrate, unsigned int *down_migrate)
+static void _update_up_down_migrate(unsigned int *up_migrate,
+ unsigned int *down_migrate, bool is_group)
{
unsigned int delta;
@@ -974,7 +974,8 @@ _update_up_down_migrate(unsigned int *up_migrate, unsigned int *down_migrate)
*up_migrate >>= 10;
*up_migrate *= NSEC_PER_USEC;
- *up_migrate = min(*up_migrate, sched_ravg_window);
+ if (!is_group)
+ *up_migrate = min(*up_migrate, sched_ravg_window);
*down_migrate /= NSEC_PER_USEC;
*down_migrate *= up_down_migrate_scale_factor;
@@ -989,14 +990,14 @@ static void update_up_down_migrate(void)
unsigned int up_migrate = pct_to_real(sysctl_sched_upmigrate_pct);
unsigned int down_migrate = pct_to_real(sysctl_sched_downmigrate_pct);
- _update_up_down_migrate(&up_migrate, &down_migrate);
+ _update_up_down_migrate(&up_migrate, &down_migrate, false);
sched_upmigrate = up_migrate;
sched_downmigrate = down_migrate;
up_migrate = pct_to_real(sysctl_sched_group_upmigrate_pct);
down_migrate = pct_to_real(sysctl_sched_group_downmigrate_pct);
- _update_up_down_migrate(&up_migrate, &down_migrate);
+ _update_up_down_migrate(&up_migrate, &down_migrate, true);
sched_group_upmigrate = up_migrate;
sched_group_downmigrate = down_migrate;
}
@@ -1849,7 +1850,7 @@ static int account_busy_for_cpu_time(struct rq *rq, struct task_struct *p,
static inline bool is_new_task(struct task_struct *p)
{
- return p->ravg.active_windows < sysctl_sched_new_task_windows;
+ return p->ravg.active_windows < SCHED_NEW_TASK_WINDOWS;
}
#define INC_STEP 8
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 7112dc54d88e..ffa85996313c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -449,13 +449,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
{
- .procname = "sched_new_task_windows",
- .data = &sysctl_sched_new_task_windows,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = sched_window_update_handler,
- },
- {
.procname = "sched_pred_alert_freq",
.data = &sysctl_sched_pred_alert_freq,
.maxlen = sizeof(unsigned int),
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 46e60923221f..5dd643d524d6 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -208,6 +208,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
u8 *data;
bool pfmemalloc;
+ if (IS_ENABLED(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE))
+ gfp_mask |= GFP_DMA;
+
cache = (flags & SKB_ALLOC_FCLONE)
? skbuff_fclone_cache : skbuff_head_cache;
@@ -358,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);
@@ -416,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/security/pfe/pfk.c b/security/pfe/pfk.c
index 7e38c9fbf171..2e5aa2fb6688 100644
--- a/security/pfe/pfk.c
+++ b/security/pfe/pfk.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -476,6 +476,18 @@ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2)
return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2,
inode1, inode2);
}
+/**
+ * Flush key table on storage core reset. During core reset key configuration
+ * is lost in ICE. We need to flash the cache, so that the keys will be
+ * reconfigured again for every subsequent transaction
+ */
+void pfk_clear_on_reset(void)
+{
+ if (!pfk_is_ready())
+ return;
+
+ pfk_kc_clear_on_reset();
+}
module_init(pfk_init);
module_exit(pfk_exit);
diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c
index cd3f08b3959d..39e67569a1dd 100644
--- a/security/pfe/pfk_kc.c
+++ b/security/pfe/pfk_kc.c
@@ -826,3 +826,27 @@ out:
return res;
}
+
+/**
+ * pfk_kc_clear_on_reset() - clear the table and remove all keys from ICE
+ * The assumption is that at this point we don't have any pending transactions
+ * Also, there is no need to clear keys from ICE
+ *
+ * Return 0 on success, error otherwise
+ *
+ */
+void pfk_kc_clear_on_reset(void)
+{
+ struct kc_entry *entry = NULL;
+ int i = 0;
+
+ if (!kc_is_ready())
+ return;
+
+ kc_spin_lock();
+ for (i = 0; i < PFK_KC_TABLE_SIZE; i++) {
+ entry = kc_entry_at_index(i);
+ kc_clear_entry(entry);
+ }
+ kc_spin_unlock();
+}
diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h
index ce3fac7edbbe..0b0ec8825c15 100644
--- a/security/pfe/pfk_kc.h
+++ b/security/pfe/pfk_kc.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
@@ -26,6 +26,7 @@ int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size,
const unsigned char *salt, size_t salt_size);
int pfk_kc_remove_key(const unsigned char *key, size_t key_size);
int pfk_kc_clear(void);
+void pfk_kc_clear_on_reset(void);
diff --git a/sound/soc/codecs/msm_hdmi_codec_rx.c b/sound/soc/codecs/msm_hdmi_codec_rx.c
index 7d649ba2b505..8ae789a90f33 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.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
@@ -85,6 +85,15 @@ static int msm_ext_disp_edid_get(struct snd_kcontrol *kcontrol,
rc = codec_data->ext_disp_ops.get_audio_edid_blk(
codec_data->ext_disp_core_pdev, &edid_blk);
if (!IS_ERR_VALUE(rc)) {
+ if (sizeof(ucontrol->value.bytes.data) <
+ (edid_blk.audio_data_blk_size +
+ edid_blk.spk_alloc_data_blk_size)) {
+ dev_err(codec->dev,
+ "%s: Not enough memory to copy EDID data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
memcpy(ucontrol->value.bytes.data,
edid_blk.audio_data_blk,
edid_blk.audio_data_blk_size);
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 85cf0eb48ee0..8f7db4d13378 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -3989,7 +3989,7 @@ static ssize_t msm_anlg_codec_version_read(struct snd_info_entry *entry,
switch (get_codec_version(sdm660_cdc_priv)) {
case DRAX_CDC:
- len = snprintf(buffer, sizeof(buffer), "DRAX_CDC_1_0\n");
+ len = snprintf(buffer, sizeof(buffer), "DRAX-CDC_1_0\n");
break;
default:
len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
index df0bdf666ba1..5e078dba0448 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -1089,7 +1089,7 @@ static ssize_t msm_dig_codec_version_read(struct snd_info_entry *entry,
switch (msm_dig->version) {
case DRAX_CDC:
- len = snprintf(buffer, sizeof(buffer), "DRAX_CDC_1_0\n");
+ len = snprintf(buffer, sizeof(buffer), "SDM660-CDC_1_0\n");
break;
default:
len = snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n");
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 8454ebfc6216..e6e40d1d6a8f 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -2157,8 +2157,14 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
- /* Insertion debounce set to 96ms */
- WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
+ if (mbhc->mbhc_cfg->enable_usbc_analog) {
+ /* Insertion debounce set to 48ms */
+ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 4);
+ } else {
+ /* Insertion debounce set to 96ms */
+ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
+ }
+
/* Button Debounce set to 16ms */
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2);
@@ -2327,22 +2333,28 @@ static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc,
int rc = 0;
struct usbc_ana_audio_config *config =
&mbhc->mbhc_cfg->usbc_analog_cfg;
+ union power_supply_propval pval;
dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n",
__func__, active);
+
+ memset(&pval, 0, sizeof(pval));
+
if (active) {
- if (config->usbc_en1_gpio_p) {
+ pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
+ if (power_supply_set_property(mbhc->usb_psy,
+ POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+ dev_info(mbhc->codec->dev, "%s: force PR_SOURCE mode unsuccessful\n",
+ __func__);
+ else
+ mbhc->usbc_force_pr_mode = true;
+
+ if (config->usbc_en1_gpio_p)
rc = msm_cdc_pinctrl_select_active_state(
config->usbc_en1_gpio_p);
- /* delay required to allow the hw to stabilize */
- usleep_range(1000, 1200);
- }
- if (rc == 0 && config->usbc_en2n_gpio_p) {
+ if (rc == 0 && config->usbc_en2n_gpio_p)
rc = msm_cdc_pinctrl_select_active_state(
config->usbc_en2n_gpio_p);
- /* delay required to allow the hw to stabilize */
- usleep_range(1000, 1200);
- }
if (rc == 0 && config->usbc_force_gpio_p)
rc = msm_cdc_pinctrl_select_active_state(
config->usbc_force_gpio_p);
@@ -2358,6 +2370,17 @@ static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc,
if (config->usbc_force_gpio_p)
msm_cdc_pinctrl_select_sleep_state(
config->usbc_force_gpio_p);
+
+ if (mbhc->usbc_force_pr_mode) {
+ pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+ if (power_supply_set_property(mbhc->usb_psy,
+ POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
+ dev_info(mbhc->codec->dev, "%s: force PR_DUAL mode unsuccessful\n",
+ __func__);
+
+ mbhc->usbc_force_pr_mode = false;
+ }
+
mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE;
}
diff --git a/sound/soc/codecs/wcd-mbhc-v2.h b/sound/soc/codecs/wcd-mbhc-v2.h
index 6f23a2dcbff7..32d9801468f9 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.h
+++ b/sound/soc/codecs/wcd-mbhc-v2.h
@@ -456,6 +456,7 @@ struct wcd_mbhc {
unsigned long intr_status;
bool is_hph_ocp_pending;
+ bool usbc_force_pr_mode;
int usbc_mode;
struct notifier_block psy_nb;
struct power_supply *usb_psy;
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsd.c b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
index 580591a32ba1..3e23e3749bda 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.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
@@ -97,6 +97,11 @@ static const struct snd_soc_dapm_route tavil_dsd_audio_map[] = {
{"DSD_FILTER_1", NULL, "DSD_R IF MUX"},
{"DSD_FILTER_1", NULL, "RX INT2 NATIVE SUPPLY"},
{"RX INT2 MIX3", "DSD HPHR Switch", "DSD_FILTER_1"},
+
+ {"DSD_FILTER_0", NULL, "RX INT3 NATIVE SUPPLY"},
+ {"RX INT3 MIX3", "DSD LO1 Switch", "DSD_FILTER_0"},
+ {"DSD_FILTER_1", NULL, "RX INT4 NATIVE SUPPLY"},
+ {"RX INT4 MIX3", "DSD LO2 Switch", "DSD_FILTER_1"},
};
static bool is_valid_dsd_interpolator(int interp_num)
diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h
index cd165af43eab..afd93b2cf56d 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-routing.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h
@@ -872,7 +872,8 @@ const struct snd_soc_dapm_route tavil_audio_map[] = {
{"RX INT3 SEC MIX", NULL, "RX INT3_1 INTERP"},
{"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"},
{"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"},
- {"RX INT3 DAC", NULL, "RX INT3 MIX2"},
+ {"RX INT3 MIX3", NULL, "RX INT3 MIX2"},
+ {"RX INT3 DAC", NULL, "RX INT3 MIX3"},
{"RX INT3 DAC", NULL, "RX_BIAS"},
{"LINEOUT1 PA", NULL, "RX INT3 DAC"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
@@ -882,7 +883,8 @@ const struct snd_soc_dapm_route tavil_audio_map[] = {
{"RX INT4 SEC MIX", NULL, "RX INT4_1 MIX1"},
{"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"},
{"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"},
- {"RX INT4 DAC", NULL, "RX INT4 MIX2"},
+ {"RX INT4 MIX3", NULL, "RX INT4 MIX2"},
+ {"RX INT4 DAC", NULL, "RX INT4 MIX3"},
{"RX INT4 DAC", NULL, "RX_BIAS"},
{"LINEOUT2 PA", NULL, "RX INT4 DAC"},
{"LINEOUT2", NULL, "LINEOUT2 PA"},
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 5b300a668489..4fe9e2d50f7a 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -2295,6 +2295,9 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0;
+ u16 dsd_mute_reg = 0, dsd_clk_reg = 0;
+ struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+ struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
@@ -2302,9 +2305,13 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
if (w->shift == 7) {
lineout_vol_reg = WCD934X_CDC_RX3_RX_PATH_CTL;
lineout_mix_vol_reg = WCD934X_CDC_RX3_RX_PATH_MIX_CTL;
+ dsd_mute_reg = WCD934X_CDC_DSD0_CFG2;
+ dsd_clk_reg = WCD934X_CDC_DSD0_PATH_CTL;
} else if (w->shift == 6) {
lineout_vol_reg = WCD934X_CDC_RX4_RX_PATH_CTL;
lineout_mix_vol_reg = WCD934X_CDC_RX4_RX_PATH_MIX_CTL;
+ dsd_mute_reg = WCD934X_CDC_DSD1_CFG2;
+ dsd_clk_reg = WCD934X_CDC_DSD1_PATH_CTL;
}
} else {
dev_err(codec->dev, "%s: Error enabling lineout PA\n",
@@ -2329,6 +2336,12 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec,
lineout_mix_vol_reg,
0x10, 0x00);
+ if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+ snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x00);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+ snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x04);
break;
case SND_SOC_DAPM_POST_PMD:
/*
@@ -6821,6 +6834,16 @@ static const struct snd_kcontrol_new hphr_mixer[] = {
tavil_dsd_mixer_get, tavil_dsd_mixer_put),
};
+static const struct snd_kcontrol_new lo1_mixer[] = {
+ SOC_SINGLE_EXT("DSD LO1 Switch", SND_SOC_NOPM, INTERP_LO1, 1, 0,
+ tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
+static const struct snd_kcontrol_new lo2_mixer[] = {
+ SOC_SINGLE_EXT("DSD LO2 Switch", SND_SOC_NOPM, INTERP_LO2, 1, 0,
+ tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
AIF1_PB, 0, tavil_codec_enable_slimrx,
@@ -6953,7 +6976,11 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("RX INT2 MIX3", SND_SOC_NOPM, 0, 0, hphr_mixer,
ARRAY_SIZE(hphr_mixer)),
SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3 MIX3", SND_SOC_NOPM, 0, 0, lo1_mixer,
+ ARRAY_SIZE(lo1_mixer)),
SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4 MIX3", SND_SOC_NOPM, 0, 0, lo2_mixer,
+ ARRAY_SIZE(lo2_mixer)),
SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0,
NULL, 0, tavil_codec_spk_boost_event,
@@ -7342,11 +7369,11 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0,
tavil_codec_enable_lineout_pa,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0,
tavil_codec_enable_lineout_pa,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0,
tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
@@ -8071,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)
@@ -8086,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);
}
@@ -8104,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_write(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+ 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);
@@ -8141,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 */
@@ -8162,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,
@@ -8183,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/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index 2d9a5101dd95..bd92ccc9e009 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -247,15 +247,15 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
* to CLK_SYS_MCLK_PRG
*/
wcd_resmgr_codec_reg_update_bits(resmgr,
- WCD934X_CLK_SYS_MCLK_PRG, 0x91, 0x91);
+ WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x80);
+ wcd_resmgr_codec_reg_update_bits(resmgr,
+ WCD934X_CLK_SYS_MCLK_PRG, 0x30, 0x10);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
wcd_resmgr_codec_reg_update_bits(resmgr,
- WCD934X_CLK_SYS_INT_CLK_TEST2, 0x04,
- 0x04);
+ WCD934X_CLK_SYS_MCLK_PRG, 0x01, 0x01);
wcd_resmgr_codec_reg_update_bits(resmgr,
- WCD934X_CLK_SYS_INT_CLK_TEST2, 0x04,
- 0x00);
+ WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x00);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
0x01, 0x01);
@@ -308,6 +308,9 @@ static int wcd_resmgr_disable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
0x08, 0x08);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD934X_CLK_SYS_MCLK_PRG, 0x02, 0x02);
+ /* Disable clock buffer */
+ wcd_resmgr_codec_reg_update_bits(resmgr,
+ WCD934X_CLK_SYS_MCLK_PRG, 0x80, 0x00);
resmgr->clk_type = WCD_CLK_RCO;
} else {
wcd_resmgr_codec_reg_update_bits(resmgr,
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 171735c8efd4..ba74175dbe10 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -759,15 +759,13 @@ static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
wsa881x_resource_acquire(codec, ENABLE);
- if (wsa881x->boost_enable)
- wsa881x_boost_ctrl(codec, ENABLE);
+ wsa881x_boost_ctrl(codec, ENABLE);
break;
case SND_SOC_DAPM_POST_PMD:
swr_slvdev_datapath_control(wsa881x->swr_slave,
wsa881x->swr_slave->dev_num,
false);
- if (wsa881x->boost_enable)
- wsa881x_boost_ctrl(codec, DISABLE);
+ wsa881x_boost_ctrl(codec, DISABLE);
wsa881x_resource_acquire(codec, DISABLE);
break;
}
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 391640d53d56..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,
@@ -514,6 +533,8 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = {
.key_code[7] = 0,
.linein_th = 5000,
.moisture_en = true,
+ .anc_micbias = MIC_BIAS_2,
+ .enable_anc_mic_detect = false,
};
static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
@@ -3809,7 +3830,6 @@ static int msm_aux_pcm_snd_startup(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int index = cpu_dai->id - 1;
- return ret = 0;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -3992,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;
@@ -3999,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",
@@ -4012,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
@@ -4064,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);
@@ -4082,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 = {
@@ -5209,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,
},
{
@@ -6844,14 +7155,19 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
pdev->dev.of_node->full_name);
dev_dbg(&pdev->dev, "Jack type properties set to default");
} else {
- if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
+ if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
+ } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
+ } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
- else
+ } else {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
dev_dbg(&pdev->dev, "Unknown value, set to default");
+ }
}
/*
* Parse US-Euro gpio info from DT. Report no error if us-euro
@@ -6877,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;
@@ -6894,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-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 2ba41ac1877f..7f032dcceabd 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -100,7 +100,7 @@ struct msm_compr_gapless_state {
static unsigned int supported_sample_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000,
- 88200, 96000, 176400, 192000, 352800, 384000, 2822400, 5644800
+ 88200, 96000, 128000, 176400, 192000, 352800, 384000, 2822400, 5644800
};
struct msm_compr_pdata {
@@ -3220,48 +3220,45 @@ static int msm_compr_playback_app_type_cfg_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
- if (0 != ucontrol->value.integer.value[2])
+ if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -3271,8 +3268,8 @@ static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_RX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -3282,48 +3279,45 @@ static int msm_compr_capture_app_type_cfg_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -3333,8 +3327,8 @@ static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_TX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
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-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 55ca659567f5..3fa14d0113ef 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -2204,26 +2204,26 @@ static int msm_lsm_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if ((fe_id < MSM_FRONTEND_DAI_LSM1) ||
- (fe_id > MSM_FRONTEND_DAI_LSM8)) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
return 0;
}
@@ -2232,21 +2232,17 @@ static int msm_lsm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if ((fe_id < MSM_FRONTEND_DAI_LSM1) ||
- (fe_id > MSM_FRONTEND_DAI_LSM8)) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -2256,8 +2252,8 @@ static int msm_lsm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_TX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index bd1468beedf6..b8610b59ca63 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.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
@@ -556,48 +556,45 @@ static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -607,8 +604,8 @@ static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_RX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -618,48 +615,45 @@ static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -669,8 +663,8 @@ static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_TX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
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 9b672d803d31..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)
{
@@ -1182,48 +1342,45 @@ static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
- if (0 != ucontrol->value.integer.value[2])
+ if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -1233,8 +1390,8 @@ static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_RX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -1244,48 +1401,45 @@ static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -1295,8 +1449,8 @@ static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_TX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -1387,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 39fdd6b49357..cfade420c509 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -56,8 +56,6 @@
#define DS2_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFF
#endif
-static int get_cal_path(int path_type);
-
static struct mutex routing_lock;
static struct cal_type_data *cal_data;
@@ -103,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 {
@@ -124,6 +125,18 @@ static struct msm_pcm_route_bdai_pp_params
{DISPLAY_PORT_RX, 0, 0, 0},
};
+/*
+ * The be_dai_name_table is passed to HAL so that it can specify the
+ * BE ID for the BE it wants to enable based on the name. Thus there
+ * is a matching table and structure in HAL that need to be updated
+ * if any changes to these are made.
+ */
+struct msm_pcm_route_bdai_name {
+ unsigned int be_id;
+ char be_name[LPASS_BE_NAME_MAX_LENGTH];
+};
+static struct msm_pcm_route_bdai_name be_dai_name_table[MSM_BACKEND_DAI_MAX];
+
static int msm_routing_send_device_pp_params(int port_id, int copp_idx);
static int msm_routing_get_bit_width(unsigned int format)
@@ -663,7 +676,7 @@ static unsigned long session_copp_map[MSM_FRONTEND_DAI_MAX][2]
static struct msm_pcm_routing_app_type_data app_type_cfg[MAX_APP_TYPES];
static struct msm_pcm_routing_app_type_data lsm_app_type_cfg[MAX_APP_TYPES];
static struct msm_pcm_stream_app_type_cfg
- fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MAX][2];
+ fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MAX][2][MSM_BACKEND_DAI_MAX];
/* The caller of this should aqcuire routing lock */
void msm_pcm_routing_get_bedai_info(int be_idx,
@@ -731,45 +744,64 @@ static bool is_mm_lsm_fe_id(int fe_id)
return rc;
}
-
-void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
- int acdb_dev_id, int sample_rate, int session_type)
+int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
+ int be_id, int app_type,
+ int acdb_dev_id, int sample_rate)
{
- pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fedai_id, session_type, app_type,
- acdb_dev_id, sample_rate);
+ int ret = 0;
+
+ pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+
if (!is_mm_lsm_fe_id(fedai_id)) {
pr_err("%s: Invalid machine driver ID %d\n",
__func__, fedai_id);
- return;
+ ret = -EINVAL;
+ goto done;
}
if (session_type != SESSION_TYPE_RX &&
session_type != SESSION_TYPE_TX) {
pr_err("%s: Invalid session type %d\n",
__func__, session_type);
- return;
+ ret = -EINVAL;
+ goto done;
+ }
+ if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds be_id %d\n",
+ __func__, be_id);
+ ret = -EINVAL;
+ goto done;
}
- fe_dai_app_type_cfg[fedai_id][session_type].app_type = app_type;
- fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id = acdb_dev_id;
- fe_dai_app_type_cfg[fedai_id][session_type].sample_rate = sample_rate;
+
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type = app_type;
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id =
+ acdb_dev_id;
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate =
+ sample_rate;
+
+done:
+ return ret;
}
/**
* msm_pcm_routing_get_stream_app_type_cfg
*
- * Receives fedai_id, session_type and populates app_type, acdb_dev_id, &
- * sample rate. Returns 0 on success. On failure returns
+ * Receives fedai_id, session_type, be_id, and populates app_type,
+ * acdb_dev_id, & sample rate. Returns 0 on success. On failure returns
* -EINVAL and does not alter passed values.
*
* fedai_id - Passed value, front end ID for which app type config is wanted
* session_type - Passed value, session type for which app type config
* is wanted
+ * be_id - Passed value, back end device id for which app type config is wanted
* app_type - Returned value, app type used by app type config
* acdb_dev_id - Returned value, ACDB device ID used by app type config
* sample_rate - Returned value, sample rate used by app type config
*/
int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
- int *app_type, int *acdb_dev_id, int *sample_rate)
+ int be_id, int *app_type,
+ int *acdb_dev_id, int *sample_rate)
{
int ret = 0;
@@ -791,18 +823,25 @@ int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
ret = -EINVAL;
goto done;
} else if (session_type != SESSION_TYPE_RX &&
- session_type != SESSION_TYPE_TX) {
+ session_type != SESSION_TYPE_TX) {
pr_err("%s: Invalid session type %d\n",
__func__, session_type);
ret = -EINVAL;
goto done;
+ } else if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds be_id %d\n",
+ __func__, be_id);
+ return -EINVAL;
}
- *app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
- *acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
- *sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
- pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fedai_id, session_type,
+ *app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
+ *acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
+ *sample_rate =
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate;
+
+ pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type, be_id,
*app_type, *acdb_dev_id, *sample_rate);
done:
return ret;
@@ -858,24 +897,27 @@ static struct cal_block_data *msm_routing_find_topology(int path,
return msm_routing_find_topology_by_path(path);
}
-static int msm_routing_get_adm_topology(int path, int fedai_id,
- int session_type)
+static int msm_routing_get_adm_topology(int fedai_id, int session_type,
+ int be_id)
{
- int topology = NULL_COPP_TOPOLOGY;
- struct cal_block_data *cal_block = NULL;
+ int topology = NULL_COPP_TOPOLOGY;
+ struct cal_block_data *cal_block = NULL;
int app_type = 0, acdb_dev_id = 0;
- pr_debug("%s\n", __func__);
- path = get_cal_path(path);
+ pr_debug("%s: fedai_id %d, session_type %d, be_id %d\n",
+ __func__, fedai_id, session_type, be_id);
+
if (cal_data == NULL)
goto done;
mutex_lock(&cal_data->lock);
- app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
- acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
+ app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
+ acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
- cal_block = msm_routing_find_topology(path, app_type, acdb_dev_id);
+ cal_block = msm_routing_find_topology(session_type, app_type,
+ acdb_dev_id);
if (cal_block == NULL)
goto unlock;
@@ -905,8 +947,8 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
int i, port_type, j, num_copps = 0;
struct route_payload payload;
- port_type = ((path_type == ADM_PATH_PLAYBACK ||
- path_type == ADM_PATH_COMPRESSED_RX) ?
+ port_type = ((path_type == ADM_PATH_PLAYBACK ||
+ path_type == ADM_PATH_COMPRESSED_RX) ?
MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
@@ -921,6 +963,18 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
payload.port_id[num_copps] =
msm_bedais[i].port_id;
payload.copp_idx[num_copps] = j;
+ payload.app_type[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][sess_type][i]
+ .app_type;
+ payload.acdb_dev_id[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][sess_type][i]
+ .acdb_dev_id;
+ payload.sample_rate[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][sess_type][i]
+ .sample_rate;
num_copps++;
}
}
@@ -930,12 +984,6 @@ static void msm_pcm_routing_build_matrix(int fedai_id, int sess_type,
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fedai_id][sess_type].strm_id;
- payload.app_type =
- fe_dai_app_type_cfg[fedai_id][sess_type].app_type;
- payload.acdb_dev_id =
- fe_dai_app_type_cfg[fedai_id][sess_type].acdb_dev_id;
- payload.sample_rate =
- fe_dai_app_type_cfg[fedai_id][sess_type].sample_rate;
adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
@@ -1001,7 +1049,8 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
int dspst_id, int stream_type,
uint32_t passthr_mode)
{
- int i, j, session_type, path_type, port_type, topology, num_copps = 0;
+ int i, j, session_type, path_type, port_type, topology;
+ int num_copps = 0;
struct route_payload payload;
u32 channels, sample_rate;
u16 bit_width = 16;
@@ -1069,13 +1118,13 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
bit_width = msm_routing_get_bit_width(
msm_bedais[i].format);
app_type =
- fe_dai_app_type_cfg[fe_id][session_type].app_type;
+ fe_dai_app_type_cfg[fe_id][session_type][i].app_type;
if (app_type && is_lsm) {
app_type_idx =
msm_pcm_routing_get_lsm_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[fe_id][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[fe_id][session_type][i]
+ .sample_rate;
bit_width =
lsm_app_type_cfg[app_type_idx].bit_width;
} else if (app_type) {
@@ -1083,19 +1132,21 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
msm_pcm_routing_get_app_type_idx(
app_type);
sample_rate =
- fe_dai_app_type_cfg[fe_id][session_type].sample_rate;
+ fe_dai_app_type_cfg[fe_id][session_type][i].sample_rate;
bit_width =
app_type_cfg[app_type_idx].bit_width;
} else {
sample_rate = msm_bedais[i].sample_rate;
}
acdb_dev_id =
- fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
- topology = msm_routing_get_adm_topology(path_type,
- fe_id, session_type);
-
- if (passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
- topology = COMPRESS_PASSTHROUGH_NONE_TOPOLOGY;
+ fe_dai_app_type_cfg[fe_id][session_type][i].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(fe_id,
+ session_type,
+ i);
+ 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);
@@ -1130,10 +1181,24 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
payload.port_id[num_copps] =
msm_bedais[i].port_id;
payload.copp_idx[num_copps] = j;
+ payload.app_type[num_copps] =
+ fe_dai_app_type_cfg
+ [fe_id][session_type][i]
+ .app_type;
+ payload.acdb_dev_id[num_copps] =
+ fe_dai_app_type_cfg
+ [fe_id][session_type][i]
+ .acdb_dev_id;
+ payload.sample_rate[num_copps] =
+ fe_dai_app_type_cfg
+ [fe_id][session_type][i]
+ .sample_rate;
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);
@@ -1143,12 +1208,6 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fe_id][session_type].strm_id;
- payload.app_type =
- fe_dai_app_type_cfg[fe_id][session_type].app_type;
- payload.acdb_dev_id =
- fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
- payload.sample_rate =
- fe_dai_app_type_cfg[fe_id][session_type].sample_rate;
adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
@@ -1247,22 +1306,24 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
msm_bedais[i].format);
app_type =
- fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ fe_dai_app_type_cfg[fedai_id][session_type][i].app_type;
if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[fedai_id][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[fedai_id][session_type][i]
+ .sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
sample_rate = msm_bedais[i].sample_rate;
acdb_dev_id =
- fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
- topology = msm_routing_get_adm_topology(path_type,
- fedai_id, session_type);
+ fe_dai_app_type_cfg[fedai_id][session_type][i]
+ .acdb_dev_id;
+ topology = msm_routing_get_adm_topology(fedai_id,
+ session_type,
+ i);
copp_idx = adm_open(msm_bedais[i].port_id, path_type,
sample_rate, channels, topology,
perf_mode, bits_per_sample,
@@ -1293,6 +1354,18 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
payload.port_id[num_copps] =
msm_bedais[i].port_id;
payload.copp_idx[num_copps] = j;
+ payload.app_type[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][session_type]
+ [i].app_type;
+ payload.acdb_dev_id[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][session_type]
+ [i].acdb_dev_id;
+ payload.sample_rate[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][session_type]
+ [i].sample_rate;
num_copps++;
}
}
@@ -1307,12 +1380,6 @@ int msm_pcm_routing_reg_phy_stream(int fedai_id, int perf_mode,
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fedai_id][session_type].strm_id;
- payload.app_type =
- fe_dai_app_type_cfg[fedai_id][session_type].app_type;
- payload.acdb_dev_id =
- fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
- payload.sample_rate =
- fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
@@ -1491,30 +1558,31 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
msm_bedais[reg].format);
app_type =
- fe_dai_app_type_cfg[val][session_type].app_type;
+ fe_dai_app_type_cfg[val][session_type][reg].app_type;
if (app_type && is_lsm) {
app_type_idx =
msm_pcm_routing_get_lsm_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[val][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[val][session_type][reg]
+ .sample_rate;
bits_per_sample =
lsm_app_type_cfg[app_type_idx].bit_width;
} else if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[val][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[val][session_type][reg]
+ .sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
sample_rate = msm_bedais[reg].sample_rate;
- topology = msm_routing_get_adm_topology(path_type, val,
- session_type);
+ topology = msm_routing_get_adm_topology(val,
+ session_type,
+ reg);
acdb_dev_id =
- fe_dai_app_type_cfg[val][session_type].acdb_dev_id;
+ fe_dai_app_type_cfg[val][session_type][reg].acdb_dev_id;
copp_idx = adm_open(msm_bedais[reg].port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
@@ -1847,6 +1915,68 @@ static int msm_routing_put_voice_stub_mixer(struct snd_kcontrol *kcontrol,
return 1;
}
+/*
+ * Return the mapping between port ID and backend ID to enable the AFE callback
+ * to determine the acdb_dev_id from the port id
+ */
+int msm_pcm_get_be_id_from_port_id(int port_id)
+{
+ int i;
+ int be_id = -EINVAL;
+
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (msm_bedais[i].port_id == port_id) {
+ be_id = i;
+ break;
+ }
+ }
+
+ return be_id;
+}
+
+/*
+ * Return the registered dev_acdb_id given a port ID to enable identifying the
+ * correct AFE calibration information by comparing the header information.
+ */
+static int msm_pcm_get_dev_acdb_id_by_port_id(int port_id)
+{
+ int acdb_id = -EINVAL;
+ int i = 0;
+ int session;
+ int port_type = afe_get_port_type(port_id);
+ int be_id = msm_pcm_get_be_id_from_port_id(port_id);
+
+ pr_debug("%s:port_id %d be_id %d, port_type 0x%x\n",
+ __func__, port_id, be_id, port_type);
+
+ if (port_type == MSM_AFE_PORT_TYPE_TX) {
+ session = SESSION_TYPE_TX;
+ } else if (port_type == MSM_AFE_PORT_TYPE_RX) {
+ session = SESSION_TYPE_RX;
+ } else {
+ pr_err("%s: Invalid port type %d\n", __func__, port_type);
+ acdb_id = -EINVAL;
+ goto exit;
+ }
+
+ if (be_id < 0) {
+ pr_err("%s: Error getting backend id %d\n", __func__, be_id);
+ goto exit;
+ }
+
+ mutex_lock(&routing_lock);
+ i = find_first_bit(&msm_bedais[be_id].fe_sessions[0],
+ MSM_FRONTEND_DAI_MAX);
+ if (i < MSM_FRONTEND_DAI_MAX)
+ acdb_id = fe_dai_app_type_cfg[i][session][be_id].acdb_dev_id;
+
+ pr_debug("%s: FE[%d] session[%d] BE[%d] acdb_id(%d)\n",
+ __func__, i, session, be_id, acdb_id);
+ mutex_unlock(&routing_lock);
+exit:
+ return acdb_id;
+}
+
static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2186,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;
@@ -2214,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);
@@ -2291,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);
@@ -9104,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[] = {
@@ -9128,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[] = {
@@ -9152,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[] = {
@@ -9176,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[] = {
@@ -9200,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[] = {
@@ -9224,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[] = {
@@ -9248,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[] = {
@@ -9272,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 =
@@ -9386,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,
@@ -11519,11 +11684,14 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
@@ -12011,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"},
@@ -12920,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"},
@@ -12928,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"},
@@ -12937,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"},
@@ -12947,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"},
@@ -12957,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"},
@@ -12966,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"},
@@ -13884,21 +14092,21 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
bedai->format);
app_type =
- fe_dai_app_type_cfg[i][session_type].app_type;
+ fe_dai_app_type_cfg[i][session_type][be_id].app_type;
if (app_type && is_lsm) {
app_type_idx =
msm_pcm_routing_get_lsm_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[i][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[i][session_type][be_id]
+ .sample_rate;
bits_per_sample =
lsm_app_type_cfg[app_type_idx].bit_width;
} else if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[i][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[i][session_type]
+ [be_id].sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
@@ -13912,9 +14120,9 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
else
channels = bedai->adm_override_ch;
acdb_dev_id =
- fe_dai_app_type_cfg[i][session_type].acdb_dev_id;
- topology = msm_routing_get_adm_topology(path_type, i,
- session_type);
+ fe_dai_app_type_cfg[i][session_type][be_id].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(i, session_type,
+ be_id);
copp_idx = adm_open(bedai->port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
@@ -14201,6 +14409,64 @@ static const struct snd_kcontrol_new aptx_dec_license_controls[] = {
msm_aptx_dec_license_control_put),
};
+static int msm_routing_be_dai_name_table_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(be_dai_name_table);
+ return 0;
+}
+
+static int msm_routing_be_dai_name_table_tlv_get(unsigned int __user *bytes,
+ unsigned int size)
+{
+ int i;
+ int ret;
+
+ if (size < sizeof(be_dai_name_table)) {
+ pr_err("%s: invalid size %d requested, returning\n",
+ __func__, size);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * Fill be_dai_name_table from msm_bedais table to reduce code changes
+ * needed when adding new backends
+ */
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ be_dai_name_table[i].be_id = i;
+ strlcpy(be_dai_name_table[i].be_name,
+ msm_bedais[i].name,
+ LPASS_BE_NAME_MAX_LENGTH);
+ }
+
+ ret = copy_to_user(bytes, &be_dai_name_table,
+ sizeof(be_dai_name_table));
+ if (ret) {
+ pr_err("%s: failed to copy be_dai_name_table\n", __func__);
+ ret = -EFAULT;
+ }
+
+done:
+ return ret;
+}
+
+static const struct snd_kcontrol_new
+ msm_routing_be_dai_name_table_mixer_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = msm_routing_be_dai_name_table_info,
+ .name = "Backend DAI Name Table",
+ .tlv.c = snd_soc_bytes_tlv_callback,
+ .private_value = (unsigned long) &(struct soc_bytes_ext) {
+ .max = sizeof(be_dai_name_table),
+ .get = msm_routing_be_dai_name_table_tlv_get,
+ }
+ },
+};
+
static struct snd_pcm_ops msm_routing_pcm_ops = {
.hw_params = msm_pcm_routing_hw_params,
.close = msm_pcm_routing_close,
@@ -14253,6 +14519,10 @@ static int msm_routing_probe(struct snd_soc_platform *platform)
device_pp_params_mixer_controls,
ARRAY_SIZE(device_pp_params_mixer_controls));
+ snd_soc_add_platform_controls(platform,
+ msm_routing_be_dai_name_table_mixer_controls,
+ ARRAY_SIZE(msm_routing_be_dai_name_table_mixer_controls));
+
msm_dts_eagle_add_controls(platform);
snd_soc_add_platform_controls(platform, msm_source_tracking_controls,
@@ -14327,15 +14597,6 @@ int msm_routing_check_backend_enabled(int fedai_id)
return 0;
}
-static int get_cal_path(int path_type)
-{
- if (path_type == ADM_PATH_PLAYBACK ||
- path_type == ADM_PATH_COMPRESSED_RX)
- return RX_DEVICE;
- else
- return TX_DEVICE;
-}
-
static int msm_routing_set_cal(int32_t cal_type,
size_t data_size, void *data)
{
@@ -14394,6 +14655,11 @@ static int __init msm_soc_routing_platform_init(void)
if (msm_routing_init_cal_data())
pr_err("%s: could not init cal data!\n", __func__);
+ afe_set_routing_callback(
+ (routing_cb)msm_pcm_get_dev_acdb_id_by_port_id);
+
+ memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+
return platform_driver_register(&msm_routing_pcm_driver);
}
module_init(msm_soc_routing_platform_init);
@@ -14401,6 +14667,7 @@ module_init(msm_soc_routing_platform_init);
static void __exit msm_soc_routing_platform_exit(void)
{
msm_routing_delete_cal_data();
+ memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
platform_driver_unregister(&msm_routing_pcm_driver);
}
module_exit(msm_soc_routing_platform_exit);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index a066e9afc9e5..94c79f00afec 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -13,6 +13,12 @@
#define _MSM_PCM_ROUTING_H
#include <sound/apr_audio-v2.h>
+/*
+ * These names are used by HAL to specify the BE. If any changes are
+ * made to the string names or the max name length corresponding
+ * changes need to be made in the HAL to ensure they still match.
+ */
+#define LPASS_BE_NAME_MAX_LENGTH 24
#define LPASS_BE_PRI_I2S_RX "PRIMARY_I2S_RX"
#define LPASS_BE_PRI_I2S_TX "PRIMARY_I2S_TX"
#define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX"
@@ -470,8 +476,10 @@ void msm_pcm_routing_get_fedai_info(int fe_idx, int sess_type,
void msm_pcm_routing_acquire_lock(void);
void msm_pcm_routing_release_lock(void);
-void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
- int acdb_dev_id, int sample_rate, int session_type);
+int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
+ int be_id, int app_type,
+ int acdb_dev_id, int sample_rate);
int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
- int *app_type, int *acdb_dev_id, int *sample_rate);
+ int be_id, int *app_type,
+ int *acdb_dev_id, int *sample_rate);
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index 24c47f764a7d..6f463c079f19 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -403,6 +403,7 @@ static int msm_afe_lb_vol_ctrl;
static int msm_afe_sec_mi2s_lb_vol_ctrl;
static int msm_afe_tert_mi2s_lb_vol_ctrl;
static int msm_afe_quat_mi2s_lb_vol_ctrl;
+static int msm_afe_slimbus_7_lb_vol_ctrl;
static int msm_afe_slimbus_8_lb_vol_ctrl;
static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
static const DECLARE_TLV_DB_LINEAR(afe_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
@@ -475,6 +476,29 @@ static int msm_qti_pp_set_tert_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
return 0;
}
+static int msm_qti_pp_get_slimbus_7_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_afe_slimbus_7_lb_vol_ctrl;
+ return 0;
+}
+
+static int msm_qti_pp_set_slimbus_7_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = afe_loopback_gain(SLIMBUS_7_TX,
+ ucontrol->value.integer.value[0]);
+
+ if (ret)
+ pr_err("%s: failed to set LB vol for SLIMBUS_7_TX, err %d\n",
+ __func__, ret);
+ else
+ msm_afe_slimbus_7_lb_vol_ctrl =
+ ucontrol->value.integer.value[0];
+
+ return ret;
+}
+
static int msm_qti_pp_get_slimbus_8_lb_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -857,6 +881,14 @@ static const struct snd_kcontrol_new tert_mi2s_lb_vol_mixer_controls[] = {
msm_qti_pp_set_tert_mi2s_lb_vol_mixer, afe_lb_vol_gain),
};
+static const struct snd_kcontrol_new slimbus_7_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("SLIMBUS_7 LOOPBACK Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0,
+ msm_qti_pp_get_slimbus_7_lb_vol_mixer,
+ msm_qti_pp_set_slimbus_7_lb_vol_mixer,
+ afe_lb_vol_gain),
+};
+
static const struct snd_kcontrol_new slimbus_8_lb_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("SLIMBUS_8 LOOPBACK Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_qti_pp_get_slimbus_8_lb_vol_mixer,
@@ -1061,6 +1093,9 @@ void msm_qti_pp_add_controls(struct snd_soc_platform *platform)
snd_soc_add_platform_controls(platform, tert_mi2s_lb_vol_mixer_controls,
ARRAY_SIZE(tert_mi2s_lb_vol_mixer_controls));
+ snd_soc_add_platform_controls(platform, slimbus_7_lb_vol_mixer_controls,
+ ARRAY_SIZE(slimbus_7_lb_vol_mixer_controls));
+
snd_soc_add_platform_controls(platform, slimbus_8_lb_vol_mixer_controls,
ARRAY_SIZE(slimbus_8_lb_vol_mixer_controls));
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 16ae05034662..4a4f02c7b9b6 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -2815,8 +2815,8 @@ int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
[port_idx][copp_idx]),
get_cal_path(path),
payload_map.session_id,
- payload_map.app_type,
- payload_map.acdb_dev_id);
+ payload_map.app_type[i],
+ payload_map.acdb_dev_id[i]);
if (!test_bit(ADM_STATUS_CALIBRATION_REQUIRED,
(void *)&this_adm.copp.adm_status[port_idx]
@@ -2827,9 +2827,9 @@ int adm_matrix_map(int path, struct route_payload payload_map, int perf_mode,
}
send_adm_cal(payload_map.port_id[i], copp_idx,
get_cal_path(path), perf_mode,
- payload_map.app_type,
- payload_map.acdb_dev_id,
- payload_map.sample_rate);
+ payload_map.app_type[i],
+ payload_map.acdb_dev_id[i],
+ payload_map.sample_rate[i]);
/* ADM COPP calibration is already sent */
clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
(void *)&this_adm.copp.
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 9a141a11d002..bc1d21a826b5 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -113,12 +113,15 @@ 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];
struct aanc_data aanc_info;
struct mutex afe_cmd_lock;
int set_custom_topology;
+ int dev_acdb_id[AFE_MAX_PORTS];
+ routing_cb rt_cb;
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -187,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;
@@ -272,6 +307,7 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv)
mutex_lock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
this_afe.set_custom_topology = 1;
mutex_unlock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
+ rtac_clear_mapping(AFE_RTAC_CAL);
if (this_afe.apr) {
apr_reset(this_afe.apr);
@@ -306,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",
@@ -317,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;
@@ -1178,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);
@@ -1245,6 +1289,10 @@ static struct cal_block_data *afe_find_cal_topo_id_by_port(
struct cal_block_data *cal_block = NULL;
int32_t path;
struct audio_cal_info_afe_top *afe_top;
+ int afe_port_index = q6audio_get_port_index(port_id);
+
+ if (afe_port_index < 0)
+ goto err_exit;
list_for_each_safe(ptr, next,
&cal_type->cal_blocks) {
@@ -1255,13 +1303,17 @@ static struct cal_block_data *afe_find_cal_topo_id_by_port(
MSM_AFE_PORT_TYPE_TX)?(TX_DEVICE):(RX_DEVICE));
afe_top =
(struct audio_cal_info_afe_top *)cal_block->cal_info;
- if (afe_top->path == path) {
+ if ((afe_top->path == path) &&
+ (afe_top->acdb_id ==
+ this_afe.dev_acdb_id[afe_port_index])) {
pr_debug("%s: top_id:%x acdb_id:%d afe_port:%d\n",
- __func__, afe_top->topology, afe_top->acdb_id,
- q6audio_get_port_id(port_id));
+ __func__, afe_top->topology, afe_top->acdb_id,
+ q6audio_get_port_id(port_id));
return cal_block;
}
}
+
+err_exit:
return NULL;
}
@@ -1364,6 +1416,7 @@ static int afe_send_port_topology_id(u16 port_id)
}
this_afe.topology[index] = topology_id;
+ rtac_update_afe_topology(port_id);
done:
pr_debug("%s: AFE set topology id 0x%x enable for port 0x%x ret %d\n",
__func__, topology_id, port_id, ret);
@@ -1405,6 +1458,41 @@ done:
return ret;
}
+static struct cal_block_data *afe_find_cal(int cal_index, int port_id)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_afe *afe_cal_info = NULL;
+ int afe_port_index = q6audio_get_port_index(port_id);
+
+ pr_debug("%s: cal_index %d port_id %d port_index %d\n", __func__,
+ cal_index, port_id, afe_port_index);
+ if (afe_port_index < 0) {
+ pr_err("%s: Error getting AFE port index %d\n",
+ __func__, afe_port_index);
+ goto exit;
+ }
+
+ list_for_each_safe(ptr, next,
+ &this_afe.cal_data[cal_index]->cal_blocks) {
+ cal_block = list_entry(ptr, struct cal_block_data, list);
+ afe_cal_info = cal_block->cal_info;
+ if ((afe_cal_info->acdb_id ==
+ this_afe.dev_acdb_id[afe_port_index]) &&
+ (afe_cal_info->sample_rate ==
+ this_afe.afe_sample_rates[afe_port_index])) {
+ pr_debug("%s: cal block is a match, size is %zd\n",
+ __func__, cal_block->cal_data.size);
+ goto exit;
+ }
+ }
+ pr_err("%s: no matching cal_block found\n", __func__);
+ cal_block = NULL;
+
+exit:
+ return cal_block;
+}
+
static void send_afe_cal_type(int cal_index, int port_id)
{
struct cal_block_data *cal_block = NULL;
@@ -1418,7 +1506,14 @@ static void send_afe_cal_type(int cal_index, int port_id)
}
mutex_lock(&this_afe.cal_data[cal_index]->lock);
- cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]);
+
+ if ((cal_index == AFE_COMMON_RX_CAL) ||
+ (cal_index == AFE_COMMON_TX_CAL))
+ cal_block = afe_find_cal(cal_index, port_id);
+ else
+ cal_block = cal_utils_get_only_cal_block(
+ this_afe.cal_data[cal_index]);
+
if (cal_block == NULL) {
pr_err("%s cal_block not found!!\n", __func__);
goto unlock;
@@ -1929,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;
}
@@ -1947,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;
@@ -2485,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;
@@ -2518,9 +2615,17 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
return ret;
}
- /* Also send the topology id here: */
+ if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[index] = rate;
+
+ if (this_afe.rt_cb)
+ this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+ }
+
+ /* 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);
@@ -2582,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) {
@@ -2612,6 +2720,11 @@ void afe_set_cal_mode(u16 port_id, enum afe_cal_mode afe_cal_mode)
this_afe.afe_cal_mode[port_index] = afe_cal_mode;
}
+void afe_set_routing_callback(routing_cb cb)
+{
+ this_afe.rt_cb = cb;
+}
+
int afe_port_send_usb_dev_param(u16 port_id, union afe_port_config *afe_config)
{
struct afe_usb_audio_dev_param_command config;
@@ -2657,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;
}
@@ -2680,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);
@@ -2841,6 +2974,13 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
return ret;
}
+ if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[index] = rate;
+
+ if (this_afe.rt_cb)
+ this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+ }
+
mutex_lock(&this_afe.afe_cmd_lock);
/* Also send the topology id here: */
port_index = afe_get_port_index(port_id);
@@ -3045,7 +3185,6 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config,
port_index = afe_get_port_index(port_id);
if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
- this_afe.afe_sample_rates[port_index] = rate;
/*
* If afe_port_start() for tx port called before
* rx port, then aanc rx sample rate is zero. So,
@@ -3408,6 +3547,14 @@ int afe_open(u16 port_id,
pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
return -EINVAL;
}
+
+ if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[index] = rate;
+
+ if (this_afe.rt_cb)
+ this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+ }
+
/* Also send the topology id here: */
afe_send_custom_topology(); /* One time call: only for first time */
afe_send_port_topology_id(port_id);
@@ -5398,6 +5545,7 @@ int afe_close(int port_id)
if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
this_afe.afe_sample_rates[port_index] = 0;
this_afe.topology[port_index] = 0;
+ this_afe.dev_acdb_id[port_index] = 0;
} else {
pr_err("%s: port %d\n", __func__, port_index);
ret = -EINVAL;
@@ -6065,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;
@@ -6873,6 +7103,8 @@ static int __init afe_init(void)
mutex_init(&this_afe.afe_cmd_lock);
for (i = 0; i < AFE_MAX_PORTS; i++) {
this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT;
+ this_afe.afe_sample_rates[i] = 0;
+ this_afe.dev_acdb_id[i] = 0;
init_waitqueue_head(&this_afe.wait[i]);
}
wakeup_source_init(&wl.ws, "spkr-prot");
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)
{
diff --git a/sound/soc/msm/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index 82551fb8ed71..83628b8d62d9 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.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
@@ -393,6 +393,24 @@ done:
return;
}
+void rtac_update_afe_topology(u32 port_id)
+{
+ u32 i = 0;
+
+ mutex_lock(&rtac_adm_mutex);
+ for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+ if (rtac_adm_data.device[i].afe_port == port_id) {
+ rtac_adm_data.device[i].afe_topology =
+ afe_get_topology(port_id);
+ pr_debug("%s: port_id = 0x%x topology_id = 0x%x copp_id = %d\n",
+ __func__, port_id,
+ rtac_adm_data.device[i].afe_topology,
+ rtac_adm_data.device[i].copp);
+ }
+ }
+ mutex_unlock(&rtac_adm_mutex);
+}
+
void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id,
u32 app_type, u32 acdb_id)
{
diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
index 3e29221fe00f..4cf5aefb0e0f 100644
--- a/sound/soc/msm/sdm660-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.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
@@ -1302,6 +1302,39 @@ static struct snd_soc_dai_link msm_ext_common_fe_dai[] = {
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {/* hw:x,35 */
+ .name = "SLIMBUS7 Hostless",
+ .stream_name = "SLIMBUS7 Hostless",
+ .cpu_dai_name = "SLIMBUS7_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {/* hw:x,36 */
+ .name = "SDM660 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
};
static struct snd_soc_dai_link msm_ext_common_be_dai[] = {
diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c
index 8b0a12a46338..2546380a5a4e 100644
--- a/sound/soc/msm/sdm660-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -1256,6 +1256,7 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(ana_cdc);
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card);
struct snd_card *card;
int ret = -ENOMEM;
@@ -1330,6 +1331,7 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
__func__);
goto done;
}
+ pdata->codec_root = codec_root;
msm_dig_codec_info_create_codec_entry(codec_root, dig_cdc);
msm_anlg_codec_info_create_codec_entry(codec_root, ana_cdc);
done:
@@ -1341,6 +1343,7 @@ static int msm_sdw_audrx_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm =
snd_soc_codec_get_dapm(codec);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(rtd->card);
struct snd_card *card;
snd_soc_add_codec_controls(codec, msm_sdw_controls,
@@ -1363,6 +1366,7 @@ static int msm_sdw_audrx_init(struct snd_soc_pcm_runtime *rtd)
__func__);
goto done;
}
+ pdata->codec_root = codec_root;
msm_sdw_codec_info_create_codec_entry(codec_root, codec);
done:
return 0;
@@ -2261,11 +2265,28 @@ static struct snd_soc_dai_link msm_int_dai[] = {
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {/* hw:x,39 */
+ .name = "SDM660 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
};
static struct snd_soc_dai_link msm_int_wsa_dai[] = {
- {/* hw:x,39 */
+ {/* hw:x,40 */
.name = LPASS_BE_INT5_MI2S_TX,
.stream_name = "INT5_mi2s Capture",
.cpu_dai_name = "msm-dai-q6-mi2s.12",