diff options
210 files changed, 27986 insertions, 2209 deletions
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/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt index 50b9b1ac8704..6ca0ac31a581 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt @@ -132,6 +132,9 @@ value is typically max(latencies of every cluster at all power levels) + 1 memory, performance etc. - qcom,debug-timeout = A bool indicating that FW errors such as SYS_ERROR, SESSION_ERROR and timeouts will be treated as Fatal. +- qcom,power-conf = Indicates the value at which or beyond, a video session + is configured in low power mode to have power benefits. Value is defined + interms of HxW of the video session beyond which power benefit is desired. [Second level nodes] Context Banks @@ -226,6 +229,7 @@ Example: qcom,qdss-presets = <0xFC307000 0x1000>, <0xFC322000 0x1000>; qcom,max-hw-load = <1224450>; /* 4k @ 30 + 1080p @ 30*/ + qcom,power-conf = <8294400>; /* WxH - 3840*2160 */ qcom,never-unload-fw; clock-names = "foo_clk", "bar_clk", "baz_clk"; qcom,clock-configs = <0x3 0x1 0x0>; 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/apm.txt b/Documentation/devicetree/bindings/power/apm.txt index 6cc53df11d02..fa03edfbb83c 100644 --- a/Documentation/devicetree/bindings/power/apm.txt +++ b/Documentation/devicetree/bindings/power/apm.txt @@ -7,7 +7,7 @@ SRAM minimum operating voltage, the APM controller can be used to request a switch to a power supply that will guarantee logic state retention. Required properties -- compatible: "qcom,msm-apm", "qcom,msm8996pro-apm", "qcom,msmtitanium-apm" +- compatible: "qcom,msm-apm", "qcom,msm8996pro-apm", "qcom,msm8953-apm" - reg: Specifies physical base address and size of memory mapped regions containing the APM controller, APCS CSR, APC PLL controller, and SPM event registers. @@ -23,16 +23,16 @@ Optional properties completes. - qcom,apm-post-halt-delay: The APM controller post halt delay counter value that SW needs to program one time before starting the APM HW controller for - msmtitanium target. + msm8953 target. - qcom,apm-halt-clk-delay: The APM controller halt clock delay counter value that SW needs to program one time before starting the APM HW controller - for msmtitanium target. + for msm8953 target. - qcom,apm-resume-clk-delay: The APM controller resume clock delay counter value that SW needs to program one time before starting the APM HW controller - for msmtitanium target. + for msm8953 target. - qcom,apm-sel-switch-delay: The APM controller switch selection delay counter value that SW needs to program one time before starting the APM HW controller - for msmtitanium target. + for msm8953 target. MSM APM Users 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/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/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/devicetree/bindings/usb/qpnp-pdphy.txt b/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt index f3c3163f0a3f..cf0628a26c5a 100644 --- a/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt +++ b/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt @@ -43,6 +43,9 @@ Optional properties: - qcom,vconn-uses-external-source: Indicates whether VCONN supply is sourced from an external regulator. If omitted, then it is assumed it is connected to VBUS. +- qcom,default-sink-caps: List of 32-bit values representing the nominal sink + capabilities in voltage (millivolts) and current + (milliamps) pairs. Example: qcom,qpnp-pdphy@1700 { @@ -64,4 +67,8 @@ Example: "msg-tx-failed", "msg-tx-discarded", "msg-rx-discarded"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>, /* 9V @ 3A */ + <12000 2250>; /* 12V @ 2.25A */ }; 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..f84708d73bd8 100644 --- a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts +++ b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts @@ -26,7 +26,7 @@ }; &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-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi index 9218f8dc583c..72f9f9ea9b2d 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi @@ -290,6 +290,10 @@ "msg-tx-failed", "msg-tx-discarded", "msg-rx-discarded"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>, /* 9V @ 3A */ + <12000 2250>; /* 12V @ 2.25A */ }; bcl@4200 { diff --git a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi index 2aa730898f75..138fa2b57248 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,24 @@ #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-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/msm8996-vidc.dtsi b/arch/arm/boot/dts/qcom/msm8996-vidc.dtsi index 3ed55f9d8671..5ac31e3dd0cb 100644 --- a/arch/arm/boot/dts/qcom/msm8996-vidc.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-vidc.dtsi @@ -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 @@ -32,6 +32,7 @@ <0x0818C000 0x2000>, <0x0818E000 0x2000>; qcom,max-hw-load = <2563200>; /* Full 4k @ 60 + 1080p @ 60 */ + qcom,power-conf = <8294400>; /* WxH - 3840*2160 */ qcom,firmware-name = "venus"; qcom,imem-size = <524288>; /* 512 kB */ qcom,never-unload-fw; 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-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi index 4aadd4802b51..236020385e1c 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 { 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-vidc.dtsi b/arch/arm/boot/dts/qcom/msm8998-vidc.dtsi index e449d81a25e5..3e7cacac9d43 100644 --- a/arch/arm/boot/dts/qcom/msm8998-vidc.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998-vidc.dtsi @@ -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 @@ -39,6 +39,7 @@ qcom,imem-size = <524288>; /* 512 kB */ qcom,max-hw-load = <2563200>; /* Full 4k @ 60 + 1080p @ 60 */ + qcom,power-conf = <8294400>; /* WxH - 3840*2160 */ qcom,load-freq-tbl = /* Encoders */ <972000 465000000 0x55555555>, /* 4k UHD @ 30 */ diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi index 2e41f3a3567d..ed2278349e25 100644 --- a/arch/arm/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm/boot/dts/qcom/msm8998.dtsi @@ -3041,7 +3041,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/sdm630-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi index 73735159101d..c824ed12b3e7 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,144 @@ /* 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>; + }; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 86b8935c5ad9..07cbb17e2826 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -51,6 +51,7 @@ reg = <0x0 0x100>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile0>; + qcom,ea = <&ea0>; efficiency = <1126>; next-level-cache = <&L2_1>; L2_1: l2-cache { @@ -67,6 +68,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_100: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; CPU1: cpu@101 { @@ -75,6 +79,7 @@ reg = <0x0 0x101>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile1>; + qcom,ea = <&ea1>; efficiency = <1126>; next-level-cache = <&L2_1>; L1_I_101: l1-icache { @@ -85,6 +90,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_101: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; CPU2: cpu@102 { @@ -93,6 +101,7 @@ reg = <0x0 0x102>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile2>; + qcom,ea = <&ea2>; efficiency = <1126>; next-level-cache = <&L2_1>; L1_I_102: l1-icache { @@ -103,6 +112,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_102: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; CPU3: cpu@103 { @@ -111,6 +123,7 @@ reg = <0x0 0x103>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile3>; + qcom,ea = <&ea3>; efficiency = <1126>; next-level-cache = <&L2_1>; L1_I_103: l1-icache { @@ -121,6 +134,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_103: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; CPU4: cpu@0 { @@ -129,6 +145,7 @@ reg = <0x0 0x0>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile4>; + qcom,ea = <&ea4>; efficiency = <1024>; next-level-cache = <&L2_0>; L2_0: l2-cache { @@ -145,6 +162,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_0: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; CPU5: cpu@1 { @@ -153,6 +173,7 @@ reg = <0x0 0x1>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile4>; + qcom,ea = <&ea5>; efficiency = <1024>; next-level-cache = <&L2_0>; L1_I_1: l1-icache { @@ -163,6 +184,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_1: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; CPU6: cpu@2 { @@ -171,6 +195,7 @@ reg = <0x0 0x2>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile4>; + qcom,ea = <&ea6>; efficiency = <1024>; next-level-cache = <&L2_0>; L1_I_2: l1-icache { @@ -181,6 +206,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_2: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; CPU7: cpu@3 { @@ -189,6 +217,7 @@ reg = <0x0 0x3>; enable-method = "psci"; qcom,limits-info = <&mitigation_profile4>; + qcom,ea = <&ea7>; efficiency = <1024>; next-level-cache = <&L2_0>; L1_I_3: l1-icache { @@ -199,6 +228,9 @@ compatible = "arm,arch-cache"; qcom,dump-size = <0x9040>; }; + L1_TLB_3: l1-tlb { + qcom,dump-size = <0x2800>; + }; }; cpu-map { @@ -312,6 +344,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 */ }; }; @@ -436,6 +498,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 { @@ -475,6 +569,8 @@ reg-names = "tsens_physical"; interrupts = <0 184 0>, <0 430 0>; interrupt-names = "tsens-upper-lower", "tsens-critical"; + qcom,client-id = <0 1 2 3 4 5 6 7 8 9 10 11>; + qcom,sensor-id = <0 8 10 4 5 6 7 9 2 1 3 11>; qcom,sensors = <12>; }; @@ -662,6 +758,45 @@ }; }; + qcom,msm-core@780000 { + compatible = "qcom,apss-core-ea"; + reg = <0x780000 0x1000>; + qcom,low-hyst-temp = <10>; + qcom,high-hyst-temp = <5>; + + ea0: ea0 { + sensor = <&sensor_information3>; + }; + + ea1: ea1 { + sensor = <&sensor_information4>; + }; + + ea2: ea2 { + sensor = <&sensor_information5>; + }; + + ea3: ea3 { + sensor = <&sensor_information6>; + }; + + ea4: ea4 { + sensor = <&sensor_information7>; + }; + + ea5: ea5 { + sensor = <&sensor_information7>; + }; + + ea6: ea6 { + sensor = <&sensor_information7>; + }; + + ea7: ea7 { + sensor = <&sensor_information7>; + }; + }; + wdog: qcom,wdt@17817000 { status = "disabled"; compatible = "qcom,msm-watchdog"; @@ -717,7 +852,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 { @@ -818,7 +960,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>; @@ -888,6 +1037,7 @@ qcom,use-ipa-tethering-bridge; qcom,modem-cfg-emb-pipe-flt; qcom,ipa-wdi2; + qcom,use-dma-zone; qcom,msm-bus,name = "ipa"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <2>; 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-coresight.dtsi b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi index b0002dddf419..431da5036a4b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-coresight.dtsi @@ -626,7 +626,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-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi index dedc0c99d2e5..e5cf0b1534ec 100644 --- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi @@ -71,7 +71,6 @@ /* <HZ/12> */ qcom,idle-timeout = <80>; - qcom,no-nap; qcom,highest-bank-bit = <14>; 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 a0cc0a6180e5..ce8273e4f1b8 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -33,7 +33,7 @@ qcom,panel-supply-entry@0 { reg = <0>; qcom,supply-name = "wqhd-vddio"; - qcom,supply-min-voltage = <1880000>; + qcom,supply-min-voltage = <1800000>; qcom,supply-max-voltage = <1950000>; qcom,supply-enable-load = <32000>; qcom,supply-disable-load = <80>; @@ -196,19 +196,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 { 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..b7329121ca49 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 = <593470>; + 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>; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-mtp.dtsi index b666d846ca04..150b88c10646 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>; 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-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-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi index c00595934cf0..0826f94a2296 100644 --- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi @@ -592,39 +592,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 = diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index 2a7ef9dcd4cd..18e3318f2219 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>; @@ -1388,6 +1444,7 @@ qcom,use-ipa-tethering-bridge; qcom,modem-cfg-emb-pipe-flt; qcom,ipa-wdi2; + qcom,use-dma-zone; qcom,msm-bus,name = "ipa"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <2>; diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig index d7eb67ff85c1..dcf4f6fa0031 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 @@ -497,6 +497,9 @@ CONFIG_CLOCK_CPU_OSM=y CONFIG_QCOM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=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..633b9ad305bc 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 @@ -643,6 +642,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..2e2d1657e604 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -539,4 +539,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/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/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index f4a7d9107f36..1498b51b8080 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -65,6 +65,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..2af41033ff89 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -63,6 +63,7 @@ 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 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..ef8bac8e2947 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 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/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..0345e977a2d4 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; 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/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 40c592457ea1..6e6adbff4676 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1111,6 +1111,16 @@ static int clk_dp_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, return clk_dp_set_rate(hw, rate, parent_rate); } +static int clk_dp_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + req->best_parent_rate = clk_hw_round_rate(req->best_parent_hw, + req->best_parent_rate); + req->rate = req->rate; + + return 0; +} + const struct clk_ops clk_dp_ops = { .is_enabled = clk_rcg2_is_enabled, .get_parent = clk_rcg2_get_parent, @@ -1118,7 +1128,7 @@ const struct clk_ops clk_dp_ops = { .recalc_rate = clk_rcg2_recalc_rate, .set_rate = clk_dp_set_rate, .set_rate_and_parent = clk_dp_set_rate_and_parent, - .determine_rate = clk_pixel_determine_rate, + .determine_rate = clk_dp_determine_rate, .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_dp_ops); diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index d8ae85b65a47..e9e3fb4876e4 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; diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index 934779f16107..aec73d62bc18 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -965,8 +965,9 @@ static struct clk_rcg2 dp_pixel_clk_src = { .parent_names = mmcc_parent_names_6, .num_parents = 4, .ops = &clk_dp_ops, + .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT, VDD_DIG_FMAX_MAP3( - LOWER, 148380, + LOWER, 154000, LOW, 296740, NOMINAL, 593470), }, diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 2788c0add14a..a5e5ad34db16 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,6 +41,13 @@ #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" @@ -830,6 +838,24 @@ static int qcom_ice_restore_config(void) return ret; } +static int qcom_ice_restore_key_config(void) +{ + 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; + desc.args[0] = 10; /* UFS_ICE */ + + 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 +1129,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(); + 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/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 15c4b9427f8e..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) @@ -1639,7 +1641,9 @@ static void a5xx_pwrlevel_change_settings(struct adreno_device *adreno_dev, static void a5xx_clk_set_options(struct adreno_device *adreno_dev, const char *name, struct clk *clk) { - if (adreno_is_a540(adreno_dev)) { + /* Handle clock settings for GFX PSCBCs */ + 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); @@ -1926,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); @@ -1952,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_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 413a3098b0ef..7f93ab8fa8d4 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -917,11 +917,15 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) "qcom,enable-midframe-timer")) { kgsl_midframe = kzalloc( sizeof(struct kgsl_midframe_info), GFP_KERNEL); - hrtimer_init(&kgsl_midframe->timer, - CLOCK_MONOTONIC, HRTIMER_MODE_REL); - kgsl_midframe->timer.function = - kgsl_pwrscale_midframe_timer; - kgsl_midframe->device = device; + if (kgsl_midframe) { + hrtimer_init(&kgsl_midframe->timer, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + kgsl_midframe->timer.function = + kgsl_pwrscale_midframe_timer; + kgsl_midframe->device = device; + } else + KGSL_PWR_ERR(device, + "Failed to enable-midframe-timer feature\n"); } /* 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/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(®, (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_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_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_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, ®, + 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(¶meter, (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, ¶meter.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 *) + ¶meter.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 *) ¶meter.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, ¶meter, + 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/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..08809a93d4b2 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -1166,6 +1166,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 +1218,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, ®ulator_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/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index f958cf13f1e3..a20252f08f44 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.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 @@ -1782,6 +1782,7 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count) struct msm_vidc_inst *inst; int rc = 0; struct hfi_device *hdev; + struct vb2_buf_entry *temp, *next; if (!q || !q->drv_priv) { dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q); return -EINVAL; @@ -1824,6 +1825,19 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count) } stream_start_failed: + if (rc) { + mutex_lock(&inst->pendingq.lock); + list_for_each_entry_safe(temp, next, &inst->pendingq.list, + list) { + if (temp->vb->type == q->type) { + vb2_buffer_done(temp->vb, + VB2_BUF_STATE_QUEUED); + list_del(&temp->list); + kfree(temp); + } + } + mutex_unlock(&inst->pendingq.lock); + } return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 6127c03df581..c909511db251 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.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 @@ -1048,9 +1048,9 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE, .name = "Set Encoder performance mode", .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY, + .minimum = V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT, .maximum = V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE, - .default_value = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY, + .default_value = V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT, .step = 1, .qmenu = NULL, }, @@ -1666,9 +1666,10 @@ static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers) static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) { - u32 rc = 0; - u32 prop_id = 0, power_save_min = 0, power_save_max = 0, inst_load = 0; + u32 rc = 0, height = 0, width = 0; + u32 prop_id = 0, hq_max = 0, power_conf = 0, inst_load = 0; void *pdata = NULL; + bool set_by_client = false, enable_low_power = false; struct hfi_device *hdev = NULL; enum hal_perf_mode venc_mode; enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD | @@ -1679,20 +1680,38 @@ static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) return -EINVAL; } + hdev = inst->core->device; inst_load = msm_comm_get_inst_load(inst, quirks); - power_save_min = inst->capability.mbs_per_sec_power_save.min; - power_save_max = inst->capability.mbs_per_sec_power_save.max; + hq_max = inst->capability.mbs_per_sec.max; + power_conf = inst->core->resources.power_conf; + height = inst->prop.height[CAPTURE_PORT]; + width = inst->prop.width[CAPTURE_PORT]; - if (!power_save_min || !power_save_max) - return rc; + switch (msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE)) { + case V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY: + case V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE: + set_by_client = true; + break; + } - hdev = inst->core->device; - if (inst_load >= power_save_min && inst_load <= power_save_max) { + if (inst_load > hq_max) { + dprintk(VIDC_INFO, "Setting low power w.r.t core limitation\n"); + enable_low_power = true; + } else if (!set_by_client) { + if (power_conf && width * height >= power_conf) { + dprintk(VIDC_INFO, + "Setting low power w.r.t system power recommendation\n"); + enable_low_power = true; + } + } + + if (enable_low_power) { prop_id = HAL_CONFIG_VENC_PERF_MODE; venc_mode = HAL_PERF_MODE_POWER_SAVE; pdata = &venc_mode; rc = call_hfi_op(hdev, session_set_property, - (void *)inst->session, prop_id, pdata); + (void *)inst->session, prop_id, pdata); if (rc) { dprintk(VIDC_ERR, "%s: Failed to set power save mode for inst: %pK\n", @@ -1758,6 +1777,7 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count) { struct msm_vidc_inst *inst; int rc = 0; + struct vb2_buf_entry *temp, *next; if (!q || !q->drv_priv) { dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q); return -EINVAL; @@ -1795,6 +1815,19 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count) } stream_start_failed: + if (rc) { + mutex_lock(&inst->pendingq.lock); + list_for_each_entry_safe(temp, next, &inst->pendingq.list, + list) { + if (temp->vb->type == q->type) { + vb2_buffer_done(temp->vb, + VB2_BUF_STATE_QUEUED); + list_del(&temp->list); + kfree(temp); + } + } + mutex_unlock(&inst->pendingq.lock); + } return rc; } @@ -3143,7 +3176,6 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; } pdata = &venc_mode; - break; case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS: if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index b36e3739e43b..662dcf7c8303 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -720,6 +720,7 @@ int msm_vidc_release_buffers(void *instance, int buffer_type) struct buffer_info *bi, *dummy; struct v4l2_buffer buffer_info; struct v4l2_plane plane[VIDEO_MAX_PLANES]; + struct vb2_buf_entry *temp, *next; int i, rc = 0; if (!inst) @@ -807,6 +808,15 @@ free_and_unmap: } } mutex_unlock(&inst->registeredbufs.lock); + + mutex_lock(&inst->pendingq.lock); + list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) { + if (temp->vb->type == buffer_type) { + list_del(&temp->list); + kfree(temp); + } + } + mutex_unlock(&inst->pendingq.lock); return rc; } EXPORT_SYMBOL(msm_vidc_release_buffers); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index a3080be8cd7a..022c776a6096 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.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 @@ -1084,6 +1084,13 @@ int read_platform_resources_from_dt( goto err_load_max_hw_load; } + rc = of_property_read_u32(pdev->dev.of_node, "qcom,power-conf", + &res->power_conf); + if (rc) { + dprintk(VIDC_DBG, + "Failed to read power configuration: %d\n", rc); + } + rc = msm_vidc_populate_legacy_context_bank(res); if (rc) { dprintk(VIDC_ERR, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index 734586a3f76c..03b31d7fd9d1 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -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 @@ -173,6 +173,7 @@ struct msm_vidc_platform_resources { uint32_t imem_size; enum imem_type imem_type; uint32_t max_load; + uint32_t power_conf; struct platform_device *pdev; struct regulator_set regulator_set; struct clock_set clock_set; diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 1653f7e1ae99..d3b41331faec 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -2135,22 +2135,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/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/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 871329c79a46..2da6589bf57e 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_HL_1_0; + 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. 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/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..de95e13a6036 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; @@ -3719,6 +3746,7 @@ static const struct wmi_ops wmi_hl_1_0_ops = { .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update, .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs, .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, + .gen_set_pdev_mac_addr = ath10k_wmi_tlv_op_gen_set_base_mac_addr, }; void ath10k_wmi_hl_1_0_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 2b8318010a35..31f34b43e381 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1849,4 +1849,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..2ce61e64c82e 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; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 09595349f24b..0bddc9d9c632 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1721,14 +1721,19 @@ int wmi_abort_scan(struct wil6210_priv *wil) 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/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_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index cd946fff31a9..8a588d26e827 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -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_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 7feb1c1ce178..9938221e34b0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1002,6 +1002,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 +2046,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/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..87743c98e0fa 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 @@ -1154,8 +1154,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 +1207,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); } /** @@ -2435,6 +2438,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: 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..55ab6177e6db 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -282,6 +282,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(fcc_delta), POWER_SUPPLY_ATTR(icl_reduction), POWER_SUPPLY_ATTR(parallel_mode), + POWER_SUPPLY_ATTR(connector_therm_zone), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/drivers/power/qcom/Kconfig b/drivers/power/qcom/Kconfig index b7ca61d6c21d..efb9dd9628bb 100644 --- a/drivers/power/qcom/Kconfig +++ b/drivers/power/qcom/Kconfig @@ -23,12 +23,12 @@ config APSS_CORE_EA and temperature information to the scheduler. config MSM_APM - bool "Qualcomm Technologies Inc platform specific APM driver" - help - Platform specific driver to manage the power source of - memory arrays. Interfaces with regulator drivers to ensure - SRAM Vmin requirements are met across different performance - levels. + bool "Qualcomm Technologies, Inc. platform specific APM driver" + help + Platform specific driver to manage the power source of + memory arrays. Interfaces with regulator drivers to ensure + SRAM Vmin requirements are met across different performance + levels. if MSM_PM menuconfig MSM_IDLE_STATS diff --git a/drivers/power/qcom/apm.c b/drivers/power/qcom/apm.c index ffd0e3833b32..6181b08a41a5 100644 --- a/drivers/power/qcom/apm.c +++ b/drivers/power/qcom/apm.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 @@ -90,7 +90,7 @@ enum { enum { MSM8996_ID, MSM8996PRO_ID, - MSMTITANIUM_ID, + MSM8953_ID, }; struct msm_apm_ctrl_dev { @@ -239,8 +239,8 @@ free_events: return ret; } -/* Titanium register offset definition */ -#define MSMTITANIUM_APM_DLY_CNTR 0x2ac +/* MSM8953 register offset definition */ +#define MSM8953_APM_DLY_CNTR 0x2ac /* Register field shift definitions */ #define APM_CTL_SEL_SWITCH_DLY_SHIFT 0 @@ -255,12 +255,12 @@ free_events: #define APM_CTL_POST_HALT_DLY_MASK GENMASK(31, 24) /* - * Get the resources associated with the msmtitanium APM controller from + * Get the resources associated with the MSM8953 APM controller from * device tree, remap all I/O addresses, and program the initial - * register configuration required for the titanium APM controller device. + * register configuration required for the MSM8953 APM controller device. */ -static int msmtitanium_apm_ctrl_init(struct platform_device *pdev, - struct msm_apm_ctrl_dev *ctrl) +static int msm8953_apm_ctrl_init(struct platform_device *pdev, + struct msm_apm_ctrl_dev *ctrl) { struct device *dev = &pdev->dev; struct resource *res; @@ -282,7 +282,7 @@ static int msmtitanium_apm_ctrl_init(struct platform_device *pdev, * Initial APM register configuration required before starting * APM HW controller. */ - regval = readl_relaxed(ctrl->reg_base + MSMTITANIUM_APM_DLY_CNTR); + regval = readl_relaxed(ctrl->reg_base + MSM8953_APM_DLY_CNTR); val = regval; if (of_find_property(dev->of_node, "qcom,apm-post-halt-delay", NULL)) { @@ -342,7 +342,7 @@ static int msmtitanium_apm_ctrl_init(struct platform_device *pdev, } if (val != regval) { - writel_relaxed(val, ctrl->reg_base + MSMTITANIUM_APM_DLY_CNTR); + writel_relaxed(val, ctrl->reg_base + MSM8953_APM_DLY_CNTR); /* make sure write completes before return */ mb(); } @@ -619,17 +619,17 @@ done: return ret; } -/* Titanium register value definitions */ -#define MSMTITANIUM_APM_MX_MODE_VAL 0x00 -#define MSMTITANIUM_APM_APCC_MODE_VAL 0x02 -#define MSMTITANIUM_APM_MX_DONE_VAL 0x00 -#define MSMTITANIUM_APM_APCC_DONE_VAL 0x03 +/* MSM8953 register value definitions */ +#define MSM8953_APM_MX_MODE_VAL 0x00 +#define MSM8953_APM_APCC_MODE_VAL 0x02 +#define MSM8953_APM_MX_DONE_VAL 0x00 +#define MSM8953_APM_APCC_DONE_VAL 0x03 -/* Titanium register offset definitions */ -#define MSMTITANIUM_APCC_APM_MODE 0x000002a8 -#define MSMTITANIUM_APCC_APM_CTL_STS 0x000002b0 +/* MSM8953 register offset definitions */ +#define MSM8953_APCC_APM_MODE 0x000002a8 +#define MSM8953_APCC_APM_CTL_STS 0x000002b0 -static int msmtitanium_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) +static int msm8953_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) { int timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; @@ -639,17 +639,17 @@ static int msmtitanium_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) spin_lock_irqsave(&ctrl_dev->lock, flags); /* Switch arrays to MX supply and wait for its completion */ - writel_relaxed(MSMTITANIUM_APM_MX_MODE_VAL, ctrl_dev->reg_base + - MSMTITANIUM_APCC_APM_MODE); + writel_relaxed(MSM8953_APM_MX_MODE_VAL, ctrl_dev->reg_base + + MSM8953_APCC_APM_MODE); /* Ensure write above completes before delaying */ mb(); while (timeout > 0) { regval = readl_relaxed(ctrl_dev->reg_base + - MSMTITANIUM_APCC_APM_CTL_STS); + MSM8953_APCC_APM_CTL_STS); if ((regval & MSM_APM_CTL_STS_MASK) == - MSMTITANIUM_APM_MX_DONE_VAL) + MSM8953_APM_MX_DONE_VAL) break; udelay(1); @@ -670,7 +670,7 @@ static int msmtitanium_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) return ret; } -static int msmtitanium_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) +static int msm8953_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) { int timeout = MSM_APM_SWITCH_TIMEOUT_US; u32 regval; @@ -680,17 +680,17 @@ static int msmtitanium_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) spin_lock_irqsave(&ctrl_dev->lock, flags); /* Switch arrays to APCC supply and wait for its completion */ - writel_relaxed(MSMTITANIUM_APM_APCC_MODE_VAL, ctrl_dev->reg_base + - MSMTITANIUM_APCC_APM_MODE); + writel_relaxed(MSM8953_APM_APCC_MODE_VAL, ctrl_dev->reg_base + + MSM8953_APCC_APM_MODE); /* Ensure write above completes before delaying */ mb(); while (timeout > 0) { regval = readl_relaxed(ctrl_dev->reg_base + - MSMTITANIUM_APCC_APM_CTL_STS); + MSM8953_APCC_APM_CTL_STS); if ((regval & MSM_APM_CTL_STS_MASK) == - MSMTITANIUM_APM_APCC_DONE_VAL) + MSM8953_APM_APCC_DONE_VAL) break; udelay(1); @@ -722,8 +722,8 @@ static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev) case MSM8996PRO_ID: ret = msm8996pro_apm_switch_to_mx(ctrl_dev); break; - case MSMTITANIUM_ID: - ret = msmtitanium_apm_switch_to_mx(ctrl_dev); + case MSM8953_ID: + ret = msm8953_apm_switch_to_mx(ctrl_dev); break; } @@ -741,8 +741,8 @@ static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev) case MSM8996PRO_ID: ret = msm8996pro_apm_switch_to_apcc(ctrl_dev); break; - case MSMTITANIUM_ID: - ret = msmtitanium_apm_switch_to_apcc(ctrl_dev); + case MSM8953_ID: + ret = msm8953_apm_switch_to_apcc(ctrl_dev); break; } @@ -898,7 +898,7 @@ static void apm_debugfs_init(struct msm_apm_ctrl_dev *ctrl_dev) return; } - temp = debugfs_create_file("supply", S_IRUGO, ctrl_dev->debugfs, + temp = debugfs_create_file("supply", 0444, ctrl_dev->debugfs, ctrl_dev, &apm_supply_fops); if (IS_ERR_OR_NULL(temp)) { pr_err("supply mode creation failed\n"); @@ -932,7 +932,7 @@ static void apm_debugfs_base_remove(void) #endif -static struct of_device_id msm_apm_match_table[] = { +static const struct of_device_id msm_apm_match_table[] = { { .compatible = "qcom,msm-apm", .data = (void *)(uintptr_t)MSM8996_ID, @@ -942,8 +942,8 @@ static struct of_device_id msm_apm_match_table[] = { .data = (void *)(uintptr_t)MSM8996PRO_ID, }, { - .compatible = "qcom,msmtitanium-apm", - .data = (void *)(uintptr_t)MSMTITANIUM_ID, + .compatible = "qcom,msm8953-apm", + .data = (void *)(uintptr_t)MSM8953_ID, }, {} }; @@ -967,10 +967,8 @@ static int msm_apm_probe(struct platform_device *pdev) return -ENODEV; ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) { - dev_err(dev, "MSM APM controller memory allocation failed\n"); + if (!ctrl) return -ENOMEM; - } INIT_LIST_HEAD(&ctrl->list); spin_lock_init(&ctrl->lock); @@ -987,8 +985,8 @@ static int msm_apm_probe(struct platform_device *pdev) return ret; } break; - case MSMTITANIUM_ID: - ret = msmtitanium_apm_ctrl_init(pdev, ctrl); + case MSM8953_ID: + ret = msm8953_apm_ctrl_init(pdev, ctrl); if (ret) { dev_err(dev, "Failed to initialize APM controller device: ret=%d\n", ret); diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c index c4cc541a0a3e..078bbaaad5a2 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 { @@ -315,7 +314,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 +445,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] = { @@ -1187,7 +1187,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 +1241,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..4e9d2894479a 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -219,6 +219,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; @@ -620,7 +637,7 @@ static int smb2_usb_main_get_prop(struct power_supply *psy, 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; } @@ -1305,7 +1322,22 @@ static int smb2_init_hw(struct smb2 *chip) smblib_get_charge_param(chg, &chg->param.dc_icl, &chip->dt.dc_icl_ua); - chg->otg_cl_ua = chip->dt.otg_cl_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->dcp_icl_ua = chip->dt.usb_icl_ua; chg->boost_threshold_ua = chip->dt.boost_threshold_ua; @@ -1515,7 +1547,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; @@ -1545,9 +1577,25 @@ static int smb2_setup_wa_flags(struct smb2 *chip) 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.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", @@ -1936,10 +1984,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..16edf875de96 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -39,7 +39,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); @@ -193,34 +193,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; @@ -325,6 +297,58 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) * 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 +441,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) { @@ -762,20 +786,6 @@ out: return rc; } -#define MICRO_250MA 250000 -static int smblib_otg_cl_config(struct smb_charger *chg, int otg_cl_ua) -{ - int rc = 0; - - rc = smblib_set_charge_param(chg, &chg->param.otg_cl, otg_cl_ua); - if (rc < 0) { - smblib_err(chg, "Couldn't set otg current limit rc=%d\n", rc); - return rc; - } - - return rc; -} - static int smblib_dc_icl_vote_callback(struct votable *votable, void *data, int icl_ua, const char *client) { @@ -955,22 +965,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 +1006,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 +1024,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 +1033,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 +1042,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 +1056,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 +1065,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 +1074,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 +1084,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 +1099,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 +1114,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 +1123,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 +1131,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 +1163,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 +1172,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 +1181,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; } @@ -1955,6 +1946,29 @@ int smblib_get_pe_start(struct smb_charger *chg, return 0; } +int smblib_get_prop_connector_therm_zone(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc, i; + 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; + } + + i = fls((stat & TEMP_RANGE_MASK) >> TEMP_RANGE_SHIFT) - 1; + if (i < 0) { + smblib_err(chg, "TEMP_RANGE is invalid\n"); + return -EINVAL; + } + + val->intval = i; + return 0; +} + /******************* * USB PSY SETTERS * * *****************/ @@ -1991,8 +2005,6 @@ int smblib_set_prop_usb_current_max(struct smb_charger *chg, 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 +2012,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; @@ -2467,50 +2480,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; - - 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); - } + if (stat & OTG_OVERCURRENT_RT_STS_BIT) + schedule_work(&chg->otg_oc_work); -unlock: - mutex_unlock(&chg->otg_overcurrent_lock); return IRQ_HANDLED; } @@ -2632,7 +2604,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, @@ -2738,16 +2711,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,14 +2739,17 @@ 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); } } @@ -2966,7 +2946,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; } @@ -3094,41 +3075,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 +3114,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); @@ -3362,6 +3308,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; @@ -3541,12 +3671,15 @@ 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) { diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index b3fce23c6508..e341484bc2ec 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -24,6 +24,7 @@ enum print_reason { PR_REGISTER = BIT(1), PR_MISC = BIT(2), PR_PARALLEL = BIT(3), + PR_OTG = BIT(4), }; #define DEFAULT_VOTER "DEFAULT_VOTER" @@ -104,6 +105,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 +146,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 { @@ -154,11 +168,12 @@ struct smb_charger { int *debug_mask; enum smb_mode mode; bool external_vconn; + struct smb_chg_freq chg_freq; /* 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; @@ -204,6 +219,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 +232,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; @@ -258,6 +275,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); @@ -360,6 +379,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_connector_therm_zone(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, diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index 5f74e27c7978..f238b055d271 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,8 @@ 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 TEMP_RANGE_SHIFT 1 #define ALERT_LEVEL_BIT BIT(4) #define TEMP_ABOVE_RANGE_BIT BIT(3) #define TEMP_WITHIN_RANGE_BIT BIT(2) @@ -1007,4 +1016,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/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c index ae15fef6c3a6..9287b7c37b97 100644 --- a/drivers/power/supply/qcom/smb138x-charger.c +++ b/drivers/power/supply/qcom/smb138x-charger.c @@ -10,18 +10,21 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "SMB138X: %s: " fmt, __func__ + #include <linux/device.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/regmap.h> -#include <linux/power_supply.h> +#include <linux/iio/consumer.h> #include <linux/interrupt.h> +#include <linux/module.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 +92,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 { @@ -132,6 +137,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.chg_temp_max_mdegc); + if (rc < 0) + chip->dt.connector_temp_max_mdegc = 105000; + return 0; } @@ -415,6 +432,7 @@ static enum power_supply_property smb138x_parallel_props[] = { POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PARALLEL_MODE, + POWER_SUPPLY_PROP_CONNECTOR_THERM_ZONE, }; static int smb138x_parallel_get_prop(struct power_supply *psy, @@ -467,6 +485,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_THERM_ZONE: + rc = smblib_get_prop_connector_therm_zone(chg, val); + break; default: pr_err("parallel power supply get prop %d not supported\n", prop); @@ -658,6 +679,138 @@ 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; @@ -681,15 +834,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 +853,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 +862,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 +877,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 +886,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 +943,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 +967,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; } @@ -971,7 +1135,7 @@ static const struct smb138x_irq_info smb138x_irqs[] = { }, { .name = "temperature-change", - .handler = smblib_handle_debug, + .handler = smb138x_handle_temperature_change, }, { .name = "switcher-power-ok", @@ -1144,95 +1308,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; } @@ -1312,6 +1435,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/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..c51ed182ba96 100644 --- a/drivers/regulator/cpr3-regulator.c +++ b/drivers/regulator/cpr3-regulator.c @@ -1622,8 +1622,6 @@ static void cpr3_regulator_set_target_quot(struct cpr3_thread *thread) } thread->last_closed_loop_aggr_corner = thread->aggr_corner; - - return; } /** @@ -1647,8 +1645,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 +4193,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 +4262,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 +4962,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 +5223,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 +5245,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 +5260,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 +5359,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 +5381,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 +5397,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 +5410,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 +5426,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 +5468,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 +5476,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 +5484,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 +5492,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 +5509,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 +5867,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 +5876,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 +5885,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 +5893,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 +5903,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 +5939,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..7dae23ca0e70 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 */ @@ -1021,7 +1021,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 +1030,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/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..c4aef84e26eb 100644 --- a/drivers/regulator/cpr4-mmss-ldo-regulator.c +++ b/drivers/regulator/cpr4-mmss-ldo-regulator.c @@ -737,6 +737,7 @@ static const struct of_device_id cpr4_mmss_regulator_match_table[] = { .compatible = "qcom,cpr4-sdm660-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..f21800e00d80 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -2007,7 +2007,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, 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/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 4a315d8f5534..1e5970b31404 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 diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 16ee98d8e4e0..f1ce71f05682 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -1339,7 +1339,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; @@ -1724,19 +1724,21 @@ 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_pd_restart_complete(struct icnss_priv *priv) { - int ret = 0; + int ret; + + clear_bit(ICNSS_PD_RESTART, &priv->state); + icnss_pm_relax(priv); if (!priv->ops || !priv->ops->reinit) goto out; if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) - goto out; + goto call_probe; icnss_pr_dbg("Calling driver reinit state: 0x%lx\n", priv->state); @@ -1751,18 +1753,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; } @@ -1787,7 +1785,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); 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/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/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-tsens.c b/drivers/thermal/msm-tsens.c index 82a8e4e200ba..d59b9736c570 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -364,6 +364,7 @@ static int32_t get_tsens_sensor_for_client_id(struct tsens_tm_device *tmdev, if (!strcmp(id->compatible, "qcom,msm8996-tsens") || (!strcmp(id->compatible, "qcom,msm8998-tsens")) || (!strcmp(id->compatible, "qcom,sdm660-tsens")) || + (!strcmp(id->compatible, "qcom,sdm630-tsens")) || (!strcmp(id->compatible, "qcom,msmhamster-tsens"))) { while (i < tmdev->tsens_num_sensor && !id_found) { if (tmdev->sensor[i].sensor_client_id == @@ -494,6 +495,7 @@ int tsens_get_hw_id_mapping(int thermal_sensor_num, int *sensor_client_id) if (!strcmp(id->compatible, "qcom,msm8996-tsens") || (!strcmp(id->compatible, "qcom,msm8998-tsens")) || (!strcmp(id->compatible, "qcom,sdm660-tsens")) || + (!strcmp(id->compatible, "qcom,sdm630-tsens")) || (!strcmp(id->compatible, "qcom,msmhamster-tsens"))) { /* Assign client id's that is used to get the * controller and hw_sensor details 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/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/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index 6c18a04f6c1c..83a98f1196f8 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -402,6 +402,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.c b/drivers/usb/host/xhci.c index 6e2c2f2bcce2..3ad30641873d 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 */ diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index ed33743c9062..611750e209f9 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -243,6 +243,10 @@ static void *usbpd_ipc_log; #define MAX_VDM_RESPONSE_TIME 60 /* 2 * tVDMSenderResponse_max(30ms) */ #define MAX_VDM_BUSY_TIME 100 /* 2 * tVDMBusy (50ms) */ +#define PD_SNK_PDO_FIXED(prs, hc, uc, usb_comm, drs, volt, curr) \ + (((prs) << 29) | ((hc) << 28) | ((uc) << 27) | ((usb_comm) << 26) | \ + ((drs) << 25) | ((volt) << 10) | (curr)) + /* VDM header is the first 32-bit object following the 16-bit PD header */ #define VDM_HDR_SVID(hdr) ((hdr) >> 16) #define VDM_IS_SVDM(hdr) ((hdr) & 0x8000) @@ -273,7 +277,7 @@ static int min_sink_current = 900; module_param(min_sink_current, int, S_IRUSR | S_IWUSR); static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */ -static const u32 default_snk_caps[] = { 0x2601905A }; /* 5V @ 900mA */ +static const u32 default_snk_caps[] = { 0x2601912C }; /* VSafe5V @ 3A */ struct vdm_tx { u32 data[7]; @@ -318,6 +322,9 @@ struct usbpd { bool peer_pr_swap; bool peer_dr_swap; + u32 sink_caps[7]; + int num_sink_caps; + struct power_supply *usb_psy; struct notifier_block psy_nb; @@ -1718,8 +1725,8 @@ static void usbpd_sm(struct work_struct *w) } } else if (IS_CTRL(rx_msg, MSG_GET_SINK_CAP)) { ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, - default_snk_caps, - ARRAY_SIZE(default_snk_caps), SOP_MSG); + pd->sink_caps, pd->num_sink_caps, + SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Sink Caps\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); @@ -1996,8 +2003,8 @@ static void usbpd_sm(struct work_struct *w) usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); } else if (IS_CTRL(rx_msg, MSG_GET_SINK_CAP)) { ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES, - default_snk_caps, - ARRAY_SIZE(default_snk_caps), SOP_MSG); + pd->sink_caps, pd->num_sink_caps, + SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending Sink Caps\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); @@ -3157,6 +3164,44 @@ struct usbpd *usbpd_create(struct device *parent) pd->vconn_is_external = device_property_present(parent, "qcom,vconn-uses-external-source"); + pd->num_sink_caps = device_property_read_u32_array(parent, + "qcom,default-sink-caps", NULL, 0); + if (pd->num_sink_caps) { + int i; + u32 sink_caps[14]; + + if (pd->num_sink_caps % 2 || pd->num_sink_caps > 14) { + ret = -EINVAL; + usbpd_err(&pd->dev, "default-sink-caps must be be specified as voltage/current, max 7 pairs\n"); + goto put_psy; + } + + ret = device_property_read_u32_array(parent, + "qcom,default-sink-caps", sink_caps, + pd->num_sink_caps); + if (ret) { + usbpd_err(&pd->dev, "Error reading default-sink-caps\n"); + goto put_psy; + } + + pd->num_sink_caps /= 2; + + for (i = 0; i < pd->num_sink_caps; i++) { + int v = sink_caps[i * 2] / 50; + int c = sink_caps[i * 2 + 1] / 10; + + pd->sink_caps[i] = + PD_SNK_PDO_FIXED(0, 0, 0, 0, 0, v, c); + } + + /* First PDO includes additional capabilities */ + pd->sink_caps[0] |= PD_SNK_PDO_FIXED(1, 0, 0, 1, 1, 0, 0); + } else { + memcpy(pd->sink_caps, default_snk_caps, + sizeof(default_snk_caps)); + pd->num_sink_caps = ARRAY_SIZE(default_snk_caps); + } + /* * Register the Android dual-role class (/sys/class/dual_role_usb/). * The first instance should be named "otg_default" as that's what 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..b65582f8e042 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -4159,6 +4159,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 +4185,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 +4216,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"); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index b7f27b818eda..2a62ae5881b3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -2031,6 +2031,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 +2060,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 +2086,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 +2118,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_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 563cb8be1a04..bd41cb9e025c 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); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 3fc5b2226b3e..d73416e311b5 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, }; 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/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/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..64f5c4ca09d5 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -237,6 +237,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_FCC_DELTA, POWER_SUPPLY_PROP_ICL_REDUCTION, POWER_SUPPLY_PROP_PARALLEL_MODE, + POWER_SUPPLY_PROP_CONNECTOR_THERM_ZONE, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ 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/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 418eb97110a3..ef8a092251aa 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -45,6 +45,14 @@ extern unsigned int sysctl_sched_initial_task_util; extern unsigned int sysctl_sched_cstate_aware; #ifdef CONFIG_SCHED_HMP + +enum freq_reporting_policy { + FREQ_REPORT_MAX_CPU_LOAD_TOP_TASK, + FREQ_REPORT_CPU_LOAD, + FREQ_REPORT_TOP_TASK, + FREQ_REPORT_INVALID_POLICY +}; + extern int sysctl_sched_freq_inc_notify; extern int sysctl_sched_freq_dec_notify; extern unsigned int sysctl_sched_freq_reporting_policy; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 8fdf57504ab6..c8653a9f0e9e 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1058,6 +1058,9 @@ enum vl42_mpeg_vidc_video_h264_svc_nal { (V4L2_CID_MPEG_MSM_VIDC_BASE + 68) enum v4l2_mpeg_vidc_video_perf_mode { +#define V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT \ + V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT + V4L2_MPEG_VIDC_VIDEO_PERF_UNINIT = 0, V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY = 1, V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE = 2 }; 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 1c0defb34ae1..5de0bac5e27e 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -953,8 +953,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; @@ -968,7 +968,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; @@ -983,14 +984,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; } @@ -2787,7 +2788,7 @@ static u64 update_task_demand(struct task_struct *p, struct rq *rq, } static inline void -update_task_burst(struct task_struct *p, struct rq *rq, int event, int runtime) +update_task_burst(struct task_struct *p, struct rq *rq, int event, u64 runtime) { /* * update_task_demand() has checks for idle task and @@ -3108,7 +3109,7 @@ static inline u64 freq_policy_load(struct rq *rq, u64 load) case FREQ_REPORT_CPU_LOAD: break; default: - WARN_ON_ONCE(1); + break; } return load; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index a91f4cc1d8d3..360e298398fb 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1071,10 +1071,6 @@ enum sched_boost_policy { #define WINDOW_STATS_AVG 3 #define WINDOW_STATS_INVALID_POLICY 4 -#define FREQ_REPORT_MAX_CPU_LOAD_TOP_TASK 0 -#define FREQ_REPORT_CPU_LOAD 1 -#define FREQ_REPORT_TOP_TASK 2 - #define SCHED_UPMIGRATE_MIN_NICE 15 #define EXITING_TASK_MARKER 0xdeaddead diff --git a/kernel/sysctl.c b/kernel/sysctl.c index a2a87c3ad44e..7112dc54d88e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -133,6 +133,7 @@ static int ten_thousand = 10000; #endif #ifdef CONFIG_SCHED_HMP static int one_thousand = 1000; +static int max_freq_reporting_policy = FREQ_REPORT_INVALID_POLICY - 1; #endif /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ @@ -297,6 +298,7 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, + .extra2 = &max_freq_reporting_policy, }, { .procname = "sched_freq_inc_notify", @@ -591,7 +593,8 @@ static struct ctl_table kern_table[] = { .data = &sysctl_sched_time_avg, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, }, { .procname = "sched_shares_window_ns", diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 46e60923221f..6f7985e6f129 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; 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/wcd-dsp-mgr.c b/sound/soc/codecs/wcd-dsp-mgr.c index f51301d1ab08..71a2052f1089 100644 --- a/sound/soc/codecs/wcd-dsp-mgr.c +++ b/sound/soc/codecs/wcd-dsp-mgr.c @@ -1,5 +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 @@ -881,12 +880,50 @@ done: static int wdsp_suspend(struct device *wdsp_dev) { - return 0; + struct wdsp_mgr_priv *wdsp; + int rc = 0, i; + + if (!wdsp_dev) { + pr_err("%s: Invalid handle to device\n", __func__); + return -EINVAL; + } + + wdsp = dev_get_drvdata(wdsp_dev); + + for (i = WDSP_CMPNT_TYPE_MAX - 1; i >= 0; i--) { + rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_SUSPEND, NULL); + if (rc < 0) { + WDSP_ERR(wdsp, "component %s failed to suspend\n", + WDSP_GET_CMPNT_TYPE_STR(i)); + break; + } + } + + return rc; } static int wdsp_resume(struct device *wdsp_dev) { - return 0; + struct wdsp_mgr_priv *wdsp; + int rc = 0, i; + + if (!wdsp_dev) { + pr_err("%s: Invalid handle to device\n", __func__); + return -EINVAL; + } + + wdsp = dev_get_drvdata(wdsp_dev); + + for (i = 0; i < WDSP_CMPNT_TYPE_MAX; i++) { + rc = wdsp_unicast_event(wdsp, i, WDSP_EVENT_RESUME, NULL); + if (rc < 0) { + WDSP_ERR(wdsp, "component %s failed to resume\n", + WDSP_GET_CMPNT_TYPE_STR(i)); + break; + } + } + + return rc; } static struct wdsp_mgr_ops wdsp_ops = { diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c index 614410c26a91..b03a8a9caed7 100644 --- a/sound/soc/codecs/wcd-spi.c +++ b/sound/soc/codecs/wcd-spi.c @@ -1,5 +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 @@ -60,7 +59,8 @@ /* Command delays */ #define WCD_SPI_CLKREQ_DELAY_USECS (500) -#define WCD_SPI_CLK_OFF_TIMER_MS (3000) +#define WCD_SPI_CLK_OFF_TIMER_MS (500) +#define WCD_SPI_RESUME_TIMEOUT_MS 100 /* Command masks */ #define WCD_CMD_ADDR_MASK \ @@ -90,6 +90,7 @@ /* Status mask bits */ #define WCD_SPI_CLK_STATE_ENABLED BIT(0) +#define WCD_SPI_IS_SUSPENDED BIT(1) /* Locking related */ #define WCD_SPI_MUTEX_LOCK(spi, lock) \ @@ -144,6 +145,9 @@ struct wcd_spi_priv { /* Debugfs related information */ struct wcd_spi_debug_data debug_data; + + /* Completion object to indicate system resume completion */ + struct completion resume_comp; }; enum xfer_request { @@ -170,6 +174,55 @@ static void wcd_spi_reinit_xfer(struct spi_transfer *xfer) xfer->len = 0; } +static bool wcd_spi_is_suspended(struct wcd_spi_priv *wcd_spi) +{ + return test_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask); +} + +static bool wcd_spi_can_suspend(struct wcd_spi_priv *wcd_spi) +{ + struct spi_device *spi = wcd_spi->spi; + + if (wcd_spi->clk_users > 0 || + test_bit(WCD_SPI_CLK_STATE_ENABLED, &wcd_spi->status_mask)) { + dev_err(&spi->dev, "%s: cannot suspend, clk_users = %d\n", + __func__, wcd_spi->clk_users); + return false; + } + + return true; +} + +static int wcd_spi_wait_for_resume(struct wcd_spi_priv *wcd_spi) +{ + struct spi_device *spi = wcd_spi->spi; + int rc = 0; + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + /* If the system is already in resumed state, return right away */ + if (!wcd_spi_is_suspended(wcd_spi)) + goto done; + + /* If suspended then wait for resume to happen */ + reinit_completion(&wcd_spi->resume_comp); + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + rc = wait_for_completion_timeout(&wcd_spi->resume_comp, + msecs_to_jiffies(WCD_SPI_RESUME_TIMEOUT_MS)); + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (rc == 0) { + dev_err(&spi->dev, "%s: failed to resume in %u msec\n", + __func__, WCD_SPI_RESUME_TIMEOUT_MS); + rc = -EIO; + goto done; + } + + dev_dbg(&spi->dev, "%s: resume successful\n", __func__); + rc = 0; +done: + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + return rc; +} + static int wcd_spi_read_single(struct spi_device *spi, u32 remote_addr, u32 *val) { @@ -579,6 +632,18 @@ static int wcd_spi_clk_ctrl(struct spi_device *spi, } if (request == WCD_SPI_CLK_ENABLE) { + /* + * If the SPI bus is suspended, then return error + * as the transaction cannot be completed. + */ + if (wcd_spi_is_suspended(wcd_spi)) { + dev_err(&spi->dev, + "%s: SPI suspended, cannot enable clk\n", + __func__); + ret = -EIO; + goto done; + } + /* Cancel the disable clk work */ WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); cancel_delayed_work_sync(&wcd_spi->clk_dwork); @@ -899,6 +964,17 @@ static int wdsp_spi_event_handler(struct device *dev, void *priv_data, ret = wdsp_spi_read_section(spi, data); break; + case WDSP_EVENT_SUSPEND: + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (!wcd_spi_can_suspend(wcd_spi)) + ret = -EBUSY; + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + break; + + case WDSP_EVENT_RESUME: + ret = wcd_spi_wait_for_resume(wcd_spi); + break; + default: dev_dbg(&spi->dev, "%s: Unhandled event %d\n", __func__, event); @@ -1303,6 +1379,7 @@ static int wcd_spi_probe(struct spi_device *spi) mutex_init(&wcd_spi->clk_mutex); mutex_init(&wcd_spi->xfer_mutex); INIT_DELAYED_WORK(&wcd_spi->clk_dwork, wcd_spi_clk_work); + init_completion(&wcd_spi->resume_comp); wcd_spi->spi = spi; spi_set_drvdata(spi, wcd_spi); @@ -1340,6 +1417,61 @@ static int wcd_spi_remove(struct spi_device *spi) return 0; } +#ifdef CONFIG_PM +static int wcd_spi_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + int rc = 0; + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + if (!wcd_spi_can_suspend(wcd_spi)) { + rc = -EBUSY; + goto done; + } + + /* + * If we are here, it is okay to let the suspend go + * through for this driver. But, still need to notify + * the master to make sure all other components can suspend + * as well. + */ + if (wcd_spi->m_dev && wcd_spi->m_ops && + wcd_spi->m_ops->suspend) { + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + rc = wcd_spi->m_ops->suspend(wcd_spi->m_dev); + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + } + + if (rc == 0) + set_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask); + else + dev_dbg(&spi->dev, "%s: cannot suspend, err = %d\n", + __func__, rc); +done: + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + return rc; +} + +static int wcd_spi_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi); + + WCD_SPI_MUTEX_LOCK(spi, wcd_spi->clk_mutex); + clear_bit(WCD_SPI_IS_SUSPENDED, &wcd_spi->status_mask); + complete(&wcd_spi->resume_comp); + WCD_SPI_MUTEX_UNLOCK(spi, wcd_spi->clk_mutex); + + return 0; +} + +static const struct dev_pm_ops wcd_spi_pm_ops = { + .suspend = wcd_spi_suspend, + .resume = wcd_spi_resume, +}; +#endif + static const struct of_device_id wcd_spi_of_match[] = { { .compatible = "qcom,wcd-spi-v2", }, { } @@ -1350,6 +1482,9 @@ static struct spi_driver wcd_spi_driver = { .driver = { .name = "wcd-spi-v2", .of_match_table = wcd_spi_of_match, +#ifdef CONFIG_PM + .pm = &wcd_spi_pm_ops, +#endif }, .probe = wcd_spi_probe, .remove = wcd_spi_remove, diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index f1607b8e5d66..9a141a11d002 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -145,7 +145,7 @@ int afe_get_topology(int port_id) int topology; int port_index = afe_get_port_index(port_id); - if ((port_index < 0) || (port_index > AFE_MAX_PORTS)) { + if ((port_index < 0) || (port_index >= AFE_MAX_PORTS)) { pr_err("%s: Invalid port index %d\n", __func__, port_index); topology = -EINVAL; goto done; @@ -726,7 +726,7 @@ static int afe_send_cal_block(u16 port_id, struct cal_block_data *cal_block) } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); result = -EINVAL; @@ -870,7 +870,7 @@ static int afe_spk_ramp_dn_cfg(int port) goto fail_cmd; } index = q6audio_get_port_index(port); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); ret = -EINVAL; @@ -951,7 +951,7 @@ static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id, goto fail_cmd; } index = q6audio_get_port_index(src_port); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); ret = -EINVAL; @@ -1196,7 +1196,7 @@ static int afe_send_hw_delay(u16 port_id, u32 rate) } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); ret = -EINVAL; @@ -1318,7 +1318,7 @@ static int afe_send_port_topology_id(u16 port_id) u32 topology_id = 0; index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS - 1) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -1675,7 +1675,7 @@ static int afe_send_slimbus_slave_port_cfg( pr_debug("%s: enter, port_id = 0x%x\n", __func__, port_id); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -1729,7 +1729,7 @@ static int afe_aanc_port_cfg(void *apr, uint16_t tx_port, uint16_t rx_port) } index = q6audio_get_port_index(tx_port); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -1814,7 +1814,7 @@ static int afe_aanc_mod_enable(void *apr, uint16_t tx_port, uint16_t enable) } index = q6audio_get_port_index(tx_port); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2036,7 +2036,7 @@ int afe_send_spdif_clk_cfg(struct afe_param_id_spdif_clk_cfg *cfg, return ret; } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2122,7 +2122,7 @@ int afe_send_spdif_ch_status_cfg(struct afe_param_id_spdif_ch_status_cfg return ret; } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2196,7 +2196,7 @@ static int afe_send_cmd_port_start(u16 port_id) pr_debug("%s: enter\n", __func__); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2267,7 +2267,7 @@ int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port, pr_debug("%s: port id: 0x%x\n", __func__, port_id); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2342,7 +2342,7 @@ int afe_send_slot_mapping_cfg( pr_debug("%s: port id: 0x%x\n", __func__, port_id); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2421,7 +2421,7 @@ int afe_send_custom_tdm_header_cfg( pr_debug("%s: port id: 0x%x\n", __func__, port_id); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2501,7 +2501,7 @@ int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port, pr_debug("%s: port id: 0x%x\n", __func__, port_id); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -2623,7 +2623,7 @@ int afe_port_send_usb_dev_param(u16 port_id, union afe_port_config *afe_config) goto exit; } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid! for port ID 0x%x\n", __func__, index, port_id); ret = -EINVAL; @@ -2824,7 +2824,7 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, pr_debug("%s: port id: 0x%x\n", __func__, port_id); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -3383,7 +3383,7 @@ int afe_open(u16 port_id, pr_err("%s: port_id 0x%x rate %d\n", __func__, port_id, rate); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -3551,7 +3551,7 @@ int afe_loopback(u16 enable, u16 rx_port, u16 tx_port) } index = q6audio_get_port_index(rx_port); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -3617,7 +3617,7 @@ int afe_loopback_gain(u16 port_id, u16 volume) goto fail_cmd; } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -3720,7 +3720,7 @@ int afe_start_pseudo_port(u16 port_id) } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -3763,7 +3763,7 @@ int afe_pseudo_port_stop_nowait(u16 port_id) return -EINVAL; } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -3924,7 +3924,7 @@ int afe_stop_pseudo_port(u16 port_id) } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -4213,7 +4213,7 @@ int afe_cmd_memory_map_nowait(int port_id, phys_addr_t dma_addr_p, rtac_set_afe_handle(this_afe.apr); } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -4477,7 +4477,7 @@ int afe_unregister_get_events(u16 port_id) } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -4821,7 +4821,7 @@ int afe_dtmf_generate_rx(int64_t duration_in_ms, goto fail_cmd; } index = q6audio_get_port_index(this_afe.dtmf_gen_rx_portid); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); ret = -EINVAL; @@ -5059,7 +5059,7 @@ int afe_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable) int index; index = q6audio_get_port_index(rx_port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); ret = -EINVAL; @@ -5072,7 +5072,7 @@ int afe_sidetone_enable(u16 tx_port_id, u16 rx_port_id, bool enable) goto done; } index = q6audio_get_port_index(tx_port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); ret = -EINVAL; @@ -5367,7 +5367,7 @@ int afe_close(int port_id) port_id = q6audio_convert_virtual_to_portid(port_id); index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -5525,7 +5525,7 @@ int afe_set_lpass_clock(u16 port_id, struct afe_clk_cfg *cfg) return ret; } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -5691,7 +5691,7 @@ int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg) int ret = 0; index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -5724,7 +5724,7 @@ int afe_set_lpass_internal_digital_codec_clock(u16 port_id, return ret; } index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -5805,7 +5805,7 @@ int afe_enable_lpass_core_shared_clock(u16 port_id, u32 enable) int ret = 0; index = q6audio_get_port_index(port_id); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); return -EINVAL; @@ -6084,7 +6084,7 @@ int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp) goto fail_cmd; } index = q6audio_get_port_index(port); - if (index < 0 || index > AFE_MAX_PORTS) { + if (index < 0 || index >= AFE_MAX_PORTS) { pr_err("%s: AFE port index[%d] invalid!\n", __func__, index); ret = -EINVAL; diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c index 6bbde623a7c1..8b0a12a46338 100644 --- a/sound/soc/msm/sdm660-internal.c +++ b/sound/soc/msm/sdm660-internal.c @@ -910,9 +910,6 @@ static const struct snd_kcontrol_new msm_sdw_controls[] = { SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate, int_mi2s_sample_rate_get, int_mi2s_sample_rate_put), - SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate, - int_mi2s_sample_rate_get, - int_mi2s_sample_rate_put), SOC_ENUM_EXT("INT4_MI2S_RX Channels", int4_mi2s_rx_chs, int_mi2s_ch_get, int_mi2s_ch_put), SOC_ENUM_EXT("VI_FEED_TX Channels", int5_mi2s_tx_chs, |
