From 85cdf78f42f18d1fcae6b73e8e4b5aec6f1c2d23 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 13 Sep 2019 14:51:02 -0400 Subject: [PATCH 01/76] MeiG Change-Id: I5119fe450ae57b860cca823bcff83ab9db448118 --- arch/arm/boot/dts/qcom/Makefile | 1 + ...si-panel-hx8394f-zzw500hah-720p-video.dtsi | 95 + .../dts/qcom/dsi-panel-ortustech-video.dtsi | 186 + .../dts/qcom/dsi-panel-ortustech32-video.dtsi | 80 + ...el-otm1289a-zzw500hc0-145b-720p-video.dtsi | 144 + .../dts/qcom/msm8909-camera-sensor-skua.dtsi | 114 + arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 4 +- arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi | 286 +- arch/arm/boot/dts/qcom/msm8909-qrd.dtsi | 32 +- arch/arm/configs/msm8909-perf_defconfig | 13 + arch/arm/configs/msm8909_defconfig | 14 +- drivers/input/misc/Kconfig | 51 + drivers/input/misc/Makefile | 27 +- drivers/input/misc/akm09911.c | 2 +- drivers/input/misc/akm09911m.c | 2661 +++ drivers/input/misc/bmi160.c | 18752 ++++++++++++++++ drivers/input/misc/bmi160.h | 11605 ++++++++++ drivers/input/misc/bmi160_driver.c | 5283 +++++ drivers/input/misc/bmi160_driver.h | 401 + drivers/input/misc/bmi160_i2c.c | 366 + drivers/input/misc/bmp280.c | 1624 ++ drivers/input/misc/bmp280.h | 1366 ++ drivers/input/misc/bmp280_core.c | 1734 ++ drivers/input/misc/bmp280_core.h | 67 + drivers/input/misc/bmp280_i2c.c | 477 + drivers/input/misc/bmp280_spi.c | 258 + drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/Makefile | 2 +- drivers/input/touchscreen/gt1xx/Kconfig | 19 + drivers/input/touchscreen/gt1xx/Makefile | 16 + drivers/input/touchscreen/gt1xx/gt1x.c | 898 + drivers/input/touchscreen/gt1xx/gt1x.h | 62 + .../input/touchscreen/gt1xx/gt1x_extents.c | 930 + .../input/touchscreen/gt1xx/gt1x_firmware.h | 551 + .../input/touchscreen/gt1xx/gt1x_generic.c | 2472 ++ .../input/touchscreen/gt1xx/gt1x_generic.h | 604 + drivers/input/touchscreen/gt1xx/gt1x_tools.c | 437 + drivers/input/touchscreen/gt1xx/gt1x_update.c | 1472 ++ drivers/platform/msm/qpnp-vibrator.c | 28 +- include/linux/akm09911.h | 168 + 40 files changed, 53271 insertions(+), 42 deletions(-) mode change 100644 => 100755 arch/arm/boot/dts/qcom/Makefile create mode 100755 arch/arm/boot/dts/qcom/dsi-panel-hx8394f-zzw500hah-720p-video.dtsi create mode 100755 arch/arm/boot/dts/qcom/dsi-panel-ortustech-video.dtsi create mode 100755 arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi create mode 100755 arch/arm/boot/dts/qcom/dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi create mode 100755 arch/arm/boot/dts/qcom/msm8909-camera-sensor-skua.dtsi mode change 100644 => 100755 arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi mode change 100644 => 100755 arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi mode change 100644 => 100755 arch/arm/boot/dts/qcom/msm8909-qrd.dtsi mode change 100644 => 100755 arch/arm/configs/msm8909-perf_defconfig mode change 100644 => 100755 arch/arm/configs/msm8909_defconfig mode change 100644 => 100755 drivers/input/misc/Kconfig mode change 100644 => 100755 drivers/input/misc/Makefile mode change 100644 => 100755 drivers/input/misc/akm09911.c create mode 100755 drivers/input/misc/akm09911m.c create mode 100755 drivers/input/misc/bmi160.c create mode 100755 drivers/input/misc/bmi160.h create mode 100755 drivers/input/misc/bmi160_driver.c create mode 100755 drivers/input/misc/bmi160_driver.h create mode 100755 drivers/input/misc/bmi160_i2c.c create mode 100755 drivers/input/misc/bmp280.c create mode 100755 drivers/input/misc/bmp280.h create mode 100755 drivers/input/misc/bmp280_core.c create mode 100755 drivers/input/misc/bmp280_core.h create mode 100755 drivers/input/misc/bmp280_i2c.c create mode 100755 drivers/input/misc/bmp280_spi.c mode change 100644 => 100755 drivers/input/touchscreen/Kconfig mode change 100644 => 100755 drivers/input/touchscreen/Makefile create mode 100755 drivers/input/touchscreen/gt1xx/Kconfig create mode 100755 drivers/input/touchscreen/gt1xx/Makefile create mode 100755 drivers/input/touchscreen/gt1xx/gt1x.c create mode 100755 drivers/input/touchscreen/gt1xx/gt1x.h create mode 100755 drivers/input/touchscreen/gt1xx/gt1x_extents.c create mode 100755 drivers/input/touchscreen/gt1xx/gt1x_firmware.h create mode 100755 drivers/input/touchscreen/gt1xx/gt1x_generic.c create mode 100755 drivers/input/touchscreen/gt1xx/gt1x_generic.h create mode 100755 drivers/input/touchscreen/gt1xx/gt1x_tools.c create mode 100755 drivers/input/touchscreen/gt1xx/gt1x_update.c mode change 100644 => 100755 drivers/platform/msm/qpnp-vibrator.c create mode 100755 include/linux/akm09911.h diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile old mode 100644 new mode 100755 index 588774d9339..222dbd27229 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -294,6 +294,7 @@ dtb-$(CONFIG_ARCH_MSM8916) += msm8952-qrd-skum.dtb \ dtb-$(CONFIG_ARCH_MSM8909) += msm8909-pm8916-mtp.dtb \ msm8909-cdp.dtb \ + msm8909-1gb-qrd-skua.dtb\ msm8909-1gb-qrd-skuc.dtb \ msm8909-1gb-qrd-skue.dtb \ msm8909-qrd-skue.dtb \ diff --git a/arch/arm/boot/dts/qcom/dsi-panel-hx8394f-zzw500hah-720p-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-hx8394f-zzw500hah-720p-video.dtsi new file mode 100755 index 00000000000..2a690e8610b --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-hx8394f-zzw500hah-720p-video.dtsi @@ -0,0 +1,95 @@ +/* Copyright (c) 2013, 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + dsi_hx8394f_zzw500hah_720p_video: qcom,mdss_dsi_hx8394f_zzw500hah_720p_video { + qcom,mdss-dsi-panel-name = "hx8394f zzw500hah hd 720X1280 video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <70>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <15>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-pixel-packing = "tight"; + qcom,mdss-dsi-pixel-alignment = <0>; + qcom,mdss-dsi-on-command = [29 01 00 00 00 00 04 B9 FF 83 94 + 29 01 00 00 00 00 07 BA 63 03 68 6B B2 C0 + 29 01 00 00 00 00 0B B1 48 11 71 09 32 54 71 71 4E 43 + 29 01 00 00 00 00 07 B2 65 80 64 05 07 2F + 29 01 00 00 00 00 16 B4 26 76 26 76 26 26 05 10 86 75 00 3F 26 76 26 76 26 26 05 10 80 + 29 01 00 00 00 00 22 D3 00 00 04 04 01 01 10 10 32 10 00 00 00 32 15 04 05 04 32 15 14 05 14 37 33 04 04 37 00 00 47 05 40 + 29 01 00 00 00 00 2D D5 18 18 18 18 18 18 18 18 18 18 18 18 18 18 25 24 27 26 18 18 11 10 15 14 13 12 17 16 01 00 05 04 03 02 07 06 21 20 23 22 18 18 18 18 + 29 01 00 00 00 00 2D D6 18 18 18 18 18 18 18 18 18 18 18 18 18 18 22 23 20 21 18 18 12 13 16 17 10 11 14 15 06 07 02 03 04 05 00 01 26 27 24 25 18 18 18 18 + 29 01 00 00 00 00 3B E0 00 04 11 1B 1E 22 27 26 51 60 70 6F 7A 8C 94 9A A9 AC A9 B9 C8 64 62 67 69 6A 7F 7F 7F 00 04 11 1A 1D 22 27 26 51 60 70 6F 79 8C 93 98 A8 AB AA B7 C8 64 63 67 6D 72 7F 7F 7F + 29 01 00 00 00 00 03 B6 7D 7D + 29 01 00 00 00 00 02 CC 0B + 29 01 00 00 00 00 03 C0 1F 31 + 29 01 00 00 00 00 02 D2 88 + 29 01 00 00 00 00 02 D4 02 + 29 01 00 00 00 00 02 BD 01 + 29 01 00 00 00 00 02 B1 00 + 29 01 00 00 00 00 02 BD 00 + 29 01 00 00 00 00 08 BF 40 81 50 00 1A FC 01 + 29 01 00 00 00 00 02 C6 EF + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 14 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-timings = [7B 1A 10 00 3E 40 16 1C 15 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x26>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-ortustech-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-ortustech-video.dtsi new file mode 100755 index 00000000000..c68160d7f04 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-ortustech-video.dtsi @@ -0,0 +1,186 @@ +/* Copyright (c) 2013 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + dsi_ortustech_video: qcom,dsi_ortustech_video { + qcom,mdss-dsi-panel-name = "mdss_dsi_ortustech_video 1440x640 video panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <480>; + qcom,mdss-dsi-panel-height = <640>; + qcom,mdss-dsi-h-front-porch = <16>; + qcom,mdss-dsi-h-back-porch = <16>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <52>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-pixel-packing = "tight"; + qcom,mdss-dsi-pixel-alignment = <0>; + qcom,mdss-dsi-on-command = [39 01 00 00 00 00 06 FF FF 98 06 04 01 + 39 01 00 00 00 00 02 08 18 + 39 01 00 00 00 00 02 21 01 + 39 01 00 00 00 00 02 30 03 + 39 01 00 00 00 00 02 31 00 + 39 01 00 00 00 00 02 60 0D + 39 01 00 00 00 00 02 61 08 + 39 01 00 00 00 00 02 62 08 + 39 01 00 00 00 00 02 63 09 + 39 01 00 00 00 00 02 40 30 + 39 01 00 00 00 00 02 41 44 + 39 01 00 00 00 00 02 42 00 + 39 01 00 00 00 00 02 43 89 + 39 01 00 00 00 00 02 44 8E + 39 01 00 00 00 00 02 45 D9 + 39 01 00 00 00 00 02 46 33 + 39 01 00 00 00 00 02 47 33 + 39 01 00 00 00 00 02 50 90 + 39 01 00 00 00 00 02 51 90 + 39 01 00 00 00 00 02 56 00 + 39 01 00 00 00 00 02 A0 00 + 39 01 00 00 00 00 02 A1 0C + 39 01 00 00 00 00 02 A2 13 + 39 01 00 00 00 00 02 A3 0F + 39 01 00 00 00 00 02 A4 12 + 39 01 00 00 00 00 02 A5 0D + 39 01 00 00 00 00 02 A6 0C + 39 01 00 00 00 00 02 A7 0B + 39 01 00 00 00 00 02 A8 01 + 39 01 00 00 00 00 02 A9 06 + 39 01 00 00 00 00 02 AA 15 + 39 01 00 00 00 00 02 AB 16 + 39 01 00 00 00 00 02 AC 12 + 39 01 00 00 00 00 02 AD 28 + 39 01 00 00 00 00 02 AE 20 + 39 01 00 00 00 00 02 AF 14 + 39 01 00 00 00 00 02 C0 00 + 39 01 00 00 00 00 02 C1 0C + 39 01 00 00 00 00 02 C2 13 + 39 01 00 00 00 00 02 C3 0F + 39 01 00 00 00 00 02 C4 11 + 39 01 00 00 00 00 02 C5 0D + 39 01 00 00 00 00 02 C6 0C + 39 01 00 00 00 00 02 C7 0B + 39 01 00 00 00 00 02 C8 01 + 39 01 00 00 00 00 02 C9 06 + 39 01 00 00 00 00 02 CA 14 + 39 01 00 00 00 00 02 CB 16 + 39 01 00 00 00 00 02 CC 0F + 39 01 00 00 00 00 02 CD 21 + 39 01 00 00 00 00 02 CE 17 + 39 01 00 00 00 00 02 CF 0A + 39 01 00 00 00 00 06 FF FF 98 06 04 07 + 39 01 00 00 00 00 02 06 11 + 39 01 00 00 00 00 02 18 1D + 39 01 00 00 00 00 02 17 32 + 39 01 00 00 00 00 06 FF FF 98 06 04 06 + 39 01 00 00 00 00 02 00 20 + 39 01 00 00 00 00 02 01 02 + 39 01 00 00 00 00 02 02 00 + 39 01 00 00 00 00 02 03 02 + 39 01 00 00 00 00 02 04 01 + 39 01 00 00 00 00 02 05 01 + 39 01 00 00 00 00 02 06 88 + 39 01 00 00 00 00 02 07 00 + 39 01 00 00 00 00 02 08 01 + 39 01 00 00 00 00 02 09 80 + 39 01 00 00 00 00 02 0A 00 + 39 01 00 00 00 00 02 0B 00 + 39 01 00 00 00 00 02 0C 01 + 39 01 00 00 00 00 02 0D 01 + 39 01 00 00 00 00 02 0E 00 + 39 01 00 00 00 00 02 0F 00 + 39 01 00 00 00 00 02 10 55 + 39 01 00 00 00 00 02 11 50 + 39 01 00 00 00 00 02 12 01 + 39 01 00 00 00 00 02 13 00 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 43 + 39 01 00 00 00 00 02 16 0B + 39 01 00 00 00 00 02 17 00 + 39 01 00 00 00 00 02 18 00 + 39 01 00 00 00 00 02 19 00 + 39 01 00 00 00 00 02 1A 00 + 39 01 00 00 00 00 02 1B 00 + 39 01 00 00 00 00 02 1C 00 + 39 01 00 00 00 00 02 1D 00 + 39 01 00 00 00 00 02 20 01 + 39 01 00 00 00 00 02 21 23 + 39 01 00 00 00 00 02 22 45 + 39 01 00 00 00 00 02 23 67 + 39 01 00 00 00 00 02 24 01 + 39 01 00 00 00 00 02 25 23 + 39 01 00 00 00 00 02 26 45 + 39 01 00 00 00 00 02 27 67 + 39 01 00 00 00 00 02 30 02 + 39 01 00 00 00 00 02 31 22 + 39 01 00 00 00 00 02 32 22 + 39 01 00 00 00 00 02 33 88 + 39 01 00 00 00 00 02 34 AA + 39 01 00 00 00 00 02 35 BB + 39 01 00 00 00 00 02 36 66 + 39 01 00 00 00 00 02 37 22 + 39 01 00 00 00 00 02 38 22 + 39 01 00 00 00 00 02 39 22 + 39 01 00 00 00 00 02 3A 22 + 39 01 00 00 00 00 02 3B 22 + 39 01 00 00 00 00 02 3C 22 + 39 01 00 00 00 00 02 3D 22 + 39 01 00 00 00 00 02 3E 22 + 39 01 00 00 00 00 02 3F 22 + 39 01 00 00 00 00 02 40 22 + 39 01 00 00 00 00 02 53 12 + 39 01 00 00 00 00 06 FF FF 98 06 04 00 + 39 01 00 00 00 00 02 3A 60 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 1C 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,mdss-dsi-panel-timings = [5A 10 0A 00 30 34 0E 14 0C 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x05>; + qcom,mdss-dsi-t-clk-pre = <0x14>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 120>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi new file mode 100755 index 00000000000..1eeb50e3390 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi @@ -0,0 +1,80 @@ +/* Copyright (c) 2013 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + dsi_ortustech32_video: qcom,dsi_ortustech32_video { + qcom,mdss-dsi-panel-name = "mdss_dsi_ortustech_video 480x800 video panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <480>; + qcom,mdss-dsi-panel-height = <800>; + qcom,mdss-dsi-h-front-porch = <16>; + qcom,mdss-dsi-h-back-porch = <16>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-pixel-packing = "tight"; + qcom,mdss-dsi-pixel-alignment = <0>; + qcom,mdss-dsi-on-command = [ + 05 01 00 00 a8 00 02 11 00 + 39 01 00 00 00 00 04 B9 FF 83 63 + 39 01 00 00 00 00 0E BA 80 00 10 08 08 10 7E 6E 6D 0A 01 84 43 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 0e 00 02 3A 70 + 39 01 00 00 00 00 0D B1 78 24 04 02 02 03 10 10 34 3C 3F 3F + 39 01 00 00 00 00 0A B4 00 08 6E 07 01 01 62 01 57 + 15 01 00 00 00 00 02 CC 0B + 39 01 00 00 0e 00 1F E0 01 48 4D 4E 58 F6 0B 4E 12 D5 15 95 55 8E 11 01 48 4D 55 5F FD 0A 4E 51 D3 17 95 96 4E 11 + 05 01 00 00 29 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,mdss-dsi-panel-timings = [7d 12 0C 01 34 38 10 16 0E 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x20>; + qcom,mdss-dsi-t-clk-pre = <0x24>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 120>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi new file mode 100755 index 00000000000..839db4d5de5 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi @@ -0,0 +1,144 @@ +/* Copyright (c) 2013, 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + dsi_otm1289a_zzw500ha0_166b_720p_video: qcom,dsi_otm1289a_zzw500ha0_166b_720p_video { + qcom,mdss-dsi-panel-name = "zhongzhengwei otm1289a zzw500ha0-166B 1280x720p video panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <70>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <15>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-pixel-packing = "tight"; + qcom,mdss-dsi-pixel-alignment = <0>; + qcom,mdss-dsi-on-command = [39 01 00 00 00 00 02 00 00 + 39 01 00 00 00 00 04 ff 12 89 01 + 39 01 00 00 00 00 02 00 80 + 39 01 00 00 00 00 03 ff 12 89 + 39 01 00 00 00 00 02 00 90 + 39 01 00 00 00 00 02 ff b0 + 39 01 00 00 00 00 02 00 80 + 39 01 00 00 00 00 09 c0 4a 00 10 10 96 01 68 40 + 39 01 00 00 00 00 02 00 90 + 39 01 00 00 00 00 04 c0 3b 01 09 + 39 01 00 00 00 00 02 00 8c + 39 01 00 00 00 00 02 c0 00 + 39 01 00 00 00 00 02 00 80 + 39 01 00 00 00 00 02 c1 33 + 39 01 00 00 00 00 02 00 85 + 39 01 00 00 00 00 04 c5 0a 0a 46 + 39 01 00 00 00 00 02 00 00 + 39 01 00 00 00 00 03 d8 27 27 + 39 01 00 00 00 00 02 00 01 + 39 01 00 00 00 00 02 d9 77 + 39 01 00 00 00 00 02 00 84 + 39 01 00 00 00 00 02 C4 02 + 39 01 00 00 00 00 02 00 93 + 39 01 00 00 00 00 02 C4 04 + 39 01 00 00 00 00 02 00 96 + 39 01 00 00 00 00 02 F5 E7 + 39 01 00 00 00 00 02 00 A0 + 39 01 00 00 00 00 02 F5 4A + 39 01 00 00 00 00 02 00 8a + 39 01 00 00 00 00 02 c0 11 + 39 01 00 00 00 00 02 00 83 + 39 01 00 00 00 00 02 F5 81 + 39 01 00 00 00 00 02 00 90 + 39 01 00 00 00 00 03 c4 96 05 + 39 01 00 00 00 00 02 00 80 + 39 01 00 00 00 00 10 cb 14 14 14 14 14 00 00 00 00 00 00 00 00 00 00 + 39 01 00 00 00 00 02 00 90 + 39 01 00 00 00 00 08 cb FC FC FC 00 14 14 14 + 39 01 00 00 00 00 02 00 80 + 39 01 00 00 00 00 0F cc 02 0A 0C 0E 10 00 00 00 00 00 00 00 00 00 + 39 01 00 00 00 00 02 00 90 + 39 01 00 00 00 00 10 cc 00 00 00 00 1E 1D 06 01 09 0B 0d 0F 00 00 00 + 39 01 00 00 00 00 02 00 a0 + 39 01 00 00 00 00 0E cc 00 00 00 00 00 00 00 00 00 00 1E 1D 05 + 39 01 00 00 00 00 02 00 b0 + 39 01 00 00 00 00 0F cc 05 0F 0D 0B 09 00 00 00 00 00 00 00 00 00 + 39 01 00 00 00 00 02 00 c0 + 39 01 00 00 00 00 10 cc 00 00 00 00 1D 1E 01 06 10 0E 0C 0A 00 00 00 + 39 01 00 00 00 00 02 00 d0 + 39 01 00 00 00 00 0E cc 00 00 00 00 00 00 00 00 00 00 1D 1E 02 + 39 01 00 00 00 00 02 00 80 + 39 01 00 00 00 00 07 ce 87 03 10 86 00 00 + 39 01 00 00 00 00 02 00 90 + 39 01 00 00 00 00 0A ce 34 ff 10 05 00 00 00 00 00 + 39 01 00 00 00 00 02 00 a0 + 39 01 00 00 00 00 10 ce 30 83 88 00 20 00 82 87 00 81 86 00 80 85 00 + 39 01 00 00 00 00 02 00 b0 + 39 01 00 00 00 00 10 ce 30 00 84 00 20 00 01 83 00 02 82 00 03 81 00 + 39 01 00 00 00 00 02 00 E0 + 39 01 00 00 00 00 09 CE 0A 04 FC 00 00 0A 04 FC + 39 01 00 00 00 00 02 00 F0 + 39 01 00 00 00 00 07 CE 01 20 01 01 00 00 + 39 01 00 00 00 00 02 00 00 + 39 01 00 00 00 00 11 E1 00 16 26 37 47 65 64 7d 76 62 69 50 38 21 13 00 + 39 01 00 00 00 00 02 00 00 + 39 01 00 00 00 00 11 E2 00 16 26 37 47 65 64 7d 76 62 69 50 38 21 13 00 + 39 01 00 00 00 00 02 00 00 + 39 01 00 00 00 00 04 ff ff ff ff + 05 01 00 00 C8 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-v-sync-rd-ptr-irq-line = <0x2c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-timings = [7B 1A 10 00 3E 40 16 1C 15 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x26>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 120>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909-camera-sensor-skua.dtsi b/arch/arm/boot/dts/qcom/msm8909-camera-sensor-skua.dtsi new file mode 100755 index 00000000000..8434c3c93c1 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909-camera-sensor-skua.dtsi @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { +}; + +&i2c_3 { + + actuator0: qcom,actuator@0 { /* added by luosiyuan 2017.05.19 */ + cell-index = <0>; + reg = <0x18>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8909_l8>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-type = <0>; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2900000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x2>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + qcom,actuator-src = <&actuator0>;/*added by luosiyuan 2017.05.19*/ + cam_vana-supply = <&pm8909_l17>; + cam_vio-supply = <&pm8909_l6>; + qcom,cam-vreg-name = "cam_vio", "cam_vana"; + qcom,cam-vreg-min-voltage = <0 2800000>; + qcom,cam-vreg-max-voltage = <0 2850000>; + qcom,cam-vreg-op-mode = <0 80000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&msm_gpio 26 0>, + <&msm_gpio 35 0>, + <&msm_gpio 34 0>, + <&msm_gpio 17 0>, /* added by luosiyuan 2017.05.19 */ + <&msm_gpio 99 0>; /* added by luosiyuan 2017.05.19 */ + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-custom2 = <3>; + qcom,gpio-custom3 = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY", + "CAM_DVDD_1V2", + "CAM_DVAF_2V8"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + cam_vana-supply = <&pm8909_l17>; + cam_vio-supply = <&pm8909_l6>; + qcom,cam-vreg-name = "cam_vio", "cam_vana"; + qcom,cam-vreg-type = <1 0>; + qcom,cam-vreg-min-voltage = <0 2850000>; + qcom,cam-vreg-max-voltage = <0 2850000>; + qcom,cam-vreg-op-mode = <0 80000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>; + gpios = <&msm_gpio 27 0>, + <&msm_gpio 28 0>, + <&msm_gpio 33 0>, + <&msm_gpio 17 0>, /* Add ov5670_8909 DVDD enable by huangfusheng 2017-05-19 */ + <&msm_gpio 99 0>; /* Add ov5670_8909 VAF enable by huangfusheng 2017-05-19 */ + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-custom2 = <3>; /* Add ov5670_8909 DVDD enable by huangfusheng 2017-05-19 */ + qcom,gpio-custom3 = <4>; /* Add ov5670_8909 VAF enable by huangfusheng 2017-05-19 */ + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_STANDBY", + "CAM_DVDD_1V2", /* Add ov5670_8909 DVDD enable by huangfusheng 2017-05-19 */ + "CAM_DVAF_2V8"; /* Add ov5670_8909 VAF enable by huangfusheng 2017-05-19 */ + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk1_clk_src>, + <&clock_gcc clk_gcc_camss_mclk1_clk>; + clock-names = "cam_src_clk", "cam_clk"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi old mode 100644 new mode 100755 index c064cfec9d6..2e968b72912 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -909,12 +909,12 @@ tlmm_gpio_key { gpio_key_active: gpio_key_active { mux { - pins = "gpio90", "gpio91", "gpio92"; + pins = "gpio90", "gpio92", "gpio11"; function = "gpio"; }; config { - pins = "gpio90", "gpio91", "gpio92"; + pins = "gpio90", "gpio92", "gpio11"; drive-strength = <2>; bias-pull-up; }; diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi old mode 100644 new mode 100755 index 6a0554a6de5..f4239d6b52b --- a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi @@ -11,7 +11,11 @@ */ #include "msm8909-qrd.dtsi" - +//#include "msm8909-camera-sensor-skua.dtsi" +#include "dsi-panel-hx8394f-zzw500hah-720p-video.dtsi" +#include "dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi" +//#include "dsi-panel-ortustech-video.dtsi" +#include "dsi-panel-ortustech32-video.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909 QRD SKUA"; compatible = "qcom,msm8909-qrd", "qcom,msm8909", "qcom,qrd"; @@ -19,14 +23,31 @@ &soc { i2c@78b9000 { /* BLSP1 QUP5 */ - focaltech@38 { + status = "ok"; + goodix@5d { + compatible = "goodix,gt1x"; + reg = <0x5d>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2>; + vdd_ana-supply = <&pm8909_l17>; + vcc_i2c-supply = <&pm8909_l6>; + goodix,rst-gpio = <&msm_gpio 12 0x00>; + goodix,irq-gpio = <&msm_gpio 13 0x00>; + pinctrl-names = "pmx_ts_active", + "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + }; +/* focaltech@38 { compatible = "focaltech,5x06"; reg = <0x38>; interrupt-parent = <&msm_gpio>; interrupts = <13 0x2>; vdd-supply = <&pm8909_l17>; vcc_i2c-supply = <&pm8909_l6>; - /* pins used by touchscreen */ + // pins used by touchscreen pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release"; pinctrl-0 = <&ts_int_active &ts_reset_active>; pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; @@ -53,6 +74,7 @@ focaltech,fw-auto-cal; focaltech,ignore-id-check; }; +*/ }; gen-vkeys { @@ -66,14 +88,17 @@ qcom,y-offset = <0>; }; +/* Modified by kuangjincheng @20171119 to optimize audio code */ sound { + status = "ok"; compatible = "qcom,msm8x16-audio-codec"; qcom,model = "msm8909-skua-snd-card"; qcom,msm-snd-card-id = <0>; qcom,msm-codec-type = "internal"; qcom,msm-ext-pa = "primary"; + qcom,msm-spk-ext-pa = <&msm_gpio 17 0x0>; qcom,msm-mclk-freq = <9600000>; - qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-hphl-swh = <0>; qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-hs-micbias-type = "internal"; qcom,msm-micbias1-ext-cap; @@ -125,31 +150,41 @@ }; }; -&tlmm_pinmux { - bma2x2_int1_pin { - qcom,pins = <&gp 96>; - qcom,num-grp-pins = <1>; - label = "bma2x2_int1_pin"; - bma2x2_int1_default: int1_default { - drive-strength = <6>; - bias-pull-up; - }; - }; - - bma2x2_int2_pin { - qcom,pins = <&gp 65>; - qcom,num-grp-pins = <1>; - label = "bma2x2_int2_pin"; - bma2x2_int2_default: int2_default { - drive-strength = <6>; - bias-pull-up; - }; +&i2c_1 { /* BLSP1 QUP1 */ + //light and proximity sensor +/* + liteon@23 { + compatible = "liteon,ltr553"; + reg = <0x23>; + pinctrl-names = "default","sleep"; + pinctrl-0 = <<r553_default>; + pinctrl-1 = <<r553_sleep>; + interrupt-parent = <&msm_gpio>; + interrupts = <94 0x2>; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + liteon,intr = <&msm_gpio 94 0x2>; + liteon,highthr = <800>; + liteon,lowthr = <300>; }; -}; +*/ + akm@c { + compatible = "ak,ak09911"; + reg = <0x0c>; + pinctrl-names = "default","sleep"; + pinctrl-0 = <&akm_default>; + pinctrl-1 = <&akm_sleep>; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + akm,layout = <0x3>; + akm,poll_interval = <200>; + akm,gpio_rstn = <&msm_gpio 65 0x0>; + akm,auto-report; + }; -&i2c_1 { /* BLSP1 QUP1 */ - bosch@18 { /* Accelerometer sensor */ + bosch@18 { //Accelerometer sensor compatible = "bosch,bma2x2"; + status = "disabled"; reg = <0x18>; pinctrl-names = "default"; pinctrl-0 = <&bma2x2_int1_default &bma2x2_int2_default>; @@ -160,8 +195,29 @@ bosch,init-interval = <200>; bosch,place = <2>; bosch,gpio-int1 = <&msm_gpio 96 0x2002>; - bosch,gpio-int2 = <&msm_gpio 65 0x2002>; + bosch,gpio-int2 = <&msm_gpio 31 0x2002>; }; + + bmp@76 { + compatible = "bmp280"; + reg = <0x76>; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + }; + + bosch@68 { /* Accelerometer and gyroscope sensor */ + compatible = "bosch,bmi160"; + //status = "disabled"; + reg = <0x68>; + pinctrl-names = "default"; + pinctrl-0 = <&bmi160_int1_default>; + interrupt-parent = <&msm_gpio>; + interrupts = <95 0x2002>; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + bosch,place = <5>; + bosch,gpio-int1 = <&msm_gpio 95 0x2002>; + }; }; &pm8909_vadc { @@ -208,12 +264,14 @@ }; &sdhc_2 { +/* qcom,nonhotplug; interrupts = <0 1>; interrupt-map = <0 &intc 0 125 0 1 &intc 0 221 0>; interrupt-names = "hc_irq", "pwr_irq"; /delete-property/ cd-gpios; +*/ }; &pm8909_mpps { @@ -251,18 +309,178 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; -&pmx_mdss { - qcom,num-grp-pins = <1>; - qcom,pins = <&gp 25>; +&msm_gpio { + pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio25"; + }; + config { + pins = "gpio25"; + }; + }; + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio25"; + }; + config { + pins = "gpio25"; + }; + }; + }; + pmx_mdss_te { + mdss_te_active: mdss_te_active { + mux { + pins = "gpio24"; + }; + config { + pins = "gpio24"; + }; + }; + mdss_te_suspend: mdss_te_suspend { + mux { + pins = "gpio24"; + }; + config { + pins = "gpio24"; + }; + }; + }; + bma2x2_int1_pin { + bma2x2_int1_default: int1_default { + mux { + pins = "gpio96"; + function = "gpio"; + }; + config { + pins = "gpio96"; + drive-dtrength = <6>; + bias-pull-up; + }; + }; + }; + bma2x2_int2_pin { + bma2x2_int2_default: int2_default { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-dtrength = <6>; + bias-pull-up; + }; + }; + }; + + bmi160_int1_pin { + bmi160_int1_default: int1_default { + mux { + pins = "gpio95"; + function = "gpio"; + }; + config { + pins = "gpio95"; + drive-dtrength = <6>; + bias-pull-up; + }; + }; + }; + + ltr553_int_pin { + ltr553_default: ltr553_default { + mux { + pins = "gpio94"; + function = "gpio"; + }; + config { + pins = "gpio94"; + drive-dtrength = <6>; + bias-pull-up; + }; + }; + ltr553_sleep: ltr553_sleep { + mux { + pins = "gpio94"; + function = "gpio"; + }; + config { + pins = "gpio94"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + akm_reset_pin { + akm_default: akm_default { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-dtrength = <6>; + bias-pull-up; + }; + }; + akm_sleep: akm_sleep { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + }; -&pmx_mdss_te { - qcom,num-grp-pins = <1>; - qcom,pins = <&gp 24>; +&dsi_otm1289a_zzw500ha0_166b_720p_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <1000>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8909_mpps 2 0>; + qcom,cont-splash-enabled; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_hx8394f_zzw500hah_720p_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <1000>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8909_mpps 2 0>; + qcom,cont-splash-enabled; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +/*&dsi_ortustech_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <1000>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8909_mpps 2 0>; + qcom,cont-splash-enabled; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +};*/ + + +&dsi_ortustech32_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <1000>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8909_mpps 2 0>; + qcom,cont-splash-enabled; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + + &mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_hx8379a_fwvga_skua_vid>; + //qcom,dsi-pref-prim-pan = <&dsi_hx8379a_fwvga_skua_vid>; + //qcom,dsi-pref-prim-pan = <&dsi_ortustech_video>; + qcom,dsi-pref-prim-pan = <&dsi_ortustech32_video>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi old mode 100644 new mode 100755 index 5ee6d9ca315..d0c00183fa0 --- a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi @@ -21,11 +21,19 @@ compatible = "qcom,msm8909-qrd", "qcom,msm8909", "qcom,qrd"; }; +&pm8909_vib { + status = "okay"; +}; &blsp1_uart1 { status = "ok"; pinctrl-names = "default"; pinctrl-0 = <&uart_console_sleep>; }; +//&blsp1_uart2 { +// status = "ok"; +// pinctrl-names = "default"; +// pinctrl-0 = <&hsuart_active>; +//}; &qcom_rng { status = "okay"; @@ -59,10 +67,25 @@ label = "volume_up"; gpios = <&msm_gpio 90 0x1>; linux,input-type = <1>; - linux,code = <115>; + linux,code = <0x19c>;/* KEY_PREVIOUS <115>;*/ + gpio-key,wakeup; + debounce-interval = <15>; + }; + vol_down { + label = "volume_down"; + gpios = <&msm_gpio 11 0x1>; + linux,input-type = <1>; + linux,code = <0x197>;/* KEY_NEXT <114>;*/ gpio-key,wakeup; debounce-interval = <15>; }; + + home_key { + label = "home_key"; + gpios = <&msm_gpio 98 0x1>; + linux,input-type = <1>; + linux,code = <28>; /* KEY_ENTER <102>*/ + }; }; }; @@ -120,6 +143,7 @@ status = "okay"; qcom,vib-timeout-ms = <15000>; qcom,vib-vtg-level-mV = <3100>; + vib-gpios = <&msm_gpio 16 0x1>; }; }; }; @@ -146,8 +170,14 @@ &qdsd_data3_jtag>; pinctrl-5 = <&qdsd_clk_spmi &qdsd_cmd_spmi &qdsd_data0_spmi &qdsd_data3_spmi>; + status = "disabled"; }; &android_usb { qcom,android-usb-cdrom; }; + +&spi_0 { + status = "disabled"; +}; + diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig old mode 100644 new mode 100755 index 22e84cb1df4..b778f15ca42 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -306,6 +306,7 @@ CONFIG_SENSORS_AKM8963=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m CONFIG_SENSORS_LTR553=y +# CONFIG_SENSORS_AKM09911=y CONFIG_SENSORS_BMA2X2=y # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set @@ -532,3 +533,15 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_FUSE_FS=y CONFIG_CMA_SIZE_MBYTES=8 +# add by liangdi +CONFIG_TOUCHSCREEN_GT1XX=y +CONFIG_SENSORS_AKM09911=y +# add by liangdi 20190821 +CONFIG_SENSORS_BMI160=y +#CONFIG_BMI160_MAG_INTERFACE_SUPPORT=y +CONFIG_SENSORS_BMI160_I2C=y +CONFIG_SENSORS_BMI160_ENABLE_INT1=y +# CONFIG_SENSORS_BMI160_ENABLE_INT2=y +CONFIG_SENSORS_BMP280=y +CONFIG_SENSORS_BMP280_I2C=y + diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig old mode 100644 new mode 100755 index 63c888e32a1..f2f16d7ab43 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -307,7 +307,7 @@ CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y CONFIG_INPUT_MISC=y CONFIG_SENSORS_MPU6050=y -CONFIG_SENSORS_AKM8963=y +# CONFIG_SENSORS_AKM8963=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m CONFIG_SENSORS_LTR553=y @@ -598,3 +598,15 @@ CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_QMI_ENCDEC=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y +# add by liangdi +CONFIG_TOUCHSCREEN_GT1XX=y +CONFIG_SENSORS_AKM09911=y +# add by liangdi 20190821 +CONFIG_SENSORS_BMI160=y +#CONFIG_BMI160_MAG_INTERFACE_SUPPORT=y +CONFIG_SENSORS_BMI160_I2C=y +CONFIG_SENSORS_BMI160_ENABLE_INT1=y +# CONFIG_SENSORS_BMI160_ENABLE_INT2=y +CONFIG_SENSORS_BMP280=y +CONFIG_SENSORS_BMP280_I2C=y + diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig old mode 100644 new mode 100755 index 7c02e682aa3..0897a5c101d --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -854,4 +854,55 @@ config DOUBLE_TAP help If you say yes here, you get support Bosch double tap sensor function +config SENSORS_BMI160 + tristate "BMI160 Sensor Support" + depends on I2C || SPI_MASTER + help + If you say yes here, you get support for Bosch Sensortec's + sensor driver of BMI160. + +config SENSORS_BMI160_I2C + tristate "support I2C bus communication" + depends on SENSORS_BMI160 && I2C + help + If you say yes here, you get support Bosch Sensortec's BMI160 sensor hooked to an I2C bus. + +config BMI160_MAG_INTERFACE_SUPPORT + tristate "BMI160 Sensor mag interface support" + depends on SENSORS_BMI160 + help + If you say yes here, you get support for Bosch Sensortec's + sensor driver of BMI160 with mag sensor support. + +config SENSORS_BMI160_ENABLE_INT1 + tristate "BMI160 sensor interrupt INT1 support" + depends on SENSORS_BMI160 + help + If you say yes here, you get INT1 support for Bosch Sensortec + sensors BMI160. + +config SENSORS_BMI160_ENABLE_INT2 + tristate "BMI160 sensor interrupt INT2 support" + depends on SENSORS_BMI160 + help + If you say yes here, you get INT2 support for Bosch Sensortec + sensors BMI160. + +config SENSORS_BMP280 + tristate "BMP280 digital Pressure Sensor" + depends on (I2C || SPI_MASTER) && SYSFS + help + If you say yes here, you get support for Bosch Sensortec's BMP280 digital pressure sensors. + +config SENSORS_BMP280_I2C + tristate "support I2C bus communication" + depends on SENSORS_BMP280 && I2C + help + If you say yes here, you get support Bosch Sensortec's BMP280 pressure sensor hooked to an I2C bus. + +config SENSORS_BMP280_SPI + tristate "support SPI bus communication" + depends on SENSORS_BMP280 && SPI_MASTER + help + If you say yes here, you get support Bosch Sensortec's BMP280 pressure sensor hooked to an SPI bus. endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile old mode 100644 new mode 100755 index e1bb7cc45b7..5355259fc5e --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -73,7 +73,7 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_SENSORS_MMC3416X) += mmc3416x.o -obj-$(CONFIG_SENSORS_AKM09911) += akm09911.o +obj-$(CONFIG_SENSORS_AKM09911) += akm09911m.o obj-$(CONFIG_SENSORS_AP3426) += ap3426.o obj-$(CONFIG_SENSORS_BMA2X2) += bstclass.o @@ -89,3 +89,28 @@ ifeq ($(CONFIG_BOSCH_BMA2X2_ENABLE_INT2),y) endif obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH) += ots_pat9125/ + +obj-$(CONFIG_SENSORS_BMI160) += bmi160_driver.o bmi160.o +ifeq ($(CONFIG_BMI160_MAG_INTERFACE_SUPPORT),y) + EXTRA_CFLAGS += -DBMI160_MAG_INTERFACE_SUPPORT +endif +ifeq ($(CONFIG_SENSORS_BMI160_ENABLE_INT1),y) + EXTRA_CFLAGS += -DBMI160_ENABLE_INT1 +endif + +ifeq ($(CONFIG_SENSORS_BMI160_ENABLE_INT2),y) + EXTRA_CFLAGS += -DBMI160_ENABLE_INT2 +endif + +obj-$(CONFIG_SENSORS_BMI160_I2C) += bmi160_i2c.o +ifeq ($(CONFIG_SENSORS_BMI160_I2C),y) + EXTRA_CFLAGS += -DBMI_USE_BASIC_I2C_FUNC + +obj-$(CONFIG_SENSORS_BMP280) += bmp280_core.o bmp280.o +obj-$(CONFIG_SENSORS_BMP280_I2C) += bmp280_i2c.o +obj-$(CONFIG_SENSORS_BMP280_SPI) += bmp280_spi.o +ifeq ($(CONFIG_SENSORS_BMP280_I2C),y) + EXTRA_CFLAGS += -DBMP_USE_BASIC_I2C_FUNC +endif +endif + diff --git a/drivers/input/misc/akm09911.c b/drivers/input/misc/akm09911.c old mode 100644 new mode 100755 index 6a2c8d0bd07..73a386e70e0 --- a/drivers/input/misc/akm09911.c +++ b/drivers/input/misc/akm09911.c @@ -2370,7 +2370,7 @@ static struct i2c_driver akm_compass_driver = { static int __init akm_compass_init(void) { - pr_info("AKM compass driver: initialize."); + pr_info("AKM compass driver: initialize.22"); return i2c_add_driver(&akm_compass_driver); } diff --git a/drivers/input/misc/akm09911m.c b/drivers/input/misc/akm09911m.c new file mode 100755 index 00000000000..87c3bbc5e46 --- /dev/null +++ b/drivers/input/misc/akm09911m.c @@ -0,0 +1,2661 @@ +/* drivers/misc/akm09911.c - akm09911 compass driver + * + * Copyright (c) 2014-2015, Linux Foundation. All rights reserved. + * Copyright (C) 2007-2014 HTC Corporation. + * Author: Hou-Kun Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +/*#define DEBUG*/ +/*#define VERBOSE_DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AKM_DEBUG_IF 1 +#define AKM_HAS_RESET 1 +#define AKM_INPUT_DEVICE_NAME "compass" +#define AKM_DRDY_TIMEOUT_MS 100 +#define AKM_BASE_NUM 10 + +#define AKM_IS_MAG_DATA_ENABLED() (akm->enable_flag & (1 << MAG_DATA_FLAG)) + +/* POWER SUPPLY VOLTAGE RANGE */ +#define AKM09911_VDD_MIN_UV 2000000 +#define AKM09911_VDD_MAX_UV 3300000 +#define AKM09911_VIO_MIN_UV 1750000 +#define AKM09911_VIO_MAX_UV 1950000 + +#define STATUS_ERROR(st) (((st)&0x08) != 0x0) + +#define AKM09911_RETRY_COUNT 10 + +enum { + AKM09911_AXIS_X = 0, + AKM09911_AXIS_Y, + AKM09911_AXIS_Z, + AKM09911_AXIS_COUNT, +}; + +/* Save last device state for power down */ +struct akm_sensor_state { + bool power_on; + uint8_t mode; +}; + +struct akm_compass_data { + struct i2c_client *i2c; + struct input_dev *input; + struct device *class_dev; + struct class *compass; + struct pinctrl *pinctrl; + struct pinctrl_state *pin_default; + struct pinctrl_state *pin_sleep; + struct sensors_classdev cdev; + struct delayed_work dwork; + struct workqueue_struct *work_queue; + struct mutex op_mutex; + + wait_queue_head_t drdy_wq; + wait_queue_head_t open_wq; + + /* These two buffers are initialized at start up. + After that, the value is not changed */ + uint8_t sense_info[AKM_SENSOR_INFO_SIZE]; + uint8_t sense_conf[AKM_SENSOR_CONF_SIZE]; + + struct mutex sensor_mutex; + uint8_t sense_data[AKM_SENSOR_DATA_SIZE]; + struct mutex accel_mutex; + int16_t accel_data[3]; + + /* Positive value means the device is working. + 0 or negative value means the device is not woking, + i.e. in power-down mode. */ + int8_t is_busy; + + struct mutex val_mutex; + uint32_t enable_flag; + int64_t delay[AKM_NUM_SENSORS]; + + atomic_t active; + atomic_t drdy; + + char layout; + int irq; + int gpio_rstn; + int power_enabled; + int auto_report; + int use_hrtimer; + + /* The input event last time */ + int last_x; + int last_y; + int last_z; + + struct regulator *vdd; + struct regulator *vio; + struct akm_sensor_state state; + struct hrtimer poll_timer; +}; + +static struct sensors_classdev sensors_cdev = { + .name = "akm09911-mag", + .vendor = "Asahi Kasei Microdevices Corporation", + .version = 1, + .handle = SENSORS_MAGNETIC_FIELD_HANDLE, + .type = SENSOR_TYPE_MAGNETIC_FIELD, + .max_range = "1228.8", + .resolution = "0.6", + .sensor_power = "0.35", + .min_delay = 200, + .max_delay = 10000, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 0, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; + +static struct akm_compass_data *s_akm; + +static int akm_compass_power_set(struct akm_compass_data *data, bool on); +/***** I2C I/O function ***********************************************/ +static int akm_i2c_rxdata( + struct i2c_client *i2c, + uint8_t *rxData, + int length) +{ + int ret; + + struct i2c_msg msgs[] = { + { + .addr = i2c->addr, + .flags = 0, + .len = 1, + .buf = rxData, + }, + { + .addr = i2c->addr, + .flags = I2C_M_RD, + .len = length, + .buf = rxData, + }, + }; + uint8_t addr = rxData[0]; + + ret = i2c_transfer(i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) { + dev_err(&i2c->dev, "%s: transfer failed.", __func__); + return ret; + } else if (ret != ARRAY_SIZE(msgs)) { + dev_err(&i2c->dev, "%s: transfer failed(size error).\n", + __func__); + return -ENXIO; + } + + dev_vdbg(&i2c->dev, "RxData: len=%02x, addr=%02x, data=%02x", + length, addr, rxData[0]); + + return 0; +} + +static int akm_i2c_txdata( + struct i2c_client *i2c, + uint8_t *txData, + int length) +{ + int ret; + + struct i2c_msg msg[] = { + { + .addr = i2c->addr, + .flags = 0, + .len = length, + .buf = txData, + }, + }; + + ret = i2c_transfer(i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + dev_err(&i2c->dev, "%s: transfer failed.", __func__); + return ret; + } else if (ret != ARRAY_SIZE(msg)) { + dev_err(&i2c->dev, "%s: transfer failed(size error).", + __func__); + return -ENXIO; + } + + dev_vdbg(&i2c->dev, "TxData: len=%02x, addr=%02x data=%02x", + length, txData[0], txData[1]); + + return 0; +} + +/***** akm miscdevice functions *************************************/ +static int AKECS_Set_CNTL( + struct akm_compass_data *akm, + uint8_t mode) +{ + uint8_t buffer[2]; + int err; + + /***** lock *****/ + mutex_lock(&akm->sensor_mutex); + /* Busy check */ + if (akm->is_busy > 0) { + dev_err(&akm->i2c->dev, + "%s: device is busy.", __func__); + err = -EBUSY; + } else { + /* Set measure mode */ + buffer[0] = AKM_REG_MODE; + buffer[1] = mode; + err = akm_i2c_txdata(akm->i2c, buffer, 2); + if (err < 0) { + dev_err(&akm->i2c->dev, + "%s: Can not set CNTL.", __func__); + } else { + dev_vdbg(&akm->i2c->dev, + "Mode is set to (%d).", mode); + /* Set flag */ + akm->is_busy = 1; + atomic_set(&akm->drdy, 0); + /* wait at least 100us after changing mode */ + udelay(100); + } + } + + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + + return err; +} + +static int AKECS_Set_PowerDown( + struct akm_compass_data *akm) +{ + uint8_t buffer[2]; + int err; + + /***** lock *****/ + mutex_lock(&akm->sensor_mutex); + + /* Set powerdown mode */ + buffer[0] = AKM_REG_MODE; + buffer[1] = AKM_MODE_POWERDOWN; + err = akm_i2c_txdata(akm->i2c, buffer, 2); + if (err < 0) { + dev_err(&akm->i2c->dev, + "%s: Can not set to powerdown mode.", __func__); + } else { + dev_dbg(&akm->i2c->dev, "Powerdown mode is set."); + /* wait at least 100us after changing mode */ + udelay(100); + } + /* Clear status */ + akm->is_busy = 0; + atomic_set(&akm->drdy, 0); + + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + + return err; +} + +static int AKECS_Reset( + struct akm_compass_data *akm, + int hard) +{ + int err; + +#if AKM_HAS_RESET + uint8_t buffer[2]; + + /***** lock *****/ + mutex_lock(&akm->sensor_mutex); + + if (hard != 0) { + gpio_set_value(akm->gpio_rstn, 0); + gpio_direction_output(akm->gpio_rstn, 0); + udelay(5); + gpio_set_value(akm->gpio_rstn, 1); + gpio_direction_output(akm->gpio_rstn, 1); + /* No error is returned */ + err = 0; + } else { + buffer[0] = AKM_REG_RESET; + buffer[1] = AKM_RESET_DATA; + err = akm_i2c_txdata(akm->i2c, buffer, 2); + if (err < 0) { + dev_err(&akm->i2c->dev, + "%s: Can not set SRST bit.", __func__); + } else { + dev_dbg(&akm->i2c->dev, "Soft reset is done."); + } + } + /* Device will be accessible 100 us after */ + udelay(100); + /* Clear status */ + akm->is_busy = 0; + atomic_set(&akm->drdy, 0); + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + +#else + err = AKECS_Set_PowerDown(akm); +#endif + + return err; +} + +static int AKECS_SetMode( + struct akm_compass_data *akm, + uint8_t mode) +{ + int err; + + switch (mode & 0x1F) { + case AKM_MODE_SNG_MEASURE: + case AKM_MODE_SELF_TEST: + case AKM_MODE_FUSE_ACCESS: + case AKM_MODE_CONTINUOUS_10HZ: + case AKM_MODE_CONTINUOUS_20HZ: + case AKM_MODE_CONTINUOUS_50HZ: + case AKM_MODE_CONTINUOUS_100HZ: + err = AKECS_Set_CNTL(akm, mode); + break; + case AKM_MODE_POWERDOWN: + err = AKECS_Set_PowerDown(akm); + break; + default: + dev_err(&akm->i2c->dev, + "%s: Unknown mode(%d).", __func__, mode); + return -EINVAL; + } + + return err; +} + +static void AKECS_SetYPR( + struct akm_compass_data *akm, + int *rbuf) +{ + uint32_t ready; + dev_vdbg(&akm->i2c->dev, "%s: flag =0x%X", __func__, rbuf[0]); + dev_vdbg(&akm->input->dev, " Acc [LSB] : %6d,%6d,%6d stat=%d", + rbuf[1], rbuf[2], rbuf[3], rbuf[4]); + dev_vdbg(&akm->input->dev, " Geo [LSB] : %6d,%6d,%6d stat=%d", + rbuf[5], rbuf[6], rbuf[7], rbuf[8]); + dev_vdbg(&akm->input->dev, " Orientation : %6d,%6d,%6d", + rbuf[9], rbuf[10], rbuf[11]); + dev_vdbg(&akm->input->dev, " Rotation V : %6d,%6d,%6d,%6d", + rbuf[12], rbuf[13], rbuf[14], rbuf[15]); + + /* No events are reported */ + if (!rbuf[0]) { + dev_dbg(&akm->i2c->dev, "Don't waste a time."); + return; + } + + mutex_lock(&akm->val_mutex); + ready = (akm->enable_flag & (uint32_t)rbuf[0]); + mutex_unlock(&akm->val_mutex); + + /* Report acceleration sensor information */ + if (ready & ACC_DATA_READY) { + input_report_abs(akm->input, ABS_X, rbuf[1]); + input_report_abs(akm->input, ABS_Y, rbuf[2]); + input_report_abs(akm->input, ABS_Z, rbuf[3]); + input_report_abs(akm->input, ABS_RX, rbuf[4]); + } + /* Report magnetic vector information */ + if (ready & MAG_DATA_READY) { + input_report_abs(akm->input, ABS_X, rbuf[5]); + input_report_abs(akm->input, ABS_Y, rbuf[6]); + input_report_abs(akm->input, ABS_Z, rbuf[7]); + input_report_abs(akm->input, ABS_MISC, rbuf[8]); + } + /* Report fusion sensor information */ + if (ready & FUSION_DATA_READY) { + /* Orientation */ + input_report_abs(akm->input, ABS_HAT0Y, rbuf[9]); + input_report_abs(akm->input, ABS_HAT1X, rbuf[10]); + input_report_abs(akm->input, ABS_HAT1Y, rbuf[11]); + /* Rotation Vector */ + input_report_abs(akm->input, ABS_TILT_X, rbuf[12]); + input_report_abs(akm->input, ABS_TILT_Y, rbuf[13]); + input_report_abs(akm->input, ABS_TOOL_WIDTH, rbuf[14]); + input_report_abs(akm->input, ABS_VOLUME, rbuf[15]); + } + + input_sync(akm->input); +} + +/* This function will block a process until the latest measurement + * data is available. + */ +static int AKECS_GetData( + struct akm_compass_data *akm, + uint8_t *rbuf, + int size) +{ + int err; + + /* Block! */ + err = wait_event_interruptible_timeout( + akm->drdy_wq, + atomic_read(&akm->drdy), + msecs_to_jiffies(AKM_DRDY_TIMEOUT_MS)); + + if (err < 0) { + dev_err(&akm->i2c->dev, + "%s: wait_event failed (%d).", __func__, err); + return err; + } + if (!atomic_read(&akm->drdy)) { + dev_err(&akm->i2c->dev, + "%s: DRDY is not set.", __func__); + return -ENODATA; + } + + /***** lock *****/ + mutex_lock(&akm->sensor_mutex); + + memcpy(rbuf, akm->sense_data, size); + atomic_set(&akm->drdy, 0); + + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + + return 0; +} + +static int AKECS_GetData_Poll( + struct akm_compass_data *akm, + uint8_t *rbuf, + int size) +{ + uint8_t buffer[AKM_SENSOR_DATA_SIZE]; + int err; + + /* Read data */ + buffer[0] = AKM_REG_STATUS; + err = akm_i2c_rxdata(akm->i2c, buffer, AKM_SENSOR_DATA_SIZE); + if (err < 0) { + dev_err(&akm->i2c->dev, "%s failed.", __func__); + return err; + } + + /* Check ST bit */ + if (!(AKM_DRDY_IS_HIGH(buffer[0]))) + dev_dbg(&akm->i2c->dev, "DRDY is low. Use last value.\n"); + + /* Data is over run is */ + if (AKM_DOR_IS_HIGH(buffer[0])) + dev_dbg(&akm->i2c->dev, "Data over run!\n"); + + memcpy(rbuf, buffer, size); + atomic_set(&akm->drdy, 0); + + /***** lock *****/ + mutex_lock(&akm->sensor_mutex); + akm->is_busy = 0; + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + + return 0; +} + +static int AKECS_GetOpenStatus( + struct akm_compass_data *akm) +{ + return wait_event_interruptible( + akm->open_wq, (atomic_read(&akm->active) > 0)); +} + +static int AKECS_GetCloseStatus( + struct akm_compass_data *akm) +{ + return wait_event_interruptible( + akm->open_wq, (atomic_read(&akm->active) <= 0)); +} + +static int AKECS_Open(struct inode *inode, struct file *file) +{ + file->private_data = s_akm; + return nonseekable_open(inode, file); +} + +static int AKECS_Release(struct inode *inode, struct file *file) +{ + return 0; +} + +static long +AKECS_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct akm_compass_data *akm = file->private_data; + + /* NOTE: In this function the size of "char" should be 1-byte. */ + uint8_t i2c_buf[AKM_RWBUF_SIZE]; /* for READ/WRITE */ + uint8_t dat_buf[AKM_SENSOR_DATA_SIZE];/* for GET_DATA */ + int32_t ypr_buf[AKM_YPR_DATA_SIZE]; /* for SET_YPR */ + int64_t delay[AKM_NUM_SENSORS]; /* for GET_DELAY */ + int16_t acc_buf[3]; /* for GET_ACCEL */ + uint8_t mode; /* for SET_MODE*/ + int status; /* for OPEN/CLOSE_STATUS */ + int ret = 0; /* Return value. */ + + switch (cmd) { + case ECS_IOCTL_READ: + case ECS_IOCTL_WRITE: + if (argp == NULL) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + if (copy_from_user(&i2c_buf, argp, sizeof(i2c_buf))) { + dev_err(&akm->i2c->dev, "copy_from_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_SET_MODE: + if (argp == NULL) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + if (copy_from_user(&mode, argp, sizeof(mode))) { + dev_err(&akm->i2c->dev, "copy_from_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_SET_YPR: + if (argp == NULL) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + if (copy_from_user(&ypr_buf, argp, sizeof(ypr_buf))) { + dev_err(&akm->i2c->dev, "copy_from_user failed."); + return -EFAULT; + } + case ECS_IOCTL_GET_INFO: + case ECS_IOCTL_GET_CONF: + case ECS_IOCTL_GET_DATA: + case ECS_IOCTL_GET_OPEN_STATUS: + case ECS_IOCTL_GET_CLOSE_STATUS: + case ECS_IOCTL_GET_DELAY: + case ECS_IOCTL_GET_LAYOUT: + case ECS_IOCTL_GET_ACCEL: + /* Check buffer pointer for writing a data later. */ + if (argp == NULL) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + break; + default: + break; + } + + switch (cmd) { + case ECS_IOCTL_READ: + dev_vdbg(&akm->i2c->dev, "IOCTL_READ called."); + if ((i2c_buf[0] < 1) || (i2c_buf[0] > (AKM_RWBUF_SIZE-1))) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + ret = akm_i2c_rxdata(akm->i2c, &i2c_buf[1], i2c_buf[0]); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_WRITE: + dev_vdbg(&akm->i2c->dev, "IOCTL_WRITE called."); + if ((i2c_buf[0] < 2) || (i2c_buf[0] > (AKM_RWBUF_SIZE-1))) { + dev_err(&akm->i2c->dev, "invalid argument."); + return -EINVAL; + } + ret = akm_i2c_txdata(akm->i2c, &i2c_buf[1], i2c_buf[0]); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_RESET: + dev_vdbg(&akm->i2c->dev, "IOCTL_RESET called."); + ret = AKECS_Reset(akm, akm->gpio_rstn); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_SET_MODE: + dev_vdbg(&akm->i2c->dev, "IOCTL_SET_MODE called."); + ret = AKECS_SetMode(akm, mode); + if (ret < 0) + return ret; + break; + case ECS_IOCTL_SET_YPR: + dev_vdbg(&akm->i2c->dev, "IOCTL_SET_YPR called."); + AKECS_SetYPR(akm, ypr_buf); + break; + case ECS_IOCTL_GET_DATA: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_DATA called."); + if (akm->irq) + ret = AKECS_GetData(akm, dat_buf, AKM_SENSOR_DATA_SIZE); + else + ret = AKECS_GetData_Poll( + akm, dat_buf, AKM_SENSOR_DATA_SIZE); + + if (ret < 0) + return ret; + break; + case ECS_IOCTL_GET_OPEN_STATUS: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_OPEN_STATUS called."); + ret = AKECS_GetOpenStatus(akm); + if (ret < 0) { + dev_err(&akm->i2c->dev, + "Get Open returns error (%d).", ret); + return ret; + } + break; + case ECS_IOCTL_GET_CLOSE_STATUS: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_CLOSE_STATUS called."); + ret = AKECS_GetCloseStatus(akm); + if (ret < 0) { + dev_err(&akm->i2c->dev, + "Get Close returns error (%d).", ret); + return ret; + } + break; + case ECS_IOCTL_GET_DELAY: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_DELAY called."); + mutex_lock(&akm->val_mutex); + delay[0] = ((akm->enable_flag & ACC_DATA_READY) ? + akm->delay[0] : -1); + delay[1] = ((akm->enable_flag & MAG_DATA_READY) ? + akm->delay[1] : -1); + delay[2] = ((akm->enable_flag & FUSION_DATA_READY) ? + akm->delay[2] : -1); + mutex_unlock(&akm->val_mutex); + break; + case ECS_IOCTL_GET_INFO: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_INFO called."); + break; + case ECS_IOCTL_GET_CONF: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_CONF called."); + break; + case ECS_IOCTL_GET_LAYOUT: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_LAYOUT called."); + break; + case ECS_IOCTL_GET_ACCEL: + dev_vdbg(&akm->i2c->dev, "IOCTL_GET_ACCEL called."); + mutex_lock(&akm->accel_mutex); + acc_buf[0] = akm->accel_data[0]; + acc_buf[1] = akm->accel_data[1]; + acc_buf[2] = akm->accel_data[2]; + mutex_unlock(&akm->accel_mutex); + break; + default: + return -ENOTTY; + } + + switch (cmd) { + case ECS_IOCTL_READ: + /* +1 is for the first byte */ + if (copy_to_user(argp, &i2c_buf, i2c_buf[0]+1)) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_INFO: + if (copy_to_user(argp, &akm->sense_info, + sizeof(akm->sense_info))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_CONF: + if (copy_to_user(argp, &akm->sense_conf, + sizeof(akm->sense_conf))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_DATA: + if (copy_to_user(argp, &dat_buf, sizeof(dat_buf))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_OPEN_STATUS: + case ECS_IOCTL_GET_CLOSE_STATUS: + status = atomic_read(&akm->active); + if (copy_to_user(argp, &status, sizeof(status))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_DELAY: + if (copy_to_user(argp, &delay, sizeof(delay))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_LAYOUT: + if (copy_to_user(argp, &akm->layout, sizeof(akm->layout))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + case ECS_IOCTL_GET_ACCEL: + if (copy_to_user(argp, &acc_buf, sizeof(acc_buf))) { + dev_err(&akm->i2c->dev, "copy_to_user failed."); + return -EFAULT; + } + break; + default: + break; + } + + return 0; +} + +static const struct file_operations AKECS_fops = { + .owner = THIS_MODULE, + .open = AKECS_Open, + .release = AKECS_Release, + .unlocked_ioctl = AKECS_ioctl, +}; + +static struct miscdevice akm_compass_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = AKM_MISCDEV_NAME, + .fops = &AKECS_fops, +}; + +/***** akm sysfs functions ******************************************/ +static int create_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + int err = 0; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (err) + break; + } + + if (err) { + for (--i; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_device_binary_attributes( + struct kobject *kobj, + struct bin_attribute *attrs) +{ + int i; + int err = 0; + + err = 0; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = sysfs_create_bin_file(kobj, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (--i; i >= 0 ; --i) + sysfs_remove_bin_file(kobj, &attrs[i]); + } + + return err; +} + +static void remove_device_binary_attributes( + struct kobject *kobj, + struct bin_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + sysfs_remove_bin_file(kobj, &attrs[i]); +} + +/********************************************************************* + * + * SysFS attribute functions + * + * directory : /sys/class/compass/akmXXXX/ + * files : + * - enable_acc [rw] [t] : enable flag for accelerometer + * - enable_mag [rw] [t] : enable flag for magnetometer + * - enable_fusion [rw] [t] : enable flag for fusion sensor + * - delay_acc [rw] [t] : delay in nanosecond for accelerometer + * - delay_mag [rw] [t] : delay in nanosecond for magnetometer + * - delay_fusion [rw] [t] : delay in nanosecond for fusion sensor + * + * debug : + * - mode [w] [t] : E-Compass mode + * - bdata [r] [t] : buffered raw data + * - asa [r] [t] : FUSEROM data + * - regs [r] [t] : read all registers + * + * [b] = binary format + * [t] = text format + */ + +/***** sysfs enable *************************************************/ +static void akm_compass_sysfs_update_status( + struct akm_compass_data *akm) +{ + uint32_t en; + mutex_lock(&akm->val_mutex); + en = akm->enable_flag; + mutex_unlock(&akm->val_mutex); + + if (en == 0) { + if (atomic_cmpxchg(&akm->active, 1, 0) == 1) { + wake_up(&akm->open_wq); + dev_dbg(akm->class_dev, "Deactivated"); + } + } else { + if (atomic_cmpxchg(&akm->active, 0, 1) == 0) { + wake_up(&akm->open_wq); + dev_dbg(akm->class_dev, "Activated"); + } + } + dev_dbg(&akm->i2c->dev, + "Status updated: enable=0x%X, active=%d", + en, atomic_read(&akm->active)); +} + +static inline uint8_t akm_select_frequency(int64_t delay_ns) +{ + if (delay_ns >= 100000000LL) + return AKM_MODE_CONTINUOUS_10HZ; + else if (delay_ns >= 50000000LL) + return AKM_MODE_CONTINUOUS_20HZ; + else if (delay_ns >= 20000000LL) + return AKM_MODE_CONTINUOUS_50HZ; + else + return AKM_MODE_CONTINUOUS_100HZ; +} + +static int akm_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + int ret = 0; + struct akm_compass_data *akm = container_of(sensors_cdev, + struct akm_compass_data, cdev); + uint8_t mode; + + mutex_lock(&akm->val_mutex); + akm->enable_flag &= ~(1<enable_flag |= ((uint32_t)(enable))<val_mutex); + + akm_compass_sysfs_update_status(akm); + mutex_lock(&akm->op_mutex); + if (enable) { + ret = akm_compass_power_set(akm, true); + if (ret) { + dev_err(&akm->i2c->dev, + "Fail to power on the device!\n"); + goto exit; + } + + if (akm->auto_report) { + mode = akm_select_frequency(akm->delay[MAG_DATA_FLAG]); + AKECS_SetMode(akm, mode); + if (akm->use_hrtimer) + hrtimer_start(&akm->poll_timer, + ns_to_ktime(akm->delay[MAG_DATA_FLAG]), + HRTIMER_MODE_REL); + else + queue_delayed_work(akm->work_queue, &akm->dwork, + (unsigned long)nsecs_to_jiffies64( + akm->delay[MAG_DATA_FLAG])); + } + } else { + if (akm->auto_report) { + if (akm->use_hrtimer) { + hrtimer_cancel(&akm->poll_timer); + cancel_work_sync(&akm->dwork.work); + } else { + cancel_delayed_work_sync(&akm->dwork); + } + AKECS_SetMode(akm, AKM_MODE_POWERDOWN); + } + ret = akm_compass_power_set(akm, false); + if (ret) { + dev_err(&akm->i2c->dev, + "Fail to power off the device!\n"); + goto exit; + } + } + +exit: + mutex_unlock(&akm->op_mutex); + return ret; +} + +static ssize_t akm_compass_sysfs_enable_show( + struct akm_compass_data *akm, char *buf, int pos) +{ + int flag; + + mutex_lock(&akm->val_mutex); + flag = ((akm->enable_flag >> pos) & 1); + mutex_unlock(&akm->val_mutex); + + return scnprintf(buf, PAGE_SIZE, "%d\n", flag); +} + +static ssize_t akm_compass_sysfs_enable_store( + struct akm_compass_data *akm, char const *buf, size_t count, int pos) +{ + long en = 0; + int ret = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (kstrtol(buf, AKM_BASE_NUM, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + mutex_lock(&akm->op_mutex); + ret = akm_compass_power_set(akm, en); + if (ret) { + dev_err(&akm->i2c->dev, + "Fail to configure device power!\n"); + goto exit; + } + mutex_lock(&akm->val_mutex); + akm->enable_flag &= ~(1<enable_flag |= ((uint32_t)(en))<val_mutex); + + akm_compass_sysfs_update_status(akm); + +exit: + mutex_unlock(&akm->op_mutex); + + return ret ? ret : count; +} + +/***** Acceleration ***/ +static ssize_t akm_enable_acc_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm_compass_sysfs_enable_show( + dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} +static ssize_t akm_enable_acc_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm_compass_sysfs_enable_store( + dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/***** Magnetic field ***/ +static ssize_t akm_enable_mag_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm_compass_sysfs_enable_show( + dev_get_drvdata(dev), buf, MAG_DATA_FLAG); +} +static ssize_t akm_enable_mag_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm_compass_sysfs_enable_store( + dev_get_drvdata(dev), buf, count, MAG_DATA_FLAG); +} + +/***** Fusion ***/ +static ssize_t akm_enable_fusion_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm_compass_sysfs_enable_show( + dev_get_drvdata(dev), buf, FUSION_DATA_FLAG); +} +static ssize_t akm_enable_fusion_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm_compass_sysfs_enable_store( + dev_get_drvdata(dev), buf, count, FUSION_DATA_FLAG); +} + +/***** sysfs delay **************************************************/ +static int akm_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_msec) +{ + struct akm_compass_data *akm = container_of(sensors_cdev, + struct akm_compass_data, cdev); + uint8_t mode; + int ret; + + mutex_lock(&akm->val_mutex); + + s_akm->delay[MAG_DATA_FLAG] = delay_msec * 1000000; + mode = akm_select_frequency(akm->delay[MAG_DATA_FLAG]); + ret = AKECS_SetMode(akm, mode); + if (ret < 0) + dev_err(&akm->i2c->dev, "Failed to set to mode(%x)\n", mode); + + mutex_unlock(&akm->val_mutex); + return ret; +} + +static ssize_t akm_compass_sysfs_delay_show( + struct akm_compass_data *akm, char *buf, int pos) +{ + int64_t val; + + mutex_lock(&akm->val_mutex); + val = akm->delay[pos]; + mutex_unlock(&akm->val_mutex); + + return scnprintf(buf, PAGE_SIZE, "%lld\n", val); +} + +static ssize_t akm_compass_sysfs_delay_store( + struct akm_compass_data *akm, char const *buf, size_t count, int pos) +{ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (kstrtoll(buf, AKM_BASE_NUM, &val)) + return -EINVAL; + + mutex_lock(&akm->val_mutex); + akm->delay[pos] = val; + mutex_unlock(&akm->val_mutex); + + return count; +} + +/*add by eliot shao 2016.8.27 start*/ +static ssize_t akm_compass_sysfs_layout_show( + struct akm_compass_data *akm, char *buf, int pos) +{ + int64_t val; + + mutex_lock(&akm->val_mutex); + val = akm->layout; + mutex_unlock(&akm->val_mutex); + + return scnprintf(buf, PAGE_SIZE, "%lld\n", val); +} + +static ssize_t akm_compass_sysfs_layout_store( + struct akm_compass_data *akm, char const *buf, size_t count, int pos) +{ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (kstrtoll(buf, AKM_BASE_NUM, &val)) + return -EINVAL; + + mutex_lock(&akm->val_mutex); + akm->layout = val; + mutex_unlock(&akm->val_mutex); + + return count; +} + +static ssize_t akm_layout_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm_compass_sysfs_layout_show( + dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} +static ssize_t akm_layout_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm_compass_sysfs_layout_store( + dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + + +/*add by eliot shao 2016.8.27 end*/ +/***** Accelerometer ***/ +static ssize_t akm_delay_acc_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm_compass_sysfs_delay_show( + dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} +static ssize_t akm_delay_acc_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm_compass_sysfs_delay_store( + dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/***** Magnetic field ***/ +static ssize_t akm_delay_mag_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm_compass_sysfs_delay_show( + dev_get_drvdata(dev), buf, MAG_DATA_FLAG); +} +static ssize_t akm_delay_mag_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm_compass_sysfs_delay_store( + dev_get_drvdata(dev), buf, count, MAG_DATA_FLAG); +} + +/***** Fusion ***/ +static ssize_t akm_delay_fusion_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return akm_compass_sysfs_delay_show( + dev_get_drvdata(dev), buf, FUSION_DATA_FLAG); +} +static ssize_t akm_delay_fusion_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + return akm_compass_sysfs_delay_store( + dev_get_drvdata(dev), buf, count, FUSION_DATA_FLAG); +} + +/***** accel (binary) ***/ +static ssize_t akm_bin_accel_write( + struct file *file, + struct kobject *kobj, + struct bin_attribute *attr, + char *buf, + loff_t pos, + size_t size) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct akm_compass_data *akm = dev_get_drvdata(dev); + int16_t *accel_data; + + if (size == 0) + return 0; + + accel_data = (int16_t *)buf; + + mutex_lock(&akm->accel_mutex); + akm->accel_data[0] = accel_data[0]; + akm->accel_data[1] = accel_data[1]; + akm->accel_data[2] = accel_data[2]; + mutex_unlock(&akm->accel_mutex); + + dev_vdbg(&akm->i2c->dev, "accel:%d,%d,%d\n", + accel_data[0], accel_data[1], accel_data[2]); + + return size; +} + + +#if AKM_DEBUG_IF +static ssize_t akm_sysfs_mode_store( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + struct akm_compass_data *akm = dev_get_drvdata(dev); + long mode = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (kstrtol(buf, AKM_BASE_NUM, &mode)) + return -EINVAL; + + if (AKECS_SetMode(akm, (uint8_t)mode) < 0) + return -EINVAL; + + return 1; +} + +static ssize_t akm_buf_print( + char *buf, uint8_t *data, size_t num) +{ + int sz, i; + char *cur; + size_t cur_len; + + cur = buf; + cur_len = PAGE_SIZE; + sz = snprintf(cur, cur_len, "(HEX):"); + if (sz < 0) + return sz; + cur += sz; + cur_len -= sz; + for (i = 0; i < num; i++) { + sz = snprintf(cur, cur_len, "%02X,", *data); + if (sz < 0) + return sz; + cur += sz; + cur_len -= sz; + data++; + } + sz = snprintf(cur, cur_len, "\n"); + if (sz < 0) + return sz; + cur += sz; + + return (ssize_t)(cur - buf); +} + +static ssize_t akm_sysfs_bdata_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct akm_compass_data *akm = dev_get_drvdata(dev); + uint8_t rbuf[AKM_SENSOR_DATA_SIZE]; + + mutex_lock(&akm->sensor_mutex); + memcpy(&rbuf, akm->sense_data, sizeof(rbuf)); + mutex_unlock(&akm->sensor_mutex); + + return akm_buf_print(buf, rbuf, AKM_SENSOR_DATA_SIZE); +} + +static ssize_t akm_sysfs_asa_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct akm_compass_data *akm = dev_get_drvdata(dev); + int err; + uint8_t asa[3]; + + err = AKECS_SetMode(akm, AKM_MODE_FUSE_ACCESS); + if (err < 0) + return err; + + asa[0] = AKM_FUSE_1ST_ADDR; + err = akm_i2c_rxdata(akm->i2c, asa, 3); + if (err < 0) + return err; + + err = AKECS_SetMode(akm, AKM_MODE_POWERDOWN); + if (err < 0) + return err; + + return akm_buf_print(buf, asa, 3); +} + +static ssize_t akm_sysfs_regs_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + /* The total number of registers depends on the device. */ + struct akm_compass_data *akm = dev_get_drvdata(dev); + int err; + uint8_t regs[AKM_REGS_SIZE]; + + /* This function does not lock mutex obj */ + regs[0] = AKM_REGS_1ST_ADDR; + err = akm_i2c_rxdata(akm->i2c, regs, AKM_REGS_SIZE); + if (err < 0) + return err; + + return akm_buf_print(buf, regs, AKM_REGS_SIZE); +} +#endif + +static struct device_attribute akm_compass_attributes[] = { + __ATTR(enable_acc, 0660, akm_enable_acc_show, akm_enable_acc_store), + __ATTR(enable_mag, 0660, akm_enable_mag_show, akm_enable_mag_store), + __ATTR(enable_fusion, 0660, akm_enable_fusion_show, + akm_enable_fusion_store), + __ATTR(delay_acc, 0660, akm_delay_acc_show, akm_delay_acc_store), + //add by eliot shao 2016.8.27 sys/class/compass/akm09911/layout_mag + __ATTR(layout_mag, 0660, akm_layout_show, akm_layout_store), + __ATTR(delay_mag, 0660, akm_delay_mag_show, akm_delay_mag_store), + __ATTR(delay_fusion, 0660, akm_delay_fusion_show, + akm_delay_fusion_store), +#if AKM_DEBUG_IF + __ATTR(mode, 0220, NULL, akm_sysfs_mode_store), + __ATTR(bdata, 0440, akm_sysfs_bdata_show, NULL), + __ATTR(asa, 0440, akm_sysfs_asa_show, NULL), + __ATTR(regs, 0440, akm_sysfs_regs_show, NULL), +#endif + __ATTR_NULL, +}; +#ifdef __BIN_ATTR +#undef __BIN_ATTR +#endif + +#define __BIN_ATTR(name_, mode_, size_, private_, read_, write_) \ + { \ + .attr = { .name = __stringify(name_), .mode = mode_ }, \ + .size = size_, \ + .private = private_, \ + .read = read_, \ + .write = write_, \ + } +#ifdef __BIN_ATTR_NULL +#undef __BIN_ATTR_NULL +#endif +#define __BIN_ATTR_NULL \ + { \ + .attr = { .name = NULL }, \ + } + +static struct bin_attribute akm_compass_bin_attributes[] = { + __BIN_ATTR(accel, 0220, 6, NULL, + NULL, akm_bin_accel_write), + __BIN_ATTR_NULL +}; + +static char const *const device_link_name = "i2c"; +static dev_t const akm_compass_device_dev_t = MKDEV(MISC_MAJOR, 240); + +static int create_sysfs_interfaces(struct akm_compass_data *akm) +{ + int err; + + if (NULL == akm) + return -EINVAL; + + err = 0; + + akm->compass = class_create(THIS_MODULE, AKM_SYSCLS_NAME); + if (IS_ERR(akm->compass)) { + err = PTR_ERR(akm->compass); + goto exit_class_create_failed; + } + + akm->class_dev = device_create( + akm->compass, + NULL, + akm_compass_device_dev_t, + akm, + AKM_SYSDEV_NAME); + if (IS_ERR(akm->class_dev)) { + err = PTR_ERR(akm->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &akm->class_dev->kobj, + &akm->i2c->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + akm->class_dev, + akm_compass_attributes); + if (0 > err) + goto exit_device_attributes_create_failed; + + err = create_device_binary_attributes( + &akm->class_dev->kobj, + akm_compass_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; + + return err; + +exit_device_binary_attributes_create_failed: + remove_device_attributes(akm->class_dev, akm_compass_attributes); +exit_device_attributes_create_failed: + sysfs_remove_link(&akm->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(akm->compass, akm_compass_device_dev_t); +exit_class_device_create_failed: + akm->class_dev = NULL; + class_destroy(akm->compass); +exit_class_create_failed: + akm->compass = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct akm_compass_data *akm) +{ + if (NULL == akm) + return; + + if (NULL != akm->class_dev) { + remove_device_binary_attributes( + &akm->class_dev->kobj, + akm_compass_bin_attributes); + remove_device_attributes( + akm->class_dev, + akm_compass_attributes); + sysfs_remove_link( + &akm->class_dev->kobj, + device_link_name); + akm->class_dev = NULL; + } + if (NULL != akm->compass) { + device_destroy( + akm->compass, + akm_compass_device_dev_t); + class_destroy(akm->compass); + akm->compass = NULL; + } +} + + +/***** akm input device functions ***********************************/ +static int akm_compass_input_init( + struct input_dev **input) +{ + int err = 0; + + /* Declare input device */ + *input = input_allocate_device(); + if (!*input) + return -ENOMEM; + + /* Setup input device */ + set_bit(EV_ABS, (*input)->evbit); + /* Accelerometer (720 x 16G)*/ + input_set_abs_params(*input, ABS_X, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_Y, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_Z, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_RX, + 0, 3, 0, 0); + /* Magnetic field (limited to 16bit) */ + input_set_abs_params(*input, ABS_RY, + -32768, 32767, 0, 0); + input_set_abs_params(*input, ABS_RZ, + -32768, 32767, 0, 0); + input_set_abs_params(*input, ABS_THROTTLE, + -32768, 32767, 0, 0); + input_set_abs_params(*input, ABS_RUDDER, + 0, 3, 0, 0); + + /* Orientation (degree in Q6 format) */ + /* yaw[0,360) pitch[-180,180) roll[-90,90) */ + input_set_abs_params(*input, ABS_HAT0Y, + 0, 23040, 0, 0); + input_set_abs_params(*input, ABS_HAT1X, + -11520, 11520, 0, 0); + input_set_abs_params(*input, ABS_HAT1Y, + -5760, 5760, 0, 0); + /* Rotation Vector [-1,+1] in Q14 format */ + input_set_abs_params(*input, ABS_TILT_X, + -16384, 16384, 0, 0); + input_set_abs_params(*input, ABS_TILT_Y, + -16384, 16384, 0, 0); + input_set_abs_params(*input, ABS_TOOL_WIDTH, + -16384, 16384, 0, 0); + input_set_abs_params(*input, ABS_VOLUME, + -16384, 16384, 0, 0); + + /* Report the dummy value */ + input_set_abs_params(*input, ABS_MISC, + INT_MIN, INT_MAX, 0, 0); + + /* Set name */ + (*input)->name = AKM_INPUT_DEVICE_NAME; + + /* Register */ + err = input_register_device(*input); + if (err) { + input_free_device(*input); + return err; + } + + return err; +} + +/***** akm functions ************************************************/ +static irqreturn_t akm_compass_irq(int irq, void *handle) +{ + struct akm_compass_data *akm = handle; + uint8_t buffer[AKM_SENSOR_DATA_SIZE]; + int err; + + memset(buffer, 0, sizeof(buffer)); + + /***** lock *****/ + mutex_lock(&akm->sensor_mutex); + + /* Read whole data */ + buffer[0] = AKM_REG_STATUS; + err = akm_i2c_rxdata(akm->i2c, buffer, AKM_SENSOR_DATA_SIZE); + if (err < 0) { + dev_err(&akm->i2c->dev, "IRQ I2C error."); + akm->is_busy = 0; + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + + return IRQ_HANDLED; + } + /* Check ST bit */ + if (!(AKM_DRDY_IS_HIGH(buffer[0]))) + goto work_func_none; + + memcpy(akm->sense_data, buffer, AKM_SENSOR_DATA_SIZE); + akm->is_busy = 0; + + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + + atomic_set(&akm->drdy, 1); + wake_up(&akm->drdy_wq); + + dev_vdbg(&akm->i2c->dev, "IRQ handled."); + return IRQ_HANDLED; + +work_func_none: + mutex_unlock(&akm->sensor_mutex); + /***** unlock *****/ + + dev_vdbg(&akm->i2c->dev, "IRQ not handled."); + return IRQ_NONE; +} + +static int akm_compass_suspend(struct device *dev) +{ + struct akm_compass_data *akm = dev_get_drvdata(dev); + int ret = 0; + + if (AKM_IS_MAG_DATA_ENABLED() && akm->auto_report) { + if (akm->use_hrtimer) + hrtimer_cancel(&akm->poll_timer); + else + cancel_delayed_work_sync(&akm->dwork); + } + + ret = AKECS_SetMode(akm, AKM_MODE_POWERDOWN); + if (ret) + dev_warn(&akm->i2c->dev, "Failed to set to POWERDOWN mode.\n"); + + akm->state.power_on = akm->power_enabled; + if (akm->state.power_on) + akm_compass_power_set(akm, false); + + ret = pinctrl_select_state(akm->pinctrl, akm->pin_sleep); + if (ret) + dev_err(dev, "Can't select pinctrl state\n"); + + dev_dbg(&akm->i2c->dev, "suspended\n"); + + return ret; +} + +static int akm_compass_resume(struct device *dev) +{ + struct akm_compass_data *akm = dev_get_drvdata(dev); + int ret = 0; + uint8_t mode; + + ret = pinctrl_select_state(akm->pinctrl, akm->pin_default); + if (ret) + dev_err(dev, "Can't select pinctrl state\n"); + + if (akm->state.power_on) { + ret = akm_compass_power_set(akm, true); + if (ret) { + dev_err(dev, "Sensor power resume fail!\n"); + goto exit; + } + + if (AKM_IS_MAG_DATA_ENABLED() && akm->auto_report) { + mode = akm_select_frequency(akm->delay[MAG_DATA_FLAG]); + ret = AKECS_SetMode(akm, akm->state.mode); + if (ret < 0) { + dev_err(&akm->i2c->dev, "Failed to set to mode(%d)\n", + mode); + goto exit; + } + if (akm->use_hrtimer) + hrtimer_start(&akm->poll_timer, + ns_to_ktime(akm->delay[MAG_DATA_FLAG]), + HRTIMER_MODE_REL); + else + queue_delayed_work(akm->work_queue, &akm->dwork, + (unsigned long)nsecs_to_jiffies64( + akm->delay[MAG_DATA_FLAG])); + } + } + + dev_dbg(&akm->i2c->dev, "resumed\n"); + +exit: + return ret; +} + +static int akm09911_i2c_check_device( + struct i2c_client *client) +{ + /* AK09911 specific function */ + struct akm_compass_data *akm = i2c_get_clientdata(client); + int err; + + akm->sense_info[0] = AK09911_REG_WIA1; + err = akm_i2c_rxdata(client, akm->sense_info, AKM_SENSOR_INFO_SIZE); + if (err < 0) + return err; + + /* Set FUSE access mode */ + err = AKECS_SetMode(akm, AK09911_MODE_FUSE_ACCESS); + if (err < 0) + return err; + + akm->sense_conf[0] = AK09911_FUSE_ASAX; + err = akm_i2c_rxdata(client, akm->sense_conf, AKM_SENSOR_CONF_SIZE); + if (err < 0) + return err; + + err = AKECS_SetMode(akm, AK09911_MODE_POWERDOWN); + if (err < 0) + return err; + + /* Check read data */ + if ((akm->sense_info[0] != AK09911_WIA1_VALUE) || + (akm->sense_info[1] != AK09911_WIA2_VALUE)){ + dev_err(&client->dev, + "%s: The device is not AKM Compass.", __func__); + return -ENXIO; + } + + return err; +} + +static int akm_compass_power_set(struct akm_compass_data *data, bool on) +{ + int rc = 0; + + if (!on && data->power_enabled) { + rc = regulator_disable(data->vdd); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator vdd disable failed rc=%d\n", rc); + goto err_vdd_disable; + } + + rc = regulator_disable(data->vio); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator vio disable failed rc=%d\n", rc); + goto err_vio_disable; + } + data->power_enabled = false; + return rc; + } else if (on && !data->power_enabled) { + rc = regulator_enable(data->vdd); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator vdd enable failed rc=%d\n", rc); + goto err_vdd_enable; + } + + rc = regulator_enable(data->vio); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator vio enable failed rc=%d\n", rc); + goto err_vio_enable; + } + data->power_enabled = true; + + /* + * The max time for the power supply rise time is 50ms. + * Use 80ms to make sure it meets the requirements. + */ + msleep(80); + return rc; + } else { + dev_warn(&data->i2c->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); + return rc; + } + +err_vio_enable: + regulator_disable(data->vio); +err_vdd_enable: + return rc; + +err_vio_disable: + if (regulator_enable(data->vdd)) + dev_warn(&data->i2c->dev, "Regulator vdd enable failed\n"); +err_vdd_disable: + return rc; +} + +static int akm_compass_power_init(struct akm_compass_data *data, bool on) +{ + int rc; + + if (!on) { + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, + AKM09911_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, 0, + AKM09911_VIO_MAX_UV); + + regulator_put(data->vio); + + } else { + data->vdd = regulator_get(&data->i2c->dev, "vdd"); + if (IS_ERR(data->vdd)) { + rc = PTR_ERR(data->vdd); + dev_err(&data->i2c->dev, + "Regulator get failed vdd rc=%d\n", rc); + return rc; + } + + if (regulator_count_voltages(data->vdd) > 0) { + rc = regulator_set_voltage(data->vdd, + AKM09911_VDD_MIN_UV, AKM09911_VDD_MAX_UV); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator set failed vdd rc=%d\n", + rc); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->i2c->dev, "vio"); + if (IS_ERR(data->vio)) { + rc = PTR_ERR(data->vio); + dev_err(&data->i2c->dev, + "Regulator get failed vio rc=%d\n", rc); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + rc = regulator_set_voltage(data->vio, + AKM09911_VIO_MIN_UV, AKM09911_VIO_MAX_UV); + if (rc) { + dev_err(&data->i2c->dev, + "Regulator set failed vio rc=%d\n", rc); + goto reg_vio_put; + } + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, AKM09911_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return rc; +} + +#ifdef CONFIG_OF +static int akm_compass_parse_dt(struct device *dev, + struct akm_compass_data *akm) +{ + struct device_node *np = dev->of_node; + u32 temp_val; + int rc; + + rc = of_property_read_u32(np, "akm,layout", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read akm,layout\n"); + return rc; + } else { + s_akm->layout = temp_val; + } + + akm->auto_report = of_property_read_bool(np, "akm,auto-report"); + akm->use_hrtimer = of_property_read_bool(np, "akm,use-hrtimer"); + rc = of_property_read_u32(np, "akm,poll_interval", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read akm,layout\n"); + return rc; + } else + s_akm->delay[MAG_DATA_FLAG] = temp_val * 1000000; + + if (of_property_read_bool(np, "akm,auto-report")) + s_akm->auto_report = 1; + else + s_akm->auto_report = 0; + s_akm->gpio_rstn = of_get_named_gpio_flags(dev->of_node, + "akm,gpio_rstn", 0, NULL); + + if (!gpio_is_valid(s_akm->gpio_rstn)) { + dev_err(dev, "gpio reset pin %d is invalid.\n", + s_akm->gpio_rstn); + return -EINVAL; + } + + return 0; +} +#else +static int akm_compass_parse_dt(struct device *dev, + struct akm_compass_data *akm) +{ + return -EINVAL; +} +#endif /* !CONFIG_OF */ + +static int akm_pinctrl_init(struct akm_compass_data *akm) +{ + struct i2c_client *client = akm->i2c; + + akm->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR_OR_NULL(akm->pinctrl)) { + dev_err(&client->dev, "Failed to get pinctrl\n"); + return PTR_ERR(akm->pinctrl); + } + + akm->pin_default = pinctrl_lookup_state(akm->pinctrl, "default"); + if (IS_ERR_OR_NULL(akm->pin_default)) { + dev_err(&client->dev, "Failed to look up default state\n"); + return PTR_ERR(akm->pin_default); + } + + akm->pin_sleep = pinctrl_lookup_state(akm->pinctrl, "sleep"); + if (IS_ERR_OR_NULL(akm->pin_sleep)) { + dev_err(&client->dev, "Failed to look up sleep state\n"); + return PTR_ERR(akm->pin_sleep); + } + + return 0; +} +#define CALIBRATION_BY_OURSELF 1 +//static int calibrate_xyz[3] = {-13,-28,-80}; +//static int calibrate_xyz[3] = {5,-31,24}; +//static int calibrate_xyz[3] = {12,-23,25}; +//static int calibrate_xyz[3] = {54,40,41}; +//static int calibrate_xyz[3] = {58,78,35}; +//static int calibrate_xyz[3] = {52,39,35}; +//static int calibrate_xyz[3] = {53,67,31}; + +#if CALIBRATION_BY_OURSELF +static int calibrate_xyz[3] = {70,7,-8}; +static int max_xyz[3] = {126,64,50}; +static int min_xyz[3] = {14,-50,-66}; +//static int max_xyz1[3] = {0,0,0}; +//static int min_xyz1[3] = {0,0,0}; +static int range_xyz[3] = {112,114,116}; +static void akm_calibrate_xyz(int *data) +{ + //static bool first_data = 1; + //static bool calibrate_use_defult[3] = {1,1,1}; + int i = 0; + /* + if(first_data) + { + max_xyz1[0] = min_xyz1[0] = data[0]; + max_xyz1[1] = min_xyz1[1] = data[1]; + max_xyz1[2] = min_xyz1[2] = data[2]; + first_data = 0; + //return; + } + */ + for(i = 0;i < 3;i ++) + { + /* + if(max_xyz1[i] < data[i] || min_xyz1[i] > data[i]) + { + if(max_xyz1[i] < data[i]) max_xyz1[i] = data[i]; + else min_xyz1[i] = data[i]; + if(!calibrate_use_defult[i]) + { + if(max_xyz1[i] - min_xyz1[i] - range_xyz[i] > -50) + { + first_data = 0; + calibrate_use_defult[0] = 1; + calibrate_use_defult[1] = 1; + calibrate_use_defult[2] = 1; + return; + } + calibrate_xyz[i] = (max_xyz1[i] + min_xyz1[i]) / 2; + } + } + */ + //if(calibrate_use_defult[i]) + //{ + if(max_xyz[i] < data[i] || min_xyz[i] > data[i]) + { + if(max_xyz[i] < data[i]) + { + max_xyz[i] = data[i]; + min_xyz[i] = max_xyz[i] - range_xyz[i]; + } + else + { + min_xyz[i] = data[i]; + max_xyz[i] = min_xyz[i] + range_xyz[i]; + } + calibrate_xyz[i] = (max_xyz[i] + min_xyz[i]) / 2; + } + /* + if(max_xyz1[i] - min_xyz1[i] - range_xyz[i] > -80) + { + calibrate_xyz[i] = (max_xyz1[i] + min_xyz1[i]) / 2; + calibrate_use_defult[i] = 0; + } + */ + //} + } + /* + if(max_xyz[0] < data[0] || min_xyz[0] > data[0]) + { + if(max_xyz[0] < data[0]) + { + max_xyz[0] = data[0]; + min_xyz[0] = max_xyz[0] - range_xyz[0]; + } + else + { + min_xyz[0] = data[0]; + max_xyz[0] = min_xyz[0] + range_xyz[0]; + } + calibrate_xyz[0] = (max_xyz[0] + min_xyz[0])/2; + } + if(max_xyz[1] < data[1] || min_xyz[1] > data[1]) + { + if(max_xyz[1] < data[1]) + { + max_xyz[1] = data[1]; + min_xyz[1] = max_xyz[1] - range_xyz[1]; + } + else + { + min_xyz[1] = data[1]; + max_xyz[1] = min_xyz[1] + range_xyz[1]; + } + calibrate_xyz[1] = (max_xyz[1] + min_xyz[1])/2; + } + if(max_xyz[2] < data[2] || min_xyz[2] > data[2]) + { + if(max_xyz[2] < data[2]) + { + max_xyz[2] = data[2]; + min_xyz[2] = max_xyz[2] - range_xyz[2]; + } + else + { + min_xyz[2] = data[2]; + max_xyz[2] = min_xyz[2] + range_xyz[2]; + } + calibrate_xyz[2] = (max_xyz[2] + min_xyz[2])/2; + } + */ + return; +} +#endif +static int akm_report_data(struct akm_compass_data *akm) +{ + uint8_t dat_buf[AKM_SENSOR_DATA_SIZE];/* for GET_DATA */ + int ret; + int mag_x, mag_y, mag_z; + int tmp; + int count = 10; + ktime_t timestamp; +#if CALIBRATION_BY_OURSELF + int data[3] = {0}; + int i,j,temp_max,temp_min; + static int pre_data[5][3] = {{0}}; + static int cnt = 0; +#endif + + do { + /* The typical time for single measurement is 7.2ms */ + ret = AKECS_GetData_Poll(akm, dat_buf, AKM_SENSOR_DATA_SIZE); + if (ret == -EAGAIN) + usleep_range(1000, 10000); + } while ((ret == -EAGAIN) && (--count)); + if (!count) { + dev_err(&akm->i2c->dev, "Timeout get valid data.\n"); + return -EIO; + } + + tmp = dat_buf[0] | dat_buf[8]; + if (STATUS_ERROR(tmp)) { + dev_warn(&s_akm->i2c->dev, "Status error(0x%x). Reset...\n", + tmp); + AKECS_Reset(akm, 0); + return -EIO; + } + + timestamp = ktime_get_boottime(); + ///////////////////////////////////////////////////////////////////////////// +#if CALIBRATION_BY_OURSELF + //data[0] = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); + //data[1] = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); + //data[2] = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); + //mag_x = data[0] - calibrate_xyz[0]; + //mag_y = data[1] - calibrate_xyz[1]; + //mag_z = data[2] - calibrate_xyz[2]; + //akm_calibrate_xyz(data); + data[0] = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); + data[1] = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); + data[2] = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); + akm_calibrate_xyz(data); + pre_data[cnt][0] = data[0] - calibrate_xyz[0]; + pre_data[cnt][1] = data[1] - calibrate_xyz[1]; + pre_data[cnt][2] = data[2] - calibrate_xyz[2]; + cnt ++; + cnt %= 5; + for(j = 0;j < 3;j ++) + { + temp_max = temp_min = pre_data[0][j]; + for(i = 1;i < 5;i ++) + { + if(pre_data[i][j] > temp_max) temp_max = pre_data[i][j]; + else if(pre_data[i][j] < temp_min) temp_min = pre_data[i][j]; + } + //data[j] = pre_data[0][j] + pre_data[1][j] + pre_data[2][j] + pre_data[3][j] + pre_data[4][j] - temp_max - temp_min; + } + //akm_calibrate_xyz(data); + mag_x = data[0]; + mag_y = data[1]; + mag_z = -data[2]; + //pr_err("%d:%d:%d\n",mag_x,mag_y,mag_y); + //orientation[0] = (float) Math.atan2((mGeomagnetic[0]*mGravity[1] - mGeomagnetic[1]*mGravity[0]) , (mGeomagnetic[2]*mGravity[1] - mGeomagnetic[1]*mGravity[2])); + //pr_err("%d,%d,%d %d,%d,%d %d,%d,%d\n",calibrate_xyz[0],calibrate_xyz[1],calibrate_xyz[2],max_xyz[0],max_xyz[1],max_xyz[2],min_xyz[0],min_xyz[1],min_xyz[2]); + //pr_err("%d:%s:===mag_x = %d,mag_y = %d,mag_z = %d\n\n",__LINE__,__func__,mag_x,mag_y,mag_y); +#else + tmp = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); + tmp = tmp * akm->sense_conf[0] / 128 + tmp; + mag_x = tmp; + + tmp = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); + tmp = tmp * akm->sense_conf[1] / 128 + tmp; + mag_y = tmp; + + tmp = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); + tmp = tmp * akm->sense_conf[2] / 128 + tmp; + mag_z = tmp; +#endif +//////////////////////////////////////////////////////////////////////////////// + + dev_dbg(&s_akm->i2c->dev, "mag_x:%d mag_y:%d mag_z:%d\n", + mag_x, mag_y, mag_z); + dev_dbg(&s_akm->i2c->dev, "raw data: %d %d %d %d %d %d %d %d\n", + dat_buf[0], dat_buf[1], dat_buf[2], dat_buf[3], + dat_buf[4], dat_buf[5], dat_buf[6], dat_buf[7]); + dev_dbg(&s_akm->i2c->dev, "asa: %d %d %d\n", akm->sense_conf[0], + akm->sense_conf[1], akm->sense_conf[2]); + + switch (akm->layout) { + case 0: + case 1: + /* Fall into the default direction */ + break; + case 2: + tmp = mag_x; + mag_x = mag_y; + mag_y = -tmp; + break; + case 3: + mag_x = -mag_x; + mag_y = -mag_y; + break; + case 4: + tmp = mag_x; + mag_x = -mag_y; + mag_y = tmp; + break; + case 5: + mag_x = -mag_x; + mag_z = -mag_z; + break; + case 6: + tmp = mag_x; + mag_x = mag_y; + mag_y = tmp; + mag_z = -mag_z; + break; + case 7: + mag_y = -mag_y; + mag_z = -mag_z; + break; + case 8: + tmp = mag_x; + mag_x = -mag_y; + mag_y = -tmp; + mag_z = -mag_z; + break; + } + + input_report_abs(akm->input, ABS_X, mag_x); + input_report_abs(akm->input, ABS_Y, mag_y); + input_report_abs(akm->input, ABS_Z, mag_z); + input_event(akm->input, + EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(akm->input, + EV_SYN, SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); + + akm->last_x = mag_x; + akm->last_y = mag_y; + akm->last_z = mag_z; + input_sync(akm->input); + + return 0; +} + +static void akm_dev_poll(struct work_struct *work) +{ + struct akm_compass_data *akm; + int ret; + + akm = container_of((struct delayed_work *)work, + struct akm_compass_data, dwork); + + ret = akm_report_data(akm); + if (ret < 0) + dev_warn(&s_akm->i2c->dev, "Failed to report data\n"); + + if (!akm->use_hrtimer) + queue_delayed_work(akm->work_queue, &akm->dwork, + (unsigned long)nsecs_to_jiffies64( + akm->delay[MAG_DATA_FLAG])); +} + +static enum hrtimer_restart akm_timer_func(struct hrtimer *timer) +{ + struct akm_compass_data *akm; + + akm = container_of(timer, struct akm_compass_data, poll_timer); + + queue_work(akm->work_queue, &akm->dwork.work); + hrtimer_forward_now(&akm->poll_timer, + ns_to_ktime(akm->delay[MAG_DATA_FLAG])); + + return HRTIMER_RESTART; +} + +static int case_test(struct akm_compass_data *akm, const char test_name[], + const int testdata, const int lo_limit, const int hi_limit, + int *fail_total) +{ + /* Pass:0, Fail:-1 */ + int result = 0; + + if (fail_total == NULL) + return -EINVAL; + + if (strcmp(test_name, "START") == 0) { + dev_dbg(&akm->i2c->dev, "----------------------------------------------------------\n"); + dev_dbg(&akm->i2c->dev, "Test Name Fail Test Data [ Low High]\n"); + dev_dbg(&akm->i2c->dev, "----------------------------------------------------------\n"); + } else if (strcmp(test_name, "END") == 0) { + dev_dbg(&akm->i2c->dev, "----------------------------------------------------------\n"); + if (*fail_total == 0) + dev_dbg(&akm->i2c->dev, "Factory shipment test passed.\n\n"); + else + dev_dbg(&akm->i2c->dev, "%d test cases failed.\n\n", + *fail_total); + } else { + if ((testdata < lo_limit) || (testdata > hi_limit)) { + result = -1; + *fail_total += 1; + } + + dev_dbg(&akm->i2c->dev, " %-10s %c %9d [%9d %9d]\n", + test_name, ((result == 0) ? ('.') : ('F')), + testdata, lo_limit, hi_limit); + } + + return result; +} + +static int akm_self_test(struct sensors_classdev *sensors_cdev) +{ + struct akm_compass_data *akm = container_of(sensors_cdev, + struct akm_compass_data, cdev); + uint8_t i2c_data[AKM_SENSOR_DATA_SIZE]; + int hdata[AKM09911_AXIS_COUNT]; + int asax, asay, asaz; + int count; + int ret; + int fail_total = 0; + uint8_t mode; + bool power_enabled = akm->power_enabled ? true : false; + + mutex_lock(&akm->op_mutex); + + asax = akm->sense_conf[AKM09911_AXIS_X]; + asay = akm->sense_conf[AKM09911_AXIS_Y]; + asaz = akm->sense_conf[AKM09911_AXIS_Z]; + + if (!power_enabled) { + ret = akm_compass_power_set(akm, true); + if (ret) { + dev_err(&akm->i2c->dev, "Power up failed.\n"); + goto exit; + } + } else { + i2c_data[0] = AKM_REG_MODE; + ret = akm_i2c_rxdata(akm->i2c, i2c_data, 1); + if (ret < 0) { + dev_err(&akm->i2c->dev, "Get mode failed.\n"); + goto exit; + } + mode = i2c_data[1]; + } + + ret = AKECS_Reset(akm, 0); + if (ret < 0) { + dev_err(&akm->i2c->dev, "Reset failed.\n"); + goto exit; + } + + /* start test */ + case_test(akm, "START", 0, 0, 0, &fail_total); + + case_test(akm, TLIMIT_TN_ASAX_09911, asax, TLIMIT_LO_ASAX_09911, + TLIMIT_HI_ASAX_09911, &fail_total); + case_test(akm, TLIMIT_TN_ASAY_09911, asay, TLIMIT_LO_ASAY_09911, + TLIMIT_HI_ASAY_09911, &fail_total); + case_test(akm, TLIMIT_TN_ASAZ_09911, asaz, TLIMIT_LO_ASAZ_09911, + TLIMIT_HI_ASAZ_09911, &fail_total); + + ret = AKECS_SetMode(akm, AK09911_MODE_SNG_MEASURE); + if (ret < 0) { + dev_err(&akm->i2c->dev, "Set to single measurement failed.\n"); + goto exit; + } + + count = AKM09911_RETRY_COUNT; + do { + /* The typical time for single measurement is 7.2ms */ + ret = AKECS_GetData_Poll(akm, i2c_data, AKM_SENSOR_DATA_SIZE); + if (ret == -EAGAIN) + usleep_range(1000, 10000); + } while ((ret == -EAGAIN) && (--count)); + + if (!count) { + dev_err(&akm->i2c->dev, "Timeout get valid data.\n"); + goto exit; + } + + hdata[AKM09911_AXIS_X] = (s16)(i2c_data[1] | (i2c_data[2] << 8)); + hdata[AKM09911_AXIS_Y] = (s16)(i2c_data[3] | (i2c_data[4] << 8)); + hdata[AKM09911_AXIS_Z] = (s16)(i2c_data[5] | (i2c_data[6] << 8)); + + i2c_data[0] &= 0x7F; + case_test(akm, TLIMIT_TN_SNG_ST1_09911, + (int)i2c_data[0], TLIMIT_LO_SNG_ST1_09911, + TLIMIT_HI_SNG_ST1_09911, &fail_total); + + case_test(akm, TLIMIT_TN_SNG_HX_09911, hdata[0], TLIMIT_LO_SNG_HX_09911, + TLIMIT_HI_SNG_HX_09911, &fail_total); + case_test(akm, TLIMIT_TN_SNG_HY_09911, hdata[1], TLIMIT_LO_SNG_HY_09911, + TLIMIT_HI_SNG_HY_09911, &fail_total); + case_test(akm, TLIMIT_TN_SNG_HZ_09911, hdata[2], TLIMIT_LO_SNG_HZ_09911, + TLIMIT_HI_SNG_HZ_09911, &fail_total); + + case_test(akm, TLIMIT_TN_SNG_ST2_09911, (int)i2c_data[8], + TLIMIT_LO_SNG_ST2_09911, TLIMIT_HI_SNG_ST2_09911, + &fail_total); + + /* self-test mode */ + ret = AKECS_SetMode(akm, AK09911_MODE_SELF_TEST); + if (ret < 0) { + dev_err(&akm->i2c->dev, "Set to self test mode failed\n"); + goto exit; + } + + count = AKM09911_RETRY_COUNT; + do { + /* The typical time for single measurement is 7.2ms */ + ret = AKECS_GetData_Poll(akm, i2c_data, AKM_SENSOR_DATA_SIZE); + if (ret == -EAGAIN) + usleep_range(1000, 10000); + } while ((ret == -EAGAIN) && (--count)); + + if (!count) { + dev_err(&akm->i2c->dev, "Timeout get valid data.\n"); + goto exit; + } + + i2c_data[0] &= 0x7F; + + case_test(akm, TLIMIT_TN_SLF_ST1_09911, (int)i2c_data[0], + TLIMIT_LO_SLF_ST1_09911, TLIMIT_HI_SLF_ST1_09911, + &fail_total); + + hdata[AKM09911_AXIS_X] = (s16)(i2c_data[1] | (i2c_data[2] << 8)); + hdata[AKM09911_AXIS_Y] = (s16)(i2c_data[3] | (i2c_data[4] << 8)); + hdata[AKM09911_AXIS_Z] = (s16)(i2c_data[5] | (i2c_data[6] << 8)); + + case_test(akm, TLIMIT_TN_SLF_RVHX_09911, (hdata[0])*(asax/128 + 1), + TLIMIT_LO_SLF_RVHX_09911, TLIMIT_HI_SLF_RVHX_09911, + &fail_total); + + case_test(akm, TLIMIT_TN_SLF_RVHY_09911, (hdata[1])*(asay/128 + 1), + TLIMIT_LO_SLF_RVHY_09911, TLIMIT_HI_SLF_RVHY_09911, + &fail_total); + + case_test(akm, TLIMIT_TN_SLF_RVHZ_09911, (hdata[2])*(asaz/128 + 1), + TLIMIT_LO_SLF_RVHZ_09911, TLIMIT_HI_SLF_RVHZ_09911, + &fail_total); + + case_test(akm, TLIMIT_TN_SLF_ST2_09911, (int)i2c_data[8], + TLIMIT_LO_SLF_ST2_09911, TLIMIT_HI_SLF_ST2_09911, + &fail_total); + + case_test(akm, "END", 0, 0, 0, &fail_total); + /* clean up */ + if (!power_enabled) { + ret = akm_compass_power_set(akm, false); + if (ret) { + dev_err(&akm->i2c->dev, "Power down failed.\n"); + goto exit; + } + } else { + /* Set measure mode */ + i2c_data[0] = AKM_REG_MODE; + i2c_data[1] = mode; + ret = akm_i2c_txdata(akm->i2c, i2c_data, 2); + if (ret < 0) { + dev_err(&akm->i2c->dev, "restore mode failed\n"); + goto exit; + } + } + +exit: + mutex_unlock(&akm->op_mutex); + return ((fail_total > 0) || ret) ? -EIO : 0; +} + +static int akm_compass_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct akm09911_platform_data *pdata; + int err = 0; + int i; + printk(KERN_ERR"=====================ak,akm09911=================\n"); + dev_dbg(&client->dev, "start probing."); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, + "%s: check_functionality failed.", __func__); + err = -ENODEV; + goto exit0; + } + + /* Allocate memory for driver data */ + s_akm = kzalloc(sizeof(struct akm_compass_data), GFP_KERNEL); + if (!s_akm) { + dev_err(&client->dev, + "%s: memory allocation failed.", __func__); + err = -ENOMEM; + goto exit1; + } + + /**** initialize variables in akm_compass_data *****/ + init_waitqueue_head(&s_akm->drdy_wq); + init_waitqueue_head(&s_akm->open_wq); + + mutex_init(&s_akm->sensor_mutex); + mutex_init(&s_akm->accel_mutex); + mutex_init(&s_akm->val_mutex); + mutex_init(&s_akm->op_mutex); + + atomic_set(&s_akm->active, 0); + atomic_set(&s_akm->drdy, 0); + + s_akm->is_busy = 0; + s_akm->enable_flag = 0; + + /* Set to 1G in Android coordination, AKSC format */ + s_akm->accel_data[0] = 0; + s_akm->accel_data[1] = 0; + s_akm->accel_data[2] = 720; + + for (i = 0; i < AKM_NUM_SENSORS; i++) + s_akm->delay[i] = -1; + + if (client->dev.of_node) { + err = akm_compass_parse_dt(&client->dev, s_akm); + if (err) { + dev_err(&client->dev, + "Unable to parse platfrom data err=%d\n", err); + goto exit2; + } + } else { + if (client->dev.platform_data) { + /* Copy platform data to local. */ + pdata = client->dev.platform_data; + s_akm->layout = pdata->layout; + s_akm->gpio_rstn = pdata->gpio_RSTN; + } else { + /* Platform data is not available. + Layout and information should be set by each application. */ + s_akm->layout = 0; + s_akm->gpio_rstn = 0; + dev_warn(&client->dev, "%s: No platform data.", + __func__); + } + } + + /***** I2C initialization *****/ + s_akm->i2c = client; + /* set client data */ + i2c_set_clientdata(client, s_akm); + /* request GPIO */ + err = gpio_request(s_akm->gpio_rstn, "akm_rsrn"); + if (err) { + printk("gpio reset request fail\n"); + goto exit2; + } + /* initialize pinctrl */ + if (!akm_pinctrl_init(s_akm)) { + err = pinctrl_select_state(s_akm->pinctrl, s_akm->pin_default); + if (err) { + dev_err(&client->dev, "Can't select pinctrl state\n"); + goto exit2; + } + } + + /* Pull up the reset pin */ + AKECS_Reset(s_akm, 1); + dev_err(&client->dev, "AKECS_Reset@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + + /* check connection */ + err = akm_compass_power_init(s_akm, 1); + if (err < 0) + goto exit2; + err = akm_compass_power_set(s_akm, 1); + if (err < 0) + goto exit3; + + err = akm09911_i2c_check_device(client); + if (err < 0) + goto exit4; + + /***** input *****/ + err = akm_compass_input_init(&s_akm->input); + if (err) { + dev_err(&client->dev, + "%s: input_dev register failed", __func__); + goto exit4; + } + input_set_drvdata(s_akm->input, s_akm); + + /***** IRQ setup *****/ + s_akm->irq = client->irq; + + dev_dbg(&client->dev, "%s: IRQ is #%d.", + __func__, s_akm->irq); + + if (s_akm->irq) { + err = request_threaded_irq( + s_akm->irq, + NULL, + akm_compass_irq, + IRQF_TRIGGER_HIGH|IRQF_ONESHOT, + dev_name(&client->dev), + s_akm); + if (err < 0) { + dev_err(&client->dev, + "%s: request irq failed.", __func__); + goto exit5; + } + } else if (s_akm->auto_report) { + if (s_akm->use_hrtimer) { + hrtimer_init(&s_akm->poll_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + s_akm->poll_timer.function = akm_timer_func; + s_akm->work_queue = alloc_workqueue("akm_poll_work", + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1); + INIT_WORK(&s_akm->dwork.work, akm_dev_poll); + } else { + s_akm->work_queue = alloc_workqueue("akm_poll_work", + /*WQ_NON_REENTRANT*/WQ_FREEZABLE, 0); + INIT_DELAYED_WORK(&s_akm->dwork, akm_dev_poll); + } + } + + /***** misc *****/ + err = misc_register(&akm_compass_dev); + if (err) { + dev_err(&client->dev, + "%s: akm_compass_dev register failed", __func__); + goto exit6; + } + + /***** sysfs *****/ + err = create_sysfs_interfaces(s_akm); + if (0 > err) { + dev_err(&client->dev, + "%s: create sysfs failed.", __func__); + goto exit7; + } + + s_akm->cdev = sensors_cdev; + s_akm->cdev.sensors_enable = akm_enable_set; + s_akm->cdev.sensors_poll_delay = akm_poll_delay_set; + s_akm->cdev.sensors_self_test = akm_self_test; +/* + s_akm->delay[MAG_DATA_FLAG] = sensors_cdev.delay_msec * 1000000; +*/ + err = sensors_classdev_register(&s_akm->input->dev, &s_akm->cdev); + + if (err) { + dev_err(&client->dev, "class device create failed: %d\n", err); + goto exit8; + } + + akm_compass_power_set(s_akm, false); + + dev_info(&client->dev, "successfully probed."); + return 0; + +exit8: + remove_sysfs_interfaces(s_akm); +exit7: + misc_deregister(&akm_compass_dev); +exit6: + if (s_akm->irq) + free_irq(s_akm->irq, s_akm); +exit5: + input_unregister_device(s_akm->input); +exit4: + akm_compass_power_set(s_akm, 0); +exit3: + akm_compass_power_init(s_akm, 0); +exit2: + kfree(s_akm); +exit1: +exit0: + return err; +} + +static int akm_compass_remove(struct i2c_client *client) +{ + struct akm_compass_data *akm = i2c_get_clientdata(client); + + if (akm->auto_report) { + if (akm->use_hrtimer) { + hrtimer_cancel(&akm->poll_timer); + cancel_work_sync(&akm->dwork.work); + } else { + cancel_delayed_work_sync(&akm->dwork); + } + destroy_workqueue(akm->work_queue); + } + + if (akm_compass_power_set(akm, 0)) + dev_err(&client->dev, "power set failed."); + if (akm_compass_power_init(akm, 0)) + dev_err(&client->dev, "power deinit failed."); + remove_sysfs_interfaces(akm); + sensors_classdev_unregister(&akm->cdev); + if (misc_deregister(&akm_compass_dev) < 0) + dev_err(&client->dev, "misc deregister failed."); + if (akm->irq) + free_irq(akm->irq, akm); + input_unregister_device(akm->input); + kfree(akm); + dev_info(&client->dev, "successfully removed."); + return 0; +} + +static const struct i2c_device_id akm_compass_id[] = { + {AKM_I2C_NAME, 0 }, + { } +}; + +static const struct dev_pm_ops akm_compass_pm_ops = { + .suspend = akm_compass_suspend, + .resume = akm_compass_resume, +}; + +static struct of_device_id akm09911_match_table[] = { + { .compatible = "ak,ak09911", }, +// { .compatible = "akm,akm09911", }, + { }, +}; + +static struct i2c_driver akm_compass_driver = { + .probe = akm_compass_probe, + .remove = akm_compass_remove, + .id_table = akm_compass_id, + .driver = { + .name = AKM_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = akm09911_match_table, + .pm = &akm_compass_pm_ops, + }, +}; + +static int __init akm_compass_init(void) +{ + pr_info("AKM compass driver: initialize1111111."); + return i2c_add_driver(&akm_compass_driver); +} + +static void __exit akm_compass_exit(void) +{ + pr_info("AKM compass driver: release."); + i2c_del_driver(&akm_compass_driver); +} + +module_init(akm_compass_init); +module_exit(akm_compass_exit); + +MODULE_AUTHOR("viral wang "); +MODULE_DESCRIPTION("AKM compass driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/bmi160.c b/drivers/input/misc/bmi160.c new file mode 100755 index 00000000000..286b975a2a1 --- /dev/null +++ b/drivers/input/misc/bmi160.c @@ -0,0 +1,18752 @@ +/* +* @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html +* +* @filename bmi160.c +* @Date: 2015/04/02 +* @id "2e89046" +* @Revision: 2.0.9 $ +* +* Usage: Sensor Driver for BMI160 sensor +* +**************************************************************************** +* \section Disclaimer +* +* Common: +* Bosch Sensortec products are developed for the consumer goods industry. +* They may only be used within the parameters of the respective valid +* product data sheet. Bosch Sensortec products are provided with the +* express understanding that there is no warranty of fitness for a +* particular purpose.They are not fit for use in life-sustaining, +* safety or security sensitive systems or any system or device +* that may lead to bodily harm or property damage if the system +* or device malfunctions. In addition,Bosch Sensortec products are +* not fit for use in products which interact with motor vehicle systems. +* The resale and or use of products are at the purchasers own risk and +* his own responsibility. The examination of fitness for the intended use +* is the sole responsibility of the Purchaser. +* +* The purchaser shall indemnify Bosch Sensortec from all third party +* claims, including any claims for incidental, or consequential damages, +* arising from any product use not covered by the parameters of +* the respective valid product data sheet or not approved by +* Bosch Sensortec and reimburse Bosch Sensortec for all costs in +* connection with such claims. +* +* The purchaser must monitor the market for the purchased products, +* particularly with regard to product safety and inform Bosch Sensortec +* without delay of all security relevant incidents. +* +* Engineering Samples are marked with an asterisk (*) or (e). +* Samples may vary from the valid technical specifications of the product +* series. They are therefore not intended or fit for resale to third +* parties or for use in end products. Their sole purpose is internal +* client testing. The testing of an engineering sample may in no way +* replace the testing of a product series. Bosch Sensortec assumes +* no liability for the use of engineering samples. +* By accepting the engineering samples, the Purchaser agrees to indemnify +* Bosch Sensortec from all claims arising from the use of engineering +* samples. +* +* Special: +* This software module (hereinafter called "Software") and any information +* on application-sheets (hereinafter called "Information") is provided +* free of charge for the sole purpose to support your application work. +* The Software and Information is subject to the following +* terms and conditions: +* +* The Software is specifically designed for the exclusive use for +* Bosch Sensortec products by personnel who have special experience +* and training. Do not use this Software if you do not have the +* proper experience or training. +* +* This Software package is provided `` as is `` and without any expressed +* or implied warranties,including without limitation, the implied warranties +* of merchantability and fitness for a particular purpose. +* +* Bosch Sensortec and their representatives and agents deny any liability +* for the functional impairment +* of this Software in terms of fitness, performance and safety. +* Bosch Sensortec and their representatives and agents shall not be liable +* for any direct or indirect damages or injury, except as +* otherwise stipulated in mandatory applicable law. +* +* The Information provided is believed to be accurate and reliable. +* Bosch Sensortec assumes no responsibility for the consequences of use +* of such Information nor for any infringement of patents or +* other rights of third parties which may result from its use. +* No license is granted by implication or otherwise under any patent or +* patent rights of Bosch. Specifications mentioned in the Information are +* subject to change without notice. +**************************************************************************/ +/*! file + brief */ +#include "bmi160.h" +#include + +/* user defined code to be added here ... */ +struct bmi160_t *p_bmi160; +/* used for reading the mag trim values for compensation*/ +struct trim_data_t mag_trim; +/* the following variable used for avoiding the selecting of auto mode +when it is running in the manual mode of BMM150 mag interface*/ +u8 V_bmm150_maual_auto_condition_u8 = BMI160_INIT_VALUE; +/* used for reading the AKM compensating data */ +struct bst_akm_sensitivity_data_t akm_asa_data; +/* Assign the fifo time */ +u32 V_fifo_time_U32 = BMI160_INIT_VALUE; + +/* FIFO data read for 1024 bytes of data */ +u8 v_fifo_data_u8[FIFO_FRAME] = {BMI160_INIT_VALUE}; +/* YAMAHA-YAS532*/ +/* value of coeff*/ +static const int yas532_version_ac_coef[] = {YAS532_VERSION_AC_COEF_X, +YAS532_VERSION_AC_COEF_Y1, YAS532_VERSION_AC_COEF_Y2}; +/* used for reading the yas532 calibration data*/ +struct yas532_t yas532_data; +/* used for reading the yas537 calibration data*/ +struct yas537_t yas537_data; +/*! + * @brief + * This function is used for initialize + * bus read and bus write functions + * assign the chip id and device address + * chip id is read in the register 0x00 bit from 0 to 7 + * + * @param bmi160 : structure pointer + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * While changing the parameter of the bmi160_t + * consider the following point: + * Changing the reference value of the parameter + * will changes the local copy or local reference + * make sure your changes will not + * affect the reference value of the parameter + * (Better case don't change the reference value of the parameter) + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_init(struct bmi160_t *bmi160) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + u8 v_pmu_data_u8 = BMI160_INIT_VALUE; + /* assign bmi160 ptr */ + p_bmi160 = bmi160; + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_CHIP_ID__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* read Chip Id */ + p_bmi160->chip_id = v_data_u8; + /* To avoid gyro wakeup it is required to write 0x00 to 0x6C*/ + com_rslt += bmi160_write_reg(BMI160_USER_PMU_TRIGGER_ADDR, + &v_pmu_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + return com_rslt; +} +/*! + * @brief + * This API write the data to + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_write_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write data from register*/ + com_rslt = + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160->dev_addr, + v_addr_u8, v_data_u8, v_len_u8); + } + return com_rslt; +} +/*! + * @brief + * This API reads the data from + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* Read data from register*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + v_addr_u8, v_data_u8, v_len_u8); + } + return com_rslt; +} +/*! + * @brief This API used to reads the fatal error + * from the Register 0x02 bit 0 + * This flag will be reset only by power-on-reset and soft reset + * + * + * @param v_fatal_err_u8 : The status of fatal error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fatal_err(u8 +*v_fatal_err_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* reading the fatal error status*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FATAL_ERR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fatal_err_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FATAL_ERR); + } + return com_rslt; +} +/*! + * @brief This API used to read the error code + * from register 0x02 bit 1 to 4 + * + * + * @param v_err_code_u8 : The status of error codes + * error_code | description + * ------------|--------------- + * 0x00 |no error + * 0x01 |ACC_CONF error (accel ODR and bandwidth not compatible) + * 0x02 |GYR_CONF error (Gyroscope ODR and bandwidth not compatible) + * 0x03 |Under sampling mode and interrupt uses pre filtered data + * 0x04 |reserved + * 0x05 |Selected trigger-readout offset in + * - |MAG_IF greater than selected ODR + * 0x06 |FIFO configuration error for header less mode + * 0x07 |Under sampling mode and pre filtered data as FIFO source + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_err_code(u8 +*v_err_code_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ERR_CODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_err_code_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_ERR_CODE); + } + return com_rslt; +} +/*! + * @brief This API Reads the i2c error code from the + * Register 0x02 bit 5. + * This error occurred in I2C master detected + * + * @param v_i2c_err_code_u8 : The status of i2c fail error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_fail_err(u8 +*v_i2c_err_code_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_I2C_FAIL_ERR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_err_code_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_I2C_FAIL_ERR); + } + return com_rslt; +} + /*! + * @brief This API Reads the dropped command error + * from the register 0x02 bit 6 + * + * + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_drop_cmd_err(u8 +*v_drop_cmd_err_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_DROP_CMD_ERR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_drop_cmd_err_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_DROP_CMD_ERR); + } + return com_rslt; +} +/*! + * @brief This API reads the magnetometer data ready + * interrupt not active. + * It reads from the error register 0x0x2 bit 7 + * + * + * + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_dada_rdy_err( +u8 *v_mag_data_rdy_err_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_MAG_DADA_RDY_ERR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_data_rdy_err_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_MAG_DADA_RDY_ERR); + } + return com_rslt; +} +/*! + * @brief This API reads the error status + * from the error register 0x02 bit 0 to 7 + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * @param v_fatal_er_u8r : The status of fatal error + * @param v_err_code_u8 : The status of error code + * @param v_i2c_fail_err_u8 : The status of I2C fail error + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_error_status(u8 *v_fatal_er_u8r, +u8 *v_err_code_u8, u8 *v_i2c_fail_err_u8, +u8 *v_drop_cmd_err_u8, u8 *v_mag_data_rdy_err_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the error codes*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ERR_STAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* fatal error*/ + *v_fatal_er_u8r = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FATAL_ERR); + /* user error*/ + *v_err_code_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_ERR_CODE); + /* i2c fail error*/ + *v_i2c_fail_err_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_I2C_FAIL_ERR); + /* drop command error*/ + *v_drop_cmd_err_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_DROP_CMD_ERR); + /* mag data ready error*/ + *v_mag_data_rdy_err_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_MAG_DADA_RDY_ERR); + } + return com_rslt; +} +/*! + * @brief This API reads the magnetometer power mode from + * PMU status register 0x03 bit 0 and 1 + * + * @param v_mag_power_mode_stat_u8 : The value of mag power mode + * mag_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x02 + * + * + * @note The power mode of mag set by the 0x7E command register + * @note using the function "bmi160_set_command_register()" + * value | mode + * ---------|---------------- + * 0x18 | MAG_MODE_SUSPEND + * 0x19 | MAG_MODE_NORMAL + * 0x1A | MAG_MODE_LOWPOWER + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_power_mode_stat(u8 +*v_mag_power_mode_stat_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_POWER_MODE_STAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_power_mode_stat_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_MAG_POWER_MODE_STAT); + } + return com_rslt; +} +/*! + * @brief This API reads the gyroscope power mode from + * PMU status register 0x03 bit 2 and 3 + * + * @param v_gyro_power_mode_stat_u8 : The value of gyro power mode + * gyro_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * FAST POWER UP | 0x03 + * + * @note The power mode of gyro set by the 0x7E command register + * @note using the function "bmi160_set_command_register()" + * value | mode + * ---------|---------------- + * 0x14 | GYRO_MODE_SUSPEND + * 0x15 | GYRO_MODE_NORMAL + * 0x17 | GYRO_MODE_FASTSTARTUP + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_power_mode_stat(u8 +*v_gyro_power_mode_stat_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_GYRO_POWER_MODE_STAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_power_mode_stat_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_POWER_MODE_STAT); + } + return com_rslt; +} +/*! + * @brief This API reads the accelerometer power mode from + * PMU status register 0x03 bit 4 and 5 + * + * + * @param v_accel_power_mode_stat_u8 : The value of accel power mode + * accel_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x02 + * + * @note The power mode of accel set by the 0x7E command register + * @note using the function "bmi160_set_command_register()" + * value | mode + * ---------|---------------- + * 0x11 | ACCEL_MODE_NORMAL + * 0x12 | ACCEL_LOWPOWER + * 0x10 | ACCEL_SUSPEND + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_power_mode_stat(u8 +*v_accel_power_mode_stat_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_POWER_MODE_STAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_power_mode_stat_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_POWER_MODE_STAT); + } + return com_rslt; +} +/*! + * @brief This API switch mag interface to normal mode + * and confirm whether the mode switching done successfully or not +* + * @return results of bus communication function and current MAG_PMU result + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_interface_normal(void) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + /* aim to check the result of switching mag normal */ + u8 v_try_times_u8 = BMI160_MAG_NOAMRL_SWITCH_TIMES; + u8 v_mag_pum_status_u8 = BMI160_INIT_VALUE; + + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt = bmi160_set_command_register(MAG_MODE_NORMAL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + while (v_try_times_u8) { + com_rslt = bmi160_get_mag_power_mode_stat(&v_mag_pum_status_u8); + if (v_mag_pum_status_u8 == MAG_INTERFACE_PMU_ENABLE) + break; + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + v_try_times_u8--; + } + if (v_mag_pum_status_u8 == MAG_INTERFACE_PMU_ENABLE) + com_rslt += SUCCESS; + else + com_rslt += E_BMI160_COMM_RES; + + return com_rslt; +} +/*! + * @brief This API reads magnetometer data X values + * from the register 0x04 and 0x05 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_x_s16 : The value of mag x + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_x(s16 *v_mag_x_s16, +u8 v_sensor_select_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the mag X lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[BMI160_MAG_X_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_DATA_MAG_X_LSB__REG, + v_data_u8, BMI160_MAG_X_DATA_LENGTH); + /* X axis*/ + v_data_u8[BMI160_MAG_X_LSB_BYTE] = + BMI160_GET_BITSLICE(v_data_u8[BMI160_MAG_X_LSB_BYTE], + BMI160_USER_DATA_MAG_X_LSB); + *v_mag_x_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_MAG_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[BMI160_MAG_X_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_0_MAG_X_LSB__REG, + v_data_u8, BMI160_MAG_X_DATA_LENGTH); + *v_mag_x_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_MAG_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_MAG_X_LSB_BYTE])); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data Y values + * from the register 0x06 and 0x07 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_y_s16 : The value of mag y + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_y(s16 *v_mag_y_s16, +u8 v_sensor_select_u8) +{ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_OUT_OF_RANGE; + /* Array contains the mag Y lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[BMI160_MAG_Y_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_DATA_MAG_Y_LSB__REG, + v_data_u8, BMI160_MAG_Y_DATA_LENGTH); + /*Y-axis lsb value shifting*/ + v_data_u8[BMI160_MAG_Y_LSB_BYTE] = + BMI160_GET_BITSLICE(v_data_u8[BMI160_MAG_Y_LSB_BYTE], + BMI160_USER_DATA_MAG_Y_LSB); + *v_mag_y_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_MAG_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[BMI160_MAG_Y_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_DATA_2_MAG_Y_LSB__REG, + v_data_u8, BMI160_MAG_Y_DATA_LENGTH); + *v_mag_y_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_MAG_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_MAG_Y_LSB_BYTE])); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data Z values + * from the register 0x08 and 0x09 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_z_s16 : The value of mag z + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_z(s16 *v_mag_z_s16, +u8 v_sensor_select_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the mag Z lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[BMI160_MAG_Z_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_DATA_MAG_Z_LSB__REG, + v_data_u8, BMI160_MAG_Z_DATA_LENGTH); + /*Z-axis lsb value shifting*/ + v_data_u8[BMI160_MAG_Z_LSB_BYTE] = + BMI160_GET_BITSLICE(v_data_u8[BMI160_MAG_Z_LSB_BYTE], + BMI160_USER_DATA_MAG_Z_LSB); + *v_mag_z_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_MAG_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_07_BITS) | + (v_data_u8[BMI160_MAG_Z_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_DATA_4_MAG_Z_LSB__REG, + v_data_u8, BMI160_MAG_Z_DATA_LENGTH); + *v_mag_z_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_MAG_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | ( + v_data_u8[BMI160_MAG_Z_LSB_BYTE])); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data RHALL values + * from the register 0x0A and 0x0B + * + * + * @param v_mag_r_s16 : The value of BMM150 r data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_r(s16 *v_mag_r_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the mag R lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[BMI160_MAG_R_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_6_RHALL_LSB__REG, + v_data_u8, BMI160_MAG_R_DATA_LENGTH); + /*R-axis lsb value shifting*/ + v_data_u8[BMI160_MAG_R_LSB_BYTE] = + BMI160_GET_BITSLICE(v_data_u8[BMI160_MAG_R_LSB_BYTE], + BMI160_USER_DATA_MAG_R_LSB); + *v_mag_r_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_MAG_R_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS) | + (v_data_u8[BMI160_MAG_R_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads magnetometer data X,Y,Z values + * from the register 0x04 to 0x09 + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag xyz data + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_xyz( +struct bmi160_mag_t *mag, u8 v_sensor_select_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the mag XYZ lSB and MSB data + v_data_u8[0] - X-LSB + v_data_u8[1] - X-MSB + v_data_u8[0] - Y-LSB + v_data_u8[1] - Y-MSB + v_data_u8[0] - Z-LSB + v_data_u8[1] - Z-MSB + */ + u8 v_data_u8[BMI160_MAG_XYZ_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_sensor_select_u8) { + case BST_BMM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_DATA_MAG_X_LSB__REG, + v_data_u8, BMI160_MAG_XYZ_DATA_LENGTH); + /*X-axis lsb value shifting*/ + v_data_u8[BMI160_DATA_FRAME_MAG_X_LSB_BYTE] = + BMI160_GET_BITSLICE( + v_data_u8[BMI160_DATA_FRAME_MAG_X_LSB_BYTE], + BMI160_USER_DATA_MAG_X_LSB); + /* Data X */ + mag->x = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[BMI160_DATA_FRAME_MAG_X_LSB_BYTE])); + /* Data Y */ + /*Y-axis lsb value shifting*/ + v_data_u8[BMI160_DATA_FRAME_MAG_Y_LSB_BYTE] = + BMI160_GET_BITSLICE( + v_data_u8[BMI160_DATA_FRAME_MAG_Y_LSB_BYTE], + BMI160_USER_DATA_MAG_Y_LSB); + mag->y = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_05_BITS) | + (v_data_u8[BMI160_DATA_FRAME_MAG_Y_LSB_BYTE])); + + /* Data Z */ + /*Z-axis lsb value shifting*/ + v_data_u8[BMI160_DATA_FRAME_MAG_Z_LSB_BYTE] + = BMI160_GET_BITSLICE( + v_data_u8[BMI160_DATA_FRAME_MAG_Z_LSB_BYTE], + BMI160_USER_DATA_MAG_Z_LSB); + mag->z = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_07_BITS) | + (v_data_u8[BMI160_DATA_FRAME_MAG_Z_LSB_BYTE])); + break; + case BST_AKM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_0_MAG_X_LSB__REG, + v_data_u8, BMI160_MAG_XYZ_DATA_LENGTH); + /* Data X */ + mag->x = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_DATA_FRAME_MAG_X_LSB_BYTE])); + /* Data Y */ + mag->y = ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_DATA_FRAME_MAG_Y_LSB_BYTE])); + /* Data Z */ + mag->z = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_DATA_FRAME_MAG_Z_LSB_BYTE])); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*!* + * @brief This API reads magnetometer data X,Y,Z,r + * values from the register 0x04 to 0x0B + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag-BMM150 xyzr data + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_xyzr( +struct bmi160_mag_xyzr_t *mag) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8[BMI160_MAG_XYZR_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_MAG_X_LSB__REG, + v_data_u8, BMI160_MAG_XYZR_DATA_LENGTH); + + /* Data X */ + /*X-axis lsb value shifting*/ + v_data_u8[BMI160_DATA_FRAME_MAG_X_LSB_BYTE] + = BMI160_GET_BITSLICE( + v_data_u8[BMI160_DATA_FRAME_MAG_X_LSB_BYTE], + BMI160_USER_DATA_MAG_X_LSB); + mag->x = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_05_BITS) + | (v_data_u8[BMI160_DATA_FRAME_MAG_X_LSB_BYTE])); + /* Data Y */ + /*Y-axis lsb value shifting*/ + v_data_u8[BMI160_DATA_FRAME_MAG_Y_LSB_BYTE] + = BMI160_GET_BITSLICE( + v_data_u8[BMI160_DATA_FRAME_MAG_Y_LSB_BYTE], + BMI160_USER_DATA_MAG_Y_LSB); + mag->y = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_05_BITS) + | (v_data_u8[ + BMI160_DATA_FRAME_MAG_Y_LSB_BYTE])); + + /* Data Z */ + /*Z-axis lsb value shifting*/ + v_data_u8[BMI160_DATA_FRAME_MAG_Z_LSB_BYTE] + = BMI160_GET_BITSLICE( + v_data_u8[BMI160_DATA_FRAME_MAG_Z_LSB_BYTE], + BMI160_USER_DATA_MAG_Z_LSB); + mag->z = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_07_BITS) + | (v_data_u8[BMI160_DATA_FRAME_MAG_Z_LSB_BYTE])); + + /* RHall */ + /*R-axis lsb value shifting*/ + v_data_u8[BMI160_DATA_FRAME_MAG_R_LSB_BYTE] + = BMI160_GET_BITSLICE( + v_data_u8[BMI160_DATA_FRAME_MAG_R_LSB_BYTE], + BMI160_USER_DATA_MAG_R_LSB); + mag->r = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_MAG_R_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS) + | (v_data_u8[BMI160_DATA_FRAME_MAG_R_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data X values + * form the register 0x0C and 0x0D + * + * + * + * + * @param v_gyro_x_s16 : The value of gyro x data + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_x(s16 *v_gyro_x_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the gyro X lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[MSB_ONE] - MSB*/ + u8 v_data_u8[BMI160_GYRO_X_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_8_GYRO_X_LSB__REG, + v_data_u8, BMI160_GYRO_DATA_LENGTH); + + *v_gyro_x_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_GYRO_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_GYRO_X_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data Y values + * form the register 0x0E and 0x0F + * + * + * + * + * @param v_gyro_y_s16 : The value of gyro y data + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error result of communication routines + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_y(s16 *v_gyro_y_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the gyro Y lSB and MSB data + v_data_u8[LSB_ZERO] - LSB + v_data_u8[MSB_ONE] - MSB*/ + u8 v_data_u8[BMI160_GYRO_Y_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro y data*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_10_GYRO_Y_LSB__REG, + v_data_u8, BMI160_GYRO_DATA_LENGTH); + + *v_gyro_y_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_GYRO_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_GYRO_Y_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data Z values + * form the register 0x10 and 0x11 + * + * + * + * + * @param v_gyro_z_s16 : The value of gyro z data + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_z(s16 *v_gyro_z_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the gyro Z lSB and MSB data + v_data_u8[LSB_ZERO] - LSB + v_data_u8[MSB_ONE] - MSB*/ + u8 v_data_u8[BMI160_GYRO_Z_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro z data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_12_GYRO_Z_LSB__REG, + v_data_u8, BMI160_GYRO_DATA_LENGTH); + + *v_gyro_z_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_GYRO_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_GYRO_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads gyro data X,Y,Z values + * from the register 0x0C to 0x11 + * + * + * + * + * @param gyro : The value of gyro xyz + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_xyz(struct bmi160_gyro_t *gyro) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the mag XYZ lSB and MSB data + v_data_u8[0] - X-LSB + v_data_u8[1] - X-MSB + v_data_u8[0] - Y-LSB + v_data_u8[1] - Y-MSB + v_data_u8[0] - Z-LSB + v_data_u8[1] - Z-MSB + */ + u8 v_data_u8[BMI160_GYRO_XYZ_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the gyro xyz data*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_8_GYRO_X_LSB__REG, + v_data_u8, BMI160_GYRO_XYZ_DATA_LENGTH); + + /* Data X */ + gyro->x = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_GYRO_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_DATA_FRAME_GYRO_X_LSB_BYTE])); + /* Data Y */ + gyro->y = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_GYRO_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_DATA_FRAME_GYRO_Y_LSB_BYTE])); + + /* Data Z */ + gyro->z = (s16) + ((((s32)((s8)v_data_u8[ + BMI160_DATA_FRAME_GYRO_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_DATA_FRAME_GYRO_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data X values + * form the register 0x12 and 0x13 + * + * + * + * + * @param v_accel_x_s16 : The value of accel x + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_x(s16 *v_accel_x_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the accel X lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[BMI160_ACCEL_X_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_14_ACCEL_X_LSB__REG, + v_data_u8, BMI160_ACCEL_DATA_LENGTH); + + *v_accel_x_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_ACCEL_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_ACCEL_X_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data Y values + * form the register 0x14 and 0x15 + * + * + * + * + * @param v_accel_y_s16 : The value of accel y + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_y(s16 *v_accel_y_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the accel Y lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[BMI160_ACCEL_Y_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_16_ACCEL_Y_LSB__REG, + v_data_u8, BMI160_ACCEL_DATA_LENGTH); + + *v_accel_y_s16 = (s16) + ((((s32)((s8)v_data_u8[BMI160_ACCEL_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (v_data_u8[BMI160_ACCEL_Y_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data Z values + * form the register 0x16 and 0x17 + * + * + * + * + * @param v_accel_z_s16 : The value of accel z + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_z(s16 *v_accel_z_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the accel Z lSB and MSB data + a_data_u8r[LSB_ZERO] - LSB + a_data_u8r[MSB_ONE] - MSB*/ + u8 a_data_u8r[BMI160_ACCEL_Z_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_18_ACCEL_Z_LSB__REG, + a_data_u8r, BMI160_ACCEL_DATA_LENGTH); + + *v_accel_z_s16 = (s16) + ((((s32)((s8)a_data_u8r[BMI160_ACCEL_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[BMI160_ACCEL_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads accelerometer data X,Y,Z values + * from the register 0x12 to 0x17 + * + * + * + * + * @param accel :The value of accel xyz + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_xyz( +struct bmi160_accel_t *accel) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the accel XYZ lSB and MSB data + a_data_u8r[0] - X-LSB + a_data_u8r[1] - X-MSB + a_data_u8r[0] - Y-LSB + a_data_u8r[1] - Y-MSB + a_data_u8r[0] - Z-LSB + a_data_u8r[1] - Z-MSB + */ + u8 a_data_u8r[BMI160_ACCEL_XYZ_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_14_ACCEL_X_LSB__REG, + a_data_u8r, BMI160_ACCEL_XYZ_DATA_LENGTH); + + /* Data X */ + accel->x = (s16) + ((((s32)((s8)a_data_u8r[ + BMI160_DATA_FRAME_ACCEL_X_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[BMI160_DATA_FRAME_ACCEL_X_LSB_BYTE])); + /* Data Y */ + accel->y = (s16) + ((((s32)((s8)a_data_u8r[ + BMI160_DATA_FRAME_ACCEL_Y_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[BMI160_DATA_FRAME_ACCEL_Y_LSB_BYTE])); + + /* Data Z */ + accel->z = (s16) + ((((s32)((s8)a_data_u8r[ + BMI160_DATA_FRAME_ACCEL_Z_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[BMI160_DATA_FRAME_ACCEL_Z_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads sensor_time from the register + * 0x18 to 0x1A + * + * + * @param v_sensor_time_u32 : The value of sensor time + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_sensor_time(u32 *v_sensor_time_u32) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the sensor time it is 32 bit data + a_data_u8r[0] - sensor time + a_data_u8r[1] - sensor time + a_data_u8r[0] - sensor time + */ + u8 a_data_u8r[BMI160_SENSOR_TIME_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_SENSORTIME_0_SENSOR_TIME_LSB__REG, + a_data_u8r, BMI160_SENSOR_TIME_LENGTH); + + *v_sensor_time_u32 = (u32) + ((((u32)a_data_u8r[BMI160_SENSOR_TIME_MSB_BYTE]) + << BMI160_SHIFT_BIT_POSITION_BY_16_BITS) + |(((u32)a_data_u8r[BMI160_SENSOR_TIME_XLSB_BYTE]) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[BMI160_SENSOR_TIME_LSB_BYTE])); + } + return com_rslt; +} +/*! + * @brief This API reads the Gyroscope self test + * status from the register 0x1B bit 1 + * + * + * @param v_gyro_selftest_u8 : The value of gyro self test status + * value | status + * ---------|---------------- + * 0 | Gyroscope self test is running or failed + * 1 | Gyroscope self test completed successfully + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_selftest(u8 +*v_gyro_selftest_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STAT_GYRO_SELFTEST_OK__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_selftest_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STAT_GYRO_SELFTEST_OK); + } + return com_rslt; +} +/*! + * @brief This API reads the status of + * mag manual interface operation form the register 0x1B bit 2 + * + * + * + * @param v_mag_manual_stat_u8 : The value of mag manual operation status + * value | status + * ---------|---------------- + * 0 | Indicates no manual magnetometer + * - | interface operation is ongoing + * 1 | Indicates manual magnetometer + * - | interface operation is ongoing + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_manual_operation_stat(u8 +*v_mag_manual_stat_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read manual operation*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STAT_MAG_MANUAL_OPERATION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_manual_stat_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STAT_MAG_MANUAL_OPERATION); + } + return com_rslt; +} +/*! + * @brief This API reads the fast offset compensation + * status form the register 0x1B bit 3 + * + * + * @param v_foc_rdy_u8 : The status of fast compensation + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_rdy(u8 +*v_foc_rdy_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the FOC status*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STAT_FOC_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_rdy_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STAT_FOC_RDY); + } + return com_rslt; +} +/*! + * @brief This API Reads the nvm_rdy status from the + * resister 0x1B bit 4 + * + * + * @param v_nvm_rdy_u8 : The value of NVM ready status + * value | status + * ---------|---------------- + * 0 | NVM write operation in progress + * 1 | NVM is ready to accept a new write trigger + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_nvm_rdy(u8 +*v_nvm_rdy_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the nvm ready status*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STAT_NVM_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_nvm_rdy_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STAT_NVM_RDY); + } + return com_rslt; +} +/*! + * @brief This API reads the status of mag data ready + * from the register 0x1B bit 5 + * The status get reset when one mag data register is read out + * + * @param v_data_rdy_u8 : The value of mag data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_data_rdy_mag(u8 +*v_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STAT_DATA_RDY_MAG__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STAT_DATA_RDY_MAG); + } + return com_rslt; +} +/*! + * @brief This API reads the status of gyro data ready form the + * register 0x1B bit 6 + * The status get reset when gyro data register read out + * + * + * @param v_data_rdy_u8 : The value of gyro data ready + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_data_rdy(u8 +*v_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STAT_DATA_RDY_GYRO__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STAT_DATA_RDY_GYRO); + } + return com_rslt; +} +/*! + * @brief This API reads the status of accel data ready form the + * register 0x1B bit 7 + * The status get reset when accel data register read out + * + * + * @param v_data_rdy_u8 : The value of accel data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_data_rdy(u8 +*v_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /*reads the status of accel data ready*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STAT_DATA_RDY_ACCEL__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STAT_DATA_RDY_ACCEL); + } + return com_rslt; +} +/*! + * @brief This API reads the step detector interrupt status + * from the register 0x1C bit 0 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_step_intr_u8 : The status of step detector interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_step_intr(u8 +*v_step_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_STEP_INTR__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_step_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_STEP_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the + * significant motion interrupt status + * from the register 0x1C bit 1 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_significant_intr_u8 : The status of step + * motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_significant_intr(u8 +*v_significant_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_significant_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR); + } + return com_rslt; +} + /*! + * @brief This API reads the any motion interrupt status + * from the register 0x1C bit 2 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * @param v_any_motion_intr_u8 : The status of any-motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_any_motion_intr(u8 +*v_any_motion_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_ANY_MOTION__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_ANY_MOTION); + } + return com_rslt; +} +/*! + * @brief This API reads the power mode trigger interrupt status + * from the register 0x1C bit 3 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_pmu_trigger_intr_u8 : The status of power mode trigger interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_pmu_trigger_intr(u8 +*v_pmu_trigger_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_PMU_TRIGGER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_pmu_trigger_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_PMU_TRIGGER); + } + return com_rslt; +} +/*! + * @brief This API reads the double tab status + * from the register 0x1C bit 4 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_double_tap_intr_u8 :The status of double tab interrupt + * + * @note Double tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_double_tap() + * @note AXIS MAPPING + * @note bmi160_get_stat2_tap_first_x() + * @note bmi160_get_stat2_tap_first_y() + * @note bmi160_get_stat2_tap_first_z() + * @note DURATION + * @note bmi160_set_intr_tap_durn() + * @note THRESHOLD + * @note bmi160_set_intr_tap_thres() + * @note TAP QUIET + * @note bmi160_set_intr_tap_quiet() + * @note TAP SHOCK + * @note bmi160_set_intr_tap_shock() + * @note TAP SOURCE + * @note bmi160_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_double_tap_intr(u8 +*v_double_tap_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_DOUBLE_TAP_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_double_tap_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_DOUBLE_TAP_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the single tab status + * from the register 0x1C bit 5 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_single_tap_intr_u8 :The status of single tap interrupt + * + * @note Single tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_single_tap() + * @note AXIS MAPPING + * @note bmi160_get_stat2_tap_first_x() + * @note bmi160_get_stat2_tap_first_y() + * @note bmi160_get_stat2_tap_first_z() + * @note DURATION + * @note bmi160_set_intr_tap_durn() + * @note THRESHOLD + * @note bmi160_set_intr_tap_thres() + * @note TAP QUIET + * @note bmi160_set_intr_tap_quiet() + * @note TAP SHOCK + * @note bmi160_set_intr_tap_shock() + * @note TAP SOURCE + * @note bmi160_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_single_tap_intr(u8 +*v_single_tap_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_SINGLE_TAP_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_single_tap_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_SINGLE_TAP_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the orient status + * from the register 0x1C bit 6 + * flag is associated with a specific interrupt function. + * It is set when the orient interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_orient_intr_u8 : The status of orient interrupt + * + * @note For orient interrupt configuration use the following functions + * @note STATUS + * @note bmi160_get_stat0_orient_intr() + * @note AXIS MAPPING + * @note bmi160_get_stat3_orient_xy() + * @note bmi160_get_stat3_orient_z() + * @note bmi160_set_intr_orient_axes_enable() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_orient() + * @note INTERRUPT OUTPUT + * @note bmi160_set_intr_orient_ud_enable() + * @note THETA + * @note bmi160_set_intr_orient_theta() + * @note HYSTERESIS + * @note bmi160_set_intr_orient_hyst() + * @note BLOCKING + * @note bmi160_set_intr_orient_blocking() + * @note MODE + * @note bmi160_set_intr_orient_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_orient_intr(u8 +*v_orient_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_ORIENT__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_ORIENT); + } + return com_rslt; +} +/*! + * @brief This API reads the flat interrupt status + * from the register 0x1C bit 7 + * flag is associated with a specific interrupt function. + * It is set when the flat interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_flat_intr_u8 : The status of flat interrupt + * + * @note For flat configuration use the following functions + * @note STATS + * @note bmi160_get_stat0_flat_intr() + * @note bmi160_get_stat3_flat() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_flat() + * @note THETA + * @note bmi160_set_intr_flat_theta() + * @note HOLD TIME + * @note bmi160_set_intr_flat_hold() + * @note HYSTERESIS + * @note bmi160_set_intr_flat_hyst() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_flat_intr(u8 +*v_flat_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_0_FLAT__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_0_FLAT); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g interrupt status + * from the register 0x1D bit 2 + * flag is associated with a specific interrupt function. + * It is set when the high g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_high_g_intr_u8 : The status of high_g interrupt + * + * @note High_g interrupt configured by following functions + * @note STATUS + * @note bmi160_get_stat1_high_g_intr() + * @note AXIS MAPPING + * @note bmi160_get_stat3_high_g_first_x() + * @note bmi160_get_stat3_high_g_first_y() + * @note bmi160_get_stat3_high_g_first_z() + * @note SIGN MAPPING + * @note bmi160_get_stat3_high_g_first_sign() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_high_g() + * @note HYSTERESIS + * @note bmi160_set_intr_high_g_hyst() + * @note DURATION + * @note bmi160_set_intr_high_g_durn() + * @note THRESHOLD + * @note bmi160_set_intr_high_g_thres() + * @note SOURCE + * @note bmi160_set_intr_low_high_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_high_g_intr(u8 +*v_high_g_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_1_HIGH_G_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_1_HIGH_G_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads the low g interrupt status + * from the register 0x1D bit 3 + * flag is associated with a specific interrupt function. + * It is set when the low g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_low_g_intr_u8 : The status of low_g interrupt + * + * @note Low_g interrupt configured by following functions + * @note STATUS + * @note bmi160_get_stat1_low_g_intr() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_low_g() + * @note SOURCE + * @note bmi160_set_intr_low_high_source() + * @note DURATION + * @note bmi160_set_intr_low_g_durn() + * @note THRESHOLD + * @note bmi160_set_intr_low_g_thres() + * @note HYSTERESIS + * @note bmi160_set_intr_low_g_hyst() + * @note MODE + * @note bmi160_set_intr_low_g_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_low_g_intr(u8 +*v_low_g_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_1_LOW_G_INTR__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_1_LOW_G_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data ready interrupt status + * from the register 0x1D bit 4 + * flag is associated with a specific interrupt function. + * It is set when the data ready interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_data_rdy_intr_u8 : The status of data ready interrupt + * + * @note Data ready interrupt configured by following functions + * @note STATUS + * @note bmi160_get_stat1_data_rdy_intr() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_data_rdy() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_data_rdy_intr(u8 +*v_data_rdy_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_1_DATA_RDY_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_data_rdy_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_1_DATA_RDY_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data ready FIFO full interrupt status + * from the register 0x1D bit 5 + * flag is associated with a specific interrupt function. + * It is set when the FIFO full interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will + * be permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_full_intr_u8 : The status of fifo full interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note bmi160_set_intr_fifo_full() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_fifo_full_intr(u8 +*v_fifo_full_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_1_FIFO_FULL_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_full_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_1_FIFO_FULL_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data + * ready FIFO watermark interrupt status + * from the register 0x1D bit 6 + * flag is associated with a specific interrupt function. + * It is set when the FIFO watermark interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_wm_intr_u8 : The status of fifo water mark interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note bmi160_set_intr_fifo_wm() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_fifo_wm_intr(u8 +*v_fifo_wm_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_1_FIFO_WM_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_wm_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_1_FIFO_WM_INTR); + } + return com_rslt; +} +/*! + * @brief This API reads data ready no motion interrupt status + * from the register 0x1D bit 7 + * flag is associated with a specific interrupt function. + * It is set when the no motion interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_nomotion_intr_u8 : The status of no motion interrupt + * + * @note No motion interrupt can be configured by following function + * @note STATUS + * @note bmi160_get_stat1_nomotion_intr() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_nomotion() + * @note DURATION + * @note bmi160_set_intr_slow_no_motion_durn() + * @note THRESHOLD + * @note bmi160_set_intr_slow_no_motion_thres() + * @note SLOW/NO MOTION SELECT + * @note bmi160_set_intr_slow_no_motion_select() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_nomotion_intr(u8 +*v_nomotion_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the no motion interrupt*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_1_NOMOTION_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_nomotion_intr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_1_NOMOTION_INTR); + } + return com_rslt; +} +/*! + *@brief This API reads the status of any motion first x + * from the register 0x1E bit 0 + * + * + *@param v_anymotion_first_x_u8 : The status of any motion first x interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_first_x(u8 +*v_anymotion_first_x_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the any motion first x interrupt*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_anymotion_first_x_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_X); + } + return com_rslt; +} +/*! + * @brief This API reads the status of any motion first y interrupt + * from the register 0x1E bit 1 + * + * + * + *@param v_any_motion_first_y_u8 : The status of any motion first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_first_y(u8 +*v_any_motion_first_y_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the any motion first y interrupt*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_first_y_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y); + } + return com_rslt; +} +/*! + * @brief This API reads the status of any motion first z interrupt + * from the register 0x1E bit 2 + * + * + * + * + *@param v_any_motion_first_z_u8 : The status of any motion first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_first_z(u8 +*v_any_motion_first_z_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the any motion first z interrupt*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_first_z_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the any motion sign status from the + * register 0x1E bit 3 + * + * + * + * + * @param v_anymotion_sign_u8 : The status of any motion sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_sign(u8 +*v_anymotion_sign_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read any motion sign interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_ANY_MOTION_SIGN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_anymotion_sign_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_ANY_MOTION_SIGN); + } + return com_rslt; +} +/*! + * @brief This API reads the any motion tap first x status from the + * register 0x1E bit 4 + * + * + * + * + * @param v_tap_first_x_u8 :The status of any motion tap first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_first_x(u8 +*v_tap_first_x_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap first x interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_TAP_FIRST_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_first_x_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_TAP_FIRST_X); + } + return com_rslt; +} +/*! + * @brief This API reads the tap first y interrupt status from the + * register 0x1E bit 5 + * + * + * + * + * @param v_tap_first_y_u8 :The status of tap first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_first_y(u8 +*v_tap_first_y_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap first y interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_TAP_FIRST_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_first_y_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_TAP_FIRST_Y); + } + return com_rslt; +} +/*! + * @brief This API reads the tap first z interrupt status from the + * register 0x1E bit 6 + * + * + * + * + * @param v_tap_first_z_u8 :The status of tap first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_first_z(u8 +*v_tap_first_z_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap first z interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_TAP_FIRST_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_first_z_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_TAP_FIRST_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the tap sign status from the + * register 0x1E bit 7 + * + * + * + * + * @param v_tap_sign_u8 : The status of tap sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_sign(u8 +*v_tap_sign_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap_sign interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_2_TAP_SIGN__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_sign_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_2_TAP_SIGN); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g first x status from the + * register 0x1F bit 0 + * + * + * + * + * @param v_high_g_first_x_u8 :The status of high_g first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_first_x(u8 +*v_high_g_first_x_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read highg_x interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_first_x_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_X); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g first y status from the + * register 0x1F bit 1 + * + * + * + * + * @param v_high_g_first_y_u8 : The status of high_g first y + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_first_y(u8 +*v_high_g_first_y_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read highg_y interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_first_y_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Y); + } + return com_rslt; +} +/*! + * @brief This API reads the high_g first z status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_first_z_u8 : The status of high_g first z + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_first_z(u8 +*v_high_g_first_z_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read highg_z interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_first_z_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the high sign status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_sign_u8 :The status of high sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_sign(u8 +*v_high_g_sign_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read highg_sign interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_3_HIGH_G_SIGN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_sign_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_3_HIGH_G_SIGN); + } + return com_rslt; +} +/*! + * @brief This API reads the status of orient_xy plane + * from the register 0x1F bit 4 and 5 + * + * + * @param v_orient_xy_u8 :The status of orient_xy plane + * value | status + * -----------|------------- + * 0x00 | portrait upright + * 0x01 | portrait upside down + * 0x02 | landscape left + * 0x03 | landscape right + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_orient_xy(u8 +*v_orient_xy_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read orient plane xy interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_3_ORIENT_XY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_xy_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_3_ORIENT_XY); + } + return com_rslt; +} +/*! + * @brief This API reads the status of orient z plane + * from the register 0x1F bit 6 + * + * + * @param v_orient_z_u8 :The status of orient z + * value | status + * -----------|------------- + * 0x00 | upward looking + * 0x01 | downward looking + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_orient_z(u8 +*v_orient_z_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read orient z plane interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_3_ORIENT_Z__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_z_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_3_ORIENT_Z); + } + return com_rslt; +} +/*! + * @brief This API reads the flat status from the register + * 0x1F bit 7 + * + * + * @param v_flat_u8 : The status of flat interrupt + * value | status + * -----------|------------- + * 0x00 | non flat + * 0x01 | flat position + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_flat(u8 +*v_flat_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read flat interrupt status */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_INTR_STAT_3_FLAT__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_STAT_3_FLAT); + } + return com_rslt; +} +/*! + * @brief This API reads the temperature of the sensor + * from the register 0x21 bit 0 to 7 + * + * + * + * @param v_temp_s16 : The value of temperature + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_temp(s16 +*v_temp_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the temperature lSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 v_data_u8[BMI160_TEMP_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read temperature data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_TEMP_LSB_VALUE__REG, v_data_u8, + BMI160_TEMP_DATA_LENGTH); + *v_temp_s16 = + (s16)(((s32)((s8) (v_data_u8[BMI160_TEMP_MSB_BYTE]) << + BMI160_SHIFT_BIT_POSITION_BY_08_BITS)) + | v_data_u8[BMI160_TEMP_LSB_BYTE]); + } + return com_rslt; +} +/*! + * @brief This API reads the of the sensor + * form the register 0x23 and 0x24 bit 0 to 7 and 0 to 2 + * @brief this byte counter is updated each time a complete frame + * was read or writtern + * + * + * @param v_fifo_length_u32 : The value of fifo byte counter + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_fifo_length(u32 *v_fifo_length_u32) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array contains the fifo length data + v_data_u8[0] - fifo length + v_data_u8[1] - fifo length*/ + u8 a_data_u8r[BMI160_FIFO_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read fifo length*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_BYTE_COUNTER_LSB__REG, a_data_u8r, + BMI160_FIFO_DATA_LENGTH); + + a_data_u8r[BMI160_FIFO_LENGTH_MSB_BYTE] = + BMI160_GET_BITSLICE( + a_data_u8r[BMI160_FIFO_LENGTH_MSB_BYTE], + BMI160_USER_FIFO_BYTE_COUNTER_MSB); + + *v_fifo_length_u32 = + (u32)(((u32)((u8) ( + a_data_u8r[BMI160_FIFO_LENGTH_MSB_BYTE]) << + BMI160_SHIFT_BIT_POSITION_BY_08_BITS)) + | a_data_u8r[BMI160_FIFO_LENGTH_LSB_BYTE]); + } + return com_rslt; +} +/*! + * @brief This API reads the fifo data of the sensor + * from the register 0x24 + * @brief Data format depends on the setting of register FIFO_CONFIG + * + * + * + * @param v_fifodata_u8 : Pointer holding the fifo data + * @param fifo_length_u16 : The value of fifo length maximum + * 1024 + * + * @note For reading FIFO data use the following functions + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_fifo_data( +u8 *v_fifodata_u8, u16 v_fifo_length_u16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read fifo data*/ + com_rslt = + p_bmi160->BMI160_BURST_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_DATA__REG, + v_fifodata_u8, v_fifo_length_u16); + + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | BMI160_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | BMI160_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | BMI160_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | BMI160_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | BMI160_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | BMI160_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | BMI160_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | BMI160_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | BMI160_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | BMI160_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | BMI160_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | BMI160_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_output_data_rate( +u8 *v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel output data rate*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_output_data_rate_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | BMI160_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | BMI160_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | BMI160_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | BMI160_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | BMI160_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | BMI160_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | BMI160_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | BMI160_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | BMI160_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | BMI160_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | BMI160_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | BMI160_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_output_data_rate( +u8 v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* accel output data rate selection */ + if ((v_output_data_rate_u8 != BMI160_INIT_VALUE) && + (v_output_data_rate_u8 <= BMI160_MAX_ACCEL_OUTPUT_DATA_RATE)) { + /* write accel output data rate */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE, + v_output_data_rate_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "BMI160_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_bw(u8 *v_bw_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel bandwidth */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_ACCEL_BW__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_bw_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_CONFIG_ACCEL_BW); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "BMI160_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_bw(u8 v_bw_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* select accel bandwidth*/ + if (v_bw_u8 <= BMI160_MAX_ACCEL_BW) { + /* write accel bandwidth*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_ACCEL_BW__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_CONFIG_ACCEL_BW, + v_bw_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_ACCEL_BW__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_under_sampling_parameter( +u8 *v_accel_under_sampling_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel under sampling parameter */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_under_sampling_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING); + } + return com_rslt; +} +/*! + * @brief This API is used to set the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_under_sampling_parameter( +u8 v_accel_under_sampling_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_accel_under_sampling_u8 <= BMI160_MAX_UNDER_SAMPLING) { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + /* write the accel under sampling parameter */ + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING, + v_accel_under_sampling_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} +return com_rslt; +} +/*! + * @brief This API is used to get the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | BMI160_ACCEL_RANGE_2G + * 0x05 | BMI160_ACCEL_RANGE_4G + * 0x08 | BMI160_ACCEL_RANGE_8G + * 0x0C | BMI160_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_range( +u8 *v_range_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel range*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_RANGE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_range_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_RANGE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | BMI160_ACCEL_RANGE_2G + * 0x05 | BMI160_ACCEL_RANGE_4G + * 0x08 | BMI160_ACCEL_RANGE_8G + * 0x0C | BMI160_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_range(u8 v_range_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if ((v_range_u8 == BMI160_ACCEL_RANGE0) || + (v_range_u8 == BMI160_ACCEL_RANGE1) || + (v_range_u8 == BMI160_ACCEL_RANGE3) || + (v_range_u8 == BMI160_ACCEL_RANGE4)) { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_ACCEL_RANGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE( + v_data_u8, BMI160_USER_ACCEL_RANGE, + v_range_u8); + /* write the accel range*/ + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_RANGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | BMI160_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | BMI160_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | BMI160_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | BMI160_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | BMI160_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | BMI160_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | BMI160_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | BMI160_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_output_data_rate( +u8 *v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the gyro output data rate*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_output_data_rate_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | BMI160_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | BMI160_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | BMI160_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | BMI160_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | BMI160_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | BMI160_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | BMI160_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | BMI160_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_output_data_rate( +u8 v_output_data_rate_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* select the gyro output data rate*/ + if ((v_output_data_rate_u8 < BMI160_OUTPUT_DATA_RATE6) && + (v_output_data_rate_u8 != BMI160_INIT_VALUE) + && (v_output_data_rate_u8 != BMI160_OUTPUT_DATA_RATE1) + && (v_output_data_rate_u8 != BMI160_OUTPUT_DATA_RATE2) + && (v_output_data_rate_u8 != BMI160_OUTPUT_DATA_RATE3) + && (v_output_data_rate_u8 != BMI160_OUTPUT_DATA_RATE4) + && (v_output_data_rate_u8 != BMI160_OUTPUT_DATA_RATE5) + && (v_output_data_rate_u8 != BMI160_OUTPUT_DATA_RATE6) + && (v_output_data_rate_u8 != BMI160_OUTPUT_DATA_RATE7)) { + /* write the gyro output data rate */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE, + v_output_data_rate_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | BMI160_GYRO_OSR4_MODE + * 0x01 | BMI160_GYRO_OSR2_MODE + * 0x02 | BMI160_GYRO_NORMAL_MODE + * 0x03 | BMI160_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_bw(u8 *v_bw_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro bandwidth*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_GYRO_CONFIG_BW__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_bw_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_CONFIG_BW); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | BMI160_GYRO_OSR4_MODE + * 0x01 | BMI160_GYRO_OSR2_MODE + * 0x02 | BMI160_GYRO_NORMAL_MODE + * 0x03 | BMI160_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_bw(u8 v_bw_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_bw_u8 <= BMI160_MAX_GYRO_BW) { + /* write the gyro bandwidth*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_GYRO_CONFIG_BW__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_CONFIG_BW, v_bw_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_CONFIG_BW__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | BMI160_GYRO_RANGE_2000_DEG_SEC + * 0x01 | BMI160_GYRO_RANGE_1000_DEG_SEC + * 0x02 | BMI160_GYRO_RANGE_500_DEG_SEC + * 0x03 | BMI160_GYRO_RANGE_250_DEG_SEC + * 0x04 | BMI160_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_range(u8 *v_range_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the gyro range */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_GYRO_RANGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_range_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_RANGE); + } + return com_rslt; +} +/*! + * @brief This API set the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | BMI160_GYRO_RANGE_2000_DEG_SEC + * 0x01 | BMI160_GYRO_RANGE_1000_DEG_SEC + * 0x02 | BMI160_GYRO_RANGE_500_DEG_SEC + * 0x03 | BMI160_GYRO_RANGE_250_DEG_SEC + * 0x04 | BMI160_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_range(u8 v_range_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_range_u8 <= BMI160_MAX_GYRO_RANGE) { + /* write the gyro range value */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_GYRO_RANGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_RANGE, + v_range_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_GYRO_RANGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |BMI160_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |BMI160_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |BMI160_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |BMI160_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |BMI160_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |BMI160_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |BMI160_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |BMI160_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |BMI160_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |BMI160_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |BMI160_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |BMI160_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_output_data_rate( +u8 *v_output_data_rat_u8e) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the mag data output rate*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_output_data_rat_u8e = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE); + } + return com_rslt; +} +/*! + * @brief This API is used to set the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |BMI160_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |BMI160_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |BMI160_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |BMI160_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |BMI160_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |BMI160_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |BMI160_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |BMI160_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |BMI160_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |BMI160_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |BMI160_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |BMI160_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_output_data_rate( +u8 v_output_data_rat_u8e) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* select the mag data output rate*/ + if ((v_output_data_rat_u8e + <= BMI160_MAX_ACCEL_OUTPUT_DATA_RATE) + && (v_output_data_rat_u8e + != BMI160_OUTPUT_DATA_RATE0) + && (v_output_data_rat_u8e + != BMI160_OUTPUT_DATA_RATE6) + && (v_output_data_rat_u8e + != BMI160_OUTPUT_DATA_RATE7)) { + /* write the mag data output rate*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE, + v_output_data_rat_u8e); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API is used to read Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_down_gyro( +u8 *v_fifo_down_gyro_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the gyro fifo down*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_DOWN_GYRO__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_down_gyro_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_DOWN_GYRO); + } + return com_rslt; +} + /*! + * @brief This API is used to set Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_down_gyro( +u8 v_fifo_down_gyro_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the gyro fifo down*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_DOWN_GYRO__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE( + v_data_u8, + BMI160_USER_FIFO_DOWN_GYRO, + v_fifo_down_gyro_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_DOWN_GYRO__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_fifo_filter_data( +u8 *v_gyro_fifo_filter_data_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the gyro fifo filter data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_FILTER_GYRO__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_fifo_filter_data_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_FILTER_GYRO); + } + return com_rslt; +} +/*! + * @brief This API is used to set gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_fifo_filter_data( +u8 v_gyro_fifo_filter_data_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_gyro_fifo_filter_data_u8 + <= BMI160_MAX_VALUE_FIFO_FILTER) { + /* write the gyro fifo filter data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_FILTER_GYRO__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE( + v_data_u8, + BMI160_USER_FIFO_FILTER_GYRO, + v_gyro_fifo_filter_data_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_FILTER_GYRO__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_down_accel( +u8 *v_fifo_down_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel fifo down data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_DOWN_ACCEL__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_down_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_DOWN_ACCEL); + } + return com_rslt; +} + /*! + * @brief This API is used to set Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_down_accel( +u8 v_fifo_down_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the accel fifo down data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_DOWN_ACCEL__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_DOWN_ACCEL, v_fifo_down_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_DOWN_ACCEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_fifo_filter_data( +u8 *v_accel_fifo_filter_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel fifo filter data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_FILTER_ACCEL__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_fifo_filter_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_FILTER_ACCEL); + } + return com_rslt; +} +/*! + * @brief This API is used to set accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_fifo_filter_data( +u8 v_accel_fifo_filter_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_accel_fifo_filter_u8 <= BMI160_MAX_VALUE_FIFO_FILTER) { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_FILTER_ACCEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + /* write accel fifo filter data */ + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_FILTER_ACCEL, + v_accel_fifo_filter_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_FILTER_ACCEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_wm( +u8 *v_fifo_wm_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the fifo water mark level*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_WM__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_wm_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_WM); + } + return com_rslt; +} +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_wm( +u8 v_fifo_wm_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the fifo water mark level*/ + com_rslt = + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_WM__REG, + &v_fifo_wm_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API reads fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_time_enable( +u8 *v_fifo_time_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the fifo sensor time*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_TIME_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_time_enable_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_TIME_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_time_enable( +u8 v_fifo_time_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_fifo_time_enable_u8 <= BMI160_MAX_VALUE_FIFO_TIME) { + /* write the fifo sensor time*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_TIME_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_TIME_ENABLE, + v_fifo_time_enable_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_TIME_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_tag_intr2_enable( +u8 *v_fifo_tag_intr2_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the fifo tag interrupt2*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_TAG_INTR2_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_tag_intr2_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_TAG_INTR2_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_tag_intr2_enable( +u8 v_fifo_tag_intr2_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_fifo_tag_intr2_u8 <= BMI160_MAX_VALUE_FIFO_INTR) { + /* write the fifo tag interrupt2*/ + com_rslt = bmi160_set_input_enable(1, + v_fifo_tag_intr2_u8); + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_TAG_INTR2_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_TAG_INTR2_ENABLE, + v_fifo_tag_intr2_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_TAG_INTR2_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API get FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_tag_intr1_enable( +u8 *v_fifo_tag_intr1_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read fifo tag interrupt*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_TAG_INTR1_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_tag_intr1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_TAG_INTR1_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_tag_intr1_enable( +u8 v_fifo_tag_intr1_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_fifo_tag_intr1_u8 <= BMI160_MAX_VALUE_FIFO_INTR) { + /* write the fifo tag interrupt*/ + com_rslt = bmi160_set_input_enable(BMI160_INIT_VALUE, + v_fifo_tag_intr1_u8); + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_TAG_INTR1_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_TAG_INTR1_ENABLE, + v_fifo_tag_intr1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_TAG_INTR1_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_header_enable( +u8 *v_fifo_header_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read fifo header */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_HEADER_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_header_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_HEADER_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API set FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_header_enable( +u8 v_fifo_header_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_fifo_header_u8 <= BMI160_MAX_VALUE_FIFO_HEADER) { + /* write the fifo header */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_HEADER_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_HEADER_ENABLE, + v_fifo_header_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_HEADER_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_mag_enable( +u8 *v_fifo_mag_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the fifo mag enable*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_MAG_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_mag_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_MAG_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_mag_enable( +u8 v_fifo_mag_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_fifo_mag_u8 <= BMI160_MAX_VALUE_FIFO_MAG) { + /* write the fifo mag enable*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FIFO_MAG_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_MAG_ENABLE, + v_fifo_mag_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FIFO_MAG_ENABLE__REG, + &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_accel_enable( +u8 *v_fifo_accel_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel fifo enable*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_ACCEL_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_accel_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_ACCEL_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_accel_enable( +u8 v_fifo_accel_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_fifo_accel_u8 <= BMI160_MAX_VALUE_FIFO_ACCEL) { + /* write the fifo mag enables*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_ACCEL_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_ACCEL_ENABLE, v_fifo_accel_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_ACCEL_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_gyro_enable( +u8 *v_fifo_gyro_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read fifo gyro enable */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_GYRO_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_fifo_gyro_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_GYRO_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_gyro_enable( +u8 v_fifo_gyro_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_fifo_gyro_u8 <= BMI160_MAX_VALUE_FIFO_GYRO) { + /* write fifo gyro enable*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_FIFO_GYRO_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FIFO_GYRO_ENABLE, v_fifo_gyro_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FIFO_GYRO_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_device_addr( +u8 *v_i2c_device_addr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the mag I2C device address*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_I2C_DEVICE_ADDR__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_device_addr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_I2C_DEVICE_ADDR); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_i2c_device_addr( +u8 v_i2c_device_addr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the mag I2C device address*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_I2C_DEVICE_ADDR__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_I2C_DEVICE_ADDR, + v_i2c_device_addr_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_I2C_DEVICE_ADDR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_burst( +u8 *v_mag_burst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read mag burst mode length*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_BURST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_burst_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_MAG_BURST); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_burst( +u8 v_mag_burst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write mag burst mode length*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_BURST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_MAG_BURST, v_mag_burst_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_MAG_BURST__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_offset( +u8 *v_mag_offset_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_OFFSET__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_offset_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_MAG_OFFSET); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_offset( +u8 v_mag_offset_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_OFFSET__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_MAG_OFFSET, v_mag_offset_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_OFFSET__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } +return com_rslt; +} +/*! + * @brief This API is used to read + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_manual_enable( +u8 *v_mag_manual_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read mag manual */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_MANUAL_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_manual_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_MAG_MANUAL_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_manual_enable( +u8 v_mag_manual_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the mag manual*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_MANUAL_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + if (com_rslt == SUCCESS) { + /* set the bit of mag manual enable*/ + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_MAG_MANUAL_ENABLE, v_mag_manual_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160->dev_addr, + BMI160_USER_MAG_MANUAL_ENABLE__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + if (com_rslt == SUCCESS) + p_bmi160->mag_manual_enable = v_mag_manual_u8; + else + p_bmi160->mag_manual_enable = E_BMI160_COMM_RES; + } +return com_rslt; +} +/*! + * @brief This API is used to read data + * magnetometer address to read from the register 0x4D bit 0 to 7 + * @brief It used to provide mag read address of auxiliary mag + * + * + * + * + * @param v_mag_read_addr_u8 : The value of address need to be read + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_read_addr( +u8 *v_mag_read_addr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the written address*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_READ_ADDR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_read_addr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_READ_ADDR); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4D bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_read_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_read_addr( +u8 v_mag_read_addr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the mag read address*/ + com_rslt = + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160->dev_addr, + BMI160_USER_READ_ADDR__REG, &v_mag_read_addr_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_write_addr( +u8 *v_mag_write_addr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the address of last written */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_WRITE_ADDR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_write_addr_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_WRITE_ADDR); + } + return com_rslt; +} +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_write_addr( +u8 v_mag_write_addr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the data of mag address to write data */ + com_rslt = + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160->dev_addr, + BMI160_USER_WRITE_ADDR__REG, &v_mag_write_addr_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_write_data( +u8 *v_mag_write_data_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_WRITE_DATA__REG, &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_mag_write_data_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_WRITE_DATA); + } + return com_rslt; +} +/*! + * @brief This API is used to set magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_write_data( +u8 v_mag_write_data_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160->dev_addr, + BMI160_USER_WRITE_DATA__REG, &v_mag_write_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_ANY_MOTION_X_ENABLE + * 1 | BMI160_ANY_MOTION_Y_ENABLE + * 2 | BMI160_ANY_MOTION_Z_ENABLE + * 3 | BMI160_DOUBLE_TAP_ENABLE + * 4 | BMI160_SINGLE_TAP_ENABLE + * 5 | BMI160_ORIENT_ENABLE + * 6 | BMI160_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_enable_0( +u8 v_enable_u8, u8 *v_intr_enable_zero_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* select interrupt to read*/ + switch (v_enable_u8) { + case BMI160_ANY_MOTION_X_ENABLE: + /* read the any motion interrupt x data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE); + break; + case BMI160_ANY_MOTION_Y_ENABLE: + /* read the any motion interrupt y data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE); + break; + case BMI160_ANY_MOTION_Z_ENABLE: + /* read the any motion interrupt z data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE); + break; + case BMI160_DOUBLE_TAP_ENABLE: + /* read the double tap interrupt data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE); + break; + case BMI160_SINGLE_TAP_ENABLE: + /* read the single tap interrupt data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE); + break; + case BMI160_ORIENT_ENABLE: + /* read the orient interrupt data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE); + break; + case BMI160_FLAT_ENABLE: + /* read the flat interrupt data */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_zero_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to set + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_ANY_MOTION_X_ENABLE + * 1 | BMI160_ANY_MOTION_Y_ENABLE + * 2 | BMI160_ANY_MOTION_Z_ENABLE + * 3 | BMI160_DOUBLE_TAP_ENABLE + * 4 | BMI160_SINGLE_TAP_ENABLE + * 5 | BMI160_ORIENT_ENABLE + * 6 | BMI160_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_enable_0( +u8 v_enable_u8, u8 v_intr_enable_zero_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_enable_u8) { + case BMI160_ANY_MOTION_X_ENABLE: + /* write any motion x*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_ANY_MOTION_Y_ENABLE: + /* write any motion y*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_ANY_MOTION_Z_ENABLE: + /* write any motion z*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_DOUBLE_TAP_ENABLE: + /* write double tap*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_SINGLE_TAP_ENABLE: + /* write single tap */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_ORIENT_ENABLE: + /* write orient interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_FLAT_ENABLE: + /* write flat interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE, + v_intr_enable_zero_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief This API is used to read + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_HIGH_G_X_ENABLE + * 1 | BMI160_HIGH_G_Y_ENABLE + * 2 | BMI160_HIGH_G_Z_ENABLE + * 3 | BMI160_LOW_G_ENABLE + * 4 | BMI160_DATA_RDY_ENABLE + * 5 | BMI160_FIFO_FULL_ENABLE + * 6 | BMI160_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_enable_1( +u8 v_enable_u8, u8 *v_intr_enable_1_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_enable_u8) { + case BMI160_HIGH_G_X_ENABLE: + /* read high_g_x interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE); + break; + case BMI160_HIGH_G_Y_ENABLE: + /* read high_g_y interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE); + break; + case BMI160_HIGH_G_Z_ENABLE: + /* read high_g_z interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE); + break; + case BMI160_LOW_G_ENABLE: + /* read low_g interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE); + break; + case BMI160_DATA_RDY_ENABLE: + /* read data ready interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE); + break; + case BMI160_FIFO_FULL_ENABLE: + /* read fifo full interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE); + break; + case BMI160_FIFO_WM_ENABLE: + /* read fifo water mark interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_1_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to set + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_HIGH_G_X_ENABLE + * 1 | BMI160_HIGH_G_Y_ENABLE + * 2 | BMI160_HIGH_G_Z_ENABLE + * 3 | BMI160_LOW_G_ENABLE + * 4 | BMI160_DATA_RDY_ENABLE + * 5 | BMI160_FIFO_FULL_ENABLE + * 6 | BMI160_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_enable_1( +u8 v_enable_u8, u8 v_intr_enable_1_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_enable_u8) { + case BMI160_HIGH_G_X_ENABLE: + /* write high_g_x interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_HIGH_G_Y_ENABLE: + /* write high_g_y interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_HIGH_G_Z_ENABLE: + /* write high_g_z interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_LOW_G_ENABLE: + /* write low_g interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_DATA_RDY_ENABLE: + /* write data ready interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_FIFO_FULL_ENABLE: + /* write fifo full interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_FIFO_WM_ENABLE: + /* write fifo water mark interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE, + v_intr_enable_1_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to read + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_NOMOTION_X_ENABLE + * 1 | BMI160_NOMOTION_Y_ENABLE + * 2 | BMI160_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_enable_2( +u8 v_enable_u8, u8 *v_intr_enable_2_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_enable_u8) { + case BMI160_NOMOTION_X_ENABLE: + /* read no motion x */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_2_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE); + break; + case BMI160_NOMOTION_Y_ENABLE: + /* read no motion y */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_2_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE); + break; + case BMI160_NOMOTION_Z_ENABLE: + /* read no motion z */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_enable_2_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief This API is used to set + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_NOMOTION_X_ENABLE + * 1 | BMI160_NOMOTION_Y_ENABLE + * 2 | BMI160_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_enable_2( +u8 v_enable_u8, u8 v_intr_enable_2_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_enable_u8) { + case BMI160_NOMOTION_X_ENABLE: + /* write no motion x */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE, + v_intr_enable_2_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_NOMOTION_Y_ENABLE: + /* write no motion y */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE, + v_intr_enable_2_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_NOMOTION_Z_ENABLE: + /* write no motion z */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE, + v_intr_enable_2_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief This API is used to read + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_step_detector_enable( +u8 *v_step_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the step detector interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_step_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API is used to set + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_detector_enable( +u8 v_step_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE, + v_step_intr_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | BMI160_INTR1_EDGE_CTRL + * 1 | BMI160_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_EDGE + * 0x00 | BMI160_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_edge_ctrl( +u8 v_channel_u8, u8 *v_intr_edge_ctrl_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_EDGE_CTRL: + /* read the edge trigger interrupt1*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_EDGE_CTRL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_edge_ctrl_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_EDGE_CTRL); + break; + case BMI160_INTR2_EDGE_CTRL: + /* read the edge trigger interrupt2*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_EDGE_CTRL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_edge_ctrl_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_EDGE_CTRL); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | BMI160_INTR1_EDGE_CTRL + * 1 | BMI160_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_EDGE + * 0x00 | BMI160_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_edge_ctrl( +u8 v_channel_u8, u8 v_intr_edge_ctrl_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_EDGE_CTRL: + /* write the edge trigger interrupt1*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_EDGE_CTRL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_EDGE_CTRL, + v_intr_edge_ctrl_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_EDGE_CTRL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_EDGE_CTRL: + /* write the edge trigger interrupt2*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_EDGE_CTRL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_EDGE_CTRL, + v_intr_edge_ctrl_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_EDGE_CTRL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used for get the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_LEVEL + * 1 | BMI160_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_LEVEL_HIGH + * 0x00 | BMI160_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_level( +u8 v_channel_u8, u8 *v_intr_level_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_LEVEL: + /* read the interrupt1 level*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_LEVEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_level_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_LEVEL); + break; + case BMI160_INTR2_LEVEL: + /* read the interrupt2 level*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_LEVEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_level_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_LEVEL); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used for set the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_LEVEL + * 1 | BMI160_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_LEVEL_HIGH + * 0x00 | BMI160_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_level( +u8 v_channel_u8, u8 v_intr_level_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_LEVEL: + /* write the interrupt1 level*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_LEVEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_LEVEL, v_intr_level_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_LEVEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_LEVEL: + /* write the interrupt2 level*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_LEVEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_LEVEL, v_intr_level_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_LEVEL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used to get configured output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_OPEN_DRAIN + * 0x00 | BMI160_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_output_type( +u8 v_channel_u8, u8 *v_intr_output_type_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_OUTPUT_TYPE: + /* read the output type of interrupt1*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_OUTPUT_TYPE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_output_type_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_OUTPUT_TYPE); + break; + case BMI160_INTR2_OUTPUT_TYPE: + /* read the output type of interrupt2*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_OUTPUT_TYPE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_output_type_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_OUTPUT_TYPE); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used to set output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_OPEN_DRAIN + * 0x00 | BMI160_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_output_type( +u8 v_channel_u8, u8 v_intr_output_type_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_OUTPUT_TYPE: + /* write the output type of interrupt1*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_OUTPUT_TYPE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_OUTPUT_TYPE, + v_intr_output_type_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_OUTPUT_TYPE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_OUTPUT_TYPE: + /* write the output type of interrupt2*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_OUTPUT_TYPE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_OUTPUT_TYPE, + v_intr_output_type_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_OUTPUT_TYPE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief API used to get the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_output_enable( +u8 v_channel_u8, u8 *v_output_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_OUTPUT_ENABLE: + /* read the output enable of interrupt1*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_OUTPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_output_enable_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_OUTPUT_ENABLE); + break; + case BMI160_INTR2_OUTPUT_ENABLE: + /* read the output enable of interrupt2*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_OUTPUT_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_output_enable_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_OUTPUT_EN); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief API used to set the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_output_enable( +u8 v_channel_u8, u8 v_output_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_OUTPUT_ENABLE: + /* write the output enable of interrupt1*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_OUTPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_OUTPUT_ENABLE, + v_output_enable_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_OUTPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_OUTPUT_ENABLE: + /* write the output enable of interrupt2*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_OUTPUT_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_OUTPUT_EN, + v_output_enable_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_OUTPUT_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! +* @brief This API is used to get the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orientation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* BMI160_LATCH_DUR_NONE | 0x00 +* BMI160_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* BMI160_LATCH_DUR_625_MICRO_SEC | 0x02 +* BMI160_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* BMI160_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* BMI160_LATCH_DUR_5_MILLI_SEC | 0x05 +* BMI160_LATCH_DUR_10_MILLI_SEC | 0x06 +* BMI160_LATCH_DUR_20_MILLI_SEC | 0x07 +* BMI160_LATCH_DUR_40_MILLI_SEC | 0x08 +* BMI160_LATCH_DUR_80_MILLI_SEC | 0x09 +* BMI160_LATCH_DUR_160_MILLI_SEC | 0x0A +* BMI160_LATCH_DUR_320_MILLI_SEC | 0x0B +* BMI160_LATCH_DUR_640_MILLI_SEC | 0x0C +* BMI160_LATCH_DUR_1_28_SEC | 0x0D +* BMI160_LATCH_DUR_2_56_SEC | 0x0E +* BMI160_LATCHED | 0x0F +* +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_latch_intr( +u8 *v_latch_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the latch duration value */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_LATCH__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_latch_intr_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LATCH); + } + return com_rslt; +} +/*! +* @brief This API is used to set the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orientation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* BMI160_LATCH_DUR_NONE | 0x00 +* BMI160_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* BMI160_LATCH_DUR_625_MICRO_SEC | 0x02 +* BMI160_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* BMI160_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* BMI160_LATCH_DUR_5_MILLI_SEC | 0x05 +* BMI160_LATCH_DUR_10_MILLI_SEC | 0x06 +* BMI160_LATCH_DUR_20_MILLI_SEC | 0x07 +* BMI160_LATCH_DUR_40_MILLI_SEC | 0x08 +* BMI160_LATCH_DUR_80_MILLI_SEC | 0x09 +* BMI160_LATCH_DUR_160_MILLI_SEC | 0x0A +* BMI160_LATCH_DUR_320_MILLI_SEC | 0x0B +* BMI160_LATCH_DUR_640_MILLI_SEC | 0x0C +* BMI160_LATCH_DUR_1_28_SEC | 0x0D +* BMI160_LATCH_DUR_2_56_SEC | 0x0E +* BMI160_LATCHED | 0x0F +* +* +* + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error +* +* +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_latch_intr(u8 v_latch_intr_u8) +{ + u8 v_data_u8 = BMI160_INIT_VALUE; + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_latch_intr_u8 <= BMI160_MAX_LATCH_INTR) { + /* write the latch duration value */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_LATCH__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LATCH, v_latch_intr_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_LATCH__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief API used to get input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | BMI160_INTR1_INPUT_ENABLE + * 1 | BMI160_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_input_enable( +u8 v_channel_u8, u8 *v_input_en_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read input enable of interrup1 and interrupt2*/ + case BMI160_INTR1_INPUT_ENABLE: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_INPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_input_en_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_INPUT_ENABLE); + break; + case BMI160_INTR2_INPUT_ENABLE: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_INPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_input_en_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_INPUT_ENABLE); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief API used to set input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | BMI160_INTR1_INPUT_ENABLE + * 1 | BMI160_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_input_enable( +u8 v_channel_u8, u8 v_input_en_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write input enable of interrup1 and interrupt2*/ + case BMI160_INTR1_INPUT_ENABLE: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_INPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR1_INPUT_ENABLE, v_input_en_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR1_INPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_INPUT_ENABLE: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_INPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR2_INPUT_ENABLE, v_input_en_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR2_INPUT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief reads the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_LOW_G + * 1 | BMI160_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g( +u8 v_channel_u8, u8 *v_intr_low_g_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the low_g interrupt */ + case BMI160_INTR1_MAP_LOW_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_low_g_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_LOW_G); + break; + case BMI160_INTR2_MAP_LOW_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_low_g_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_LOW_G); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief set the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_LOW_G + * 1 | BMI160_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g( +u8 v_channel_u8, u8 v_intr_low_g_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +u8 v_step_cnt_stat_u8 = BMI160_INIT_VALUE; +u8 v_step_det_stat_u8 = BMI160_INIT_VALUE; + +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* check the step detector interrupt enable status*/ + com_rslt = bmi160_get_step_detector_enable(&v_step_det_stat_u8); + /* disable the step detector interrupt */ + if (v_step_det_stat_u8 != BMI160_INIT_VALUE) + com_rslt += bmi160_set_step_detector_enable(BMI160_INIT_VALUE); + /* check the step counter interrupt enable status*/ + com_rslt += bmi160_get_step_counter_enable(&v_step_cnt_stat_u8); + /* disable the step counter interrupt */ + if (v_step_cnt_stat_u8 != BMI160_INIT_VALUE) + com_rslt += bmi160_set_step_counter_enable( + BMI160_INIT_VALUE); + switch (v_channel_u8) { + /* write the low_g interrupt*/ + case BMI160_INTR1_MAP_LOW_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_LOW_G, v_intr_low_g_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_LOW_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_LOW_G, v_intr_low_g_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_HIGH_G + * 1 | BMI160_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g( +u8 v_channel_u8, u8 *v_intr_high_g_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the high_g interrupt*/ + switch (v_channel_u8) { + case BMI160_INTR1_MAP_HIGH_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_HIGH_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_high_g_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_HIGH_G); + break; + case BMI160_INTR2_MAP_HIGH_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_HIGH_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_high_g_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_HIGH_G); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_HIGH_G + * 1 | BMI160_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g( +u8 v_channel_u8, u8 v_intr_high_g_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the high_g interrupt*/ + case BMI160_INTR1_MAP_HIGH_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_HIGH_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_HIGH_G, v_intr_high_g_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_HIGH_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_HIGH_G: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_HIGH_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_HIGH_G, v_intr_high_g_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_HIGH_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ANY_MOTION + * 1 | BMI160_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_any_motion( +u8 v_channel_u8, u8 *v_intr_any_motion_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the any motion interrupt */ + case BMI160_INTR1_MAP_ANY_MOTION: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_any_motion_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION); + break; + case BMI160_INTR2_MAP_ANY_MOTION: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_any_motion_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ANY_MOTION + * 1 | BMI160_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_any_motion( +u8 v_channel_u8, u8 v_intr_any_motion_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +u8 sig_mot_stat = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the status of significant motion interrupt */ + com_rslt = bmi160_get_intr_significant_motion_select(&sig_mot_stat); + /* disable the significant motion interrupt */ + if (sig_mot_stat != BMI160_INIT_VALUE) + com_rslt += bmi160_set_intr_significant_motion_select( + BMI160_INIT_VALUE); + switch (v_channel_u8) { + /* write the any motion interrupt */ + case BMI160_INTR1_MAP_ANY_MOTION: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION, + v_intr_any_motion_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_ANY_MOTION: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION, + v_intr_any_motion_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_NOMO + * 1 | BMI160_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_nomotion( +u8 v_channel_u8, u8 *v_intr_nomotion_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the no motion interrupt*/ + case BMI160_INTR1_MAP_NOMO: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_NOMOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_nomotion_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_NOMOTION); + break; + case BMI160_INTR2_MAP_NOMO: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_NOMOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_nomotion_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_NOMOTION); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_NOMO + * 1 | BMI160_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_nomotion( +u8 v_channel_u8, u8 v_intr_nomotion_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the no motion interrupt*/ + case BMI160_INTR1_MAP_NOMO: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_NOMOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_NOMOTION, + v_intr_nomotion_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_NOMOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_NOMO: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_NOMOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_NOMOTION, + v_intr_nomotion_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_NOMOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DOUBLE_TAP + * 1 | BMI160_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_double_tap( +u8 v_channel_u8, u8 *v_intr_double_tap_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + case BMI160_INTR1_MAP_DOUBLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_double_tap_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP); + break; + case BMI160_INTR2_MAP_DOUBLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_double_tap_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DOUBLE_TAP + * 1 | BMI160_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_double_tap( +u8 v_channel_u8, u8 v_intr_double_tap_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* set the double tap interrupt */ + case BMI160_INTR1_MAP_DOUBLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP, + v_intr_double_tap_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_DOUBLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP, + v_intr_double_tap_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_SINGLE_TAP + * 1 | BMI160_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_single_tap( +u8 v_channel_u8, u8 *v_intr_single_tap_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* reads the single tap interrupt*/ + case BMI160_INTR1_MAP_SINGLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_single_tap_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP); + break; + case BMI160_INTR2_MAP_SINGLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_single_tap_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_SINGLE_TAP + * 1 | BMI160_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_single_tap( +u8 v_channel_u8, u8 v_intr_single_tap_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the single tap interrupt */ + case BMI160_INTR1_MAP_SINGLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP, + v_intr_single_tap_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_SINGLE_TAP: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP, + v_intr_single_tap_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ORIENT + * 1 | BMI160_INTR2_MAP_ORIENT + * + * @param v_intr_orient_u8 : The value of orient enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient( +u8 v_channel_u8, u8 *v_intr_orient_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the orientation interrupt*/ + case BMI160_INTR1_MAP_ORIENT: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_ORIENT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_orient_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_ORIENT); + break; + case BMI160_INTR2_MAP_ORIENT: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_ORIENT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_orient_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_ORIENT); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ORIENT + * 1 | BMI160_INTR2_MAP_ORIENT + * + * @param v_intr_orient_u8 : The value of orient enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient( +u8 v_channel_u8, u8 v_intr_orient_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the orientation interrupt*/ + case BMI160_INTR1_MAP_ORIENT: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_ORIENT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_ORIENT, v_intr_orient_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_ORIENT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_ORIENT: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_ORIENT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_ORIENT, v_intr_orient_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_ORIENT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief Reads the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FLAT + * 1 | BMI160_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat( +u8 v_channel_u8, u8 *v_intr_flat_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the flat interrupt*/ + case BMI160_INTR1_MAP_FLAT: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_FLAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_flat_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_FLAT); + break; + case BMI160_INTR2_MAP_FLAT: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_FLAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_flat_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_FLAT); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} + /*! + * @brief Write the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FLAT + * 1 | BMI160_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat( +u8 v_channel_u8, u8 v_intr_flat_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the flat interrupt */ + case BMI160_INTR1_MAP_FLAT: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_0_INTR1_FLAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_0_INTR1_FLAT, + v_intr_flat_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_MAP_0_INTR1_FLAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_FLAT: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_2_INTR2_FLAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_2_INTR2_FLAT, + v_intr_flat_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_MAP_2_INTR2_FLAT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Reads PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_PMUTRIG + * 1 | BMI160_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_pmu_trig( +u8 v_channel_u8, u8 *v_intr_pmu_trig_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the pmu trigger interrupt*/ + case BMI160_INTR1_MAP_PMUTRIG: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_pmu_trig_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG); + break; + case BMI160_INTR2_MAP_PMUTRIG: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_pmu_trig_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_PMUTRIG + * 1 | BMI160_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | trigger enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_pmu_trig( +u8 v_channel_u8, u8 v_intr_pmu_trig_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the pmu trigger interrupt */ + case BMI160_INTR1_MAP_PMUTRIG: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG, + v_intr_pmu_trig_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_PMUTRIG: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG, + v_intr_pmu_trig_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} +/*! + * @brief Reads FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_FULL + * 1 | BMI160_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_fifo_full( +u8 v_channel_u8, u8 *v_intr_fifo_full_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the fifo full interrupt */ + case BMI160_INTR1_MAP_FIFO_FULL: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_full_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL); + break; + case BMI160_INTR2_MAP_FIFO_FULL: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_full_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_FULL + * 1 | BMI160_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_fifo_full( +u8 v_channel_u8, u8 v_intr_fifo_full_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the fifo full interrupt */ + case BMI160_INTR1_MAP_FIFO_FULL: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL, + v_intr_fifo_full_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_FIFO_FULL: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL, + v_intr_fifo_full_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Reads FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_WM + * 1 | BMI160_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_fifo_wm( +u8 v_channel_u8, u8 *v_intr_fifo_wm_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* read the fifo water mark interrupt */ + case BMI160_INTR1_MAP_FIFO_WM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_wm_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM); + break; + case BMI160_INTR2_MAP_FIFO_WM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_fifo_wm_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_WM + * 1 | BMI160_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_fifo_wm( +u8 v_channel_u8, u8 v_intr_fifo_wm_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /* write the fifo water mark interrupt */ + case BMI160_INTR1_MAP_FIFO_WM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM, + v_intr_fifo_wm_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_FIFO_WM: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM, + v_intr_fifo_wm_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, + BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Reads Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DATA_RDY + * 1 | BMI160_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_data_rdy( +u8 v_channel_u8, u8 *v_intr_data_rdy_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /*Read Data Ready interrupt*/ + case BMI160_INTR1_MAP_DATA_RDY: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_data_rdy_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY); + break; + case BMI160_INTR2_MAP_DATA_RDY: + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_data_rdy_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + } + return com_rslt; +} +/*! + * @brief Write Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DATA_RDY + * 1 | BMI160_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_data_rdy( +u8 v_channel_u8, u8 v_intr_data_rdy_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + switch (v_channel_u8) { + /*Write Data Ready interrupt*/ + case BMI160_INTR1_MAP_DATA_RDY: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY, + v_intr_data_rdy_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + case BMI160_INTR2_MAP_DATA_RDY: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY, + v_intr_data_rdy_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC(p_bmi160-> + dev_addr, BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } +} +return com_rslt; +} + /*! + * @brief This API reads data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_source(u8 *v_tap_source_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the tap source interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_source_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE); + } + return com_rslt; +} + /*! + * @brief This API write data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_source( +u8 v_tap_source_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_tap_source_u8 <= BMI160_MAX_VALUE_SOURCE_INTR) { + /* write the tap source interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE, + v_tap_source_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API Reads Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_high_source( +u8 *v_low_high_source_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the high_low_g source interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_low_high_source_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE); + } + return com_rslt; +} +/*! + * @brief This API write Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_high_source( +u8 v_low_high_source_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_low_high_source_u8 <= BMI160_MAX_VALUE_SOURCE_INTR) { + /* write the high_low_g source interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE, + v_low_high_source_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API reads Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_motion_source( +u8 *v_motion_source_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the any/no motion interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_motion_source_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE); + } + return com_rslt; +} + /*! + * @brief This API write Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_motion_source( +u8 v_motion_source_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_motion_source_u8 <= BMI160_MAX_VALUE_SOURCE_INTR) { + /* write the any/no motion interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE, + v_motion_source_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API is used to read the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_durn( +u8 *v_low_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the low_g interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_durn_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_0_INTR_LOW_DURN); + } + return com_rslt; +} + /*! + * @brief This API is used to write the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_durn(u8 v_low_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the low_g interrupt */ + com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__REG, + &v_low_g_durn_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_thres( +u8 *v_low_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read low_g threshold */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_thres_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_1_INTR_LOW_THRES); + } + return com_rslt; +} +/*! + * @brief This API is used to write Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_thres( +u8 v_low_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write low_g threshold */ + com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__REG, + &v_low_g_thres_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} + /*! + * @brief This API Reads Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_hyst( +u8 *v_low_hyst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read low_g hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_low_hyst_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST); + } + return com_rslt; +} + /*! + * @brief This API write Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_hyst( +u8 v_low_hyst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write low_g hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST, + v_low_hyst_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API reads Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_mode(u8 *v_low_g_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /*read Low-g interrupt mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_low_g_mode_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE); + } + return com_rslt; +} +/*! + * @brief This API write Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_mode( +u8 v_low_g_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_low_g_mode_u8 <= BMI160_MAX_VALUE_LOW_G_MODE) { + /*write Low-g interrupt mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE, + v_low_g_mode_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API reads High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g_hyst( +u8 *v_high_g_hyst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read high_g hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_hyst_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST); + } + return com_rslt; +} +/*! + * @brief This API write High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g_hyst( +u8 v_high_g_hyst_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write high_g hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST, + v_high_g_hyst_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } +return com_rslt; +} +/*! + * @brief This API is used to read Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g_durn( +u8 *v_high_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read high_g duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_durn_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN); + } + return com_rslt; +} +/*! + * @brief This API is used to write Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g_durn( +u8 v_high_g_durn_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write high_g duration*/ + com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__REG, + &v_high_g_durn_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API is used to read Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g_thres( +u8 *v_high_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_high_g_thres_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES); + } + return com_rslt; +} +/*! + * @brief This API is used to write Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g_thres( +u8 v_high_g_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__REG, + &v_high_g_thres_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} +/*! + * @brief This API reads any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_any_motion_durn( +u8 *v_any_motion_durn_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read any motion duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_durn_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN); + } + return com_rslt; +} +/*! + * @brief This API write any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_any_motion_durn( +u8 v_any_motion_durn_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write any motion duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN, + v_any_motion_durn_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_slow_no_motion_durn( +u8 *v_slow_no_motion_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read slow no motion duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_slow_no_motion_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN); + } +return com_rslt; +} + /*! + * @brief This API write Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_slow_no_motion_durn( +u8 v_slow_no_motion_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write slow no motion duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN, + v_slow_no_motion_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } +} +return com_rslt; +} +/*! + * @brief This API is used to read threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_any_motion_thres( +u8 *v_any_motion_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read any motion threshold*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_any_motion_thres_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES); + } + return com_rslt; +} +/*! + * @brief This API is used to write threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_any_motion_thres( +u8 v_any_motion_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write any motion threshold*/ + com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__REG, + &v_any_motion_thres_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} + /*! + * @brief This API is used to read threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_slow_no_motion_thres( +u8 *v_slow_no_motion_thres_u8) +{ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read slow no motion threshold*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_slow_no_motion_thres_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES); + } +return com_rslt; +} + /*! + * @brief This API is used to write threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_slow_no_motion_thres( +u8 v_slow_no_motion_thres_u8) +{ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write slow no motion threshold*/ + com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__REG, + &v_slow_no_motion_thres_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } +return com_rslt; +} + /*! + * @brief This API is used to read + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_slow_no_motion_select( +u8 *v_intr_slow_no_motion_select_u8) +{ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read slow no motion select*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_slow_no_motion_select_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT); + } +return com_rslt; +} + /*! + * @brief This API is used to write + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_slow_no_motion_select( +u8 v_intr_slow_no_motion_select_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; +} else { +if (v_intr_slow_no_motion_select_u8 <= BMI160_MAX_VALUE_NO_MOTION) { + /* write slow no motion select*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT, + v_intr_slow_no_motion_select_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } +} else { +com_rslt = E_BMI160_OUT_OF_RANGE; +} +} +return com_rslt; +} + /*! + * @brief This API is used to select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_significant_motion_select( +u8 *v_intr_significant_motion_select_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the significant or any motion interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_intr_significant_motion_select_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT); + } + return com_rslt; +} + /*! + * @brief This API is used to write, select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_significant_motion_select( +u8 v_intr_significant_motion_select_u8) +{ +/* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_intr_significant_motion_select_u8 <= + BMI160_MAX_VALUE_SIGNIFICANT_MOTION) { + /* write the significant or any motion interrupt*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT, + v_intr_significant_motion_select_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API is used to read + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_significant_motion_skip( +u8 *v_int_sig_mot_skip_u8) +{ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read significant skip time*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_int_sig_mot_skip_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP); + } + return com_rslt; +} + /*! + * @brief This API is used to write + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_significant_motion_skip( +u8 v_int_sig_mot_skip_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_int_sig_mot_skip_u8 <= BMI160_MAX_UNDER_SIG_MOTION) { + /* write significant skip time*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP, + v_int_sig_mot_skip_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API is used to read + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_significant_motion_proof( +u8 *v_significant_motion_proof_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read significant proof time */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_significant_motion_proof_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF); + } + return com_rslt; +} + /*! + * @brief This API is used to write + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_significant_motion_proof( +u8 v_significant_motion_proof_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_significant_motion_proof_u8 + <= BMI160_MAX_UNDER_SIG_MOTION) { + /* write significant proof time */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF, + v_significant_motion_proof_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API is used to get the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_DURN_50MS + * 0x01 | BMI160_TAP_DURN_100MS + * 0x03 | BMI160_TAP_DURN_150MS + * 0x04 | BMI160_TAP_DURN_200MS + * 0x05 | BMI160_TAP_DURN_250MS + * 0x06 | BMI160_TAP_DURN_375MS + * 0x07 | BMI160_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_durn( +u8 *v_tap_durn_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_durn_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_INTR_TAP_0_INTR_TAP_DURN); + } + return com_rslt; +} +/*! + * @brief This API is used to write the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_DURN_50MS + * 0x01 | BMI160_TAP_DURN_100MS + * 0x03 | BMI160_TAP_DURN_150MS + * 0x04 | BMI160_TAP_DURN_200MS + * 0x05 | BMI160_TAP_DURN_250MS + * 0x06 | BMI160_TAP_DURN_375MS + * 0x07 | BMI160_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_durn( +u8 v_tap_durn_u8) +{ + u8 v_data_u8 = BMI160_INIT_VALUE; + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_tap_durn_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_tap_durn_u8 <= BMI160_MAX_TAP_TURN) { + switch (v_tap_durn_u8) { + case BMI160_TAP_DURN_50MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_50MS; + break; + case BMI160_TAP_DURN_100MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_100MS; + break; + case BMI160_TAP_DURN_150MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_150MS; + break; + case BMI160_TAP_DURN_200MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_200MS; + break; + case BMI160_TAP_DURN_250MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_250MS; + break; + case BMI160_TAP_DURN_375MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_375MS; + break; + case BMI160_TAP_DURN_500MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_500MS; + break; + case BMI160_TAP_DURN_700MS: + v_data_tap_durn_u8 = BMI160_TAP_DURN_700MS; + break; + default: + break; + } + /* write tap duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_TAP_0_INTR_TAP_DURN, + v_data_tap_durn_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_DURN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_SHOCK_50MS + * 0x01 | BMI160_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_shock( +u8 *v_tap_shock_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap shock duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_shock_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK); + } + return com_rslt; +} + /*! + * @brief This API write the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_SHOCK_50MS + * 0x01 | BMI160_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_shock(u8 v_tap_shock_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_tap_shock_u8 <= BMI160_MAX_VALUE_TAP_SHOCK) { + /* write tap shock duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK, + v_tap_shock_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_QUIET_30MS + * 0x01 | BMI160_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_quiet( +u8 *v_tap_quiet_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap quiet duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_quiet_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET); + } + return com_rslt; +} +/*! + * @brief This API write + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_QUIET_30MS + * 0x01 | BMI160_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_quiet(u8 v_tap_quiet_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_tap_quiet_u8 <= BMI160_MAX_VALUE_TAP_QUIET) { + /* write tap quiet duration*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET, + v_tap_quiet_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_thres( +u8 *v_tap_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read tap threshold*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_1_INTR_TAP_THRES__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_tap_thres_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_TAP_1_INTR_TAP_THRES); + } + return com_rslt; +} + /*! + * @brief This API write Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_thres( +u8 v_tap_thres_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write tap threshold*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_1_INTR_TAP_THRES__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_TAP_1_INTR_TAP_THRES, + v_tap_thres_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_TAP_1_INTR_TAP_THRES__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read the threshold for orientation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mode_u8 : The value of threshold for orientation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_mode( +u8 *v_orient_mode_u8) +{ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read orientation threshold*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_mode_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE); + } + return com_rslt; +} + /*! + * @brief This API write the threshold for orientation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mode_u8 : The value of threshold for orientation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_mode( +u8 v_orient_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_orient_mode_u8 <= BMI160_MAX_ORIENT_MODE) { + /* write orientation threshold*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE, + v_orient_mode_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read the orient blocking mode + * that is used for the generation of the orientation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_blocking_u8 : The value of orient blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_blocking( +u8 *v_orient_blocking_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read orient blocking mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_blocking_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING); + } + return com_rslt; +} +/*! + * @brief This API write the orient blocking mode + * that is used for the generation of the orientation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_blocking_u8 : The value of orient blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_blocking( +u8 v_orient_blocking_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_orient_blocking_u8 <= BMI160_MAX_ORIENT_BLOCKING) { + /* write orient blocking mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING, + v_orient_blocking_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} +return com_rslt; +} +/*! + * @brief This API read Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_hyst_u8 : The value of orient hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_hyst( +u8 *v_orient_hyst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read orient hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_hyst_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST); + } + return com_rslt; +} +/*! + * @brief This API write Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_hyst_u8 : The value of orient hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_hyst( +u8 v_orient_hyst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write orient hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST, + v_orient_hyst_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_theta( +u8 *v_orient_theta_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read Orient blocking angle*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_theta_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA); + } + return com_rslt; +} + /*! + * @brief This API write Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_theta( +u8 v_orient_theta_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_orient_theta_u8 <= BMI160_MAX_ORIENT_THETA) { + /* write Orient blocking angle*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA, + v_orient_theta_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} +return com_rslt; +} +/*! + * @brief This API read orient change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_ud_u8 : The value of orient change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orientation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_ud_enable( +u8 *v_orient_ud_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read orient up/down enable*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_ud_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write orient change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_ud_u8 : The value of orient change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orientation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_ud_enable( +u8 v_orient_ud_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_orient_ud_u8 <= BMI160_MAX_VALUE_ORIENT_UD) { + /* write orient up/down enable */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE, + v_orient_ud_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API read orientation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_axes_u8 : The value of orient axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_ax_noex + * 0x01 | x = y, y = z, z = x|orient_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_axes_enable( +u8 *v_orient_axes_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read orientation axes changes */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_orient_axes_u8 = BMI160_GET_BITSLICE + (v_data_u8, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX); + } + return com_rslt; +} + /*! + * @brief This API write orientation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_axes_u8 : The value of orient axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_ax_noex + * 0x01 | x = y, y = z, z = x|orient_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_axes_enable( +u8 v_orient_axes_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_orient_axes_u8 <= BMI160_MAX_VALUE_ORIENT_AXES) { + /*write orientation axes changes */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX, + v_orient_axes_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} +return com_rslt; +} + /*! + * @brief This API read Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat_theta( +u8 *v_flat_theta_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read Flat angle*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_theta_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA); + } + return com_rslt; +} + /*! + * @brief This API write Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat_theta( +u8 v_flat_theta_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_flat_theta_u8 <= BMI160_MAX_FLAT_THETA) { + /* write Flat angle */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA, + v_flat_theta_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat_hold( +u8 *v_flat_hold_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read flat hold time*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_hold_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD); + } + return com_rslt; +} +/*! + * @brief This API write Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat_hold( +u8 v_flat_hold_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_flat_hold_u8 <= BMI160_MAX_FLAT_HOLD) { + /* write flat hold time*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD, + v_flat_hold_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat_hyst( +u8 *v_flat_hyst_u8) +{ + /* variable used to return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the flat hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_flat_hyst_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST); + } + return com_rslt; +} +/*! + * @brief This API write flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat_hyst( +u8 v_flat_hyst_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_flat_hyst_u8 <= BMI160_MAX_FLAT_HYST) { + /* read the flat hysteresis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST, + v_flat_hyst_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_accel_z(u8 *v_foc_accel_z_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel offset compensation for z axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_accel_z_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_Z); + } + return com_rslt; +} + /*! + * @brief This API write accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_accel_z( +u8 v_foc_accel_z_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write the accel offset compensation for z axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_Z, + v_foc_accel_z_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API read accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_accel_y(u8 *v_foc_accel_y_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel offset compensation for y axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_accel_y_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_Y); + } + return com_rslt; +} +/*! + * @brief This API write accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x02 | -1g + * 0x03 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_accel_y(u8 v_foc_accel_y_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_foc_accel_y_u8 <= BMI160_MAX_ACCEL_FOC) { + /* write the accel offset compensation for y axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_Y, + v_foc_accel_y_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x02 | -1g + * 0x03 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_accel_x(u8 *v_foc_accel_x_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the accel offset compensation for x axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_accel_x_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_X); + } + return com_rslt; +} +/*! + * @brief This API write accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_accel_x(u8 v_foc_accel_x_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_foc_accel_x_u8 <= BMI160_MAX_ACCEL_FOC) { + /* write the accel offset compensation for x axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_X, + v_foc_accel_x_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API writes accel fast offset compensation + * from the register 0x69 bit 0 to 5 + * @brief This API writes each axis individually + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_u8: The value of accel offset compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_axis_u8: The value of accel offset axis selection + * value | axis + * ----------|------------------- + * 0 | FOC_X_AXIS + * 1 | FOC_Y_AXIS + * 2 | FOC_Z_AXIS + * + * @param v_accel_offset_s8: The accel offset value + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_foc_trigger(u8 v_axis_u8, +u8 v_foc_accel_u8, s8 *v_accel_offset_s8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +s8 v_status_s8 = SUCCESS; +u8 v_timeout_u8 = BMI160_INIT_VALUE; +s8 v_foc_accel_offset_x_s8 = BMI160_INIT_VALUE; +s8 v_foc_accel_offset_y_s8 = BMI160_INIT_VALUE; +s8 v_foc_accel_offset_z_s8 = BMI160_INIT_VALUE; +u8 focstatus = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; +} else { + v_status_s8 = bmi160_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + switch (v_axis_u8) { + case FOC_X_AXIS: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_X, + v_foc_accel_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the + FOC need to write + 0x03 in the register 0x7e*/ + com_rslt += + bmi160_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += + bmi160_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH + && v_timeout_u8 < + BMI160_MAXIMUM_TIMEOUT)) { + p_bmi160->delay_msec( + BMI160_DELAY_SETTLING_TIME); + com_rslt = bmi160_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == BMI160_FOC_STAT_HIGH)) { + com_rslt += + bmi160_get_accel_offset_compensation_xaxis( + &v_foc_accel_offset_x_s8); + *v_accel_offset_s8 = + v_foc_accel_offset_x_s8; + } + break; + case FOC_Y_AXIS: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_Y, + v_foc_accel_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC + need to write 0x03 + in the register 0x7e*/ + com_rslt += + bmi160_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += + bmi160_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH + && v_timeout_u8 < + BMI160_MAXIMUM_TIMEOUT)) { + p_bmi160->delay_msec( + BMI160_DELAY_SETTLING_TIME); + com_rslt = bmi160_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == BMI160_FOC_STAT_HIGH)) { + com_rslt += + bmi160_get_accel_offset_compensation_yaxis( + &v_foc_accel_offset_y_s8); + *v_accel_offset_s8 = + v_foc_accel_offset_y_s8; + } + break; + case FOC_Z_AXIS: + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FOC_ACCEL_Z, + v_foc_accel_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC need to write + 0x03 in the register 0x7e*/ + com_rslt += + bmi160_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += + bmi160_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH + && v_timeout_u8 < + BMI160_MAXIMUM_TIMEOUT)) { + p_bmi160->delay_msec( + BMI160_DELAY_SETTLING_TIME); + com_rslt = bmi160_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == BMI160_FOC_STAT_HIGH)) { + com_rslt += + bmi160_get_accel_offset_compensation_zaxis( + &v_foc_accel_offset_z_s8); + *v_accel_offset_s8 = + v_foc_accel_offset_z_s8; + } + break; + default: + break; + } + } else { + com_rslt = ERROR; + } +} +return com_rslt; +} +/*! + * @brief This API write fast accel offset compensation + * it writes all axis together.To the register 0x69 bit 0 to 5 + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_x_u8: The value of accel offset x compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_y_u8: The value of accel offset y compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_z_u8: The value of accel offset z compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_accel_off_x_s8: The value of accel offset x axis + * @param v_accel_off_y_s8: The value of accel offset y axis + * @param v_accel_off_z_s8: The value of accel offset z axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_accel_foc_trigger_xyz(u8 v_foc_accel_x_u8, +u8 v_foc_accel_y_u8, u8 v_foc_accel_z_u8, s8 *v_accel_off_x_s8, +s8 *v_accel_off_y_s8, s8 *v_accel_off_z_s8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 focx = BMI160_INIT_VALUE; +u8 focy = BMI160_INIT_VALUE; +u8 focz = BMI160_INIT_VALUE; +s8 v_foc_accel_offset_x_s8 = BMI160_INIT_VALUE; +s8 v_foc_accel_offset_y_s8 = BMI160_INIT_VALUE; +s8 v_foc_accel_offset_z_s8 = BMI160_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +u8 v_timeout_u8 = BMI160_INIT_VALUE; +u8 focstatus = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + v_status_s8 = bmi160_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* foc x axis*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_X__REG, + &focx, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + focx = BMI160_SET_BITSLICE(focx, + BMI160_USER_FOC_ACCEL_X, + v_foc_accel_x_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_X__REG, + &focx, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + /* foc y axis*/ + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Y__REG, + &focy, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + focy = BMI160_SET_BITSLICE(focy, + BMI160_USER_FOC_ACCEL_Y, + v_foc_accel_y_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Y__REG, + &focy, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + /* foc z axis*/ + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Z__REG, + &focz, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + focz = BMI160_SET_BITSLICE(focz, + BMI160_USER_FOC_ACCEL_Z, + v_foc_accel_z_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_ACCEL_Z__REG, + &focz, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC need to + write 0x03 in the register 0x7e*/ + com_rslt += bmi160_set_command_register( + START_FOC_ACCEL_GYRO); + + com_rslt += bmi160_get_foc_rdy( + &focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH + && v_timeout_u8 < + BMI160_MAXIMUM_TIMEOUT)) { + p_bmi160->delay_msec( + BMI160_DELAY_SETTLING_TIME); + com_rslt = bmi160_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == BMI160_GEN_READ_WRITE_DATA_LENGTH)) { + com_rslt += + bmi160_get_accel_offset_compensation_xaxis( + &v_foc_accel_offset_x_s8); + *v_accel_off_x_s8 = + v_foc_accel_offset_x_s8; + com_rslt += + bmi160_get_accel_offset_compensation_yaxis( + &v_foc_accel_offset_y_s8); + *v_accel_off_y_s8 = + v_foc_accel_offset_y_s8; + com_rslt += + bmi160_get_accel_offset_compensation_zaxis( + &v_foc_accel_offset_z_s8); + *v_accel_off_z_s8 = + v_foc_accel_offset_z_s8; + } + } else { + com_rslt = ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_gyro_enable( +u8 *v_foc_gyro_u8) +{ + /* used for return the status of bus communication */ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the gyro fast offset enable*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_FOC_GYRO_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_foc_gyro_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_FOC_GYRO_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * @param v_gyro_off_x_s16 : The value of gyro fast offset x axis data + * @param v_gyro_off_y_s16 : The value of gyro fast offset y axis data + * @param v_gyro_off_z_s16 : The value of gyro fast offset z axis data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_gyro_enable( +u8 v_foc_gyro_u8, s16 *v_gyro_off_x_s16, +s16 *v_gyro_off_y_s16, s16 *v_gyro_off_z_s16) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +u8 v_timeout_u8 = BMI160_INIT_VALUE; +s16 offsetx = BMI160_INIT_VALUE; +s16 offsety = BMI160_INIT_VALUE; +s16 offsetz = BMI160_INIT_VALUE; +u8 focstatus = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + v_status_s8 = bmi160_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FOC_GYRO_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_FOC_GYRO_ENABLE, + v_foc_gyro_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_FOC_GYRO_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + /* trigger the FOC need to write 0x03 + in the register 0x7e*/ + com_rslt += bmi160_set_command_register + (START_FOC_ACCEL_GYRO); + + com_rslt += bmi160_get_foc_rdy(&focstatus); + if ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH)) { + while ((com_rslt != SUCCESS) || + (focstatus != BMI160_FOC_STAT_HIGH + && v_timeout_u8 < + BMI160_MAXIMUM_TIMEOUT)) { + p_bmi160->delay_msec( + BMI160_DELAY_SETTLING_TIME); + com_rslt = bmi160_get_foc_rdy( + &focstatus); + v_timeout_u8++; + } + } + if ((com_rslt == SUCCESS) && + (focstatus == BMI160_FOC_STAT_HIGH)) { + com_rslt += + bmi160_get_gyro_offset_compensation_xaxis + (&offsetx); + *v_gyro_off_x_s16 = offsetx; + + com_rslt += + bmi160_get_gyro_offset_compensation_yaxis + (&offsety); + *v_gyro_off_y_s16 = offsety; + + com_rslt += + bmi160_get_gyro_offset_compensation_zaxis( + &offsetz); + *v_gyro_off_z_s16 = offsetz; + } + } else { + com_rslt = ERROR; + } + } +return com_rslt; +} + /*! + * @brief This API read NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_nvm_prog_enable( +u8 *v_nvm_prog_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read NVM program*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_CONFIG_NVM_PROG_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_nvm_prog_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_CONFIG_NVM_PROG_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API write NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_nvm_prog_enable( +u8 v_nvm_prog_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_nvm_prog_u8 <= BMI160_MAX_VALUE_NVM_PROG) { + /* write the NVM program*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_CONFIG_NVM_PROG_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_CONFIG_NVM_PROG_ENABLE, + v_nvm_prog_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_CONFIG_NVM_PROG_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_spi3( +u8 *v_spi3_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read SPI mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_SPI3__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_spi3_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_SPI3); + } + return com_rslt; +} +/*! + * @brief This API write to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_spi3( +u8 v_spi3_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_spi3_u8 <= BMI160_MAX_VALUE_SPI3) { + /* write SPI mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_SPI3__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_SPI3, + v_spi3_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_SPI3__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_wdt_select( +u8 *v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read I2C watch dog timer */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_I2C_WDT_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_wdt_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_I2C_WDT_SELECT); + } + return com_rslt; +} +/*! + * @brief This API write I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_i2c_wdt_select( +u8 v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_i2c_wdt_u8 <= BMI160_MAX_VALUE_I2C_WDT) { + /* write I2C watch dog timer */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_I2C_WDT_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_I2C_WDT_SELECT, + v_i2c_wdt_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_I2C_WDT_SELECT__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_wdt_enable( +u8 *v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read i2c watch dog eneble */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_i2c_wdt_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_i2c_wdt_enable( +u8 v_i2c_wdt_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_i2c_wdt_u8 <= BMI160_MAX_VALUE_I2C_WDT) { + /* write i2c watch dog eneble */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE, + v_i2c_wdt_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_if_mode( +u8 *v_if_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read if mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_IF_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_if_mode_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_IF_MODE); + } + return com_rslt; +} +/*! + * @brief This API write I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_if_mode( +u8 v_if_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_if_mode_u8 <= BMI160_MAX_IF_MODE) { + /* write if mode*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_IF_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_IF_CONFIG_IF_MODE, + v_if_mode_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_IF_CONFIG_IF_MODE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_sleep_trigger( +u8 *v_gyro_sleep_trigger_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro sleep trigger */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SLEEP_TRIGGER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_sleep_trigger_u8 = + BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_SLEEP_TRIGGER); + } + return com_rslt; +} +/*! + * @brief This API write gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_sleep_trigger( +u8 v_gyro_sleep_trigger_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_gyro_sleep_trigger_u8 <= BMI160_MAX_GYRO_SLEEP_TIGGER) { + /* write gyro sleep trigger */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SLEEP_TRIGGER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_SLEEP_TRIGGER, + v_gyro_sleep_trigger_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SLEEP_TRIGGER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_wakeup_trigger( +u8 *v_gyro_wakeup_trigger_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro wakeup trigger */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_WAKEUP_TRIGGER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_wakeup_trigger_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_GYRO_WAKEUP_TRIGGER); + } + return com_rslt; +} +/*! + * @brief This API write gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_wakeup_trigger( +u8 v_gyro_wakeup_trigger_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_gyro_wakeup_trigger_u8 + <= BMI160_MAX_GYRO_WAKEUP_TRIGGER) { + /* write gyro wakeup trigger */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_WAKEUP_TRIGGER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_WAKEUP_TRIGGER, + v_gyro_wakeup_trigger_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_WAKEUP_TRIGGER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_sleep_state( +u8 *v_gyro_sleep_state_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro sleep state*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SLEEP_STATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_sleep_state_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_GYRO_SLEEP_STATE); + } + return com_rslt; +} +/*! + * @brief This API write Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_sleep_state( +u8 v_gyro_sleep_state_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_gyro_sleep_state_u8 <= BMI160_MAX_VALUE_SLEEP_STATE) { + /* write gyro sleep state*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SLEEP_STATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_SLEEP_STATE, + v_gyro_sleep_state_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SLEEP_STATE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_wakeup_intr( +u8 *v_gyro_wakeup_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro wakeup interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_WAKEUP_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_wakeup_intr_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_GYRO_WAKEUP_INTR); + } + return com_rslt; +} +/*! + * @brief This API write gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_wakeup_intr( +u8 v_gyro_wakeup_intr_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_gyro_wakeup_intr_u8 <= BMI160_MAX_VALUE_WAKEUP_INTR) { + /* write gyro wakeup interrupt */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_WAKEUP_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_WAKEUP_INTR, + v_gyro_wakeup_intr_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_WAKEUP_INTR__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_selftest_axis( +u8 *v_accel_selftest_axis_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read accel self test axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_SELFTEST_AXIS__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_selftest_axis_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_ACCEL_SELFTEST_AXIS); + } + return com_rslt; +} +/*! + * @brief This API write accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_selftest_axis( +u8 v_accel_selftest_axis_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_accel_selftest_axis_u8 + <= BMI160_MAX_ACCEL_SELFTEST_AXIS) { + /* write accel self test axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_SELFTEST_AXIS__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_SELFTEST_AXIS, + v_accel_selftest_axis_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_SELFTEST_AXIS__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_selftest_sign( +u8 *v_accel_selftest_sign_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read accel self test axis sign*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_SELFTEST_SIGN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_selftest_sign_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_ACCEL_SELFTEST_SIGN); + } + return com_rslt; +} +/*! + * @brief This API write accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_selftest_sign( +u8 v_accel_selftest_sign_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_accel_selftest_sign_u8 <= + BMI160_MAX_VALUE_SELFTEST_SIGN) { + /* write accel self test axis sign*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_SELFTEST_SIGN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_ACCEL_SELFTEST_SIGN, + v_accel_selftest_sign_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_ACCEL_SELFTEST_SIGN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_selftest_amp( +u8 *v_accel_selftest_amp_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read self test amplitude*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_SELFTEST_AMP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_selftest_amp_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_SELFTEST_AMP); + } + return com_rslt; +} +/*! + * @brief This API write accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_selftest_amp( +u8 v_accel_selftest_amp_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_accel_selftest_amp_u8 <= + BMI160_MAX_VALUE_SELFTEST_AMP) { + /* write self test amplitude*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_SELFTEST_AMP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_SELFTEST_AMP, + v_accel_selftest_amp_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_SELFTEST_AMP__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_selftest_start( +u8 *v_gyro_selftest_start_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro self test start */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SELFTEST_START__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_selftest_start_u8 = BMI160_GET_BITSLICE( + v_data_u8, + BMI160_USER_GYRO_SELFTEST_START); + } + return com_rslt; +} +/*! + * @brief This API write gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_selftest_start( +u8 v_gyro_selftest_start_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_gyro_selftest_start_u8 <= + BMI160_MAX_VALUE_SELFTEST_START) { + /* write gyro self test start */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SELFTEST_START__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_GYRO_SELFTEST_START, + v_gyro_selftest_start_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_GYRO_SELFTEST_START__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_spi_enable(u8 *v_spi_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read interface section*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_SPI_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_spi_enable_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_NV_CONFIG_SPI_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API write primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_spi_enable(u8 v_spi_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write interface section*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_SPI_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_NV_CONFIG_SPI_ENABLE, + v_spi_enable_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_SPI_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_spare0_trim(u8 *v_spare0_trim_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read spare zero*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_SPARE0__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_spare0_trim_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_NV_CONFIG_SPARE0); + } + return com_rslt; +} + /*! + * @brief This API write the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_spare0_trim(u8 v_spare0_trim_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write spare zero*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_SPARE0__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_NV_CONFIG_SPARE0, + v_spare0_trim_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_SPARE0__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + /*! + * @brief This API read the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_nvm_counter(u8 *v_nvm_counter_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read NVM counter*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_NVM_COUNTER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_nvm_counter_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_NV_CONFIG_NVM_COUNTER); + } + return com_rslt; +} + /*! + * @brief This API write the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_nvm_counter( +u8 v_nvm_counter_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write NVM counter*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_NVM_COUNTER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_NV_CONFIG_NVM_COUNTER, + v_nvm_counter_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_NV_CONFIG_NVM_COUNTER__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API read accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_compensation_xaxis( +s8 *v_accel_off_x_s8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read accel manual offset compensation of x axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_0_ACCEL_OFF_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_x_s8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_0_ACCEL_OFF_X); + } + return com_rslt; +} +/*! + * @brief This API write accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_compensation_xaxis( +s8 v_accel_off_x_s8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* enable accel offset */ + v_status_s8 = bmi160_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* write accel manual offset compensation of x axis*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_0_ACCEL_OFF_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE( + v_data_u8, + BMI160_USER_OFFSET_0_ACCEL_OFF_X, + v_accel_off_x_s8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_0_ACCEL_OFF_X__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = ERROR; + } + } + return com_rslt; +} +/*! + * @brief This API read accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_compensation_yaxis( +s8 *v_accel_off_y_s8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read accel manual offset compensation of y axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_1_ACCEL_OFF_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_y_s8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_1_ACCEL_OFF_Y); + } + return com_rslt; +} +/*! + * @brief This API write accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_compensation_yaxis( +s8 v_accel_off_y_s8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* enable accel offset */ + v_status_s8 = bmi160_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* write accel manual offset compensation of y axis*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_1_ACCEL_OFF_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE( + v_data_u8, + BMI160_USER_OFFSET_1_ACCEL_OFF_Y, + v_accel_off_y_s8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_1_ACCEL_OFF_Y__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = ERROR; + } + } + return com_rslt; +} +/*! + * @brief This API read accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_compensation_zaxis( +s8 *v_accel_off_z_s8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read accel manual offset compensation of z axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_2_ACCEL_OFF_Z__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_z_s8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_2_ACCEL_OFF_Z); + } + return com_rslt; +} +/*! + * @brief This API write accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_compensation_zaxis( +s8 v_accel_off_z_s8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + u8 v_status_s8 = SUCCESS; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* enable accel offset */ + v_status_s8 = bmi160_set_accel_offset_enable( + ACCEL_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + /* write accel manual offset + compensation of z axis*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_2_ACCEL_OFF_Z__REG, + &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_2_ACCEL_OFF_Z, + v_accel_off_z_s8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_2_ACCEL_OFF_Z__REG, + &v_data_u8, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = ERROR; + } + } + return com_rslt; +} +/*! + * @brief This API read gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_compensation_xaxis( +s16 *v_gyro_off_x_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data1_u8r = BMI160_INIT_VALUE; + u8 v_data2_u8r = BMI160_INIT_VALUE; + s16 v_data3_u8r, v_data4_u8r = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro offset x*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_3_GYRO_OFF_X__REG, + &v_data1_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = BMI160_GET_BITSLICE(v_data1_u8r, + BMI160_USER_OFFSET_3_GYRO_OFF_X); + com_rslt += p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_X__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = BMI160_GET_BITSLICE(v_data2_u8r, + BMI160_USER_OFFSET_6_GYRO_OFF_X); + v_data3_u8r = v_data2_u8r + << BMI160_SHIFT_BIT_POSITION_BY_14_BITS; + v_data4_u8r = v_data1_u8r + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS; + v_data3_u8r = v_data3_u8r | v_data4_u8r; + *v_gyro_off_x_s16 = v_data3_u8r + >> BMI160_SHIFT_BIT_POSITION_BY_06_BITS; + } + return com_rslt; +} +/*! + * @brief This API write gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_compensation_xaxis( +s16 v_gyro_off_x_s16) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data1_u8r, v_data2_u8r = BMI160_INIT_VALUE; +u16 v_data3_u8r = BMI160_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write gyro offset x*/ + v_status_s8 = bmi160_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + if (v_status_s8 == SUCCESS) { + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_3_GYRO_OFF_X__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data1_u8r = + ((s8) (v_gyro_off_x_s16 & + BMI160_GYRO_MANUAL_OFFSET_0_7)); + v_data2_u8r = BMI160_SET_BITSLICE( + v_data2_u8r, + BMI160_USER_OFFSET_3_GYRO_OFF_X, + v_data1_u8r); + /* write 0x74 bit 0 to 7*/ + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_3_GYRO_OFF_X__REG, + &v_data2_u8r, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + com_rslt += p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_X__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u8r = + (u16) (v_gyro_off_x_s16 & + BMI160_GYRO_MANUAL_OFFSET_8_9); + v_data1_u8r = (u8)(v_data3_u8r + >> BMI160_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = BMI160_SET_BITSLICE( + v_data2_u8r, + BMI160_USER_OFFSET_6_GYRO_OFF_X, + v_data1_u8r); + /* write 0x77 bit 0 and 1*/ + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_X__REG, + &v_data2_u8r, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + return ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_compensation_yaxis( +s16 *v_gyro_off_y_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data1_u8r = BMI160_INIT_VALUE; + u8 v_data2_u8r = BMI160_INIT_VALUE; + s16 v_data3_u8r, v_data4_u8r = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro offset y*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_4_GYRO_OFF_Y__REG, + &v_data1_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = BMI160_GET_BITSLICE(v_data1_u8r, + BMI160_USER_OFFSET_4_GYRO_OFF_Y); + com_rslt += p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_Y__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = BMI160_GET_BITSLICE(v_data2_u8r, + BMI160_USER_OFFSET_6_GYRO_OFF_Y); + v_data3_u8r = v_data2_u8r + << BMI160_SHIFT_BIT_POSITION_BY_14_BITS; + v_data4_u8r = v_data1_u8r + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS; + v_data3_u8r = v_data3_u8r | v_data4_u8r; + *v_gyro_off_y_s16 = v_data3_u8r + >> BMI160_SHIFT_BIT_POSITION_BY_06_BITS; + } + return com_rslt; +} +/*! + * @brief This API write gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_compensation_yaxis( +s16 v_gyro_off_y_s16) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data1_u8r, v_data2_u8r = BMI160_INIT_VALUE; +u16 v_data3_u8r = BMI160_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* enable gyro offset bit */ + v_status_s8 = bmi160_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + /* write gyro offset y*/ + if (v_status_s8 == SUCCESS) { + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_4_GYRO_OFF_Y__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data1_u8r = + ((s8) (v_gyro_off_y_s16 & + BMI160_GYRO_MANUAL_OFFSET_0_7)); + v_data2_u8r = BMI160_SET_BITSLICE( + v_data2_u8r, + BMI160_USER_OFFSET_4_GYRO_OFF_Y, + v_data1_u8r); + /* write 0x75 bit 0 to 7*/ + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_4_GYRO_OFF_Y__REG, + &v_data2_u8r, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + com_rslt += p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_Y__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u8r = + (u16) (v_gyro_off_y_s16 & + BMI160_GYRO_MANUAL_OFFSET_8_9); + v_data1_u8r = (u8)(v_data3_u8r + >> BMI160_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = BMI160_SET_BITSLICE( + v_data2_u8r, + BMI160_USER_OFFSET_6_GYRO_OFF_Y, + v_data1_u8r); + /* write 0x77 bit 2 and 3*/ + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_Y__REG, + &v_data2_u8r, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + return ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_compensation_zaxis( +s16 *v_gyro_off_z_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data1_u8r = BMI160_INIT_VALUE; + u8 v_data2_u8r = BMI160_INIT_VALUE; + s16 v_data3_u8r, v_data4_u8r = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro manual offset z axis*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_5_GYRO_OFF_Z__REG, + &v_data1_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = BMI160_GET_BITSLICE + (v_data1_u8r, + BMI160_USER_OFFSET_5_GYRO_OFF_Z); + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_Z__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = BMI160_GET_BITSLICE( + v_data2_u8r, + BMI160_USER_OFFSET_6_GYRO_OFF_Z); + v_data3_u8r = v_data2_u8r + << BMI160_SHIFT_BIT_POSITION_BY_14_BITS; + v_data4_u8r = v_data1_u8r + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS; + v_data3_u8r = v_data3_u8r | v_data4_u8r; + *v_gyro_off_z_s16 = v_data3_u8r + >> BMI160_SHIFT_BIT_POSITION_BY_06_BITS; + } + return com_rslt; +} +/*! + * @brief This API write gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_compensation_zaxis( +s16 v_gyro_off_z_s16) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data1_u8r, v_data2_u8r = BMI160_INIT_VALUE; +u16 v_data3_u8r = BMI160_INIT_VALUE; +u8 v_status_s8 = SUCCESS; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* enable gyro offset*/ + v_status_s8 = bmi160_set_gyro_offset_enable( + GYRO_OFFSET_ENABLE); + /* write gyro manual offset z axis*/ + if (v_status_s8 == SUCCESS) { + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_5_GYRO_OFF_Z__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data1_u8r = + ((u8) (v_gyro_off_z_s16 & + BMI160_GYRO_MANUAL_OFFSET_0_7)); + v_data2_u8r = BMI160_SET_BITSLICE( + v_data2_u8r, + BMI160_USER_OFFSET_5_GYRO_OFF_Z, + v_data1_u8r); + /* write 0x76 bit 0 to 7*/ + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_5_GYRO_OFF_Z__REG, + &v_data2_u8r, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + com_rslt += p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_Z__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u8r = + (u16) (v_gyro_off_z_s16 & + BMI160_GYRO_MANUAL_OFFSET_8_9); + v_data1_u8r = (u8)(v_data3_u8r + >> BMI160_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = BMI160_SET_BITSLICE( + v_data2_u8r, + BMI160_USER_OFFSET_6_GYRO_OFF_Z, + v_data1_u8r); + /* write 0x77 bit 4 and 5*/ + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_Z__REG, + &v_data2_u8r, + BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + return ERROR; + } + } +return com_rslt; +} +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_enable( +u8 *v_accel_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read accel offset enable */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_accel_off_enable_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE); + } + return com_rslt; +} +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_enable( +u8 v_accel_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write accel offset enable */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE, + v_accel_off_enable_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_enable( +u8 *v_gyro_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read gyro offset*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_gyro_off_enable_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_6_GYRO_OFF_EN); + } + return com_rslt; +} +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_enable( +u8 v_gyro_off_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write gyro offset*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_OFFSET_6_GYRO_OFF_EN, + v_gyro_off_enable_u8); + com_rslt += p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_USER_OFFSET_6_GYRO_OFF_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} +/*! + * @brief This API reads step counter value + * form the register 0x78 and 0x79 + * + * + * + * + * @param v_step_cnt_s16 : The value of step counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_step_count(s16 *v_step_cnt_s16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* array having the step counter LSB and MSB data + v_data_u8[0] - LSB + v_data_u8[1] - MSB*/ + u8 a_data_u8r[BMI160_STEP_COUNT_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read step counter */ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STEP_COUNT_LSB__REG, + a_data_u8r, BMI160_STEP_COUNTER_LENGTH); + + *v_step_cnt_s16 = (s16) + ((((s32)((s8)a_data_u8r[BMI160_STEP_COUNT_MSB_BYTE])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8r[BMI160_STEP_COUNT_LSB_BYTE])); + } + return com_rslt; +} + /*! + * @brief This API Reads + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : The value of step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_step_config( +u16 *v_step_config_u16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data1_u8r = BMI160_INIT_VALUE; + u8 v_data2_u8r = BMI160_INIT_VALUE; + u16 v_data3_u8r = BMI160_INIT_VALUE; + /* Read the 0 to 7 bit*/ + com_rslt = + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ZERO__REG, + &v_data1_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* Read the 8 to 10 bit*/ + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ONE_CNF1__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data2_u8r = BMI160_GET_BITSLICE(v_data2_u8r, + BMI160_USER_STEP_CONFIG_ONE_CNF1); + v_data3_u8r = ((u16)((((u32) + ((u8)v_data2_u8r)) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | (v_data1_u8r))); + /* Read the 11 to 14 bit*/ + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ONE_CNF2__REG, + &v_data1_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data1_u8r = BMI160_GET_BITSLICE(v_data1_u8r, + BMI160_USER_STEP_CONFIG_ONE_CNF2); + *v_step_config_u16 = ((u16)((((u32) + ((u8)v_data1_u8r)) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | (v_data3_u8r))); + + return com_rslt; +} + /*! + * @brief This API write + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : + * the value of Enable step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_config( +u16 v_step_config_u16) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data1_u8r = BMI160_INIT_VALUE; + u8 v_data2_u8r = BMI160_INIT_VALUE; + u16 v_data3_u16 = BMI160_INIT_VALUE; + + /* write the 0 to 7 bit*/ + v_data1_u8r = (u8)(v_step_config_u16 & + BMI160_STEP_CONFIG_0_7); + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ZERO__REG, + &v_data1_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* write the 8 to 10 bit*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ONE_CNF1__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u16 = (u16) (v_step_config_u16 & + BMI160_STEP_CONFIG_8_10); + v_data1_u8r = (u8)(v_data3_u16 + >> BMI160_SHIFT_BIT_POSITION_BY_08_BITS); + v_data2_u8r = BMI160_SET_BITSLICE(v_data2_u8r, + BMI160_USER_STEP_CONFIG_ONE_CNF1, v_data1_u8r); + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ONE_CNF1__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + /* write the 11 to 14 bit*/ + com_rslt += p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ONE_CNF2__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data3_u16 = (u16) (v_step_config_u16 & + BMI160_STEP_CONFIG_11_14); + v_data1_u8r = (u8)(v_data3_u16 + >> BMI160_SHIFT_BIT_POSITION_BY_12_BITS); + v_data2_u8r = BMI160_SET_BITSLICE(v_data2_u8r, + BMI160_USER_STEP_CONFIG_ONE_CNF2, v_data1_u8r); + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_ONE_CNF2__REG, + &v_data2_u8r, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + + return com_rslt; +} + /*! + * @brief This API read enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_step_counter_enable( +u8 *v_step_counter_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the step counter */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_step_counter_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE); + } + return com_rslt; +} + /*! + * @brief This API write enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_counter_enable(u8 v_step_counter_u8) +{ +/* variable used for return the status of communication result*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_data_u8 = BMI160_INIT_VALUE; +/* check the p_bmi160 structure as NULL*/ +if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; +} else { + if (v_step_counter_u8 <= BMI160_MAX_GYRO_STEP_COUNTER) { + /* write the step counter */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE, + v_step_counter_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } +} + return com_rslt; +} + /*! + * @brief This API set Step counter modes + * + * + * @param v_step_mode_u8 : The value of step counter mode + * value | mode + * ----------|----------- + * 0 | BMI160_STEP_NORMAL_MODE + * 1 | BMI160_STEP_SENSITIVE_MODE + * 2 | BMI160_STEP_ROBUST_MODE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_mode(u8 v_step_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + + switch (v_step_mode_u8) { + case BMI160_STEP_NORMAL_MODE: + com_rslt = bmi160_set_step_config( + STEP_CONFIG_NORMAL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_STEP_SENSITIVE_MODE: + com_rslt = bmi160_set_step_config( + STEP_CONFIG_SENSITIVE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_STEP_ROBUST_MODE: + com_rslt = bmi160_set_step_config( + STEP_CONFIG_ROBUST); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + + return com_rslt; +} +/*! + * @brief This API used to trigger the signification motion + * interrupt + * + * + * @param v_significant_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | BMI160_MAP_INTR1 + * 1 | BMI160_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_map_significant_motion_intr( +u8 v_significant_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_sig_motion_u8 = BMI160_INIT_VALUE; + u8 v_data_u8 = BMI160_INIT_VALUE; + u8 v_any_motion_intr1_stat_u8 = BMI160_ENABLE_ANY_MOTION_INTR1; + u8 v_any_motion_intr2_stat_u8 = BMI160_ENABLE_ANY_MOTION_INTR2; + u8 v_any_motion_axis_stat_u8 = BMI160_ENABLE_ANY_MOTION_AXIS; + /* enable the significant motion interrupt */ + com_rslt = bmi160_get_intr_significant_motion_select(&v_sig_motion_u8); + if (v_sig_motion_u8 != BMI160_SIG_MOTION_STAT_HIGH) + com_rslt += bmi160_set_intr_significant_motion_select( + BMI160_SIG_MOTION_INTR_ENABLE); + switch (v_significant_u8) { + case BMI160_MAP_INTR1: + /* interrupt */ + com_rslt += bmi160_read_reg( + BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_intr1_stat_u8; + /* map the signification interrupt to any-motion interrupt1*/ + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* axis*/ + com_rslt = bmi160_read_reg(BMI160_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_axis_stat_u8; + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + + case BMI160_MAP_INTR2: + /* map the signification interrupt to any-motion interrupt2*/ + com_rslt += bmi160_read_reg( + BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_intr2_stat_u8; + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* axis*/ + com_rslt = bmi160_read_reg(BMI160_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_any_motion_axis_stat_u8; + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_ENABLE_0_ADDR, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + + } + return com_rslt; +} +/*! + * @brief This API used to trigger the step detector + * interrupt + * + * + * @param v_step_detector_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | BMI160_MAP_INTR1 + * 1 | BMI160_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_map_step_detector_intr( +u8 v_step_detector_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_step_det_u8 = BMI160_INIT_VALUE; + u8 v_data_u8 = BMI160_INIT_VALUE; + u8 v_low_g_intr_u81_stat_u8 = BMI160_LOW_G_INTR_STAT; + u8 v_low_g_intr_u82_stat_u8 = BMI160_LOW_G_INTR_STAT; + u8 v_low_g_enable_u8 = BMI160_ENABLE_LOW_G; + /* read the v_status_s8 of step detector interrupt*/ + com_rslt = bmi160_get_step_detector_enable(&v_step_det_u8); + if (v_step_det_u8 != BMI160_STEP_DET_STAT_HIGH) + com_rslt += bmi160_set_step_detector_enable( + BMI160_STEP_DETECT_INTR_ENABLE); + switch (v_step_detector_u8) { + case BMI160_MAP_INTR1: + com_rslt += bmi160_read_reg( + BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_intr_u81_stat_u8; + /* map the step detector interrupt + to Low-g interrupt 1*/ + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Enable the Low-g interrupt*/ + com_rslt = bmi160_read_reg( + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_enable_u8; + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_MAP_INTR2: + /* map the step detector interrupt + to Low-g interrupt 1*/ + com_rslt += bmi160_read_reg( + BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_intr_u82_stat_u8; + + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Enable the Low-g interrupt*/ + com_rslt = bmi160_read_reg( + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_data_u8 |= v_low_g_enable_u8; + com_rslt += bmi160_write_reg( + BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + return com_rslt; +} + /*! + * @brief This API used to clear the step counter interrupt + * interrupt + * + * + * @param : None + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_clear_step_counter(void) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* clear the step counter*/ + com_rslt = bmi160_set_command_register(RESET_STEP_COUNTER); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + + return com_rslt; + +} + /*! + * @brief This API writes value to the register 0x7E bit 0 to 7 + * + * + * @param v_command_reg_u8 : The value to write command register + * value | Description + * ---------|-------------------------------------------------------- + * 0x00 | Reserved + * 0x03 | Starts fast offset calibration for the accel and gyro + * 0x10 | Sets the PMU mode for the Accelerometer to suspend + * 0x11 | Sets the PMU mode for the Accelerometer to normal + * 0x12 | Sets the PMU mode for the Accelerometer Lowpower + * 0x14 | Sets the PMU mode for the Gyroscope to suspend + * 0x15 | Sets the PMU mode for the Gyroscope to normal + * 0x16 | Reserved + * 0x17 | Sets the PMU mode for the Gyroscope to fast start-up + * 0x18 | Sets the PMU mode for the Magnetometer to suspend + * 0x19 | Sets the PMU mode for the Magnetometer to normal + * 0x1A | Sets the PMU mode for the Magnetometer to Lowpower + * 0xB0 | Clears all data in the FIFO + * 0xB1 | Resets the interrupt engine + * 0xB2 | step_cnt_clr Clears the step counter + * 0xB6 | Triggers a reset + * 0x37 | See extmode_en_last + * 0x9A | See extmode_en_last + * 0xC0 | Enable the extended mode + * 0xC4 | Erase NVM cell + * 0xC8 | Load NVM cell + * 0xF0 | Reset acceleration data path + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_command_register(u8 v_command_reg_u8) +{ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write command register */ + com_rslt = p_bmi160->BMI160_BUS_WRITE_FUNC( + p_bmi160->dev_addr, + BMI160_CMD_COMMANDS__REG, + &v_command_reg_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + return com_rslt; +} + /*! + * @brief This API read target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_target_page(u8 *v_target_page_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the page*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_CMD_TARGET_PAGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_target_page_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_CMD_TARGET_PAGE); + } + return com_rslt; +} + /*! + * @brief This API write target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_target_page(u8 v_target_page_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_target_page_u8 <= BMI160_MAX_TARGET_PAGE) { + /* write the page*/ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_CMD_TARGET_PAGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_CMD_TARGET_PAGE, + v_target_page_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_CMD_TARGET_PAGE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_paging_enable(u8 *v_page_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the page enable */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_CMD_PAGING_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_page_enable_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_CMD_PAGING_EN); + } + return com_rslt; +} + /*! + * @brief This API write page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_paging_enable( +u8 v_page_enable_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + if (v_page_enable_u8 <= BMI160_MAX_VALUE_PAGE) { + /* write the page enable */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_CMD_PAGING_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_CMD_PAGING_EN, + v_page_enable_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_CMD_PAGING_EN__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } else { + com_rslt = E_BMI160_OUT_OF_RANGE; + } + } + return com_rslt; +} + /*! + * @brief This API read + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_pullup_configuration( +u8 *v_control_pullup_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read pull up value */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC( + p_bmi160->dev_addr, + BMI160_COM_C_TRIM_FIVE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + *v_control_pullup_u8 = BMI160_GET_BITSLICE(v_data_u8, + BMI160_COM_C_TRIM_FIVE); + } + return com_rslt; + +} + /*! + * @brief This API write + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_pullup_configuration( +u8 v_control_pullup_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* write pull up value */ + com_rslt = p_bmi160->BMI160_BUS_READ_FUNC + (p_bmi160->dev_addr, + BMI160_COM_C_TRIM_FIVE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + if (com_rslt == SUCCESS) { + v_data_u8 = + BMI160_SET_BITSLICE(v_data_u8, + BMI160_COM_C_TRIM_FIVE, + v_control_pullup_u8); + com_rslt += + p_bmi160->BMI160_BUS_WRITE_FUNC + (p_bmi160->dev_addr, + BMI160_COM_C_TRIM_FIVE__REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + } + } + return com_rslt; +} + +/*! + * @brief This function used for read the compensated value of mag + * Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_compensate_xyz( +struct bmi160_mag_xyz_s32_t *mag_comp_xyz) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + struct bmi160_mag_xyzr_t mag_xyzr; + com_rslt = bmi160_read_mag_xyzr(&mag_xyzr); + if (com_rslt) + return com_rslt; + /* Compensation for X axis */ + mag_comp_xyz->x = bmi160_bmm150_mag_compensate_X( + mag_xyzr.x, mag_xyzr.r); + + /* Compensation for Y axis */ + mag_comp_xyz->y = bmi160_bmm150_mag_compensate_Y( + mag_xyzr.y, mag_xyzr.r); + + /* Compensation for Z axis */ + mag_comp_xyz->z = bmi160_bmm150_mag_compensate_Z( + mag_xyzr.z, mag_xyzr.r); + + return com_rslt; +} + +/*! + * @brief This function used for read the compensated value of mag + * Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_compensate_xyz_raw( +struct bmi160_mag_xyz_s32_t *mag_comp_xyz, struct bmi160_mag_xyzr_t mag_xyzr) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + + /* Compensation for X axis */ + mag_comp_xyz->x = bmi160_bmm150_mag_compensate_X( + mag_xyzr.x, mag_xyzr.r); + + /* Compensation for Y axis */ + mag_comp_xyz->y = bmi160_bmm150_mag_compensate_Y( + mag_xyzr.y, mag_xyzr.r); + + /* Compensation for Z axis */ + mag_comp_xyz->z = bmi160_bmm150_mag_compensate_Z( + mag_xyzr.z, mag_xyzr.r); + + return com_rslt; +} +/*! + * @brief This API used to get the compensated BMM150-X data + * the out put of X as s32 + * Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_x_s16 : The value of mag raw X data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated X data value output as s32 + * + */ +s32 bmi160_bmm150_mag_compensate_X(s16 v_mag_data_x_s16, u16 v_data_r_u16) +{ +s32 inter_retval = BMI160_INIT_VALUE; +/* no overflow */ +if (v_mag_data_x_s16 != BMI160_MAG_FLIP_OVERFLOW_ADCVAL) { + if ((v_data_r_u16 != 0) + && (mag_trim.dig_xyz1 != 0)) { + inter_retval = ((s32)(((u16) + ((((s32)mag_trim.dig_xyz1) + << BMI160_SHIFT_BIT_POSITION_BY_14_BITS)/ + (v_data_r_u16 != 0 ? + v_data_r_u16 : mag_trim.dig_xyz1))) - + ((u16)0x4000))); + } else { + inter_retval = BMI160_MAG_OVERFLOW_OUTPUT; + return inter_retval; + } + inter_retval = ((s32)((((s32)v_mag_data_x_s16) * + ((((((((s32)mag_trim.dig_xy2) * + ((((s32)inter_retval) * + ((s32)inter_retval)) + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS)) + + (((s32)inter_retval) * + ((s32)(((s16)mag_trim.dig_xy1) + << BMI160_SHIFT_BIT_POSITION_BY_07_BITS)))) + >> BMI160_SHIFT_BIT_POSITION_BY_09_BITS) + + ((s32)0x100000)) * + ((s32)(((s16)mag_trim.dig_x2) + + ((s16)0xA0)))) + >> BMI160_SHIFT_BIT_POSITION_BY_12_BITS)) + >> BMI160_SHIFT_BIT_POSITION_BY_13_BITS)) + + (((s16)mag_trim.dig_x1) + << BMI160_SHIFT_BIT_POSITION_BY_03_BITS); + /* check the overflow output */ + if (inter_retval == (s32)BMI160_MAG_OVERFLOW_OUTPUT) + inter_retval = BMI160_MAG_OVERFLOW_OUTPUT_S32; +} else { + /* overflow */ + inter_retval = BMI160_MAG_OVERFLOW_OUTPUT; +} +return inter_retval; +} +/*! + * @brief This API used to get the compensated BMM150-Y data + * the out put of Y as s32 + * Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_y_s16 : The value of mag raw Y data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Y data value output as s32 + */ +s32 bmi160_bmm150_mag_compensate_Y(s16 v_mag_data_y_s16, u16 v_data_r_u16) +{ +s32 inter_retval = BMI160_INIT_VALUE; +/* no overflow */ +if (v_mag_data_y_s16 != BMI160_MAG_FLIP_OVERFLOW_ADCVAL) { + if ((v_data_r_u16 != 0) + && (mag_trim.dig_xyz1 != 0)) { + inter_retval = ((s32)(((u16)((( + (s32)mag_trim.dig_xyz1) + << BMI160_SHIFT_BIT_POSITION_BY_14_BITS) / + (v_data_r_u16 != 0 ? + v_data_r_u16 : mag_trim.dig_xyz1))) - + ((u16)0x4000))); + } else { + inter_retval = BMI160_MAG_OVERFLOW_OUTPUT; + return inter_retval; + } + inter_retval = ((s32)((((s32)v_mag_data_y_s16) * ((((((((s32) + mag_trim.dig_xy2) * ((((s32) inter_retval) * + ((s32)inter_retval)) >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS)) + + (((s32)inter_retval) * + ((s32)(((s16)mag_trim.dig_xy1) + << BMI160_SHIFT_BIT_POSITION_BY_07_BITS)))) + >> BMI160_SHIFT_BIT_POSITION_BY_09_BITS) + + ((s32)0x100000)) + * ((s32)(((s16)mag_trim.dig_y2) + + ((s16)0xA0)))) + >> BMI160_SHIFT_BIT_POSITION_BY_12_BITS)) + >> BMI160_SHIFT_BIT_POSITION_BY_13_BITS)) + + (((s16)mag_trim.dig_y1) + << BMI160_SHIFT_BIT_POSITION_BY_03_BITS); + /* check the overflow output */ + if (inter_retval == (s32)BMI160_MAG_OVERFLOW_OUTPUT) + inter_retval = BMI160_MAG_OVERFLOW_OUTPUT_S32; +} else { + /* overflow */ + inter_retval = BMI160_MAG_OVERFLOW_OUTPUT; +} +return inter_retval; +} +/*! + * @brief This API used to get the compensated BMM150-Z data + * the out put of Z as s32 + * Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_z_s16 : The value of mag raw Z data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Z data value output as s32 + */ +s32 bmi160_bmm150_mag_compensate_Z(s16 v_mag_data_z_s16, u16 v_data_r_u16) +{ + s32 retval = BMI160_INIT_VALUE; + + if (v_mag_data_z_s16 != BMI160_MAG_HALL_OVERFLOW_ADCVAL) { + if ((v_data_r_u16 != 0) + && (mag_trim.dig_z2 != 0) + /* && (mag_trim.dig_z3 != 0)*/ + && (mag_trim.dig_z1 != 0) + && (mag_trim.dig_xyz1 != 0)) { + retval = (((((s32)(v_mag_data_z_s16 - mag_trim.dig_z4)) + << BMI160_SHIFT_BIT_POSITION_BY_15_BITS) - + ((((s32)mag_trim.dig_z3) * + ((s32)(((s16)v_data_r_u16) - + ((s16)mag_trim.dig_xyz1)))) + >> BMI160_SHIFT_BIT_POSITION_BY_02_BITS))/ + (mag_trim.dig_z2 + + ((s16)(((((s32)mag_trim.dig_z1) * + ((((s16)v_data_r_u16) + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT))) + + (1 << BMI160_SHIFT_BIT_POSITION_BY_15_BITS)) + >> BMI160_SHIFT_BIT_POSITION_BY_16_BITS)))); + } + } else { + retval = BMI160_MAG_OVERFLOW_OUTPUT; + } + return retval; +} + /*! + * @brief This function used for initialize the bmm150 sensor + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_interface_init(void) +{ + /* This variable used for provide the communication + results*/ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + u8 v_pull_value_u8 = BMI160_INIT_VALUE; + u8 v_data_u8 = BMI160_INIT_VALUE; + /* accel operation mode to normal*/ + com_rslt = bmi160_set_command_register(ACCEL_MODE_NORMAL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* write the mag power mode as NORMAL*/ + com_rslt += bmi160_set_mag_interface_normal(); + + /* register 0x7E write the 0x37, 0x9A and 0x30*/ + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_ONE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_TWO); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_THREE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /*switch the page1*/ + com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_target_page(&v_data_u8); + com_rslt += bmi160_set_paging_enable(BMI160_WRITE_ENABLE_PAGE1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_paging_enable(&v_data_u8); + /* enable the pullup configuration from + the register 0x05 bit 4 and 5 as 10*/ + bmi160_get_pullup_configuration(&v_pull_value_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + v_pull_value_u8 = v_pull_value_u8 | BMI160_PULL_UP_DATA; + com_rslt += bmi160_set_pullup_configuration(v_pull_value_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /*switch the page0*/ + com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE0); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_target_page(&v_data_u8); + /* Write the BMM150 i2c address*/ + com_rslt += bmi160_set_i2c_device_addr(BMI160_AUX_BMM150_I2C_ADDRESS); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* enable the mag interface to manual mode*/ + com_rslt += bmi160_set_mag_manual_enable(BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_mag_manual_enable(&v_data_u8); + /*Enable the MAG interface */ + com_rslt += bmi160_set_if_mode(BMI160_ENABLE_MAG_IF_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_if_mode(&v_data_u8); + /* Mag normal mode*/ + com_rslt += bmi160_bmm150_mag_wakeup(); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Read the BMM150 device id is 0x32*/ + /*com_rslt += bmi160_set_mag_read_addr(BMI160_BMM150_CHIP_ID);*/ + /*p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);*/ + /*com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH);*/ + /**v_chip_id_u8 = v_data_u8;*/ + /*p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY);*/ + /* write the power mode register*/ + com_rslt += bmi160_set_mag_write_data(BMI160_BMM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /*write 0x4C register to write set power mode to normal*/ + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_MODE_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* read the mag trim values*/ + com_rslt += bmi160_read_bmm150_mag_trim(); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + /* To avoid the auto mode enable when manual mode operation running*/ + V_bmm150_maual_auto_condition_u8 = BMI160_MANUAL_ENABLE; + /* write the XY and Z repetitions*/ + com_rslt += bmi160_set_bmm150_mag_presetmode( + BMI160_MAG_PRESETMODE_REGULAR); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + /* To avoid the auto mode enable when manual mode operation running*/ + V_bmm150_maual_auto_condition_u8 = BMI160_MANUAL_DISABLE; + /* Set the power mode of mag as force mode*/ + /* The data have to write for the register + It write the value in the register 0x4F */ + com_rslt += bmi160_set_mag_write_data(BMI160_BMM150_FORCE_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + printk(KERN_INFO "com_rslt:%d, <%s><%d>\n", + com_rslt, __func__, __LINE__); + /* write into power mode register*/ + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_MODE_REG); + /* write the mag v_data_bw_u8 as 25Hz*/ + com_rslt += bmi160_set_mag_output_data_rate( + BMI160_MAG_OUTPUT_DATA_RATE_25HZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + /* When mag interface is auto mode - The mag read address + starts the register 0x42*/ + com_rslt += bmi160_set_mag_read_addr( + BMI160_BMM150_DATA_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* enable mag interface to auto mode*/ + com_rslt += bmi160_set_mag_manual_enable(BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_mag_manual_enable(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + return com_rslt; +} + /*! + * @brief This function used for set the mag power control + * bit enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_wakeup(void) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + u8 v_try_times_u8 = BMI160_BMM150_MAX_RETRY_WAKEUP; + u8 v_power_control_bit_u8 = BMI160_INIT_VALUE; + u8 i = BMI160_INIT_VALUE; + + for (i = BMI160_INIT_VALUE; i < v_try_times_u8; i++) { + com_rslt = bmi160_set_mag_write_data(BMI160_BMM150_POWER_ON); + p_bmi160->delay_msec(BMI160_BMM150_WAKEUP_DELAY1); + /*write 0x4B register to enable power control bit*/ + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_CONTROL_REG); + p_bmi160->delay_msec(BMI160_BMM150_WAKEUP_DELAY2); + com_rslt += bmi160_set_mag_read_addr( + BMI160_BMM150_POWE_CONTROL_REG); + /* 0x04 is secondary read mag x lsb register */ + p_bmi160->delay_msec(BMI160_BMM150_WAKEUP_DELAY3); + com_rslt += bmi160_read_reg(BMI160_USER_DATA_0_ADDR, + &v_power_control_bit_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + v_power_control_bit_u8 = BMI160_BMM150_SET_POWER_CONTROL + & v_power_control_bit_u8; + if (v_power_control_bit_u8 == BMI160_BMM150_POWER_ON) + break; + } + com_rslt = (i >= v_try_times_u8) ? + BMI160_BMM150_POWER_ON_FAIL : BMI160_BMM150_POWER_ON_SUCCESS; + return com_rslt; +} + /*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | BMI160_MAG_FORCE_MODE + * 1 | BMI160_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_bmm150_mag_and_secondary_if_power_mode( +u8 v_mag_sec_if_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + /* set the accel power mode to NORMAL*/ + com_rslt = bmi160_set_command_register(ACCEL_MODE_NORMAL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + /* set mag interface manual mode*/ + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) { + com_rslt += bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + + switch (v_mag_sec_if_pow_mode_u8) { + case BMI160_MAG_FORCE_MODE: + /* set the secondary mag power mode as NORMAL*/ + com_rslt += bmi160_set_mag_interface_normal(); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + /* set the mag power mode as FORCE mode*/ + com_rslt += bmi160_bmm150_mag_set_power_mode(FORCE_MODE); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_MAG_SUSPEND_MODE: + /* set the mag power mode as SUSPEND mode*/ + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + com_rslt += bmi160_bmm150_mag_set_power_mode(SUSPEND_MODE); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* set the secondary mag power mode as SUSPEND*/ + com_rslt += bmi160_set_command_register(MAG_MODE_SUSPEND); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) { + /* set mag interface auto mode*/ + com_rslt += bmi160_set_mag_manual_enable( + BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + return com_rslt; +} +/*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @param v_mag_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | FORCE_MODE + * 1 | SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_set_power_mode( +u8 v_mag_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + u8 manual_enable_status = 0; + /* set mag interface manual mode*/ + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) { + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_get_mag_manual_enable(&manual_enable_status); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + printk(KERN_INFO "1com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_bmi160->mag_manual_enable, manual_enable_status); + } + printk(KERN_INFO "2com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_bmi160->mag_manual_enable, manual_enable_status); + + switch (v_mag_pow_mode_u8) { + case FORCE_MODE: + /* Set the power control bit enabled */ + com_rslt = bmi160_bmm150_mag_wakeup(); + /* write the mag power mode as FORCE mode*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_BMM150_FORCE_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* To avoid the auto mode enable when manual + mode operation running*/ + V_bmm150_maual_auto_condition_u8 = BMI160_MANUAL_ENABLE; + /* set the preset mode */ + com_rslt += bmi160_set_bmm150_mag_presetmode( + BMI160_MAG_PRESETMODE_REGULAR); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* To avoid the auto mode enable when manual + mode operation running*/ + V_bmm150_maual_auto_condition_u8 = BMI160_MANUAL_DISABLE; + /* set the mag read address to data registers*/ + com_rslt += bmi160_set_mag_read_addr( + BMI160_BMM150_DATA_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case SUSPEND_MODE: + printk(KERN_INFO "3com_rslt:%d, manual:%d, read_manual:%d\n", + com_rslt, p_bmi160->mag_manual_enable, manual_enable_status); + /* Set the power mode of mag as suspend mode*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_BMM150_POWER_OFF); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_CONTROL_REG); + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + printk(KERN_INFO "4com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_bmi160->mag_manual_enable, manual_enable_status); + /* set mag interface auto mode*/ + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) { + com_rslt += bmi160_set_mag_manual_enable( + BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_get_mag_manual_enable(&manual_enable_status); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "5com_rslt:%d, manual:%d, manual_read:%d\n", + com_rslt, p_bmi160->mag_manual_enable, manual_enable_status); + return com_rslt; +} +/*! + * @brief This API used to set the pre-set modes of bmm150 + * The pre-set mode setting is depend on data rate and xy and z repetitions + * + * @note + * Before set the mag preset mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_mode_u8: The value of pre-set mode selection value + * value | pre_set mode + * ----------|------------ + * 1 | BMI160_MAG_PRESETMODE_LOWPOWER + * 2 | BMI160_MAG_PRESETMODE_REGULAR + * 3 | BMI160_MAG_PRESETMODE_HIGHACCURACY + * 4 | BMI160_MAG_PRESETMODE_ENHANCED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_bmm150_mag_presetmode(u8 v_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + switch (v_mode_u8) { + case BMI160_MAG_PRESETMODE_LOWPOWER: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = bmi160_set_mag_write_data( + BMI160_MAG_LOWPOWER_REPXY); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_XY_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_LOWPOWER_REPZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_Z_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 10 to the register 0x4C*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_LOWPOWER_DR); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_MODE_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_MAG_PRESETMODE_REGULAR: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = bmi160_set_mag_write_data( + BMI160_MAG_REGULAR_REPXY); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_XY_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_REGULAR_REPZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_Z_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 10 to the register 0x4C*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_REGULAR_DR); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_MODE_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_MAG_PRESETMODE_HIGHACCURACY: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = bmi160_set_mag_write_data( + BMI160_MAG_HIGHACCURACY_REPXY); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_XY_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_HIGHACCURACY_REPZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_Z_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 20 to the register 0x4C*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_HIGHACCURACY_DR); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_MODE_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_MAG_PRESETMODE_ENHANCED: + /* write the XY and Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt = bmi160_set_mag_write_data( + BMI160_MAG_ENHANCED_REPXY); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_XY_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_ENHANCED_REPZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_Z_REP); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* set the mag v_data_u8 rate as 10 to the register 0x4C*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_MAG_ENHANCED_DR); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + BMI160_BMM150_POWE_MODE_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + + return com_rslt; +} + /*! + * @brief This function used for read the trim values of magnetometer + * + * @note + * Before reading the mag trimming values + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_bmm150_mag_trim(void) +{ + /* This variable used for provide the communication + results*/ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array holding the bmm150 trim data + */ + u8 v_data_u8[BMI160_MAG_TRIM_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE}; + /* read dig_x1 value */ + com_rslt = bmi160_set_mag_read_addr( + BMI160_MAG_DIG_X1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_X1], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_x1 = v_data_u8[BMI160_BMM150_DIG_X1]; + /* read dig_y1 value */ + com_rslt += bmi160_set_mag_read_addr( + BMI160_MAG_DIG_Y1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_Y1], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_y1 = v_data_u8[BMI160_BMM150_DIG_Y1]; + + /* read dig_x2 value */ + com_rslt += bmi160_set_mag_read_addr( + BMI160_MAG_DIG_X2); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_X2], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_x2 = v_data_u8[BMI160_BMM150_DIG_X2]; + /* read dig_y2 value */ + com_rslt += bmi160_set_mag_read_addr( + BMI160_MAG_DIG_Y2); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_Y3], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_y2 = v_data_u8[BMI160_BMM150_DIG_Y3]; + + /* read dig_xy1 value */ + com_rslt += bmi160_set_mag_read_addr( + BMI160_MAG_DIG_XY1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_XY1], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_xy1 = v_data_u8[BMI160_BMM150_DIG_XY1]; + /* read dig_xy2 value */ + com_rslt += bmi160_set_mag_read_addr( + BMI160_MAG_DIG_XY2); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 ls register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_XY2], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_xy2 = v_data_u8[BMI160_BMM150_DIG_XY2]; + + /* read dig_z1 lsb value */ + com_rslt += bmi160_set_mag_read_addr( + BMI160_MAG_DIG_Z1_LSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_Z1_LSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* read dig_z1 msb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_Z1_MSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_Z1_MSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_z1 = + (u16)((((u32)((u8)v_data_u8[BMI160_BMM150_DIG_Z1_MSB])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_BMM150_DIG_Z1_LSB])); + + /* read dig_z2 lsb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_Z2_LSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_Z2_LSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* read dig_z2 msb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_Z2_MSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_Z2_MSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_z2 = + (s16)((((s32)((s8)v_data_u8[BMI160_BMM150_DIG_Z2_MSB])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_BMM150_DIG_Z2_LSB])); + + /* read dig_z3 lsb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_Z3_LSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_DIG_Z3_LSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* read dig_z3 msb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_Z3_MSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_DIG_Z3_MSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_z3 = + (s16)((((s32)((s8)v_data_u8[BMI160_BMM150_DIG_DIG_Z3_MSB])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_BMM150_DIG_DIG_Z3_LSB])); + + /* read dig_z4 lsb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_Z4_LSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_DIG_Z4_LSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* read dig_z4 msb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_Z4_MSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_DIG_Z4_MSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_z4 = + (s16)((((s32)((s8)v_data_u8[BMI160_BMM150_DIG_DIG_Z4_MSB])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_BMM150_DIG_DIG_Z4_LSB])); + + /* read dig_xyz1 lsb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_XYZ1_LSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_DIG_XYZ1_LSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* read dig_xyz1 msb value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_MAG_DIG_XYZ1_MSB); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is v_mag_x_s16 msb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[BMI160_BMM150_DIG_DIG_XYZ1_MSB], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + mag_trim.dig_xyz1 = + (u16)((((u32)((u8)v_data_u8[BMI160_BMM150_DIG_DIG_XYZ1_MSB])) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | + (v_data_u8[BMI160_BMM150_DIG_DIG_XYZ1_LSB])); + + return com_rslt; +} + /*! + * @brief This function used for initialize + * the AKM09911 and AKM09912 sensor + * + * + * @param v_akm_i2c_address_u8: The value of device address + * AKM sensor | Slave address + * --------------|--------------------- + * AKM09911 | AKM09911_I2C_ADDR_1 + * - | and AKM09911_I2C_ADDR_2 + * AKM09912 | AKM09912_I2C_ADDR_1 + * - | AKM09912_I2C_ADDR_2 + * - | AKM09912_I2C_ADDR_3 + * - | AKM09912_I2C_ADDR_4 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm_mag_interface_init( +u8 v_akm_i2c_address_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_pull_value_u8 = BMI160_INIT_VALUE; + u8 v_data_u8 = BMI160_INIT_VALUE; + u8 v_akm_chip_id_u8 = BMI160_INIT_VALUE; + /* accel operation mode to normal*/ + com_rslt = bmi160_set_command_register(ACCEL_MODE_NORMAL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_command_register(MAG_MODE_NORMAL); + p_bmi160->delay_msec(BMI160_AKM_INIT_DELAY); + bmi160_get_mag_power_mode_stat(&v_data_u8); + /* register 0x7E write the 0x37, 0x9A and 0x30*/ + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_ONE); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_TWO); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_THREE); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /*switch the page1*/ + com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_target_page(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_paging_enable(BMI160_WRITE_ENABLE_PAGE1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_paging_enable(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* enable the pullup configuration from + the register 0x05 bit 4 and 5 to 10*/ + bmi160_get_pullup_configuration(&v_pull_value_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + v_pull_value_u8 = v_pull_value_u8 | BMI160_PULL_UP_DATA; + com_rslt += bmi160_set_pullup_configuration(v_pull_value_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + /*switch the page0*/ + com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE0); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_target_page(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Write the AKM09911 0r AKM09912 i2c address*/ + com_rslt += bmi160_set_i2c_device_addr(v_akm_i2c_address_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* enable the mag interface to manual mode*/ + com_rslt += bmi160_set_mag_manual_enable(BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_mag_manual_enable(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /*Enable the MAG interface */ + com_rslt += bmi160_set_if_mode(BMI160_ENABLE_MAG_IF_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_if_mode(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + /* Set the AKM Fuse ROM mode */ + /* Set value for fuse ROM mode*/ + com_rslt += bmi160_set_mag_write_data(AKM_FUSE_ROM_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* AKM mode address is 0x31*/ + com_rslt += bmi160_set_mag_write_addr(AKM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Read the Fuse ROM v_data_u8 from registers + 0x60,0x61 and 0x62*/ + /* ASAX v_data_u8 */ + com_rslt += bmi160_read_bst_akm_sensitivity_data(); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* read the device id of the AKM sensor + if device id is 0x05 - AKM09911 + if device id is 0x04 - AKM09912*/ + com_rslt += bmi160_set_mag_read_addr(AKM09912_CHIP_ID_REG); + /* 0x04 is mag_x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_akm_chip_id_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + printk(KERN_INFO "bmi160,addr:0x%x, akm_chip_id:0x%x", + v_akm_i2c_address_u8, v_akm_chip_id_u8); + /* Set value power down mode mode*/ + com_rslt += bmi160_set_mag_write_data(AKM_POWER_DOWN_MODE_DATA); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* AKM mode address is 0x31*/ + com_rslt += bmi160_set_mag_write_addr(AKM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Set AKM Force mode*/ + com_rslt += bmi160_set_mag_write_data( + AKM_SINGLE_MEASUREMENT_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* AKM mode address is 0x31*/ + com_rslt += bmi160_set_mag_write_addr(AKM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Set the AKM read xyz v_data_u8 address*/ + com_rslt += bmi160_set_mag_read_addr(AKM_DATA_REGISTER); + /* write the mag v_data_bw_u8 as 25Hz*/ + com_rslt += bmi160_set_mag_output_data_rate( + BMI160_MAG_OUTPUT_DATA_RATE_25HZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Enable mag interface to auto mode*/ + com_rslt += bmi160_set_mag_manual_enable(BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_mag_manual_enable(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + return com_rslt; +} + /*! + * @brief This function used for read the sensitivity data of + * AKM09911 and AKM09912 + * + * @note Before reading the mag sensitivity values + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_bst_akm_sensitivity_data(void) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array holding the sensitivity ax,ay and az data*/ + u8 v_data_u8[BMI160_AKM_SENSITIVITY_DATA_SIZE] = { + BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* read asax value */ + com_rslt = bmi160_set_mag_read_addr(BMI160_BST_AKM_ASAX); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[AKM_ASAX], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + akm_asa_data.asax = v_data_u8[AKM_ASAX]; + /* read asay value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_BST_AKM_ASAY); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[AKM_ASAY], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + akm_asa_data.asay = v_data_u8[AKM_ASAY]; + /* read asaz value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_BST_AKM_ASAZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[AKM_ASAZ], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + akm_asa_data.asaz = v_data_u8[AKM_ASAZ]; + + return com_rslt; +} +/*! + * @brief This API used to get the compensated X data + * of AKM09911 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 bmi160_bst_akm09911_compensate_X(s16 v_bst_akm_x_s16) +{ + /*Return value of AKM x compensated v_data_u8*/ + s32 retval = BMI160_INIT_VALUE; + /* Convert raw v_data_u8 into compensated v_data_u8*/ + retval = (v_bst_akm_x_s16 * + ((akm_asa_data.asax/AKM09911_SENSITIVITY_DIV) + + BMI160_GEN_READ_WRITE_DATA_LENGTH)); + return retval; +} +/*! + * @brief This API used to get the compensated Y data + * of AKM09911 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 bmi160_bst_akm09911_compensate_Y(s16 v_bst_akm_y_s16) +{ + /*Return value of AKM y compensated v_data_u8*/ + s32 retval = BMI160_INIT_VALUE; + /* Convert raw v_data_u8 into compensated v_data_u8*/ + retval = (v_bst_akm_y_s16 * + ((akm_asa_data.asay/AKM09911_SENSITIVITY_DIV) + + BMI160_GEN_READ_WRITE_DATA_LENGTH)); + return retval; +} +/*! + * @brief This API used to get the compensated Z data + * of AKM09911 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 bmi160_bst_akm09911_compensate_Z(s16 v_bst_akm_z_s16) +{ + /*Return value of AKM z compensated v_data_u8*/ + s32 retval = BMI160_INIT_VALUE; + /* Convert raw v_data_u8 into compensated v_data_u8*/ + retval = (v_bst_akm_z_s16 * + ((akm_asa_data.asaz/AKM09911_SENSITIVITY_DIV) + + BMI160_GEN_READ_WRITE_DATA_LENGTH)); + return retval; +} +/*! + * @brief This API used to get the compensated X data + * of AKM09912 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 bmi160_bst_akm09912_compensate_X(s16 v_bst_akm_x_s16) +{ + /*Return value of AKM x compensated data*/ + s32 retval = BMI160_INIT_VALUE; + /* Convert raw data into compensated data*/ + retval = v_bst_akm_x_s16 * + (akm_asa_data.asax + AKM09912_SENSITIVITY) + / AKM09912_SENSITIVITY_DIV; + return retval; +} +/*! + * @brief This API used to get the compensated Y data + * of AKM09912 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 bmi160_bst_akm09912_compensate_Y(s16 v_bst_akm_y_s16) +{ + /*Return value of AKM y compensated data*/ + s32 retval = BMI160_INIT_VALUE; + /* Convert raw data into compensated data*/ + retval = v_bst_akm_y_s16 * + (akm_asa_data.asax + AKM09912_SENSITIVITY) + / AKM09912_SENSITIVITY_DIV; + return retval; +} +/*! + * @brief This API used to get the compensated Z data + * of AKM09912 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 bmi160_bst_akm09912_compensate_Z(s16 v_bst_akm_z_s16) +{ + /*Return value of AKM z compensated data*/ + s32 retval = BMI160_INIT_VALUE; + /* Convert raw data into compensated data*/ + retval = v_bst_akm_z_s16 * + (akm_asa_data.asax + AKM09912_SENSITIVITY) + / AKM09912_SENSITIVITY_DIV; + return retval; +} + /*! + * @brief This function used for read the compensated value of + * AKM09911 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm09911_compensate_xyz( +struct bmi160_mag_xyz_s32_t *bst_akm_xyz) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + struct bmi160_mag_t mag_xyz; + + com_rslt = bmi160_read_mag_xyz(&mag_xyz, BST_AKM); + /* Compensation for X axis */ + bst_akm_xyz->x = bmi160_bst_akm09911_compensate_X(mag_xyz.x); + + /* Compensation for Y axis */ + bst_akm_xyz->y = bmi160_bst_akm09911_compensate_Y(mag_xyz.y); + + /* Compensation for Z axis */ + bst_akm_xyz->z = bmi160_bst_akm09911_compensate_Z(mag_xyz.z); + + return com_rslt; +} + /*! + * @brief This function used for read the compensated value of + * AKM09912 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm09912_compensate_xyz( +struct bmi160_mag_xyz_s32_t *bst_akm_xyz) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + struct bmi160_mag_t mag_xyz; + + com_rslt = bmi160_read_mag_xyz(&mag_xyz, BST_AKM); + printk(KERN_INFO "akm09912_raw_x:%d, %d, %d, <%s>,<%d>", + mag_xyz.x, mag_xyz.y, mag_xyz.z, __func__, __LINE__); + /* Compensation for X axis */ + bst_akm_xyz->x = bmi160_bst_akm09912_compensate_X(mag_xyz.x); + + /* Compensation for Y axis */ + bst_akm_xyz->y = bmi160_bst_akm09912_compensate_Y(mag_xyz.y); + + /* Compensation for Z axis */ + bst_akm_xyz->z = bmi160_bst_akm09912_compensate_Z(mag_xyz.z); + return com_rslt; +} + /*! + * @brief This function used for read the compensated value of + * AKM09912 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm09912_compensate_xyz_raw( +struct bmi160_mag_xyz_s32_t *bst_akm_xyz) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Compensation for X axis */ + bst_akm_xyz->x = bmi160_bst_akm09912_compensate_X(bst_akm_xyz->x); + + /* Compensation for Y axis */ + bst_akm_xyz->y = bmi160_bst_akm09912_compensate_Y(bst_akm_xyz->y); + + /* Compensation for Z axis */ + bst_akm_xyz->z = bmi160_bst_akm09912_compensate_Z(bst_akm_xyz->z); + + return com_rslt; +} +/*! + * @brief This function used for set the AKM09911 and AKM09912 + * power mode. + * @note Before set the AKM power mode + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @param v_akm_pow_mode_u8 : The value of akm power mode + * value | Description + * ---------|-------------------- + * 0 | AKM_POWER_DOWN_MODE + * 1 | AKM_SINGLE_MEAS_MODE + * 2 | FUSE_ROM_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm_set_powermode( +u8 v_akm_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + /* set mag interface manual mode*/ + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) { + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__); + switch (v_akm_pow_mode_u8) { + case AKM_POWER_DOWN_MODE: + /* Set the power mode of AKM as power down mode*/ + com_rslt += bmi160_set_mag_write_data(AKM_POWER_DOWN_MODE_DATA); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(AKM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + case AKM_SINGLE_MEAS_MODE: + /* Set the power mode of AKM as + single measurement mode*/ + com_rslt += bmi160_set_mag_write_data + (AKM_SINGLE_MEASUREMENT_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(AKM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_read_addr(AKM_DATA_REGISTER); + break; + case FUSE_ROM_MODE: + /* Set the power mode of AKM as + Fuse ROM mode*/ + com_rslt += bmi160_set_mag_write_data(AKM_FUSE_ROM_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(AKM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Sensitivity v_data_u8 */ + com_rslt += bmi160_read_bst_akm_sensitivity_data(); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* power down mode*/ + com_rslt += bmi160_set_mag_write_data(AKM_POWER_DOWN_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(AKM_POWER_MODE_REG); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + /* set mag interface auto mode*/ + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) { + com_rslt += bmi160_set_mag_manual_enable( + BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + } + printk(KERN_INFO "com_rslt:%d, manual:%d, <%s><%d>\n", + com_rslt, p_bmi160->mag_manual_enable, __func__, __LINE__); + return com_rslt; +} + /*! + * @brief This function used for set the magnetometer + * power mode of AKM09911 and AKM09912 + * @note Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of secondary if power mode + * value | Description + * ---------|-------------------- + * 0 | BMI160_MAG_FORCE_MODE + * 1 | BMI160_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_bst_akm_and_secondary_if_powermode( +u8 v_mag_sec_if_pow_mode_u8) +{ + /* variable used for return the status of communication result*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* accel operation mode to normal*/ + com_rslt = bmi160_set_command_register(ACCEL_MODE_NORMAL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* set mag interface manual mode*/ + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) { + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + } + printk(KERN_ERR "com_rslt:%d, manual:%d,after setacc normal mode\n", + com_rslt, p_bmi160->mag_manual_enable); + switch (v_mag_sec_if_pow_mode_u8) { + case BMI160_MAG_FORCE_MODE: + /* set the secondary mag power mode as NORMAL*/ + com_rslt += bmi160_set_mag_interface_normal(); + /* set the akm power mode as single measurement mode*/ + com_rslt += bmi160_bst_akm_set_powermode(AKM_SINGLE_MEAS_MODE); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_read_addr(AKM_DATA_REGISTER); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + break; + case BMI160_MAG_SUSPEND_MODE: + /* set the akm power mode as power down mode*/ + com_rslt += bmi160_bst_akm_set_powermode(AKM_POWER_DOWN_MODE); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* set the secondary mag power mode as SUSPEND*/ + com_rslt += bmi160_set_command_register(MAG_MODE_SUSPEND); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + break; + default: + com_rslt = E_BMI160_OUT_OF_RANGE; + break; + } + /* set mag interface auto mode*/ + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) + com_rslt += bmi160_set_mag_manual_enable( + BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + return com_rslt; +} +/*! + * @brief This function used for read the YAMAH-YAS532 init + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas532_mag_interface_init( +void) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + u8 v_pull_value_u8 = BMI160_INIT_VALUE; + u8 v_data_u8 = BMI160_INIT_VALUE; + u8 i = BMI160_INIT_VALUE; + /* accel operation mode to normal*/ + com_rslt = bmi160_set_command_register(ACCEL_MODE_NORMAL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* write mag power mode as NORMAL*/ + com_rslt += bmi160_set_mag_interface_normal(); + /* register 0x7E write the 0x37, 0x9A and 0x30*/ + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_ONE); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_TWO); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_THREE); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /*switch the page1*/ + com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_target_page(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_paging_enable(BMI160_WRITE_ENABLE_PAGE1); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_paging_enable(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* enable the pullup configuration from + the register 0x05 bit 4 and 5 as 10*/ + bmi160_get_pullup_configuration(&v_pull_value_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + v_pull_value_u8 = v_pull_value_u8 | BMI160_PULL_UP_DATA; + com_rslt += bmi160_set_pullup_configuration(v_pull_value_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /*switch the page0*/ + com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE0); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_target_page(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Write the YAS532 i2c address*/ + com_rslt += bmi160_set_i2c_device_addr(BMI160_AUX_YAS532_I2C_ADDRESS); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* enable the mag interface to manual mode*/ + com_rslt += bmi160_set_mag_manual_enable(BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_mag_manual_enable(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /*Enable the MAG interface */ + com_rslt += bmi160_set_if_mode(BMI160_ENABLE_MAG_IF_MODE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_if_mode(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + v_data_u8 = BMI160_MANUAL_DISABLE; + /* Read the YAS532 device id is 0x02*/ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS_DEVICE_ID_REG); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Read the YAS532 calibration data*/ + com_rslt += bmi160_bst_yamaha_yas532_calib_values(); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* Assign the data acquisition mode*/ + yas532_data.measure_state = YAS532_MAG_STATE_INIT_COIL; + /* Set the default offset as invalid offset*/ + set_vector(yas532_data.v_hard_offset_s8, INVALID_OFFSET); + /* set the transform to zero */ + yas532_data.transform = BMI160_NULL; + /* Assign overflow as zero*/ + yas532_data.overflow = 0; + #if YAS532_MAG_LOG < YAS532_MAG_TEMPERATURE_LOG + yas532_data.temp_data.num = + yas532_data.temp_data.idx = 0; + #endif + /* Assign the coef value*/ + for (i = 0; i < 3; i++) { + yas532_data.coef[i] = yas532_version_ac_coef[i]; + yas532_data.last_raw[i] = 0; + } + yas532_data.last_raw[3] = 0; + /* Set the initial values of yas532*/ + com_rslt += bmi160_bst_yas532_set_initial_values(); + /* write the mag v_data_bw_u8 as 25Hz*/ + com_rslt += bmi160_set_mag_output_data_rate( + BMI160_MAG_OUTPUT_DATA_RATE_25HZ); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Enable mag interface to auto mode*/ + com_rslt += bmi160_set_mag_manual_enable( + BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + bmi160_get_mag_manual_enable(&v_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + return com_rslt; +} +/*! + * @brief This function used to set the YAS532 initial values + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_set_initial_values(void) +{ +/* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* write testr1 as 0x00*/ + com_rslt = bmi160_set_mag_write_data( + BMI160_YAS532_WRITE_TESTR1); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(BMI160_YAS532_TESTR1); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write testr2 as 0x00*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_YAS532_WRITE_TESTR2); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(BMI160_YAS532_TESTR2); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write Rcoil as 0x00*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_YAS532_WRITE_RCOIL); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(BMI160_YAS532_RCOIL); + p_bmi160->delay_msec(BMI160_YAS532_SET_INITIAL_VALUE_DELAY); + /* check the valid offset*/ + if (is_valid_offset(yas532_data.v_hard_offset_s8)) { + com_rslt += bmi160_bst_yas532_set_offset( + yas532_data.v_hard_offset_s8); + yas532_data.measure_state = YAS532_MAG_STATE_NORMAL; + } else { + /* set the default offset as invalid offset*/ + set_vector(yas532_data.v_hard_offset_s8, INVALID_OFFSET); + /*Set the default measure state for offset correction*/ + yas532_data.measure_state = YAS532_MAG_STATE_MEASURE_OFFSET; + } + return com_rslt; +} +/*! + * @brief This function used for YAS532 offset correction + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_magnetic_measure_set_offset( +void) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* used for offset value set to the offset register*/ + s8 v_hard_offset_s8[BMI160_HARD_OFFSET_DATA_SIZE] = { + BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* offset correction factors*/ + static const u8 v_correct_u8[BMI160_YAS_CORRECT_DATA_SIZE] = { + 16, 8, 4, 2, 1}; + /* used for the temperature */ + u16 v_temp_u16 = BMI160_INIT_VALUE; + /* used for the xy1y2 read*/ + u16 v_xy1y2_u16[BMI160_YAS_XY1Y2_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* local flag for assign the values*/ + s32 v_flag_s32[BMI160_YAS_FLAG_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + u8 i, j, v_busy_u8, v_overflow_u8 = BMI160_INIT_VALUE; + + for (i = 0; i < 5; i++) { + /* set the offset values*/ + com_rslt = bmi160_bst_yas532_set_offset(v_hard_offset_s8); + /* read the sensor data*/ + com_rslt += bmi160_bst_yas532_normal_measurement_data( + BMI160_YAS532_ACQ_START, &v_busy_u8, &v_temp_u16, + v_xy1y2_u16, &v_overflow_u8); + /* check the sensor busy status*/ + if (v_busy_u8) + return E_BMI160_BUSY; + /* calculate the magnetic correction with + offset and assign the values + to the offset register */ + for (j = 0; j < 3; j++) { + if (YAS532_DATA_CENTER == v_xy1y2_u16[j]) + v_flag_s32[j] = 0; + if (YAS532_DATA_CENTER < v_xy1y2_u16[j]) + v_flag_s32[j] = 1; + if (v_xy1y2_u16[j] < YAS532_DATA_CENTER) + v_flag_s32[j] = -1; + } + for (j = 0; j < 3; j++) { + if (v_flag_s32[j]) + v_hard_offset_s8[j] = (s8)(v_hard_offset_s8[j] + + v_flag_s32[j] * v_correct_u8[i]); + } + } + /* set the offset */ + com_rslt += bmi160_bst_yas532_set_offset(v_hard_offset_s8); + return com_rslt; +} +/*! + * @brief This function used for read the + * YAMAHA YAS532 calibration data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas532_calib_values(void) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array holding the YAS532 calibration values */ + u8 v_data_u8[BMI160_YAS532_CALIB_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* Read the DX value */ + com_rslt = bmi160_set_mag_read_addr(BMI160_YAS532_CALIB_CX); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[0], BMI160_GEN_READ_WRITE_DATA_LENGTH); + yas532_data.calib_yas532.cx = (s32)((v_data_u8[0] + * 10) - 1280); + /* Read the DY1 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB_CY1); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[1], BMI160_GEN_READ_WRITE_DATA_LENGTH); + yas532_data.calib_yas532.cy1 = + (s32)((v_data_u8[1] * 10) - 1280); + /* Read the DY2 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB_CY2); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[2], BMI160_GEN_READ_WRITE_DATA_LENGTH); + yas532_data.calib_yas532.cy2 = + (s32)((v_data_u8[2] * 10) - 1280); + /* Read the D2 and D3 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB1); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[3], BMI160_GEN_READ_WRITE_DATA_LENGTH); + yas532_data.calib_yas532.a2 = + (s32)(((v_data_u8[3] >> + BMI160_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x03F) - 32); + /* Read the D3 and D4 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB2); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[4], BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a3*/ + yas532_data.calib_yas532.a3 = (s32)((((v_data_u8[3] << + BMI160_SHIFT_BIT_POSITION_BY_02_BITS) & 0x0C) | + ((v_data_u8[4] + >> BMI160_SHIFT_BIT_POSITION_BY_06_BITS) + & 0x03)) - 8); + /* calculate a4*/ + yas532_data.calib_yas532.a4 = (s32)((v_data_u8[4] + & 0x3F) - 32); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* Read the D5 and D6 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB3); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[5], BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a5*/ + yas532_data.calib_yas532.a5 = + (s32)(((v_data_u8[5] + >> BMI160_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x3F) + 38); + /* Read the D6 and D7 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB4); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[6], BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a6*/ + yas532_data.calib_yas532.a6 = + (s32)((((v_data_u8[5] + << BMI160_SHIFT_BIT_POSITION_BY_04_BITS) + & 0x30) | ((v_data_u8[6] >> + BMI160_SHIFT_BIT_POSITION_BY_04_BITS) + & 0x0F)) - 32); + /* Read the D7 and D8 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB5); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[7], BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a7*/ + yas532_data.calib_yas532.a7 = (s32)((((v_data_u8[6] + << BMI160_SHIFT_BIT_POSITION_BY_03_BITS) + & 0x78) | + ((v_data_u8[7] + >> BMI160_SHIFT_BIT_POSITION_BY_05_BITS) & + 0x07)) - 64); + /* Read the D8 and D9 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CLAIB6); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[8], BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a8*/ + yas532_data.calib_yas532.a8 = (s32)((((v_data_u8[7] << + BMI160_GEN_READ_WRITE_DATA_LENGTH) & 0x3E) | + ((v_data_u8[8] >> + BMI160_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)) - + 32); + + /* Read the D8 and D9 value */ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB7); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[9], BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* calculate a9*/ + yas532_data.calib_yas532.a9 = (s32)(((v_data_u8[8] << + BMI160_GEN_READ_WRITE_DATA_LENGTH) & 0xFE) | + ((v_data_u8[9] >> + BMI160_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + /* calculate k*/ + yas532_data.calib_yas532.k = (s32)((v_data_u8[9] >> + BMI160_SHIFT_BIT_POSITION_BY_02_BITS) & 0x1F); + /* Read the value from register 0x9A*/ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB8); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[10], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* Read the value from register 0x9B*/ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIIB9); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[11], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* Read the value from register 0x9C*/ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB10); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[12], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* Read the value from register 0x9D*/ + com_rslt += bmi160_set_mag_read_addr(BMI160_YAS532_CALIB11); + /* 0x04 is secondary read mag x lsb register */ + com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, + &v_data_u8[13], + BMI160_GEN_READ_WRITE_DATA_LENGTH); + /* Calculate the fxy1y2 and rxy1y1*/ + yas532_data.calib_yas532.fxy1y2[0] = + (u8)(((v_data_u8[10] + & 0x01) + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) + | ((v_data_u8[11] >> + BMI160_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + yas532_data.calib_yas532.rxy1y2[0] = + ((s8)(((v_data_u8[10] + >> BMI160_SHIFT_BIT_POSITION_BY_01_BIT) & 0x3F) + << BMI160_SHIFT_BIT_POSITION_BY_02_BITS)) + >> BMI160_SHIFT_BIT_POSITION_BY_02_BITS; + yas532_data.calib_yas532.fxy1y2[1] = + (u8)(((v_data_u8[11] & 0x01) + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) + | ((v_data_u8[12] >> + BMI160_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + yas532_data.calib_yas532.rxy1y2[1] = + ((s8)(((v_data_u8[11] + >> BMI160_SHIFT_BIT_POSITION_BY_01_BIT) & 0x3F) + << BMI160_SHIFT_BIT_POSITION_BY_02_BITS)) + >> BMI160_SHIFT_BIT_POSITION_BY_02_BITS; + yas532_data.calib_yas532.fxy1y2[2] = + (u8)(((v_data_u8[12] & 0x01) + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) + | ((v_data_u8[13] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01)); + yas532_data.calib_yas532.rxy1y2[2] = + ((s8)(((v_data_u8[12] + >> BMI160_SHIFT_BIT_POSITION_BY_01_BIT) & 0x3F) + << BMI160_SHIFT_BIT_POSITION_BY_02_BITS)) + >> BMI160_SHIFT_BIT_POSITION_BY_02_BITS; + + return com_rslt; +} +/*! + * @brief This function used for calculate the + * YAS532 read the linear data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_xy1y2_to_linear( +u16 *v_xy1y2_u16, s32 *xy1y2_linear) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = SUCCESS; + static const u16 v_calib_data[] = { + 3721, 3971, 4221, 4471}; + u8 i = BMI160_INIT_VALUE; + + for (i = 0; i < 3; i++) + xy1y2_linear[i] = v_xy1y2_u16[i] - + v_calib_data[yas532_data.calib_yas532.fxy1y2[i]] + + (yas532_data.v_hard_offset_s8[i] - + yas532_data.calib_yas532.rxy1y2[i]) + * yas532_data.coef[i]; + return com_rslt; +} +/*! + * @brief This function used for read the YAS532 sensor data + * @param v_acquisition_command_u8: used to set the data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param v_busy_u8 : used to get the busy flay for sensor data read + * @param v_temp_u16 : used to get the temperature data + * @param v_xy1y2_u16 : used to get the sensor xy1y2 data + * @param v_overflow_u8 : used to get the overflow data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_normal_measurement_data( +u8 v_acquisition_command_u8, u8 *v_busy_u8, +u16 *v_temp_u16, u16 *v_xy1y2_u16, u8 *v_overflow_u8) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + /* Array holding the YAS532 xyy1 data*/ + u8 v_data_u8[BMI160_YAS_XY1Y2T_DATA_SIZE] = { + BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + u8 i = BMI160_INIT_VALUE; + /* check the p_bmi160 structure as NULL*/ + if (p_bmi160 == BMI160_NULL) { + return E_BMI160_NULL_PTR; + } else { + /* read the sensor data */ + com_rslt = bmi160_bst_yas532_acquisition_command_register( + v_acquisition_command_u8); + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_MAG_X_LSB__REG, + v_data_u8, BMI160_MAG_YAS_DATA_LENGTH); + /* read the xyy1 data*/ + *v_busy_u8 = + ((v_data_u8[0] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS) & 0x01); + *v_temp_u16 = + (u16)((((s32)v_data_u8[0] + << BMI160_SHIFT_BIT_POSITION_BY_03_BITS) + & 0x3F8) | ((v_data_u8[1] + >> BMI160_SHIFT_BIT_POSITION_BY_05_BITS) & 0x07)); + v_xy1y2_u16[0] = + (u16)((((s32)v_data_u8[2] + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS) & 0x1FC0) + | ((v_data_u8[3] >> + BMI160_SHIFT_BIT_POSITION_BY_02_BITS) & 0x3F)); + v_xy1y2_u16[1] = + (u16)((((s32)v_data_u8[4] + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS) + & 0x1FC0) + | ((v_data_u8[5] + >> BMI160_SHIFT_BIT_POSITION_BY_02_BITS) & 0x3F)); + v_xy1y2_u16[2] = + (u16)((((s32)v_data_u8[6] + << BMI160_SHIFT_BIT_POSITION_BY_06_BITS) + & 0x1FC0) + | ((v_data_u8[7] + >> BMI160_SHIFT_BIT_POSITION_BY_02_BITS) & 0x3F)); + *v_overflow_u8 = 0; + for (i = 0; i < 3; i++) { + if (v_xy1y2_u16[i] == YAS532_DATA_OVERFLOW) + *v_overflow_u8 |= (1 << (i * 2)); + if (v_xy1y2_u16[i] == YAS532_DATA_UNDERFLOW) + *v_overflow_u8 |= (1 << (i * 2 + 1)); + } + } + return com_rslt; +} +/*! + * @brief This function used for YAS532 sensor data + * @param v_acquisition_command_u8 : the value of CMDR + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param xyz_data : the vector xyz output + * @param v_overflow_s8 : the value of overflow + * @param v_temp_correction_u8 : the value of temperate correction enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_measurement_xyz_data( +struct yas532_vector *xyz_data, u8 *v_overflow_s8, u8 v_temp_correction_u8, +u8 v_acquisition_command_u8) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = BMI160_INIT_VALUE; + /* Array holding the linear calculation output*/ + s32 v_xy1y2_linear_s32[BMI160_YAS_XY1Y2_DATA_SIZE] = { + BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* Array holding the temperature data */ + s32 v_xyz_tmp_s32[BMI160_YAS_TEMP_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + s32 tmp = BMI160_INIT_VALUE; + s32 sx, sy1, sy2, sy, sz = BMI160_INIT_VALUE; + u8 i, v_busy_u8 = BMI160_INIT_VALUE; + u16 v_temp_u16 = BMI160_INIT_VALUE; + /* Array holding the xyy1 sensor raw data*/ + u16 v_xy1y2_u16[BMI160_YAS_XY1Y2_DATA_SIZE] = {BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + #if YAS532_MAG_LOG < YAS532_MAG_TEMPERATURE_LOG + s32 sum = BMI160_INIT_VALUE; + #endif + *v_overflow_s8 = BMI160_INIT_VALUE; + switch (yas532_data.measure_state) { + case YAS532_MAG_STATE_INIT_COIL: + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + /* write Rcoil*/ + com_rslt += bmi160_set_mag_write_data( + BMI160_YAS_DISABLE_RCOIL); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(BMI160_YAS532_RCOIL); + p_bmi160->delay_msec(BMI160_YAS532_MEASUREMENT_DELAY); + if (!yas532_data.overflow && is_valid_offset( + yas532_data.v_hard_offset_s8)) + yas532_data.measure_state = 0; + break; + case YAS532_MAG_STATE_MEASURE_OFFSET: + com_rslt = bmi160_bst_yas532_magnetic_measure_set_offset(); + yas532_data.measure_state = 0; + break; + default: + break; + } + /* Read sensor data*/ + com_rslt += bmi160_bst_yas532_normal_measurement_data( + v_acquisition_command_u8, &v_busy_u8, &v_temp_u16, + v_xy1y2_u16, v_overflow_s8); + /* Calculate the linear data*/ + com_rslt += bmi160_bst_yas532_xy1y2_to_linear(v_xy1y2_u16, + v_xy1y2_linear_s32); + /* Calculate temperature correction */ + #if YAS532_MAG_LOG < YAS532_MAG_TEMPERATURE_LOG + yas532_data.temp_data.log[yas532_data.temp_data.idx++] = + v_temp_u16; + if (YAS532_MAG_TEMPERATURE_LOG <= yas532_data.temp_data.idx) + yas532_data.temp_data.idx = 0; + yas532_data.temp_data.num++; + if (YAS532_MAG_TEMPERATURE_LOG <= yas532_data.temp_data.num) + yas532_data.temp_data.num = YAS532_MAG_TEMPERATURE_LOG; + for (i = 0; i < yas532_data.temp_data.num; i++) + sum += yas532_data.temp_data.log[i]; + tmp = sum * 10 / yas532_data.temp_data.num + - YAS532_TEMP20DEGREE_TYPICAL * 10; + #else + tmp = (v_temp_u16 - YAS532_TEMP20DEGREE_TYPICAL) + * 10; + #endif + sx = v_xy1y2_linear_s32[0]; + sy1 = v_xy1y2_linear_s32[1]; + sy2 = v_xy1y2_linear_s32[2]; + /* Temperature correction */ + if (v_temp_correction_u8) { + sx -= (yas532_data.calib_yas532.cx * tmp) + / 1000; + sy1 -= (yas532_data.calib_yas532.cy1 * tmp) + / 1000; + sy2 -= (yas532_data.calib_yas532.cy2 * tmp) + / 1000; + } + sy = sy1 - sy2; + sz = -sy1 - sy2; + + xyz_data->yas532_vector_xyz[0] = yas532_data.calib_yas532.k * + ((100 * sx + yas532_data.calib_yas532.a2 * sy + + yas532_data.calib_yas532.a3 * sz) / 10); + xyz_data->yas532_vector_xyz[1] = yas532_data.calib_yas532.k * + ((yas532_data.calib_yas532.a4 * sx + yas532_data.calib_yas532.a5 * sy + + yas532_data.calib_yas532.a6 * sz) / 10); + xyz_data->yas532_vector_xyz[2] = yas532_data.calib_yas532.k * + ((yas532_data.calib_yas532.a7 * sx + yas532_data.calib_yas532.a8 * sy + + yas532_data.calib_yas532.a9 * sz) / 10); + if (yas532_data.transform != BMI160_NULL) { + for (i = 0; i < 3; i++) { + v_xyz_tmp_s32[i] = yas532_data.transform[i + * 3] * + xyz_data->yas532_vector_xyz[0] + + yas532_data.transform[i * 3 + 1] * + xyz_data->yas532_vector_xyz[1] + + yas532_data.transform[i * 3 + 2] * + xyz_data->yas532_vector_xyz[2]; + } + set_vector(xyz_data->yas532_vector_xyz, v_xyz_tmp_s32); + } + for (i = 0; i < 3; i++) { + xyz_data->yas532_vector_xyz[i] -= + xyz_data->yas532_vector_xyz[i] % 10; + if (*v_overflow_s8 & (1 + << (i * 2))) + xyz_data->yas532_vector_xyz[i] += + 1; /* set overflow */ + if (*v_overflow_s8 & (1 << + (i * 2 + 1))) + xyz_data->yas532_vector_xyz[i] += 2; /* set underflow */ + } + + +if (v_busy_u8) + return com_rslt; + if (0 < *v_overflow_s8) { + if (!yas532_data.overflow) + yas532_data.overflow = 1; + yas532_data.measure_state = YAS532_MAG_STATE_INIT_COIL; + } else + yas532_data.overflow = 0; + for (i = 0; i < 3; i++) + yas532_data.last_raw[i] = v_xy1y2_u16[i]; + yas532_data.last_raw[i] = v_temp_u16; + return com_rslt; +} +/*! + * @brief This function used for YAS532 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_acquisition_command_register( +u8 v_command_reg_data_u8) +{ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + + com_rslt = bmi160_set_mag_write_data(v_command_reg_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* YAMAHA YAS532-0x82*/ + com_rslt += bmi160_set_mag_write_addr( + BMI160_YAS532_COMMAND_REGISTER); + p_bmi160->delay_msec(BMI160_YAS_ACQ_COMMAND_DELAY); + com_rslt += bmi160_set_mag_read_addr( + BMI160_YAS532_DATA_REGISTER); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) + com_rslt += bmi160_set_mag_manual_enable(BMI160_MANUAL_DISABLE); + + return com_rslt; + +} +/*! + * @brief This function used write offset of YAS532 + * + * @param p_offset_s8 : The value of offset to write + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_set_offset( +const s8 *p_offset_s8) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) + com_rslt = bmi160_set_mag_manual_enable(BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_YAS532_OFFSET_DELAY); + + /* Write offset X data*/ + com_rslt = bmi160_set_mag_write_data(p_offset_s8[0]); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* YAS532 offset x write*/ + com_rslt += bmi160_set_mag_write_addr(BMI160_YAS532_OFFSET_X); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + /* Write offset Y data*/ + com_rslt = bmi160_set_mag_write_data(p_offset_s8[1]); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* YAS532 offset y write*/ + com_rslt += bmi160_set_mag_write_addr(BMI160_YAS532_OFFSET_Y); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + /* Write offset Z data*/ + com_rslt = bmi160_set_mag_write_data(p_offset_s8[2]); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* YAS532 offset z write*/ + com_rslt += bmi160_set_mag_write_addr(BMI160_YAS532_OFFSET_Z); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + set_vector(yas532_data.v_hard_offset_s8, p_offset_s8); + + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) + com_rslt = bmi160_set_mag_manual_enable(BMI160_MANUAL_DISABLE); + return com_rslt; +} +/*! + * @brief This function used to init the YAMAH-YAS537 + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_mag_interface_init( +void) +{ +/* This variable used for provide the communication +results*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +u8 v_pull_value_u8 = BMI160_INIT_VALUE; +u8 v_data_u8 = BMI160_INIT_VALUE; +u8 i = BMI160_INIT_VALUE; +/* accel operation mode to normal*/ +com_rslt = bmi160_set_command_register(ACCEL_MODE_NORMAL); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* write mag power mode as NORMAL*/ +com_rslt += bmi160_set_mag_interface_normal(); +/* register 0x7E write the 0x37, 0x9A and 0x30*/ +com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_ONE); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_TWO); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_command_register(BMI160_COMMAND_REG_THREE); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/*switch the page1*/ +com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE1); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +bmi160_get_target_page(&v_data_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_paging_enable(BMI160_WRITE_ENABLE_PAGE1); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +bmi160_get_paging_enable(&v_data_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* enable the pullup configuration from +the register 0x05 bit 4 and 5 as 10*/ +bmi160_get_pullup_configuration(&v_pull_value_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +v_pull_value_u8 = v_pull_value_u8 | BMI160_PULL_UP_DATA; +com_rslt += bmi160_set_pullup_configuration(v_pull_value_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/*switch the page0*/ +com_rslt += bmi160_set_target_page(BMI160_WRITE_TARGET_PAGE0); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +bmi160_get_target_page(&v_data_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* Write the YAS532 i2c address*/ +com_rslt += bmi160_set_i2c_device_addr(BMI160_YAS537_I2C_ADDRESS); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* enable the mag interface to manual mode*/ +com_rslt += bmi160_set_mag_manual_enable(BMI160_MANUAL_ENABLE); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +bmi160_get_mag_manual_enable(&v_data_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/*Enable the MAG interface */ +com_rslt += bmi160_set_if_mode(BMI160_ENABLE_MAG_IF_MODE); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +bmi160_get_if_mode(&v_data_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +v_data_u8 = BMI160_MANUAL_DISABLE; +/* Read the YAS537 device id*/ +com_rslt += bmi160_set_mag_read_addr(BMI160_YAS_DEVICE_ID_REG); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&v_data_u8, BMI160_GEN_READ_WRITE_DATA_LENGTH); +yas537_data.dev_id = v_data_u8; +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* Read the YAS532 calibration data*/ +com_rslt += +bmi160_bst_yamaha_yas537_calib_values( +BMI160_GEN_READ_WRITE_DATA_LENGTH); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* set the mode to NORMAL*/ +yas537_data.measure_state = YAS537_MAG_STATE_NORMAL; +/* set the transform to zero */ +yas537_data.transform = BMI160_NULL; +yas537_data.average = 32; +for (i = 0; i < 3; i++) { + yas537_data.hard_offset[i] = -128; + yas537_data.last_after_rcoil[i] = 0; +} +for (i = 0; i < 4; i++) + yas537_data.last_raw[i] = 0; +/* write the mag bandwidth as 25Hz*/ +com_rslt += bmi160_set_mag_output_data_rate( +BMI160_MAG_OUTPUT_DATA_RATE_25HZ); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* Enable mag interface to auto mode*/ +com_rslt += bmi160_set_mag_manual_enable( +BMI160_MANUAL_DISABLE); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +bmi160_get_mag_manual_enable(&v_data_u8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +return com_rslt; +} +/*! +* @brief This function used for read the +* YAMAHA YAS537 calibration data +* +* +* @param v_rcoil_u8 : The value of r coil +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_calib_values( +u8 v_rcoil_u8) +{ +/* This variable used for provide the communication +results*/ +BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; +/* Array holding the YAS532 calibration values */ +u8 a_data_u8[BMI160_YAS537_CALIB_DATA_SIZE] = { +BMI160_INIT_VALUE, BMI160_INIT_VALUE, +BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, +BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, +BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, +BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, +BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, +}; +static const u8 v_avrr_u8[] = {0x50, 0x60, 0x70}; +u8 v_cal_valid_u8 = BMI160_INIT_VALUE, i; +/* write soft reset as 0x02*/ +com_rslt = bmi160_set_mag_write_data( +YAS537_SRSTR_DATA); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_mag_write_addr(YAS537_REG_SRSTR); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* Read the DX value */ +com_rslt = bmi160_set_mag_read_addr(YAS537_REG_CALR_C0); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[0], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the DY1 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C1); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[1], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the DY2 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C2); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[2], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D2 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C3); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[3], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D3 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C4); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[4], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D4 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C5); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[5], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D5 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C6); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[6], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D6 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C7); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[7], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D7 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C8); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[8], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D8 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_C9); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[9], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the D9 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_CA); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[10], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RX value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_CB); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[11], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RY1 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_CC); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[12], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RY2 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_CD); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[13], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the RY2 value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_CE); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[14], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the CHF value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_CF); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[15], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* Read the VER value */ +com_rslt += bmi160_set_mag_read_addr(YAS537_REG_CALR_DO); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +/* 0x04 is secondary read mag x lsb register */ +com_rslt += bmi160_read_reg(BMI160_MAG_DATA_READ_REG, +&a_data_u8[16], BMI160_GEN_READ_WRITE_DATA_LENGTH); +/* get the calib ver*/ +yas537_data.calib_yas537.ver = +(a_data_u8[16] >> BMI160_SHIFT_BIT_POSITION_BY_06_BITS); +for (i = 0; i < 17; i++) { + if (((i < 16 && a_data_u8[i]) != 0)) + v_cal_valid_u8 = 1; + if ((i < 16 && + (a_data_u8[i] & 0x3F)) != 0) + v_cal_valid_u8 = 1; +} +if (!v_cal_valid_u8) + return ERROR; +if (yas537_data.calib_yas537.ver == 0) { + for (i = 0; i < 17; i++) { + if (i < 12) { + /* write offset*/ + com_rslt += bmi160_set_mag_write_data( + a_data_u8[i]); + p_bmi160->delay_msec( + BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + YAS537_REG_MTCR + i); + p_bmi160->delay_msec( + BMI160_GEN_READ_WRITE_DELAY); + } else if (i < 15) { + /* write offset correction*/ + com_rslt += bmi160_set_mag_write_data( + a_data_u8[i]); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(( + (YAS537_REG_OXR + i) - 12)); + p_bmi160->delay_msec( + BMI160_GEN_READ_WRITE_DELAY); + yas537_data.hard_offset[i - 12] + = a_data_u8[i]; + } else { + /* write offset correction*/ + com_rslt += bmi160_set_mag_write_data( + a_data_u8[i]); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(( + (YAS537_REG_OXR + i) - 11)); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + } + +} +} else if (yas537_data.calib_yas537.ver == 1) { + for (i = 0; i < 3; i++) { + /* write offset*/ + com_rslt += bmi160_set_mag_write_data( + a_data_u8[i]); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + YAS537_REG_MTCR + i); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + if (com_rslt == SUCCESS) { + /* write offset*/ + com_rslt += bmi160_set_mag_write_data( + a_data_u8[i + 12]); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + YAS537_REG_OXR + i); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + yas537_data.hard_offset[i] = + a_data_u8[i + 12]; + } else { + com_rslt = ERROR; + } + } + /* write offset*/ + com_rslt += bmi160_set_mag_write_data( + ((a_data_u8[i] & 0xE0) | 0x10)); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr( + YAS537_REG_MTCR + i); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write offset*/ + com_rslt += bmi160_set_mag_write_data( + ((a_data_u8[15] + >> BMI160_SHIFT_BIT_POSITION_BY_03_BITS) + & 0x1E)); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(YAS537_REG_HCKR); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write offset*/ + com_rslt += bmi160_set_mag_write_data( + ((a_data_u8[15] << 1) & 0x1E)); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(YAS537_REG_LCKR); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* write offset*/ + com_rslt += bmi160_set_mag_write_data( + (a_data_u8[16] & 0x3F)); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(YAS537_REG_OCR); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + + /* Assign the calibration values*/ + /* a2 */ + yas537_data.calib_yas537.a2 = + ((((a_data_u8[3] + << BMI160_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x7C) + | (a_data_u8[4] + >> BMI160_SHIFT_BIT_POSITION_BY_06_BITS)) - 64); + /* a3 */ + yas537_data.calib_yas537.a3 = + ((((a_data_u8[4] << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) + & 0x7E) + | (a_data_u8[5] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS)) - 64); + /* a4 */ + yas537_data.calib_yas537.a4 = + ((((a_data_u8[5] + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) + & 0xFE) + | (a_data_u8[6] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS)) + - 128); + /* a5 */ + yas537_data.calib_yas537.a5 = + ((((a_data_u8[6] + << BMI160_SHIFT_BIT_POSITION_BY_02_BITS) + & 0x1FC) + | (a_data_u8[7] + >> BMI160_SHIFT_BIT_POSITION_BY_06_BITS)) + - 112); + /* a6 */ + yas537_data.calib_yas537.a6 = + ((((a_data_u8[7] + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) + & 0x7E) + | (a_data_u8[8] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS)) - 64); + /* a7 */ + yas537_data.calib_yas537.a7 = + ((((a_data_u8[8] + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) + & 0xFE) + | (a_data_u8[9] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS)) + - 128); + /* a8 */ + yas537_data.calib_yas537.a8 = ((a_data_u8[9] & + 0x7F) - 64); + /* a9 */ + yas537_data.calib_yas537.a9 = ((((a_data_u8[10] + << BMI160_SHIFT_BIT_POSITION_BY_01_BIT) & 0x1FE) + | (a_data_u8[11] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS)) + - 112); + /* k */ + yas537_data.calib_yas537.k = ( + a_data_u8[11] & 0x7F); + } else { + return ERROR; + } +/* write A/D converter*/ +com_rslt += bmi160_set_mag_write_data( +YAS537_WRITE_A_D_CONVERTER); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_mag_write_addr(YAS537_REG_ADCCALR); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* write A/D converter second register*/ +com_rslt += bmi160_set_mag_write_data( +YAS537_WRITE_A_D_CONVERTER2); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_mag_write_addr(YAS537_REG_ADCCALR_ONE); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* write temperature calibration register*/ +com_rslt += bmi160_set_mag_write_data(YAS537_WRITE_TEMP_CALIB); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_mag_write_addr(YAS537_REG_TRMR); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +/* write average filter register*/ +com_rslt += bmi160_set_mag_write_data( +v_avrr_u8[yas537_data.average]); +p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); +com_rslt += bmi160_set_mag_write_addr(YAS537_REG_AVRR); +p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +if (v_rcoil_u8) { + /* write average; filter register*/ + com_rslt += bmi160_set_mag_write_data( + YAS537_WRITE_FILTER); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(YAS537_REG_CONFR); + p_bmi160->delay_msec( + BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); +} + +return com_rslt; + +} +/*! + * @brief This function used for YAS537 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas537_acquisition_command_register( +u8 v_command_reg_data_u8) +{ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + com_rslt = bmi160_set_mag_write_data(v_command_reg_data_u8); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + /* YAMAHA YAS532-0x82*/ + com_rslt += bmi160_set_mag_write_addr( + BMI160_REG_YAS537_CMDR); + /* set the mode to RECORD*/ + yas537_data.measure_state = YAS537_MAG_STATE_RECORD_DATA; + p_bmi160->delay_msec(BMI160_YAS_ACQ_COMMAND_DELAY); + com_rslt += bmi160_set_mag_read_addr( + YAS537_REG_TEMPERATURE_0); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) + com_rslt += bmi160_set_mag_manual_enable( + BMI160_MANUAL_DISABLE); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + + return com_rslt; + +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param xy1y2: The value of raw xy1y2 data + * @param xyz: The value of xyz data + * + * + * @return None + * + * + */ +static void xy1y2_to_xyz(u16 *xy1y2, s32 *xyz) +{ + xyz[0] = ((xy1y2[0] - 8192) + * 300); + xyz[1] = (((xy1y2[1] - xy1y2[2]) + * 1732) / 10); + xyz[2] = (((-xy1y2[2] - xy1y2[2]) + + 16384) * 300); +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_coil_stat_u8: The value of R coil status + * @param v_busy_u8: The value of busy status + * @param v_temperature_u16: The value of temperature + * @param xy1y2: The value of raw xy1y2 data + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_read_xy1y2_data( +u8 *v_coil_stat_u8, u8 *v_busy_u8, +u16 *v_temperature_u16, u16 *xy1y2, u8 *v_ouflow_u8) +{ + /* This variable used for provide the communication + results*/ + BMI160_RETURN_FUNCTION_TYPE com_rslt = E_BMI160_COMM_RES; + /* Array holding the YAS532 calibration values */ + u8 a_data_u8[BMI160_YAS_XY1Y2T_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE, + }; + u8 i = BMI160_INIT_VALUE; + s32 a_h_s32[BMI160_YAS_H_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + s32 a_s_s32[BMI160_YAS_S_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + /* set command register*/ + com_rslt = bmi160_bst_yas537_acquisition_command_register( + YAS537_SET_COMMAND_REGISTER); + /* read the yas537 sensor data of xy1y2*/ + com_rslt += + p_bmi160->BMI160_BUS_READ_FUNC(p_bmi160->dev_addr, + BMI160_USER_DATA_MAG_X_LSB__REG, + a_data_u8, BMI160_MAG_YAS_DATA_LENGTH); + /* read the busy flag*/ + *v_busy_u8 = a_data_u8[2] + >> BMI160_SHIFT_BIT_POSITION_BY_07_BITS; + /* read the coil status*/ + *v_coil_stat_u8 = + ((a_data_u8[2] >> + BMI160_SHIFT_BIT_POSITION_BY_06_BITS) & 0X01); + /* read temperature data*/ + *v_temperature_u16 = (u16)((a_data_u8[0] + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) | a_data_u8[1]); + /* read x data*/ + xy1y2[0] = (u16)(((a_data_u8[2] & + 0x3F) + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | (a_data_u8[3])); + /* read y1 data*/ + xy1y2[1] = (u16)((a_data_u8[4] + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | a_data_u8[5]); + /* read y2 data*/ + xy1y2[2] = (u16)((a_data_u8[6] + << BMI160_SHIFT_BIT_POSITION_BY_08_BITS) + | a_data_u8[7]); + for (i = 0; i < 3; i++) + yas537_data.last_raw[i] = xy1y2[i]; + yas537_data.last_raw[i] = *v_temperature_u16; + if (yas537_data.calib_yas537.ver == 1) { + for (i = 0; i < 3; i++) + a_s_s32[i] = xy1y2[i] - 8192; + /* read hx*/ + a_h_s32[0] = ((yas537_data.calib_yas537.k * ( + (128 * a_s_s32[0]) + + (yas537_data.calib_yas537.a2 * a_s_s32[1]) + + (yas537_data.calib_yas537.a3 * a_s_s32[2]))) + / (8192)); + /* read hy1*/ + a_h_s32[1] = ((yas537_data.calib_yas537.k * ( + (yas537_data.calib_yas537.a4 * a_s_s32[0]) + + (yas537_data.calib_yas537.a5 * a_s_s32[1]) + + (yas537_data.calib_yas537.a6 * a_s_s32[2]))) + / (8192)); + /* read hy2*/ + a_h_s32[2] = ((yas537_data.calib_yas537.k * ( + (yas537_data.calib_yas537.a7 * a_s_s32[0]) + + (yas537_data.calib_yas537.a8 * a_s_s32[1]) + + (yas537_data.calib_yas537.a9 * a_s_s32[2]))) + / (8192)); + + for (i = 0; i < 3; i++) { + if (a_h_s32[i] < -8192) + a_h_s32[i] = -8192; + + if (8192 < a_h_s32[i]) + a_h_s32[i] = 8192; + + xy1y2[i] = a_h_s32[i] + 8192; + + } + } + *v_ouflow_u8 = 0; + for (i = 0; i < 3; i++) { + if (YAS537_DATA_OVERFLOW <= xy1y2[i]) + *v_ouflow_u8 |= (1 << (i * 2)); + if (xy1y2[i] == YAS537_DATA_UNDERFLOW) + *v_ouflow_u8 |= (1 << (i * 2 + 1)); + } + + return com_rslt; + +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +static BMI160_RETURN_FUNCTION_TYPE invalid_magnetic_field( +u16 *v_cur_u16, u16 *v_last_u16) +{ + s16 invalid_thresh[] = {1500, 1500, 1500}; + u8 i = BMI160_INIT_VALUE; + + for (i = 0; i < 3; i++) + if (invalid_thresh[i] < ABS(v_cur_u16[i] - v_last_u16[i])) + return 1; + return 0; +} +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_measure_xyz_data( +u8 *v_ouflow_u8, struct yas_vector *vector_xyz) +{ + s32 a_xyz_tmp_s32[BMI160_YAS_TEMP_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + u8 i = BMI160_INIT_VALUE; + s8 com_rslt = BMI160_INIT_VALUE; + u8 v_busy_u8 = BMI160_INIT_VALUE; + u8 v_rcoil_u8 = BMI160_INIT_VALUE; + u16 v_temperature_u16 = BMI160_INIT_VALUE; + u16 a_xy1y2_u16[BMI160_YAS_XY1Y2_DATA_SIZE] = { + BMI160_INIT_VALUE, BMI160_INIT_VALUE, BMI160_INIT_VALUE}; + *v_ouflow_u8 = 0; + /* read the yas537 xy1y2 data*/ + com_rslt = bmi160_bst_yamaha_yas537_read_xy1y2_data( + &v_rcoil_u8, &v_busy_u8, + &v_temperature_u16, a_xy1y2_u16, v_ouflow_u8); + /* linear calculation*/ + xy1y2_to_xyz(a_xy1y2_u16, vector_xyz->yas537_vector_xyz); + if (yas537_data.transform != BMI160_NULL) { + for (i = 0; i < 3; i++) { + a_xyz_tmp_s32[i] = (( + yas537_data.transform[i + 3] + * vector_xyz->yas537_vector_xyz[0]) + + (yas537_data.transform[ + i * 3 + 1] + * vector_xyz->yas537_vector_xyz[1]) + + (yas537_data.transform[ + i * 3 + 2] + * vector_xyz->yas537_vector_xyz[2])); + } + yas537_set_vector( + vector_xyz->yas537_vector_xyz, a_xyz_tmp_s32); + } + for (i = 0; i < 3; i++) { + vector_xyz->yas537_vector_xyz[i] -= + vector_xyz->yas537_vector_xyz[i] % 10; + if (*v_ouflow_u8 & (1 << + (i * 2))) + vector_xyz->yas537_vector_xyz[i] += + 1; /* set overflow */ + if (*v_ouflow_u8 & (1 << (i * 2 + 1))) + /* set underflow */ + vector_xyz->yas537_vector_xyz[i] += 2; + } + if (v_busy_u8) + return ERROR; + switch (yas537_data.measure_state) { + case YAS537_MAG_STATE_INIT_COIL: + if (p_bmi160->mag_manual_enable != BMI160_MANUAL_ENABLE) + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_ENABLE); + com_rslt += bmi160_set_mag_write_data(YAS537_WRITE_CONFR); + p_bmi160->delay_msec(BMI160_GEN_READ_WRITE_DELAY); + com_rslt += bmi160_set_mag_write_addr(YAS537_REG_CONFR); + p_bmi160->delay_msec(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + yas537_data.measure_state = YAS537_MAG_STATE_RECORD_DATA; + if (p_bmi160->mag_manual_enable == BMI160_MANUAL_ENABLE) + com_rslt = bmi160_set_mag_manual_enable( + BMI160_MANUAL_DISABLE); + break; + case YAS537_MAG_STATE_RECORD_DATA: + if (v_rcoil_u8) + break; + yas537_set_vector(yas537_data.last_after_rcoil, a_xy1y2_u16); + yas537_data.measure_state = YAS537_MAG_STATE_NORMAL; + break; + case YAS537_MAG_STATE_NORMAL: + if (BMI160_INIT_VALUE < v_ouflow_u8 + || invalid_magnetic_field(a_xy1y2_u16, + yas537_data.last_after_rcoil)) { + yas537_data.measure_state = YAS537_MAG_STATE_INIT_COIL; + for (i = 0; i < 3; i++) { + if (!*v_ouflow_u8) + vector_xyz->yas537_vector_xyz[i] += 3; + } + } + break; + } + + return com_rslt; +} +/*! + * @brief This function used for reading + * bmi160_t structure + * + * @return the reference and values of bmi160_t + * + * +*/ +struct bmi160_t *bmi160_get_ptr(void) +{ + return p_bmi160; +} diff --git a/drivers/input/misc/bmi160.h b/drivers/input/misc/bmi160.h new file mode 100755 index 00000000000..fdfa5b77001 --- /dev/null +++ b/drivers/input/misc/bmi160.h @@ -0,0 +1,11605 @@ +/* +**************************************************************************** +* Copyright (C) 2014 Bosch Sensortec GmbH +* +* bmi160.h +* Date : 2015/04/02 +* @id "2e89046" +* Revision : 2.0.9 $ +* @brief +* The head file of BMI160API +* +**************************************************************************** +* +* \section Disclaimer +* +* Common: +* Bosch Sensortec products are developed for the consumer goods industry. +* They may only be used within the parameters of the respective valid +* product data sheet. Bosch Sensortec products are provided with the +* express understanding that there is no warranty of fitness for a +* particular purpose.They are not fit for use in life-sustaining, +* safety or security sensitive systems or any system or device +* that may lead to bodily harm or property damage if the system +* or device malfunctions. In addition,Bosch Sensortec products are +* not fit for use in products which interact with motor vehicle systems. +* The resale and or use of products are at the purchasers own risk and +* his own responsibility. The examination of fitness for the intended use +* is the sole responsibility of the Purchaser. +* +* The purchaser shall indemnify Bosch Sensortec from all third party +* claims, including any claims for incidental, or consequential damages, +* arising from any product use not covered by the parameters of +* the respective valid product data sheet or not approved by +* Bosch Sensortec and reimburse Bosch Sensortec for all costs in +* connection with such claims. +* +* The purchaser must monitor the market for the purchased products, +* particularly with regard to product safety and inform Bosch Sensortec +* without delay of all security relevant incidents. +* +* Engineering Samples are marked with an asterisk (*) or (e). +* Samples may vary from the valid technical specifications of the product +* series. They are therefore not intended or fit for resale to third +* parties or for use in end products. Their sole purpose is internal +* client testing. The testing of an engineering sample may in no way +* replace the testing of a product series. Bosch Sensortec assumes +* no liability for the use of engineering samples. +* By accepting the engineering samples, the Purchaser agrees to indemnify +* Bosch Sensortec from all claims arising from the use of engineering +* samples. +* +* Special: +* This software module (hereinafter called "Software") and any information +* on application-sheets (hereinafter called "Information") is provided +* free of charge for the sole purpose to support your application work. +* The Software and Information is subject to the following +* terms and conditions: +* +* The Software is specifically designed for the exclusive use for +* Bosch Sensortec products by personnel who have special experience +* and training. Do not use this Software if you do not have the +* proper experience or training. +* +* This Software package is provided `` as is `` and without any expressed +* or implied warranties,including without limitation, the implied warranties +* of merchantability and fitness for a particular purpose. +* +* Bosch Sensortec and their representatives and agents deny any liability +* for the functional impairment +* of this Software in terms of fitness, performance and safety. +* Bosch Sensortec and their representatives and agents shall not be liable +* for any direct or indirect damages or injury, except as +* otherwise stipulated in mandatory applicable law. +* +* The Information provided is believed to be accurate and reliable. +* Bosch Sensortec assumes no responsibility for the consequences of use +* of such Information nor for any infringement of patents or +* other rights of third parties which may result from its use. +* No license is granted by implication or otherwise under any patent or +* patent rights of Bosch. Specifications mentioned in the Information are +* subject to change without notice. +**************************************************************************/ +/*! \file bmi160.h + \brief BMI160 Sensor Driver Support Header File */ +/* user defined code to be added here ... */ +#ifndef __BMI160_H__ +#define __BMI160_H__ + + +#include + +/***************************************************************/ +/**\name BUS READ AND WRITE FUNCTION POINTERS */ +/***************************************************************/ +/*! + @brief Define the calling convention of YOUR bus communication routine. + @note This includes types of parameters. This example shows the + configuration for an SPI bus link. + + If your communication function looks like this: + + write_my_bus_xy(u8 device_addr, u8 register_addr, + u8 * data, u8 length); + + The BMI160_WR_FUNC_PTR would equal: + + BMI160_WR_FUNC_PTR s8 (* bus_write)(u8, + u8, u8 *, u8) + + Parameters can be mixed as needed refer to the + @ref BMI160_BUS_WRITE_FUNC macro. + + +*/ +#define BMI160_WR_FUNC_PTR s8 (*bus_write)(u8, u8,\ +u8 *, u8) +/**< link macro between API function calls and bus write function + @note The bus write function can change since this is a + system dependant issue. + + If the bus_write parameter calling order is like: reg_addr, + reg_data, wr_len it would be as it is here. + + If the parameters are differently ordered or your communication + function like I2C need to know the device address, + you can change this macro accordingly. + + + BMI160_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_write(dev_addr, reg_addr, reg_data, wr_len) + + This macro lets all API functions call YOUR communication routine in a + way that equals your definition in the + @ref BMI160_WR_FUNC_PTR definition. + +*/ +#define BMI160_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_write(dev_addr, reg_addr, reg_data, wr_len) + +/**< Define the calling convention of YOUR bus communication routine. + @note This includes types of parameters. This example shows the + configuration for an SPI bus link. + + If your communication function looks like this: + + read_my_bus_xy(u8 device_addr, u8 register_addr, + u8 * data, u8 length); + + The BMI160_RD_FUNC_PTR would equal: + + BMI160_RD_FUNC_PTR s8 (* bus_read)(u8, + u8, u8 *, u8) + + Parameters can be mixed as needed refer to the + refer BMI160_BUS_READ_FUNC macro. + +*/ +#define BMI160_SPI_RD_MASK (0x80) /* for spi read transactions on SPI the + MSB has to be set */ +#define BMI160_RD_FUNC_PTR s8 (*bus_read)(u8,\ + u8, u8 *, u8) + +#define BMI160_BRD_FUNC_PTR s8 \ +(*burst_read)(u8, u8, u8 *, u32) + +/**< link macro between API function calls and bus read function + @note The bus write function can change since this is a + system dependant issue. + + If the bus_read parameter calling order is like: reg_addr, + reg_data, wr_len it would be as it is here. + + If the parameters are differently ordered or your communication + function like I2C need to know the device address, + you can change this macro accordingly. + + + BMI160_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_read(dev_addr, reg_addr, reg_data, wr_len) + + This macro lets all API functions call YOUR communication routine in a + way that equals your definition in the + refer BMI160_WR_FUNC_PTR definition. + + @note: this macro also includes the "MSB='1' + for reading BMI160 addresses. + +*/ +#define BMI160_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, r_len)\ + bus_read(dev_addr, reg_addr, reg_data, r_len) + +#define BMI160_BURST_READ_FUNC(device_addr, \ +register_addr, register_data, rd_len)\ +burst_read(device_addr, register_addr, register_data, rd_len) + + +#define BMI160_MDELAY_DATA_TYPE u32 + +/***************************************************************/ +/**\name BUS READ AND WRITE FUNCTION POINTERS */ +/***************************************************************/ +#define BMI160_I2C_ADDR1 0x68 /**< I2C Address needs to be changed */ +#define BMI160_I2C_ADDR2 0x69 /**< I2C Address needs to be changed */ +#define BMI160_AUX_BMM150_I2C_ADDRESS (0x10) +#define BMI160_AUX_YAS532_I2C_ADDRESS (0x2E) +/**< I2C address of YAS532*/ +#define BMI160_AKM09911_I2C_ADDRESS 0x0C/**< I2C address of AKM09911*/ +/**< I2C address of AKM09911*/ +#define BMI160_AUX_AKM09911_I2C_ADDR_2 (0x0D) +/**< I2C address of AKM09911*/ +#define BMI160_AUX_AKM09912_I2C_ADDR_1 (0x0C) +/**< I2C address of AKM09912*/ +#define BMI160_AUX_AKM09912_I2C_ADDR_2 (0x0D) +/**< I2C address of AKM09912*/ +#define BMI160_AUX_AKM09912_I2C_ADDR_3 (0x0E) +/**< I2C address of AKM09912*/ +#define BMI160_AKM09912_I2C_ADDRESS 0x0F/**< I2C address of akm09912*/ + +#define BMI160_YAS532_I2C_ADDRESS 0x2E/**< I2C address of YAS532*/ +/*******************************************/ +/**\name CONSTANTS */ +/******************************************/ +#define BMI160_INIT_VALUE (0) +#define BMI160_GEN_READ_WRITE_DATA_LENGTH (1) +#define BMI160_MAXIMUM_TIMEOUT (10) +/* output data rate condition check*/ +#define BMI160_OUTPUT_DATA_RATE0 (0) +#define BMI160_OUTPUT_DATA_RATE1 (1) +#define BMI160_OUTPUT_DATA_RATE2 (2) +#define BMI160_OUTPUT_DATA_RATE3 (3) +#define BMI160_OUTPUT_DATA_RATE4 (4) +#define BMI160_OUTPUT_DATA_RATE5 (5) +#define BMI160_OUTPUT_DATA_RATE6 (14) +#define BMI160_OUTPUT_DATA_RATE7 (15) +/* accel range check*/ +#define BMI160_ACCEL_RANGE0 (3) +#define BMI160_ACCEL_RANGE1 (5) +#define BMI160_ACCEL_RANGE3 (8) +#define BMI160_ACCEL_RANGE4 (12) +/* check the status of registers*/ +#define BMI160_FOC_STAT_HIGH (1) +#define BMI160_SIG_MOTION_STAT_HIGH (1) +#define BMI160_STEP_DET_STAT_HIGH (1) + +/*condition check for reading and writing data*/ +#define BMI160_MAX_VALUE_SIGNIFICANT_MOTION (1) +#define BMI160_MAX_VALUE_FIFO_FILTER (1) +#define BMI160_MAX_VALUE_FIFO_TIME (1) +#define BMI160_MAX_VALUE_FIFO_INTR (1) +#define BMI160_MAX_VALUE_FIFO_HEADER (1) +#define BMI160_MAX_VALUE_FIFO_MAG (1) +#define BMI160_MAX_VALUE_FIFO_ACCEL (1) +#define BMI160_MAX_VALUE_FIFO_GYRO (1) +#define BMI160_MAX_VALUE_SOURCE_INTR (1) +#define BMI160_MAX_VALUE_LOW_G_MODE (1) +#define BMI160_MAX_VALUE_NO_MOTION (1) +#define BMI160_MAX_VALUE_TAP_SHOCK (1) +#define BMI160_MAX_VALUE_TAP_QUIET (1) +#define BMI160_MAX_VALUE_ORIENT_UD (1) +#define BMI160_MAX_VALUE_ORIENT_AXES (1) +#define BMI160_MAX_VALUE_NVM_PROG (1) +#define BMI160_MAX_VALUE_SPI3 (1) +#define BMI160_MAX_VALUE_PAGE (1) +#define BMI160_MAX_VALUE_I2C_WDT (1) +#define BMI160_MAX_VALUE_SLEEP_STATE (1) +#define BMI160_MAX_VALUE_WAKEUP_INTR (1) +#define BMI160_MAX_VALUE_SELFTEST_SIGN (1) +#define BMI160_MAX_VALUE_SELFTEST_AMP (1) +#define BMI160_MAX_VALUE_SELFTEST_START (1) +#define BMI160_MAX_GYRO_WAKEUP_TRIGGER (3) +#define BMI160_MAX_ACCEL_SELFTEST_AXIS (3) +#define BMI160_MAX_GYRO_STEP_COUNTER (1) +#define BMI160_MAX_GYRO_BW (3) +#define BMI160_MAX_ACCEL_BW (7) +#define BMI160_MAX_ORIENT_MODE (3) +#define BMI160_MAX_ORIENT_BLOCKING (3) +#define BMI160_MAX_FLAT_HOLD (3) +#define BMI160_MAX_ACCEL_FOC (3) +#define BMI160_MAX_IF_MODE (3) +#define BMI160_MAX_TARGET_PAGE (3) +#define BMI160_MAX_GYRO_RANGE (4) +#define BMI160_MAX_GYRO_SLEEP_TIGGER (7) +#define BMI160_MAX_TAP_TURN (7) +#define BMI160_MAX_UNDER_SAMPLING (1) +#define BMI160_MAX_UNDER_SIG_MOTION (3) +#define BMI160_MAX_ACCEL_OUTPUT_DATA_RATE (12) +#define BMI160_MAX_LATCH_INTR (15) +#define BMI160_MAX_FLAT_HYST (15) +#define BMI160_MAX_ORIENT_THETA (63) +#define BMI160_MAX_FLAT_THETA (63) + +/* FIFO index definitions*/ +#define BMI160_FIFO_X_LSB_DATA (0) +#define BMI160_FIFO_X_MSB_DATA (1) +#define BMI160_FIFO_Y_LSB_DATA (2) +#define BMI160_FIFO_Y_MSB_DATA (3) +#define BMI160_FIFO_Z_LSB_DATA (4) +#define BMI160_FIFO_Z_MSB_DATA (5) +#define BMI160_FIFO_R_LSB_DATA (6) +#define BMI160_FIFO_R_MSB_DATA (7) +/* FIFO gyro definition*/ +#define BMI160_GA_FIFO_G_X_LSB (0) +#define BMI160_GA_FIFO_G_X_MSB (1) +#define BMI160_GA_FIFO_G_Y_LSB (2) +#define BMI160_GA_FIFO_G_Y_MSB (3) +#define BMI160_GA_FIFO_G_Z_LSB (4) +#define BMI160_GA_FIFO_G_Z_MSB (5) +#define BMI160_GA_FIFO_A_X_LSB (6) +#define BMI160_GA_FIFO_A_X_MSB (7) +#define BMI160_GA_FIFO_A_Y_LSB (8) +#define BMI160_GA_FIFO_A_Y_MSB (9) +#define BMI160_GA_FIFO_A_Z_LSB (10) +#define BMI160_GA_FIFO_A_Z_MSB (11) +/* FIFO mag/gyro/accel definition*/ +#define BMI160_MGA_FIFO_M_X_LSB (0) +#define BMI160_MGA_FIFO_M_X_MSB (1) +#define BMI160_MGA_FIFO_M_Y_LSB (2) +#define BMI160_MGA_FIFO_M_Y_MSB (3) +#define BMI160_MGA_FIFO_M_Z_LSB (4) +#define BMI160_MGA_FIFO_M_Z_MSB (5) +#define BMI160_MGA_FIFO_M_R_LSB (6) +#define BMI160_MGA_FIFO_M_R_MSB (7) +#define BMI160_MGA_FIFO_G_X_LSB (8) +#define BMI160_MGA_FIFO_G_X_MSB (9) +#define BMI160_MGA_FIFO_G_Y_LSB (10) +#define BMI160_MGA_FIFO_G_Y_MSB (11) +#define BMI160_MGA_FIFO_G_Z_LSB (12) +#define BMI160_MGA_FIFO_G_Z_MSB (13) +#define BMI160_MGA_FIFO_A_X_LSB (14) +#define BMI160_MGA_FIFO_A_X_MSB (15) +#define BMI160_MGA_FIFO_A_Y_LSB (16) +#define BMI160_MGA_FIFO_A_Y_MSB (17) +#define BMI160_MGA_FIFO_A_Z_LSB (18) +#define BMI160_MGA_FIFO_A_Z_MSB (19) +/* FIFO mag definition*/ +#define BMI160_MA_FIFO_M_X_LSB (0) +#define BMI160_MA_FIFO_M_X_MSB (1) +#define BMI160_MA_FIFO_M_Y_LSB (2) +#define BMI160_MA_FIFO_M_Y_MSB (3) +#define BMI160_MA_FIFO_M_Z_LSB (4) +#define BMI160_MA_FIFO_M_Z_MSB (5) +#define BMI160_MA_FIFO_M_R_LSB (6) +#define BMI160_MA_FIFO_M_R_MSB (7) +#define BMI160_MA_FIFO_A_X_LSB (8) +#define BMI160_MA_FIFO_A_X_MSB (9) +#define BMI160_MA_FIFO_A_Y_LSB (10) +#define BMI160_MA_FIFO_A_Y_MSB (11) +#define BMI160_MA_FIFO_A_Z_LSB (12) +#define BMI160_MA_FIFO_A_Z_MSB (13) +/* FIFO mag/gyro definition*/ +#define BMI160_MG_FIFO_M_X_LSB (0) +#define BMI160_MG_FIFO_M_X_MSB (1) +#define BMI160_MG_FIFO_M_Y_LSB (2) +#define BMI160_MG_FIFO_M_Y_MSB (3) +#define BMI160_MG_FIFO_M_Z_LSB (4) +#define BMI160_MG_FIFO_M_Z_MSB (5) +#define BMI160_MG_FIFO_M_R_LSB (6) +#define BMI160_MG_FIFO_M_R_MSB (7) +#define BMI160_MG_FIFO_G_X_LSB (8) +#define BMI160_MG_FIFO_G_X_MSB (9) +#define BMI160_MG_FIFO_G_Y_LSB (10) +#define BMI160_MG_FIFO_G_Y_MSB (11) +#define BMI160_MG_FIFO_G_Z_LSB (12) +#define BMI160_MG_FIFO_G_Z_MSB (13) +/* FIFO length definitions*/ +#define BMI160_FIFO_SENSOR_TIME_LSB (0) +#define BMI160_FIFO_SENSOR_TIME_XLSB (1) +#define BMI160_FIFO_SENSOR_TIME_MSB (2) +#define BMI160_FIFO_SENSOR_TIME_LENGTH (3) +#define BMI160_FIFO_A_LENGTH (6) +#define BMI160_FIFO_G_LENGTH (6) +#define BMI160_FIFO_M_LENGTH (8) +#define BMI160_FIFO_AG_LENGTH (12) +#define BMI160_FIFO_AMG_LENGTH (20) +#define BMI160_FIFO_MA_OR_MG_LENGTH (14) + +/* bus read and write length for mag, accel and gyro*/ +#define BMI160_MAG_X_DATA_LENGTH (2) +#define BMI160_MAG_Y_DATA_LENGTH (2) +#define BMI160_MAG_Z_DATA_LENGTH (2) +#define BMI160_MAG_R_DATA_LENGTH (2) +#define BMI160_MAG_XYZ_DATA_LENGTH (6) +#define BMI160_MAG_XYZR_DATA_LENGTH (8) +#define BMI160_MAG_YAS_DATA_LENGTH (8) +#define BMI160_GYRO_DATA_LENGTH (2) +#define BMI160_GYRO_XYZ_DATA_LENGTH (6) +#define BMI160_ACCEL_DATA_LENGTH (2) +#define BMI160_ACCEL_XYZ_DATA_LENGTH (6) +#define BMI160_TEMP_DATA_LENGTH (2) +#define BMI160_FIFO_DATA_LENGTH (2) +#define BMI160_STEP_COUNTER_LENGTH (2) +#define BMI160_SENSOR_TIME_LENGTH (3) + +/* Delay definitions*/ +#define BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY (5) +#define BMI160_BMM150_WAKEUP_DELAY1 (2) +#define BMI160_BMM150_WAKEUP_DELAY2 (3) +#define BMI160_BMM150_WAKEUP_DELAY3 (1) +#define BMI160_YAS532_OFFSET_DELAY (2) +#define BMI160_GEN_READ_WRITE_DELAY (1) +#define BMI160_YAS532_MEASUREMENT_DELAY (25) +#define BMI160_YAS_ACQ_COMMAND_DELAY (50) +#define BMI160_YAS532_SET_INITIAL_VALUE_DELAY (200) +#define BMI160_AKM_INIT_DELAY (60) +/****************************************************/ +/**\name ARRAY SIZE DEFINITIONS */ +/***************************************************/ +#define BMI160_ACCEL_X_DATA_SIZE (2) +#define BMI160_ACCEL_Y_DATA_SIZE (2) +#define BMI160_ACCEL_Z_DATA_SIZE (2) +#define BMI160_ACCEL_XYZ_DATA_SIZE (6) + +#define BMI160_GYRO_X_DATA_SIZE (2) +#define BMI160_GYRO_Y_DATA_SIZE (2) +#define BMI160_GYRO_Z_DATA_SIZE (2) +#define BMI160_GYRO_XYZ_DATA_SIZE (6) + +#define BMI160_MAG_X_DATA_SIZE (2) +#define BMI160_MAG_Y_DATA_SIZE (2) +#define BMI160_MAG_Z_DATA_SIZE (2) +#define BMI160_MAG_R_DATA_SIZE (2) +#define BMI160_MAG_XYZ_DATA_SIZE (6) +#define BMI160_MAG_XYZR_DATA_SIZE (8) +#define BMI160_MAG_TRIM_DATA_SIZE (16) + + +#define BMI160_TEMP_DATA_SIZE (2) +#define BMI160_FIFO_DATA_SIZE (2) +#define BMI160_STEP_COUNT_DATA_SIZE (2) + +#define BMI160_SENSOR_TIME_DATA_SIZE (3) +#define BMI160_AKM_SENSITIVITY_DATA_SIZE (3) +#define BMI160_HARD_OFFSET_DATA_SIZE (3) +#define BMI160_YAS_XY1Y2_DATA_SIZE (3) +#define BMI160_YAS_FLAG_DATA_SIZE (3) +#define BMI160_YAS_TEMP_DATA_SIZE (3) +#define BMI160_YAS_H_DATA_SIZE (3) +#define BMI160_YAS_S_DATA_SIZE (3) +#define BMI160_YAS_CORRECT_DATA_SIZE (5) +#define BMI160_YAS_XY1Y2T_DATA_SIZE (8) +#define BMI160_YAS537_CALIB_DATA_SIZE (17) +#define BMI160_YAS532_CALIB_DATA_SIZE (14) +/****************************************************/ +/**\name ARRAY PARAMETER DEFINITIONS */ +/***************************************************/ +#define BMI160_SENSOR_TIME_MSB_BYTE (2) +#define BMI160_SENSOR_TIME_XLSB_BYTE (1) +#define BMI160_SENSOR_TIME_LSB_BYTE (0) + +#define BMI160_MAG_X_LSB_BYTE (0) +#define BMI160_MAG_X_MSB_BYTE (1) +#define BMI160_MAG_Y_LSB_BYTE (0) +#define BMI160_MAG_Y_MSB_BYTE (1) +#define BMI160_MAG_Z_LSB_BYTE (0) +#define BMI160_MAG_Z_MSB_BYTE (1) +#define BMI160_MAG_R_LSB_BYTE (0) +#define BMI160_MAG_R_MSB_BYTE (1) +#define BMI160_DATA_FRAME_MAG_X_LSB_BYTE (0) +#define BMI160_DATA_FRAME_MAG_X_MSB_BYTE (1) +#define BMI160_DATA_FRAME_MAG_Y_LSB_BYTE (2) +#define BMI160_DATA_FRAME_MAG_Y_MSB_BYTE (3) +#define BMI160_DATA_FRAME_MAG_Z_LSB_BYTE (4) +#define BMI160_DATA_FRAME_MAG_Z_MSB_BYTE (5) +#define BMI160_DATA_FRAME_MAG_R_LSB_BYTE (6) +#define BMI160_DATA_FRAME_MAG_R_MSB_BYTE (7) + +#define BMI160_GYRO_X_LSB_BYTE (0) +#define BMI160_GYRO_X_MSB_BYTE (1) +#define BMI160_GYRO_Y_LSB_BYTE (0) +#define BMI160_GYRO_Y_MSB_BYTE (1) +#define BMI160_GYRO_Z_LSB_BYTE (0) +#define BMI160_GYRO_Z_MSB_BYTE (1) +#define BMI160_DATA_FRAME_GYRO_X_LSB_BYTE (0) +#define BMI160_DATA_FRAME_GYRO_X_MSB_BYTE (1) +#define BMI160_DATA_FRAME_GYRO_Y_LSB_BYTE (2) +#define BMI160_DATA_FRAME_GYRO_Y_MSB_BYTE (3) +#define BMI160_DATA_FRAME_GYRO_Z_LSB_BYTE (4) +#define BMI160_DATA_FRAME_GYRO_Z_MSB_BYTE (5) + +#define BMI160_ACCEL_X_LSB_BYTE (0) +#define BMI160_ACCEL_X_MSB_BYTE (1) +#define BMI160_ACCEL_Y_LSB_BYTE (0) +#define BMI160_ACCEL_Y_MSB_BYTE (1) +#define BMI160_ACCEL_Z_LSB_BYTE (0) +#define BMI160_ACCEL_Z_MSB_BYTE (1) +#define BMI160_DATA_FRAME_ACCEL_X_LSB_BYTE (0) +#define BMI160_DATA_FRAME_ACCEL_X_MSB_BYTE (1) +#define BMI160_DATA_FRAME_ACCEL_Y_LSB_BYTE (2) +#define BMI160_DATA_FRAME_ACCEL_Y_MSB_BYTE (3) +#define BMI160_DATA_FRAME_ACCEL_Z_LSB_BYTE (4) +#define BMI160_DATA_FRAME_ACCEL_Z_MSB_BYTE (5) + +#define BMI160_TEMP_LSB_BYTE (0) +#define BMI160_TEMP_MSB_BYTE (1) + +#define BMI160_FIFO_LENGTH_LSB_BYTE (0) +#define BMI160_FIFO_LENGTH_MSB_BYTE (1) + +#define BMI160_STEP_COUNT_LSB_BYTE (0) +#define BMI160_STEP_COUNT_MSB_BYTE (1) +/****************************************************/ +/**\name ERROR CODES */ +/***************************************************/ + +#define E_BMI160_NULL_PTR ((s8)-127) +#define E_BMI160_COMM_RES ((s8)-1) +#define E_BMI160_OUT_OF_RANGE ((s8)-2) +#define E_BMI160_BUSY ((s8)-3) +#define SUCCESS ((u8)0) +#define ERROR ((s8)-1) + +/* Constants */ +#define BMI160_NULL (0) +#define BMI160_DELAY_SETTLING_TIME (5) +/*This refers BMI160 return type as s8 */ +#define BMI160_RETURN_FUNCTION_TYPE s8 +/****************************************************/ +/**\name REGISTER DEFINITIONS */ +/***************************************************/ +/*******************/ +/**\name CHIP ID */ +/*******************/ +#define BMI160_USER_CHIP_ID_ADDR (0x00) +/*******************/ +/**\name ERROR STATUS */ +/*******************/ +#define BMI160_USER_ERROR_ADDR (0X02) +/*******************/ +/**\name POWER MODE STATUS */ +/*******************/ +#define BMI160_USER_PMU_STAT_ADDR (0X03) +/*******************/ +/**\name MAG DATA REGISTERS */ +/*******************/ +#define BMI160_USER_DATA_0_ADDR (0X04) +#define BMI160_USER_DATA_1_ADDR (0X05) +#define BMI160_USER_DATA_2_ADDR (0X06) +#define BMI160_USER_DATA_3_ADDR (0X07) +#define BMI160_USER_DATA_4_ADDR (0X08) +#define BMI160_USER_DATA_5_ADDR (0X09) +#define BMI160_USER_DATA_6_ADDR (0X0A) +#define BMI160_USER_DATA_7_ADDR (0X0B) +/*******************/ +/**\name GYRO DATA REGISTERS */ +/*******************/ +#define BMI160_USER_DATA_8_ADDR (0X0C) +#define BMI160_USER_DATA_9_ADDR (0X0D) +#define BMI160_USER_DATA_10_ADDR (0X0E) +#define BMI160_USER_DATA_11_ADDR (0X0F) +#define BMI160_USER_DATA_12_ADDR (0X10) +#define BMI160_USER_DATA_13_ADDR (0X11) +#define BMI160_USER_DATA_14_ADDR (0X12) +#define BMI160_USER_DATA_15_ADDR (0X13) +/*******************/ +/**\name ACCEL DATA REGISTERS */ +/*******************/ +#define BMI160_USER_DATA_16_ADDR (0X14) +#define BMI160_USER_DATA_17_ADDR (0X15) +#define BMI160_USER_DATA_18_ADDR (0X16) +#define BMI160_USER_DATA_19_ADDR (0X17) +/*******************/ +/**\name SENSOR TIME REGISTERS */ +/*******************/ +#define BMI160_USER_SENSORTIME_0_ADDR (0X18) +#define BMI160_USER_SENSORTIME_1_ADDR (0X19) +#define BMI160_USER_SENSORTIME_2_ADDR (0X1A) +/*******************/ +/**\name STATUS REGISTER FOR SENSOR STATUS FLAG */ +/*******************/ +#define BMI160_USER_STAT_ADDR (0X1B) +/*******************/ +/**\name INTERRUPY STATUS REGISTERS */ +/*******************/ +#define BMI160_USER_INTR_STAT_0_ADDR (0X1C) +#define BMI160_USER_INTR_STAT_1_ADDR (0X1D) +#define BMI160_USER_INTR_STAT_2_ADDR (0X1E) +#define BMI160_USER_INTR_STAT_3_ADDR (0X1F) +/*******************/ +/**\name TEMPERATURE REGISTERS */ +/*******************/ +#define BMI160_USER_TEMPERATURE_0_ADDR (0X20) +#define BMI160_USER_TEMPERATURE_1_ADDR (0X21) +/*******************/ +/**\name FIFO REGISTERS */ +/*******************/ +#define BMI160_USER_FIFO_LENGTH_0_ADDR (0X22) +#define BMI160_USER_FIFO_LENGTH_1_ADDR (0X23) +#define BMI160_USER_FIFO_DATA_ADDR (0X24) +/***************************************************/ +/**\name ACCEL CONFIG REGISTERS FOR ODR, BANDWIDTH AND UNDERSAMPLING*/ +/******************************************************/ +#define BMI160_USER_ACCEL_CONFIG_ADDR (0X40) +/*******************/ +/**\name ACCEL RANGE */ +/*******************/ +#define BMI160_USER_ACCEL_RANGE_ADDR (0X41) +/***************************************************/ +/**\name GYRO CONFIG REGISTERS FOR ODR AND BANDWIDTH */ +/******************************************************/ +#define BMI160_USER_GYRO_CONFIG_ADDR (0X42) +/*******************/ +/**\name GYRO RANGE */ +/*******************/ +#define BMI160_USER_GYRO_RANGE_ADDR (0X43) +/***************************************************/ +/**\name MAG CONFIG REGISTERS FOR ODR*/ +/******************************************************/ +#define BMI160_USER_MAG_CONFIG_ADDR (0X44) +/***************************************************/ +/**\name REGISTER FOR GYRO AND ACCEL DOWNSAMPLING RATES FOR FIFO*/ +/******************************************************/ +#define BMI160_USER_FIFO_DOWN_ADDR (0X45) +/***************************************************/ +/**\name FIFO CONFIG REGISTERS*/ +/******************************************************/ +#define BMI160_USER_FIFO_CONFIG_0_ADDR (0X46) +#define BMI160_USER_FIFO_CONFIG_1_ADDR (0X47) +/***************************************************/ +/**\name MAG INTERFACE REGISTERS*/ +/******************************************************/ +#define BMI160_USER_MAG_IF_0_ADDR (0X4B) +#define BMI160_USER_MAG_IF_1_ADDR (0X4C) +#define BMI160_USER_MAG_IF_2_ADDR (0X4D) +#define BMI160_USER_MAG_IF_3_ADDR (0X4E) +#define BMI160_USER_MAG_IF_4_ADDR (0X4F) +/***************************************************/ +/**\name INTERRUPT ENABLE REGISTERS*/ +/******************************************************/ +#define BMI160_USER_INTR_ENABLE_0_ADDR (0X50) +#define BMI160_USER_INTR_ENABLE_1_ADDR (0X51) +#define BMI160_USER_INTR_ENABLE_2_ADDR (0X52) +#define BMI160_USER_INTR_OUT_CTRL_ADDR (0X53) +/***************************************************/ +/**\name LATCH DURATION REGISTERS*/ +/******************************************************/ +#define BMI160_USER_INTR_LATCH_ADDR (0X54) +/***************************************************/ +/**\name MAP INTERRUPT 1 and 2 REGISTERS*/ +/******************************************************/ +#define BMI160_USER_INTR_MAP_0_ADDR (0X55) +#define BMI160_USER_INTR_MAP_1_ADDR (0X56) +#define BMI160_USER_INTR_MAP_2_ADDR (0X57) +/***************************************************/ +/**\name DATA SOURCE REGISTERS*/ +/******************************************************/ +#define BMI160_USER_INTR_DATA_0_ADDR (0X58) +#define BMI160_USER_INTR_DATA_1_ADDR (0X59) +/***************************************************/ +/**\name +INTERRUPT THRESHOLD, HYSTERESIS, DURATION, MODE CONFIGURATION REGISTERS*/ +/******************************************************/ +#define BMI160_USER_INTR_LOWHIGH_0_ADDR (0X5A) +#define BMI160_USER_INTR_LOWHIGH_1_ADDR (0X5B) +#define BMI160_USER_INTR_LOWHIGH_2_ADDR (0X5C) +#define BMI160_USER_INTR_LOWHIGH_3_ADDR (0X5D) +#define BMI160_USER_INTR_LOWHIGH_4_ADDR (0X5E) +#define BMI160_USER_INTR_MOTION_0_ADDR (0X5F) +#define BMI160_USER_INTR_MOTION_1_ADDR (0X60) +#define BMI160_USER_INTR_MOTION_2_ADDR (0X61) +#define BMI160_USER_INTR_MOTION_3_ADDR (0X62) +#define BMI160_USER_INTR_TAP_0_ADDR (0X63) +#define BMI160_USER_INTR_TAP_1_ADDR (0X64) +#define BMI160_USER_INTR_ORIENT_0_ADDR (0X65) +#define BMI160_USER_INTR_ORIENT_1_ADDR (0X66) +#define BMI160_USER_INTR_FLAT_0_ADDR (0X67) +#define BMI160_USER_INTR_FLAT_1_ADDR (0X68) +/***************************************************/ +/**\name FAST OFFSET CONFIGURATION REGISTER*/ +/******************************************************/ +#define BMI160_USER_FOC_CONFIG_ADDR (0X69) +/***************************************************/ +/**\name MISCELLANEOUS CONFIGURATION REGISTER*/ +/******************************************************/ +#define BMI160_USER_CONFIG_ADDR (0X6A) +/***************************************************/ +/**\name SERIAL INTERFACE SETTINGS REGISTER*/ +/******************************************************/ +#define BMI160_USER_IF_CONFIG_ADDR (0X6B) +/***************************************************/ +/**\name GYRO POWER MODE TRIGGER REGISTER */ +/******************************************************/ +#define BMI160_USER_PMU_TRIGGER_ADDR (0X6C) +/***************************************************/ +/**\name SELF_TEST REGISTER*/ +/******************************************************/ +#define BMI160_USER_SELF_TEST_ADDR (0X6D) +/***************************************************/ +/**\name SPI,I2C SELECTION REGISTER*/ +/******************************************************/ +#define BMI160_USER_NV_CONFIG_ADDR (0x70) +/***************************************************/ +/**\name ACCEL AND GYRO OFFSET REGISTERS*/ +/******************************************************/ +#define BMI160_USER_OFFSET_0_ADDR (0X71) +#define BMI160_USER_OFFSET_1_ADDR (0X72) +#define BMI160_USER_OFFSET_2_ADDR (0X73) +#define BMI160_USER_OFFSET_3_ADDR (0X74) +#define BMI160_USER_OFFSET_4_ADDR (0X75) +#define BMI160_USER_OFFSET_5_ADDR (0X76) +#define BMI160_USER_OFFSET_6_ADDR (0X77) +/***************************************************/ +/**\name STEP COUNTER INTERRUPT REGISTERS*/ +/******************************************************/ +#define BMI160_USER_STEP_COUNT_0_ADDR (0X78) +#define BMI160_USER_STEP_COUNT_1_ADDR (0X79) +/***************************************************/ +/**\name STEP COUNTER CONFIGURATION REGISTERS*/ +/******************************************************/ +#define BMI160_USER_STEP_CONFIG_0_ADDR (0X7A) +#define BMI160_USER_STEP_CONFIG_1_ADDR (0X7B) +/***************************************************/ +/**\name COMMAND REGISTER*/ +/******************************************************/ +#define BMI160_CMD_COMMANDS_ADDR (0X7E) +/***************************************************/ +/**\name PAGE REGISTERS*/ +/******************************************************/ +#define BMI160_CMD_EXT_MODE_ADDR (0X7F) +#define BMI160_COM_C_TRIM_FIVE_ADDR (0X05) + +/****************************************************/ +/**\name SHIFT VALUE DEFINITION */ +/***************************************************/ +#define BMI160_SHIFT_BIT_POSITION_BY_01_BIT (1) +#define BMI160_SHIFT_BIT_POSITION_BY_02_BITS (2) +#define BMI160_SHIFT_BIT_POSITION_BY_03_BITS (3) +#define BMI160_SHIFT_BIT_POSITION_BY_04_BITS (4) +#define BMI160_SHIFT_BIT_POSITION_BY_05_BITS (5) +#define BMI160_SHIFT_BIT_POSITION_BY_06_BITS (6) +#define BMI160_SHIFT_BIT_POSITION_BY_07_BITS (7) +#define BMI160_SHIFT_BIT_POSITION_BY_08_BITS (8) +#define BMI160_SHIFT_BIT_POSITION_BY_09_BITS (9) +#define BMI160_SHIFT_BIT_POSITION_BY_12_BITS (12) +#define BMI160_SHIFT_BIT_POSITION_BY_13_BITS (13) +#define BMI160_SHIFT_BIT_POSITION_BY_14_BITS (14) +#define BMI160_SHIFT_BIT_POSITION_BY_15_BITS (15) +#define BMI160_SHIFT_BIT_POSITION_BY_16_BITS (16) + +/****************************************************/ +/**\name DEFINITIONS USED FOR YAMAHA-YAS532 */ +/***************************************************/ +#define YAS532_MAG_STATE_NORMAL (0) +#define YAS532_MAG_STATE_INIT_COIL (1) +#define YAS532_MAG_STATE_MEASURE_OFFSET (2) +#define YAS532_MAG_INITCOIL_TIMEOUT (1000) +#define YAS532_MAG_NOTRANS_POSITION (3) +#define YAS532_DEFAULT_SENSOR_DELAY (50) +#define YAS532_DATA_OVERFLOW (8190) +#define YAS532_DATA_UNDERFLOW (0) +#define YAS532_MAG_LOG (20) +#define YAS532_MAG_TEMPERATURE_LOG (10) +#define YAS532_TEMP20DEGREE_TYPICAL (390) +#define YAS532_VERSION_AC_COEF_X (850) +#define YAS532_VERSION_AC_COEF_Y1 (750) +#define YAS532_VERSION_AC_COEF_Y2 (750) +#define YAS532_DATA_CENTER (4096) +/****************************************************/ +/**\name YAMAHA-YAS532 OFFSET DEFINITION */ +/***************************************************/ +static const s8 INVALID_OFFSET[] = {0x7f, 0x7f, 0x7f}; +#define set_vector(to, from) \ + {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } +#define is_valid_offset(a) \ + (((a)[0] <= 31) && ((a)[1] <= 31) && ((a)[2] <= 31) \ + && (-31 <= (a)[0]) && (-31 <= (a)[1]) && (-31 <= (a)[2])) + +/**************************************************/ +/**\name YAS532 CALIB DATA DEFINITIONS */ +/*************************************************/ + + +/* register address of YAS532*/ +#define BMI160_YAS532_TESTR1 (0x88) +#define BMI160_YAS532_TESTR2 (0x89) +#define BMI160_YAS532_RCOIL (0x81) +#define BMI160_YAS532_COMMAND_REGISTER (0x82) +#define BMI160_YAS532_DATA_REGISTER (0xB0) +/* calib data register definition*/ +#define BMI160_YAS532_CALIB_CX (0x90) +#define BMI160_YAS532_CALIB_CY1 (0x91) +#define BMI160_YAS532_CALIB_CY2 (0x92) +#define BMI160_YAS532_CALIB1 (0x93) +#define BMI160_YAS532_CALIB2 (0x94) +#define BMI160_YAS532_CALIB3 (0x95) +#define BMI160_YAS532_CALIB4 (0x96) +#define BMI160_YAS532_CALIB5 (0x97) +#define BMI160_YAS532_CLAIB6 (0x98) +#define BMI160_YAS532_CALIB7 (0x99) +#define BMI160_YAS532_CALIB8 (0x9A) +#define BMI160_YAS532_CALIIB9 (0x9B) +#define BMI160_YAS532_CALIB10 (0x9C) +#define BMI160_YAS532_CALIB11 (0x9D) +/* offset definition */ +#define BMI160_YAS532_OFFSET_X (0x85) +#define BMI160_YAS532_OFFSET_Y (0x86) +#define BMI160_YAS532_OFFSET_Z (0x87) +/* data to write register for yas532*/ +#define BMI160_YAS532_WRITE_TESTR1 (0x00) +#define BMI160_YAS532_WRITE_TESTR2 (0x00) +#define BMI160_YAS532_WRITE_RCOIL (0x00) +/**************************************************/ +/**\name YAS537 DEFINITION */ +/*************************************************/ + +#define YAS537_SRSTR_DATA (0x02) +#define YAS537_WRITE_A_D_CONVERTER (0x03) +#define YAS537_WRITE_A_D_CONVERTER2 (0xF8) +#define YAS537_WRITE_FILTER (0x08) +#define YAS537_WRITE_CONFR (0x08) +#define YAS537_WRITE_TEMP_CALIB (0xFF) +#define YAS537_SET_COMMAND_REGISTER (0x01) + +/**************************************************/ +/**\name YAS537 REGISTER DEFINITION */ +/*************************************************/ +#define YAS537_REG_SRSTR (0x90) +#define YAS537_REG_CALR_C0 (0xC0) +#define YAS537_REG_CALR_C1 (0xC1) +#define YAS537_REG_CALR_C2 (0xC2) +#define YAS537_REG_CALR_C3 (0xC3) +#define YAS537_REG_CALR_C4 (0xC4) +#define YAS537_REG_CALR_C5 (0xC5) +#define YAS537_REG_CALR_C6 (0xC6) +#define YAS537_REG_CALR_C7 (0xC7) +#define YAS537_REG_CALR_C8 (0xC8) +#define YAS537_REG_CALR_C9 (0xC9) +#define YAS537_REG_CALR_CA (0xCA) +#define YAS537_REG_CALR_CB (0xCB) +#define YAS537_REG_CALR_CC (0xCC) +#define YAS537_REG_CALR_CD (0xCD) +#define YAS537_REG_CALR_CE (0xCE) +#define YAS537_REG_CALR_CF (0xCF) +#define YAS537_REG_CALR_DO (0xD0) +#define YAS537_REG_MTCR (0x93) +#define YAS537_REG_CONFR (0x82) +#define BMI160_REG_YAS537_CMDR (0x81) +#define YAS537_REG_OXR (0x84) +#define YAS537_REG_AVRR (0x87) +#define YAS537_REG_HCKR (0x88) +#define YAS537_REG_LCKR (0x89) +#define YAS537_REG_ADCCALR (0x91) +#define YAS537_REG_ADCCALR_ONE (0x92) +#define YAS537_REG_OCR (0x9E) +#define YAS537_REG_TRMR (0x9F) +#define YAS537_REG_TEMPERATURE_0 (0xB0) +#define YAS537_REG_TEMPERATURE_1 (0xB1) +#define YAS537_REG_DATA_X_0 (0xB2) +#define YAS537_REG_DATA_X_1 (0xB3) +#define YAS537_REG_DATA_Y1_0 (0xB4) +#define YAS537_REG_DATA_Y1_1 (0xB5) +#define YAS537_REG_DATA_Y2_0 (0xB6) +#define YAS537_REG_DATA_Y2_1 (0xB7) +#define YAS537_MAG_STATE_NORMAL (0) +#define YAS537_MAG_STATE_INIT_COIL (1) +#define YAS537_MAG_STATE_RECORD_DATA (2) +#define YAS537_DATA_UNDERFLOW (0) +#define YAS537_DATA_OVERFLOW (16383) +/****************************************************/ +/**\name YAS537_set vector */ +/***************************************************/ +#define yas537_set_vector(to, from) \ + {int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; } + +#ifndef ABS +#define ABS(a) ((a) > 0 ? (a) : -(a)) /*!< Absolute value */ +#endif +/****************************************************/ +/**\name AKM09911 AND AKM09912 DEFINITION */ +/***************************************************/ +#define AKM09912_SENSITIVITY_DIV (256) +#define AKM09912_SENSITIVITY (128) +#define AKM09911_SENSITIVITY_DIV (128) +#define AKM_ASAX (0) +#define AKM_ASAY (1) +#define AKM_ASAZ (2) +#define AKM_POWER_DOWN_MODE_DATA (0x00) +#define AKM_FUSE_ROM_MODE (0x1F) +#define AKM_POWER_MODE_REG (0x31) +#define AKM_SINGLE_MEASUREMENT_MODE (0x01) +#define AKM_DATA_REGISTER (0x11) +/*! AKM09912 Register definition */ +#define AKM09912_CHIP_ID_REG (0x01) +/****************************************************/ +/**\name BMM150 DEFINITION */ +/***************************************************/ +#define BMI160_BMM150_SET_POWER_CONTROL (0x01) +#define BMI160_BMM150_MAX_RETRY_WAKEUP (5) +#define BMI160_BMM150_POWER_ON (0x01) +#define BMI160_BMM150_POWER_OFF (0x00) +#define BMI160_BMM150_FORCE_MODE (0x02) +#define BMI160_BMM150_POWER_ON_SUCCESS (0) +#define BMI160_BMM150_POWER_ON_FAIL ((s8)-1) + +#define BMI160_BMM150_DIG_X1 (0) +#define BMI160_BMM150_DIG_Y1 (1) +#define BMI160_BMM150_DIG_X2 (2) +#define BMI160_BMM150_DIG_Y3 (3) +#define BMI160_BMM150_DIG_XY1 (4) +#define BMI160_BMM150_DIG_XY2 (5) +#define BMI160_BMM150_DIG_Z1_LSB (6) +#define BMI160_BMM150_DIG_Z1_MSB (7) +#define BMI160_BMM150_DIG_Z2_LSB (8) +#define BMI160_BMM150_DIG_Z2_MSB (9) +#define BMI160_BMM150_DIG_DIG_Z3_LSB (10) +#define BMI160_BMM150_DIG_DIG_Z3_MSB (11) +#define BMI160_BMM150_DIG_DIG_Z4_LSB (12) +#define BMI160_BMM150_DIG_DIG_Z4_MSB (13) +#define BMI160_BMM150_DIG_DIG_XYZ1_LSB (14) +#define BMI160_BMM150_DIG_DIG_XYZ1_MSB (15) + +/**************************************************************/ +/**\name STRUCTURE DEFINITIONS */ +/**************************************************************/ +/*! +* @brief bmi160 structure +* This structure holds all relevant information about bmi160 +*/ +struct bmi160_t { +u8 chip_id;/**< chip id of BMI160 */ +u8 dev_addr;/**< device address of BMI160 */ +s8 mag_manual_enable;/**< used for check the mag manual/auto mode status */ +BMI160_WR_FUNC_PTR;/**< bus write function pointer */ +BMI160_RD_FUNC_PTR;/**< bus read function pointer */ +BMI160_BRD_FUNC_PTR;/**< burst write function pointer */ +void (*delay_msec)(BMI160_MDELAY_DATA_TYPE);/**< delay function pointer */ +}; +/*! + * @brief Structure containing bmm150 and akm09911 + * magnetometer values for x,y and + * z-axis in s16 + */ +struct bmi160_mag_t { +s16 x;/**< BMM150 and AKM09911 and AKM09912 X raw data*/ +s16 y;/**< BMM150 and AKM09911 and AKM09912 Y raw data*/ +s16 z;/**< BMM150 and AKM09911 and AKM09912 Z raw data*/ +}; +/*! + * @brief Structure containing bmm150 xyz data and temperature + */ +struct bmi160_mag_xyzr_t { +s16 x;/**< BMM150 X raw data*/ +s16 y;/**< BMM150 Y raw data*/ +s16 z;/** (0x00), Bit --> 0...7 */ +#define BMI160_USER_CHIP_ID__POS (0) +#define BMI160_USER_CHIP_ID__MSK (0xFF) +#define BMI160_USER_CHIP_ID__LEN (8) +#define BMI160_USER_CHIP_ID__REG (BMI160_USER_CHIP_ID_ADDR) +/**************************************************************/ +/**\name ERROR STATUS LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Error Description - Reg Addr --> (0x02), Bit --> 0 */ +#define BMI160_USER_ERR_STAT__POS (0) +#define BMI160_USER_ERR_STAT__LEN (8) +#define BMI160_USER_ERR_STAT__MSK (0xFF) +#define BMI160_USER_ERR_STAT__REG (BMI160_USER_ERROR_ADDR) + +#define BMI160_USER_FATAL_ERR__POS (0) +#define BMI160_USER_FATAL_ERR__LEN (1) +#define BMI160_USER_FATAL_ERR__MSK (0x01) +#define BMI160_USER_FATAL_ERR__REG (BMI160_USER_ERROR_ADDR) + +/* Error Description - Reg Addr --> (0x02), Bit --> 1...4 */ +#define BMI160_USER_ERR_CODE__POS (1) +#define BMI160_USER_ERR_CODE__LEN (4) +#define BMI160_USER_ERR_CODE__MSK (0x1E) +#define BMI160_USER_ERR_CODE__REG (BMI160_USER_ERROR_ADDR) + +/* Error Description - Reg Addr --> (0x02), Bit --> 5 */ +#define BMI160_USER_I2C_FAIL_ERR__POS (5) +#define BMI160_USER_I2C_FAIL_ERR__LEN (1) +#define BMI160_USER_I2C_FAIL_ERR__MSK (0x20) +#define BMI160_USER_I2C_FAIL_ERR__REG (BMI160_USER_ERROR_ADDR) + +/* Error Description - Reg Addr --> (0x02), Bit --> 6 */ +#define BMI160_USER_DROP_CMD_ERR__POS (6) +#define BMI160_USER_DROP_CMD_ERR__LEN (1) +#define BMI160_USER_DROP_CMD_ERR__MSK (0x40) +#define BMI160_USER_DROP_CMD_ERR__REG (BMI160_USER_ERROR_ADDR) +/**************************************************************/ +/**\name MAG DATA READY LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Error Description - Reg Addr --> (0x02), Bit --> 7 */ +#define BMI160_USER_MAG_DADA_RDY_ERR__POS (7) +#define BMI160_USER_MAG_DADA_RDY_ERR__LEN (1) +#define BMI160_USER_MAG_DADA_RDY_ERR__MSK (0x80) +#define BMI160_USER_MAG_DADA_RDY_ERR__REG (BMI160_USER_ERROR_ADDR) +/**************************************************************/ +/**\name MAG POWER MODE LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* PMU_Status Description of MAG - Reg Addr --> (0x03), Bit --> 1..0 */ +#define BMI160_USER_MAG_POWER_MODE_STAT__POS (0) +#define BMI160_USER_MAG_POWER_MODE_STAT__LEN (2) +#define BMI160_USER_MAG_POWER_MODE_STAT__MSK (0x03) +#define BMI160_USER_MAG_POWER_MODE_STAT__REG \ +(BMI160_USER_PMU_STAT_ADDR) +/**************************************************************/ +/**\name GYRO POWER MODE LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* PMU_Status Description of GYRO - Reg Addr --> (0x03), Bit --> 3...2 */ +#define BMI160_USER_GYRO_POWER_MODE_STAT__POS (2) +#define BMI160_USER_GYRO_POWER_MODE_STAT__LEN (2) +#define BMI160_USER_GYRO_POWER_MODE_STAT__MSK (0x0C) +#define BMI160_USER_GYRO_POWER_MODE_STAT__REG \ +(BMI160_USER_PMU_STAT_ADDR) +/**************************************************************/ +/**\name ACCEL POWER MODE LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* PMU_Status Description of ACCEL - Reg Addr --> (0x03), Bit --> 5...4 */ +#define BMI160_USER_ACCEL_POWER_MODE_STAT__POS (4) +#define BMI160_USER_ACCEL_POWER_MODE_STAT__LEN (2) +#define BMI160_USER_ACCEL_POWER_MODE_STAT__MSK (0x30) +#define BMI160_USER_ACCEL_POWER_MODE_STAT__REG \ +(BMI160_USER_PMU_STAT_ADDR) +/**************************************************************/ +/**\name MAG DATA XYZ LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Mag_X(LSB) Description - Reg Addr --> (0x04), Bit --> 0...7 */ +#define BMI160_USER_DATA_0_MAG_X_LSB__POS (0) +#define BMI160_USER_DATA_0_MAG_X_LSB__LEN (8) +#define BMI160_USER_DATA_0_MAG_X_LSB__MSK (0xFF) +#define BMI160_USER_DATA_0_MAG_X_LSB__REG (BMI160_USER_DATA_0_ADDR) + +/* Mag_X(LSB) Description - Reg Addr --> (0x04), Bit --> 3...7 */ +#define BMI160_USER_DATA_MAG_X_LSB__POS (3) +#define BMI160_USER_DATA_MAG_X_LSB__LEN (5) +#define BMI160_USER_DATA_MAG_X_LSB__MSK (0xF8) +#define BMI160_USER_DATA_MAG_X_LSB__REG (BMI160_USER_DATA_0_ADDR) + +/* Mag_X(MSB) Description - Reg Addr --> (0x05), Bit --> 0...7 */ +#define BMI160_USER_DATA_1_MAG_X_MSB__POS (0) +#define BMI160_USER_DATA_1_MAG_X_MSB__LEN (8) +#define BMI160_USER_DATA_1_MAG_X_MSB__MSK (0xFF) +#define BMI160_USER_DATA_1_MAG_X_MSB__REG (BMI160_USER_DATA_1_ADDR) + +/* Mag_Y(LSB) Description - Reg Addr --> (0x06), Bit --> 0...7 */ +#define BMI160_USER_DATA_2_MAG_Y_LSB__POS (0) +#define BMI160_USER_DATA_2_MAG_Y_LSB__LEN (8) +#define BMI160_USER_DATA_2_MAG_Y_LSB__MSK (0xFF) +#define BMI160_USER_DATA_2_MAG_Y_LSB__REG (BMI160_USER_DATA_2_ADDR) + +/* Mag_Y(LSB) Description - Reg Addr --> (0x06), Bit --> 3...7 */ +#define BMI160_USER_DATA_MAG_Y_LSB__POS (3) +#define BMI160_USER_DATA_MAG_Y_LSB__LEN (5) +#define BMI160_USER_DATA_MAG_Y_LSB__MSK (0xF8) +#define BMI160_USER_DATA_MAG_Y_LSB__REG (BMI160_USER_DATA_2_ADDR) + +/* Mag_Y(MSB) Description - Reg Addr --> (0x07), Bit --> 0...7 */ +#define BMI160_USER_DATA_3_MAG_Y_MSB__POS (0) +#define BMI160_USER_DATA_3_MAG_Y_MSB__LEN (8) +#define BMI160_USER_DATA_3_MAG_Y_MSB__MSK (0xFF) +#define BMI160_USER_DATA_3_MAG_Y_MSB__REG (BMI160_USER_DATA_3_ADDR) + +/* Mag_Z(LSB) Description - Reg Addr --> (0x08), Bit --> 0...7 */ +#define BMI160_USER_DATA_4_MAG_Z_LSB__POS (0) +#define BMI160_USER_DATA_4_MAG_Z_LSB__LEN (8) +#define BMI160_USER_DATA_4_MAG_Z_LSB__MSK (0xFF) +#define BMI160_USER_DATA_4_MAG_Z_LSB__REG (BMI160_USER_DATA_4_ADDR) + +/* Mag_X(LSB) Description - Reg Addr --> (0x08), Bit --> 3...7 */ +#define BMI160_USER_DATA_MAG_Z_LSB__POS (1) +#define BMI160_USER_DATA_MAG_Z_LSB__LEN (7) +#define BMI160_USER_DATA_MAG_Z_LSB__MSK (0xFE) +#define BMI160_USER_DATA_MAG_Z_LSB__REG (BMI160_USER_DATA_4_ADDR) + +/* Mag_Z(MSB) Description - Reg Addr --> (0x09), Bit --> 0...7 */ +#define BMI160_USER_DATA_5_MAG_Z_MSB__POS (0) +#define BMI160_USER_DATA_5_MAG_Z_MSB__LEN (8) +#define BMI160_USER_DATA_5_MAG_Z_MSB__MSK (0xFF) +#define BMI160_USER_DATA_5_MAG_Z_MSB__REG (BMI160_USER_DATA_5_ADDR) + +/* RHALL(LSB) Description - Reg Addr --> (0x0A), Bit --> 0...7 */ +#define BMI160_USER_DATA_6_RHALL_LSB__POS (0) +#define BMI160_USER_DATA_6_RHALL_LSB__LEN (8) +#define BMI160_USER_DATA_6_RHALL_LSB__MSK (0xFF) +#define BMI160_USER_DATA_6_RHALL_LSB__REG (BMI160_USER_DATA_6_ADDR) + +/* Mag_R(LSB) Description - Reg Addr --> (0x0A), Bit --> 3...7 */ +#define BMI160_USER_DATA_MAG_R_LSB__POS (2) +#define BMI160_USER_DATA_MAG_R_LSB__LEN (6) +#define BMI160_USER_DATA_MAG_R_LSB__MSK (0xFC) +#define BMI160_USER_DATA_MAG_R_LSB__REG (BMI160_USER_DATA_6_ADDR) + +/* RHALL(MSB) Description - Reg Addr --> (0x0B), Bit --> 0...7 */ +#define BMI160_USER_DATA_7_RHALL_MSB__POS (0) +#define BMI160_USER_DATA_7_RHALL_MSB__LEN (8) +#define BMI160_USER_DATA_7_RHALL_MSB__MSK (0xFF) +#define BMI160_USER_DATA_7_RHALL_MSB__REG (BMI160_USER_DATA_7_ADDR) +/**************************************************************/ +/**\name GYRO DATA XYZ LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* GYR_X (LSB) Description - Reg Addr --> (0x0C), Bit --> 0...7 */ +#define BMI160_USER_DATA_8_GYRO_X_LSB__POS (0) +#define BMI160_USER_DATA_8_GYRO_X_LSB__LEN (8) +#define BMI160_USER_DATA_8_GYRO_X_LSB__MSK (0xFF) +#define BMI160_USER_DATA_8_GYRO_X_LSB__REG (BMI160_USER_DATA_8_ADDR) + +/* GYR_X (MSB) Description - Reg Addr --> (0x0D), Bit --> 0...7 */ +#define BMI160_USER_DATA_9_GYRO_X_MSB__POS (0) +#define BMI160_USER_DATA_9_GYRO_X_MSB__LEN (8) +#define BMI160_USER_DATA_9_GYRO_X_MSB__MSK (0xFF) +#define BMI160_USER_DATA_9_GYRO_X_MSB__REG (BMI160_USER_DATA_9_ADDR) + +/* GYR_Y (LSB) Description - Reg Addr --> 0x0E, Bit --> 0...7 */ +#define BMI160_USER_DATA_10_GYRO_Y_LSB__POS (0) +#define BMI160_USER_DATA_10_GYRO_Y_LSB__LEN (8) +#define BMI160_USER_DATA_10_GYRO_Y_LSB__MSK (0xFF) +#define BMI160_USER_DATA_10_GYRO_Y_LSB__REG (BMI160_USER_DATA_10_ADDR) + +/* GYR_Y (MSB) Description - Reg Addr --> (0x0F), Bit --> 0...7 */ +#define BMI160_USER_DATA_11_GYRO_Y_MSB__POS (0) +#define BMI160_USER_DATA_11_GYRO_Y_MSB__LEN (8) +#define BMI160_USER_DATA_11_GYRO_Y_MSB__MSK (0xFF) +#define BMI160_USER_DATA_11_GYRO_Y_MSB__REG (BMI160_USER_DATA_11_ADDR) + +/* GYR_Z (LSB) Description - Reg Addr --> (0x10), Bit --> 0...7 */ +#define BMI160_USER_DATA_12_GYRO_Z_LSB__POS (0) +#define BMI160_USER_DATA_12_GYRO_Z_LSB__LEN (8) +#define BMI160_USER_DATA_12_GYRO_Z_LSB__MSK (0xFF) +#define BMI160_USER_DATA_12_GYRO_Z_LSB__REG (BMI160_USER_DATA_12_ADDR) + +/* GYR_Z (MSB) Description - Reg Addr --> (0x11), Bit --> 0...7 */ +#define BMI160_USER_DATA_13_GYRO_Z_MSB__POS (0) +#define BMI160_USER_DATA_13_GYRO_Z_MSB__LEN (8) +#define BMI160_USER_DATA_13_GYRO_Z_MSB__MSK (0xFF) +#define BMI160_USER_DATA_13_GYRO_Z_MSB__REG (BMI160_USER_DATA_13_ADDR) +/**************************************************************/ +/**\name ACCEL DATA XYZ LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* ACC_X (LSB) Description - Reg Addr --> (0x12), Bit --> 0...7 */ +#define BMI160_USER_DATA_14_ACCEL_X_LSB__POS (0) +#define BMI160_USER_DATA_14_ACCEL_X_LSB__LEN (8) +#define BMI160_USER_DATA_14_ACCEL_X_LSB__MSK (0xFF) +#define BMI160_USER_DATA_14_ACCEL_X_LSB__REG (BMI160_USER_DATA_14_ADDR) + +/* ACC_X (MSB) Description - Reg Addr --> 0x13, Bit --> 0...7 */ +#define BMI160_USER_DATA_15_ACCEL_X_MSB__POS (0) +#define BMI160_USER_DATA_15_ACCEL_X_MSB__LEN (8) +#define BMI160_USER_DATA_15_ACCEL_X_MSB__MSK (0xFF) +#define BMI160_USER_DATA_15_ACCEL_X_MSB__REG (BMI160_USER_DATA_15_ADDR) + +/* ACC_Y (LSB) Description - Reg Addr --> (0x14), Bit --> 0...7 */ +#define BMI160_USER_DATA_16_ACCEL_Y_LSB__POS (0) +#define BMI160_USER_DATA_16_ACCEL_Y_LSB__LEN (8) +#define BMI160_USER_DATA_16_ACCEL_Y_LSB__MSK (0xFF) +#define BMI160_USER_DATA_16_ACCEL_Y_LSB__REG (BMI160_USER_DATA_16_ADDR) + +/* ACC_Y (MSB) Description - Reg Addr --> (0x15), Bit --> 0...7 */ +#define BMI160_USER_DATA_17_ACCEL_Y_MSB__POS (0) +#define BMI160_USER_DATA_17_ACCEL_Y_MSB__LEN (8) +#define BMI160_USER_DATA_17_ACCEL_Y_MSB__MSK (0xFF) +#define BMI160_USER_DATA_17_ACCEL_Y_MSB__REG (BMI160_USER_DATA_17_ADDR) + +/* ACC_Z (LSB) Description - Reg Addr --> 0x16, Bit --> 0...7 */ +#define BMI160_USER_DATA_18_ACCEL_Z_LSB__POS (0) +#define BMI160_USER_DATA_18_ACCEL_Z_LSB__LEN (8) +#define BMI160_USER_DATA_18_ACCEL_Z_LSB__MSK (0xFF) +#define BMI160_USER_DATA_18_ACCEL_Z_LSB__REG (BMI160_USER_DATA_18_ADDR) + +/* ACC_Z (MSB) Description - Reg Addr --> (0x17), Bit --> 0...7 */ +#define BMI160_USER_DATA_19_ACCEL_Z_MSB__POS (0) +#define BMI160_USER_DATA_19_ACCEL_Z_MSB__LEN (8) +#define BMI160_USER_DATA_19_ACCEL_Z_MSB__MSK (0xFF) +#define BMI160_USER_DATA_19_ACCEL_Z_MSB__REG (BMI160_USER_DATA_19_ADDR) +/**************************************************************/ +/**\name SENSOR TIME LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* SENSORTIME_0 (LSB) Description - Reg Addr --> (0x18), Bit --> 0...7 */ +#define BMI160_USER_SENSORTIME_0_SENSOR_TIME_LSB__POS (0) +#define BMI160_USER_SENSORTIME_0_SENSOR_TIME_LSB__LEN (8) +#define BMI160_USER_SENSORTIME_0_SENSOR_TIME_LSB__MSK (0xFF) +#define BMI160_USER_SENSORTIME_0_SENSOR_TIME_LSB__REG \ + (BMI160_USER_SENSORTIME_0_ADDR) + +/* SENSORTIME_1 (MSB) Description - Reg Addr --> (0x19), Bit --> 0...7 */ +#define BMI160_USER_SENSORTIME_1_SENSOR_TIME_MSB__POS (0) +#define BMI160_USER_SENSORTIME_1_SENSOR_TIME_MSB__LEN (8) +#define BMI160_USER_SENSORTIME_1_SENSOR_TIME_MSB__MSK (0xFF) +#define BMI160_USER_SENSORTIME_1_SENSOR_TIME_MSB__REG \ + (BMI160_USER_SENSORTIME_1_ADDR) + +/* SENSORTIME_2 (MSB) Description - Reg Addr --> (0x1A), Bit --> 0...7 */ +#define BMI160_USER_SENSORTIME_2_SENSOR_TIME_MSB__POS (0) +#define BMI160_USER_SENSORTIME_2_SENSOR_TIME_MSB__LEN (8) +#define BMI160_USER_SENSORTIME_2_SENSOR_TIME_MSB__MSK (0xFF) +#define BMI160_USER_SENSORTIME_2_SENSOR_TIME_MSB__REG \ + (BMI160_USER_SENSORTIME_2_ADDR) +/**************************************************************/ +/**\name GYRO SELF TEST LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 1 */ +#define BMI160_USER_STAT_GYRO_SELFTEST_OK__POS (1) +#define BMI160_USER_STAT_GYRO_SELFTEST_OK__LEN (1) +#define BMI160_USER_STAT_GYRO_SELFTEST_OK__MSK (0x02) +#define BMI160_USER_STAT_GYRO_SELFTEST_OK__REG \ + (BMI160_USER_STAT_ADDR) +/**************************************************************/ +/**\name MAG MANUAL OPERATION LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 2 */ +#define BMI160_USER_STAT_MAG_MANUAL_OPERATION__POS (2) +#define BMI160_USER_STAT_MAG_MANUAL_OPERATION__LEN (1) +#define BMI160_USER_STAT_MAG_MANUAL_OPERATION__MSK (0x04) +#define BMI160_USER_STAT_MAG_MANUAL_OPERATION__REG \ + (BMI160_USER_STAT_ADDR) +/**************************************************************/ +/**\name FOC STATUS LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 3 */ +#define BMI160_USER_STAT_FOC_RDY__POS (3) +#define BMI160_USER_STAT_FOC_RDY__LEN (1) +#define BMI160_USER_STAT_FOC_RDY__MSK (0x08) +#define BMI160_USER_STAT_FOC_RDY__REG (BMI160_USER_STAT_ADDR) +/**************************************************************/ +/**\name NVM READY LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 4 */ +#define BMI160_USER_STAT_NVM_RDY__POS (4) +#define BMI160_USER_STAT_NVM_RDY__LEN (1) +#define BMI160_USER_STAT_NVM_RDY__MSK (0x10) +#define BMI160_USER_STAT_NVM_RDY__REG (BMI160_USER_STAT_ADDR) +/**************************************************************/ +/**\name DATA READY LENGTH, POSITION AND MASK FOR ACCEL, MAG AND GYRO*/ +/**************************************************************/ +/* Status Description - Reg Addr --> 0x1B, Bit --> 5 */ +#define BMI160_USER_STAT_DATA_RDY_MAG__POS (5) +#define BMI160_USER_STAT_DATA_RDY_MAG__LEN (1) +#define BMI160_USER_STAT_DATA_RDY_MAG__MSK (0x20) +#define BMI160_USER_STAT_DATA_RDY_MAG__REG (BMI160_USER_STAT_ADDR) + +/* Status Description - Reg Addr --> 0x1B, Bit --> 6 */ +#define BMI160_USER_STAT_DATA_RDY_GYRO__POS (6) +#define BMI160_USER_STAT_DATA_RDY_GYRO__LEN (1) +#define BMI160_USER_STAT_DATA_RDY_GYRO__MSK (0x40) +#define BMI160_USER_STAT_DATA_RDY_GYRO__REG (BMI160_USER_STAT_ADDR) + +/* Status Description - Reg Addr --> 0x1B, Bit --> 7 */ +#define BMI160_USER_STAT_DATA_RDY_ACCEL__POS (7) +#define BMI160_USER_STAT_DATA_RDY_ACCEL__LEN (1) +#define BMI160_USER_STAT_DATA_RDY_ACCEL__MSK (0x80) +#define BMI160_USER_STAT_DATA_RDY_ACCEL__REG (BMI160_USER_STAT_ADDR) +/**************************************************************/ +/**\name INTERRUPT STATUS LENGTH, POSITION AND MASK */ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 0 */ +#define BMI160_USER_INTR_STAT_0_STEP_INTR__POS (0) +#define BMI160_USER_INTR_STAT_0_STEP_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_0_STEP_INTR__MSK (0x01) +#define BMI160_USER_INTR_STAT_0_STEP_INTR__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name SIGNIFICANT INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 1 */ +#define BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR__POS (1) +#define BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR__MSK (0x02) +#define BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name ANY_MOTION INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 2 */ +#define BMI160_USER_INTR_STAT_0_ANY_MOTION__POS (2) +#define BMI160_USER_INTR_STAT_0_ANY_MOTION__LEN (1) +#define BMI160_USER_INTR_STAT_0_ANY_MOTION__MSK (0x04) +#define BMI160_USER_INTR_STAT_0_ANY_MOTION__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name PMU TRIGGER INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 3 */ +#define BMI160_USER_INTR_STAT_0_PMU_TRIGGER__POS 3 +#define BMI160_USER_INTR_STAT_0_PMU_TRIGGER__LEN (1) +#define BMI160_USER_INTR_STAT_0_PMU_TRIGGER__MSK (0x08) +#define BMI160_USER_INTR_STAT_0_PMU_TRIGGER__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name DOUBLE TAP INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 4 */ +#define BMI160_USER_INTR_STAT_0_DOUBLE_TAP_INTR__POS 4 +#define BMI160_USER_INTR_STAT_0_DOUBLE_TAP_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_0_DOUBLE_TAP_INTR__MSK (0x10) +#define BMI160_USER_INTR_STAT_0_DOUBLE_TAP_INTR__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name SINGLE TAP INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 5 */ +#define BMI160_USER_INTR_STAT_0_SINGLE_TAP_INTR__POS 5 +#define BMI160_USER_INTR_STAT_0_SINGLE_TAP_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_0_SINGLE_TAP_INTR__MSK (0x20) +#define BMI160_USER_INTR_STAT_0_SINGLE_TAP_INTR__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name ORIENT INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 6 */ +#define BMI160_USER_INTR_STAT_0_ORIENT__POS (6) +#define BMI160_USER_INTR_STAT_0_ORIENT__LEN (1) +#define BMI160_USER_INTR_STAT_0_ORIENT__MSK (0x40) +#define BMI160_USER_INTR_STAT_0_ORIENT__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name FLAT INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_0 Description - Reg Addr --> 0x1C, Bit --> 7 */ +#define BMI160_USER_INTR_STAT_0_FLAT__POS (7) +#define BMI160_USER_INTR_STAT_0_FLAT__LEN (1) +#define BMI160_USER_INTR_STAT_0_FLAT__MSK (0x80) +#define BMI160_USER_INTR_STAT_0_FLAT__REG \ + (BMI160_USER_INTR_STAT_0_ADDR) +/**************************************************************/ +/**\name HIGH_G INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 2 */ +#define BMI160_USER_INTR_STAT_1_HIGH_G_INTR__POS (2) +#define BMI160_USER_INTR_STAT_1_HIGH_G_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_1_HIGH_G_INTR__MSK (0x04) +#define BMI160_USER_INTR_STAT_1_HIGH_G_INTR__REG \ + (BMI160_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name LOW_G INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 3 */ +#define BMI160_USER_INTR_STAT_1_LOW_G_INTR__POS (3) +#define BMI160_USER_INTR_STAT_1_LOW_G_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_1_LOW_G_INTR__MSK (0x08) +#define BMI160_USER_INTR_STAT_1_LOW_G_INTR__REG \ + (BMI160_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name DATA READY INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 4 */ +#define BMI160_USER_INTR_STAT_1_DATA_RDY_INTR__POS (4) +#define BMI160_USER_INTR_STAT_1_DATA_RDY_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_1_DATA_RDY_INTR__MSK (0x10) +#define BMI160_USER_INTR_STAT_1_DATA_RDY_INTR__REG \ + (BMI160_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name FIFO FULL INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 5 */ +#define BMI160_USER_INTR_STAT_1_FIFO_FULL_INTR__POS (5) +#define BMI160_USER_INTR_STAT_1_FIFO_FULL_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_1_FIFO_FULL_INTR__MSK (0x20) +#define BMI160_USER_INTR_STAT_1_FIFO_FULL_INTR__REG \ + (BMI160_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name FIFO WATERMARK INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 6 */ +#define BMI160_USER_INTR_STAT_1_FIFO_WM_INTR__POS (6) +#define BMI160_USER_INTR_STAT_1_FIFO_WM_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_1_FIFO_WM_INTR__MSK (0x40) +#define BMI160_USER_INTR_STAT_1_FIFO_WM_INTR__REG \ + (BMI160_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name NO MOTION INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_1 Description - Reg Addr --> 0x1D, Bit --> 7 */ +#define BMI160_USER_INTR_STAT_1_NOMOTION_INTR__POS (7) +#define BMI160_USER_INTR_STAT_1_NOMOTION_INTR__LEN (1) +#define BMI160_USER_INTR_STAT_1_NOMOTION_INTR__MSK (0x80) +#define BMI160_USER_INTR_STAT_1_NOMOTION_INTR__REG \ + (BMI160_USER_INTR_STAT_1_ADDR) +/**************************************************************/ +/**\name ANY MOTION-XYZ AXIS INTERRUPT STATUS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 0 */ +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__POS (0) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__LEN (1) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__MSK (0x01) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_X__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 1 */ +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__POS (1) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__LEN (1) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__MSK (0x02) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 2 */ +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__POS (2) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__LEN (1) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__MSK (0x04) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name ANY MOTION SIGN LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 3 */ +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_SIGN__POS (3) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_SIGN__LEN (1) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_SIGN__MSK (0x08) +#define BMI160_USER_INTR_STAT_2_ANY_MOTION_SIGN__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name TAP_XYZ AND SIGN LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 4 */ +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_X__POS (4) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_X__LEN (1) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_X__MSK (0x10) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_X__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 5 */ +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Y__POS (5) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Y__LEN (1) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Y__MSK (0x20) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Y__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 6 */ +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Z__POS (6) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Z__LEN (1) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Z__MSK (0x40) +#define BMI160_USER_INTR_STAT_2_TAP_FIRST_Z__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) + +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 7 */ +#define BMI160_USER_INTR_STAT_2_TAP_SIGN__POS (7) +#define BMI160_USER_INTR_STAT_2_TAP_SIGN__LEN (1) +#define BMI160_USER_INTR_STAT_2_TAP_SIGN__MSK (0x80) +#define BMI160_USER_INTR_STAT_2_TAP_SIGN__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT SATAUS FOR WHOLE 0x1E LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_2 Description - Reg Addr --> 0x1E, Bit --> 0...7 */ +#define BMI160_USER_INTR_STAT_2__POS (0) +#define BMI160_USER_INTR_STAT_2__LEN (8) +#define BMI160_USER_INTR_STAT_2__MSK (0xFF) +#define BMI160_USER_INTR_STAT_2__REG \ + (BMI160_USER_INTR_STAT_2_ADDR) +/**************************************************************/ +/**\name HIGH_G-XYZ AND SIGN LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 0 */ +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_X__POS (0) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_X__LEN (1) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_X__MSK (0x01) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_X__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> 0x1E, Bit --> 1 */ +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Y__POS (1) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Y__LEN (1) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Y__MSK (0x02) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Y__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 2 */ +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Z__POS (2) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Z__LEN (1) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Z__MSK (0x04) +#define BMI160_USER_INTR_STAT_3_HIGH_G_FIRST_Z__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 3 */ +#define BMI160_USER_INTR_STAT_3_HIGH_G_SIGN__POS (3) +#define BMI160_USER_INTR_STAT_3_HIGH_G_SIGN__LEN (1) +#define BMI160_USER_INTR_STAT_3_HIGH_G_SIGN__MSK (0x08) +#define BMI160_USER_INTR_STAT_3_HIGH_G_SIGN__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name ORIENT XY and Z AXIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 4...5 */ +#define BMI160_USER_INTR_STAT_3_ORIENT_XY__POS (4) +#define BMI160_USER_INTR_STAT_3_ORIENT_XY__LEN (2) +#define BMI160_USER_INTR_STAT_3_ORIENT_XY__MSK (0x30) +#define BMI160_USER_INTR_STAT_3_ORIENT_XY__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) + +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 6 */ +#define BMI160_USER_INTR_STAT_3_ORIENT_Z__POS (6) +#define BMI160_USER_INTR_STAT_3_ORIENT_Z__LEN (1) +#define BMI160_USER_INTR_STAT_3_ORIENT_Z__MSK (0x40) +#define BMI160_USER_INTR_STAT_3_ORIENT_Z__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name FLAT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 7 */ +#define BMI160_USER_INTR_STAT_3_FLAT__POS (7) +#define BMI160_USER_INTR_STAT_3_FLAT__LEN (1) +#define BMI160_USER_INTR_STAT_3_FLAT__MSK (0x80) +#define BMI160_USER_INTR_STAT_3_FLAT__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name (0x1F) LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Status_3 Description - Reg Addr --> (0x1F), Bit --> 0...7 */ +#define BMI160_USER_INTR_STAT_3__POS (0) +#define BMI160_USER_INTR_STAT_3__LEN (8) +#define BMI160_USER_INTR_STAT_3__MSK (0xFF) +#define BMI160_USER_INTR_STAT_3__REG \ + (BMI160_USER_INTR_STAT_3_ADDR) +/**************************************************************/ +/**\name TEMPERATURE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Temperature Description - LSB Reg Addr --> (0x20), Bit --> 0...7 */ +#define BMI160_USER_TEMP_LSB_VALUE__POS (0) +#define BMI160_USER_TEMP_LSB_VALUE__LEN (8) +#define BMI160_USER_TEMP_LSB_VALUE__MSK (0xFF) +#define BMI160_USER_TEMP_LSB_VALUE__REG \ + (BMI160_USER_TEMPERATURE_0_ADDR) + +/* Temperature Description - LSB Reg Addr --> 0x21, Bit --> 0...7 */ +#define BMI160_USER_TEMP_MSB_VALUE__POS (0) +#define BMI160_USER_TEMP_MSB_VALUE__LEN (8) +#define BMI160_USER_TEMP_MSB_VALUE__MSK (0xFF) +#define BMI160_USER_TEMP_MSB_VALUE__REG \ + (BMI160_USER_TEMPERATURE_1_ADDR) +/**************************************************************/ +/**\name FIFO BYTE COUNTER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Length0 Description - Reg Addr --> 0x22, Bit --> 0...7 */ +#define BMI160_USER_FIFO_BYTE_COUNTER_LSB__POS (0) +#define BMI160_USER_FIFO_BYTE_COUNTER_LSB__LEN (8) +#define BMI160_USER_FIFO_BYTE_COUNTER_LSB__MSK (0xFF) +#define BMI160_USER_FIFO_BYTE_COUNTER_LSB__REG \ + (BMI160_USER_FIFO_LENGTH_0_ADDR) + +/*Fifo_Length1 Description - Reg Addr --> 0x23, Bit --> 0...2 */ +#define BMI160_USER_FIFO_BYTE_COUNTER_MSB__POS (0) +#define BMI160_USER_FIFO_BYTE_COUNTER_MSB__LEN 3 +#define BMI160_USER_FIFO_BYTE_COUNTER_MSB__MSK (0x07) +#define BMI160_USER_FIFO_BYTE_COUNTER_MSB__REG \ + (BMI160_USER_FIFO_LENGTH_1_ADDR) + +/**************************************************************/ +/**\name FIFO DATA LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Data Description - Reg Addr --> 0x24, Bit --> 0...7 */ +#define BMI160_USER_FIFO_DATA__POS (0) +#define BMI160_USER_FIFO_DATA__LEN (8) +#define BMI160_USER_FIFO_DATA__MSK (0xFF) +#define BMI160_USER_FIFO_DATA__REG (BMI160_USER_FIFO_DATA_ADDR) + +/**************************************************************/ +/**\name ACCEL CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Acc_Conf Description - Reg Addr --> (0x40), Bit --> 0...3 */ +#define BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__POS (0) +#define BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__LEN (4) +#define BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__MSK (0x0F) +#define BMI160_USER_ACCEL_CONFIG_OUTPUT_DATA_RATE__REG \ +(BMI160_USER_ACCEL_CONFIG_ADDR) + +/* Acc_Conf Description - Reg Addr --> (0x40), Bit --> 4...6 */ +#define BMI160_USER_ACCEL_CONFIG_ACCEL_BW__POS (4) +#define BMI160_USER_ACCEL_CONFIG_ACCEL_BW__LEN (3) +#define BMI160_USER_ACCEL_CONFIG_ACCEL_BW__MSK (0x70) +#define BMI160_USER_ACCEL_CONFIG_ACCEL_BW__REG (BMI160_USER_ACCEL_CONFIG_ADDR) + +/* Acc_Conf Description - Reg Addr --> (0x40), Bit --> 7 */ +#define BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__POS (7) +#define BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__LEN (1) +#define BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__MSK (0x80) +#define BMI160_USER_ACCEL_CONFIG_ACCEL_UNDER_SAMPLING__REG \ +(BMI160_USER_ACCEL_CONFIG_ADDR) + +/* Acc_Range Description - Reg Addr --> 0x41, Bit --> 0...3 */ +#define BMI160_USER_ACCEL_RANGE__POS (0) +#define BMI160_USER_ACCEL_RANGE__LEN (4) +#define BMI160_USER_ACCEL_RANGE__MSK (0x0F) +#define BMI160_USER_ACCEL_RANGE__REG \ +(BMI160_USER_ACCEL_RANGE_ADDR) +/**************************************************************/ +/**\name GYRO CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Gyro_Conf Description - Reg Addr --> (0x42), Bit --> 0...3 */ +#define BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__POS (0) +#define BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__LEN (4) +#define BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__MSK (0x0F) +#define BMI160_USER_GYRO_CONFIG_OUTPUT_DATA_RATE__REG \ +(BMI160_USER_GYRO_CONFIG_ADDR) + +/* Gyro_Conf Description - Reg Addr --> (0x42), Bit --> 4...5 */ +#define BMI160_USER_GYRO_CONFIG_BW__POS (4) +#define BMI160_USER_GYRO_CONFIG_BW__LEN (2) +#define BMI160_USER_GYRO_CONFIG_BW__MSK (0x30) +#define BMI160_USER_GYRO_CONFIG_BW__REG \ +(BMI160_USER_GYRO_CONFIG_ADDR) + +/* Gyr_Range Description - Reg Addr --> 0x43, Bit --> 0...2 */ +#define BMI160_USER_GYRO_RANGE__POS (0) +#define BMI160_USER_GYRO_RANGE__LEN (3) +#define BMI160_USER_GYRO_RANGE__MSK (0x07) +#define BMI160_USER_GYRO_RANGE__REG (BMI160_USER_GYRO_RANGE_ADDR) +/**************************************************************/ +/**\name MAG CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Mag_Conf Description - Reg Addr --> (0x44), Bit --> 0...3 */ +#define BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE__POS (0) +#define BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE__LEN (4) +#define BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE__MSK (0x0F) +#define BMI160_USER_MAG_CONFIG_OUTPUT_DATA_RATE__REG \ +(BMI160_USER_MAG_CONFIG_ADDR) +/**************************************************************/ +/**\name FIFO DOWNS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Downs Description - Reg Addr --> 0x45, Bit --> 0...2 */ +#define BMI160_USER_FIFO_DOWN_GYRO__POS (0) +#define BMI160_USER_FIFO_DOWN_GYRO__LEN (3) +#define BMI160_USER_FIFO_DOWN_GYRO__MSK (0x07) +#define BMI160_USER_FIFO_DOWN_GYRO__REG (BMI160_USER_FIFO_DOWN_ADDR) +/**************************************************************/ +/**\name FIFO FILTER FOR ACCEL AND GYRO LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_filt Description - Reg Addr --> 0x45, Bit --> 3 */ +#define BMI160_USER_FIFO_FILTER_GYRO__POS (3) +#define BMI160_USER_FIFO_FILTER_GYRO__LEN (1) +#define BMI160_USER_FIFO_FILTER_GYRO__MSK (0x08) +#define BMI160_USER_FIFO_FILTER_GYRO__REG (BMI160_USER_FIFO_DOWN_ADDR) + +/* Fifo_Downs Description - Reg Addr --> 0x45, Bit --> 4...6 */ +#define BMI160_USER_FIFO_DOWN_ACCEL__POS (4) +#define BMI160_USER_FIFO_DOWN_ACCEL__LEN (3) +#define BMI160_USER_FIFO_DOWN_ACCEL__MSK (0x70) +#define BMI160_USER_FIFO_DOWN_ACCEL__REG (BMI160_USER_FIFO_DOWN_ADDR) + +/* Fifo_FILT Description - Reg Addr --> 0x45, Bit --> 7 */ +#define BMI160_USER_FIFO_FILTER_ACCEL__POS (7) +#define BMI160_USER_FIFO_FILTER_ACCEL__LEN (1) +#define BMI160_USER_FIFO_FILTER_ACCEL__MSK (0x80) +#define BMI160_USER_FIFO_FILTER_ACCEL__REG (BMI160_USER_FIFO_DOWN_ADDR) +/**************************************************************/ +/**\name FIFO WATER MARK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_0 Description - Reg Addr --> 0x46, Bit --> 0...7 */ +#define BMI160_USER_FIFO_WM__POS (0) +#define BMI160_USER_FIFO_WM__LEN (8) +#define BMI160_USER_FIFO_WM__MSK (0xFF) +#define BMI160_USER_FIFO_WM__REG (BMI160_USER_FIFO_CONFIG_0_ADDR) +/**************************************************************/ +/**\name FIFO TIME LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 1 */ +#define BMI160_USER_FIFO_TIME_ENABLE__POS (1) +#define BMI160_USER_FIFO_TIME_ENABLE__LEN (1) +#define BMI160_USER_FIFO_TIME_ENABLE__MSK (0x02) +#define BMI160_USER_FIFO_TIME_ENABLE__REG (BMI160_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO TAG INTERRUPT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 2 */ +#define BMI160_USER_FIFO_TAG_INTR2_ENABLE__POS (2) +#define BMI160_USER_FIFO_TAG_INTR2_ENABLE__LEN (1) +#define BMI160_USER_FIFO_TAG_INTR2_ENABLE__MSK (0x04) +#define BMI160_USER_FIFO_TAG_INTR2_ENABLE__REG (BMI160_USER_FIFO_CONFIG_1_ADDR) + +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 3 */ +#define BMI160_USER_FIFO_TAG_INTR1_ENABLE__POS (3) +#define BMI160_USER_FIFO_TAG_INTR1_ENABLE__LEN (1) +#define BMI160_USER_FIFO_TAG_INTR1_ENABLE__MSK (0x08) +#define BMI160_USER_FIFO_TAG_INTR1_ENABLE__REG (BMI160_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO HEADER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 4 */ +#define BMI160_USER_FIFO_HEADER_ENABLE__POS (4) +#define BMI160_USER_FIFO_HEADER_ENABLE__LEN (1) +#define BMI160_USER_FIFO_HEADER_ENABLE__MSK (0x10) +#define BMI160_USER_FIFO_HEADER_ENABLE__REG \ +(BMI160_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO MAG ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 5 */ +#define BMI160_USER_FIFO_MAG_ENABLE__POS (5) +#define BMI160_USER_FIFO_MAG_ENABLE__LEN (1) +#define BMI160_USER_FIFO_MAG_ENABLE__MSK (0x20) +#define BMI160_USER_FIFO_MAG_ENABLE__REG \ +(BMI160_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO ACCEL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 6 */ +#define BMI160_USER_FIFO_ACCEL_ENABLE__POS (6) +#define BMI160_USER_FIFO_ACCEL_ENABLE__LEN (1) +#define BMI160_USER_FIFO_ACCEL_ENABLE__MSK (0x40) +#define BMI160_USER_FIFO_ACCEL_ENABLE__REG \ +(BMI160_USER_FIFO_CONFIG_1_ADDR) +/**************************************************************/ +/**\name FIFO GYRO ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Fifo_Config_1 Description - Reg Addr --> 0x47, Bit --> 7 */ +#define BMI160_USER_FIFO_GYRO_ENABLE__POS (7) +#define BMI160_USER_FIFO_GYRO_ENABLE__LEN (1) +#define BMI160_USER_FIFO_GYRO_ENABLE__MSK (0x80) +#define BMI160_USER_FIFO_GYRO_ENABLE__REG \ +(BMI160_USER_FIFO_CONFIG_1_ADDR) + +/**************************************************************/ +/**\name MAG I2C ADDRESS SELECTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ + +/* Mag_IF_0 Description - Reg Addr --> 0x4b, Bit --> 1...7 */ +#define BMI160_USER_I2C_DEVICE_ADDR__POS (1) +#define BMI160_USER_I2C_DEVICE_ADDR__LEN (7) +#define BMI160_USER_I2C_DEVICE_ADDR__MSK (0xFE) +#define BMI160_USER_I2C_DEVICE_ADDR__REG (BMI160_USER_MAG_IF_0_ADDR) +/**************************************************************/ +/**\name MAG CONFIGURATION FOR SECONDARY + INTERFACE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Mag_IF_1 Description - Reg Addr --> 0x4c, Bit --> 0...1 */ +#define BMI160_USER_MAG_BURST__POS (0) +#define BMI160_USER_MAG_BURST__LEN (2) +#define BMI160_USER_MAG_BURST__MSK (0x03) +#define BMI160_USER_MAG_BURST__REG (BMI160_USER_MAG_IF_1_ADDR) + +/* Mag_IF_1 Description - Reg Addr --> 0x4c, Bit --> 2...5 */ +#define BMI160_USER_MAG_OFFSET__POS (2) +#define BMI160_USER_MAG_OFFSET__LEN (4) +#define BMI160_USER_MAG_OFFSET__MSK (0x3C) +#define BMI160_USER_MAG_OFFSET__REG (BMI160_USER_MAG_IF_1_ADDR) + +/* Mag_IF_1 Description - Reg Addr --> 0x4c, Bit --> 7 */ +#define BMI160_USER_MAG_MANUAL_ENABLE__POS (7) +#define BMI160_USER_MAG_MANUAL_ENABLE__LEN (1) +#define BMI160_USER_MAG_MANUAL_ENABLE__MSK (0x80) +#define BMI160_USER_MAG_MANUAL_ENABLE__REG \ +(BMI160_USER_MAG_IF_1_ADDR) + +/* Mag_IF_2 Description - Reg Addr --> 0x4d, Bit -->0... 7 */ +#define BMI160_USER_READ_ADDR__POS (0) +#define BMI160_USER_READ_ADDR__LEN (8) +#define BMI160_USER_READ_ADDR__MSK (0xFF) +#define BMI160_USER_READ_ADDR__REG (BMI160_USER_MAG_IF_2_ADDR) + +/* Mag_IF_3 Description - Reg Addr --> 0x4e, Bit -->0... 7 */ +#define BMI160_USER_WRITE_ADDR__POS (0) +#define BMI160_USER_WRITE_ADDR__LEN (8) +#define BMI160_USER_WRITE_ADDR__MSK (0xFF) +#define BMI160_USER_WRITE_ADDR__REG (BMI160_USER_MAG_IF_3_ADDR) + +/* Mag_IF_4 Description - Reg Addr --> 0x4f, Bit -->0... 7 */ +#define BMI160_USER_WRITE_DATA__POS (0) +#define BMI160_USER_WRITE_DATA__LEN (8) +#define BMI160_USER_WRITE_DATA__MSK (0xFF) +#define BMI160_USER_WRITE_DATA__REG (BMI160_USER_MAG_IF_4_ADDR) +/**************************************************************/ +/**\name ANY MOTION XYZ AXIS ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->0 */ +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__POS (0) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__MSK (0x01) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_X_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_0_ADDR) + +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->1 */ +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__POS (1) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__MSK (0x02) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Y_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_0_ADDR) + +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->2 */ +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__POS (2) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__MSK (0x04) +#define BMI160_USER_INTR_ENABLE_0_ANY_MOTION_Z_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name DOUBLE TAP ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->4 */ +#define BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__POS (4) +#define BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__MSK (0x10) +#define BMI160_USER_INTR_ENABLE_0_DOUBLE_TAP_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name SINGLE TAP ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->5 */ +#define BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__POS (5) +#define BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__MSK (0x20) +#define BMI160_USER_INTR_ENABLE_0_SINGLE_TAP_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name ORIENT ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->6 */ +#define BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__POS (6) +#define BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__MSK (0x40) +#define BMI160_USER_INTR_ENABLE_0_ORIENT_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name FLAT ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_0 Description - Reg Addr --> 0x50, Bit -->7 */ +#define BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__POS (7) +#define BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__MSK (0x80) +#define BMI160_USER_INTR_ENABLE_0_FLAT_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_0_ADDR) +/**************************************************************/ +/**\name HIGH_G XYZ ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->0 */ +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__POS (0) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__MSK (0x01) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_X_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_1_ADDR) + +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->1 */ +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__POS (1) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__MSK (0x02) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Y_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_1_ADDR) + +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->2 */ +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__POS (2) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__MSK (0x04) +#define BMI160_USER_INTR_ENABLE_1_HIGH_G_Z_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name LOW_G ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->3 */ +#define BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__POS (3) +#define BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__MSK (0x08) +#define BMI160_USER_INTR_ENABLE_1_LOW_G_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name DATA READY ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->4 */ +#define BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__POS (4) +#define BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__MSK (0x10) +#define BMI160_USER_INTR_ENABLE_1_DATA_RDY_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name FIFO FULL AND WATER MARK ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->5 */ +#define BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__POS (5) +#define BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__MSK (0x20) +#define BMI160_USER_INTR_ENABLE_1_FIFO_FULL_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_1_ADDR) + +/* Int_En_1 Description - Reg Addr --> (0x51), Bit -->6 */ +#define BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__POS (6) +#define BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__MSK (0x40) +#define BMI160_USER_INTR_ENABLE_1_FIFO_WM_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_1_ADDR) +/**************************************************************/ +/**\name NO MOTION XYZ ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->0 */ +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__POS (0) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__MSK (0x01) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_X_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_2_ADDR) + +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->1 */ +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__POS (1) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__MSK (0x02) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Y_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_2_ADDR) + +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->2 */ +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__POS (2) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__MSK (0x04) +#define BMI160_USER_INTR_ENABLE_2_NOMOTION_Z_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_2_ADDR) +/**************************************************************/ +/**\name STEP DETECTOR ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_En_2 Description - Reg Addr --> (0x52), Bit -->3 */ +#define BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__POS (3) +#define BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__LEN (1) +#define BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__MSK (0x08) +#define BMI160_USER_INTR_ENABLE_2_STEP_DETECTOR_ENABLE__REG \ +(BMI160_USER_INTR_ENABLE_2_ADDR) +/**************************************************************/ +/**\name EDGE CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->0 */ +#define BMI160_USER_INTR1_EDGE_CTRL__POS (0) +#define BMI160_USER_INTR1_EDGE_CTRL__LEN (1) +#define BMI160_USER_INTR1_EDGE_CTRL__MSK (0x01) +#define BMI160_USER_INTR1_EDGE_CTRL__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name LEVEL CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->1 */ +#define BMI160_USER_INTR1_LEVEL__POS (1) +#define BMI160_USER_INTR1_LEVEL__LEN (1) +#define BMI160_USER_INTR1_LEVEL__MSK (0x02) +#define BMI160_USER_INTR1_LEVEL__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name OUTPUT TYPE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->2 */ +#define BMI160_USER_INTR1_OUTPUT_TYPE__POS (2) +#define BMI160_USER_INTR1_OUTPUT_TYPE__LEN (1) +#define BMI160_USER_INTR1_OUTPUT_TYPE__MSK (0x04) +#define BMI160_USER_INTR1_OUTPUT_TYPE__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name OUTPUT TYPE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->3 */ +#define BMI160_USER_INTR1_OUTPUT_ENABLE__POS (3) +#define BMI160_USER_INTR1_OUTPUT_ENABLE__LEN (1) +#define BMI160_USER_INTR1_OUTPUT_ENABLE__MSK (0x08) +#define BMI160_USER_INTR1_OUTPUT_ENABLE__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name EDGE CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->4 */ +#define BMI160_USER_INTR2_EDGE_CTRL__POS (4) +#define BMI160_USER_INTR2_EDGE_CTRL__LEN (1) +#define BMI160_USER_INTR2_EDGE_CTRL__MSK (0x10) +#define BMI160_USER_INTR2_EDGE_CTRL__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name LEVEL CONTROL ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->5 */ +#define BMI160_USER_INTR2_LEVEL__POS (5) +#define BMI160_USER_INTR2_LEVEL__LEN (1) +#define BMI160_USER_INTR2_LEVEL__MSK (0x20) +#define BMI160_USER_INTR2_LEVEL__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name OUTPUT TYPE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->6 */ +#define BMI160_USER_INTR2_OUTPUT_TYPE__POS (6) +#define BMI160_USER_INTR2_OUTPUT_TYPE__LEN (1) +#define BMI160_USER_INTR2_OUTPUT_TYPE__MSK (0x40) +#define BMI160_USER_INTR2_OUTPUT_TYPE__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) + +/* Int_Out_Ctrl Description - Reg Addr --> 0x53, Bit -->7 */ +#define BMI160_USER_INTR2_OUTPUT_EN__POS (7) +#define BMI160_USER_INTR2_OUTPUT_EN__LEN (1) +#define BMI160_USER_INTR2_OUTPUT_EN__MSK (0x80) +#define BMI160_USER_INTR2_OUTPUT_EN__REG \ +(BMI160_USER_INTR_OUT_CTRL_ADDR) +/**************************************************************/ +/**\name LATCH INTERRUPT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Latch Description - Reg Addr --> 0x54, Bit -->0...3 */ +#define BMI160_USER_INTR_LATCH__POS (0) +#define BMI160_USER_INTR_LATCH__LEN (4) +#define BMI160_USER_INTR_LATCH__MSK (0x0F) +#define BMI160_USER_INTR_LATCH__REG (BMI160_USER_INTR_LATCH_ADDR) +/**************************************************************/ +/**\name INPUT ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Latch Description - Reg Addr --> 0x54, Bit -->4 */ +#define BMI160_USER_INTR1_INPUT_ENABLE__POS (4) +#define BMI160_USER_INTR1_INPUT_ENABLE__LEN (1) +#define BMI160_USER_INTR1_INPUT_ENABLE__MSK (0x10) +#define BMI160_USER_INTR1_INPUT_ENABLE__REG \ +(BMI160_USER_INTR_LATCH_ADDR) + +/* Int_Latch Description - Reg Addr --> 0x54, Bit -->5*/ +#define BMI160_USER_INTR2_INPUT_ENABLE__POS (5) +#define BMI160_USER_INTR2_INPUT_ENABLE__LEN (1) +#define BMI160_USER_INTR2_INPUT_ENABLE__MSK (0x20) +#define BMI160_USER_INTR2_INPUT_ENABLE__REG \ +(BMI160_USER_INTR_LATCH_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF LOW_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->0 */ +#define BMI160_USER_INTR_MAP_0_INTR1_LOW_G__POS (0) +#define BMI160_USER_INTR_MAP_0_INTR1_LOW_G__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_LOW_G__MSK (0x01) +#define BMI160_USER_INTR_MAP_0_INTR1_LOW_G__REG (BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF HIGH_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->1 */ +#define BMI160_USER_INTR_MAP_0_INTR1_HIGH_G__POS (1) +#define BMI160_USER_INTR_MAP_0_INTR1_HIGH_G__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_HIGH_G__MSK (0x02) +#define BMI160_USER_INTR_MAP_0_INTR1_HIGH_G__REG \ +(BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT MAPPIONG OF ANY MOTION_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->2 */ +#define BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__POS (2) +#define BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__MSK (0x04) +#define BMI160_USER_INTR_MAP_0_INTR1_ANY_MOTION__REG \ +(BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF NO MOTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->3 */ +#define BMI160_USER_INTR_MAP_0_INTR1_NOMOTION__POS (3) +#define BMI160_USER_INTR_MAP_0_INTR1_NOMOTION__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_NOMOTION__MSK (0x08) +#define BMI160_USER_INTR_MAP_0_INTR1_NOMOTION__REG (BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF DOUBLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->4 */ +#define BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__POS (4) +#define BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__MSK (0x10) +#define BMI160_USER_INTR_MAP_0_INTR1_DOUBLE_TAP__REG \ +(BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF SINGLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->5 */ +#define BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP__POS (5) +#define BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP__MSK (0x20) +#define BMI160_USER_INTR_MAP_0_INTR1_SINGLE_TAP__REG \ +(BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF ORIENT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x55, Bit -->6 */ +#define BMI160_USER_INTR_MAP_0_INTR1_ORIENT__POS (6) +#define BMI160_USER_INTR_MAP_0_INTR1_ORIENT__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_ORIENT__MSK (0x40) +#define BMI160_USER_INTR_MAP_0_INTR1_ORIENT__REG \ +(BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT MAPPIONG OF FLAT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_0 Description - Reg Addr --> 0x56, Bit -->7 */ +#define BMI160_USER_INTR_MAP_0_INTR1_FLAT__POS (7) +#define BMI160_USER_INTR_MAP_0_INTR1_FLAT__LEN (1) +#define BMI160_USER_INTR_MAP_0_INTR1_FLAT__MSK (0x80) +#define BMI160_USER_INTR_MAP_0_INTR1_FLAT__REG (BMI160_USER_INTR_MAP_0_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF PMU TRIGGER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->0 */ +#define BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG__POS (0) +#define BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG__MSK (0x01) +#define BMI160_USER_INTR_MAP_1_INTR2_PMU_TRIG__REG (BMI160_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF FIFO FULL AND + WATER MARK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->1 */ +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL__POS (1) +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL__MSK (0x02) +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_FULL__REG \ +(BMI160_USER_INTR_MAP_1_ADDR) + +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->2 */ +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__POS (2) +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__MSK (0x04) +#define BMI160_USER_INTR_MAP_1_INTR2_FIFO_WM__REG \ +(BMI160_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF DATA READY LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->3 */ +#define BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY__POS (3) +#define BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY__MSK (0x08) +#define BMI160_USER_INTR_MAP_1_INTR2_DATA_RDY__REG \ +(BMI160_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF PMU TRIGGER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->4 */ +#define BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG__POS (4) +#define BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG__MSK (0x10) +#define BMI160_USER_INTR_MAP_1_INTR1_PMU_TRIG__REG (BMI160_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF FIFO FULL AND + WATER MARK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->5 */ +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL__POS (5) +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL__MSK (0x20) +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_FULL__REG \ +(BMI160_USER_INTR_MAP_1_ADDR) + +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->6 */ +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__POS (6) +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__MSK (0x40) +#define BMI160_USER_INTR_MAP_1_INTR1_FIFO_WM__REG \ +(BMI160_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT1 MAPPIONG OF DATA READY LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_1 Description - Reg Addr --> 0x56, Bit -->7 */ +#define BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY__POS (7) +#define BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY__LEN (1) +#define BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY__MSK (0x80) +#define BMI160_USER_INTR_MAP_1_INTR1_DATA_RDY__REG \ +(BMI160_USER_INTR_MAP_1_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF LOW_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->0 */ +#define BMI160_USER_INTR_MAP_2_INTR2_LOW_G__POS (0) +#define BMI160_USER_INTR_MAP_2_INTR2_LOW_G__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_LOW_G__MSK (0x01) +#define BMI160_USER_INTR_MAP_2_INTR2_LOW_G__REG (BMI160_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF HIGH_G LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->1 */ +#define BMI160_USER_INTR_MAP_2_INTR2_HIGH_G__POS (1) +#define BMI160_USER_INTR_MAP_2_INTR2_HIGH_G__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_HIGH_G__MSK (0x02) +#define BMI160_USER_INTR_MAP_2_INTR2_HIGH_G__REG \ +(BMI160_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF ANY MOTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->2 */ +#define BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__POS (2) +#define BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__MSK (0x04) +#define BMI160_USER_INTR_MAP_2_INTR2_ANY_MOTION__REG \ +(BMI160_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF NO MOTION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->3 */ +#define BMI160_USER_INTR_MAP_2_INTR2_NOMOTION__POS (3) +#define BMI160_USER_INTR_MAP_2_INTR2_NOMOTION__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_NOMOTION__MSK (0x08) +#define BMI160_USER_INTR_MAP_2_INTR2_NOMOTION__REG (BMI160_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF DOUBLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->4 */ +#define BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__POS (4) +#define BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__MSK (0x10) +#define BMI160_USER_INTR_MAP_2_INTR2_DOUBLE_TAP__REG \ +(BMI160_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF SINGLE TAP LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->5 */ +#define BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP__POS (5) +#define BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP__MSK (0x20) +#define BMI160_USER_INTR_MAP_2_INTR2_SINGLE_TAP__REG \ +(BMI160_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF ORIENT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->6 */ +#define BMI160_USER_INTR_MAP_2_INTR2_ORIENT__POS (6) +#define BMI160_USER_INTR_MAP_2_INTR2_ORIENT__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_ORIENT__MSK (0x40) +#define BMI160_USER_INTR_MAP_2_INTR2_ORIENT__REG \ +(BMI160_USER_INTR_MAP_2_ADDR) +/**************************************************************/ +/**\name INTERRUPT2 MAPPIONG OF FLAT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Map_2 Description - Reg Addr --> 0x57, Bit -->7 */ +#define BMI160_USER_INTR_MAP_2_INTR2_FLAT__POS (7) +#define BMI160_USER_INTR_MAP_2_INTR2_FLAT__LEN (1) +#define BMI160_USER_INTR_MAP_2_INTR2_FLAT__MSK (0x80) +#define BMI160_USER_INTR_MAP_2_INTR2_FLAT__REG (BMI160_USER_INTR_MAP_2_ADDR) + +/**************************************************************/ +/**\name TAP SOURCE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Data_0 Description - Reg Addr --> 0x58, Bit --> 3 */ +#define BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE__POS (3) +#define BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE__LEN (1) +#define BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE__MSK (0x08) +#define BMI160_USER_INTR_DATA_0_INTR_TAP_SOURCE__REG \ +(BMI160_USER_INTR_DATA_0_ADDR) + +/**************************************************************/ +/**\name HIGH SOURCE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Data_0 Description - Reg Addr --> 0x58, Bit --> 7 */ +#define BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__POS (7) +#define BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__LEN (1) +#define BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__MSK (0x80) +#define BMI160_USER_INTR_DATA_0_INTR_LOW_HIGH_SOURCE__REG \ +(BMI160_USER_INTR_DATA_0_ADDR) + +/**************************************************************/ +/**\name MOTION SOURCE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Data_1 Description - Reg Addr --> 0x59, Bit --> 7 */ +#define BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE__POS (7) +#define BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE__LEN (1) +#define BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE__MSK (0x80) +#define BMI160_USER_INTR_DATA_1_INTR_MOTION_SOURCE__REG \ + (BMI160_USER_INTR_DATA_1_ADDR) +/**************************************************************/ +/**\name LOW HIGH DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_0 Description - Reg Addr --> 0x5a, Bit --> 0...7 */ +#define BMI160_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__POS (0) +#define BMI160_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__LEN (8) +#define BMI160_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__MSK (0xFF) +#define BMI160_USER_INTR_LOWHIGH_0_INTR_LOW_DURN__REG \ + (BMI160_USER_INTR_LOWHIGH_0_ADDR) +/**************************************************************/ +/**\name LOW THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_1 Description - Reg Addr --> 0x5b, Bit --> 0...7 */ +#define BMI160_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__POS (0) +#define BMI160_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__LEN (8) +#define BMI160_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__MSK (0xFF) +#define BMI160_USER_INTR_LOWHIGH_1_INTR_LOW_THRES__REG \ + (BMI160_USER_INTR_LOWHIGH_1_ADDR) +/**************************************************************/ +/**\name LOW HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_2 Description - Reg Addr --> 0x5c, Bit --> 0...1 */ +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__POS (0) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__LEN (2) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__MSK (0x03) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_HYST__REG \ + (BMI160_USER_INTR_LOWHIGH_2_ADDR) +/**************************************************************/ +/**\name LOW MODE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_2 Description - Reg Addr --> 0x5c, Bit --> 2 */ +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__POS (2) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__LEN (1) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__MSK (0x04) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_LOW_G_MODE__REG \ + (BMI160_USER_INTR_LOWHIGH_2_ADDR) +/**************************************************************/ +/**\name HIGH_G HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_2 Description - Reg Addr --> 0x5c, Bit --> 6...7 */ +#define BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__POS (6) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__LEN (2) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__MSK (0xC0) +#define BMI160_USER_INTR_LOWHIGH_2_INTR_HIGH_G_HYST__REG \ + (BMI160_USER_INTR_LOWHIGH_2_ADDR) +/**************************************************************/ +/**\name HIGH_G DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_3 Description - Reg Addr --> 0x5d, Bit --> 0...7 */ +#define BMI160_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__POS (0) +#define BMI160_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__LEN (8) +#define BMI160_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__MSK (0xFF) +#define BMI160_USER_INTR_LOWHIGH_3_INTR_HIGH_G_DURN__REG \ + (BMI160_USER_INTR_LOWHIGH_3_ADDR) +/**************************************************************/ +/**\name HIGH_G THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_LowHigh_4 Description - Reg Addr --> 0x5e, Bit --> 0...7 */ +#define BMI160_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__POS (0) +#define BMI160_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__LEN (8) +#define BMI160_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__MSK (0xFF) +#define BMI160_USER_INTR_LOWHIGH_4_INTR_HIGH_THRES__REG \ + (BMI160_USER_INTR_LOWHIGH_4_ADDR) +/**************************************************************/ +/**\name ANY MOTION DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_0 Description - Reg Addr --> 0x5f, Bit --> 0...1 */ +#define BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__POS (0) +#define BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__LEN (2) +#define BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__MSK (0x03) +#define BMI160_USER_INTR_MOTION_0_INTR_ANY_MOTION_DURN__REG \ + (BMI160_USER_INTR_MOTION_0_ADDR) +/**************************************************************/ +/**\name SLOW/NO MOTION DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ + /* Int_Motion_0 Description - Reg Addr --> 0x5f, Bit --> 2...7 */ +#define BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__POS (2) +#define BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__LEN (6) +#define BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__MSK (0xFC) +#define BMI160_USER_INTR_MOTION_0_INTR_SLOW_NO_MOTION_DURN__REG \ + (BMI160_USER_INTR_MOTION_0_ADDR) +/**************************************************************/ +/**\name ANY MOTION THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_1 Description - Reg Addr --> (0x60), Bit --> 0...7 */ +#define BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__POS (0) +#define BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__LEN (8) +#define BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__MSK (0xFF) +#define BMI160_USER_INTR_MOTION_1_INTR_ANY_MOTION_THRES__REG \ + (BMI160_USER_INTR_MOTION_1_ADDR) +/**************************************************************/ +/**\name SLOW/NO MOTION THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_2 Description - Reg Addr --> 0x61, Bit --> 0...7 */ +#define BMI160_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__POS (0) +#define BMI160_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__LEN (8) +#define BMI160_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__MSK (0xFF) +#define BMI160_USER_INTR_MOTION_2_INTR_SLOW_NO_MOTION_THRES__REG \ + (BMI160_USER_INTR_MOTION_2_ADDR) +/**************************************************************/ +/**\name SLOW/NO MOTION SELECT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 0 */ +#define BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__POS (0) +#define BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__LEN (1) +#define BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__MSK (0x01) +#define BMI160_USER_INTR_MOTION_3_INTR_SLOW_NO_MOTION_SELECT__REG \ +(BMI160_USER_INTR_MOTION_3_ADDR) +/**************************************************************/ +/**\name SIGNIFICANT MOTION SELECT LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 1 */ +#define BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__POS (1) +#define BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__LEN (1) +#define BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__MSK (0x02) +#define BMI160_USER_INTR_SIGNIFICATION_MOTION_SELECT__REG \ + (BMI160_USER_INTR_MOTION_3_ADDR) + +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 3..2 */ +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__POS (2) +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__LEN (2) +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__MSK (0x0C) +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_SKIP__REG \ + (BMI160_USER_INTR_MOTION_3_ADDR) + +/* Int_Motion_3 Description - Reg Addr --> (0x62), Bit --> 5..4 */ +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__POS (4) +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__LEN (2) +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__MSK (0x30) +#define BMI160_USER_INTR_SIGNIFICANT_MOTION_PROOF__REG \ + (BMI160_USER_INTR_MOTION_3_ADDR) +/**************************************************************/ +/**\name TAP DURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* INT_TAP_0 Description - Reg Addr --> (0x63), Bit --> 0..2*/ +#define BMI160_USER_INTR_TAP_0_INTR_TAP_DURN__POS (0) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_DURN__LEN (3) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_DURN__MSK (0x07) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_DURN__REG \ +(BMI160_USER_INTR_TAP_0_ADDR) +/**************************************************************/ +/**\name TAP SHOCK LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Tap_0 Description - Reg Addr --> (0x63), Bit --> 6 */ +#define BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK__POS (6) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK__LEN (1) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK__MSK (0x40) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_SHOCK__REG (BMI160_USER_INTR_TAP_0_ADDR) +/**************************************************************/ +/**\name TAP QUIET LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Tap_0 Description - Reg Addr --> (0x63), Bit --> 7 */ +#define BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET__POS (7) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET__LEN (1) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET__MSK (0x80) +#define BMI160_USER_INTR_TAP_0_INTR_TAP_QUIET__REG (BMI160_USER_INTR_TAP_0_ADDR) +/**************************************************************/ +/**\name TAP THRESHOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Tap_1 Description - Reg Addr --> (0x64), Bit --> 0...4 */ +#define BMI160_USER_INTR_TAP_1_INTR_TAP_THRES__POS (0) +#define BMI160_USER_INTR_TAP_1_INTR_TAP_THRES__LEN (5) +#define BMI160_USER_INTR_TAP_1_INTR_TAP_THRES__MSK (0x1F) +#define BMI160_USER_INTR_TAP_1_INTR_TAP_THRES__REG (BMI160_USER_INTR_TAP_1_ADDR) +/**************************************************************/ +/**\name ORIENT MODE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_0 Description - Reg Addr --> (0x65), Bit --> 0...1 */ +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__POS (0) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__LEN (2) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__MSK (0x03) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_MODE__REG \ + (BMI160_USER_INTR_ORIENT_0_ADDR) +/**************************************************************/ +/**\name ORIENT BLOCKING LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_0 Description - Reg Addr --> (0x65), Bit --> 2...3 */ +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__POS (2) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__LEN (2) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__MSK (0x0C) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_BLOCKING__REG \ + (BMI160_USER_INTR_ORIENT_0_ADDR) +/**************************************************************/ +/**\name ORIENT HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_0 Description - Reg Addr --> (0x65), Bit --> 4...7 */ +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__POS (4) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__LEN (4) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__MSK (0xF0) +#define BMI160_USER_INTR_ORIENT_0_INTR_ORIENT_HYST__REG \ + (BMI160_USER_INTR_ORIENT_0_ADDR) +/**************************************************************/ +/**\name ORIENT THETA LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_1 Description - Reg Addr --> 0x66, Bit --> 0...5 */ +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__POS (0) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__LEN (6) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__MSK (0x3F) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_THETA__REG \ + (BMI160_USER_INTR_ORIENT_1_ADDR) +/**************************************************************/ +/**\name ORIENT UD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_1 Description - Reg Addr --> 0x66, Bit --> 6 */ +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__POS (6) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__LEN (1) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__MSK (0x40) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_UD_ENABLE__REG \ + (BMI160_USER_INTR_ORIENT_1_ADDR) +/**************************************************************/ +/**\name ORIENT AXIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Orient_1 Description - Reg Addr --> 0x66, Bit --> 7 */ +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__POS (7) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__LEN (1) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__MSK (0x80) +#define BMI160_USER_INTR_ORIENT_1_INTR_ORIENT_AXES_EX__REG \ + (BMI160_USER_INTR_ORIENT_1_ADDR) +/**************************************************************/ +/**\name FLAT THETA LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Flat_0 Description - Reg Addr --> 0x67, Bit --> 0...5 */ +#define BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA__POS (0) +#define BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA__LEN (6) +#define BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA__MSK (0x3F) +#define BMI160_USER_INTR_FLAT_0_INTR_FLAT_THETA__REG \ + (BMI160_USER_INTR_FLAT_0_ADDR) +/**************************************************************/ +/**\name FLAT HYSTERESIS LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Flat_1 Description - Reg Addr --> (0x68), Bit --> 0...3 */ +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST__POS (0) +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST__LEN (4) +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST__MSK (0x0F) +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HYST__REG \ +(BMI160_USER_INTR_FLAT_1_ADDR) +/**************************************************************/ +/**\name FLAT HOLD LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Int_Flat_1 Description - Reg Addr --> (0x68), Bit --> 4...5 */ +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD__POS (4) +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD__LEN (2) +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD__MSK (0x30) +#define BMI160_USER_INTR_FLAT_1_INTR_FLAT_HOLD__REG \ +(BMI160_USER_INTR_FLAT_1_ADDR) +/**************************************************************/ +/**\name FOC ACCEL XYZ LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 0...1 */ +#define BMI160_USER_FOC_ACCEL_Z__POS (0) +#define BMI160_USER_FOC_ACCEL_Z__LEN (2) +#define BMI160_USER_FOC_ACCEL_Z__MSK (0x03) +#define BMI160_USER_FOC_ACCEL_Z__REG (BMI160_USER_FOC_CONFIG_ADDR) + +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 2...3 */ +#define BMI160_USER_FOC_ACCEL_Y__POS (2) +#define BMI160_USER_FOC_ACCEL_Y__LEN (2) +#define BMI160_USER_FOC_ACCEL_Y__MSK (0x0C) +#define BMI160_USER_FOC_ACCEL_Y__REG (BMI160_USER_FOC_CONFIG_ADDR) + +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 4...5 */ +#define BMI160_USER_FOC_ACCEL_X__POS (4) +#define BMI160_USER_FOC_ACCEL_X__LEN (2) +#define BMI160_USER_FOC_ACCEL_X__MSK (0x30) +#define BMI160_USER_FOC_ACCEL_X__REG (BMI160_USER_FOC_CONFIG_ADDR) +/**************************************************************/ +/**\name FOC GYRO LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Foc_Conf Description - Reg Addr --> (0x69), Bit --> 6 */ +#define BMI160_USER_FOC_GYRO_ENABLE__POS (6) +#define BMI160_USER_FOC_GYRO_ENABLE__LEN (1) +#define BMI160_USER_FOC_GYRO_ENABLE__MSK (0x40) +#define BMI160_USER_FOC_GYRO_ENABLE__REG \ +(BMI160_USER_FOC_CONFIG_ADDR) +/**************************************************************/ +/**\name NVM PROGRAM LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* CONF Description - Reg Addr --> (0x6A), Bit --> 1 */ +#define BMI160_USER_CONFIG_NVM_PROG_ENABLE__POS (1) +#define BMI160_USER_CONFIG_NVM_PROG_ENABLE__LEN (1) +#define BMI160_USER_CONFIG_NVM_PROG_ENABLE__MSK (0x02) +#define BMI160_USER_CONFIG_NVM_PROG_ENABLE__REG \ +(BMI160_USER_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x6B), Bit --> 0 */ + +#define BMI160_USER_IF_CONFIG_SPI3__POS (0) +#define BMI160_USER_IF_CONFIG_SPI3__LEN (1) +#define BMI160_USER_IF_CONFIG_SPI3__MSK (0x01) +#define BMI160_USER_IF_CONFIG_SPI3__REG \ +(BMI160_USER_IF_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x6B), Bit --> 5..4 */ +#define BMI160_USER_IF_CONFIG_IF_MODE__POS (4) +#define BMI160_USER_IF_CONFIG_IF_MODE__LEN (2) +#define BMI160_USER_IF_CONFIG_IF_MODE__MSK (0x30) +#define BMI160_USER_IF_CONFIG_IF_MODE__REG \ +(BMI160_USER_IF_CONFIG_ADDR) +/**************************************************************/ +/**\name GYRO SLEEP CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 0...2 */ +#define BMI160_USER_GYRO_SLEEP_TRIGGER__POS (0) +#define BMI160_USER_GYRO_SLEEP_TRIGGER__LEN (3) +#define BMI160_USER_GYRO_SLEEP_TRIGGER__MSK (0x07) +#define BMI160_USER_GYRO_SLEEP_TRIGGER__REG (BMI160_USER_PMU_TRIGGER_ADDR) + +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 3...4 */ +#define BMI160_USER_GYRO_WAKEUP_TRIGGER__POS (3) +#define BMI160_USER_GYRO_WAKEUP_TRIGGER__LEN (2) +#define BMI160_USER_GYRO_WAKEUP_TRIGGER__MSK (0x18) +#define BMI160_USER_GYRO_WAKEUP_TRIGGER__REG (BMI160_USER_PMU_TRIGGER_ADDR) + +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 5 */ +#define BMI160_USER_GYRO_SLEEP_STATE__POS (5) +#define BMI160_USER_GYRO_SLEEP_STATE__LEN (1) +#define BMI160_USER_GYRO_SLEEP_STATE__MSK (0x20) +#define BMI160_USER_GYRO_SLEEP_STATE__REG (BMI160_USER_PMU_TRIGGER_ADDR) + +/* Pmu_Trigger Description - Reg Addr --> 0x6c, Bit --> 6 */ +#define BMI160_USER_GYRO_WAKEUP_INTR__POS (6) +#define BMI160_USER_GYRO_WAKEUP_INTR__LEN (1) +#define BMI160_USER_GYRO_WAKEUP_INTR__MSK (0x40) +#define BMI160_USER_GYRO_WAKEUP_INTR__REG (BMI160_USER_PMU_TRIGGER_ADDR) +/**************************************************************/ +/**\name ACCEL SELF TEST LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 0...1 */ +#define BMI160_USER_ACCEL_SELFTEST_AXIS__POS (0) +#define BMI160_USER_ACCEL_SELFTEST_AXIS__LEN (2) +#define BMI160_USER_ACCEL_SELFTEST_AXIS__MSK (0x03) +#define BMI160_USER_ACCEL_SELFTEST_AXIS__REG (BMI160_USER_SELF_TEST_ADDR) + +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 2 */ +#define BMI160_USER_ACCEL_SELFTEST_SIGN__POS (2) +#define BMI160_USER_ACCEL_SELFTEST_SIGN__LEN (1) +#define BMI160_USER_ACCEL_SELFTEST_SIGN__MSK (0x04) +#define BMI160_USER_ACCEL_SELFTEST_SIGN__REG (BMI160_USER_SELF_TEST_ADDR) + +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 3 */ +#define BMI160_USER_SELFTEST_AMP__POS (3) +#define BMI160_USER_SELFTEST_AMP__LEN (1) +#define BMI160_USER_SELFTEST_AMP__MSK (0x08) +#define BMI160_USER_SELFTEST_AMP__REG (BMI160_USER_SELF_TEST_ADDR) +/**************************************************************/ +/**\name GYRO SELF TEST LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Self_Test Description - Reg Addr --> 0x6d, Bit --> 4 */ +#define BMI160_USER_GYRO_SELFTEST_START__POS (4) +#define BMI160_USER_GYRO_SELFTEST_START__LEN (1) +#define BMI160_USER_GYRO_SELFTEST_START__MSK (0x10) +#define BMI160_USER_GYRO_SELFTEST_START__REG \ +(BMI160_USER_SELF_TEST_ADDR) +/**************************************************************/ +/**\name NV_CONFIG LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* NV_CONF Description - Reg Addr --> (0x70), Bit --> 0 */ +#define BMI160_USER_NV_CONFIG_SPI_ENABLE__POS (0) +#define BMI160_USER_NV_CONFIG_SPI_ENABLE__LEN (1) +#define BMI160_USER_NV_CONFIG_SPI_ENABLE__MSK (0x01) +#define BMI160_USER_NV_CONFIG_SPI_ENABLE__REG (BMI160_USER_NV_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x70), Bit --> 1 */ +#define BMI160_USER_IF_CONFIG_I2C_WDT_SELECT__POS (1) +#define BMI160_USER_IF_CONFIG_I2C_WDT_SELECT__LEN (1) +#define BMI160_USER_IF_CONFIG_I2C_WDT_SELECT__MSK (0x02) +#define BMI160_USER_IF_CONFIG_I2C_WDT_SELECT__REG \ +(BMI160_USER_NV_CONFIG_ADDR) + +/*IF_CONF Description - Reg Addr --> (0x70), Bit --> 2 */ +#define BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE__POS (2) +#define BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE__LEN (1) +#define BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE__MSK (0x04) +#define BMI160_USER_IF_CONFIG_I2C_WDT_ENABLE__REG \ +(BMI160_USER_NV_CONFIG_ADDR) + +/* NV_CONF Description - Reg Addr --> (0x70), Bit --> 3 */ +#define BMI160_USER_NV_CONFIG_SPARE0__POS (3) +#define BMI160_USER_NV_CONFIG_SPARE0__LEN (1) +#define BMI160_USER_NV_CONFIG_SPARE0__MSK (0x08) +#define BMI160_USER_NV_CONFIG_SPARE0__REG (BMI160_USER_NV_CONFIG_ADDR) + +/* NV_CONF Description - Reg Addr --> (0x70), Bit --> 4...7 */ +#define BMI160_USER_NV_CONFIG_NVM_COUNTER__POS (4) +#define BMI160_USER_NV_CONFIG_NVM_COUNTER__LEN (4) +#define BMI160_USER_NV_CONFIG_NVM_COUNTER__MSK (0xF0) +#define BMI160_USER_NV_CONFIG_NVM_COUNTER__REG (BMI160_USER_NV_CONFIG_ADDR) +/**************************************************************/ +/**\name ACCEL MANUAL OFFSET LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_0 Description - Reg Addr --> (0x71), Bit --> 0...7 */ +#define BMI160_USER_OFFSET_0_ACCEL_OFF_X__POS (0) +#define BMI160_USER_OFFSET_0_ACCEL_OFF_X__LEN (8) +#define BMI160_USER_OFFSET_0_ACCEL_OFF_X__MSK (0xFF) +#define BMI160_USER_OFFSET_0_ACCEL_OFF_X__REG (BMI160_USER_OFFSET_0_ADDR) + +/* Offset_1 Description - Reg Addr --> 0x72, Bit --> 0...7 */ +#define BMI160_USER_OFFSET_1_ACCEL_OFF_Y__POS (0) +#define BMI160_USER_OFFSET_1_ACCEL_OFF_Y__LEN (8) +#define BMI160_USER_OFFSET_1_ACCEL_OFF_Y__MSK (0xFF) +#define BMI160_USER_OFFSET_1_ACCEL_OFF_Y__REG (BMI160_USER_OFFSET_1_ADDR) + +/* Offset_2 Description - Reg Addr --> 0x73, Bit --> 0...7 */ +#define BMI160_USER_OFFSET_2_ACCEL_OFF_Z__POS (0) +#define BMI160_USER_OFFSET_2_ACCEL_OFF_Z__LEN (8) +#define BMI160_USER_OFFSET_2_ACCEL_OFF_Z__MSK (0xFF) +#define BMI160_USER_OFFSET_2_ACCEL_OFF_Z__REG (BMI160_USER_OFFSET_2_ADDR) +/**************************************************************/ +/**\name GYRO MANUAL OFFSET LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_3 Description - Reg Addr --> 0x74, Bit --> 0...7 */ +#define BMI160_USER_OFFSET_3_GYRO_OFF_X__POS (0) +#define BMI160_USER_OFFSET_3_GYRO_OFF_X__LEN (8) +#define BMI160_USER_OFFSET_3_GYRO_OFF_X__MSK (0xFF) +#define BMI160_USER_OFFSET_3_GYRO_OFF_X__REG (BMI160_USER_OFFSET_3_ADDR) + +/* Offset_4 Description - Reg Addr --> 0x75, Bit --> 0...7 */ +#define BMI160_USER_OFFSET_4_GYRO_OFF_Y__POS (0) +#define BMI160_USER_OFFSET_4_GYRO_OFF_Y__LEN (8) +#define BMI160_USER_OFFSET_4_GYRO_OFF_Y__MSK (0xFF) +#define BMI160_USER_OFFSET_4_GYRO_OFF_Y__REG (BMI160_USER_OFFSET_4_ADDR) + +/* Offset_5 Description - Reg Addr --> 0x76, Bit --> 0...7 */ +#define BMI160_USER_OFFSET_5_GYRO_OFF_Z__POS (0) +#define BMI160_USER_OFFSET_5_GYRO_OFF_Z__LEN (8) +#define BMI160_USER_OFFSET_5_GYRO_OFF_Z__MSK (0xFF) +#define BMI160_USER_OFFSET_5_GYRO_OFF_Z__REG (BMI160_USER_OFFSET_5_ADDR) + + +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 0..1 */ +#define BMI160_USER_OFFSET_6_GYRO_OFF_X__POS (0) +#define BMI160_USER_OFFSET_6_GYRO_OFF_X__LEN (2) +#define BMI160_USER_OFFSET_6_GYRO_OFF_X__MSK (0x03) +#define BMI160_USER_OFFSET_6_GYRO_OFF_X__REG (BMI160_USER_OFFSET_6_ADDR) + +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 2...3 */ +#define BMI160_USER_OFFSET_6_GYRO_OFF_Y__POS (2) +#define BMI160_USER_OFFSET_6_GYRO_OFF_Y__LEN (2) +#define BMI160_USER_OFFSET_6_GYRO_OFF_Y__MSK (0x0C) +#define BMI160_USER_OFFSET_6_GYRO_OFF_Y__REG (BMI160_USER_OFFSET_6_ADDR) + +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 4...5 */ +#define BMI160_USER_OFFSET_6_GYRO_OFF_Z__POS (4) +#define BMI160_USER_OFFSET_6_GYRO_OFF_Z__LEN (2) +#define BMI160_USER_OFFSET_6_GYRO_OFF_Z__MSK (0x30) +#define BMI160_USER_OFFSET_6_GYRO_OFF_Z__REG (BMI160_USER_OFFSET_6_ADDR) +/**************************************************************/ +/**\name ACCEL OFFSET ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 6 */ +#define BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE__POS (6) +#define BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE__LEN (1) +#define BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE__MSK (0x40) +#define BMI160_USER_OFFSET_6_ACCEL_OFF_ENABLE__REG \ +(BMI160_USER_OFFSET_6_ADDR) +/**************************************************************/ +/**\name GYRO OFFSET ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Offset_6 Description - Reg Addr --> 0x77, Bit --> 7 */ +#define BMI160_USER_OFFSET_6_GYRO_OFF_EN__POS (7) +#define BMI160_USER_OFFSET_6_GYRO_OFF_EN__LEN (1) +#define BMI160_USER_OFFSET_6_GYRO_OFF_EN__MSK (0x80) +#define BMI160_USER_OFFSET_6_GYRO_OFF_EN__REG (BMI160_USER_OFFSET_6_ADDR) +/**************************************************************/ +/**\name STEP COUNTER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* STEP_CNT_0 Description - Reg Addr --> 0x78, Bit --> 0 to 7 */ +#define BMI160_USER_STEP_COUNT_LSB__POS (0) +#define BMI160_USER_STEP_COUNT_LSB__LEN (7) +#define BMI160_USER_STEP_COUNT_LSB__MSK (0xFF) +#define BMI160_USER_STEP_COUNT_LSB__REG (BMI160_USER_STEP_COUNT_0_ADDR) + +/* STEP_CNT_1 Description - Reg Addr --> 0x79, Bit --> 0 to 7 */ +#define BMI160_USER_STEP_COUNT_MSB__POS (0) +#define BMI160_USER_STEP_COUNT_MSB__LEN (7) +#define BMI160_USER_STEP_COUNT_MSB__MSK (0xFF) +#define BMI160_USER_STEP_COUNT_MSB__REG (BMI160_USER_STEP_COUNT_1_ADDR) +/**************************************************************/ +/**\name STEP COUNTER CONFIGURATION LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* STEP_CONFIG_0 Description - Reg Addr --> 0x7A, Bit --> 0 to 7 */ +#define BMI160_USER_STEP_CONFIG_ZERO__POS (0) +#define BMI160_USER_STEP_CONFIG_ZERO__LEN (7) +#define BMI160_USER_STEP_CONFIG_ZERO__MSK (0xFF) +#define BMI160_USER_STEP_CONFIG_ZERO__REG \ +(BMI160_USER_STEP_CONFIG_0_ADDR) + + +/* STEP_CONFIG_1 Description - Reg Addr --> 0x7B, Bit --> 0 to 2 and +4 to 7 */ +#define BMI160_USER_STEP_CONFIG_ONE_CNF1__POS (0) +#define BMI160_USER_STEP_CONFIG_ONE_CNF1__LEN (3) +#define BMI160_USER_STEP_CONFIG_ONE_CNF1__MSK (0x07) +#define BMI160_USER_STEP_CONFIG_ONE_CNF1__REG \ +(BMI160_USER_STEP_CONFIG_1_ADDR) + +#define BMI160_USER_STEP_CONFIG_ONE_CNF2__POS (4) +#define BMI160_USER_STEP_CONFIG_ONE_CNF2__LEN (4) +#define BMI160_USER_STEP_CONFIG_ONE_CNF2__MSK (0xF0) +#define BMI160_USER_STEP_CONFIG_ONE_CNF2__REG \ +(BMI160_USER_STEP_CONFIG_1_ADDR) +/**************************************************************/ +/**\name STEP COUNTER ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* STEP_CONFIG_1 Description - Reg Addr --> 0x7B, Bit --> 0 to 2 */ +#define BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__POS (3) +#define BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__LEN (1) +#define BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__MSK (0x08) +#define BMI160_USER_STEP_CONFIG_1_STEP_COUNT_ENABLE__REG \ +(BMI160_USER_STEP_CONFIG_1_ADDR) + +/* USER REGISTERS DEFINITION END */ +/**************************************************************************/ +/* CMD REGISTERS DEFINITION START */ +/**************************************************************/ +/**\name COMMAND REGISTER LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Command description address - Reg Addr --> 0x7E, Bit --> 0....7 */ +#define BMI160_CMD_COMMANDS__POS (0) +#define BMI160_CMD_COMMANDS__LEN (8) +#define BMI160_CMD_COMMANDS__MSK (0xFF) +#define BMI160_CMD_COMMANDS__REG (BMI160_CMD_COMMANDS_ADDR) +/**************************************************************/ +/**\name PAGE ENABLE LENGTH, POSITION AND MASK*/ +/**************************************************************/ +/* Target page address - Reg Addr --> 0x7F, Bit --> 4....5 */ +#define BMI160_CMD_TARGET_PAGE__POS (4) +#define BMI160_CMD_TARGET_PAGE__LEN (2) +#define BMI160_CMD_TARGET_PAGE__MSK (0x30) +#define BMI160_CMD_TARGET_PAGE__REG (BMI160_CMD_EXT_MODE_ADDR) + +/* Target page address - Reg Addr --> 0x7F, Bit --> 4....5 */ +#define BMI160_CMD_PAGING_EN__POS (7) +#define BMI160_CMD_PAGING_EN__LEN (1) +#define BMI160_CMD_PAGING_EN__MSK (0x80) +#define BMI160_CMD_PAGING_EN__REG (BMI160_CMD_EXT_MODE_ADDR) + +/* Target page address - Reg Addr --> 0x7F, Bit --> 4....5 */ +#define BMI160_COM_C_TRIM_FIVE__POS (0) +#define BMI160_COM_C_TRIM_FIVE__LEN (8) +#define BMI160_COM_C_TRIM_FIVE__MSK (0xFF) +#define BMI160_COM_C_TRIM_FIVE__REG (BMI160_COM_C_TRIM_FIVE_ADDR) + +/**************************************************************************/ +/* CMD REGISTERS DEFINITION END */ + +/**************************************************/ +/**\name FIFO FRAME COUNT DEFINITION */ +/*************************************************/ +#define FIFO_FRAME (1024) +#define FIFO_CONFIG_CHECK1 (0x00) +#define FIFO_CONFIG_CHECK2 (0x80) +/**************************************************/ +/**\name MAG SENSOR SELECT */ +/*************************************************/ +#define BST_BMM (0) +#define BST_AKM (1) +#define BMI160_YAS537_I2C_ADDRESS (0x2E) +/**************************************************/ +/**\name ACCEL RANGE */ +/*************************************************/ +#define BMI160_ACCEL_RANGE_2G (0X03) +#define BMI160_ACCEL_RANGE_4G (0X05) +#define BMI160_ACCEL_RANGE_8G (0X08) +#define BMI160_ACCEL_RANGE_16G (0X0C) +/**************************************************/ +/**\name ACCEL ODR */ +/*************************************************/ +#define BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED (0x00) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_0_78HZ (0x01) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_1_56HZ (0x02) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_3_12HZ (0x03) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_6_25HZ (0x04) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_12_5HZ (0x05) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_25HZ (0x06) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_50HZ (0x07) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_100HZ (0x08) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_200HZ (0x09) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_400HZ (0x0A) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_800HZ (0x0B) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_1600HZ (0x0C) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED0 (0x0D) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED1 (0x0E) +#define BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED2 (0x0F) +/**************************************************/ +/**\name ACCEL BANDWIDTH PARAMETER */ +/*************************************************/ +#define BMI160_ACCEL_OSR4_AVG1 (0x00) +#define BMI160_ACCEL_OSR2_AVG2 (0x01) +#define BMI160_ACCEL_NORMAL_AVG4 (0x02) +#define BMI160_ACCEL_CIC_AVG8 (0x03) +#define BMI160_ACCEL_RES_AVG16 (0x04) +#define BMI160_ACCEL_RES_AVG32 (0x05) +#define BMI160_ACCEL_RES_AVG64 (0x06) +#define BMI160_ACCEL_RES_AVG128 (0x07) +/**************************************************/ +/**\name GYRO ODR */ +/*************************************************/ +#define BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED (0x00) +#define BMI160_GYRO_OUTPUT_DATA_RATE_25HZ (0x06) +#define BMI160_GYRO_OUTPUT_DATA_RATE_50HZ (0x07) +#define BMI160_GYRO_OUTPUT_DATA_RATE_100HZ (0x08) +#define BMI160_GYRO_OUTPUT_DATA_RATE_200HZ (0x09) +#define BMI160_GYRO_OUTPUT_DATA_RATE_400HZ (0x0A) +#define BMI160_GYRO_OUTPUT_DATA_RATE_800HZ (0x0B) +#define BMI160_GYRO_OUTPUT_DATA_RATE_1600HZ (0x0C) +#define BMI160_GYRO_OUTPUT_DATA_RATE_3200HZ (0x0D) +/**************************************************/ +/**\name GYRO BANDWIDTH PARAMETER */ +/*************************************************/ +#define BMI160_GYRO_OSR4_MODE (0x00) +#define BMI160_GYRO_OSR2_MODE (0x01) +#define BMI160_GYRO_NORMAL_MODE (0x02) +#define BMI160_GYRO_CIC_MODE (0x03) +/**************************************************/ +/**\name GYROSCOPE RANGE PARAMETER */ +/*************************************************/ +#define BMI160_GYRO_RANGE_2000_DEG_SEC (0x00) +#define BMI160_GYRO_RANGE_1000_DEG_SEC (0x01) +#define BMI160_GYRO_RANGE_500_DEG_SEC (0x02) +#define BMI160_GYRO_RANGE_250_DEG_SEC (0x03) +#define BMI160_GYRO_RANGE_125_DEG_SEC (0x04) +/**************************************************/ +/**\name MAG ODR */ +/*************************************************/ +#define BMI160_MAG_OUTPUT_DATA_RATE_RESERVED (0x00) +#define BMI160_MAG_OUTPUT_DATA_RATE_0_78HZ (0x01) +#define BMI160_MAG_OUTPUT_DATA_RATE_1_56HZ (0x02) +#define BMI160_MAG_OUTPUT_DATA_RATE_3_12HZ (0x03) +#define BMI160_MAG_OUTPUT_DATA_RATE_6_25HZ (0x04) +#define BMI160_MAG_OUTPUT_DATA_RATE_12_5HZ (0x05) +#define BMI160_MAG_OUTPUT_DATA_RATE_25HZ (0x06) +#define BMI160_MAG_OUTPUT_DATA_RATE_50HZ (0x07) +#define BMI160_MAG_OUTPUT_DATA_RATE_100HZ (0x08) +#define BMI160_MAG_OUTPUT_DATA_RATE_200HZ (0x09) +#define BMI160_MAG_OUTPUT_DATA_RATE_400HZ (0x0A) +#define BMI160_MAG_OUTPUT_DATA_RATE_800HZ (0x0B) +#define BMI160_MAG_OUTPUT_DATA_RATE_1600HZ (0x0C) +#define BMI160_MAG_OUTPUT_DATA_RATE_RESERVED0 (0x0D) +#define BMI160_MAG_OUTPUT_DATA_RATE_RESERVED1 (0x0E) +#define BMI160_MAG_OUTPUT_DATA_RATE_RESERVED2 (0x0F) + +/**************************************************/ +/**\name ENABLE/DISABLE SELECTIONS */ +/*************************************************/ + +/* Enable accel and gyro offset */ +#define ACCEL_OFFSET_ENABLE (0x01) +#define GYRO_OFFSET_ENABLE (0x01) + +/* command register definition */ +#define START_FOC_ACCEL_GYRO (0X03) + + /* INT ENABLE 1 */ +#define BMI160_ANY_MOTION_X_ENABLE (0) +#define BMI160_ANY_MOTION_Y_ENABLE (1) +#define BMI160_ANY_MOTION_Z_ENABLE (2) +#define BMI160_DOUBLE_TAP_ENABLE (4) +#define BMI160_SINGLE_TAP_ENABLE (5) +#define BMI160_ORIENT_ENABLE (6) +#define BMI160_FLAT_ENABLE (7) + +/* INT ENABLE 1 */ +#define BMI160_HIGH_G_X_ENABLE (0) +#define BMI160_HIGH_G_Y_ENABLE (1) +#define BMI160_HIGH_G_Z_ENABLE (2) +#define BMI160_LOW_G_ENABLE (3) +#define BMI160_DATA_RDY_ENABLE (4) +#define BMI160_FIFO_FULL_ENABLE (5) +#define BMI160_FIFO_WM_ENABLE (6) + +/* INT ENABLE 2 */ +#define BMI160_NOMOTION_X_ENABLE (0) +#define BMI160_NOMOTION_Y_ENABLE (1) +#define BMI160_NOMOTION_Z_ENABLE (2) +#define BMI160_STEP_DETECTOR_EN (3) + +/* FOC axis selection for accel*/ +#define FOC_X_AXIS (0) +#define FOC_Y_AXIS (1) +#define FOC_Z_AXIS (2) + +/* IN OUT CONTROL */ +#define BMI160_INTR1_EDGE_CTRL (0) +#define BMI160_INTR2_EDGE_CTRL (1) +#define BMI160_INTR1_LEVEL (0) +#define BMI160_INTR2_LEVEL (1) +#define BMI160_INTR1_OUTPUT_TYPE (0) +#define BMI160_INTR2_OUTPUT_TYPE (1) +#define BMI160_INTR1_OUTPUT_ENABLE (0) +#define BMI160_INTR2_OUTPUT_ENABLE (1) + +#define BMI160_INTR1_INPUT_ENABLE (0) +#define BMI160_INTR2_INPUT_ENABLE (1) + +/* INTERRUPT MAPS */ +#define BMI160_INTR1_MAP_LOW_G (0) +#define BMI160_INTR2_MAP_LOW_G (1) +#define BMI160_INTR1_MAP_HIGH_G (0) +#define BMI160_INTR2_MAP_HIGH_G (1) +#define BMI160_INTR1_MAP_ANY_MOTION (0) +#define BMI160_INTR2_MAP_ANY_MOTION (1) +#define BMI160_INTR1_MAP_NOMO (0) +#define BMI160_INTR2_MAP_NOMO (1) +#define BMI160_INTR1_MAP_DOUBLE_TAP (0) +#define BMI160_INTR2_MAP_DOUBLE_TAP (1) +#define BMI160_INTR1_MAP_SINGLE_TAP (0) +#define BMI160_INTR2_MAP_SINGLE_TAP (1) +#define BMI160_INTR1_MAP_ORIENT (0) +#define BMI160_INTR2_MAP_ORIENT (1) +#define BMI160_INTR1_MAP_FLAT (0) +#define BMI160_INTR2_MAP_FLAT (1) +#define BMI160_INTR1_MAP_DATA_RDY (0) +#define BMI160_INTR2_MAP_DATA_RDY (1) +#define BMI160_INTR1_MAP_FIFO_WM (0) +#define BMI160_INTR2_MAP_FIFO_WM (1) +#define BMI160_INTR1_MAP_FIFO_FULL (0) +#define BMI160_INTR2_MAP_FIFO_FULL (1) +#define BMI160_INTR1_MAP_PMUTRIG (0) +#define BMI160_INTR2_MAP_PMUTRIG (1) + +/* Interrupt mapping*/ +#define BMI160_MAP_INTR1 (0) +#define BMI160_MAP_INTR2 (1) +/**************************************************/ +/**\name TAP DURATION */ +/*************************************************/ +#define BMI160_TAP_DURN_50MS (0x00) +#define BMI160_TAP_DURN_100MS (0x01) +#define BMI160_TAP_DURN_150MS (0x02) +#define BMI160_TAP_DURN_200MS (0x03) +#define BMI160_TAP_DURN_250MS (0x04) +#define BMI160_TAP_DURN_375MS (0x05) +#define BMI160_TAP_DURN_500MS (0x06) +#define BMI160_TAP_DURN_700MS (0x07) +/**************************************************/ +/**\name TAP SHOCK */ +/*************************************************/ +#define BMI160_TAP_SHOCK_50MS (0x00) +#define BMI160_TAP_SHOCK_75MS (0x01) +/**************************************************/ +/**\name TAP QUIET */ +/*************************************************/ +#define BMI160_TAP_QUIET_30MS (0x00) +#define BMI160_TAP_QUIET_20MS (0x01) +/**************************************************/ +/**\name STEP DETECTION SELECTION MODES */ +/*************************************************/ +#define BMI160_STEP_NORMAL_MODE (0) +#define BMI160_STEP_SENSITIVE_MODE (1) +#define BMI160_STEP_ROBUST_MODE (2) +/**************************************************/ +/**\name STEP CONFIGURATION SELECT MODE */ +/*************************************************/ +#define STEP_CONFIG_NORMAL (0X315) +#define STEP_CONFIG_SENSITIVE (0X2D) +#define STEP_CONFIG_ROBUST (0X71D) +/**************************************************/ +/**\name BMM150 TRIM DATA DEFINITIONS */ +/*************************************************/ +#define BMI160_MAG_DIG_X1 (0x5D) +#define BMI160_MAG_DIG_Y1 (0x5E) +#define BMI160_MAG_DIG_Z4_LSB (0x62) +#define BMI160_MAG_DIG_Z4_MSB (0x63) +#define BMI160_MAG_DIG_X2 (0x64) +#define BMI160_MAG_DIG_Y2 (0x65) +#define BMI160_MAG_DIG_Z2_LSB (0x68) +#define BMI160_MAG_DIG_Z2_MSB (0x69) +#define BMI160_MAG_DIG_Z1_LSB (0x6A) +#define BMI160_MAG_DIG_Z1_MSB (0x6B) +#define BMI160_MAG_DIG_XYZ1_LSB (0x6C) +#define BMI160_MAG_DIG_XYZ1_MSB (0x6D) +#define BMI160_MAG_DIG_Z3_LSB (0x6E) +#define BMI160_MAG_DIG_Z3_MSB (0x6F) +#define BMI160_MAG_DIG_XY2 (0x70) +#define BMI160_MAG_DIG_XY1 (0x71) +/**************************************************/ +/**\name BMM150 PRE-SET MODE DEFINITIONS */ +/*************************************************/ +#define BMI160_MAG_PRESETMODE_LOWPOWER (1) +#define BMI160_MAG_PRESETMODE_REGULAR (2) +#define BMI160_MAG_PRESETMODE_HIGHACCURACY (3) +#define BMI160_MAG_PRESETMODE_ENHANCED (4) +/**************************************************/ +/**\name BMM150 PRESET MODES - DATA RATES */ +/*************************************************/ +#define BMI160_MAG_LOWPOWER_DR (0x02) +#define BMI160_MAG_REGULAR_DR (0x02) +#define BMI160_MAG_HIGHACCURACY_DR (0x2A) +#define BMI160_MAG_ENHANCED_DR (0x02) +/**************************************************/ +/**\name BMM150 PRESET MODES - REPETITIONS-XY RATES */ +/*************************************************/ +#define BMI160_MAG_LOWPOWER_REPXY (1) +#define BMI160_MAG_REGULAR_REPXY (4) +#define BMI160_MAG_HIGHACCURACY_REPXY (23) +#define BMI160_MAG_ENHANCED_REPXY (7) +/**************************************************/ +/**\name BMM150 PRESET MODES - REPETITIONS-Z RATES */ +/*************************************************/ +#define BMI160_MAG_LOWPOWER_REPZ (2) +#define BMI160_MAG_REGULAR_REPZ (14) +#define BMI160_MAG_HIGHACCURACY_REPZ (82) +#define BMI160_MAG_ENHANCED_REPZ (26) +#define BMI160_MAG_NOAMRL_SWITCH_TIMES (5) +#define MAG_INTERFACE_PMU_ENABLE (1) +#define MAG_INTERFACE_PMU_DISABLE (0) +/**************************************************/ +/**\name USED FOR MAG OVERFLOW CHECK FOR BMM150 */ +/*************************************************/ +#define BMI160_MAG_OVERFLOW_OUTPUT ((s16)-32768) +#define BMI160_MAG_OVERFLOW_OUTPUT_S32 ((s32)(-2147483647-1)) +#define BMI160_MAG_NEGATIVE_SATURATION_Z ((s16)-32767) +#define BMI160_MAG_POSITIVE_SATURATION_Z ((u16)32767) +#define BMI160_MAG_FLIP_OVERFLOW_ADCVAL ((s16)-4096) +#define BMI160_MAG_HALL_OVERFLOW_ADCVAL ((s16)-16384) +/**************************************************/ +/**\name BMM150 REGISTER DEFINITION */ +/*************************************************/ +#define BMI160_BMM150_CHIP_ID (0x40) +#define BMI160_BMM150_POWE_CONTROL_REG (0x4B) +#define BMI160_BMM150_POWE_MODE_REG (0x4C) +#define BMI160_BMM150_DATA_REG (0x42) +#define BMI160_BMM150_XY_REP (0x51) +#define BMI160_BMM150_Z_REP (0x52) +/**************************************************/ +/**\name AKM COMPENSATING DATA REGISTERS */ +/*************************************************/ +#define BMI160_BST_AKM_ASAX (0x60) +#define BMI160_BST_AKM_ASAY (0x61) +#define BMI160_BST_AKM_ASAZ (0x62) +/**************************************************/ +/**\name AKM POWER MODE SELECTION */ +/*************************************************/ +#define AKM_POWER_DOWN_MODE (0) +#define AKM_SINGLE_MEAS_MODE (1) +#define FUSE_ROM_MODE (2) +/**************************************************/ +/**\name SECONDARY_MAG POWER MODE SELECTION */ +/*************************************************/ +#define BMI160_MAG_FORCE_MODE (0) +#define BMI160_MAG_SUSPEND_MODE (1) +/**************************************************/ +/**\name MAG POWER MODE SELECTION */ +/*************************************************/ +#define FORCE_MODE (0) +#define SUSPEND_MODE (1) +#define NORMAL_MODE (2) +#define MAG_SUSPEND_MODE (1) +/**************************************************/ +/**\name FIFO CONFIGURATIONS */ +/*************************************************/ +#define FIFO_HEADER_ENABLE (0x01) +#define FIFO_MAG_ENABLE (0x01) +#define FIFO_ACCEL_ENABLE (0x01) +#define FIFO_GYRO_ENABLE (0x01) +#define FIFO_TIME_ENABLE (0x01) +#define FIFO_STOPONFULL_ENABLE (0x01) +#define FIFO_WM_INTERRUPT_ENABLE (0x01) +#define BMI160_FIFO_INDEX_LENGTH (1) +#define BMI160_FIFO_TAG_INTR_MASK (0xFC) + +/**************************************************/ +/**\name ACCEL POWER MODE */ +/*************************************************/ +#define ACCEL_MODE_NORMAL (0x11) +#define ACCEL_LOWPOWER (0X12) +#define ACCEL_SUSPEND (0X10) +/**************************************************/ +/**\name GYRO POWER MODE */ +/*************************************************/ +#define GYRO_MODE_SUSPEND (0x14) +#define GYRO_MODE_NORMAL (0x15) +#define GYRO_MODE_FASTSTARTUP (0x17) +/**************************************************/ +/**\name MAG POWER MODE */ +/*************************************************/ +#define MAG_MODE_SUSPEND (0x18) +#define MAG_MODE_NORMAL (0x19) +#define MAG_MODE_LOWPOWER (0x1A) +/**************************************************/ +/**\name ENABLE/DISABLE BIT VALUES */ +/*************************************************/ +#define BMI160_ENABLE (0x01) +#define BMI160_DISABLE (0x00) +/**************************************************/ +/**\name INTERRUPT EDGE TRIGGER ENABLE */ +/*************************************************/ +#define BMI160_EDGE (0x01) +#define BMI160_LEVEL (0x00) +/**************************************************/ +/**\name INTERRUPT LEVEL ENABLE */ +/*************************************************/ +#define BMI160_LEVEL_LOW (0x00) +#define BMI160_LEVEL_HIGH (0x01) +/**************************************************/ +/**\name INTERRUPT OUTPUT ENABLE */ +/*************************************************/ +#define BMI160_OPEN_DRAIN (0x01) +#define BMI160_PUSH_PULL (0x00) + +/* interrupt output enable*/ +#define BMI160_INPUT (0x01) +#define BMI160_OUTPUT (0x00) + +/**************************************************/ +/**\name INTERRUPT TAP SOURCE ENABLE */ +/*************************************************/ +#define FILTER_DATA (0x00) +#define UNFILTER_DATA (0x01) +/**************************************************/ +/**\name SLOW MOTION/ NO MOTION SELECT */ +/*************************************************/ +#define SLOW_MOTION (0x00) +#define NO_MOTION (0x01) +/**************************************************/ +/**\name SIGNIFICANT MOTION SELECTION */ +/*************************************************/ +#define ANY_MOTION (0x00) +#define SIGNIFICANT_MOTION (0x01) +/**************************************************/ +/**\name LATCH DURATION */ +/*************************************************/ +#define BMI160_LATCH_DUR_NONE (0x00) +#define BMI160_LATCH_DUR_312_5_MICRO_SEC (0x01) +#define BMI160_LATCH_DUR_625_MICRO_SEC (0x02) +#define BMI160_LATCH_DUR_1_25_MILLI_SEC (0x03) +#define BMI160_LATCH_DUR_2_5_MILLI_SEC (0x04) +#define BMI160_LATCH_DUR_5_MILLI_SEC (0x05) +#define BMI160_LATCH_DUR_10_MILLI_SEC (0x06) +#define BMI160_LATCH_DUR_20_MILLI_SEC (0x07) +#define BMI160_LATCH_DUR_40_MILLI_SEC (0x08) +#define BMI160_LATCH_DUR_80_MILLI_SEC (0x09) +#define BMI160_LATCH_DUR_160_MILLI_SEC (0x0A) +#define BMI160_LATCH_DUR_320_MILLI_SEC (0x0B) +#define BMI160_LATCH_DUR_640_MILLI_SEC (0x0C) +#define BMI160_LATCH_DUR_1_28_SEC (0x0D) +#define BMI160_LATCH_DUR_2_56_SEC (0x0E) +#define BMI160_LATCHED (0x0F) +/**************************************************/ +/**\name GYRO OFFSET MASK DEFINITION */ +/*************************************************/ +#define BMI160_GYRO_MANUAL_OFFSET_0_7 (0x00FF) +#define BMI160_GYRO_MANUAL_OFFSET_8_9 (0x0300) +/**************************************************/ +/**\name STEP CONFIGURATION MASK DEFINITION */ +/*************************************************/ +#define BMI160_STEP_CONFIG_0_7 (0x00FF) +#define BMI160_STEP_CONFIG_8_10 (0x0700) +#define BMI160_STEP_CONFIG_11_14 (0xF000) +/**************************************************/ +/**\name DEFINITION USED FOR DIFFERENT WRITE */ +/*************************************************/ +#define BMI160_WRITE_TARGET_PAGE0 (0x00) +#define BMI160_WRITE_TARGET_PAGE1 (0x01) +#define BMI160_WRITE_ENABLE_PAGE1 (0x01) +#define BMI160_MANUAL_DISABLE (0x00) +#define BMI160_MANUAL_ENABLE (0x01) +#define BMI160_YAS_DISABLE_RCOIL (0x00) +#define BMI160_ENABLE_MAG_IF_MODE (0x02) +#define BMI160_ENABLE_ANY_MOTION_INTR1 (0x04) +#define BMI160_ENABLE_ANY_MOTION_INTR2 (0x04) +#define BMI160_MAG_DATA_READ_REG (0x04) +#define BMI160_BMM_POWER_MODE_REG (0x06) +#define BMI160_ENABLE_ANY_MOTION_AXIS (0x07) +#define BMI160_ENABLE_LOW_G (0x08) +#define BMI160_YAS532_ACQ_START (0x11) +#define BMI160_YAS_DEVICE_ID_REG (0x80) +#define BMI160_FIFO_GYRO_ENABLE (0x80) +#define BMI160_SIG_MOTION_INTR_ENABLE (0x01) +#define BMI160_STEP_DETECT_INTR_ENABLE (0x01) +#define BMI160_LOW_G_INTR_STAT (0x01) +#define BMI160_PULL_UP_DATA (0x30) +#define BMI160_FIFO_M_G_A_ENABLE (0xE0) +#define BMI160_FIFO_M_G_ENABLE (0xA0) +#define BMI160_FIFO_M_A_ENABLE (0x60) +#define BMI160_FIFO_G_A_ENABLE (0xC0) +#define BMI160_FIFO_A_ENABLE (0x40) +#define BMI160_FIFO_M_ENABLE (0x20) +/**************************************************/ +/**\name MAG INIT DEFINITION */ +/*************************************************/ +#define BMI160_COMMAND_REG_ONE (0x37) +#define BMI160_COMMAND_REG_TWO (0x9A) +#define BMI160_COMMAND_REG_THREE (0xC0) +#define RESET_STEP_COUNTER (0xB2) +/**************************************************/ +/**\name BIT SLICE GET AND SET FUNCTIONS */ +/*************************************************/ +#define BMI160_GET_BITSLICE(regvar, bitname)\ + ((regvar & bitname##__MSK) >> bitname##__POS) + + +#define BMI160_SET_BITSLICE(regvar, bitname, val)\ + ((regvar & ~bitname##__MSK) | \ + ((val< Success + * @retval -1 -> Error + * + * @note + * While changing the parameter of the bmi160_t + * consider the following point: + * Changing the reference value of the parameter + * will changes the local copy or local reference + * make sure your changes will not + * affect the reference value of the parameter + * (Better case don't change the reference value of the parameter) + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_init(struct bmi160_t *bmi160); +/**************************************************/ +/**\name FUNCTION FOR READ AND WRITE REGISTERS */ +/*************************************************/ +/*! + * @brief + * This API write the data to + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_write_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8); +/*! + * @brief + * This API reads the data from + * the given register + * + * + * @param v_addr_u8 -> Address of the register + * @param v_data_u8 -> The data from the register + * @param v_len_u8 -> no of bytes to read + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_reg(u8 v_addr_u8, +u8 *v_data_u8, u8 v_len_u8); +/**************************************************/ +/**\name FUNCTION FOR ERROR CODES */ +/*************************************************/ +/*! + * @brief This API used to reads the fatal error + * from the Register 0x02 bit 0 + * This flag will be reset only by power-on-reset and soft reset + * + * + * @param v_fatal_err_u8 : The status of fatal error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fatal_err(u8 +*v_fatal_err_u8); +/*! + * @brief This API used to read the error code + * from register 0x02 bit 1 to 4 + * + * + * @param v_err_code_u8 : The status of error codes + * error_code | description + * ------------|--------------- + * 0x00 |no error + * 0x01 |ACC_CONF error (accel ODR and bandwidth not compatible) + * 0x02 |GYR_CONF error (Gyroscope ODR and bandwidth not compatible) + * 0x03 |Under sampling mode and interrupt uses pre filtered data + * 0x04 |reserved + * 0x05 |Selected trigger-readout offset in + * - |MAG_IF greater than selected ODR + * 0x06 |FIFO configuration error for header less mode + * 0x07 |Under sampling mode and pre filtered data as FIFO source + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_err_code(u8 +*v_error_code_u8); +/*! + * @brief This API Reads the i2c error code from the + * Register 0x02 bit 5. + * This error occurred in I2C master detected + * + * @param v_i2c_err_code_u8 : The status of i2c fail error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_fail_err(u8 +*v_i2c_error_code_u8); + /*! + * @brief This API Reads the dropped command error + * from the register 0x02 bit 6 + * + * + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_drop_cmd_err(u8 +*v_drop_cmd_err_u8); +/*! + * @brief This API reads the magnetometer data ready + * interrupt not active. + * It reads from the error register 0x0x2 bit 7 + * + * + * + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_dada_rdy_err(u8 +*v_mag_data_rdy_err_u8); +/*! + * @brief This API reads the error status + * from the error register 0x02 bit 0 to 7 + * + * @param v_mag_data_rdy_err_u8 : The status of mag data ready interrupt + * @param v_fatal_er_u8r : The status of fatal error + * @param v_err_code_u8 : The status of error code + * @param v_i2c_fail_err_u8 : The status of I2C fail error + * @param v_drop_cmd_err_u8 : The status of drop command error + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_error_status(u8 *v_fatal_er_u8r, +u8 *v_err_code_u8, u8 *v_i2c_fail_err_u8, +u8 *v_drop_cmd_err_u8, u8 *v_mag_data_rdy_err_u8); +/******************************************************************/ +/**\name FUNCTIONS FOR MAG,ACCEL AND GYRO POWER MODE STATUS */ +/*****************************************************************/ +/*! + * @brief This API reads the magnetometer power mode from + * PMU status register 0x03 bit 0 and 1 + * + * @param v_mag_power_mode_stat_u8 : The value of mag power mode + * mag_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x02 + * + * + * @note The power mode of mag set by the 0x7E command register + * @note using the function "bmi160_set_command_register()" + * value | mode + * ---------|---------------- + * 0x18 | MAG_MODE_SUSPEND + * 0x19 | MAG_MODE_NORMAL + * 0x1A | MAG_MODE_LOWPOWER + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_power_mode_stat(u8 +*v_mag_power_mode_stat_u8); +/*! + * @brief This API reads the gyroscope power mode from + * PMU status register 0x03 bit 2 and 3 + * + * @param v_gyro_power_mode_stat_u8 : The value of gyro power mode + * gyro_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * FAST POWER UP | 0x03 + * + * @note The power mode of gyro set by the 0x7E command register + * @note using the function "bmi160_set_command_register()" + * value | mode + * ---------|---------------- + * 0x14 | GYRO_MODE_SUSPEND + * 0x15 | GYRO_MODE_NORMAL + * 0x17 | GYRO_MODE_FASTSTARTUP + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_power_mode_stat(u8 +*v_gyro_power_mode_stat_u8); +/*! + * @brief This API reads the accelerometer power mode from + * PMU status register 0x03 bit 4 and 5 + * + * + * @param v_accel_power_mode_stat_u8 : The value of accel power mode + * accel_powermode | value + * ------------------|---------- + * SUSPEND | 0x00 + * NORMAL | 0x01 + * LOW POWER | 0x03 + * + * @note The power mode of accel set by the 0x7E command register + * @note using the function "bmi160_set_command_register()" + * value | mode + * ---------|---------------- + * 0x11 | ACCEL_MODE_NORMAL + * 0x12 | ACCEL_LOWPOWER + * 0x10 | ACCEL_SUSPEND + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_power_mode_stat(u8 +*v_accel_power_mode_stat_u8); +/*! + * @brief This API switch mag interface to normal mode + * and confirm whether the mode switching done successfully or not +* + * @return results of bus communication function and current MAG_PMU result + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_interface_normal(void); +/**************************************************/ +/**\name FUNCTION FOR Mag XYZ data read */ +/*************************************************/ +/*! + * @brief This API reads magnetometer data X values + * from the register 0x04 and 0x05 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_x_s16 : The value of mag x + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_x(s16 *v_mag_x_s16, +u8 v_sensor_select_u8); +/*! + * @brief This API reads magnetometer data Y values + * from the register 0x06 and 0x07 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_y_s16 : The value of mag y + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_y(s16 *v_mag_y_s16, +u8 v_sensor_select_u8); +/*! + * @brief This API reads magnetometer data Z values + * from the register 0x08 and 0x09 + * @brief The mag sensor data read form auxiliary mag + * + * @param v_mag_z_s16 : The value of mag z + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_z(s16 *v_mag_z_s16, +u8 v_sensor_select_u8); +/*! + * @brief This API reads magnetometer data RHALL values + * from the register 0x0A and 0x0B + * + * + * @param v_mag_r_s16 : The value of BMM150 r data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_r( +s16 *v_mag_r_s16); +/*! + * @brief This API reads magnetometer data X,Y,Z values + * from the register 0x04 to 0x09 + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag xyz data + * @param v_sensor_select_u8 : Mag selection value + * value | sensor + * ---------|---------------- + * 0 | BMM150 + * 1 | AKM09911 or AKM09912 + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_xyz( +struct bmi160_mag_t *mag, u8 v_sensor_select_u8); + /*!* + * @brief This API reads magnetometer data X,Y,Z,r + * values from the register 0x04 to 0x0B + * + * @brief The mag sensor data read form auxiliary mag + * + * @param mag : The value of mag-BMM150 xyzr data + * + * @note For mag data output rate configuration use the following function + * @note bmi160_set_mag_output_data_rate() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_mag_xyzr( +struct bmi160_mag_xyzr_t *mag); +/**************************************************/ +/**\name FUNCTION FOR GYRO XYZ DATA READ */ +/*************************************************/ +/*! + * @brief This API reads gyro data X values + * form the register 0x0C and 0x0D + * + * + * + * + * @param v_gyro_x_s16 : The value of gyro x data + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_x( +s16 *v_gyro_x_s16); +/*! + * @brief This API reads gyro data Y values + * form the register 0x0E and 0x0F + * + * + * + * + * @param v_gyro_y_s16 : The value of gyro y data + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error result of communication routines + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_y( +s16 *v_gyro_y_s16); +/*! + * @brief This API reads gyro data Z values + * form the register 0x10 and 0x11 + * + * + * + * + * @param v_gyro_z_s16 : The value of gyro z data + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_z( +s16 *v_gyro_z_s16); +/*! + * @brief This API reads gyro data X,Y,Z values + * from the register 0x0C to 0x11 + * + * + * + * + * @param gyro : The value of gyro xyz + * + * @note Gyro Configuration use the following function + * @note bmi160_set_gyro_output_data_rate() + * @note bmi160_set_gyro_bw() + * @note bmi160_set_gyro_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_gyro_xyz( +struct bmi160_gyro_t *gyro); +/**************************************************/ +/**\name FUNCTION FOR ACCEL XYZ DATA READ */ +/*************************************************/ +/*! + * @brief This API reads accelerometer data X values + * form the register 0x12 and 0x13 + * + * + * + * + * @param v_accel_x_s16 : The value of accel x + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_x( +s16 *v_accel_x_s16); +/*! + * @brief This API reads accelerometer data Y values + * form the register 0x14 and 0x15 + * + * + * + * + * @param v_accel_y_s16 : The value of accel y + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_y( +s16 *v_accel_y_s16); +/*! + * @brief This API reads accelerometer data Z values + * form the register 0x16 and 0x17 + * + * + * + * + * @param v_accel_z_s16 : The value of accel z + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_z( +s16 *v_accel_z_s16); +/*! + * @brief This API reads accelerometer data X,Y,Z values + * from the register 0x12 to 0x17 + * + * + * + * + * @param accel :The value of accel xyz + * + * @note For accel configuration use the following functions + * @note bmi160_set_accel_output_data_rate() + * @note bmi160_set_accel_bw() + * @note bmi160_set_accel_under_sampling_parameter() + * @note bmi160_set_accel_range() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_accel_xyz( +struct bmi160_accel_t *accel); +/**************************************************/ +/**\name FUNCTION FOR SENSOR TIME */ +/*************************************************/ +/*! + * @brief This API reads sensor_time from the register + * 0x18 to 0x1A + * + * + * @param v_sensor_time_u32 : The value of sensor time + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_sensor_time( +u32 *v_sensor_time_u32); +/**************************************************/ +/**\name FUNCTION FOR GYRO SLEF TEST */ +/*************************************************/ +/*! + * @brief This API reads the Gyroscope self test + * status from the register 0x1B bit 1 + * + * + * @param v_gyro_selftest_u8 : The value of gyro self test status + * value | status + * ---------|---------------- + * 0 | Gyroscope self test is running or failed + * 1 | Gyroscope self test completed successfully + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_selftest(u8 +*v_gyro_selftest_u8); +/**************************************************/ +/**\name FUNCTION FOR MANUAL INTERFACE */ +/*************************************************/ +/*! + * @brief This API reads the status of + * mag manual interface operation form the register 0x1B bit 2 + * + * + * + * @param v_mag_manual_stat_u8 : The value of mag manual operation status + * value | status + * ---------|---------------- + * 0 | Indicates no manual magnetometer + * - | interface operation is ongoing + * 1 | Indicates manual magnetometer + * - | interface operation is ongoing + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_manual_operation_stat(u8 +*v_mag_manual_stat_u8); +/**************************************************/ +/**\name FUNCTION FOR FAST OFFSET READY */ +/*************************************************/ +/*! + * @brief This API reads the fast offset compensation + * status form the register 0x1B bit 3 + * + * + * @param v_foc_rdy_u8 : The status of fast compensation + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_rdy(u8 +*v_foc_rdy_u8); +/**************************************************/ +/**\name FUNCTION FOR NVM READY */ +/*************************************************/ +/*! + * @brief This API Reads the nvm_rdy status from the + * resister 0x1B bit 4 + * + * + * @param v_nvm_rdy_u8 : The value of NVM ready status + * value | status + * ---------|---------------- + * 0 | NVM write operation in progress + * 1 | NVM is ready to accept a new write trigger + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_nvm_rdy(u8 +*v_nvm_rdy_u8); +/**************************************************/ +/**\name FUNCTION FOR DATA READY FOR MAG, GYRO, AND ACCEL */ +/*************************************************/ +/*! + * @brief This API reads the status of mag data ready + * from the register 0x1B bit 5 + * The status get reset when one mag data register is read out + * + * @param v_data_rdy_u8 : The value of mag data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_data_rdy_mag(u8 +*v_data_rdy_u8); +/*! + * @brief This API reads the status of gyro data ready form the + * register 0x1B bit 6 + * The status get reset when gyro data register read out + * + * + * @param v_data_rdy_u8 : The value of gyro data ready + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_data_rdy(u8 +*v_data_rdy_u8); +/*! + * @brief This API reads the status of accel data ready form the + * register 0x1B bit 7 + * The status get reset when accel data register read out + * + * + * @param v_data_rdy_u8 : The value of accel data ready status + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_data_rdy(u8 +*drdy_acc); +/**************************************************/ +/**\name FUNCTION FOR STEP INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the step detector interrupt status + * from the register 0x1C bit 0 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_step_intr_u8 : The status of step detector interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_step_intr(u8 +*v_step_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR SIGNIFICANT INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the + * significant motion interrupt status + * from the register 0x1C bit 1 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_significant_intr_u8 : The status of step + * motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_significant_intr(u8 +*sigmot_intr); +/**************************************************/ +/**\name FUNCTION FOR ANY MOTION INTERRUPT STATUS */ +/*************************************************/ + /*! + * @brief This API reads the any motion interrupt status + * from the register 0x1C bit 2 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * @param v_any_motion_intr_u8 : The status of any-motion interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_any_motion_intr(u8 +*v_any_motion_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR PMU TRIGGER INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the power mode trigger interrupt status + * from the register 0x1C bit 3 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * + * @param v_pmu_trigger_intr_u8 : The status of power mode trigger interrupt + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_pmu_trigger_intr(u8 +*v_pmu_trigger_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR DOUBLE TAB STATUS */ +/*************************************************/ +/*! + * @brief This API reads the double tab status + * from the register 0x1C bit 4 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_double_tap_intr_u8 :The status of double tab interrupt + * + * @note Double tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_double_tap() + * @note AXIS MAPPING + * @note bmi160_get_stat2_tap_first_x() + * @note bmi160_get_stat2_tap_first_y() + * @note bmi160_get_stat2_tap_first_z() + * @note DURATION + * @note bmi160_set_intr_tap_durn() + * @note THRESHOLD + * @note bmi160_set_intr_tap_thres() + * @note TAP QUIET + * @note bmi160_set_intr_tap_quiet() + * @note TAP SHOCK + * @note bmi160_set_intr_tap_shock() + * @note TAP SOURCE + * @note bmi160_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_double_tap_intr(u8 +*v_double_tap_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR SINGLE TAB STATUS */ +/*************************************************/ +/*! + * @brief This API reads the single tab status + * from the register 0x1C bit 5 + * flag is associated with a specific interrupt function. + * It is set when the single tab interrupt triggers. The + * setting of INT_LATCH controls if the interrupt + * signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_single_tap_intr_u8 :The status of single tap interrupt + * + * @note Single tap interrupt can be configured by the following functions + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_single_tap() + * @note AXIS MAPPING + * @note bmi160_get_stat2_tap_first_x() + * @note bmi160_get_stat2_tap_first_y() + * @note bmi160_get_stat2_tap_first_z() + * @note DURATION + * @note bmi160_set_intr_tap_durn() + * @note THRESHOLD + * @note bmi160_set_intr_tap_thres() + * @note TAP QUIET + * @note bmi160_set_intr_tap_quiet() + * @note TAP SHOCK + * @note bmi160_set_intr_tap_shock() + * @note TAP SOURCE + * @note bmi160_set_intr_tap_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_single_tap_intr(u8 +*v_single_tap_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR ORIENT INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the orient status + * from the register 0x1C bit 6 + * flag is associated with a specific interrupt function. + * It is set when the orient interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_orient_intr_u8 : The status of orient interrupt + * + * @note For orient interrupt configuration use the following functions + * @note STATUS + * @note bmi160_get_stat0_orient_intr() + * @note AXIS MAPPING + * @note bmi160_get_stat3_orient_xy() + * @note bmi160_get_stat3_orient_z() + * @note bmi160_set_intr_orient_axes_enable() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_orient() + * @note INTERRUPT OUTPUT + * @note bmi160_set_intr_orient_ud_enable() + * @note THETA + * @note bmi160_set_intr_orient_theta() + * @note HYSTERESIS + * @note bmi160_set_intr_orient_hyst() + * @note BLOCKING + * @note bmi160_set_intr_orient_blocking() + * @note MODE + * @note bmi160_set_intr_orient_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_orient_intr(u8 +*v_orient_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR FLAT INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the flat interrupt status + * from the register 0x1C bit 7 + * flag is associated with a specific interrupt function. + * It is set when the flat interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_flat_intr_u8 : The status of flat interrupt + * + * @note For flat configuration use the following functions + * @note STATS + * @note bmi160_get_stat0_flat_intr() + * @note bmi160_get_stat3_flat() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_flat() + * @note THETA + * @note bmi160_set_intr_flat_theta() + * @note HOLD TIME + * @note bmi160_set_intr_flat_hold() + * @note HYSTERESIS + * @note bmi160_set_intr_flat_hyst() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat0_flat_intr(u8 +*v_flat_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR HIGH_G INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the high_g interrupt status + * from the register 0x1D bit 2 + * flag is associated with a specific interrupt function. + * It is set when the high g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_high_g_intr_u8 : The status of high_g interrupt + * + * @note High_g interrupt configured by following functions + * @note STATUS + * @note bmi160_get_stat1_high_g_intr() + * @note AXIS MAPPING + * @note bmi160_get_stat3_high_g_first_x() + * @note bmi160_get_stat3_high_g_first_y() + * @note bmi160_get_stat3_high_g_first_z() + * @note SIGN MAPPING + * @note bmi160_get_stat3_high_g_first_sign() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_high_g() + * @note HYSTERESIS + * @note bmi160_set_intr_high_g_hyst() + * @note DURATION + * @note bmi160_set_intr_high_g_durn() + * @note THRESHOLD + * @note bmi160_set_intr_high_g_thres() + * @note SOURCE + * @note bmi160_set_intr_low_high_source() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_high_g_intr(u8 +*v_high_g_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR LOW_G INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads the low g interrupt status + * from the register 0x1D bit 3 + * flag is associated with a specific interrupt function. + * It is set when the low g interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_low_g_intr_u8 : The status of low_g interrupt + * + * @note Low_g interrupt configured by following functions + * @note STATUS + * @note bmi160_get_stat1_low_g_intr() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_low_g() + * @note SOURCE + * @note bmi160_set_intr_low_high_source() + * @note DURATION + * @note bmi160_set_intr_low_g_durn() + * @note THRESHOLD + * @note bmi160_set_intr_low_g_thres() + * @note HYSTERESIS + * @note bmi160_set_intr_low_g_hyst() + * @note MODE + * @note bmi160_set_intr_low_g_mode() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_low_g_intr(u8 +*v_low_g_intr_u8); +/**************************************************/ +/**\name FUNCTION FOR DATA READY INTERRUPT STATUS */ +/*************************************************/ +/*! + * @brief This API reads data ready interrupt status + * from the register 0x1D bit 4 + * flag is associated with a specific interrupt function. + * It is set when the data ready interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_data_rdy_intr_u8 : The status of data ready interrupt + * + * @note Data ready interrupt configured by following functions + * @note STATUS + * @note bmi160_get_stat1_data_rdy_intr() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_data_rdy() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_data_rdy_intr(u8 +*v_data_rdy_intr_u8); +/**************************************************/ +/**\name FUNCTIONS FOR FIFO FULL AND WATER MARK INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads data ready FIFO full interrupt status + * from the register 0x1D bit 5 + * flag is associated with a specific interrupt function. + * It is set when the FIFO full interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will + * be permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_full_intr_u8 : The status of fifo full interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note bmi160_set_intr_fifo_full() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_fifo_full_intr(u8 +*v_fifo_full_intr_u8); +/*! + * @brief This API reads data + * ready FIFO watermark interrupt status + * from the register 0x1D bit 6 + * flag is associated with a specific interrupt function. + * It is set when the FIFO watermark interrupt triggers. The + * setting of INT_LATCH controls if the + * interrupt signal and hence the + * respective interrupt flag will be + * permanently latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_fifo_wm_intr_u8 : The status of fifo water mark interrupt + * + * @note FIFO full interrupt can be configured by following functions + * @note bmi160_set_intr_fifo_wm() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_fifo_wm_intr(u8 +*v_fifo_wm_intr_u8); +/**************************************************/ +/**\name FUNCTIONS FOR NO MOTION INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads data ready no motion interrupt status + * from the register 0x1D bit 7 + * flag is associated with a specific interrupt function. + * It is set when the no motion interrupt triggers. The + * setting of INT_LATCH controls if the interrupt signal and hence the + * respective interrupt flag will be permanently + * latched, temporarily latched + * or not latched. + * + * + * + * + * @param v_nomotion_intr_u8 : The status of no motion interrupt + * + * @note No motion interrupt can be configured by following function + * @note STATUS + * @note bmi160_get_stat1_nomotion_intr() + * @note INTERRUPT MAPPING + * @note bmi160_set_intr_nomotion() + * @note DURATION + * @note bmi160_set_intr_slow_no_motion_durn() + * @note THRESHOLD + * @note bmi160_set_intr_slow_no_motion_thres() + * @note SLOW/NO MOTION SELECT + * @note bmi160_set_intr_slow_no_motion_select() + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat1_nomotion_intr(u8 +*nomo_intr); +/**************************************************/ +/**\name FUNCTIONS FOR ANY MOTION FIRST XYZ AND SIGN INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the status of any motion first x + * from the register 0x1E bit 0 + * + * + * @param v_anymotion_first_x_u8 : The status of any motion first x interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_first_x(u8 +*v_anymotion_first_x_u8); +/*! + * @brief This API reads the status of any motion first y interrupt + * from the register 0x1E bit 1 + * + * + * + *@param v_any_motion_first_y_u8 : The status of any motion first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_first_y(u8 +*v_any_motion_first_y_u8); +/*! + * @brief This API reads the status of any motion first z interrupt + * from the register 0x1E bit 2 + * + * + * + * + *@param v_any_motion_first_z_u8 : The status of any motion first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_first_z(u8 +*v_any_motion_first_z_u8); +/*! + * @brief This API reads the any motion sign status from the + * register 0x1E bit 3 + * + * + * + * + * @param v_anymotion_sign_u8 : The status of any motion sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_any_motion_sign(u8 +*v_anymotion_sign_u8); +/**************************************************/ +/**\name FUNCTIONS FOR TAP FIRST XYZ AND SIGN INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the any motion tap first x status from the + * register 0x1E bit 4 + * + * + * + * + * @param v_tap_first_x_u8 :The status of any motion tap first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_first_x(u8 +*v_tap_first_x_u8); +/*! + * @brief This API reads the tap first y interrupt status from the + * register 0x1E bit 5 + * + * + * + * + * @param v_tap_first_y_u8 :The status of tap first y interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_first_y(u8 +*v_tap_first_y_u8); +/*! + * @brief This API reads the tap first z interrupt status from the + * register 0x1E bit 6 + * + * + * + * + * @param v_tap_first_z_u8 :The status of tap first z interrupt + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_first_z(u8 +*v_tap_first_z_u8); +/*! + * @brief This API reads the tap sign status from the + * register 0x1E bit 7 + * + * + * + * + * @param v_tap_sign_u8 : The status of tap sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat2_tap_sign(u8 +*tap_sign); +/**************************************************/ +/**\name FUNCTIONS FOR HIGH_G FIRST XYZ AND SIGN INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the high_g first x status from the + * register 0x1F bit 0 + * + * + * + * + * @param v_high_g_first_x_u8 :The status of high_g first x + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_first_x(u8 +*v_high_g_first_x_u8); +/*! + * @brief This API reads the high_g first y status from the + * register 0x1F bit 1 + * + * + * + * + * @param v_high_g_first_y_u8 : The status of high_g first y + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_first_y(u8 +*v_high_g_first_y_u8); +/*! + * @brief This API reads the high_g first z status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_first_z_u8 : The status of high_g first z + * value | status + * -----------|------------- + * 0 | not triggered + * 1 | triggered by z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_first_z(u8 +*v_high_g_first_z_u8); +/*! + * @brief This API reads the high sign status from the + * register 0x1F bit 3 + * + * + * + * + * @param v_high_g_sign_u8 :The status of high sign + * value | sign + * -----------|------------- + * 0 | positive + * 1 | negative + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_high_g_sign(u8 +*v_high_g_sign_u8); +/**************************************************/ +/**\name FUNCTIONS FOR ORIENT XY AND Z INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the status of orient_xy plane + * from the register 0x1F bit 4 and 5 + * + * + * @param v_orient_xy_u8 :The status of orient_xy plane + * value | status + * -----------|------------- + * 0x00 | portrait upright + * 0x01 | portrait upside down + * 0x02 | landscape left + * 0x03 | landscape right + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_orient_xy(u8 +*v_orient_xy_u8); +/*! + * @brief This API reads the status of orient z plane + * from the register 0x1F bit 6 + * + * + * @param v_orient_z_u8 :The status of orient z + * value | status + * -----------|------------- + * 0x00 | upward looking + * 0x01 | downward looking + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_orient_z(u8 +*v_orient_z_u8); +/**************************************************/ +/**\name FUNCTIONS FOR FLAT INTERRUPT STATUS*/ +/*************************************************/ +/*! + * @brief This API reads the flat status from the register + * 0x1F bit 7 + * + * + * @param v_flat_u8 : The status of flat interrupt + * value | status + * -----------|------------- + * 0x00 | non flat + * 0x01 | flat position + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_stat3_flat(u8 +*flat); +/**************************************************/ +/**\name FUNCTION FOR TEMPERATUE READ */ +/*************************************************/ +/*! + * @brief This API reads the temperature of the sensor + * from the register 0x21 bit 0 to 7 + * + * + * + * @param v_temp_s16 : The value of temperature + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_temp(s16 +*v_temp_s16); +/**************************************************/ +/**\name FUNCTION FOR FIFO LENGTH AND FIFO DATA READ */ +/*************************************************/ +/*! + * @brief This API reads the of the sensor + * form the register 0x23 and 0x24 bit 0 to 7 and 0 to 2 + * @brief this byte counter is updated each time a complete frame + * was read or writtern + * + * + * @param v_fifo_length_u32 : The value of fifo byte counter + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_fifo_length( +u32 *v_fifo_length_u32); +/*! + * @brief This API reads the fifo data of the sensor + * from the register 0x24 + * @brief Data format depends on the setting of register FIFO_CONFIG + * + * + * + * @param v_fifodata_u8 : Pointer holding the fifo data + * + * @note For reading FIFO data use the following functions + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_fifo_data( +u8 *v_fifodata_u8, u16 v_fifo_length_u16); +/**************************************************/ +/**\name FUNCTION FOR ACCEL CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API is used to get the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | BMI160_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | BMI160_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | BMI160_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | BMI160_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | BMI160_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | BMI160_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | BMI160_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | BMI160_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | BMI160_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | BMI160_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | BMI160_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | BMI160_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_output_data_rate( +u8 *v_output_data_rate_u8); +/*! + * @brief This API is used to set the + * accel output date rate form the register 0x40 bit 0 to 3 + * + * + * @param v_output_data_rate_u8 :The value of accel output date rate + * value | output data rate + * -------|-------------------------- + * 0 | BMI160_ACCEL_OUTPUT_DATA_RATE_RESERVED + * 1 | BMI160_ACCEL_OUTPUT_DATA_RATE_0_78HZ + * 2 | BMI160_ACCEL_OUTPUT_DATA_RATE_1_56HZ + * 3 | BMI160_ACCEL_OUTPUT_DATA_RATE_3_12HZ + * 4 | BMI160_ACCEL_OUTPUT_DATA_RATE_6_25HZ + * 5 | BMI160_ACCEL_OUTPUT_DATA_RATE_12_5HZ + * 6 | BMI160_ACCEL_OUTPUT_DATA_RATE_25HZ + * 7 | BMI160_ACCEL_OUTPUT_DATA_RATE_50HZ + * 8 | BMI160_ACCEL_OUTPUT_DATA_RATE_100HZ + * 9 | BMI160_ACCEL_OUTPUT_DATA_RATE_200HZ + * 10 | BMI160_ACCEL_OUTPUT_DATA_RATE_400HZ + * 11 | BMI160_ACCEL_OUTPUT_DATA_RATE_800HZ + * 12 | BMI160_ACCEL_OUTPUT_DATA_RATE_1600HZ + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_output_data_rate(u8 odr); +/*! + * @brief This API is used to get the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "BMI160_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_bw(u8 *v_bw_u8); +/*! + * @brief This API is used to set the + * accel bandwidth from the register 0x40 bit 4 to 6 + * @brief bandwidth parameter determines filter configuration(acc_us=0) + * and averaging for under sampling mode(acc_us=1) + * + * + * @param v_bw_u8 : The value of accel bandwidth + * + * @note accel bandwidth depends on under sampling parameter + * @note under sampling parameter cab be set by the function + * "BMI160_SET_ACCEL_UNDER_SAMPLING_PARAMETER" + * + * @note Filter configuration + * accel_us | Filter configuration + * -----------|--------------------- + * 0x00 | OSR4 mode + * 0x01 | OSR2 mode + * 0x02 | normal mode + * 0x03 | CIC mode + * 0x04 | Reserved + * 0x05 | Reserved + * 0x06 | Reserved + * 0x07 | Reserved + * + * @note accel under sampling mode + * accel_us | Under sampling mode + * -----------|--------------------- + * 0x00 | no averaging + * 0x01 | average 2 samples + * 0x02 | average 4 samples + * 0x03 | average 8 samples + * 0x04 | average 16 samples + * 0x05 | average 32 samples + * 0x06 | average 64 samples + * 0x07 | average 128 samples + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_bw(u8 v_bw_u8); +/*! + * @brief This API is used to get the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_under_sampling_parameter( +u8 *v_accel_under_sampling_u8); +/*! + * @brief This API is used to set the accel + * under sampling parameter form the register 0x40 bit 7 + * + * + * + * + * @param v_accel_under_sampling_u8 : The value of accel under sampling + * value | under_sampling + * ----------|--------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_under_sampling_parameter( +u8 v_accel_under_sampling_u8); +/*! + * @brief This API is used to get the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | BMI160_ACCEL_RANGE_2G + * 0x05 | BMI160_ACCEL_RANGE_4G + * 0x08 | BMI160_ACCEL_RANGE_8G + * 0x0C | BMI160_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_range( +u8 *v_range_u8); +/*! + * @brief This API is used to set the ranges + * (g values) of the accel from the register 0x41 bit 0 to 3 + * + * + * + * + * @param v_range_u8 : The value of accel g range + * value | g_range + * ----------|----------- + * 0x03 | BMI160_ACCEL_RANGE_2G + * 0x05 | BMI160_ACCEL_RANGE_4G + * 0x08 | BMI160_ACCEL_RANGE_8G + * 0x0C | BMI160_ACCEL_RANGE_16G + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_range( +u8 v_range_u8); +/**************************************************/ +/**\name FUNCTION FOR GYRO CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API is used to get the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | BMI160_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | BMI160_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | BMI160_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | BMI160_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | BMI160_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | BMI160_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | BMI160_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | BMI160_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_output_data_rate( +u8 *gyro_output_typer); +/*! + * @brief This API is used to set the + * gyroscope output data rate from the register 0x42 bit 0 to 3 + * + * + * + * + * @param v_output_data_rate_u8 :The value of gyro output data rate + * value | gyro output data rate + * -----------|----------------------------- + * 0x00 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x01 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x02 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x03 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x04 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x05 | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x06 | BMI160_GYRO_OUTPUT_DATA_RATE_25HZ + * 0x07 | BMI160_GYRO_OUTPUT_DATA_RATE_50HZ + * 0x08 | BMI160_GYRO_OUTPUT_DATA_RATE_100HZ + * 0x09 | BMI160_GYRO_OUTPUT_DATA_RATE_200HZ + * 0x0A | BMI160_GYRO_OUTPUT_DATA_RATE_400HZ + * 0x0B | BMI160_GYRO_OUTPUT_DATA_RATE_800HZ + * 0x0C | BMI160_GYRO_OUTPUT_DATA_RATE_1600HZ + * 0x0D | BMI160_GYRO_OUTPUT_DATA_RATE_3200HZ + * 0x0E | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * 0x0F | BMI160_GYRO_OUTPUT_DATA_RATE_RESERVED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_output_data_rate( +u8 gyro_output_typer); +/*! + * @brief This API is used to get the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | BMI160_GYRO_OSR4_MODE + * 0x01 | BMI160_GYRO_OSR2_MODE + * 0x02 | BMI160_GYRO_NORMAL_MODE + * 0x03 | BMI160_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_bw(u8 *v_bw_u8); +/*! + * @brief This API is used to set the + * data of gyro from the register 0x42 bit 4 to 5 + * + * + * + * + * @param v_bw_u8 : The value of gyro bandwidth + * value | gyro bandwidth + * ----------|---------------- + * 0x00 | BMI160_GYRO_OSR4_MODE + * 0x01 | BMI160_GYRO_OSR2_MODE + * 0x02 | BMI160_GYRO_NORMAL_MODE + * 0x03 | BMI160_GYRO_CIC_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_bw(u8 v_bw_u8); +/*! + * @brief This API reads the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | BMI160_GYRO_RANGE_2000_DEG_SEC + * 0x01 | BMI160_GYRO_RANGE_1000_DEG_SEC + * 0x02 | BMI160_GYRO_RANGE_500_DEG_SEC + * 0x03 | BMI160_GYRO_RANGE_250_DEG_SEC + * 0x04 | BMI160_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_range( +u8 *v_range_u8); +/*! + * @brief This API set the range + * of gyro from the register 0x43 bit 0 to 2 + * + * @param v_range_u8 : The value of gyro range + * value | range + * ----------|------------------------------- + * 0x00 | BMI160_GYRO_RANGE_2000_DEG_SEC + * 0x01 | BMI160_GYRO_RANGE_1000_DEG_SEC + * 0x02 | BMI160_GYRO_RANGE_500_DEG_SEC + * 0x03 | BMI160_GYRO_RANGE_250_DEG_SEC + * 0x04 | BMI160_GYRO_RANGE_125_DEG_SEC + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_range( +u8 v_range_u8); +/**************************************************/ +/**\name FUNCTION FOR MAG CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API is used to get the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |BMI160_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |BMI160_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |BMI160_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |BMI160_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |BMI160_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |BMI160_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |BMI160_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |BMI160_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |BMI160_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |BMI160_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |BMI160_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |BMI160_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_output_data_rate(u8 *odr); +/*! + * @brief This API is used to set the + * output data rate of magnetometer from the register 0x44 bit 0 to 3 + * + * + * + * + * @param v_output_data_rat_u8e : The value of mag output data rate + * value | mag output data rate + * ---------|--------------------------- + * 0x00 |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED + * 0x01 |BMI160_MAG_OUTPUT_DATA_RATE_0_78HZ + * 0x02 |BMI160_MAG_OUTPUT_DATA_RATE_1_56HZ + * 0x03 |BMI160_MAG_OUTPUT_DATA_RATE_3_12HZ + * 0x04 |BMI160_MAG_OUTPUT_DATA_RATE_6_25HZ + * 0x05 |BMI160_MAG_OUTPUT_DATA_RATE_12_5HZ + * 0x06 |BMI160_MAG_OUTPUT_DATA_RATE_25HZ + * 0x07 |BMI160_MAG_OUTPUT_DATA_RATE_50HZ + * 0x08 |BMI160_MAG_OUTPUT_DATA_RATE_100HZ + * 0x09 |BMI160_MAG_OUTPUT_DATA_RATE_200HZ + * 0x0A |BMI160_MAG_OUTPUT_DATA_RATE_400HZ + * 0x0B |BMI160_MAG_OUTPUT_DATA_RATE_800HZ + * 0x0C |BMI160_MAG_OUTPUT_DATA_RATE_1600HZ + * 0x0D |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED0 + * 0x0E |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED1 + * 0x0F |BMI160_MAG_OUTPUT_DATA_RATE_RESERVED2 + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_output_data_rate(u8 odr); +/**************************************************/ +/**\name FUNCTION FOR FIFO CONFIGURATIONS */ +/*************************************************/ + /*! + * @brief This API is used to read Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_down_gyro( +u8 *v_fifo_down_gyro_u8); + /*! + * @brief This API is used to set Down sampling + * for gyro (2**downs_gyro) in the register 0x45 bit 0 to 2 + * + * + * + * + * @param v_fifo_down_gyro_u8 :The value of gyro fifo down + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_down_gyro( +u8 v_fifo_down_gyro_u8); +/*! + * @brief This API is used to read gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_fifo_filter_data( +u8 *v_gyro_fifo_filter_data_u8); +/*! + * @brief This API is used to set gyro fifo filter data + * from the register 0x45 bit 3 + * + * + * + * @param v_gyro_fifo_filter_data_u8 :The value of gyro filter data + * value | gyro_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_fifo_filter_data( +u8 v_gyro_fifo_filter_data_u8); +/*! + * @brief This API is used to read Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_down_accel( +u8 *v_fifo_down_u8); + /*! + * @brief This API is used to set Down sampling + * for accel (2*downs_accel) from the register 0x45 bit 4 to 6 + * + * + * + * + * @param v_fifo_down_u8 :The value of accel fifo down + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_down_accel( +u8 v_fifo_down_u8); +/*! + * @brief This API is used to read accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_fifo_filter_data( +u8 *v_accel_fifo_filter_u8); +/*! + * @brief This API is used to set accel fifo filter data + * from the register 0x45 bit 7 + * + * + * + * @param v_accel_fifo_filter_u8 :The value of accel filter data + * value | accel_fifo_filter_data + * ------------|------------------------- + * 0x00 | Unfiltered data + * 0x01 | Filtered data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_fifo_filter_data( +u8 v_accel_fifo_filter_u8); +/**************************************************/ +/**\name FUNCTION FOR FIFO WATER MARK ENABLE */ +/*************************************************/ +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_wm( +u8 *v_fifo_wm_u8); +/*! + * @brief This API is used to Trigger an interrupt + * when FIFO contains water mark level from the register 0x46 bit 0 to 7 + * + * + * + * @param v_fifo_wm_u8 : The value of fifo water mark level + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_wm( +u8 v_fifo_wm_u8); +/**************************************************/ +/**\name FUNCTION FOR FIFO CONFIGURATIONS */ +/*************************************************/ +/*! + * @brief This API reads fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_time_enable( +u8 *v_fifo_time_enable_u8); +/*! + * @brief This API set fifo sensor time + * frame after the last valid data frame form the register 0x47 bit 1 + * + * + * + * + * @param v_fifo_time_enable_u8 : The value of sensor time + * value | fifo sensor time + * ------------|------------------------- + * 0x00 | do not return sensortime frame + * 0x01 | return sensortime frame + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_time_enable( +u8 v_fifo_time_enable_u8); +/*! + * @brief This API reads FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_tag_intr2_enable( +u8 *v_fifo_tag_intr2_u8); +/*! + * @brief This API set FIFO tag interrupt2 enable status + * from the resister 0x47 bit 2 + * + * @param v_fifo_tag_intr2_u8 : The value of fifo tag interrupt + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_tag_intr2_enable( +u8 v_fifo_tag_intr2_u8); +/*! + * @brief This API get FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_tag_intr1_enable( +u8 *v_fifo_tag_intr1_u8); +/*! + * @brief This API set FIFO tag interrupt1 enable status + * from the resister 0x47 bit 3 + * + * @param v_fifo_tag_intr1_u8 :The value of fifo tag interrupt1 + * value | fifo tag interrupt + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_tag_intr1_enable( +u8 v_fifo_tag_intr1_u8); +/*! + * @brief This API reads FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_header_enable( +u8 *v_fifo_header_u8); +/*! + * @brief This API set FIFO frame + * header enable from the register 0x47 bit 4 + * + * @param v_fifo_header_u8 :The value of fifo header + * value | fifo header + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_header_enable( +u8 v_fifo_header_u8); +/*! + * @brief This API is used to read stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_mag_enable( +u8 *v_fifo_mag_u8); +/*! + * @brief This API is used to set stored + * magnetometer data in FIFO (all 3 axes) from the register 0x47 bit 5 + * + * @param v_fifo_mag_u8 : The value of fifo mag enble + * value | fifo mag + * ----------|------------------- + * 0x00 | no magnetometer data is stored + * 0x01 | magnetometer data is stored + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_mag_enable( +u8 v_fifo_mag_u8); +/*! + * @brief This API is used to read stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_accel_enable( +u8 *v_fifo_accel_u8); +/*! + * @brief This API is used to set stored + * accel data in FIFO (all 3 axes) from the register 0x47 bit 6 + * + * @param v_fifo_accel_u8 : The value of fifo accel enble + * value | fifo accel + * ----------|------------------- + * 0x00 | no accel data is stored + * 0x01 | accel data is stored + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_accel_enable( +u8 v_fifo_accel_u8); +/*! + * @brief This API is used to read stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_fifo_gyro_enable( +u8 *v_fifo_gyro_u8); +/*! + * @brief This API is used to set stored + * gyro data in FIFO (all 3 axes) from the resister 0x47 bit 7 + * + * + * @param v_fifo_gyro_u8 : The value of fifo gyro enble + * value | fifo gyro + * ----------|------------------- + * 0x00 | no gyro data is stored + * 0x01 | gyro data is stored + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_fifo_gyro_enable( +u8 v_fifo_gyro_u8); +/***************************************************************/ +/**\name FUNCTION FOR MAG I2C ADDRESS SELECTION */ +/***************************************************************/ +/*! + * @brief This API is used to read + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_device_addr( +u8 *v_i2c_device_addr_u8); +/*! + * @brief This API is used to set + * I2C device address of auxiliary mag from the register 0x4B bit 1 to 7 + * + * + * + * + * @param v_i2c_device_addr_u8 : The value of mag I2C device address + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_i2c_device_addr( +u8 v_i2c_device_addr_u8); +/*! + * @brief This API is used to read + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_burst( +u8 *v_mag_burst_u8); +/*! + * @brief This API is used to set + * Burst data length (1,2,6,8 byte) from the register 0x4C bit 0 to 1 + * + * + * + * + * @param v_mag_burst_u8 : The data of mag burst read lenth + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_burst( +u8 v_mag_burst_u8); +/***************************************************************/ +/**\name FUNCTION FOR MAG OFFSET */ +/***************************************************************/ +/*! + * @brief This API is used to read + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_offset( +u8 *v_mag_offset_u8); +/*! + * @brief This API is used to set + * trigger-readout offset in units of 2.5 ms. If set to zero, + * the offset is maximum, i.e. after readout a trigger + * is issued immediately. from the register 0x4C bit 2 to 5 + * + * + * + * + * @param v_mag_offset_u8 : The value of mag offset + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_offset( +u8 v_mag_offset_u8); +/***************************************************************/ +/**\name FUNCTION FOR MAG MANUAL/AUTO MODE SELECTION */ +/***************************************************************/ +/*! + * @brief This API is used to read + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_manual_enable( +u8 *v_mag_manual_u8); +/*! + * @brief This API is used to set + * Enable register access on MAG_IF[2] or MAG_IF[3] writes. + * This implies that the DATA registers are not updated with + * magnetometer values. Accessing magnetometer requires + * the magnetometer in normal mode in PMU_STATUS. + * from the register 0x4C bit 7 + * + * + * + * @param v_mag_manual_u8 : The value of mag manual enable + * value | mag manual + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_manual_enable( +u8 v_mag_manual_u8); +/***************************************************************/ +/**\name FUNCTIONS FOR MAG READ, WRITE AND WRITE DATA ADDRESS */ +/***************************************************************/ +/*! + * @brief This API is used to read data + * magnetometer address to read from the register 0x4D bit 0 to 7 + * @brief It used to provide mag read address of auxiliary mag + * + * + * + * + * @param v_mag_read_addr_u8 : The value of address need to be read + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_read_addr( +u8 *v_mag_read_addr_u8); +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4D bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_read_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_read_addr( +u8 v_mag_read_addr_u8); +/*! + * @brief This API is used to read + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_write_addr( +u8 *v_mag_write_addr_u8); +/*! + * @brief This API is used to set + * magnetometer write address from the register 0x4E bit 0 to 7 + * @brief mag write address writes the address of auxiliary mag to write + * + * + * + * @param v_mag_write_addr_u8: + * The data of auxiliary mag address to write data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_write_addr( +u8 v_mag_write_addr_u8); +/*! + * @brief This API is used to read magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_mag_write_data( +u8 *v_mag_write_data_u8); +/*! + * @brief This API is used to set magnetometer write data + * form the resister 0x4F bit 0 to 7 + * @brief This writes the data will be wrote to mag + * + * + * + * @param v_mag_write_data_u8: The value of mag data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_mag_write_data( +u8 v_mag_write_data_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF +ANY-MOTION XYZ, DOUBLE AND SINGLE TAP, ORIENT AND FLAT */ +/***************************************************************/ +/*! + * @brief This API is used to read + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_ANY_MOTION_X_ENABLE + * 1 | BMI160_ANY_MOTION_Y_ENABLE + * 2 | BMI160_ANY_MOTION_Z_ENABLE + * 3 | BMI160_DOUBLE_TAP_ENABLE + * 4 | BMI160_SINGLE_TAP_ENABLE + * 5 | BMI160_ORIENT_ENABLE + * 6 | BMI160_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_enable_0( +u8 enable, u8 *v_intr_enable_zero_u8); +/*! + * @brief This API is used to set + * interrupt enable from the register 0x50 bit 0 to 7 + * + * + * + * + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_ANY_MOTION_X_ENABLE + * 1 | BMI160_ANY_MOTION_Y_ENABLE + * 2 | BMI160_ANY_MOTION_Z_ENABLE + * 3 | BMI160_DOUBLE_TAP_ENABLE + * 4 | BMI160_SINGLE_TAP_ENABLE + * 5 | BMI160_ORIENT_ENABLE + * 6 | BMI160_FLAT_ENABLE + * + * @param v_intr_enable_zero_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_enable_0( +u8 enable, u8 v_intr_enable_zero_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF +HIGH_G XYZ, LOW_G, DATA READY, FIFO FULL AND FIFO WATER MARK */ +/***************************************************************/ +/*! + * @brief This API is used to read + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_HIGH_G_X_ENABLE + * 1 | BMI160_HIGH_G_Y_ENABLE + * 2 | BMI160_HIGH_G_Z_ENABLE + * 3 | BMI160_LOW_G_ENABLE + * 4 | BMI160_DATA_RDY_ENABLE + * 5 | BMI160_FIFO_FULL_ENABLE + * 6 | BMI160_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_enable_1( +u8 enable, u8 *v_intr_enable_1_u8); +/*! + * @brief This API is used to set + * interrupt enable byte1 from the register 0x51 bit 0 to 6 + * @brief It read the high_g_x,high_g_y,high_g_z,low_g_enable + * data ready, fifo full and fifo water mark. + * + * + * + * @param v_enable_u8 : The value of interrupt enable + * @param v_enable_u8 : Value to decided to select interrupt + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_HIGH_G_X_ENABLE + * 1 | BMI160_HIGH_G_Y_ENABLE + * 2 | BMI160_HIGH_G_Z_ENABLE + * 3 | BMI160_LOW_G_ENABLE + * 4 | BMI160_DATA_RDY_ENABLE + * 5 | BMI160_FIFO_FULL_ENABLE + * 6 | BMI160_FIFO_WM_ENABLE + * + * @param v_intr_enable_1_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_enable_1( +u8 enable, u8 v_intr_enable_1_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF +NO MOTION XYZ */ +/***************************************************************/ +/*! + * @brief This API is used to read + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_NOMOTION_X_ENABLE + * 1 | BMI160_NOMOTION_Y_ENABLE + * 2 | BMI160_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_enable_2( +u8 enable, u8 *v_intr_enable_2_u8); +/*! + * @brief This API is used to set + * interrupt enable byte2 from the register bit 0x52 bit 0 to 3 + * @brief It reads no motion x,y and z + * + * + * + * @param v_enable_u8: The value of interrupt enable + * v_enable_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_NOMOTION_X_ENABLE + * 1 | BMI160_NOMOTION_Y_ENABLE + * 2 | BMI160_NOMOTION_Z_ENABLE + * + * @param v_intr_enable_2_u8 : The interrupt enable value + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_enable_2( +u8 enable, u8 v_intr_enable_2_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT ENABLE OF + STEP DETECTOR */ +/***************************************************************/ + /*! + * @brief This API is used to read + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_step_detector_enable( +u8 *v_step_intr_u8); + /*! + * @brief This API is used to set + * interrupt enable step detector interrupt from + * the register bit 0x52 bit 3 + * + * + * + * + * @param v_step_intr_u8 : The value of step detector interrupt enable + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_detector_enable( +u8 v_step_intr_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT CONTROL */ +/***************************************************************/ +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | BMI160_INTR1_EDGE_CTRL + * 1 | BMI160_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_EDGE + * 0x00 | BMI160_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_edge_ctrl( +u8 v_channel_u8, u8 *v_intr_edge_ctrl_u8); +/*! + * @brief Configure trigger condition of interrupt1 + * and interrupt2 pin from the register 0x53 + * @brief interrupt1 - bit 0 + * @brief interrupt2 - bit 4 + * + * @param v_channel_u8: The value of edge trigger selection + * v_channel_u8 | Edge trigger + * ---------------|--------------- + * 0 | BMI160_INTR1_EDGE_CTRL + * 1 | BMI160_INTR2_EDGE_CTRL + * + * @param v_intr_edge_ctrl_u8 : The value of edge trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_EDGE + * 0x00 | BMI160_LEVEL + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_edge_ctrl( +u8 v_channel_u8, u8 v_intr_edge_ctrl_u8); +/*! + * @brief API used for get the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_LEVEL + * 1 | BMI160_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_LEVEL_HIGH + * 0x00 | BMI160_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_level( +u8 v_channel_u8, u8 *v_intr_level_u8); +/*! + * @brief API used for set the Configure level condition of interrupt1 + * and interrupt2 pin form the register 0x53 + * @brief interrupt1 - bit 1 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of level condition selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_LEVEL + * 1 | BMI160_INTR2_LEVEL + * + * @param v_intr_level_u8 : The value of level of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_LEVEL_HIGH + * 0x00 | BMI160_LEVEL_LOW + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_level( +u8 v_channel_u8, u8 v_intr_level_u8); +/*! + * @brief API used to get configured output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_OPEN_DRAIN + * 0x00 | BMI160_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_output_type( +u8 v_channel_u8, u8 *v_intr_output_type_u8); +/*! + * @brief API used to set output enable of interrupt1 + * and interrupt2 from the register 0x53 + * @brief interrupt1 - bit 2 + * @brief interrupt2 - bit 6 + * + * + * @param v_channel_u8: The value of output type enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_intr_output_type_u8 : + * The value of output type of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_OPEN_DRAIN + * 0x00 | BMI160_PUSH_PULL + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_output_type( +u8 v_channel_u8, u8 v_intr_output_type_u8); + /*! + * @brief API used to get the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_output_enable( +u8 v_channel_u8, u8 *v_output_enable_u8); + /*! + * @brief API used to set the Output enable for interrupt1 + * and interrupt1 pin from the register 0x53 + * @brief interrupt1 - bit 3 + * @brief interrupt2 - bit 7 + * + * @param v_channel_u8: The value of output enable selection + * v_channel_u8 | level selection + * ---------------|--------------- + * 0 | BMI160_INTR1_OUTPUT_TYPE + * 1 | BMI160_INTR2_OUTPUT_TYPE + * + * @param v_output_enable_u8 : + * The value of output enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_output_enable( +u8 v_channel_u8, u8 v_output_enable_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT LATCH INTERRUPT */ +/***************************************************************/ +/*! +* @brief This API is used to get the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orientation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* BMI160_LATCH_DUR_NONE | 0x00 +* BMI160_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* BMI160_LATCH_DUR_625_MICRO_SEC | 0x02 +* BMI160_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* BMI160_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* BMI160_LATCH_DUR_5_MILLI_SEC | 0x05 +* BMI160_LATCH_DUR_10_MILLI_SEC | 0x06 +* BMI160_LATCH_DUR_20_MILLI_SEC | 0x07 +* BMI160_LATCH_DUR_40_MILLI_SEC | 0x08 +* BMI160_LATCH_DUR_80_MILLI_SEC | 0x09 +* BMI160_LATCH_DUR_160_MILLI_SEC | 0x0A +* BMI160_LATCH_DUR_320_MILLI_SEC | 0x0B +* BMI160_LATCH_DUR_640_MILLI_SEC | 0x0C +* BMI160_LATCH_DUR_1_28_SEC | 0x0D +* BMI160_LATCH_DUR_2_56_SEC | 0x0E +* BMI160_LATCHED | 0x0F +* +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_latch_intr( +u8 *v_latch_intr_u8); +/*! +* @brief This API is used to set the latch duration +* from the register 0x54 bit 0 to 3 +* @brief This latch selection is not applicable for data ready, +* orientation and flat interrupts. +* +* +* +* @param v_latch_intr_u8 : The value of latch duration +* Latch Duration | value +* --------------------------------------|------------------ +* BMI160_LATCH_DUR_NONE | 0x00 +* BMI160_LATCH_DUR_312_5_MICRO_SEC | 0x01 +* BMI160_LATCH_DUR_625_MICRO_SEC | 0x02 +* BMI160_LATCH_DUR_1_25_MILLI_SEC | 0x03 +* BMI160_LATCH_DUR_2_5_MILLI_SEC | 0x04 +* BMI160_LATCH_DUR_5_MILLI_SEC | 0x05 +* BMI160_LATCH_DUR_10_MILLI_SEC | 0x06 +* BMI160_LATCH_DUR_20_MILLI_SEC | 0x07 +* BMI160_LATCH_DUR_40_MILLI_SEC | 0x08 +* BMI160_LATCH_DUR_80_MILLI_SEC | 0x09 +* BMI160_LATCH_DUR_160_MILLI_SEC | 0x0A +* BMI160_LATCH_DUR_320_MILLI_SEC | 0x0B +* BMI160_LATCH_DUR_640_MILLI_SEC | 0x0C +* BMI160_LATCH_DUR_1_28_SEC | 0x0D +* BMI160_LATCH_DUR_2_56_SEC | 0x0E +* BMI160_LATCHED | 0x0F +* +* +* +* @return results of bus communication function +* @retval 0 -> Success +* @retval -1 -> Error +* +* +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_latch_intr( +u8 v_latch_intr_u8); +/*! + * @brief API used to get input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | BMI160_INTR1_INPUT_ENABLE + * 1 | BMI160_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_input_enable( +u8 v_channel_u8, u8 *v_input_en_u8); +/*! + * @brief API used to set input enable for interrupt1 + * and interrupt2 pin from the register 0x54 + * @brief interrupt1 - bit 4 + * @brief interrupt2 - bit 5 + * + * @param v_channel_u8: The value of input enable selection + * v_channel_u8 | input selection + * ---------------|--------------- + * 0 | BMI160_INTR1_INPUT_ENABLE + * 1 | BMI160_INTR2_INPUT_ENABLE + * + * @param v_input_en_u8 : + * The value of input enable of interrupt enable + * value | Behaviour + * ----------|------------------- + * 0x01 | BMI160_INPUT + * 0x00 | BMI160_OUTPUT + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_input_enable( +u8 v_channel_u8, u8 v_input_en_u8); +/***************************************************************/ +/**\name FUNCTION FOR INTERRUPT1 AND INTERRUPT2 MAPPING */ +/***************************************************************/ + /*! + * @brief reads the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_LOW_G + * 1 | BMI160_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g( +u8 v_channel_u8, u8 *v_intr_low_g_u8); + /*! + * @brief set the Low g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 0 in the register 0x55 + * @brief interrupt2 bit 0 in the register 0x57 + * + * + * @param v_channel_u8: The value of low_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_LOW_G + * 1 | BMI160_INTR2_MAP_LOW_G + * + * @param v_intr_low_g_u8 : The value of low_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g( +u8 v_channel_u8, u8 v_intr_low_g_u8); +/*! + * @brief Reads the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_HIGH_G + * 1 | BMI160_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g( +u8 v_channel_u8, u8 *v_intr_high_g_u8); +/*! + * @brief Write the HIGH g interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 1 in the register 0x55 + * @brief interrupt2 bit 1 in the register 0x57 + * + * + * @param v_channel_u8: The value of high_g selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_HIGH_G + * 1 | BMI160_INTR2_MAP_HIGH_G + * + * @param v_intr_high_g_u8 : The value of high_g enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g( +u8 v_channel_u8, u8 v_intr_high_g_u8); +/*! + * @brief Reads the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ANY_MOTION + * 1 | BMI160_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_any_motion( +u8 v_channel_u8, u8 *v_intr_any_motion_u8); +/*! + * @brief Write the Any motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 2 in the register 0x55 + * @brief interrupt2 bit 2 in the register 0x57 + * + * + * @param v_channel_u8: The value of any motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ANY_MOTION + * 1 | BMI160_INTR2_MAP_ANY_MOTION + * + * @param v_intr_any_motion_u8 : The value of any motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_any_motion( +u8 v_channel_u8, u8 v_intr_any_motion_u8); +/*! + * @brief Reads the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_NOMO + * 1 | BMI160_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_nomotion( +u8 v_channel_u8, u8 *v_intr_nomotion_u8); +/*! + * @brief Write the No motion interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 3 in the register 0x55 + * @brief interrupt2 bit 3 in the register 0x57 + * + * + * @param v_channel_u8: The value of no motion selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_NOMO + * 1 | BMI160_INTR2_MAP_NOMO + * + * @param v_intr_nomotion_u8 : The value of no motion enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_nomotion( +u8 v_channel_u8, u8 v_intr_nomotion_u8); +/*! + * @brief Reads the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DOUBLE_TAP + * 1 | BMI160_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_double_tap( +u8 v_channel_u8, u8 *v_intr_double_tap_u8); +/*! + * @brief Write the Double Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 4 in the register 0x55 + * @brief interrupt2 bit 4 in the register 0x57 + * + * + * @param v_channel_u8: The value of double tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DOUBLE_TAP + * 1 | BMI160_INTR2_MAP_DOUBLE_TAP + * + * @param v_intr_double_tap_u8 : The value of double tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_double_tap( +u8 v_channel_u8, u8 v_intr_double_tap_u8); +/*! + * @brief Reads the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_SINGLE_TAP + * 1 | BMI160_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_single_tap( +u8 v_channel_u8, u8 *v_intr_single_tap_u8); +/*! + * @brief Write the Single Tap interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 5 in the register 0x55 + * @brief interrupt2 bit 5 in the register 0x57 + * + * + * @param v_channel_u8: The value of single tap interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_SINGLE_TAP + * 1 | BMI160_INTR2_MAP_SINGLE_TAP + * + * @param v_intr_single_tap_u8 : The value of single tap enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_single_tap( +u8 v_channel_u8, u8 v_intr_single_tap_u8); +/*! + * @brief Reads the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ORIENT + * 1 | BMI160_INTR2_MAP_ORIENT + * + * @param v_intr_orient_u8 : The value of orient enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient( +u8 v_channel_u8, u8 *v_intr_orient_u8); +/*! + * @brief Write the Orient interrupt + * interrupt mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 6 in the register 0x55 + * @brief interrupt2 bit 6 in the register 0x57 + * + * + * @param v_channel_u8: The value of orient interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_ORIENT + * 1 | BMI160_INTR2_MAP_ORIENT + * + * @param v_intr_orient_u8 : The value of orient enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient( +u8 v_channel_u8, u8 v_intr_orient_u8); + /*! + * @brief Reads the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FLAT + * 1 | BMI160_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat( +u8 v_channel_u8, u8 *v_intr_flat_u8); + /*! + * @brief Write the Flat interrupt + * mapped to interrupt1 + * and interrupt2 from the register 0x55 and 0x57 + * @brief interrupt1 bit 7 in the register 0x55 + * @brief interrupt2 bit 7 in the register 0x57 + * + * + * @param v_channel_u8: The value of flat interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FLAT + * 1 | BMI160_INTR2_MAP_FLAT + * + * @param v_intr_flat_u8 : The value of flat enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat( +u8 v_channel_u8, u8 v_intr_flat_u8); +/*! + * @brief Reads PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_PMUTRIG + * 1 | BMI160_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_pmu_trig( +u8 v_channel_u8, u8 *v_intr_pmu_trig_u8); +/*! + * @brief Write PMU trigger interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 0 and 4 + * @brief interrupt1 bit 0 in the register 0x56 + * @brief interrupt2 bit 4 in the register 0x56 + * + * + * @param v_channel_u8: The value of pmu trigger selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_PMUTRIG + * 1 | BMI160_INTR2_MAP_PMUTRIG + * + * @param v_intr_pmu_trig_u8 : The value of pmu trigger enable + * value | trigger enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_pmu_trig( +u8 v_channel_u8, u8 v_intr_pmu_trig_u8); +/*! + * @brief Reads FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_FULL + * 1 | BMI160_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_fifo_full( +u8 v_channel_u8, u8 *v_intr_fifo_full_u8); +/*! + * @brief Write FIFO Full interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 5 and 1 + * @brief interrupt1 bit 5 in the register 0x56 + * @brief interrupt2 bit 1 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo full interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_FULL + * 1 | BMI160_INTR2_MAP_FIFO_FULL + * + * @param v_intr_fifo_full_u8 : The value of fifo full interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_fifo_full( +u8 v_channel_u8, u8 v_intr_fifo_full_u8); +/*! + * @brief Reads FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_WM + * 1 | BMI160_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_fifo_wm( +u8 v_channel_u8, u8 *v_intr_fifo_wm_u8); +/*! + * @brief Write FIFO Watermark interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 bit 6 and 2 + * @brief interrupt1 bit 6 in the register 0x56 + * @brief interrupt2 bit 2 in the register 0x56 + * + * + * @param v_channel_u8: The value of fifo Watermark interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_FIFO_WM + * 1 | BMI160_INTR2_MAP_FIFO_WM + * + * @param v_intr_fifo_wm_u8 : The value of fifo Watermark interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_fifo_wm( +u8 v_channel_u8, u8 v_intr_fifo_wm_u8); +/*! + * @brief Reads Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DATA_RDY + * 1 | BMI160_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_data_rdy( +u8 v_channel_u8, u8 *v_intr_data_rdy_u8); +/*! + * @brief Write Data Ready interrupt mapped to interrupt1 + * and interrupt2 form the register 0x56 + * @brief interrupt1 bit 7 in the register 0x56 + * @brief interrupt2 bit 3 in the register 0x56 + * + * + * @param v_channel_u8: The value of data ready interrupt selection + * v_channel_u8 | interrupt + * ---------------|--------------- + * 0 | BMI160_INTR1_MAP_DATA_RDY + * 1 | BMI160_INTR2_MAP_DATA_RDY + * + * @param v_intr_data_rdy_u8 : The value of data ready interrupt enable + * value | interrupt enable + * ----------|------------------- + * 0x01 | BMI160_ENABLE + * 0x00 | BMI160_DISABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_data_rdy( +u8 v_channel_u8, u8 v_intr_data_rdy_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP SOURCE CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API reads data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_source( +u8 *v_tap_source_u8); + /*! + * @brief This API write data source for the interrupt + * engine for the single and double tap interrupts from the register + * 0x58 bit 3 + * + * + * @param v_tap_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_source( +u8 v_tap_source_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G AND HIGH_G SOURCE CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API Reads Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_high_source( +u8 *v_low_high_source_u8); + /*! + * @brief This API write Data source for the + * interrupt engine for the low and high g interrupts + * from the register 0x58 bit 7 + * + * @param v_low_high_source_u8 : The value of the tap source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_high_source( +u8 v_low_high_source_u8); +/***************************************************************/ +/**\name FUNCTION FOR MOTION SOURCE CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API reads Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_motion_source( +u8 *v_motion_source_u8); + /*! + * @brief This API write Data source for the + * interrupt engine for the nomotion and anymotion interrupts + * from the register 0x59 bit 7 + * + * @param v_motion_source_u8 : + * The value of the any/no motion interrupt source + * value | Description + * ----------|------------------- + * 0x01 | UNFILTER_DATA + * 0x00 | FILTER_DATA + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_motion_source( +u8 v_motion_source_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G DURATION CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_durn( +u8 *v_low_durn_u8); + /*! + * @brief This API is used to write the low_g duration from register + * 0x5A bit 0 to 7 + * + * + * + * + * @param v_low_g_durn_u8 : The value of low_g duration + * + * @note Low_g duration trigger trigger delay according to + * "(v_low_g_durn_u8 * 2.5)ms" in a range from 2.5ms to 640ms. + * the default corresponds delay is 20ms + * @note When low_g data source of interrupt is unfiltered + * the sensor must not be in low power mode + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_durn( +u8 v_low_durn_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G THRESH CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_thres( +u8 *v_low_g_thres_u8); +/*! + * @brief This API is used to write Threshold + * definition for the low-g interrupt from the register 0x5B bit 0 to 7 + * + * + * + * + * @param v_low_g_thres_u8 : The value of low_g threshold + * + * @note Low_g interrupt trigger threshold according to + * (v_low_g_thres_u8 * 7.81)mg for v_low_g_thres_u8 > 0 + * 3.91 mg for v_low_g_thres_u8 = 0 + * The threshold range is form 3.91mg to 2.000mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_thres( +u8 v_low_g_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G HYSTERESIS CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API Reads Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_hyst( +u8 *v_low_hyst_u8); + /*! + * @brief This API write Low-g interrupt hysteresis + * from the register 0x5C bit 0 to 1 + * + * @param v_low_hyst_u8 :The value of low_g hysteresis + * + * @note Low_g hysteresis calculated by v_low_hyst_u8*125 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_hyst( +u8 v_low_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FOR LOW_G MODE CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API reads Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_low_g_mode( +u8 *v_low_g_mode_u8); +/*! + * @brief This API write Low-g interrupt mode + * from the register 0x5C bit 2 + * + * @param v_low_g_mode_u8 : The value of low_g mode + * Value | Description + * ----------|----------------- + * 0 | single-axis + * 1 | axis-summing + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_low_g_mode( +u8 v_low_g_mode_u8); +/***************************************************************/ +/**\name FUNCTION FOR HIGH_G HYST CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API reads High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g_hyst( +u8 *v_high_g_hyst_u8); +/*! + * @brief This API write High-g interrupt hysteresis + * from the register 0x5C bit 6 and 7 + * + * @param v_high_g_hyst_u8 : The value of high hysteresis + * + * @note High_g hysteresis changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g hysteresis + * ----------------|--------------------- + * 2g | high_hy*125 mg + * 4g | high_hy*250 mg + * 8g | high_hy*500 mg + * 16g | high_hy*1000 mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g_hyst( +u8 v_high_g_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FOR HIGH_G DURATION CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g_durn( +u8 *v_high_g_durn_u8); +/*! + * @brief This API is used to write Delay + * time definition for the high-g interrupt from the register + * 0x5D bit 0 to 7 + * + * + * + * @param v_high_g_durn_u8 : The value of high duration + * + * @note High_g interrupt delay triggered according to + * v_high_g_durn_u8 * 2.5ms in a range from 2.5ms to 640ms + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g_durn( +u8 v_high_g_durn_u8); +/***************************************************************/ +/**\name FUNCTION FOR HIGH_G THRESHOLD CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_high_g_thres( +u8 *v_high_g_thres_u8); +/*! + * @brief This API is used to write Threshold + * definition for the high-g interrupt from the register 0x5E 0 to 7 + * + * + * + * + * @param v_high_g_thres_u8 : Pointer holding the value of Threshold + * @note High_g threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | v_high_g_thres_u8*7.81 mg + * 4g | v_high_g_thres_u8*15.63 mg + * 8g | v_high_g_thres_u8*31.25 mg + * 16g | v_high_g_thres_u8*62.5 mg + * @note when v_high_g_thres_u8 = 0 + * accel_range | high_g threshold + * ----------------|--------------------- + * 2g | 3.91 mg + * 4g | 7.81 mg + * 8g | 15.63 mg + * 16g | 31.25 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_high_g_thres( +u8 v_high_g_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR ANY MOTION DURATION CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API reads any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_any_motion_durn( +u8 *v_any_motion_durn_u8); +/*! + * @brief This API write any motion duration + * from the register 0x5F bit 0 and 1 + * + * @param v_any_motion_durn_u8 : The value of any motion duration + * + * @note Any motion duration can be calculated by "v_any_motion_durn_u8 + 1" + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_any_motion_durn( +u8 nomotion); +/***************************************************************/ +/**\name FUNCTION FOR SLOW NO MOTION DURATION CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API read Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_slow_no_motion_durn( +u8 *v_slow_no_motion_u8); + /*! + * @brief This API write Slow/no-motion + * interrupt trigger delay duration from the register 0x5F bit 2 to 7 + * + * @param v_slow_no_motion_u8 :The value of slow no motion duration + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * @note + * @note v_slow_no_motion_u8(5:4)=0b00 -> + * [v_slow_no_motion_u8(3:0) + 1] * 1.28s (1.28s-20.48s) + * @note v_slow_no_motion_u8(5:4)=1 -> + * [v_slow_no_motion_u8(3:0)+5] * 5.12s (25.6s-102.4s) + * @note v_slow_no_motion_u8(5)='1' -> + * [(v_slow_no_motion_u8:0)+11] * 10.24s (112.64s-430.08s); + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_slow_no_motion_durn( +u8 v_slow_no_motion_u8); +/***************************************************************/ +/**\name FUNCTION FOR ANY MOTION THRESHOLD CONFIGURATION */ +/***************************************************************/ +/*! + * @brief This API is used to read threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_any_motion_thres( +u8 *v_any_motion_thres_u8); +/*! + * @brief This API is used to write threshold + * definition for the any-motion interrupt + * from the register 0x60 bit 0 to 7 + * + * + * @param v_any_motion_thres_u8 : The value of any motion threshold + * + * @note any motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | v_any_motion_thres_u8*3.91 mg + * 4g | v_any_motion_thres_u8*7.81 mg + * 8g | v_any_motion_thres_u8*15.63 mg + * 16g | v_any_motion_thres_u8*31.25 mg + * @note when v_any_motion_thres_u8 = 0 + * accel_range | any motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_any_motion_thres( +u8 v_any_motion_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR SLO/NO MOTION THRESHOLD CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API is used to read threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_slow_no_motion_thres( +u8 *v_slow_no_motion_thres_u8); + /*! + * @brief This API is used to write threshold + * for the slow/no-motion interrupt + * from the register 0x61 bit 0 to 7 + * + * + * + * + * @param v_slow_no_motion_thres_u8 : The value of slow no motion threshold + * @note slow no motion threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | v_slow_no_motion_thres_u8*3.91 mg + * 4g | v_slow_no_motion_thres_u8*7.81 mg + * 8g | v_slow_no_motion_thres_u8*15.63 mg + * 16g | v_slow_no_motion_thres_u8*31.25 mg + * @note when v_slow_no_motion_thres_u8 = 0 + * accel_range | slow no motion threshold + * ----------------|--------------------- + * 2g | 1.95 mg + * 4g | 3.91 mg + * 8g | 7.81 mg + * 16g | 15.63 mg + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_slow_no_motion_thres( +u8 v_slow_no_motion_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR SLO/NO MOTION SELECT CONFIGURATION */ +/***************************************************************/ + /*! + * @brief This API is used to read + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_slow_no_motion_select( +u8 *v_intr_slow_no_motion_select_u8); + /*! + * @brief This API is used to write + * the slow/no-motion selection from the register 0x62 bit 0 + * + * + * + * + * @param v_intr_slow_no_motion_select_u8 : + * The value of slow/no-motion select + * value | Behaviour + * ----------|------------------- + * 0x00 | SLOW_MOTION + * 0x01 | NO_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_slow_no_motion_select( +u8 v_intr_slow_no_motion_select_u8); +/***************************************************************/ +/**\name FUNCTION FOR SIGNIFICANT MOTION SELECT CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API is used to select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_significant_motion_select( +u8 *int_sig_mot_sel); + /*! + * @brief This API is used to write, select + * the significant or any motion interrupt from the register 0x62 bit 1 + * + * + * + * + * @param v_intr_significant_motion_select_u8 : + * the value of significant or any motion interrupt selection + * value | Behaviour + * ----------|------------------- + * 0x00 | ANY_MOTION + * 0x01 | SIGNIFICANT_MOTION + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_significant_motion_select( +u8 int_sig_mot_sel); + /*! + * @brief This API is used to read + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_significant_motion_skip( +u8 *v_int_sig_mot_skip_u8); + /*! + * @brief This API is used to write + * the significant skip time from the register 0x62 bit 2 and 3 + * + * + * + * + * @param v_int_sig_mot_skip_u8 : the value of significant skip time + * value | Behaviour + * ----------|------------------- + * 0x00 | skip time 1.5 seconds + * 0x01 | skip time 3 seconds + * 0x02 | skip time 6 seconds + * 0x03 | skip time 12 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_significant_motion_skip( +u8 v_int_sig_mot_skip_u8); + /*! + * @brief This API is used to read + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_significant_motion_proof( +u8 *int_sig_mot_proof); + /*! + * @brief This API is used to write + * the significant proof time from the register 0x62 bit 4 and 5 + * + * + * + * + * @param v_significant_motion_proof_u8 : + * the value of significant proof time + * value | Behaviour + * ----------|------------------- + * 0x00 | proof time 0.25 seconds + * 0x01 | proof time 0.5 seconds + * 0x02 | proof time 1 seconds + * 0x03 | proof time 2 seconds + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_significant_motion_proof( +u8 int_sig_mot_proof); +/***************************************************************/ +/**\name FUNCTION FOR TAP DURATION CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API is used to get the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_DURN_50MS + * 0x01 | BMI160_TAP_DURN_100MS + * 0x03 | BMI160_TAP_DURN_150MS + * 0x04 | BMI160_TAP_DURN_200MS + * 0x05 | BMI160_TAP_DURN_250MS + * 0x06 | BMI160_TAP_DURN_375MS + * 0x07 | BMI160_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_durn( +u8 *v_tap_durn_u8); +/*! + * @brief This API is used to write the tap duration + * from the register 0x63 bit 0 to 2 + * + * + * + * @param v_tap_durn_u8 : The value of tap duration + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_DURN_50MS + * 0x01 | BMI160_TAP_DURN_100MS + * 0x03 | BMI160_TAP_DURN_150MS + * 0x04 | BMI160_TAP_DURN_200MS + * 0x05 | BMI160_TAP_DURN_250MS + * 0x06 | BMI160_TAP_DURN_375MS + * 0x07 | BMI160_TAP_DURN_700MS + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_durn( +u8 v_tap_durn_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP SHOCK CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_SHOCK_50MS + * 0x01 | BMI160_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_shock( +u8 *v_tap_shock_u8); + /*! + * @brief This API write the + * tap shock duration from the register 0x63 bit 2 + * + * @param v_tap_shock_u8 :The value of tap shock + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_SHOCK_50MS + * 0x01 | BMI160_TAP_SHOCK_75MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_shock( +u8 v_tap_shock_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP QUIET CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_QUIET_30MS + * 0x01 | BMI160_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_quiet( +u8 *v_tap_quiet_u8); +/*! + * @brief This API write + * tap quiet duration from the register 0x63 bit 7 + * + * + * @param v_tap_quiet_u8 : The value of tap quiet + * value | Behaviour + * ----------|------------------- + * 0x00 | BMI160_TAP_QUIET_30MS + * 0x01 | BMI160_TAP_QUIET_20MS + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_quiet( +u8 v_tap_quiet_u8); +/***************************************************************/ +/**\name FUNCTION FOR TAP THRESHOLD CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_tap_thres( +u8 *v_tap_thres_u8); + /*! + * @brief This API write Threshold of the + * single/double tap interrupt from the register 0x64 bit 0 to 4 + * + * + * @param v_tap_thres_u8 : The value of single/double tap threshold + * + * @note single/double tap threshold changes according to accel g range + * accel g range can be set by the function "" + * accel_range | single/double tap threshold + * ----------------|--------------------- + * 2g | ((v_tap_thres_u8 + 1) * 62.5)mg + * 4g | ((v_tap_thres_u8 + 1) * 125)mg + * 8g | ((v_tap_thres_u8 + 1) * 250)mg + * 16g | ((v_tap_thres_u8 + 1) * 500)mg + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_tap_thres( +u8 v_tap_thres_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT MODE CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read the threshold for orientation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mode_u8 : The value of threshold for orientation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_mode( +u8 *v_orient_mode_u8); + /*! + * @brief This API write the threshold for orientation interrupt + * from the register 0x65 bit 0 and 1 + * + * @param v_orient_mode_u8 : The value of threshold for orientation + * value | Behaviour + * ----------|------------------- + * 0x00 | symmetrical + * 0x01 | high-asymmetrical + * 0x02 | low-asymmetrical + * 0x03 | symmetrical + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_mode( +u8 v_orient_mode_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT BLOCKING CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read the orient blocking mode + * that is used for the generation of the orientation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_blocking_u8 : The value of orient blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_blocking( +u8 *v_orient_blocking_u8); +/*! + * @brief This API write the orient blocking mode + * that is used for the generation of the orientation interrupt. + * from the register 0x65 bit 2 and 3 + * + * @param v_orient_blocking_u8 : The value of orient blocking mode + * value | Behaviour + * ----------|------------------- + * 0x00 | No blocking + * 0x01 | Theta blocking or acceleration in any axis > 1.5g + * 0x02 | Theta blocking or acceleration slope in any axis > + * - | 0.2g or acceleration in any axis > 1.5g + * 0x03 | Theta blocking or acceleration slope in any axis > + * - | 0.4g or acceleration in any axis > + * - | 1.5g and value of orient is not stable + * - | for at least 100 ms + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_blocking( +u8 v_orient_blocking_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT HYSTERESIS CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_hyst_u8 : The value of orient hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_hyst( +u8 *v_orient_hyst_u8); +/*! + * @brief This API write Orient interrupt + * hysteresis, from the register 0x64 bit 4 to 7 + * + * + * + * @param v_orient_hyst_u8 : The value of orient hysteresis + * + * @note 1 LSB corresponds to 62.5 mg, + * irrespective of the selected accel range + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_hyst( +u8 v_orient_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT THETA CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_theta( +u8 *v_orient_theta_u8); + /*! + * @brief This API write Orient + * blocking angle (0 to 44.8) from the register 0x66 bit 0 to 5 + * + * @param v_orient_theta_u8 : The value of Orient blocking angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_theta( +u8 v_orient_theta_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT OUTPUT ENABLE CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read orient change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_ud_u8 : The value of orient change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orientation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_ud_enable( +u8 *v_orient_ud_u8); +/*! + * @brief This API write orient change + * of up/down bit from the register 0x66 bit 6 + * + * @param v_orient_ud_u8 : The value of orient change of up/down + * value | Behaviour + * ----------|------------------- + * 0x00 | Is ignored + * 0x01 | Generates orientation interrupt + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_ud_enable( +u8 v_orient_ud_u8); +/***************************************************************/ +/**\name FUNCTION FOR ORIENT AXIS ENABLE CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read orientation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_axes_u8 : The value of orient axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_ax_noex + * 0x01 | x = y, y = z, z = x|orient_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_orient_axes_enable( +u8 *v_orient_axes_u8); + /*! + * @brief This API write orientation axes changes + * from the register 0x66 bit 7 + * + * @param v_orient_axes_u8 : The value of orient axes assignment + * value | Behaviour | Name + * ----------|--------------------|------ + * 0x00 | x = x, y = y, z = z|orient_ax_noex + * 0x01 | x = y, y = z, z = x|orient_ax_ex + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_orient_axes_enable( +u8 v_orient_axes_u8); +/***************************************************************/ +/**\name FUNCTION FOR FLAT THETA CONFIGURATION*/ +/***************************************************************/ + /*! + * @brief This API read Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat_theta( +u8 *v_flat_theta_u8); + /*! + * @brief This API write Flat angle (0 to 44.8) for flat interrupt + * from the register 0x67 bit 0 to 5 + * + * @param v_flat_theta_u8 : The value of flat angle + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat_theta( +u8 v_flat_theta_u8); +/***************************************************************/ +/**\name FUNCTION FOR FLAT HOLD CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat_hold( +u8 *v_flat_hold_u8); +/*! + * @brief This API write Flat interrupt hold time; + * from the register 0x68 bit 4 and 5 + * + * @param v_flat_hold_u8 : The value of flat hold time + * value | Behaviour + * ----------|------------------- + * 0x00 | 0ms + * 0x01 | 512ms + * 0x01 | 1024ms + * 0x01 | 2048ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat_hold( +u8 v_flat_hold_u8); +/***************************************************************/ +/**\name FUNCTION FOR FLAT HYSTERESIS CONFIGURATION*/ +/***************************************************************/ +/*! + * @brief This API read flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_intr_flat_hyst( +u8 *v_flat_hyst_u8); +/*! + * @brief This API write flat interrupt hysteresis + * from the register 0x68 bit 0 to 3 + * + * @param v_flat_hyst_u8 : The value of flat hysteresis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_intr_flat_hyst( +u8 v_flat_hyst_u8); +/***************************************************************/ +/**\name FUNCTION FAST OFFSET COMPENSATION FOR ACCEL */ +/***************************************************************/ + /*! + * @brief This API read accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_accel_z( +u8 *v_foc_accel_z_u8); + /*! + * @brief This API write accel offset compensation + * target value for z-axis from the register 0x69 bit 0 and 1 + * + * @param v_foc_accel_z_u8 : the value of accel offset compensation z axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_accel_z( +u8 v_foc_accel_z_u8); +/*! + * @brief This API read accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_accel_y( +u8 *v_foc_accel_y_u8); +/*! + * @brief This API write accel offset compensation + * target value for y-axis + * from the register 0x69 bit 2 and 3 + * + * @param v_foc_accel_y_u8 : the value of accel offset compensation y axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_accel_y( +u8 v_foc_accel_y_u8); +/*! + * @brief This API read accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_accel_x( +u8 *v_foc_accel_x_u8); +/*! + * @brief This API write accel offset compensation + * target value for x-axis is + * from the register 0x69 bit 4 and 5 + * + * @param v_foc_accel_x_u8 : the value of accel offset compensation x axis + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_accel_x( +u8 v_foc_accel_x_u8); +/***************************************************************/ +/**\name FUNCTION FAST OFFSET COMPENSATION FOR GYRO */ +/***************************************************************/ +/*! + * @brief This API write gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * @param v_gyro_off_x_s16 : The value of gyro fast offset x axis data + * @param v_gyro_off_y_s16 : The value of gyro fast offset y axis data + * @param v_gyro_off_z_s16 : The value of gyro fast offset z axis data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_foc_gyro_enable( +u8 v_foc_gyro_u8, s16 *v_gyro_off_x_s16, +s16 *v_gyro_off_y_s16, s16 *v_gyro_off_z_s16); +/***************************************************/ +/**\name FUNCTION FOR NVM*/ +/***************************************************/ + /*! + * @brief This API read NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_nvm_prog_enable( +u8 *v_nvm_prog_u8); + /*! + * @brief This API write NVM program enable + * from the register 0x6A bit 1 + * + * @param v_nvm_prog_u8 : The value of NVM program enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_nvm_prog_enable( +u8 v_nvm_prog_u8); +/***************************************************/ +/**\name FUNCTION FOR SPI MODE*/ +/***************************************************/ +/*! + * @brief This API read to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_spi3( +u8 *v_spi3_u8); +/*! + * @brief This API write to configure SPI + * Interface Mode for primary and OIS interface + * from the register 0x6B bit 0 + * + * @param v_spi3_u8 : The value of SPI mode selection + * Value | Description + * --------|------------- + * 0 | SPI 4-wire mode + * 1 | SPI 3-wire mode + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_spi3( +u8 v_spi3_u8); +/***************************************************/ +/**\name FUNCTION FOR FOC GYRO */ +/***************************************************/ +/*! + * @brief This API read gyro fast offset enable + * from the register 0x69 bit 6 + * + * @param v_foc_gyro_u8 : The value of gyro fast offset enable + * value | Description + * ----------|------------- + * 0 | fast offset compensation disabled + * 1 | fast offset compensation enabled + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_foc_gyro_enable( +u8 *v_foc_gyro_u8); +/***************************************************/ +/**\name FUNCTION FOR I2C WATCHDOG TIMBER */ +/***************************************************/ +/*! + * @brief This API read I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_wdt_select( +u8 *v_i2c_wdt_u8); +/*! + * @brief This API write I2C Watchdog timer + * from the register 0x70 bit 1 + * + * @param v_i2c_wdt_u8 : The value of I2C watch dog timer + * Value | Description + * --------|------------- + * 0 | I2C watchdog v_timeout_u8 after 1 ms + * 1 | I2C watchdog v_timeout_u8 after 50 ms + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE +bmi160_set_i2c_wdt_select(u8 v_i2c_wdt_u8); +/*! + * @brief This API read I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_i2c_wdt_enable( +u8 *v_i2c_wdt_u8); +/*! + * @brief This API write I2C watchdog enable + * from the register 0x70 bit 2 + * + * @param v_i2c_wdt_u8 : The value of I2C watchdog enable + * Value | Description + * --------|------------- + * 0 | DISABLE + * 1 | ENABLE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_i2c_wdt_enable( +u8 v_i2c_wdt_u8); +/***************************************************/ +/**\name FUNCTION FOR IF MODE*/ +/***************************************************/ +/*! + * @brief This API read I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_if_mode( +u8 *v_if_mode_u8); +/*! + * @brief This API write I2C interface configuration(if) moe + * from the register 0x6B bit 4 and 5 + * + * @param v_if_mode_u8 : The value of interface configuration mode + * Value | Description + * --------|------------- + * 0x00 | Primary interface:autoconfig / secondary interface:off + * 0x01 | Primary interface:I2C / secondary interface:OIS + * 0x02 | Primary interface:autoconfig/secondary interface:Magnetometer + * 0x03 | Reserved + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_if_mode( +u8 v_if_mode_u8); +/***************************************************/ +/**\name FUNCTION FOR GYRO SLEEP TRIGGER INTERRUPT CONFIGURATION*/ +/***************************************************/ +/*! + * @brief This API read gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_sleep_trigger( +u8 *v_gyro_sleep_trigger_u8); +/*! + * @brief This API write gyro sleep trigger + * from the register 0x6C bit 0 to 2 + * + * @param v_gyro_sleep_trigger_u8 : The value of gyro sleep trigger + * Value | Description + * --------|------------- + * 0x00 | nomotion: no / Not INT1 pin: no / INT2 pin: no + * 0x01 | nomotion: no / Not INT1 pin: no / INT2 pin: yes + * 0x02 | nomotion: no / Not INT1 pin: yes / INT2 pin: no + * 0x03 | nomotion: no / Not INT1 pin: yes / INT2 pin: yes + * 0x04 | nomotion: yes / Not INT1 pin: no / INT2 pin: no + * 0x05 | anymotion: yes / Not INT1 pin: no / INT2 pin: yes + * 0x06 | anymotion: yes / Not INT1 pin: yes / INT2 pin: no + * 0x07 | anymotion: yes / Not INT1 pin: yes / INT2 pin: yes + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_sleep_trigger( +u8 v_gyro_sleep_trigger_u8); +/*! + * @brief This API read gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_wakeup_trigger( +u8 *v_gyro_wakeup_trigger_u8); +/*! + * @brief This API write gyro wakeup trigger + * from the register 0x6C bit 3 and 4 + * + * @param v_gyro_wakeup_trigger_u8 : The value of gyro wakeup trigger + * Value | Description + * --------|------------- + * 0x00 | anymotion: no / INT1 pin: no + * 0x01 | anymotion: no / INT1 pin: yes + * 0x02 | anymotion: yes / INT1 pin: no + * 0x03 | anymotion: yes / INT1 pin: yes + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_wakeup_trigger( +u8 v_gyro_wakeup_trigger_u8); +/*! + * @brief This API read Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_sleep_state( +u8 *v_gyro_sleep_state_u8); +/*! + * @brief This API write Target state for gyro sleep mode + * from the register 0x6C bit 5 + * + * @param v_gyro_sleep_state_u8 : The value of gyro sleep mode + * Value | Description + * --------|------------- + * 0x00 | Sleep transition to fast wake up state + * 0x01 | Sleep transition to suspend state + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_sleep_state( +u8 v_gyro_sleep_state_u8); +/*! + * @brief This API read gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_wakeup_intr( +u8 *v_gyro_wakeup_intr_u8); +/*! + * @brief This API write gyro wakeup interrupt + * from the register 0x6C bit 6 + * + * @param v_gyro_wakeup_intr_u8 : The valeu of gyro wakeup interrupt + * Value | Description + * --------|------------- + * 0x00 | DISABLE + * 0x01 | ENABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_wakeup_intr( +u8 v_gyro_wakeup_intr_u8); +/***************************************************/ +/**\name FUNCTION FOR ACCEL SELF TEST */ +/***************************************************/ +/*! + * @brief This API read accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_selftest_axis( +u8 *acc_selftest_axis); +/*! + * @brief This API write accel select axis to be self-test + * + * @param v_accel_selftest_axis_u8 : + * The value of accel self test axis selection + * Value | Description + * --------|------------- + * 0x00 | disabled + * 0x01 | x-axis + * 0x02 | y-axis + * 0x03 | z-axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_selftest_axis( +u8 acc_selftest_axis); +/*! + * @brief This API read accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_selftest_sign( +u8 *acc_selftest_sign); +/*! + * @brief This API write accel self test axis sign + * from the register 0x6D bit 2 + * + * @param v_accel_selftest_sign_u8: The value of accel self test axis sign + * Value | Description + * --------|------------- + * 0x00 | negative + * 0x01 | positive + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_selftest_sign( +u8 acc_selftest_sign); +/*! + * @brief This API read accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_selftest_amp( +u8 *acc_selftest_amp); +/*! + * @brief This API write accel self test amplitude + * from the register 0x6D bit 3 + * select amplitude of the selftest deflection: + * + * @param v_accel_selftest_amp_u8 : The value of accel self test amplitude + * Value | Description + * --------|------------- + * 0x00 | LOW + * 0x01 | HIGH + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_selftest_amp( +u8 acc_selftest_amp); +/***************************************************/ +/**\name FUNCTION FOR GYRO SELF TEST */ +/***************************************************/ +/*! + * @brief This API read gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_selftest_start( +u8 *v_gyro_selftest_start_u8); +/*! + * @brief This API write gyro self test trigger + * + * @param v_gyro_selftest_start_u8: The value of gyro self test start + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_selftest_start( +u8 v_gyro_selftest_start_u8); +/***************************************************/ +/**\name FUNCTION FOR SPI/I2C ENABLE */ +/***************************************************/ + /*! + * @brief This API read primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_spi_enable( +u8 *v_spi_enable_u8); + /*! + * @brief This API write primary interface selection I2C or SPI + * from the register 0x70 bit 0 + * + * @param v_spi_enable_u8: The value of Interface selection + * Value | Description + * --------|------------- + * 0x00 | I2C Enable + * 0x01 | I2C DISBALE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_spi_enable( +u8 v_spi_enable_u8); + /*! + * @brief This API read the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_spare0_trim +(u8 *v_spare0_trim_u8); + /*! + * @brief This API write the spare zero + * form register 0x70 bit 3 + * + * + * @param v_spare0_trim_u8: The value of spare zero + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_spare0_trim +(u8 v_spare0_trim_u8); +/***************************************************/ +/**\name FUNCTION FOR NVM COUNTER */ +/***************************************************/ + /*! + * @brief This API read the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_nvm_counter( +u8 *v_nvm_counter_u8); + /*! + * @brief This API write the NVM counter + * form register 0x70 bit 4 to 7 + * + * + * @param v_nvm_counter_u8: The value of NVM counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_nvm_counter( +u8 v_nvm_counter_u8); +/***************************************************/ +/**\name FUNCTION FOR ACCEL MANUAL OFFSET COMPENSATION */ +/***************************************************/ +/*! + * @brief This API read accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_compensation_xaxis( +s8 *v_accel_off_x_s8); +/*! + * @brief This API write accel manual offset compensation of x axis + * from the register 0x71 bit 0 to 7 + * + * + * + * @param v_accel_off_x_s8: + * The value of accel manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_compensation_xaxis( +s8 v_accel_off_x_s8); +/*! + * @brief This API read accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_compensation_yaxis( +s8 *v_accel_off_y_s8); +/*! + * @brief This API write accel manual offset compensation of y axis + * from the register 0x72 bit 0 to 7 + * + * + * + * @param v_accel_off_y_s8: + * The value of accel manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_compensation_yaxis( +s8 v_accel_off_y_s8); +/*! + * @brief This API read accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_compensation_zaxis( +s8 *v_accel_off_z_s8); +/*! + * @brief This API write accel manual offset compensation of z axis + * from the register 0x73 bit 0 to 7 + * + * + * + * @param v_accel_off_z_s8: + * The value of accel manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_compensation_zaxis( +s8 v_accel_off_z_s8); +/***************************************************/ +/**\name FUNCTION FOR GYRO MANUAL OFFSET COMPENSATION */ +/***************************************************/ +/*! + * @brief This API read gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_compensation_xaxis( +s16 *v_gyro_off_x_s16); +/*! + * @brief This API write gyro manual offset compensation of x axis + * from the register 0x74 bit 0 to 7 and 0x77 bit 0 and 1 + * + * + * + * @param v_gyro_off_x_s16: + * The value of gyro manual offset compensation of x axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_compensation_xaxis( +s16 v_gyro_off_x_s16); +/*! + * @brief This API read gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_compensation_yaxis( +s16 *v_gyro_off_y_s16); +/*! + * @brief This API write gyro manual offset compensation of y axis + * from the register 0x75 bit 0 to 7 and 0x77 bit 2 and 3 + * + * + * + * @param v_gyro_off_y_s16: + * The value of gyro manual offset compensation of y axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_compensation_yaxis( +s16 v_gyro_off_y_s16); +/*! + * @brief This API read gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_compensation_zaxis( +s16 *v_gyro_off_z_s16); +/*! + * @brief This API write gyro manual offset compensation of z axis + * from the register 0x76 bit 0 to 7 and 0x77 bit 4 and 5 + * + * + * + * @param v_gyro_off_z_s16: + * The value of gyro manual offset compensation of z axis + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_compensation_zaxis( +s16 v_gyro_off_z_s16); +/*! + * @brief This API writes accel fast offset compensation + * from the register 0x69 bit 0 to 5 + * @brief This API writes each axis individually + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_u8: The value of accel offset compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_axis_u8: The value of accel offset axis selection + * value | axis + * ----------|------------------- + * 0 | FOC_X_AXIS + * 1 | FOC_Y_AXIS + * 2 | FOC_Z_AXIS + * + * @param v_accel_offset_s8: The accel offset value + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_foc_trigger(u8 axis, +u8 foc_acc, s8 *accel_offset); +/*! + * @brief This API write fast accel offset compensation + * it writes all axis together.To the register 0x69 bit 0 to 5 + * FOC_X_AXIS - bit 4 and 5 + * FOC_Y_AXIS - bit 2 and 3 + * FOC_Z_AXIS - bit 0 and 1 + * + * @param v_foc_accel_x_u8: The value of accel offset x compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_y_u8: The value of accel offset y compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_foc_accel_z_u8: The value of accel offset z compensation + * value | Behaviour + * ----------|------------------- + * 0x00 | disable + * 0x01 | +1g + * 0x01 | -1g + * 0x01 | 0g + * + * @param v_accel_off_x_s8: The value of accel offset x axis + * @param v_accel_off_y_s8: The value of accel offset y axis + * @param v_accel_off_z_s8: The value of accel offset z axis + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_accel_foc_trigger_xyz(u8 v_foc_accel_x_u8, +u8 v_foc_accel_y_u8, u8 v_foc_accel_z_u8, +s8 *acc_off_x, s8 *acc_off_y, s8 *acc_off_z); +/***************************************************/ +/**\name FUNCTION FOR ACEL AND GYRO OFFSET ENABLE */ +/***************************************************/ +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_accel_offset_enable( +u8 *acc_off_en); +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 6 + * + * + * + * @param v_accel_off_enable_u8: The value of accel offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_accel_offset_enable( +u8 acc_off_en); +/*! + * @brief This API read the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_gyro_offset_enable( +u8 *v_gyro_off_enable_u8); +/*! + * @brief This API write the accel offset enable bit + * from the register 0x77 bit 7 + * + * + * + * @param v_gyro_off_enable_u8: The value of gyro offset enable + * value | Description + * ----------|-------------- + * 0x01 | ENABLE + * 0x00 | DISABLE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_gyro_offset_enable( +u8 v_gyro_off_enable_u8); +/***************************************************/ +/**\name FUNCTION FOR STEP COUNTER INTERRUPT */ +/***************************************************/ +/*! + * @brief This API reads step counter value + * form the register 0x78 and 0x79 + * + * + * + * + * @param v_step_cnt_s16 : The value of step counter + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_step_count(s16 *v_step_cnt_s16); + /*! + * @brief This API Reads + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : The value of step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_step_config( +u16 *v_step_config_u16); + /*! + * @brief This API write + * step counter configuration + * from the register 0x7A bit 0 to 7 + * and from the register 0x7B bit 0 to 2 and 4 to 7 + * + * + * @param v_step_config_u16 : + * the value of Enable step configuration + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_config( +u16 v_step_config_u16); + /*! + * @brief This API read enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_step_counter_enable( +u8 *v_step_counter_u8); + /*! + * @brief This API write enable step counter + * from the register 0x7B bit 3 + * + * + * @param v_step_counter_u8 : The value of step counter enable + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_counter_enable( +u8 v_step_counter_u8); + /*! + * @brief This API set Step counter modes + * + * + * @param v_step_mode_u8 : The value of step counter mode + * value | mode + * ----------|----------- + * 0 | BMI160_STEP_NORMAL_MODE + * 1 | BMI160_STEP_SENSITIVE_MODE + * 2 | BMI160_STEP_ROBUST_MODE + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_step_mode(u8 v_step_mode_u8); +/*! + * @brief This API used to trigger the signification motion + * interrupt + * + * + * @param v_significant_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | BMI160_MAP_INTR1 + * 1 | BMI160_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_map_significant_motion_intr( +u8 v_significant_u8); +/*! + * @brief This API used to trigger the step detector + * interrupt + * + * + * @param v_step_detector_u8 : The value of interrupt selection + * value | interrupt + * ----------|----------- + * 0 | BMI160_MAP_INTR1 + * 1 | BMI160_MAP_INTR2 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_map_step_detector_intr( +u8 v_step_detector_u8); + /*! + * @brief This API used to clear the step counter interrupt + * interrupt + * + * + * @param : None + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_clear_step_counter(void); +/***************************************************/ +/**\name FUNCTION FOR STEP COMMAND REGISTER WRITE */ +/***************************************************/ + /*! + * @brief This API writes value to the register 0x7E bit 0 to 7 + * + * + * @param v_command_reg_u8 : The value to write command register + * value | Description + * ---------|-------------------------------------------------------- + * 0x00 | Reserved + * 0x03 | Starts fast offset calibration for the accel and gyro + * 0x10 | Sets the PMU mode for the Accelerometer to suspend + * 0x11 | Sets the PMU mode for the Accelerometer to normal + * 0x12 | Sets the PMU mode for the Accelerometer Lowpower + * 0x14 | Sets the PMU mode for the Gyroscope to suspend + * 0x15 | Sets the PMU mode for the Gyroscope to normal + * 0x16 | Reserved + * 0x17 | Sets the PMU mode for the Gyroscope to fast start-up + * 0x18 | Sets the PMU mode for the Magnetometer to suspend + * 0x19 | Sets the PMU mode for the Magnetometer to normal + * 0x1A | Sets the PMU mode for the Magnetometer to Lowpower + * 0xB0 | Clears all data in the FIFO + * 0xB1 | Resets the interrupt engine + * 0xB2 | step_cnt_clr Clears the step counter + * 0xB6 | Triggers a reset + * 0x37 | See extmode_en_last + * 0x9A | See extmode_en_last + * 0xC0 | Enable the extended mode + * 0xC4 | Erase NVM cell + * 0xC8 | Load NVM cell + * 0xF0 | Reset acceleration data path + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_command_register( +u8 v_command_reg_u8); +/***************************************************/ +/**\name FUNCTION FOR PAGE ENABLE */ +/***************************************************/ + /*! + * @brief This API read target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_target_page( +u8 *v_target_page_u8); + /*! + * @brief This API write target page from the register 0x7F bit 4 and 5 + * + * @param v_target_page_u8: The value of target page + * value | page + * ---------|----------- + * 0 | User data/configure page + * 1 | Chip level trim/test page + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_target_page( +u8 v_target_page_u8); + /*! + * @brief This API read page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_paging_enable( +u8 *v_page_enable_u8); + /*! + * @brief This API write page enable from the register 0x7F bit 7 + * + * + * + * @param v_page_enable_u8: The value of page enable + * value | page + * ---------|----------- + * 0 | DISABLE + * 1 | ENABLE + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_paging_enable( +u8 v_page_enable_u8); + /*! + * @brief This API read + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_get_pullup_configuration( +u8 *v_control_pullup_u8); + /*! + * @brief This API write + * pull up configuration from the register 0X85 bit 4 an 5 + * + * + * + * @param v_control_pullup_u8: The value of pull up register + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_pullup_configuration( +u8 v_control_pullup_u8); +/***************************************************/ +/**\name FUNCTION FOR BMM150 */ +/***************************************************/ + /*! + * @brief This function used for initialize the bmm150 sensor + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_interface_init(void); + /*! + * @brief This function used for set the mag power control + * bit enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_wakeup(void); + /*! + * @brief This function used for read the trim values of magnetometer + * + * @note + * Before reading the mag trimming values + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_bmm150_mag_trim(void); + /*! + * @brief This function used for read the compensated value of mag + * Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_compensate_xyz( +struct bmi160_mag_xyz_s32_t *mag_comp_xyz); +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_compensate_xyz_raw( +struct bmi160_mag_xyz_s32_t *mag_comp_xyz, struct bmi160_mag_xyzr_t mag_xyzr); + +/*! + * @brief This API used to get the compensated BMM150-X data + * the out put of X as s32 + * Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_x_s16 : The value of mag raw X data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated X data value output as s32 + * + */ +s32 bmi160_bmm150_mag_compensate_X(s16 v_mag_data_x_s16, u16 v_data_r_u16); +/*! + * @brief This API used to get the compensated BMM150-Y data + * the out put of Y as s32 + * Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_y_s16 : The value of mag raw Y data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Y data value output as s32 + */ +s32 bmi160_bmm150_mag_compensate_Y(s16 v_mag_data_y_s16, u16 v_data_r_u16); +/*! + * @brief This API used to get the compensated BMM150-Z data + * the out put of Z as s32 + * Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * + * @param v_mag_data_z_s16 : The value of mag raw Z data + * @param v_data_r_u16 : The value of mag R data + * + * @return results of compensated Z data value output as s32 + */ +s32 bmi160_bmm150_mag_compensate_Z(s16 v_mag_data_z_s16, u16 v_data_r_u16); +/*! + * @brief This API used to set the pre-set modes of bmm150 + * The pre-set mode setting is depend on data rate and xy and z repetitions + * + * @note + * Before set the mag preset mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_mode_u8: The value of pre-set mode selection value + * value | pre_set mode + * ----------|------------ + * 1 | BMI160_MAG_PRESETMODE_LOWPOWER + * 2 | BMI160_MAG_PRESETMODE_REGULAR + * 3 | BMI160_MAG_PRESETMODE_HIGHACCURACY + * 4 | BMI160_MAG_PRESETMODE_ENHANCED + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_bmm150_mag_presetmode(u8 mode); +/*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two points are addressed + * @note + * 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note + * 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @param v_mag_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | FORCE_MODE + * 1 | SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bmm150_mag_set_power_mode(u8 mag_pow_mode); + /*! + * @brief This function used for set the magnetometer + * power mode. + * @note + * Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of mag power mode + * value | mode + * ----------|------------ + * 0 | BMI160_MAG_FORCE_MODE + * 1 | BMI160_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_bmm150_mag_and_secondary_if_power_mode( +u8 v_mag_sec_if_pow_mode_u8); +/***************************************************/ +/**\name FUNCTIONS FOR AKM09911 AND AKM09912*/ +/***************************************************/ + /*! + * @brief This function used for initialize + * the AKM09911 and AKM09912 sensor + * + * + * @param v_akm_i2c_address_u8: The value of device address + * AKM sensor | Slave address + * --------------|--------------------- + * AKM09911 | AKM09911_I2C_ADDR_1 + * - | and AKM09911_I2C_ADDR_2 + * AKM09912 | AKM09912_I2C_ADDR_1 + * - | AKM09912_I2C_ADDR_2 + * - | AKM09912_I2C_ADDR_3 + * - | AKM09912_I2C_ADDR_4 + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm_mag_interface_init( +u8 v_akm_i2c_address_u8); + /*! + * @brief This function used for read the sensitivity data of + * AKM09911 and AKM09912 + * + * @note Before reading the mag sensitivity values + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_bst_akm_sensitivity_data(void); +/*! + * @brief This API used to get the compensated X data + * of AKM09911 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 bmi160_bst_akm09911_compensate_X(s16 v_bst_akm_x_s16); +/*! + * @brief This API used to get the compensated Y data + * of AKM09911 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 bmi160_bst_akm09911_compensate_Y(s16 v_bst_akm_y_s16); +/*! + * @brief This API used to get the compensated Z data + * of AKM09911 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 bmi160_bst_akm09911_compensate_Z(s16 v_bst_akm_z_s16); +/*! + * @brief This API used to get the compensated X data + * of AKM09912 the out put of X as s32 + * @note Before start reading the mag compensated X data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_x_s16 : The value of X data + * + * @return results of compensated X data value output as s32 + * + */ +s32 bmi160_bst_akm09912_compensate_X(s16 v_bst_akm_x_s16); +/*! + * @brief This API used to get the compensated Y data + * of AKM09912 the out put of Y as s32 + * @note Before start reading the mag compensated Y data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_y_s16 : The value of Y data + * + * @return results of compensated Y data value output as s32 + * + */ +s32 bmi160_bst_akm09912_compensate_Y(s16 v_bst_akm_y_s16); +/*! + * @brief This API used to get the compensated Z data + * of AKM09912 the out put of Z as s32 + * @note Before start reading the mag compensated Z data + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * + * @param v_bst_akm_z_s16 : The value of Z data + * + * @return results of compensated Z data value output as s32 + * + */ +s32 bmi160_bst_akm09912_compensate_Z(s16 v_bst_akm_z_s16); + /*! + * @brief This function used for read the compensated value of + * AKM09911 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm09911_compensate_xyz( +struct bmi160_mag_xyz_s32_t *bst_akm_xyz); + /*! + * @brief This function used for read the compensated value of + * AKM09912 + * @note Before start reading the mag compensated data's + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm09912_compensate_xyz( +struct bmi160_mag_xyz_s32_t *bst_akm_xyz); +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm09912_compensate_xyz_raw( +struct bmi160_mag_xyz_s32_t *bst_akm_xyz); +/*! + * @brief This function used for set the AKM09911 and AKM09912 + * power mode. + * @note Before set the AKM power mode + * make sure the following two points are addressed + * @note 1. Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * @note 2. And also confirm the secondary-interface power mode + * is not in the SUSPEND mode. + * by using the function bmi160_get_mag_pmu_status(). + * If the secondary-interface power mode is in SUSPEND mode + * set the value of 0x19(NORMAL mode)by using the + * bmi160_set_command_register(0x19) function. + * + * @param v_akm_pow_mode_u8 : The value of akm power mode + * value | Description + * ---------|-------------------- + * 0 | AKM_POWER_DOWN_MODE + * 1 | AKM_SINGLE_MEAS_MODE + * 2 | FUSE_ROM_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_akm_set_powermode(u8 v_akm_pow_mode_u8); + /*! + * @brief This function used for set the magnetometer + * power mode of AKM09911 and AKM09912 + * @note Before set the mag power mode + * make sure the following two point is addressed + * Make sure the mag interface is enabled or not, + * by using the bmi160_get_if_mode() function. + * If mag interface is not enabled set the value of 0x02 + * to the function bmi160_get_if_mode(0x02) + * + * @param v_mag_sec_if_pow_mode_u8 : The value of secondary if power mode + * value | Description + * ---------|-------------------- + * 0 | BMI160_MAG_FORCE_MODE + * 1 | BMI160_MAG_SUSPEND_MODE + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_set_bst_akm_and_secondary_if_powermode( +u8 v_mag_sec_if_pow_mode_u8); +/***************************************************/ +/**\name FUNCTIONS FOR YAMAH-YAS532 */ +/***************************************************/ +/*! + * @brief This function used for read the YAMAH-YAS532 init + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas532_mag_interface_init( +void); +/*! + * @brief This function used to set the YAS532 initial values + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_set_initial_values(void); +/*! + * @brief This function used for YAS532 offset correction + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_magnetic_measure_set_offset( +void); +/*! + * @brief This function used for read the + * YAMAHA YAS532 calibration data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas532_calib_values(void); +/*! + * @brief This function used for calculate the + * YAS532 read the linear data + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_xy1y2_to_linear( +u16 *v_xy1y2_u16, s32 *xy1y2_linear); +/*! + * @brief This function used for read the YAS532 sensor data + * @param v_acquisition_command_u8: used to set the data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param v_busy_u8 : used to get the busy flay for sensor data read + * @param v_temp_u16 : used to get the temperature data + * @param v_xy1y2_u16 : used to get the sensor xy1y2 data + * @param v_overflow_u8 : used to get the overflow data + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_normal_measurement_data( +u8 v_acquisition_command_u8, u8 *v_busy_u8, +u16 *v_temp_u16, u16 *v_xy1y2_u16, u8 *v_overflow_u8); +/*! + * @brief This function used for YAS532 sensor data + * @param v_acquisition_command_u8 : the value of CMDR + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * @param xyz_data : the vector xyz output + * @param v_overflow_s8 : the value of overflow + * @param v_temp_correction_u8 : the value of temperate correction enable + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_measurement_xyz_data( +struct yas532_vector *xyz_data, u8 *v_overflow_s8, u8 v_temp_correction_u8, +u8 v_acquisition_command_u8); +/*! + * @brief This function used for YAS532 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_acquisition_command_register( +u8 v_command_reg_data_u8); +/*! + * @brief This function used write offset of YAS532 + * + * @param p_offset_s8 : The value of offset to write + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas532_set_offset( +const s8 *p_offset_s8); +/*! + * @brief This function used to init the YAMAH-YAS537 + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * +*/ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_mag_interface_init( +void); +/*! + * @brief This function used for read the + * YAMAHA YAS537 calibration data + * + * + * @param v_rcoil_u8 : The value of r coil + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_calib_values( +u8 v_rcoil_u8); +/*! + * @brief This function used for YAS537 write data acquisition + * command register write + * @param v_command_reg_data_u8 : the value of data acquisition + * acquisition_command | operation + * ---------------------|------------------------- + * 0x17 | turn on the acquisition coil + * - | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Deferred acquisition mode + * 0x07 | turn on the acquisition coil + * _ | set direction of the coil + * _ | (x and y as minus(-)) + * _ | Normal acquisition mode + * 0x11 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Deferred acquisition mode + * 0x01 | turn OFF the acquisition coil + * _ | set direction of the coil + * _ | (x and y as plus(+)) + * _ | Normal acquisition mode + * + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yas537_acquisition_command_register( +u8 v_command_reg_data_u8); + +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_coil_stat_u8: The value of R coil status + * @param v_busy_u8: The value of busy status + * @param v_temperature_u16: The value of temperature + * @param xy1y2: The value of raw xy1y2 data + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_read_xy1y2_data( +u8 *v_coil_stat_u8, u8 *v_busy_u8, +u16 *v_temperature_u16, u16 *xy1y2, u8 *v_ouflow_u8); +/*! + * @brief This function used for read the + * YAMAHA YAS537 xy1y2 data + * + * @param v_ouflow_u8: The value of overflow + * + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_bst_yamaha_yas537_measure_xyz_data( +u8 *v_ouflow_u8, struct yas_vector *vector_xyz); + +/***************************************************/ +/**\name FUNCTIONS FOR FIFO DATA READ */ +/***************************************************/ +/*! + * @brief This function used for reading the + * fifo data of header less mode + * + * + * + * @note Configure the below functions for FIFO header less mode + * @note 1. bmi160_set_fifo_down_gyro + * @note 2. bmi160_set_gyro_fifo_filter_data + * @note 3. bmi160_set_fifo_down_accel + * @note 4. bmi160_set_accel_fifo_filter_dat + * @note 5. bmi160_set_fifo_mag_enable + * @note 6. bmi160_set_fifo_accel_enable + * @note 7. bmi160_set_fifo_gyro_enable + * @note For interrupt configuration + * @note 1. bmi160_set_intr_fifo_full + * @note 2. bmi160_set_intr_fifo_wm + * @note 3. bmi160_set_fifo_tag_intr2_enable + * @note 4. bmi160_set_fifo_tag_intr1_enable + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_fifo_headerless_mode( +void); +/*! + * @brief This function used for reading the + * fifo data of header less mode for using user defined length + * + * + * @param v_fifo_user_length_u16: The value of length of fifo read data + * + * @note Configure the below functions for FIFO header less mode + * @note 1. bmi160_set_fifo_down_gyro + * @note 2. bmi160_set_gyro_fifo_filter_data + * @note 3. bmi160_set_fifo_down_accel + * @note 4. bmi160_set_accel_fifo_filter_dat + * @note 5. bmi160_set_fifo_mag_enable + * @note 6. bmi160_set_fifo_accel_enable + * @note 7. bmi160_set_fifo_gyro_enable + * @note For interrupt configuration + * @note 1. bmi160_set_intr_fifo_full + * @note 2. bmi160_set_intr_fifo_wm + * @note 3. bmi160_set_fifo_tag_intr2_enable + * @note 4. bmi160_set_fifo_tag_intr1_enable + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE +bmi160_read_fifo_headerless_mode_user_defined_length( +u16 v_fifo_user_length_u16); +/*! + * @brief This function used for reading the + * fifo data of header mode + * + * + * @note Configure the below functions for FIFO header mode + * @note 1. bmi160_set_fifo_down_gyro() + * @note 2. bmi160_set_gyro_fifo_filter_data() + * @note 3. bmi160_set_fifo_down_accel() + * @note 4. bmi160_set_accel_fifo_filter_dat() + * @note 5. bmi160_set_fifo_mag_enable() + * @note 6. bmi160_set_fifo_accel_enable() + * @note 7. bmi160_set_fifo_gyro_enable() + * @note 8. bmi160_set_fifo_header_enable() + * @note For interrupt configuration + * @note 1. bmi160_set_intr_fifo_full() + * @note 2. bmi160_set_intr_fifo_wm() + * @note 3. bmi160_set_fifo_tag_intr2_enable() + * @note 4. bmi160_set_fifo_tag_intr1_enable() + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_fifo_header_data( +void); +/*! + * @brief This function used for reading the + * fifo data of header mode for using user defined length + * + * + * @note Configure the below functions for FIFO header mode + * @note 1. bmi160_set_fifo_down_gyro() + * @note 2. bmi160_set_gyro_fifo_filter_data() + * @note 3. bmi160_set_fifo_down_accel() + * @note 4. bmi160_set_accel_fifo_filter_dat() + * @note 5. bmi160_set_fifo_mag_enable() + * @note 6. bmi160_set_fifo_accel_enable() + * @note 7. bmi160_set_fifo_gyro_enable() + * @note 8. bmi160_set_fifo_header_enable() + * @note For interrupt configuration + * @note 1. bmi160_set_intr_fifo_full() + * @note 2. bmi160_set_intr_fifo_wm() + * @note 3. bmi160_set_fifo_tag_intr2_enable() + * @note 4. bmi160_set_fifo_tag_intr1_enable() + * + * @note The fifo reads the whole 1024 bytes + * and processing the data + * + * @return results of bus communication function + * @retval 0 -> Success + * @retval -1 -> Error + * + * + */ +BMI160_RETURN_FUNCTION_TYPE bmi160_read_fifo_header_data_user_defined_length( +u16 v_fifo_user_length_u16); +/*! + * @brief This function used for reading + * bmi160_t structure + * + * @return the reference and values of bmi160_t + * + * +*/ +struct bmi160_t *bmi160_get_ptr(void); + +#endif + diff --git a/drivers/input/misc/bmi160_driver.c b/drivers/input/misc/bmi160_driver.c new file mode 100755 index 00000000000..627440c160a --- /dev/null +++ b/drivers/input/misc/bmi160_driver.c @@ -0,0 +1,5283 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bmi160_driver.c + * @date 2015/08/17 14:40 + * @id "09afbe6" + * @version 1.4 + * + * @brief + * The core code of BMI160 device driver + * + * @detail + * This file implements the core code of BMI160 device driver, + * which includes hardware related functions, input device register, + * device attribute files, etc. +*/ + +#include "bmi160_driver.h" +#include +#include +#include +#include + +#define I2C_BURST_READ_MAX_LEN (256) +#define BMI160_STORE_COUNT (6000) +#define LMADA (1) +uint64_t g_current_apts_us; +static unsigned char g_fifo_data_arr[2048];/*1024 + 12*4*/ + +/*BMI power supply VDD 1.71V-3.6V VIO 1.2-3.6V */ +#define BMI160_VDD_MIN_UV 1750000 +#define BMI160_VDD_MAX_UV 3600000 +#define BMI160_VIO_MIN_UV 1200000 +#define BMI160_VIO_MAX_UV 3600000 + +static struct sensors_classdev accel_cdev = { + .name = "bmi160-accel", + .vendor = "Bosch Corporation", + .version = 1, + .handle = SENSORS_ACCELERATION_HANDLE, + .type = SENSOR_TYPE_ACCELEROMETER, + .max_range = "156.8", + .resolution = "0.00781", + .sensor_power = "0.13", + .min_delay = 1000, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_calibrate = NULL, + .sensors_write_cal_params = NULL, + .params = NULL, +}; + +static struct sensors_classdev gyro_cdev = { + .name = "bmi160-gyro", + .vendor = "Bosch Corporation", + .version = 1, + .handle = SENSORS_GYROSCOPE_HANDLE, + .type = SENSOR_TYPE_GYROSCOPE, + .max_range = "35", + .resolution = "0.06", + .sensor_power = "0.13", + .min_delay = 2000, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_calibrate = NULL, + .sensors_write_cal_params = NULL, + .params = NULL, +}; + +enum BMI_SENSOR_INT_T { + /* Interrupt enable0*/ + BMI_ANYMO_X_INT = 0, + BMI_ANYMO_Y_INT, + BMI_ANYMO_Z_INT, + BMI_D_TAP_INT, + BMI_S_TAP_INT, + BMI_ORIENT_INT, + BMI_FLAT_INT, + /* Interrupt enable1*/ + BMI_HIGH_X_INT, + BMI_HIGH_Y_INT, + BMI_HIGH_Z_INT, + BMI_LOW_INT, + BMI_DRDY_INT, + BMI_FFULL_INT, + BMI_FWM_INT, + /* Interrupt enable2 */ + BMI_NOMOTION_X_INT, + BMI_NOMOTION_Y_INT, + BMI_NOMOTION_Z_INT, + BMI_STEP_DETECTOR_INT, + INT_TYPE_MAX +}; + +/*bmi fifo sensor type combination*/ +enum BMI_SENSOR_FIFO_COMBINATION { + BMI_FIFO_A = 0, + BMI_FIFO_G, + BMI_FIFO_M, + BMI_FIFO_G_A, + BMI_FIFO_M_A, + BMI_FIFO_M_G, + BMI_FIFO_M_G_A, + BMI_FIFO_COM_MAX +}; + +/*bmi fifo analyse return err status*/ +enum BMI_FIFO_ANALYSE_RETURN_T { + FIFO_OVER_READ_RETURN = -10, + FIFO_SENSORTIME_RETURN = -9, + FIFO_SKIP_OVER_LEN = -8, + FIFO_M_G_A_OVER_LEN = -7, + FIFO_M_G_OVER_LEN = -6, + FIFO_M_A_OVER_LEN = -5, + FIFO_G_A_OVER_LEN = -4, + FIFO_M_OVER_LEN = -3, + FIFO_G_OVER_LEN = -2, + FIFO_A_OVER_LEN = -1 +}; + +/*!bmi sensor generic power mode enum */ +enum BMI_DEV_OP_MODE { + SENSOR_PM_NORMAL = 0, + SENSOR_PM_LP1, + SENSOR_PM_SUSPEND, + SENSOR_PM_LP2 +}; + +/*! bmi acc sensor power mode enum */ +enum BMI_ACC_PM_TYPE { + BMI_ACC_PM_NORMAL = 0, + BMI_ACC_PM_LP1, + BMI_ACC_PM_SUSPEND, + BMI_ACC_PM_LP2, + BMI_ACC_PM_MAX +}; + +/*! bmi gyro sensor power mode enum */ +enum BMI_GYRO_PM_TYPE { + BMI_GYRO_PM_NORMAL = 0, + BMI_GYRO_PM_FAST_START, + BMI_GYRO_PM_SUSPEND, + BMI_GYRO_PM_MAX +}; + +/*! bmi mag sensor power mode enum */ +enum BMI_MAG_PM_TYPE { + BMI_MAG_PM_NORMAL = 0, + BMI_MAG_PM_LP1, + BMI_MAG_PM_SUSPEND, + BMI_MAG_PM_LP2, + BMI_MAG_PM_MAX +}; + + +/*! bmi sensor support type*/ +enum BMI_SENSOR_TYPE { + BMI_ACC_SENSOR, + BMI_GYRO_SENSOR, + BMI_MAG_SENSOR, + BMI_SENSOR_TYPE_MAX +}; + +/*!bmi sensor generic power mode enum */ +enum BMI_AXIS_TYPE { + X_AXIS = 0, + Y_AXIS, + Z_AXIS, + AXIS_MAX +}; + +/*!bmi sensor generic intterrupt enum */ +enum BMI_INT_TYPE { + BMI160_INT0 = 0, + BMI160_INT1, + BMI160_INT_MAX +}; + +/*! bmi sensor time resolution definition*/ +enum BMI_SENSOR_TIME_RS_TYPE { + TS_0_78_HZ = 1,/*0.78HZ*/ + TS_1_56_HZ,/*1.56HZ*/ + TS_3_125_HZ,/*3.125HZ*/ + TS_6_25_HZ,/*6.25HZ*/ + TS_12_5_HZ,/*12.5HZ*/ + TS_25_HZ,/*25HZ, odr=6*/ + TS_50_HZ,/*50HZ*/ + TS_100_HZ,/*100HZ*/ + TS_200_HZ,/*200HZ*/ + TS_400_HZ,/*400HZ*/ + TS_800_HZ,/*800HZ*/ + TS_1600_HZ,/*1600HZ*/ + TS_MAX_HZ +}; + +/*! bmi sensor interface mode */ +enum BMI_SENSOR_IF_MODE_TYPE { + /*primary interface:autoconfig/secondary interface off*/ + P_AUTO_S_OFF = 0, + /*primary interface:I2C/secondary interface:OIS*/ + P_I2C_S_OIS, + /*primary interface:autoconfig/secondary interface:Magnetometer*/ + P_AUTO_S_MAG, + /*interface mode reseved*/ + IF_MODE_RESEVED + +}; + +/*! bmi160 acc/gyro calibration status in H/W layer */ +enum BMI_CALIBRATION_STATUS_TYPE { + /*BMI FAST Calibration ready x/y/z status*/ + BMI_ACC_X_FAST_CALI_RDY = 0, + BMI_ACC_Y_FAST_CALI_RDY, + BMI_ACC_Z_FAST_CALI_RDY +}; + +unsigned int reg_op_addr; + +static const int bmi_pmu_cmd_acc_arr[BMI_ACC_PM_MAX] = { + /*!bmi pmu for acc normal, low power1, + * suspend, low power2 mode command */ + CMD_PMU_ACC_NORMAL, + CMD_PMU_ACC_LP1, + CMD_PMU_ACC_SUSPEND, + CMD_PMU_ACC_LP2 +}; + +static const int bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_MAX] = { + /*!bmi pmu for gyro normal, fast startup, + * suspend mode command */ + CMD_PMU_GYRO_NORMAL, + CMD_PMU_GYRO_FASTSTART, + CMD_PMU_GYRO_SUSPEND +}; + +static const int bmi_pmu_cmd_mag_arr[BMI_MAG_PM_MAX] = { + /*!bmi pmu for mag normal, low power1, + * suspend, low power2 mode command */ + CMD_PMU_MAG_NORMAL, + CMD_PMU_MAG_LP1, + CMD_PMU_MAG_SUSPEND, + CMD_PMU_MAG_LP2 +}; + +static const char *bmi_axis_name[AXIS_MAX] = {"x", "y", "z"}; + +static const int bmi_interrupt_type[] = { + /*!bmi interrupt type */ + /* Interrupt enable0 , index=0~6*/ + BMI160_ANY_MOTION_X_ENABLE, + BMI160_ANY_MOTION_Y_ENABLE, + BMI160_ANY_MOTION_Z_ENABLE, + BMI160_DOUBLE_TAP_ENABLE, + BMI160_SINGLE_TAP_ENABLE, + BMI160_ORIENT_ENABLE, + BMI160_FLAT_ENABLE, + /* Interrupt enable1, index=7~13*/ + BMI160_HIGH_G_X_ENABLE, + BMI160_HIGH_G_Y_ENABLE, + BMI160_HIGH_G_Z_ENABLE, + BMI160_LOW_G_ENABLE, + BMI160_DATA_RDY_ENABLE, + BMI160_FIFO_FULL_ENABLE, + BMI160_FIFO_WM_ENABLE, + /* Interrupt enable2, index = 14~17*/ + BMI160_NOMOTION_X_ENABLE, + BMI160_NOMOTION_Y_ENABLE, + BMI160_NOMOTION_Z_ENABLE, + BMI160_STEP_DETECTOR_EN +}; + +/*! bmi sensor time depend on ODR*/ +struct bmi_sensor_time_odr_tbl { + u32 ts_duration_lsb; + u32 ts_duration_us; + u32 ts_delat;/*sub current delat fifo_time*/ +}; + +struct bmi160_axis_data_t { + s16 x; + s16 y; + s16 z; +}; +struct bmi160_value_t { + struct bmi160_axis_data_t acc; + struct bmi160_axis_data_t gyro; +#ifdef BMI160_MAG_INTERFACE_SUPPORT + struct bmi160_axis_data_t mag; +#endif + int64_t ts_intvl; +}; +struct bmi160_type_mapping_type { + + /*! bmi16x sensor chip id */ + uint16_t chip_id; + + /*! bmi16x chip revision code */ + uint16_t revision_id; + + /*! bmi160 sensor name */ + const char *sensor_name; +}; + +struct bmi160_store_info_t { + uint8_t current_frm_cnt; + uint64_t current_apts_us[2]; + uint8_t fifo_ts_total_frmcnt; + uint64_t fifo_time; +}; +static struct workqueue_struct *reportdata_wq; +#define FIFO_READ_LENGTH_RECOMMENDED (67) +#define FIFO_SENSORTIME_OVERFLOW_MASK (0x1000000) +#define FIFO_SENSORTIME_RESOLUTION (390625) + +static uint8_t s_fifo_data_buf[FIFO_DATA_BUFSIZE * 2] = {0}; +static uint64_t sensor_time_old = 0; +static uint64_t sensor_time_new = 0; +static uint64_t host_time_old = 0; +static uint64_t host_time_new = 0; + +#define BMI_RING_BUF_SIZE 100 + +static struct bmi160_value_t bmi_ring_buf[BMI_RING_BUF_SIZE]; +static int s_ring_buf_head = 0; +static int s_ring_buf_tail = 0; + + +uint64_t get_current_timestamp(void) +{ + uint64_t ts; + struct timeval tv; + + do_gettimeofday(&tv); + ts = (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec; + + return ts; +} + + +/*! sensor support type map */ +static const struct bmi160_type_mapping_type sensor_type_map[] = { + + {SENSOR_CHIP_ID_BMI, SENSOR_CHIP_REV_ID_BMI, "BMI160/162AB"}, + {SENSOR_CHIP_ID_BMI_C2, SENSOR_CHIP_REV_ID_BMI, "BMI160C2"}, + {SENSOR_CHIP_ID_BMI_C3, SENSOR_CHIP_REV_ID_BMI, "BMI160C3"}, + +}; + +/*!bmi160 sensor time depends on ODR */ +static const struct bmi_sensor_time_odr_tbl + sensortime_duration_tbl[TS_MAX_HZ] = { + {0x010000, 2560000, 0x00ffff},/*2560ms, 0.39hz, odr=resver*/ + {0x008000, 1280000, 0x007fff},/*1280ms, 0.78hz, odr_acc=1*/ + {0x004000, 640000, 0x003fff},/*640ms, 1.56hz, odr_acc=2*/ + {0x002000, 320000, 0x001fff},/*320ms, 3.125hz, odr_acc=3*/ + {0x001000, 160000, 0x000fff},/*160ms, 6.25hz, odr_acc=4*/ + {0x000800, 80000, 0x0007ff},/*80ms, 12.5hz*/ + {0x000400, 40000, 0x0003ff},/*40ms, 25hz, odr_acc = odr_gyro =6*/ + {0x000200, 20000, 0x0001ff},/*20ms, 50hz, odr = 7*/ + {0x000100, 10000, 0x0000ff},/*10ms, 100hz, odr=8*/ + {0x000080, 5000, 0x00007f},/*5ms, 200hz, odr=9*/ + {0x000040, 2500, 0x00003f},/*2.5ms, 400hz, odr=10*/ + {0x000020, 1250, 0x00001f},/*1.25ms, 800hz, odr=11*/ + {0x000010, 625, 0x00000f},/*0.625ms, 1600hz, odr=12*/ + +}; + +static void bmi_dump_reg(struct bmi_client_data *client_data) +{ + #define REG_MAX0 0x24 + #define REG_MAX1 0x56 + int i; + u8 dbg_buf0[REG_MAX0]; + u8 dbg_buf1[REG_MAX1]; + u8 dbg_buf_str0[REG_MAX0 * 3 + 1] = ""; + u8 dbg_buf_str1[REG_MAX1 * 3 + 1] = ""; + + dev_notice(client_data->dev, "\nFrom 0x00:\n"); + + client_data->device.bus_read(client_data->device.dev_addr, + BMI_REG_NAME(USER_CHIP_ID), dbg_buf0, REG_MAX0); + for (i = 0; i < REG_MAX0; i++) { + sprintf(dbg_buf_str0 + i * 3, "%02x%c", dbg_buf0[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + dev_notice(client_data->dev, "%s\n", dbg_buf_str0); + + client_data->device.bus_read(client_data->device.dev_addr, + BMI160_USER_ACCEL_CONFIG_ADDR, dbg_buf1, REG_MAX1); + dev_notice(client_data->dev, "\nFrom 0x40:\n"); + for (i = 0; i < REG_MAX1; i++) { + sprintf(dbg_buf_str1 + i * 3, "%02x%c", dbg_buf1[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + dev_notice(client_data->dev, "\n%s\n", dbg_buf_str1); + +} + +/*! +* BMI160 sensor remapping function +* need to give some parameter in BSP files first. +*/ +static const struct bosch_sensor_axis_remap + bst_axis_remap_tab_dft[MAX_AXIS_REMAP_TAB_SZ] = { + /* src_x src_y src_z sign_x sign_y sign_z */ + { 0, 1, 2, 1, 1, 1 }, /* P0 */ + { 1, 0, 2, 1, -1, 1 }, /* P1 */ + { 0, 1, 2, -1, -1, 1 }, /* P2 */ + { 1, 0, 2, -1, 1, 1 }, /* P3 */ + + { 0, 1, 2, -1, 1, -1 }, /* P4 */ + { 1, 0, 2, -1, -1, -1 }, /* P5 */ + { 0, 1, 2, 1, -1, -1 }, /* P6 */ + { 1, 0, 2, 1, 1, -1 }, /* P7 */ +}; + +static int bmi160_power_ctl(struct bmi_client_data *data, bool enable) +{ + int ret = 0; + int err = 0; + + if (!enable && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = enable; + } else if (enable && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_enable(data->vio); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + data->power_enabled = enable; + } else { + dev_info(&data->i2c->dev, + "Power on=%d. enabled=%d\n", + enable, data->power_enabled); + } + + return ret; +} + +static int bmi160_power_init(struct bmi_client_data *data) +{ + int ret; + + data->vdd = regulator_get(&data->i2c->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + dev_err(&data->i2c->dev, + "Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + BMI160_VDD_MIN_UV, + BMI160_VDD_MAX_UV); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator set failed vdd ret=%d\n", + ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->i2c->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + dev_err(&data->i2c->dev, + "Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + BMI160_VIO_MIN_UV, + BMI160_VIO_MAX_UV); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, BMI160_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + +static int bmi160_power_deinit(struct bmi_client_data *data) +{ + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, + 0, BMI160_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, + 0, BMI160_VIO_MAX_UV); + + regulator_put(data->vio); + + return 0; +} + +static void bst_remap_sensor_data(struct bosch_sensor_data *data, + const struct bosch_sensor_axis_remap *remap) +{ + struct bosch_sensor_data tmp; + + tmp.x = data->v[remap->src_x] * remap->sign_x; + tmp.y = data->v[remap->src_y] * remap->sign_y; + tmp.z = data->v[remap->src_z] * remap->sign_z; + + memcpy(data, &tmp, sizeof(*data)); +} + +static void bst_remap_sensor_data_dft_tab(struct bosch_sensor_data *data, + int place) +{ +/* sensor with place 0 needs not to be remapped */ + if ((place <= 0) || (place >= MAX_AXIS_REMAP_TAB_SZ)) + return; + bst_remap_sensor_data(data, &bst_axis_remap_tab_dft[place]); +} + +static void bmi_remap_sensor_data(struct bmi160_axis_data_t *val, + struct bmi_client_data *client_data) +{ + struct bosch_sensor_data bsd; + + if ((NULL == client_data->bst_pd) || + (BOSCH_SENSOR_PLACE_UNKNOWN + == client_data->bst_pd->place)) + return; + + bsd.x = val->x; + bsd.y = val->y; + bsd.z = val->z; + + bst_remap_sensor_data_dft_tab(&bsd, + client_data->bst_pd->place); + + val->x = bsd.x; + val->y = bsd.y; + val->z = bsd.z; + +} + +static void bmi_remap_data_acc(struct bmi_client_data *client_data, + struct bmi160_accel_t *acc_frame) +{ + struct bosch_sensor_data bsd; + + if ((NULL == client_data->bst_pd) || + (BOSCH_SENSOR_PLACE_UNKNOWN + == client_data->bst_pd->place)) + return; + + bsd.x = acc_frame->x; + bsd.y = acc_frame->y; + bsd.z = acc_frame->z; + + bst_remap_sensor_data_dft_tab(&bsd, + client_data->bst_pd->place); + + acc_frame->x = bsd.x; + acc_frame->y = bsd.y; + acc_frame->z = bsd.z; + + +} + +static void bmi_remap_data_gyro(struct bmi_client_data *client_data, + struct bmi160_gyro_t *gyro_frame) +{ + struct bosch_sensor_data bsd; + + if ((NULL == client_data->bst_pd) || + (BOSCH_SENSOR_PLACE_UNKNOWN + == client_data->bst_pd->place)) + return; + + bsd.x = gyro_frame->x; + bsd.y = gyro_frame->y; + bsd.z = gyro_frame->z; + + bst_remap_sensor_data_dft_tab(&bsd, + client_data->bst_pd->place); + + gyro_frame->x = bsd.x; + gyro_frame->y = bsd.y; + gyro_frame->z = bsd.z; + + +} + +static void bmi_fifo_frame_bytes_extend_calc( + struct bmi_client_data *client_data, + unsigned int *fifo_frmbytes_extend) +{ + + switch (client_data->fifo_data_sel) { + case BMI_FIFO_A_SEL: + case BMI_FIFO_G_SEL: + *fifo_frmbytes_extend = 7; + break; + case BMI_FIFO_G_A_SEL: + *fifo_frmbytes_extend = 13; + break; + case BMI_FIFO_M_SEL: + *fifo_frmbytes_extend = 9; + break; + case BMI_FIFO_M_A_SEL: + case BMI_FIFO_M_G_SEL: + /*8(mag) + 6(gyro or acc) +1(head) = 15*/ + *fifo_frmbytes_extend = 15; + break; + case BMI_FIFO_M_G_A_SEL: + /*8(mag) + 6(gyro or acc) + 6 + 1 = 21*/ + *fifo_frmbytes_extend = 21; + break; + default: + *fifo_frmbytes_extend = 0; + break; + + }; + +} + +static int bmi_input_init(struct bmi_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = devm_input_allocate_device(&client_data->i2c->dev); + if (NULL == dev) + return -ENOMEM; + + dev->name = BMI160_ACCEL_INPUT_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Z, ABSMIN, ABSMAX, 0, 0); + + input_set_drvdata(dev, client_data); + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + dev_notice(client_data->dev, "bmi160 accel input free!\n"); + return err; + } + client_data->input_accel = dev; + dev_notice(client_data->dev, + "bmi160 accel input register successfully, %s!\n", + client_data->input_accel->name); + + dev = devm_input_allocate_device(&client_data->i2c->dev); + if (NULL == dev) + return -ENOMEM; + + dev->name = BMI160_GYRO_INPUT_NAME; + dev->id.bustype = BUS_I2C; + + + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_RX, GYRO_MAX_VALUE, GYRO_MIN_VALUE, 0, 0); + input_set_abs_params(dev, ABS_RY, GYRO_MAX_VALUE, GYRO_MIN_VALUE, 0, 0); + input_set_abs_params(dev, ABS_RZ, GYRO_MAX_VALUE, GYRO_MIN_VALUE, 0, 0); + input_set_drvdata(dev, client_data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + dev_notice(client_data->dev, "bmi160 accel input free!\n"); + return err; + } + client_data->input_gyro = dev; + dev_notice(client_data->dev, + "bmi160 gyro input register successfully, %s!\n", + client_data->input_gyro->name); + + return err; +} + + +static void bmi_input_destroy(struct bmi_client_data *client_data) +{ + struct input_dev *dev = client_data->input_accel; + + input_unregister_device(dev); + input_free_device(dev); + + dev = client_data->input_gyro; + input_unregister_device(dev); + input_free_device(dev); +} + +static int bmi_check_chip_id(struct bmi_client_data *client_data) +{ + int8_t err = 0; + int8_t i = 0; + uint8_t chip_id = 0; + uint8_t read_count = 0; + u8 bmi_sensor_cnt = sizeof(sensor_type_map) + / sizeof(struct bmi160_type_mapping_type); + /* read and check chip id */ + while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { + if (client_data->device.bus_read(client_data->device.dev_addr, + BMI_REG_NAME(USER_CHIP_ID), &chip_id, 1) < 0) { + + dev_err(client_data->dev, + "Bosch Sensortec Device not found" + "read chip_id:%d\n", chip_id); + continue; + } else { + for (i = 0; i < bmi_sensor_cnt; i++) { + if (sensor_type_map[i].chip_id == chip_id) { + client_data->chip_id = chip_id; + dev_notice(client_data->dev, + "Bosch Sensortec Device detected, " + "HW IC name: %s\n", sensor_type_map[i].sensor_name); + break; + } + } + if (i < bmi_sensor_cnt) + break; + else { + if (read_count == CHECK_CHIP_ID_TIME_MAX) { + dev_err(client_data->dev, + "Failed!Bosch Sensortec Device not found" + " mismatch chip_id:%d\n", chip_id); + err = -ENODEV; + return err; + } + } + mdelay(1); + } + } + return err; + +} + +static int bmi_pmu_set_suspend(struct bmi_client_data *client_data) +{ + int err = 0; + if (client_data == NULL) + return -EINVAL; + else { + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[SENSOR_PM_SUSPEND]); + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[SENSOR_PM_SUSPEND]); + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_mag_arr[SENSOR_PM_SUSPEND]); + client_data->pw.acc_pm = BMI_ACC_PM_SUSPEND; + client_data->pw.gyro_pm = BMI_GYRO_PM_SUSPEND; + client_data->pw.mag_pm = BMI_MAG_PM_SUSPEND; + } + + return err; +} + +static int bmi_get_err_status(struct bmi_client_data *client_data) +{ + int err = 0; + + err = BMI_CALL_API(get_error_status)(&client_data->err_st.fatal_err, + &client_data->err_st.err_code, &client_data->err_st.i2c_fail, + &client_data->err_st.drop_cmd, &client_data->err_st.mag_drdy_err); + return err; +} + + +static enum hrtimer_restart reportdata_timer_fun( + struct hrtimer *hrtimer) +{ + struct bmi_client_data *client_data = + container_of(hrtimer, struct bmi_client_data, timer); + int32_t delay = 0; + delay = atomic_read(&client_data->delay); + queue_work(reportdata_wq, &(client_data->report_data_work)); + client_data->work_delay_kt = ns_to_ktime(delay*1000000); + hrtimer_forward(hrtimer, ktime_get(), client_data->work_delay_kt); + + return HRTIMER_RESTART; +} + +static ssize_t bmi_show_enable_timer(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + return snprintf(buf, 16, "%d\n", client_data->is_timer_running); +} + +static ssize_t bmi_store_enable_timer(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int error; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + error = kstrtoul(buf, 10, &data); + if (error) + return error; + if (data) { + if (0 == client_data->is_timer_running) { + hrtimer_start(&client_data->timer, + ns_to_ktime(10000000), + HRTIMER_MODE_REL); + client_data->is_timer_running = 1; + } + } else { + if (1 == client_data->is_timer_running) { + hrtimer_cancel(&client_data->timer); + client_data->is_timer_running = 0; + } + } + return count; +} + +static void bmi_work_func(struct work_struct *work) +{ + struct bmi_client_data *client_data = + container_of((struct delayed_work *)work, + struct bmi_client_data, work); + unsigned long delay = + msecs_to_jiffies(atomic_read(&client_data->delay)); + struct bmi160_accel_t data; + struct bmi160_axis_data_t bmi160_udata; + int err; + + err = BMI_CALL_API(read_accel_xyz)(&data); + if (err < 0) + return; + + bmi160_udata.x = data.x; + bmi160_udata.y = data.y; + bmi160_udata.z = data.z; + + bmi_remap_sensor_data(&bmi160_udata, client_data); + /*report current frame via input event*/ + input_event(client_data->input_accel, EV_ABS, ABS_X, bmi160_udata.x); + input_event(client_data->input_accel, EV_ABS, ABS_Y, bmi160_udata.y); + input_event(client_data->input_accel, EV_ABS, ABS_Z, bmi160_udata.z); + input_sync(client_data->input_accel); + + schedule_delayed_work(&client_data->work, delay); +} + +static void bmi_gyro_work_func(struct work_struct *work) +{ + struct bmi_client_data *client_data = container_of( + (struct delayed_work *)work, + struct bmi_client_data, gyro_work); + unsigned long delay = + msecs_to_jiffies(atomic_read(&client_data->delay)); + struct bmi160_gyro_t data; + struct bmi160_axis_data_t bmi160_udata; + int err; + + err = BMI_CALL_API(read_gyro_xyz)(&data); + if (err < 0) + return; + + bmi160_udata.x = data.x; + bmi160_udata.y = data.y; + bmi160_udata.z = data.z; + + bmi_remap_sensor_data(&bmi160_udata, client_data); + /*report current frame via input event*/ + input_event(client_data->input_gyro, EV_ABS, ABS_RX, bmi160_udata.x); + input_event(client_data->input_gyro, EV_ABS, ABS_RY, bmi160_udata.y); + input_event(client_data->input_gyro, EV_ABS, ABS_RZ, bmi160_udata.z); + input_sync(client_data->input_gyro); + + schedule_delayed_work(&client_data->gyro_work, delay); +} + +static uint8_t dbg_buf_str[2048] = ""; +static void bmi_hrtimer_work_func(struct work_struct *work) +{ + struct bmi_client_data *client_data = + container_of((struct delayed_work *)work, + struct bmi_client_data, work); + + unsigned int fifo_len0 = 0; + unsigned int fifo_frmbytes_ext = 0; + unsigned int fifo_read_len = 0; + int i, err; + + bmi_fifo_frame_bytes_extend_calc(client_data, &fifo_frmbytes_ext); + + err = BMI_CALL_API(fifo_length)(&fifo_len0); + client_data->fifo_bytecount = fifo_len0; + + if (client_data->fifo_bytecount == 0 || err) { + return ; + } + + fifo_read_len = client_data->fifo_bytecount + fifo_frmbytes_ext; + if (fifo_read_len > FIFO_DATA_BUFSIZE) { + fifo_read_len = FIFO_DATA_BUFSIZE; + } + + if (!err) { + err = bmi_burst_read_wrapper(client_data->device.dev_addr, + BMI160_USER_FIFO_DATA__REG, s_fifo_data_buf, + fifo_read_len); + } + + for (i = 0; i < fifo_read_len; i++) { + sprintf(dbg_buf_str + i * 3, "%02x%c", s_fifo_data_buf[i], + (((i + 1) % BYTES_PER_LINE == 0) ? '\n' : ' ')); + } + pr_info("%s\n", dbg_buf_str); + +} + +static ssize_t bmi160_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + return sprintf(buf, "0x%x\n", client_data->chip_id); +} + +static ssize_t bmi160_err_st_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err = 0; + err = bmi_get_err_status(client_data); + if (err) + return err; + else { + return sprintf(buf, "fatal_err:0x%x, err_code:%d,\n\n" + "i2c_fail_err:%d, drop_cmd_err:%d, mag_drdy_err:%d\n", + client_data->err_st.fatal_err, + client_data->err_st.err_code, + client_data->err_st.i2c_fail, + client_data->err_st.drop_cmd, + client_data->err_st.mag_drdy_err); + } +} + +static ssize_t bmi160_sensor_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + u32 sensor_time; + err = BMI_CALL_API(get_sensor_time)(&sensor_time); + if (err) + return err; + else + return sprintf(buf, "0x%x\n", (unsigned int)sensor_time); +} + +static ssize_t bmi160_fifo_flush_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long enable; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable) + err = BMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA); + + if (err) + dev_err(client_data->dev, "fifo flush failed!\n"); + + return count; + +} + + +static ssize_t bmi160_fifo_bytecount_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned int fifo_bytecount = 0; + + BMI_CALL_API(fifo_length)(&fifo_bytecount); + err = sprintf(buf, "%u\n", fifo_bytecount); + return err; +} + +static ssize_t bmi160_fifo_bytecount_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err; + unsigned long data; + err = kstrtoul(buf, 10, &data); + if (err) + return err; + client_data->fifo_bytecount = (unsigned int) data; + + return count; +} + +int bmi160_fifo_data_sel_get(struct bmi_client_data *client_data) +{ + int err = 0; + unsigned char fifo_acc_en, fifo_gyro_en, fifo_mag_en; + unsigned char fifo_datasel; + + err += BMI_CALL_API(get_fifo_accel_enable)(&fifo_acc_en); + err += BMI_CALL_API(get_fifo_gyro_enable)(&fifo_gyro_en); + err += BMI_CALL_API(get_fifo_mag_enable)(&fifo_mag_en); + + if (err) + return err; + + fifo_datasel = (fifo_acc_en << BMI_ACC_SENSOR) | + (fifo_gyro_en << BMI_GYRO_SENSOR) | + (fifo_mag_en << BMI_MAG_SENSOR); + + client_data->fifo_data_sel = fifo_datasel; + + return err; + + +} + +static ssize_t bmi160_fifo_data_sel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + err = bmi160_fifo_data_sel_get(client_data); + if (err) + return -EINVAL; + return sprintf(buf, "%d\n", client_data->fifo_data_sel); +} + +/* write any value to clear all the fifo data. */ +static ssize_t bmi160_fifo_data_sel_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err; + unsigned long data; + unsigned char fifo_datasel; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* data format: aimed 0b0000 0x(m)x(g)x(a), x:1 enable, 0:disable*/ + if (data > 7) + return -EINVAL; + + + fifo_datasel = (unsigned char)data; + + + err += BMI_CALL_API(set_fifo_accel_enable) + ((fifo_datasel & (1 << BMI_ACC_SENSOR)) ? 1 : 0); + err += BMI_CALL_API(set_fifo_gyro_enable) + (fifo_datasel & (1 << BMI_GYRO_SENSOR) ? 1 : 0); + err += BMI_CALL_API(set_fifo_mag_enable) + ((fifo_datasel & (1 << BMI_MAG_SENSOR)) ? 1 : 0); + + /*err += BMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA);*/ + if (err) + return -EIO; + else { + dev_notice(client_data->dev, "FIFO A_en:%d, G_en:%d, M_en:%d\n", + (fifo_datasel & (1 << BMI_ACC_SENSOR)) ? 1 : 0, + (fifo_datasel & (1 << BMI_GYRO_SENSOR) ? 1 : 0), + ((fifo_datasel & (1 << BMI_MAG_SENSOR)) ? 1 : 0)); + client_data->fifo_data_sel = fifo_datasel; + } + + return count; +} + +static int bmi_fifo_analysis_handle(struct bmi_client_data *client_data, + u8 *fifo_data, u16 fifo_length, char *buf) +{ + u8 frame_head = 0;/* every frame head*/ + int len = 0; + + /*u8 skip_frame_cnt = 0;*/ + u8 acc_frm_cnt = 0;/*0~146*/ + u8 gyro_frm_cnt = 0; + u8 mag_frm_cnt = 0; + u8 tmp_frm_cnt = 0; + /*u8 tmp_odr = 0;*/ + /*uint64_t current_apts_us = 0;*/ + /*fifo data last frame start_index A G M*/ + u64 fifo_time = 0; + static uint32_t current_frm_ts; + u16 fifo_index = 0;/* fifo data buff index*/ + u16 fifo_index_tmp = 0; + u16 i = 0; + s8 last_return_st = 0; + int err = 0; + unsigned int frame_bytes = 0; + struct bmi160_mag_xyzr_t mag; + struct bmi160_mag_xyz_s32_t mag_comp_xyz; + struct bmi160_accel_t acc_frame_arr[FIFO_FRAME_CNT]; + struct bmi160_gyro_t gyro_frame_arr[FIFO_FRAME_CNT]; + struct bmi160_mag_xyzr_t mag_frame_arr[FIFO_FRAME_CNT]; + + struct odr_t odr; + + memset(&odr, 0, sizeof(odr)); + memset(&mag, 0, sizeof(mag)); + memset(&mag_comp_xyz, 0, sizeof(mag_comp_xyz)); + for (i = 0; i < FIFO_FRAME_CNT; i++) { + memset(&mag_frame_arr[i], 0, sizeof(struct bmi160_mag_xyzr_t)); + memset(&acc_frame_arr[i], 0, sizeof(struct bmi160_accel_t)); + memset(&gyro_frame_arr[i], 0, sizeof(struct bmi160_gyro_t)); + } + /*current_apts_us = get_current_timestamp();*/ + /* no fifo select for bmi sensor*/ + if (!client_data->fifo_data_sel) { + dev_err(client_data->dev, + "No select any sensor FIFO for BMI16x\n"); + return -EINVAL; + } + /*driver need read acc_odr/gyro_odr/mag_odr*/ + if ((client_data->fifo_data_sel) & (1 << BMI_ACC_SENSOR)) + odr.acc_odr = client_data->odr.acc_odr; + if ((client_data->fifo_data_sel) & (1 << BMI_GYRO_SENSOR)) + odr.gyro_odr = client_data->odr.gyro_odr; + if ((client_data->fifo_data_sel) & (1 << BMI_MAG_SENSOR)) + odr.mag_odr = client_data->odr.mag_odr; + bmi_fifo_frame_bytes_extend_calc(client_data, &frame_bytes); +/* search sensor time sub function firstly */ + for (fifo_index = 0; fifo_index < fifo_length;) { + /* conside limited HW i2c burst reading issue, + need to re-calc index 256 512 768 1024...*/ + if ((fifo_index_tmp >> 8) != (fifo_index >> 8)) { + if (fifo_data[fifo_index_tmp] == + fifo_data[(fifo_index >> 8)<<8]) { + fifo_index = (fifo_index >> 8) << 8; + fifo_length += + (fifo_index - fifo_index_tmp + 1); + } + } + fifo_index_tmp = fifo_index; + /* compare index with 256/512/ before doing parsing*/ + if (((fifo_index + frame_bytes) >> 8) != (fifo_index >> 8)) { + fifo_index = ((fifo_index + frame_bytes) >> 8) << 8; + continue; + } + + frame_head = fifo_data[fifo_index]; + + switch (frame_head) { + /*skip frame 0x40 22 0x84*/ + case FIFO_HEAD_SKIP_FRAME: + /*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + 1 > fifo_length) { + last_return_st = FIFO_SKIP_OVER_LEN; + break; + } + /*skip_frame_cnt = fifo_data[fifo_index];*/ + fifo_index = fifo_index + 1; + break; + + /*M & G & A*/ + case FIFO_HEAD_M_G_A: + {/*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + MGA_BYTES_FRM > fifo_length) { + last_return_st = FIFO_M_G_A_OVER_LEN; + break; + } + + /* mag frm index = gyro */ + mag_frm_cnt = gyro_frm_cnt; + mag_frame_arr[mag_frm_cnt].x = + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + mag_frame_arr[mag_frm_cnt].y = + fifo_data[fifo_index + 3] << 8 | + fifo_data[fifo_index + 2]; + mag_frame_arr[mag_frm_cnt].z = + fifo_data[fifo_index + 5] << 8 | + fifo_data[fifo_index + 4]; + mag_frame_arr[mag_frm_cnt].r = + fifo_data[fifo_index + 7] << 8 | + fifo_data[fifo_index + 6]; + + gyro_frame_arr[gyro_frm_cnt].x = + fifo_data[fifo_index + 9] << 8 | + fifo_data[fifo_index + 8]; + gyro_frame_arr[gyro_frm_cnt].y = + fifo_data[fifo_index + 11] << 8 | + fifo_data[fifo_index + 10]; + gyro_frame_arr[gyro_frm_cnt].z = + fifo_data[fifo_index + 13] << 8 | + fifo_data[fifo_index + 12]; + + acc_frame_arr[acc_frm_cnt].x = + fifo_data[fifo_index + 15] << 8 | + fifo_data[fifo_index + 14]; + acc_frame_arr[acc_frm_cnt].y = + fifo_data[fifo_index + 17] << 8 | + fifo_data[fifo_index + 16]; + acc_frame_arr[acc_frm_cnt].z = + fifo_data[fifo_index + 19] << 8 | + fifo_data[fifo_index + 18]; + + mag_frm_cnt++;/* M fram_cnt++ */ + gyro_frm_cnt++;/* G fram_cnt++ */ + acc_frm_cnt++;/* A fram_cnt++ */ + + fifo_index = fifo_index + MGA_BYTES_FRM; + break; + } + + case FIFO_HEAD_M_A: + {/*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + MA_BYTES_FRM > fifo_length) { + last_return_st = FIFO_M_A_OVER_LEN; + break; + } + + mag_frm_cnt = acc_frm_cnt; + + mag_frame_arr[mag_frm_cnt].x = + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + mag_frame_arr[mag_frm_cnt].y = + fifo_data[fifo_index + 3] << 8 | + fifo_data[fifo_index + 2]; + mag_frame_arr[mag_frm_cnt].z = + fifo_data[fifo_index + 5] << 8 | + fifo_data[fifo_index + 4]; + mag_frame_arr[mag_frm_cnt].r = + fifo_data[fifo_index + 7] << 8 | + fifo_data[fifo_index + 6]; + + acc_frame_arr[acc_frm_cnt].x = + fifo_data[fifo_index + 9] << 8 | + fifo_data[fifo_index + 8]; + acc_frame_arr[acc_frm_cnt].y = + fifo_data[fifo_index + 11] << 8 | + fifo_data[fifo_index + 10]; + acc_frame_arr[acc_frm_cnt].z = + fifo_data[fifo_index + 13] << 8 | + fifo_data[fifo_index + 12]; + + mag_frm_cnt++;/* M fram_cnt++ */ + acc_frm_cnt++;/* A fram_cnt++ */ + + fifo_index = fifo_index + MA_BYTES_FRM; + break; + } + + case FIFO_HEAD_M_G: + {/*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + MG_BYTES_FRM > fifo_length) { + last_return_st = FIFO_M_G_OVER_LEN; + break; + } + + mag_frm_cnt = gyro_frm_cnt; + mag_frame_arr[mag_frm_cnt].x = + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + mag_frame_arr[mag_frm_cnt].y = + fifo_data[fifo_index + 3] << 8 | + fifo_data[fifo_index + 2]; + mag_frame_arr[mag_frm_cnt].z = + fifo_data[fifo_index + 5] << 8 | + fifo_data[fifo_index + 4]; + mag_frame_arr[mag_frm_cnt].r = + fifo_data[fifo_index + 7] << 8 | + fifo_data[fifo_index + 6]; + + gyro_frame_arr[gyro_frm_cnt].x = + fifo_data[fifo_index + 9] << 8 | + fifo_data[fifo_index + 8]; + gyro_frame_arr[gyro_frm_cnt].y = + fifo_data[fifo_index + 11] << 8 | + fifo_data[fifo_index + 10]; + gyro_frame_arr[gyro_frm_cnt].z = + fifo_data[fifo_index + 13] << 8 | + fifo_data[fifo_index + 12]; + + mag_frm_cnt++;/* M fram_cnt++ */ + gyro_frm_cnt++;/* G fram_cnt++ */ + fifo_index = fifo_index + MG_BYTES_FRM; + break; + } + + case FIFO_HEAD_G_A: + { /*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + GA_BYTES_FRM > fifo_length) { + last_return_st = FIFO_G_A_OVER_LEN; + break; + } + gyro_frame_arr[gyro_frm_cnt].x = + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + gyro_frame_arr[gyro_frm_cnt].y = + fifo_data[fifo_index + 3] << 8 | + fifo_data[fifo_index + 2]; + gyro_frame_arr[gyro_frm_cnt].z = + fifo_data[fifo_index + 5] << 8 | + fifo_data[fifo_index + 4]; + + acc_frame_arr[acc_frm_cnt].x = + fifo_data[fifo_index + 7] << 8 | + fifo_data[fifo_index + 6]; + acc_frame_arr[acc_frm_cnt].y = + fifo_data[fifo_index + 9] << 8 | + fifo_data[fifo_index + 8]; + acc_frame_arr[acc_frm_cnt].z = + fifo_data[fifo_index + 11] << 8 | + fifo_data[fifo_index + 10]; + + bmi_remap_data_gyro(client_data, + &gyro_frame_arr[gyro_frm_cnt]); + bmi_remap_data_acc(client_data, + &acc_frame_arr[acc_frm_cnt]); + + gyro_frm_cnt++; + acc_frm_cnt++; + fifo_index = fifo_index + GA_BYTES_FRM; + + break; + } + case FIFO_HEAD_A: + { /*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + A_BYTES_FRM > fifo_length) { + last_return_st = FIFO_A_OVER_LEN; + break; + } + + acc_frame_arr[acc_frm_cnt].x = + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + acc_frame_arr[acc_frm_cnt].y = + fifo_data[fifo_index + 3] << 8 | + fifo_data[fifo_index + 2]; + acc_frame_arr[acc_frm_cnt].z = + fifo_data[fifo_index + 5] << 8 | + fifo_data[fifo_index + 4]; + + bmi_remap_data_acc(client_data, + &acc_frame_arr[acc_frm_cnt]); + + acc_frm_cnt++;/*acc_frm_cnt*/ + fifo_index = fifo_index + A_BYTES_FRM; + break; + } + case FIFO_HEAD_G: + { /*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + G_BYTES_FRM > fifo_length) { + last_return_st = FIFO_G_OVER_LEN; + break; + } + + gyro_frame_arr[gyro_frm_cnt].x = + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + gyro_frame_arr[gyro_frm_cnt].y = + fifo_data[fifo_index + 3] << 8 | + fifo_data[fifo_index + 2]; + gyro_frame_arr[gyro_frm_cnt].z = + fifo_data[fifo_index + 5] << 8 | + fifo_data[fifo_index + 4]; + + bmi_remap_data_gyro(client_data, + &gyro_frame_arr[gyro_frm_cnt]); + + gyro_frm_cnt++;/*gyro_frm_cnt*/ + + fifo_index = fifo_index + G_BYTES_FRM; + break; + } + case FIFO_HEAD_M: + { /*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + if (fifo_index + A_BYTES_FRM > fifo_length) { + last_return_st = FIFO_M_OVER_LEN; + break; + } + + mag_frame_arr[mag_frm_cnt].x = + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + mag_frame_arr[mag_frm_cnt].y = + fifo_data[fifo_index + 3] << 8 | + fifo_data[fifo_index + 2]; + mag_frame_arr[mag_frm_cnt].z = + fifo_data[fifo_index + 5] << 8 | + fifo_data[fifo_index + 4]; + mag_frame_arr[mag_frm_cnt].r = + fifo_data[fifo_index + 7] << 8 | + fifo_data[fifo_index + 6]; + + mag_frm_cnt++;/* M fram_cnt++ */ + + fifo_index = fifo_index + M_BYTES_FRM; + break; + } + + /* sensor time frame*/ + case FIFO_HEAD_SENSOR_TIME: + { + /*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + + if (fifo_index + 3 > fifo_length) { + last_return_st = FIFO_SENSORTIME_RETURN; + break; + } + fifo_time = + fifo_data[fifo_index + 2] << 16 | + fifo_data[fifo_index + 1] << 8 | + fifo_data[fifo_index + 0]; + + client_data->fifo_time = fifo_time; + /*fifo sensor time frame index + 3*/ + fifo_index = fifo_index + 3; + break; + } + case FIFO_HEAD_OVER_READ_LSB: + /*fifo data frame index + 1*/ + fifo_index = fifo_index + 1; + + if (fifo_index + 1 > fifo_length) { + last_return_st = FIFO_OVER_READ_RETURN; + break; + } + if (fifo_data[fifo_index] == + FIFO_HEAD_OVER_READ_MSB) { + /*fifo over read frame index + 1*/ + fifo_index = fifo_index + 1; + break; + } else { + last_return_st = FIFO_OVER_READ_RETURN; + break; + } + + default: + last_return_st = 1; + break; + + } + if (last_return_st) + break; + } + fifo_time = 0; +/*current_frm_ts = current_apts_us - +((fifo_time & (sensortime_duration_tbl[odr.acc_odr].ts_delat)) + +(sensortime_duration_tbl[odr.acc_odr].ts_duration_lsb +*(acc_frm_cnt - i - 1)))*625/16;*/ +/*Acc Only*/ + if (client_data->fifo_data_sel == BMI_FIFO_A_SEL) { + for (i = 0; i < acc_frm_cnt; i++) { + /*current_frm_ts += 256;*/ + current_frm_ts += + sensortime_duration_tbl[odr.acc_odr].ts_duration_us*LMADA; + + len = sprintf(buf, "%s %d %d %d %u ", + ACC_FIFO_HEAD, + acc_frame_arr[i].x, + acc_frame_arr[i].y, + acc_frame_arr[i].z, + current_frm_ts); + buf += len; + err += len; + } + } + + + /*only for G*/ + if (client_data->fifo_data_sel == BMI_FIFO_G_SEL) { + for (i = 0; i < gyro_frm_cnt; i++) { + /*current_frm_ts += 256;*/ + current_frm_ts += + sensortime_duration_tbl[odr.gyro_odr].ts_duration_us*LMADA; + + len = sprintf(buf, "%s %d %d %d %u ", + GYRO_FIFO_HEAD, + gyro_frame_arr[i].x, + gyro_frame_arr[i].y, + gyro_frame_arr[i].z, + current_frm_ts + ); + buf += len; + err += len; + } + } + + /*only for M*/ + if (client_data->fifo_data_sel == BMI_FIFO_M_SEL) { + for (i = 0; i < mag_frm_cnt; i++) { + /*current_frm_ts += 256;*/ + current_frm_ts += + sensortime_duration_tbl[odr.mag_odr].ts_duration_us*LMADA; +#ifdef BMI160_AKM09912_SUPPORT + mag_comp_xyz.x = mag_frame_arr[i].x; + mag_comp_xyz.y = mag_frame_arr[i].y; + mag_comp_xyz.z = mag_frame_arr[i].z; + bmi160_bst_akm09912_compensate_xyz_raw( + &mag_comp_xyz); +#else + mag.x = mag_frame_arr[i].x >> 3; + mag.y = mag_frame_arr[i].y >> 3; + mag.z = mag_frame_arr[i].z >> 1; + mag.r = mag_frame_arr[i].r >> 2; + bmi160_bmm150_mag_compensate_xyz_raw( + &mag_comp_xyz, mag); +#endif + len = sprintf(buf, "%s %d %d %d %u ", + MAG_FIFO_HEAD, + mag_comp_xyz.x, + mag_comp_xyz.y, + mag_comp_xyz.z, + current_frm_ts + ); + + buf += len; + err += len; + } + + } + +/*only for A M G*/ +if (client_data->fifo_data_sel == BMI_FIFO_M_G_A_SEL) { + + for (i = 0; i < gyro_frm_cnt; i++) { + /*sensor timeLSB*/ + /*dia(sensor_time) = fifo_time & (0xff), uint:LSB, 39.0625us*/ + /*AP tinmestamp 390625/10000 = 625 /16 */ + current_frm_ts += + sensortime_duration_tbl[odr.gyro_odr].ts_duration_us*LMADA; + + if (mag_frame_arr[i].x) { +#ifdef BMI160_AKM09912_SUPPORT + mag_comp_xyz.x = mag_frame_arr[i].x; + mag_comp_xyz.y = mag_frame_arr[i].y; + mag_comp_xyz.z = mag_frame_arr[i].z; + bmi160_bst_akm09912_compensate_xyz_raw( + &mag_comp_xyz); +#else + mag.x = mag_frame_arr[i].x >> 3; + mag.y = mag_frame_arr[i].y >> 3; + mag.z = mag_frame_arr[i].z >> 1; + mag.r = mag_frame_arr[i].r >> 2; + bmi160_bmm150_mag_compensate_xyz_raw( + &mag_comp_xyz, mag); +#endif + len = sprintf(buf, + "%s %d %d %d %u %s %d %d %d %u %s %d %d %d %u ", + GYRO_FIFO_HEAD, + gyro_frame_arr[i].x, + gyro_frame_arr[i].y, + gyro_frame_arr[i].z, + current_frm_ts, + ACC_FIFO_HEAD, + acc_frame_arr[i].x, + acc_frame_arr[i].y, + acc_frame_arr[i].z, + current_frm_ts, + MAG_FIFO_HEAD, + mag_comp_xyz.x, + mag_comp_xyz.y, + mag_comp_xyz.z, + current_frm_ts); + buf += len; + err += len; + } else { + len = sprintf(buf, + "%s %d %d %d %u %s %d %d %d %u ", + GYRO_FIFO_HEAD, + gyro_frame_arr[i].x, + gyro_frame_arr[i].y, + gyro_frame_arr[i].z, + current_frm_ts, + ACC_FIFO_HEAD, + acc_frame_arr[i].x, + acc_frame_arr[i].y, + acc_frame_arr[i].z, + current_frm_ts + ); + + buf += len; + err += len; + } + } + +} +/*only for A G*/ +if (client_data->fifo_data_sel == BMI_FIFO_G_A_SEL) { + + for (i = 0; i < gyro_frm_cnt; i++) { + /*sensor timeLSB*/ + /*dia(sensor_time) = fifo_time & (0xff), uint:LSB, 39.0625us*/ + /*AP tinmestamp 390625/10000 = 625 /16 */ + current_frm_ts += + sensortime_duration_tbl[odr.gyro_odr].ts_duration_us*LMADA; + len = sprintf(buf, + "%s %d %d %d %u %s %d %d %d %u ", + GYRO_FIFO_HEAD, + gyro_frame_arr[i].x, + gyro_frame_arr[i].y, + gyro_frame_arr[i].z, + current_frm_ts, + ACC_FIFO_HEAD, + acc_frame_arr[i].x, + acc_frame_arr[i].y, + acc_frame_arr[i].z, + current_frm_ts + ); + buf += len; + err += len; + } + } + +/*only for A M */ +if (client_data->fifo_data_sel == BMI_FIFO_M_A_SEL) { + for (i = 0; i < acc_frm_cnt; i++) { + /*sensor timeLSB*/ + /*dia(sensor_time) = fifo_time & (0xff), uint:LSB, 39.0625us*/ + /*AP tinmestamp 390625/10000 = 625 /16 */ + /*current_frm_ts += 256;*/ + current_frm_ts += + sensortime_duration_tbl[odr.acc_odr].ts_duration_us*LMADA; + + if (mag_frame_arr[i].x) { +#ifdef BMI160_AKM09912_SUPPORT + mag_comp_xyz.x = mag_frame_arr[i].x; + mag_comp_xyz.y = mag_frame_arr[i].y; + mag_comp_xyz.z = mag_frame_arr[i].z; + bmi160_bst_akm09912_compensate_xyz_raw( + &mag_comp_xyz); +#else + mag.x = mag_frame_arr[i].x >> 3; + mag.y = mag_frame_arr[i].y >> 3; + mag.z = mag_frame_arr[i].z >> 1; + mag.r = mag_frame_arr[i].r >> 2; + bmi160_bmm150_mag_compensate_xyz_raw( + &mag_comp_xyz, mag); +#endif + len = sprintf(buf, + "%s %d %d %d %u %s %d %d %d %u ", + ACC_FIFO_HEAD, + acc_frame_arr[i].x, + acc_frame_arr[i].y, + acc_frame_arr[i].z, + current_frm_ts, + MAG_FIFO_HEAD, + mag_comp_xyz.x, + mag_comp_xyz.y, + mag_comp_xyz.z, + current_frm_ts); + buf += len; + err += len; + } else { + len = sprintf(buf, "%s %d %d %d %u ", + ACC_FIFO_HEAD, + acc_frame_arr[i].x, + acc_frame_arr[i].y, + acc_frame_arr[i].z, + current_frm_ts + ); + + buf += len; + err += len; + } + } +} + +/*only forG M*/ +if (client_data->fifo_data_sel == BMI_FIFO_M_G_SEL) { + if (gyro_frm_cnt) { + tmp_frm_cnt = gyro_frm_cnt; + /*tmp_odr = odr.gyro_odr;*/ + } + + for (i = 0; i < tmp_frm_cnt; i++) { + current_frm_ts += + sensortime_duration_tbl[odr.gyro_odr].ts_duration_us*LMADA; + if (mag_frame_arr[i].x) { +#ifdef BMI160_AKM09912_SUPPORT + mag_comp_xyz.x = mag_frame_arr[i].x; + mag_comp_xyz.y = mag_frame_arr[i].y; + mag_comp_xyz.z = mag_frame_arr[i].z; + bmi160_bst_akm09912_compensate_xyz_raw( + &mag_comp_xyz); +#else + mag.x = mag_frame_arr[i].x >> 3; + mag.y = mag_frame_arr[i].y >> 3; + mag.z = mag_frame_arr[i].z >> 1; + mag.r = mag_frame_arr[i].r >> 2; + bmi160_bmm150_mag_compensate_xyz_raw( + &mag_comp_xyz, mag); +#endif + len = sprintf(buf, + "%s %d %d %d %u %s %d %d %d %u ", + GYRO_FIFO_HEAD, + gyro_frame_arr[i].x, + gyro_frame_arr[i].y, + gyro_frame_arr[i].z, + current_frm_ts, + MAG_FIFO_HEAD, + mag_comp_xyz.x, + mag_comp_xyz.y, + mag_comp_xyz.z, + current_frm_ts); + buf += len; + err += len; + } else { + len = sprintf(buf, "%s %d %d %d %u ", + GYRO_FIFO_HEAD, + gyro_frame_arr[i].x, + gyro_frame_arr[i].y, + gyro_frame_arr[i].z, + current_frm_ts + ); + + buf += len; + err += len; + } + } +} + + + return err; + + +} + + +static ssize_t bmi160_fifo_data_out_frame_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err = 0; + unsigned int fifo_bytecount_tmp; + + if (client_data->selftest > 0) { + dev_err(client_data->dev, + "in selftest no data available in fifo_data_frame\n"); + return -ENOMEM; + } + + if (NULL == g_fifo_data_arr) { + dev_err(client_data->dev, + "no memory available in fifo_data_frame\n"); + return -ENOMEM; + } + + if (client_data->pw.acc_pm == 2 && client_data->pw.gyro_pm == 2 + && client_data->pw.mag_pm == 2) { + dev_err(client_data->dev, "pw_acc: %d, pw_gyro: %d, pw_mag:%d\n", + client_data->pw.acc_pm, client_data->pw.gyro_pm, + client_data->pw.mag_pm); + return -EINVAL; + } + if (!client_data->fifo_data_sel) + return sprintf(buf, + "no selsect sensor fifo, fifo_data_sel:%d\n", + client_data->fifo_data_sel); + + if (client_data->fifo_bytecount == 0) + return -EINVAL; + + g_current_apts_us = get_current_timestamp(); + + BMI_CALL_API(fifo_length)(&fifo_bytecount_tmp); + if (fifo_bytecount_tmp > client_data->fifo_bytecount) + client_data->fifo_bytecount = fifo_bytecount_tmp; + if (client_data->fifo_bytecount > 210) { + /*err += BMI_CALL_API(set_command_register)( + CMD_CLR_FIFO_DATA);*/ + client_data->fifo_bytecount = 210; + } + if (!err) { + memset(g_fifo_data_arr, 0, 2048); + err = bmi_burst_read_wrapper(client_data->device.dev_addr, + BMI160_USER_FIFO_DATA__REG, g_fifo_data_arr, + client_data->fifo_bytecount); + } else + dev_err(client_data->dev, "read fifo leght err"); + if (err) { + dev_err(client_data->dev, "brust read fifo err\n"); + return err; + } + err = bmi_fifo_analysis_handle(client_data, g_fifo_data_arr, + client_data->fifo_bytecount, buf); + + + return err; +} + +static ssize_t bmi160_fifo_watermark_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data = 0xff; + + err = BMI_CALL_API(get_fifo_wm)(&data); + + if (err) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_fifo_watermark_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long data; + unsigned char fifo_watermark; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + fifo_watermark = (unsigned char)data; + err = BMI_CALL_API(set_fifo_wm)(fifo_watermark); + if (err) + return -EIO; + + pr_info("fifo_watermark count %d", count); + + if (BMI_CALL_API(set_intr_enable_1) + (BMI160_FIFO_WM_ENABLE, 1) < 0) { + pr_info("set fifo wm enable failed"); + return -EIO; + } + mutex_lock(&client_data->mutex_ring_buf); + s_ring_buf_head = s_ring_buf_tail = 0; + mutex_unlock(&client_data->mutex_ring_buf); + + return count; +} + + +static ssize_t bmi160_fifo_header_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data = 0xff; + + err = BMI_CALL_API(get_fifo_header_enable)(&data); + + if (err) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_fifo_header_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err; + unsigned long data; + unsigned char fifo_header_en; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + if (data > 1) + return -ENOENT; + + fifo_header_en = (unsigned char)data; + err = BMI_CALL_API(set_fifo_header_enable)(fifo_header_en); + if (err) + return -EIO; + + client_data->fifo_head_en = fifo_header_en; + + return count; +} + +static ssize_t bmi160_fifo_time_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data = 0; + + err = BMI_CALL_API(get_fifo_time_enable)(&data); + + if (!err) + err = sprintf(buf, "%d\n", data); + + return err; +} + +static ssize_t bmi160_fifo_time_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long data; + unsigned char fifo_ts_en; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + fifo_ts_en = (unsigned char)data; + + err = BMI_CALL_API(set_fifo_time_enable)(fifo_ts_en); + if (err) + return -EIO; + + return count; +} + +static ssize_t bmi160_fifo_int_tag_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + unsigned char fifo_tag_int1 = 0; + unsigned char fifo_tag_int2 = 0; + unsigned char fifo_tag_int; + + err += BMI_CALL_API(get_fifo_tag_intr1_enable)(&fifo_tag_int1); + err += BMI_CALL_API(get_fifo_tag_intr2_enable)(&fifo_tag_int2); + + fifo_tag_int = (fifo_tag_int1 << BMI160_INT0) | + (fifo_tag_int2 << BMI160_INT1); + + if (!err) + err = sprintf(buf, "%d\n", fifo_tag_int); + + return err; +} + +static ssize_t bmi160_fifo_int_tag_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err; + unsigned long data; + unsigned char fifo_tag_int_en; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + if (data > 3) + return -EINVAL; + + fifo_tag_int_en = (unsigned char)data; + + err += BMI_CALL_API(set_fifo_tag_intr1_enable) + ((fifo_tag_int_en & (1 << BMI160_INT0)) ? 1 : 0); + err += BMI_CALL_API(set_fifo_tag_intr2_enable) + ((fifo_tag_int_en & (1 << BMI160_INT1)) ? 1 : 0); + + if (err) { + dev_err(client_data->dev, "fifo int tag en err:%d\n", err); + return -EIO; + } + client_data->fifo_int_tag_en = fifo_tag_int_en; + + return count; +} + +static int bmi160_set_acc_op_mode(struct bmi_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + unsigned char stc_enable; + unsigned char std_enable; + mutex_lock(&client_data->mutex_op_mode); + + if (op_mode < BMI_ACC_PM_MAX) { + switch (op_mode) { + case BMI_ACC_PM_NORMAL: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_NORMAL]); + client_data->pw.acc_pm = BMI_ACC_PM_NORMAL; + mdelay(10); + break; + case BMI_ACC_PM_LP1: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_LP1]); + client_data->pw.acc_pm = BMI_ACC_PM_LP1; + mdelay(3); + break; + case BMI_ACC_PM_SUSPEND: + BMI_CALL_API(get_step_counter_enable)(&stc_enable); + BMI_CALL_API(get_step_detector_enable)(&std_enable); + if ((stc_enable == 0) && (std_enable == 0) && + (client_data->sig_flag == 0)) { + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_SUSPEND]); + client_data->pw.acc_pm = BMI_ACC_PM_SUSPEND; + mdelay(10); + } + break; + case BMI_ACC_PM_LP2: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_LP2]); + client_data->pw.acc_pm = BMI_ACC_PM_LP2; + mdelay(3); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + + return err; + + +} + +static int bmi160_set_gyro_op_mode(struct bmi_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + + mutex_lock(&client_data->mutex_op_mode); + + if (op_mode < BMI_GYRO_PM_MAX) { + switch (op_mode) { + case BMI_GYRO_PM_NORMAL: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_NORMAL]); + client_data->pw.gyro_pm = BMI_GYRO_PM_NORMAL; + msleep(60); + break; + case BMI_GYRO_PM_FAST_START: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_FAST_START]); + client_data->pw.gyro_pm = BMI_GYRO_PM_FAST_START; + msleep(60); + break; + case BMI_GYRO_PM_SUSPEND: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_SUSPEND]); + client_data->pw.gyro_pm = BMI_GYRO_PM_SUSPEND; + msleep(60); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + return err; + +} + +static ssize_t bmi160_temperature_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + s16 temp = 0xff; + + err = BMI_CALL_API(get_temp)(&temp); + + if (!err) + err = sprintf(buf, "0x%x\n", temp); + + return err; +} + +static ssize_t bmi160_place_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int place = BOSCH_SENSOR_PLACE_UNKNOWN; + + if (NULL != client_data->bst_pd) + place = client_data->bst_pd->place; + + return sprintf(buf, "%d\n", place); +} + +static ssize_t bmi160_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", atomic_read(&client_data->delay)); + +} + +static ssize_t bmi160_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err; + unsigned long data; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + if (data == 0) { + err = -EINVAL; + return err; + } + + if (data < BMI_DELAY_MIN) + data = BMI_DELAY_MIN; + + atomic_set(&client_data->delay, (unsigned int)data); + + return count; +} + +static ssize_t bmi160_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", atomic_read(&client_data->wkqueue_en)); + +} + +static ssize_t bmi160_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err; + unsigned long enable; + int pre_enable = atomic_read(&client_data->wkqueue_en); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + + enable = enable ? 1 : 0; + mutex_lock(&client_data->mutex_enable); + if (enable) { + if (pre_enable == 0) { + if (bmi160_power_ctl(client_data, true)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + bmi160_set_acc_op_mode(client_data, + BMI_ACC_PM_NORMAL); + schedule_delayed_work(&client_data->work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + atomic_set(&client_data->wkqueue_en, 1); + } + + } else { + if (pre_enable == 1) { + bmi160_set_acc_op_mode(client_data, + BMI_ACC_PM_SUSPEND); + + cancel_delayed_work_sync(&client_data->work); + atomic_set(&client_data->wkqueue_en, 0); + if (bmi160_power_ctl(client_data, false)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + } + +mutex_exit: + mutex_unlock(&client_data->mutex_enable); + + mutex_lock(&client_data->mutex_ring_buf); + s_ring_buf_head = s_ring_buf_tail = 0; + mutex_unlock(&client_data->mutex_ring_buf); + + return count; +} + +#if defined(BMI160_ENABLE_INT1) || defined(BMI160_ENABLE_INT2) +/* accel sensor part */ +static ssize_t bmi160_anymot_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char data; + + err = BMI_CALL_API(get_intr_any_motion_durn)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_anymot_duration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_intr_any_motion_durn)((unsigned char)data); + if (err < 0) + return -EIO; + + return count; +} + +static ssize_t bmi160_anymot_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_intr_any_motion_thres)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_anymot_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_intr_any_motion_thres)((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_step_detector_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data = 0; + u8 step_det; + int err; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + err = BMI_CALL_API(get_step_detector_enable)(&step_det); + /*bmi160_get_status0_step_int*/ + if (err < 0) + return err; +/*client_data->std will be updated in bmi_stepdetector_interrupt_handle */ + if ((step_det == 1) && (client_data->std == 1)) { + data = 1; + client_data->std = 0; + } + else { + data = 0; + } + return snprintf(buf, 16, "%d\n", data); +} + +static ssize_t bmi160_step_detector_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_step_detector_enable)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_step_detector_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_step_detector_enable)((unsigned char)data); + if (err < 0) + return -EIO; + if (data == 0) + client_data->pedo_data.wkar_step_detector_status = 0; + return count; +} + +static ssize_t bmi160_signification_motion_enable_store( + struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel*/ + err = BMI_CALL_API(set_intr_significant_motion_select)( + (unsigned char)data); + if (err < 0) + return -EIO; + if (data == 1) { + err = BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_X_ENABLE, 1); + err += BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_Y_ENABLE, 1); + err += BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_Z_ENABLE, 1); + if (err < 0) + return -EIO; + client_data->sig_flag = 1; + } else { + err = BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_X_ENABLE, 0); + err += BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_Y_ENABLE, 0); + err += BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_Z_ENABLE, 0); + if (err < 0) + return -EIO; + client_data->sig_flag = 0; + } + return count; +} + +static ssize_t bmi160_signification_motion_enable_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + /*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel*/ + err = BMI_CALL_API(get_intr_significant_motion_select)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static int sigmotion_init_interrupts(u8 sig_map_int_pin) +{ + int ret = 0; +/*0x60 */ + ret += bmi160_set_intr_any_motion_thres(0x1e); +/* 0x62(bit 3~2) 0=1.5s */ + ret += bmi160_set_intr_significant_motion_skip(0); +/*0x62(bit 5~4) 1=0.5s*/ + ret += bmi160_set_intr_significant_motion_proof(1); +/*0x50 (bit 0, 1, 2) INT_EN_0 anymo x y z*/ + ret += bmi160_map_significant_motion_intr(sig_map_int_pin); +/*0x62 (bit 1) INT_MOTION_3 int_sig_mot_sel +close the signification_motion*/ + ret += bmi160_set_intr_significant_motion_select(0); +/*close the anymotion interrupt*/ + ret += BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_X_ENABLE, 0); + ret += BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_Y_ENABLE, 0); + ret += BMI_CALL_API(set_intr_enable_0) + (BMI160_ANY_MOTION_Z_ENABLE, 0); + if (ret) + pr_info("bmi160 sig motion failed setting,%d!\n", ret); + return ret; + +} +#endif + +static ssize_t bmi160_acc_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char range; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = BMI_CALL_API(get_accel_range)(&range); + if (err) + return err; + + client_data->range.acc_range = range; + return sprintf(buf, "%d\n", range); +} + +static ssize_t bmi160_acc_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long range; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &range); + if (err) + return err; + + err = BMI_CALL_API(set_accel_range)(range); + if (err) + return -EIO; + + client_data->range.acc_range = range; + return count; +} + +static ssize_t bmi160_acc_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char acc_odr; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = BMI_CALL_API(get_accel_output_data_rate)(&acc_odr); + if (err) + return err; + + client_data->odr.acc_odr = acc_odr; + return sprintf(buf, "%d\n", acc_odr); +} + +static ssize_t bmi160_acc_odr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long acc_odr; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &acc_odr); + if (err) + return err; + + if (acc_odr < 1 || acc_odr > 12) + return -EIO; + + if (acc_odr < 5) + err = BMI_CALL_API(set_accel_under_sampling_parameter)(1); + else + err = BMI_CALL_API(set_accel_under_sampling_parameter)(0); + + if (err) + return err; + + err = BMI_CALL_API(set_accel_output_data_rate)(acc_odr); + if (err) + return -EIO; + client_data->odr.acc_odr = acc_odr; + return count; +} + +static ssize_t bmi160_acc_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err = 0; + u8 accel_pmu_status = 0; + err = BMI_CALL_API(get_accel_power_mode_stat)( + &accel_pmu_status); + + if (err) + return err; + else + return sprintf(buf, "reg:%d, val:%d\n", accel_pmu_status, + client_data->pw.acc_pm); +} + +static ssize_t bmi160_acc_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err; + unsigned long op_mode; + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + + err = bmi160_set_acc_op_mode(client_data, op_mode); + if (err) + return err; + else + return count; + +} + +static ssize_t bmi160_acc_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + struct bmi160_accel_t data; + struct bmi160_axis_data_t bmi160_udata; + int err; + + err = BMI_CALL_API(read_accel_xyz)(&data); + if (err < 0) + return err; + + bmi160_udata.x = data.x; + bmi160_udata.y = data.y; + bmi160_udata.z = data.z; + + bmi_remap_sensor_data(&bmi160_udata, client_data); + return sprintf(buf, "%hd %hd %hd\n", + bmi160_udata.x, bmi160_udata.y, bmi160_udata.z); +} + +static ssize_t bmi160_acc_fast_calibration_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_foc_accel_x)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_acc_fast_calibration_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + s8 accel_offset_x = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* 0: disable, 1: +1g, 2: -1g, 3: 0g */ + if (data > 3) + return -EINVAL; + + err = BMI_CALL_API(set_accel_foc_trigger)(X_AXIS, + data, &accel_offset_x); + if (err) + return -EIO; + else + client_data->calib_status |= + BMI_FAST_CALI_TRUE << BMI_ACC_X_FAST_CALI_RDY; + return count; +} + +static ssize_t bmi160_acc_fast_calibration_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_foc_accel_y)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_acc_fast_calibration_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + s8 accel_offset_y = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* 0: disable, 1: +1g, 2: -1g, 3: 0g */ + if (data > 3) + return -EINVAL; + + err = BMI_CALL_API(set_accel_foc_trigger)(Y_AXIS, + data, &accel_offset_y); + if (err) + return -EIO; + else + client_data->calib_status |= + BMI_FAST_CALI_TRUE << BMI_ACC_Y_FAST_CALI_RDY; + return count; +} + +static ssize_t bmi160_acc_fast_calibration_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_foc_accel_z)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_acc_fast_calibration_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + s8 accel_offset_z = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + /* 0: disable, 1: +1g, 2: -1g, 3: 0g */ + if (data > 3) + return -EINVAL; + + err = BMI_CALL_API(set_accel_foc_trigger)(Z_AXIS, + data, &accel_offset_z); + if (err) + return -EIO; + else + client_data->calib_status |= + BMI_FAST_CALI_TRUE << BMI_ACC_Z_FAST_CALI_RDY; + + if (client_data->calib_status == BMI_FAST_CALI_ALL_RDY) { + input_event(client_data->input_accel, EV_MSC, + INPUT_EVENT_FAST_ACC_CALIB_DONE, 1); + input_sync(client_data->input_accel); + client_data->calib_status = 0; + } + + return count; +} + +static ssize_t bmi160_acc_offset_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_accel_offset_compensation_xaxis)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + + +static ssize_t bmi160_acc_offset_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_accel_offset_compensation_xaxis) + ((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_acc_offset_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_accel_offset_compensation_yaxis)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_acc_offset_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_accel_offset_compensation_yaxis) + ((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_acc_offset_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_accel_offset_compensation_zaxis)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_acc_offset_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_accel_offset_compensation_zaxis) + ((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + u8 raw_data[15] = {0}; + unsigned int sensor_time = 0; + + int err; + memset(raw_data, 0, sizeof(raw_data)); + + err = client_data->device.bus_read(client_data->device.dev_addr, + BMI160_USER_DATA_8_GYRO_X_LSB__REG, raw_data, 15); + if (err) + return err; + + udelay(10); + sensor_time = (u32)(raw_data[14] << 16 | raw_data[13] << 8 + | raw_data[12]); + + return sprintf(buf, "%d %d %d %d %d %d %u", + (s16)(raw_data[1] << 8 | raw_data[0]), + (s16)(raw_data[3] << 8 | raw_data[2]), + (s16)(raw_data[5] << 8 | raw_data[4]), + (s16)(raw_data[7] << 8 | raw_data[6]), + (s16)(raw_data[9] << 8 | raw_data[8]), + (s16)(raw_data[11] << 8 | raw_data[10]), + sensor_time); + +} + +static ssize_t bmi160_step_counter_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = BMI_CALL_API(get_step_counter_enable)(&data); + + client_data->stc_enable = data; + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_step_counter_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_step_counter_enable)((unsigned char)data); + + client_data->stc_enable = data; + + if (err < 0) + return -EIO; + return count; +} + + +static ssize_t bmi160_step_counter_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_step_mode)((unsigned char)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_step_counter_clc_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = bmi160_clear_step_counter(); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_step_counter_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 data; + int err; + static u16 last_stc_value; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = BMI_CALL_API(read_step_count)(&data); + + if (err < 0) + return err; + if (data >= last_stc_value) { + client_data->pedo_data.last_step_counter_value += ( + data - last_stc_value); + last_stc_value = data; + } else + last_stc_value = data; + return sprintf(buf, "%d\n", + client_data->pedo_data.last_step_counter_value); +} + +static ssize_t bmi160_bmi_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + u8 raw_data[12] = {0}; + + int err; + memset(raw_data, 0, sizeof(raw_data)); + + err = client_data->device.bus_read(client_data->device.dev_addr, + BMI160_USER_DATA_8_GYRO_X_LSB__REG, raw_data, 12); + if (err) + return err; + /*output:gyro x y z acc x y z*/ + return sprintf(buf, "%hd %d %hd %hd %hd %hd\n", + (s16)(raw_data[1] << 8 | raw_data[0]), + (s16)(raw_data[3] << 8 | raw_data[2]), + (s16)(raw_data[5] << 8 | raw_data[4]), + (s16)(raw_data[7] << 8 | raw_data[6]), + (s16)(raw_data[9] << 8 | raw_data[8]), + (s16)(raw_data[11] << 8 | raw_data[10])); + +} + +static int bmi_ring_buf_get(struct bmi160_value_t *pData); +static ssize_t bmi160_ring_buf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + int len; + struct bmi160_value_t data; + char *tmp = buf; + + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + mutex_lock(&client_data->mutex_ring_buf); + while (bmi_ring_buf_get(&data) != 0) + { +#ifdef BMI160_MAG_INTERFACE_SUPPORT + len = snprintf(tmp, PAGE_SIZE, + "%d %d %d %d %d %d %d %d %d %lld", + data.acc.x, data.acc.y, data.acc.z, + data.gyro.x, data.gyro.y, data.gyro.z, + data.mag.x, data.mag.y, data.mag.z, + data.ts_intvl); + pr_info("%d %d %d %lld\n", + data.mag.x, + data.mag.y, + data.mag.z, + data.ts_intvl); +#else + len = snprintf(tmp, PAGE_SIZE, + "%d %d %d %d %d %d %lld", + data.acc.x, data.acc.y, data.acc.z, + data.gyro.x, data.gyro.y, data.gyro.z, + data.ts_intvl); +#endif + tmp += len; + err += len; + pr_info("%d %d %d %d %d %d %lld\n", + data.acc.x, data.acc.y, data.acc.z, + data.gyro.x, data.gyro.y, data.gyro.z, + data.ts_intvl); + + } + mutex_unlock(&client_data->mutex_ring_buf); + return err; + +} + +static ssize_t bmi160_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + return sprintf(buf, "0x%x\n", + atomic_read(&client_data->selftest_result)); +} + +static int bmi_restore_hw_cfg(struct bmi_client_data *client); +static void bmi_delay(u32 msec); +/*! + * @brief store selftest result which make up of acc and gyro + * format: 0b 0000 xxxx x:1 failed, 0 success + * bit3: gyro_self + * bit2..0: acc_self z y x + */ +static ssize_t bmi160_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err = 0; + int i = 0; + + u8 acc_selftest = 0; + u8 gyro_selftest = 0; + u8 bmi_selftest = 0; + s16 axis_p_value, axis_n_value; + u16 diff_axis[3] = {0xff, 0xff, 0xff}; + u8 acc_odr, range, acc_selftest_amp, acc_selftest_sign; + +#ifdef BMI160_MAG_INTERFACE_SUPPORT + struct bmi160_mag_xyz_s32_t pos_data; + struct bmi160_mag_xyz_s32_t neg_data; +#endif + + dev_notice(client_data->dev, "Selftest for BMI16x starting.\n"); + + client_data->selftest = 1; + +#ifdef BMI160_MAG_INTERFACE_SUPPORT + /* Power mode value 0x06 */ + err += bmi160_set_mag_write_data(BMI160_BMM_POWER_MODE_REG); + bmi_delay(BMI160_GEN_READ_WRITE_DELAY); + /*write 0x4C register to write set power mode to normal*/ + err += bmi160_set_mag_write_addr(BMI160_BMM150_POWE_MODE_REG); + bmi_delay(BMI160_GEN_READ_WRITE_DELAY); + + /* 0x18 Sets the PMU mode for the Magnetometer to suspend */ + err += bmi160_set_mag_write_data(MAG_MODE_SUSPEND); + bmi_delay(BMI160_GEN_READ_WRITE_DELAY); + /* write 0x18 to register 0x4E */ + err += bmi160_set_mag_write_addr(BMI160_USER_MAG_IF_3_ADDR); + /* write the Z repetitions*/ + /* The v_data_u8 have to write for the register + It write the value in the register 0x4F*/ + err += bmi160_set_mag_write_data(BMI160_MAG_REGULAR_REPZ); + bmi_delay(BMI160_GEN_READ_WRITE_DELAY); + err += bmi160_set_mag_write_addr(BMI160_BMM150_Z_REP); + bmi_delay(BMI160_GEN_READ_WRITE_DELAY); + + /* 0xC2 */ + err += bmi160_set_mag_write_data(0xC2); + bmi_delay(BMI160_GEN_READ_WRITE_DELAY); + /* write register 0x4C */ + err += bmi160_set_mag_write_addr(BMI160_BMM150_POWE_MODE_REG); + bmi_delay(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + + err += bmi160_bmm150_mag_compensate_xyz(&pos_data); + bmi_delay(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + /* 0X82 */ + err += bmi160_set_mag_write_data(0x82); + bmi_delay(BMI160_GEN_READ_WRITE_DELAY); + /* write register 0x4C */ + err += bmi160_set_mag_write_addr(BMI160_BMM150_POWE_MODE_REG); + + bmi_delay(BMI160_SEC_INTERFACE_GEN_READ_WRITE_DELAY); + err += bmi160_bmm150_mag_compensate_xyz(&neg_data); + + diff_axis[2] = pos_data.z - neg_data.z; + dev_info(client_data->dev, + "pos_data.x:%d, pos_data.y:%d, pos_data.z:%d,\nneg_data.x:%d, neg_data.y:%d, neg_data.z:%d\n", + pos_data.x, pos_data.y, pos_data.z, neg_data.x, neg_data.y, neg_data.z); +#endif + + /*soft reset*/ + err = BMI_CALL_API(set_command_register)(CMD_RESET_USER_REG); + msleep(70); + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_NORMAL]); + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_NORMAL]); + err += BMI_CALL_API(set_accel_under_sampling_parameter)(0); + err += BMI_CALL_API(set_accel_output_data_rate)( + BMI160_ACCEL_OUTPUT_DATA_RATE_1600HZ); + + /* set to 8G range*/ + err += BMI_CALL_API(set_accel_range)(BMI160_ACCEL_RANGE_8G); + /* set to self amp high */ + err += BMI_CALL_API(set_accel_selftest_amp)(BMI_SELFTEST_AMP_HIGH); + + + err += BMI_CALL_API(get_accel_output_data_rate)(&acc_odr); + err += BMI_CALL_API(get_accel_range)(&range); + err += BMI_CALL_API(get_accel_selftest_amp)(&acc_selftest_amp); + err += BMI_CALL_API(read_accel_x)(&axis_n_value); + + dev_info(client_data->dev, + "acc_odr:%d, acc_range:%d, acc_selftest_amp:%d, acc_x:%d\n", + acc_odr, range, acc_selftest_amp, axis_n_value); + + for (i = X_AXIS; i < AXIS_MAX; i++) { + axis_n_value = 0; + axis_p_value = 0; + /* set every selftest axis */ + /*set_acc_selftest_axis(param),param x:1, y:2, z:3 + * but X_AXIS:0, Y_AXIS:1, Z_AXIS:2 + * so we need to +1*/ + err += BMI_CALL_API(set_accel_selftest_axis)(i + 1); + msleep(50); + switch (i) { + case X_AXIS: + /* set negative sign */ + err += BMI_CALL_API(set_accel_selftest_sign)(0); + err += BMI_CALL_API(get_accel_selftest_sign)( + &acc_selftest_sign); + + msleep(60); + err += BMI_CALL_API(read_accel_x)(&axis_n_value); + dev_info(client_data->dev, + "acc_x_selftest_sign:%d, axis_n_value:%d\n", + acc_selftest_sign, axis_n_value); + + /* set postive sign */ + err += BMI_CALL_API(set_accel_selftest_sign)(1); + err += BMI_CALL_API(get_accel_selftest_sign)( + &acc_selftest_sign); + + msleep(60); + err += BMI_CALL_API(read_accel_x)(&axis_p_value); + dev_info(client_data->dev, + "acc_x_selftest_sign:%d, axis_p_value:%d\n", + acc_selftest_sign, axis_p_value); + diff_axis[i] = abs(axis_p_value - axis_n_value); + break; + + case Y_AXIS: + /* set negative sign */ + err += BMI_CALL_API(set_accel_selftest_sign)(0); + msleep(60); + err += BMI_CALL_API(read_accel_y)(&axis_n_value); + /* set postive sign */ + err += BMI_CALL_API(set_accel_selftest_sign)(1); + msleep(60); + err += BMI_CALL_API(read_accel_y)(&axis_p_value); + diff_axis[i] = abs(axis_p_value - axis_n_value); + break; + + case Z_AXIS: + /* set negative sign */ + err += BMI_CALL_API(set_accel_selftest_sign)(0); + msleep(60); + err += BMI_CALL_API(read_accel_z)(&axis_n_value); + /* set postive sign */ + err += BMI_CALL_API(set_accel_selftest_sign)(1); + msleep(60); + err += BMI_CALL_API(read_accel_z)(&axis_p_value); + /* also start gyro self test */ + err += BMI_CALL_API(set_gyro_selftest_start)(1); + msleep(60); + err += BMI_CALL_API(get_gyro_selftest)(&gyro_selftest); + + diff_axis[i] = abs(axis_p_value - axis_n_value); + break; + default: + err += -EINVAL; + break; + } + if (err) { + dev_err(client_data->dev, + "Failed selftest axis:%s, p_val=%d, n_val=%d\n", + bmi_axis_name[i], axis_p_value, axis_n_value); + client_data->selftest = 0; + return -EINVAL; + } + + /*400mg for acc z axis*/ + if (Z_AXIS == i) { + if (diff_axis[i] < 1639) { + acc_selftest |= 1 << i; + dev_err(client_data->dev, + "Over selftest minimum for " + "axis:%s,diff=%d,p_val=%d, n_val=%d\n", + bmi_axis_name[i], diff_axis[i], + axis_p_value, axis_n_value); + } + } else { + /*800mg for x or y axis*/ + if (diff_axis[i] < 3277) { + acc_selftest |= 1 << i; + + if (bmi_get_err_status(client_data) < 0) + return err; + dev_err(client_data->dev, + "Over selftest minimum for " + "axis:%s,diff=%d, p_val=%d, n_val=%d\n", + bmi_axis_name[i], diff_axis[i], + axis_p_value, axis_n_value); + dev_err(client_data->dev, "err_st:0x%x\n", + client_data->err_st.err_st_all); + + } + } + + } + /* gyro_selftest==1,gyro selftest successfully, + * but bmi_result bit4 0 is successful, 1 is failed*/ + bmi_selftest = (acc_selftest & 0x0f) | ((!gyro_selftest) << AXIS_MAX); + atomic_set(&client_data->selftest_result, bmi_selftest); + /*soft reset*/ + err = BMI_CALL_API(set_command_register)(CMD_RESET_USER_REG); + if (err) { + client_data->selftest = 0; + return err; + } + msleep(50); + + bmi_restore_hw_cfg(client_data); + + client_data->selftest = 0; + dev_notice(client_data->dev, "Selftest for BMI16x finished\n"); + + return count; +} + +/* gyro sensor part */ +static ssize_t bmi160_gyro_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + int err = 0; + u8 gyro_pmu_status = 0; + + err = BMI_CALL_API(get_gyro_power_mode_stat)( + &gyro_pmu_status); + + if (err) + return err; + else + return sprintf(buf, "reg:%d, val:%d\n", gyro_pmu_status, + client_data->pw.gyro_pm); +} + +static ssize_t bmi160_gyro_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + unsigned long op_mode; + int err; + + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + + mutex_lock(&client_data->mutex_op_mode); + + if (op_mode < BMI_GYRO_PM_MAX) { + switch (op_mode) { + case BMI_GYRO_PM_NORMAL: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_NORMAL]); + client_data->pw.gyro_pm = BMI_GYRO_PM_NORMAL; + mdelay(60); + break; + case BMI_GYRO_PM_FAST_START: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_FAST_START]); + client_data->pw.gyro_pm = BMI_GYRO_PM_FAST_START; + mdelay(60); + break; + case BMI_GYRO_PM_SUSPEND: + err = BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_SUSPEND]); + client_data->pw.gyro_pm = BMI_GYRO_PM_SUSPEND; + mdelay(60); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + + if (err) + return err; + else + return count; + +} + +static ssize_t bmi160_gyro_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + struct bmi160_gyro_t data; + struct bmi160_axis_data_t bmi160_udata; + int err; + + err = BMI_CALL_API(read_gyro_xyz)(&data); + if (err < 0) + return err; + + bmi160_udata.x = data.x; + bmi160_udata.y = data.y; + bmi160_udata.z = data.z; + + bmi_remap_sensor_data(&bmi160_udata, client_data); + + return sprintf(buf, "%hd %hd %hd\n", bmi160_udata.x, + bmi160_udata.y, bmi160_udata.z); +} + +static ssize_t bmi160_gyro_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char range; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = BMI_CALL_API(get_gyro_range)(&range); + if (err) + return err; + + client_data->range.gyro_range = range; + return sprintf(buf, "%d\n", range); +} + +static ssize_t bmi160_gyro_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long range; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &range); + if (err) + return err; + + err = BMI_CALL_API(set_gyro_range)(range); + if (err) + return -EIO; + + client_data->range.gyro_range = range; + return count; +} + +static ssize_t bmi160_gyro_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + unsigned char gyro_odr; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = BMI_CALL_API(get_gyro_output_data_rate)(&gyro_odr); + if (err) + return err; + + client_data->odr.gyro_odr = gyro_odr; + return sprintf(buf, "%d\n", gyro_odr); +} + +static ssize_t bmi160_gyro_odr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long gyro_odr; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &gyro_odr); + if (err) + return err; + + if (gyro_odr < 6 || gyro_odr > 13) + return -EIO; + + err = BMI_CALL_API(set_gyro_output_data_rate)(gyro_odr); + if (err) + return -EIO; + + client_data->odr.gyro_odr = gyro_odr; + return count; +} + +static ssize_t bmi160_gyro_fast_calibration_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned char data; + int err; + + err = BMI_CALL_API(get_foc_gyro_enable)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_gyro_fast_calibration_en_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long enable; + s8 err; + s16 gyr_off_x; + s16 gyr_off_y; + s16 gyr_off_z; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + + err = BMI_CALL_API(set_foc_gyro_enable)((u8)enable, + &gyr_off_x, &gyr_off_y, &gyr_off_z); + + if (err < 0) + return -EIO; + else { + input_event(client_data->input_gyro, EV_MSC, + INPUT_EVENT_FAST_GYRO_CALIB_DONE, 1); + input_sync(client_data->input_gyro); + } + return count; +} + +static ssize_t bmi160_gyro_offset_x_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 data = 0; + s8 err = 0; + + err = BMI_CALL_API(get_gyro_offset_compensation_xaxis)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_gyro_offset_x_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + s8 err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_gyro_offset_compensation_xaxis)((s16)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_gyro_offset_y_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 data = 0; + s8 err = 0; + + err = BMI_CALL_API(get_gyro_offset_compensation_yaxis)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_gyro_offset_y_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + s8 err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_gyro_offset_compensation_yaxis)((s16)data); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_gyro_offset_z_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 data = 0; + int err = 0; + + err = BMI_CALL_API(get_gyro_offset_compensation_zaxis)(&data); + + if (err < 0) + return err; + return sprintf(buf, "%d\n", data); +} + +static ssize_t bmi160_gyro_offset_z_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err = BMI_CALL_API(set_gyro_offset_compensation_zaxis)((s16)data); + + if (err < 0) + return -EIO; + return count; +} + + +/* mag sensor part */ +#ifdef BMI160_MAG_INTERFACE_SUPPORT +static ssize_t bmi160_mag_op_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + u8 mag_op_mode; + s8 err; + err = bmi160_get_mag_power_mode_stat(&mag_op_mode); + if (err) { + dev_err(client_data->dev, + "Failed to get BMI160 mag power mode:%d\n", err); + return err; + } else + return sprintf(buf, "%d, reg:%d\n", + client_data->pw.mag_pm, mag_op_mode); +} + +static ssize_t bmi160_mag_op_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + unsigned long op_mode; + int err; + + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + + if (op_mode == client_data->pw.mag_pm) + return count; + + mutex_lock(&client_data->mutex_op_mode); + + + if (op_mode < BMI_MAG_PM_MAX) { + switch (op_mode) { + case BMI_MAG_PM_NORMAL: + /* need to modify as mag sensor connected, + * set write address to 0x4c and triggers + * write operation + * 0x4c(op mode control reg) + * enables normal mode in magnetometer */ +#ifdef BMI160_AKM09912_SUPPORT + err = bmi160_set_bst_akm_and_secondary_if_powermode + (BMI160_MAG_FORCE_MODE); +#else + err = bmi160_set_bmm150_mag_and_secondary_if_power_mode + (BMI160_MAG_FORCE_MODE); +#endif + client_data->pw.mag_pm = BMI_MAG_PM_NORMAL; + mdelay(5); + break; + case BMI_MAG_PM_LP1: + /* need to modify as mag sensor connected, + * set write address to 0x4 band triggers + * write operation + * 0x4b(bmm150, power control reg, bit0) + * enables power in magnetometer*/ +#ifdef BMI160_AKM09912_SUPPORT + err = bmi160_set_bst_akm_and_secondary_if_powermode + (BMI160_MAG_FORCE_MODE); +#else + err = bmi160_set_bmm150_mag_and_secondary_if_power_mode + (BMI160_MAG_FORCE_MODE); +#endif + client_data->pw.mag_pm = BMI_MAG_PM_LP1; + mdelay(5); + break; + case BMI_MAG_PM_SUSPEND: + case BMI_MAG_PM_LP2: +#ifdef BMI160_AKM09912_SUPPORT + err = bmi160_set_bst_akm_and_secondary_if_powermode + (BMI160_MAG_SUSPEND_MODE); +#else + err = bmi160_set_bmm150_mag_and_secondary_if_power_mode + (BMI160_MAG_SUSPEND_MODE); +#endif + client_data->pw.mag_pm = op_mode; + mdelay(5); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + + if (err) { + dev_err(client_data->dev, + "Failed to switch BMI160 mag power mode:%d\n", + client_data->pw.mag_pm); + return err; + } else + return count; + +} + +static ssize_t bmi160_mag_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + unsigned char mag_odr = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = BMI_CALL_API(get_mag_output_data_rate)(&mag_odr); + if (err) + return err; + + client_data->odr.mag_odr = mag_odr; + return sprintf(buf, "%d\n", mag_odr); +} + +static ssize_t bmi160_mag_odr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + unsigned long mag_odr; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &mag_odr); + if (err) + return err; + /*1~25/32hz,..6(25hz),7(50hz),... */ + err = BMI_CALL_API(set_mag_output_data_rate)(mag_odr); + if (err) + return -EIO; + + client_data->odr.mag_odr = mag_odr; + return count; +} + +static ssize_t bmi160_mag_i2c_address_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + s8 err; + + err = BMI_CALL_API(set_mag_manual_enable)(1); + err += BMI_CALL_API(get_i2c_device_addr)(&data); + err += BMI_CALL_API(set_mag_manual_enable)(0); + + if (err < 0) + return err; + return sprintf(buf, "0x%x\n", data); +} + +static ssize_t bmi160_mag_i2c_address_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err += BMI_CALL_API(set_mag_manual_enable)(1); + if (!err) + err += BMI_CALL_API(set_i2c_device_addr)((unsigned char)data); + err += BMI_CALL_API(set_mag_manual_enable)(0); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_mag_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + struct bmi160_mag_xyz_s32_t data; + + struct bmi160_axis_data_t bmi160_udata; + int err; + /* raw data with compensation */ +#ifdef BMI160_AKM09912_SUPPORT + err = bmi160_bst_akm09912_compensate_xyz(&data); +#else + err = bmi160_bmm150_mag_compensate_xyz(&data); +#endif + + if (err < 0) { + memset(&data, 0, sizeof(data)); + dev_err(client_data->dev, "mag not ready!\n"); + } + bmi160_udata.x = data.x; + bmi160_udata.y = data.y; + bmi160_udata.z = data.z; + + bmi_remap_sensor_data(&bmi160_udata, client_data); + return sprintf(buf, "%hd %hd %hd\n", bmi160_udata.x, + bmi160_udata.y, bmi160_udata.z); + +} + +static ssize_t bmi160_mag_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + unsigned char mag_offset; + err = BMI_CALL_API(get_mag_offset)(&mag_offset); + if (err) + return err; + + return sprintf(buf, "%d\n", mag_offset); + +} + +static ssize_t bmi160_mag_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long data; + int err; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + err += BMI_CALL_API(set_mag_manual_enable)(1); + if (err == 0) + err += BMI_CALL_API(set_mag_offset)((unsigned char)data); + err += BMI_CALL_API(set_mag_manual_enable)(0); + + if (err < 0) + return -EIO; + return count; +} + +static ssize_t bmi160_mag_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s8 err = 0; + u8 mag_chipid; + + err = bmi160_set_mag_manual_enable(0x01); + /* read mag chip_id value */ +#ifdef BMI160_AKM09912_SUPPORT + err += bmi160_set_mag_read_addr(AKM09912_CHIP_ID_REG); + /* 0x04 is mag_x lsb register */ + err += bmi160_read_reg(BMI160_USER_DATA_0_MAG_X_LSB__REG, + &mag_chipid, 1); + + /* Must add this commands to re-set data register addr of mag sensor */ + err += bmi160_set_mag_read_addr(AKM_DATA_REGISTER); +#else + err += bmi160_set_mag_read_addr(BMI160_BMM150_CHIP_ID); + /* 0x04 is mag_x lsb register */ + err += bmi160_read_reg(BMI160_USER_DATA_0_MAG_X_LSB__REG, + &mag_chipid, 1); + + /* Must add this commands to re-set data register addr of mag sensor */ + /* 0x42 is bmm150 data register address */ + err += bmi160_set_mag_read_addr(BMI160_BMM150_DATA_REG); +#endif + + err += bmi160_set_mag_manual_enable(0x00); + + if (err) + return err; + + return sprintf(buf, "chip_id:0x%x\n", mag_chipid); + +} + +#endif + +#if defined(BMI160_ENABLE_INT1) || defined(BMI160_ENABLE_INT2) +static ssize_t bmi_enable_int_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int interrupt_type, value; + + sscanf(buf, "%3d %3d", &interrupt_type, &value); + + if (interrupt_type < 0 || interrupt_type > 16) + return -EINVAL; + + if (interrupt_type <= BMI_FLAT_INT) { + if (BMI_CALL_API(set_intr_enable_0) + (bmi_interrupt_type[interrupt_type], value) < 0) + return -EINVAL; + } else if (interrupt_type <= BMI_FWM_INT) { + if (BMI_CALL_API(set_intr_enable_1) + (bmi_interrupt_type[interrupt_type], value) < 0) + return -EINVAL; + } else { + if (BMI_CALL_API(set_intr_enable_2) + (bmi_interrupt_type[interrupt_type], value) < 0) + return -EINVAL; + } + + return count; +} + +#endif + +static ssize_t bmi_register_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmi_client_data *client_data = dev_get_drvdata(dev); + bmi_dump_reg(client_data); + + return sprintf(buf, "Dump OK\n"); +} + +static ssize_t bmi_register_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + int reg_addr = 0; + int data; + u8 write_reg_add = 0; + u8 write_data = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + err = sscanf(buf, "%3d %3d", ®_addr, &data); + if (err < 2) + return err; + + if (data > 0xff) + return -EINVAL; + + write_reg_add = (u8)reg_addr; + write_data = (u8)data; + err += BMI_CALL_API(write_reg)(write_reg_add, &write_data, 1); + + if (!err) { + dev_info(client_data->dev, "write reg 0x%2x, value= 0x%2x\n", + reg_addr, data); + } else { + dev_err(client_data->dev, "write reg fail\n"); + return err; + } + return count; +} + +static DEVICE_ATTR(chip_id, S_IRUGO, + bmi160_chip_id_show, NULL); +static DEVICE_ATTR(err_st, S_IRUGO, + bmi160_err_st_show, NULL); +static DEVICE_ATTR(sensor_time, S_IRUGO, + bmi160_sensor_time_show, NULL); + +static DEVICE_ATTR(selftest, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_selftest_show, bmi160_selftest_store); +static DEVICE_ATTR(fifo_flush, S_IWUSR|S_IWGRP/*|S_IWOTH*/, + NULL, bmi160_fifo_flush_store); +static DEVICE_ATTR(fifo_bytecount, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_fifo_bytecount_show, bmi160_fifo_bytecount_store); +static DEVICE_ATTR(fifo_data_sel, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_fifo_data_sel_show, bmi160_fifo_data_sel_store); +static DEVICE_ATTR(fifo_data_frame, S_IRUGO, + bmi160_fifo_data_out_frame_show, NULL); + +static DEVICE_ATTR(fifo_watermark, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_fifo_watermark_show, bmi160_fifo_watermark_store); + +static DEVICE_ATTR(fifo_header_en, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_fifo_header_en_show, bmi160_fifo_header_en_store); +static DEVICE_ATTR(fifo_time_en, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_fifo_time_en_show, bmi160_fifo_time_en_store); +static DEVICE_ATTR(fifo_int_tag_en, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_fifo_int_tag_en_show, bmi160_fifo_int_tag_en_store); + +static DEVICE_ATTR(temperature, S_IRUGO, + bmi160_temperature_show, NULL); +static DEVICE_ATTR(place, S_IRUGO, + bmi160_place_show, NULL); +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_delay_show, bmi160_delay_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_enable_show, bmi160_enable_store); +static DEVICE_ATTR(acc_range, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_range_show, bmi160_acc_range_store); +static DEVICE_ATTR(acc_odr, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_odr_show, bmi160_acc_odr_store); +static DEVICE_ATTR(acc_op_mode, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_op_mode_show, bmi160_acc_op_mode_store); +static DEVICE_ATTR(acc_value, S_IRUGO, + bmi160_acc_value_show, NULL); +static DEVICE_ATTR(acc_fast_calibration_x, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_fast_calibration_x_show, + bmi160_acc_fast_calibration_x_store); +static DEVICE_ATTR(acc_fast_calibration_y, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_fast_calibration_y_show, + bmi160_acc_fast_calibration_y_store); +static DEVICE_ATTR(acc_fast_calibration_z, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_fast_calibration_z_show, + bmi160_acc_fast_calibration_z_store); +static DEVICE_ATTR(acc_offset_x, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_offset_x_show, + bmi160_acc_offset_x_store); +static DEVICE_ATTR(acc_offset_y, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_offset_y_show, + bmi160_acc_offset_y_store); +static DEVICE_ATTR(acc_offset_z, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_acc_offset_z_show, + bmi160_acc_offset_z_store); +static DEVICE_ATTR(test, S_IRUGO, + bmi160_test_show, NULL); +static DEVICE_ATTR(stc_enable, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_step_counter_enable_show, + bmi160_step_counter_enable_store); +static DEVICE_ATTR(stc_mode, S_IWUSR|S_IWGRP/*|S_IWOTH*/, + NULL, bmi160_step_counter_mode_store); +static DEVICE_ATTR(stc_clc, S_IWUSR|S_IWGRP/*|S_IWOTH*/, + NULL, bmi160_step_counter_clc_store); +static DEVICE_ATTR(stc_value, S_IRUGO, + bmi160_step_counter_value_show, NULL); + + +/* gyro part */ +static DEVICE_ATTR(gyro_op_mode, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_gyro_op_mode_show, bmi160_gyro_op_mode_store); +static DEVICE_ATTR(gyro_value, S_IRUGO, + bmi160_gyro_value_show, NULL); +static DEVICE_ATTR(gyro_range, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_gyro_range_show, bmi160_gyro_range_store); +static DEVICE_ATTR(gyro_odr, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_gyro_odr_show, bmi160_gyro_odr_store); +static DEVICE_ATTR(gyro_fast_calibration_en, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, +bmi160_gyro_fast_calibration_en_show, bmi160_gyro_fast_calibration_en_store); +static DEVICE_ATTR(gyro_offset_x, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, +bmi160_gyro_offset_x_show, bmi160_gyro_offset_x_store); +static DEVICE_ATTR(gyro_offset_y, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, +bmi160_gyro_offset_y_show, bmi160_gyro_offset_y_store); +static DEVICE_ATTR(gyro_offset_z, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, +bmi160_gyro_offset_z_show, bmi160_gyro_offset_z_store); + +#ifdef BMI160_MAG_INTERFACE_SUPPORT +static DEVICE_ATTR(mag_op_mode, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_mag_op_mode_show, bmi160_mag_op_mode_store); +static DEVICE_ATTR(mag_odr, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_mag_odr_show, bmi160_mag_odr_store); +static DEVICE_ATTR(mag_i2c_addr, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_mag_i2c_address_show, bmi160_mag_i2c_address_store); +static DEVICE_ATTR(mag_value, S_IRUGO, + bmi160_mag_value_show, NULL); +static DEVICE_ATTR(mag_offset, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_mag_offset_show, bmi160_mag_offset_store); + +static DEVICE_ATTR(mag_chip_id, S_IRUGO, + bmi160_mag_chip_id_show, NULL); + +#endif + + +#if defined(BMI160_ENABLE_INT1) || defined(BMI160_ENABLE_INT2) +static DEVICE_ATTR(enable_int, S_IWUSR|S_IWGRP/*|S_IWOTH*/, + NULL, bmi_enable_int_store); +static DEVICE_ATTR(anymot_duration, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_anymot_duration_show, bmi160_anymot_duration_store); +static DEVICE_ATTR(anymot_threshold, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_anymot_threshold_show, bmi160_anymot_threshold_store); +static DEVICE_ATTR(std_stu, S_IRUGO, + bmi160_step_detector_status_show, NULL); +static DEVICE_ATTR(std_en, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_step_detector_enable_show, + bmi160_step_detector_enable_store); +static DEVICE_ATTR(sig_en, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi160_signification_motion_enable_show, + bmi160_signification_motion_enable_store); + +#endif +static DEVICE_ATTR(enable_timer, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi_show_enable_timer, bmi_store_enable_timer); + +static DEVICE_ATTR(register, S_IRUGO|S_IWUSR|S_IWGRP/*|S_IWOTH*/, + bmi_register_show, bmi_register_store); + +static DEVICE_ATTR(bmi_value, S_IRUGO, + bmi160_bmi_value_show, NULL); + +static DEVICE_ATTR(bmi_ring_buf, S_IRUGO, + bmi160_ring_buf_show, NULL); + + +static struct attribute *bmi160_attributes[] = { + &dev_attr_chip_id.attr, + &dev_attr_err_st.attr, + &dev_attr_sensor_time.attr, + &dev_attr_selftest.attr, + + &dev_attr_test.attr, + &dev_attr_fifo_flush.attr, + &dev_attr_fifo_header_en.attr, + &dev_attr_fifo_time_en.attr, + &dev_attr_fifo_int_tag_en.attr, + &dev_attr_fifo_bytecount.attr, + &dev_attr_fifo_data_sel.attr, + &dev_attr_fifo_data_frame.attr, + + &dev_attr_fifo_watermark.attr, + + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_temperature.attr, + &dev_attr_place.attr, + + &dev_attr_acc_range.attr, + &dev_attr_acc_odr.attr, + &dev_attr_acc_op_mode.attr, + &dev_attr_acc_value.attr, + + &dev_attr_acc_fast_calibration_x.attr, + &dev_attr_acc_fast_calibration_y.attr, + &dev_attr_acc_fast_calibration_z.attr, + &dev_attr_acc_offset_x.attr, + &dev_attr_acc_offset_y.attr, + &dev_attr_acc_offset_z.attr, + + &dev_attr_stc_enable.attr, + &dev_attr_stc_mode.attr, + &dev_attr_stc_clc.attr, + &dev_attr_stc_value.attr, + + &dev_attr_gyro_op_mode.attr, + &dev_attr_gyro_value.attr, + &dev_attr_gyro_range.attr, + &dev_attr_gyro_odr.attr, + &dev_attr_gyro_fast_calibration_en.attr, + &dev_attr_gyro_offset_x.attr, + &dev_attr_gyro_offset_y.attr, + &dev_attr_gyro_offset_z.attr, + +#ifdef BMI160_MAG_INTERFACE_SUPPORT + &dev_attr_mag_chip_id.attr, + &dev_attr_mag_op_mode.attr, + &dev_attr_mag_odr.attr, + &dev_attr_mag_i2c_addr.attr, + &dev_attr_mag_value.attr, + &dev_attr_mag_offset.attr, + +#endif + +#if defined(BMI160_ENABLE_INT1) || defined(BMI160_ENABLE_INT2) + &dev_attr_enable_int.attr, + + &dev_attr_anymot_duration.attr, + &dev_attr_anymot_threshold.attr, + &dev_attr_std_stu.attr, + &dev_attr_std_en.attr, + &dev_attr_sig_en.attr, + +#endif + &dev_attr_enable_timer.attr, + &dev_attr_register.attr, + &dev_attr_bmi_value.attr, + &dev_attr_bmi_ring_buf.attr, + NULL +}; + +static struct attribute_group bmi160_attribute_group = { + .attrs = bmi160_attributes +}; + +static void bmi_delay(u32 msec) +{ + mdelay(msec); +} + +#if defined(BMI160_ENABLE_INT1) || defined(BMI160_ENABLE_INT2) +static void bmi_slope_interrupt_handle(struct bmi_client_data *client_data) +{ + /* anym_first[0..2]: x, y, z */ + u8 anym_first[3] = {0}; + u8 status2; + u8 anym_sign; + u8 i = 0; + + client_data->device.bus_read(client_data->device.dev_addr, + BMI160_USER_INTR_STAT_2_ADDR, &status2, 1); + anym_first[0] = BMI160_GET_BITSLICE(status2, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_X); + anym_first[1] = BMI160_GET_BITSLICE(status2, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Y); + anym_first[2] = BMI160_GET_BITSLICE(status2, + BMI160_USER_INTR_STAT_2_ANY_MOTION_FIRST_Z); + anym_sign = BMI160_GET_BITSLICE(status2, + BMI160_USER_INTR_STAT_2_ANY_MOTION_SIGN); + + for (i = 0; i < 3; i++) { + if (anym_first[i]) { + /*1: negative*/ + if (anym_sign) + dev_notice(client_data->dev, + "Anymotion interrupt happend!" + "%s axis, negative sign\n", bmi_axis_name[i]); + else + dev_notice(client_data->dev, + "Anymotion interrupt happend!" + "%s axis, postive sign\n", bmi_axis_name[i]); + } + } + + +} + +static uint64_t bmi_get_alarm_timestamp_ns(void) +{ + uint64_t ts_ap; + struct timespec tmp_time; + get_monotonic_boottime(&tmp_time); + ts_ap = (uint64_t)tmp_time.tv_sec * 1000000000L + tmp_time.tv_nsec; + return ts_ap; +} + + +static int bmi_ring_buf_empty(void) +{ + return s_ring_buf_head == s_ring_buf_tail; +} + +static int bmi_ring_buf_full(void) +{ + return (s_ring_buf_tail + 1) % BMI_RING_BUF_SIZE == s_ring_buf_head; +} + +static int bmi_ring_buf_put(struct bmi160_value_t data) +{ + if (bmi_ring_buf_full()) + return 0; + + bmi_ring_buf[s_ring_buf_tail].acc.x = data.acc.x; + bmi_ring_buf[s_ring_buf_tail].acc.y = data.acc.y; + bmi_ring_buf[s_ring_buf_tail].acc.z = data.acc.z; + bmi_ring_buf[s_ring_buf_tail].gyro.x = data.gyro.x; + bmi_ring_buf[s_ring_buf_tail].gyro.y = data.gyro.y; + bmi_ring_buf[s_ring_buf_tail].gyro.z = data.gyro.z; +#ifdef BMI160_MAG_INTERFACE_SUPPORT + bmi_ring_buf[s_ring_buf_tail].mag.x = data.mag.x; + bmi_ring_buf[s_ring_buf_tail].mag.y = data.mag.y; + bmi_ring_buf[s_ring_buf_tail].mag.z = data.mag.z; +#endif + bmi_ring_buf[s_ring_buf_tail].ts_intvl= data.ts_intvl; + s_ring_buf_tail = (s_ring_buf_tail + 1) % BMI_RING_BUF_SIZE; + + return 1; +} + +static int bmi_ring_buf_get(struct bmi160_value_t *pData) +{ + if (bmi_ring_buf_empty()) + return 0; + + pData->acc.x = bmi_ring_buf[s_ring_buf_head].acc.x; + pData->acc.y = bmi_ring_buf[s_ring_buf_head].acc.y; + pData->acc.z = bmi_ring_buf[s_ring_buf_head].acc.z; + pData->gyro.x = bmi_ring_buf[s_ring_buf_head].gyro.x; + pData->gyro.y = bmi_ring_buf[s_ring_buf_head].gyro.y; + pData->gyro.z = bmi_ring_buf[s_ring_buf_head].gyro.z; +#ifdef BMI160_MAG_INTERFACE_SUPPORT + pData->mag.x = bmi_ring_buf[s_ring_buf_head].mag.x; + pData->mag.y = bmi_ring_buf[s_ring_buf_head].mag.y; + pData->mag.z = bmi_ring_buf[s_ring_buf_head].mag.z; +#endif + pData->ts_intvl = bmi_ring_buf[s_ring_buf_head].ts_intvl; + + s_ring_buf_head = (s_ring_buf_head + 1) % BMI_RING_BUF_SIZE; + + return 1; +} + + +static int bmi_fifo_get_decode_data(struct bmi160_axis_data_t *acc, + struct bmi160_axis_data_t *gyro, + struct bmi160_axis_data_t *mag, + u8 *fifo_data, + u16 fifo_index) +{ + /* array index to get elements from fifo data*/ + u16 array_index = 0; + + /* get xyzr axis mag data */ + if (mag != NULL) + { + struct bmi160_mag_xyzr_t mag_valid; + struct bmi160_mag_xyzr_t mag_data; + struct bmi160_mag_xyz_s32_t mag_comp_xyz; + mag_data.x = fifo_data[fifo_index + 0] + | fifo_data[fifo_index + 1] << 8; + mag_data.y = fifo_data[fifo_index + 2] + | fifo_data[fifo_index + 3] << 8; + mag_data.z = fifo_data[fifo_index + 4] + | fifo_data[fifo_index + 5] << 8; + mag_data.r = fifo_data[fifo_index + 6] + | fifo_data[fifo_index + 7] << 8; + fifo_index += 8; + mag_valid.x = mag_data.x >> 3; + mag_valid.y = mag_data.y >> 3; + mag_valid.z = mag_data.z >> 1; + mag_valid.r = mag_data.r >> 2; + bmi160_bmm150_mag_compensate_xyz_raw(&mag_comp_xyz, mag_valid); + mag->x = mag_comp_xyz.x; + mag->y = mag_comp_xyz.y; + mag->z = mag_comp_xyz.z; + } + + /* get xyz axis gyro data */ + if (gyro != NULL) + { + gyro->x = fifo_data[fifo_index + 0] + | fifo_data[fifo_index + 1] << 8; + gyro->y = fifo_data[fifo_index + 2] + | fifo_data[fifo_index + 3] << 8; + gyro->z = fifo_data[fifo_index + 4] + | fifo_data[fifo_index + 5] << 8; + fifo_index += 6; + } + + /* get xyz axis accel data */ + if (acc != NULL) + { + acc->x = fifo_data[fifo_index + 0] + | fifo_data[fifo_index + 1] << 8; + acc->y = fifo_data[fifo_index + 2] + | fifo_data[fifo_index + 3] << 8; + acc->z = fifo_data[fifo_index + 4] + | fifo_data[fifo_index + 5] << 8; + fifo_index += 6; + } + + return array_index; + +} + +static int bmi_pow(int x, int y) +{ + int result = 1; + + if (y == 1) + return x; + + + if (y > 0) { + while (--y) { + result *= x; + } + } else { + result = 0; + } + + return result; +} + +/* +* Decoding of FIFO frames (only exemplary subset). Calculates accurate timestamps based on the +* drift information. Returns value of the SENSORTIME frame. +* +* fifo_data_buf - pointer to fetched FIFO buffer +* fifo_length - number of valid bytes in the FIFO buffer +* drift - clock drift value, needed to calculate accurate timestamps +* timestamp - initial timestamp for the first sample of the FIFO chunk +* acc_odr - current value of the ACC_CONF.acc_odr register field +*/ +static uint64_t bmi_fifo_data_decode(uint8_t *fifo_data_buf, uint16_t fifo_length, + int drift, uint64_t timestamp, int odr_pow) +{ + int idx = 0; + uint8_t header; + uint64_t fifo_time = 0; + uint64_t timestamp_next = timestamp; + struct bmi160_value_t bmi160_value; + + while (idx < fifo_length) { + header = fifo_data_buf[idx]; + memset(&bmi160_value, 0, sizeof (bmi160_value)); + switch (header) { + case FIFO_HEAD_SENSOR_TIME: + /* sensortime frame, length = 4 bytes*/ + if (idx + 3 < fifo_length) { + fifo_time = fifo_data_buf[idx + 1] | + fifo_data_buf[idx + 2] << 8 | + fifo_data_buf[idx + 3] << 16; + return fifo_time; + } + idx += 4; + break; + case FIFO_HEAD_A: + /* accel frame, length = 7 bytes */ + idx += 1; + if (idx + 6 < fifo_length) { + bmi_fifo_get_decode_data( + &bmi160_value.acc, + NULL, NULL, + fifo_data_buf, idx); + bmi160_value.ts_intvl = + (int64_t)(625 * odr_pow * (drift > 0 ? drift : 1000)); + if (bmi_ring_buf_put(bmi160_value) == 0) + pr_info("bmi ring buf full head %d, tail %d", + s_ring_buf_head, s_ring_buf_tail); + if (drift > 0) + timestamp_next += (uint64_t)(625 * odr_pow * drift); + else + timestamp_next += (uint64_t)(625 * odr_pow * 1000); + } + idx += 6; + break; + case FIFO_HEAD_G: + /* gyro frame, length = 7 bytes */ + idx += 1; + if (idx + 6 < fifo_length) { + bmi_fifo_get_decode_data(NULL, + &bmi160_value.gyro, + NULL, fifo_data_buf, idx); + bmi160_value.ts_intvl = + (int64_t)(625 * odr_pow * (drift > 0 ? drift : 1000)); + if (bmi_ring_buf_put(bmi160_value) == 0) + pr_info("bmi ring buf full head %d, tail %d", + s_ring_buf_head, s_ring_buf_tail); + } + + idx += 6; + break; + case FIFO_HEAD_G_A: + idx += 1; + if (idx + 12 < fifo_length) { + bmi_fifo_get_decode_data(&bmi160_value.acc, + &bmi160_value.gyro, + NULL, fifo_data_buf, idx); + bmi160_value.ts_intvl = + (int64_t)(625 * odr_pow * (drift > 0 ? drift : 1000)); + if (bmi_ring_buf_put(bmi160_value) == 0) + pr_info("bmi ring buf full head %d, tail %d", + s_ring_buf_head, s_ring_buf_tail); + } + + idx += 12; + break; +#ifdef BMI160_MAG_INTERFACE_SUPPORT + case FIFO_HEAD_M: + idx +=1; + if (idx + 8 < fifo_length) { + bmi_fifo_get_decode_data(NULL, NULL, + &bmi160_value.mag, + fifo_data_buf, idx); + bmi160_value.ts_intvl = + (int64_t)(625 * odr_pow * (drift > 0 ? drift : 1000)); + if (bmi_ring_buf_put(bmi160_value) == 0) + pr_info("bmi ring buf full head %d, tail %d", + s_ring_buf_head, s_ring_buf_tail); + } + + idx += 8; + break; + case FIFO_HEAD_M_A: + idx +=1; + if (idx + 14 < fifo_length) { + bmi_fifo_get_decode_data(&bmi160_value.acc, NULL, + &bmi160_value.mag, fifo_data_buf, idx); + bmi160_value.ts_intvl = + (int64_t)(625 * odr_pow * (drift > 0 ? drift : 1000)); + if (bmi_ring_buf_put(bmi160_value) == 0) + pr_info("bmi ring buf full head %d, tail %d", + s_ring_buf_head, s_ring_buf_tail); + } + + idx += 14; + break; + + case FIFO_HEAD_M_G: + idx +=1; + if (idx + 14 < fifo_length) { + bmi_fifo_get_decode_data(NULL, &bmi160_value.gyro, + &bmi160_value.mag, fifo_data_buf, idx); + bmi160_value.ts_intvl = + (int64_t)(625 * odr_pow * (drift > 0 ? drift : 1000)); + if (bmi_ring_buf_put(bmi160_value) == 0) + pr_info("bmi ring buf full head %d, tail %d", + s_ring_buf_head, s_ring_buf_tail); + } + + idx += 14; + break; + case FIFO_HEAD_M_G_A: + idx +=1; + if (idx + 20 < fifo_length) { + bmi_fifo_get_decode_data(&bmi160_value.acc, + &bmi160_value.gyro, + &bmi160_value.mag, fifo_data_buf, idx); + bmi160_value.ts_intvl = + (int64_t)(625 * odr_pow * (drift > 0 ? drift : 1000)); + if (bmi_ring_buf_put(bmi160_value) == 0) + pr_info("bmi ring buf full head %d, tail %d", + s_ring_buf_head, s_ring_buf_tail); + } + + idx += 20; + pr_info("second interface mag"); + break; +#endif + case FIFO_HEAD_OVER_READ_LSB: + /* end of fifo chunk */ + idx = fifo_length; + break; + default: + pr_info("ERROR parsing FIFO!! header 0x%x", header); + idx = fifo_length; + break; + } + } + + return -1; +} + +static uint64_t bmi_fifo_next_timestamp_calc(uint64_t host_time_new, + uint64_t sensor_time_new, + int drift, int odr_pow, + uint8_t bmi_odr) +{ + uint64_t time_age = ((sensor_time_new & (0xFFFF >> bmi_odr)) + * (drift > 0 ? drift : 1000)) * 390625; + return ((host_time_new - div64_u64(time_age, 10000000) + + ((drift > 0 ? drift : 1000) * (625 * odr_pow)))); +} + +static int bmi_fifo_time_drift_calc(uint64_t host_time_new, + uint64_t sensor_time_new, + uint64_t host_time_old, + uint64_t sensor_time_old) +{ + uint64_t delta_st, delta_ht; + int drift = 0; + + if (host_time_old > 0) { + delta_st = sensor_time_new >= sensor_time_old ? + (sensor_time_new - sensor_time_old) : + (sensor_time_new + FIFO_SENSORTIME_OVERFLOW_MASK - sensor_time_old); + delta_ht = host_time_new - host_time_old; + if (delta_st != 0) + drift = (int)div64_u64(delta_ht * 10000, + (delta_st * FIFO_SENSORTIME_RESOLUTION)); + else + drift = 0; + + } else { + drift = 0; + } + + return drift; +} + +static void bmi_fifo_watermark_interrupt_handle + (struct bmi_client_data *client_data) +{ + int err = 0; + unsigned int fifo_len0 = 0; + unsigned int fifo_frmbytes_ext = 0; + static int time_drift = 0; + static uint64_t timestamp_next = 0; + uint8_t bmi_odr = client_data->odr.acc_odr; + int odr_pow = bmi_pow(2, 12 - bmi_odr + 1); + /*TO DO*/ + + if (client_data->fifo_data_sel == 4) + { + bmi_odr = client_data->odr.mag_odr; + odr_pow = bmi_pow(2, 12 - bmi_odr + 1); + } + + bmi_fifo_frame_bytes_extend_calc(client_data, &fifo_frmbytes_ext); + + if (client_data->pw.acc_pm == 2 && client_data->pw.gyro_pm == 2 + && client_data->pw.mag_pm == 2) + pr_info("pw_acc: %d, pw_gyro: %d\n", + client_data->pw.acc_pm, client_data->pw.gyro_pm); + if (!client_data->fifo_data_sel) + pr_info("no selsect sensor fifo, fifo_data_sel:%d\n", + client_data->fifo_data_sel); + + err = BMI_CALL_API(fifo_length)(&fifo_len0); + client_data->fifo_bytecount = fifo_len0; + + if (client_data->fifo_bytecount == 0 || err) + { + pr_info("fifo_bytecount is 0!!"); + return ; + } + if (client_data->fifo_bytecount + fifo_frmbytes_ext > FIFO_DATA_BUFSIZE) + client_data->fifo_bytecount = FIFO_DATA_BUFSIZE; + /* need give attention for the time of burst read*/ + memset (s_fifo_data_buf, 0, sizeof (s_fifo_data_buf)); + if (!err) { + err = bmi_burst_read_wrapper(client_data->device.dev_addr, + BMI160_USER_FIFO_DATA__REG, s_fifo_data_buf, + client_data->fifo_bytecount + fifo_frmbytes_ext); + /* store host timestamp after reading fifo */ + host_time_new = bmi_get_alarm_timestamp_ns(); + if (timestamp_next == 0) { + sensor_time_new = bmi_fifo_data_decode(s_fifo_data_buf, + client_data->fifo_bytecount + fifo_frmbytes_ext, + time_drift, timestamp_next, odr_pow); + } else { + sensor_time_new = bmi_fifo_data_decode(s_fifo_data_buf, + client_data->fifo_bytecount + fifo_frmbytes_ext, + time_drift, host_time_new, odr_pow); + } + if (sensor_time_new >= 0) { + time_drift = bmi_fifo_time_drift_calc(host_time_new, + sensor_time_new, host_time_old, sensor_time_old); + timestamp_next = bmi_fifo_next_timestamp_calc(host_time_new, + sensor_time_new, time_drift, odr_pow, bmi_odr); + /* store current timestamps as the old ones + for next delta calculation */ + host_time_old = host_time_new; + sensor_time_old = sensor_time_new; + } + } else { + dev_err(client_data->dev, "read fifo leght err"); + } + + if (err) + dev_err(client_data->dev, "brust read fifo err\n"); + +} + +static void bmi_signification_motion_interrupt_handle( + struct bmi_client_data *client_data) +{ + pr_info("bmi_signification_motion_interrupt_handle\n"); + input_event(client_data->input_accel, EV_MSC, INPUT_EVENT_SGM, 1); + input_sync(client_data->input_accel); + input_event(client_data->input_gyro, EV_MSC, INPUT_EVENT_SGM, 1); + input_sync(client_data->input_gyro); + bmi160_set_command_register(CMD_RESET_INT_ENGINE); + +} +static void bmi_stepdetector_interrupt_handle( + struct bmi_client_data *client_data) +{ + u8 current_step_dector_st = 0; + client_data->pedo_data.wkar_step_detector_status++; + current_step_dector_st = + client_data->pedo_data.wkar_step_detector_status; + client_data->std = ((current_step_dector_st == 1) ? 0 : 1); +} + +static void bmi_irq_work_func(struct work_struct *work) +{ + struct bmi_client_data *client_data = + container_of((struct work_struct *)work, + struct bmi_client_data, irq_work); + + unsigned char int_status[4] = {0, 0, 0, 0}; + + pr_err("--->liangdi bmi_irq_work_func\n"); + + client_data->device.bus_read(client_data->device.dev_addr, + BMI160_USER_INTR_STAT_0_ADDR, int_status, 4); + + if (BMI160_GET_BITSLICE(int_status[0], + BMI160_USER_INTR_STAT_0_ANY_MOTION)) + bmi_slope_interrupt_handle(client_data); + + if (BMI160_GET_BITSLICE(int_status[0], + BMI160_USER_INTR_STAT_0_STEP_INTR)) + bmi_stepdetector_interrupt_handle(client_data); + if (BMI160_GET_BITSLICE(int_status[1], + BMI160_USER_INTR_STAT_1_FIFO_WM_INTR)) + bmi_fifo_watermark_interrupt_handle(client_data); + + /* Clear ALL inputerrupt status after handler sig mition*/ + /* Put this commads intot the last one*/ + if (BMI160_GET_BITSLICE(int_status[0], + BMI160_USER_INTR_STAT_0_SIGNIFICANT_INTR)) + bmi_signification_motion_interrupt_handle(client_data); + +} + +static irqreturn_t bmi_irq_handler(int irq, void *handle) +{ + struct bmi_client_data *client_data = handle; + + if (client_data == NULL) + return IRQ_HANDLED; + if (client_data->dev == NULL) + return IRQ_HANDLED; + schedule_work(&client_data->irq_work); + + return IRQ_HANDLED; +} +#endif /* defined(BMI_ENABLE_INT1)||defined(BMI_ENABLE_INT2) */ + +static int bmi_restore_hw_cfg(struct bmi_client_data *client) +{ + int err = 0; + + if ((client->fifo_data_sel) & (1 << BMI_ACC_SENSOR)) { + err += BMI_CALL_API(set_accel_range)(client->range.acc_range); + err += BMI_CALL_API(set_accel_output_data_rate) + (client->odr.acc_odr); + err += BMI_CALL_API(set_fifo_accel_enable)(1); + } + if ((client->fifo_data_sel) & (1 << BMI_GYRO_SENSOR)) { + err += BMI_CALL_API(set_gyro_range)(client->range.gyro_range); + err += BMI_CALL_API(set_gyro_output_data_rate) + (client->odr.gyro_odr); + err += BMI_CALL_API(set_fifo_gyro_enable)(1); + } + if ((client->fifo_data_sel) & (1 << BMI_MAG_SENSOR)) { + err += BMI_CALL_API(set_mag_output_data_rate) + (client->odr.mag_odr); + err += BMI_CALL_API(set_fifo_mag_enable)(1); + } + err += BMI_CALL_API(set_command_register)(CMD_CLR_FIFO_DATA); + + mutex_lock(&client->mutex_op_mode); + if (client->pw.acc_pm != BMI_ACC_PM_SUSPEND) { + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_NORMAL]); + mdelay(3); + } + mutex_unlock(&client->mutex_op_mode); + + mutex_lock(&client->mutex_op_mode); + if (client->pw.gyro_pm != BMI_GYRO_PM_SUSPEND) { + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_NORMAL]); + mdelay(3); + } + mutex_unlock(&client->mutex_op_mode); + + mutex_lock(&client->mutex_op_mode); + + if (client->pw.mag_pm != BMI_MAG_PM_SUSPEND) { +#ifdef BMI160_AKM09912_SUPPORT + err += bmi160_set_bst_akm_and_secondary_if_powermode + (BMI160_MAG_FORCE_MODE); +#else + err += bmi160_set_bmm150_mag_and_secondary_if_power_mode + (BMI160_MAG_FORCE_MODE); +#endif + mdelay(3); + } + mutex_unlock(&client->mutex_op_mode); + + return err; +} + +static void bmi160_set_acc_enable(struct device *dev, unsigned int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bmi_client_data *client_data = i2c_get_clientdata(client); + int acc_pre_enable = atomic_read(&client_data->wkqueue_en); + int gyro_current_enable; + + mutex_lock(&client_data->mutex_enable); + if (enable) { + if (acc_pre_enable == 0) { + if (!client_data->power_enabled) { + if (bmi160_power_ctl(client_data, true)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + + bmi160_set_acc_op_mode(client_data, BMI_ACC_PM_NORMAL); + schedule_delayed_work(&client_data->work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + atomic_set(&client_data->wkqueue_en, 1); + } + } else { + if ((acc_pre_enable == 1) && client_data->power_enabled) { + bmi160_set_acc_op_mode(client_data, BMI_ACC_PM_SUSPEND); + cancel_delayed_work_sync(&client_data->work); + atomic_set(&client_data->wkqueue_en, 0); + gyro_current_enable = atomic_read(&client_data->gyro_en); + if (!gyro_current_enable) { + if (bmi160_power_ctl(client_data, false)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + } + } + +mutex_exit: + mutex_unlock(&client_data->mutex_enable); + dev_notice(dev, + "acc_enable en_state=%d\n", + atomic_read(&client_data->wkqueue_en)); +} + + +static void bmi160_set_gyro_enable(struct device *dev, unsigned int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bmi_client_data *client_data = i2c_get_clientdata(client); + int gyro_pre_enable = atomic_read(&client_data->gyro_en); + int acc_current_enable; + + mutex_lock(&client_data->mutex_enable); + if (enable) { + if (gyro_pre_enable == 0) { + if (!client_data->power_enabled) { + if (bmi160_power_ctl(client_data, true)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + bmi160_set_gyro_op_mode(client_data, BMI_GYRO_PM_NORMAL); + schedule_delayed_work(&client_data->gyro_work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + atomic_set(&client_data->gyro_en, 1); + } + } else { + if ((gyro_pre_enable == 1) && client_data->power_enabled) { + bmi160_set_gyro_op_mode(client_data, BMI_GYRO_PM_SUSPEND); + cancel_delayed_work_sync(&client_data->gyro_work); + atomic_set(&client_data->gyro_en, 0); + acc_current_enable = atomic_read(&client_data->wkqueue_en); + if (!acc_current_enable) { + if (bmi160_power_ctl(client_data, false)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + } + } + +mutex_exit: + mutex_unlock(&client_data->mutex_enable); + dev_notice(&client->dev, "gyro_enable en_state=%d\n", + atomic_read(&client_data->gyro_en)); +} + + +static int bmi160_self_calibration_xyz(struct sensors_classdev *sensors_cdev, + int axis, int apply_now) +{ + int err = 0; + s8 accel_offset_x = 0; + s8 accel_offset_y = 0; + s8 accel_offset_z = 0; + + struct bmi_client_data *client_data = container_of(sensors_cdev, + struct bmi_client_data, accel_cdev); + + err = BMI_CALL_API(set_accel_foc_trigger)(X_AXIS, + 1, &accel_offset_x); + if (!err) + client_data->calib_status |= + BMI_FAST_CALI_TRUE << BMI_ACC_X_FAST_CALI_RDY; + else + return -EIO; + + err = BMI_CALL_API(set_accel_foc_trigger)(Y_AXIS, + 1, &accel_offset_y); + if (!err) + client_data->calib_status |= + BMI_FAST_CALI_TRUE << BMI_ACC_Y_FAST_CALI_RDY; + else + return -EIO; + + err = BMI_CALL_API(set_accel_foc_trigger)(Z_AXIS, + 1, &accel_offset_z); + if (!err) + client_data->calib_status |= + BMI_FAST_CALI_TRUE << BMI_ACC_Z_FAST_CALI_RDY; + else + return -EIO; + + return 0; +} + +static int bmi160_accel_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct bmi_client_data *data = container_of(sensors_cdev, + struct bmi_client_data, accel_cdev); + + if (delay_ms < 10) + delay_ms = 10; + if (delay_ms > 10) + delay_ms = 10; + atomic_set(&data->delay, (unsigned int) delay_ms); + return 0; +} + +static int bmi160_cdev_enable_accel(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmi_client_data *client_data = container_of(sensors_cdev, + struct bmi_client_data, accel_cdev); + bmi160_set_acc_enable(&client_data->i2c->dev, enable); + return 0; +} + +static int bmi160_gyro_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct bmi_client_data *data = container_of(sensors_cdev, + struct bmi_client_data, gyro_cdev); + + if (delay_ms < 10) + delay_ms = 10; + if (delay_ms > 10) + delay_ms = 10; + atomic_set(&data->delay, (unsigned int) delay_ms); + return 0; +} + + +static int bmi160_cdev_enable_gyro(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmi_client_data *client_data = container_of(sensors_cdev, + struct bmi_client_data, gyro_cdev); + bmi160_set_gyro_enable(&client_data->i2c->dev, enable); + return 0; +} + + +int bmi_probe(struct bmi_client_data *client_data, struct device *dev) +{ + int err = 0; +#ifdef BMI160_MAG_INTERFACE_SUPPORT + u8 mag_dev_addr; + u8 mag_urst_len; + u8 mag_op_mode; +#endif + err = bmi160_power_init(client_data); + if (err) { + dev_err(&client_data->i2c->dev, + "Failed to get sensor regulators\n"); + err = -EINVAL; + goto exit_err_clean; + } + err = bmi160_power_ctl(client_data, true); + if (err) { + dev_err(&client_data->i2c->dev, + "Failed to enable sensor power\n"); + err = -EINVAL; + goto deinit_power_exit; + } + + /* check chip id */ + err = bmi_check_chip_id(client_data); + if (err) + goto disable_power_exit; + + dev_set_drvdata(dev, client_data); + client_data->dev = dev; + + mutex_init(&client_data->mutex_enable); + mutex_init(&client_data->mutex_op_mode); + mutex_init(&client_data->mutex_ring_buf); + + /* input device init */ + err = bmi_input_init(client_data); + if (err < 0) + goto disable_power_exit; + + /* sysfs node creation */ + err = sysfs_create_group(&client_data->i2c->dev.kobj, + &bmi160_attribute_group); + + if (err < 0) + goto exit_err_sysfs; + + /*to do*/ + client_data->accel_cdev = accel_cdev; + client_data->accel_cdev.sensors_enable = bmi160_cdev_enable_accel; + client_data->accel_cdev.sensors_poll_delay = bmi160_accel_poll_delay; + client_data->accel_cdev.sensors_calibrate = bmi160_self_calibration_xyz; + err = sensors_classdev_register(&client_data->input_accel->dev, + &client_data->accel_cdev); + if (err) { + dev_err(&client_data->i2c->dev, "sensors class register failed.\n"); + return err; + } + + client_data->gyro_cdev = gyro_cdev; + client_data->gyro_cdev.sensors_enable = bmi160_cdev_enable_gyro; + client_data->gyro_cdev.sensors_poll_delay = bmi160_gyro_poll_delay; + err = sensors_classdev_register(&client_data->input_gyro->dev, + &client_data->gyro_cdev); + if (err) { + dev_err(&client_data->i2c->dev, "sensors class register failed.\n"); + return err; + } + + if (NULL != dev->platform_data) { + client_data->bst_pd = kzalloc(sizeof(*client_data->bst_pd), + GFP_KERNEL); + + if (NULL != client_data->bst_pd) { + memcpy(client_data->bst_pd, dev->platform_data, + sizeof(*client_data->bst_pd)); + dev_notice(dev, "%s sensor driver set place: p%d\n", + client_data->bst_pd->name, + client_data->bst_pd->place); + } + } + + if (NULL != client_data->bst_pd) { + memcpy(client_data->bst_pd, dev->platform_data, + sizeof(*client_data->bst_pd)); + dev_notice(dev, "%s sensor driver set place: p%d\n", + client_data->bst_pd->name, + client_data->bst_pd->place); + } + + /* workqueue init */ + INIT_DELAYED_WORK(&client_data->work, bmi_work_func); + INIT_DELAYED_WORK(&client_data->gyro_work, bmi_gyro_work_func); + atomic_set(&client_data->delay, BMI_DELAY_DEFAULT); + atomic_set(&client_data->wkqueue_en, 0); + atomic_set(&client_data->gyro_en, 0); + + /* h/w init */ + client_data->device.delay_msec = bmi_delay; + err = BMI_CALL_API(init)(&client_data->device); + + /*workqueue init*/ + INIT_WORK(&client_data->report_data_work, bmi_hrtimer_work_func); + reportdata_wq = create_singlethread_workqueue("bmi160_wq"); + if (NULL == reportdata_wq) { + pr_info("fail to create the reportdta_wq %d", -ENOMEM); + } + hrtimer_init(&client_data->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + client_data->timer.function = reportdata_timer_fun; + client_data->work_delay_kt = ns_to_ktime(10000000); + client_data->is_timer_running = 0; + client_data->time_odr = 500000; /*200Hz*/ + + bmi_dump_reg(client_data); + + /*power on detected*/ + /*or softrest(cmd 0xB6) */ + /*fatal err check*/ + /*soft reset*/ + err += BMI_CALL_API(set_command_register)(CMD_RESET_USER_REG); + mdelay(3); + if (err) + dev_err(dev, "Failed soft reset, er=%d", err); + /*usr data config page*/ + err += BMI_CALL_API(set_target_page)(USER_DAT_CFG_PAGE); + if (err) + dev_err(dev, "Failed cffg page, er=%d", err); + err += bmi_get_err_status(client_data); + if (err) { + dev_err(dev, "Failed to bmi16x init!err_st=0x%x\n", + client_data->err_st.err_st_all); + goto exit_err_sysfs; + } + +#ifdef BMI160_MAG_INTERFACE_SUPPORT + err += bmi160_set_command_register(MAG_MODE_NORMAL); + mdelay(2); + err += bmi160_get_mag_power_mode_stat(&mag_op_mode); + mdelay(2); + err += BMI_CALL_API(get_i2c_device_addr)(&mag_dev_addr); + mdelay(2); +#ifdef BMI160_AKM09912_SUPPORT + err += BMI_CALL_API(set_i2c_device_addr)(BMI160_AKM09912_I2C_ADDRESS); + /*do not need to check the return value for mag 2nd interface*/ + bmi160_bst_akm_mag_interface_init(BMI160_AKM09912_I2C_ADDRESS); +#else + err += BMI_CALL_API(set_i2c_device_addr)(BMI160_AUX_BMM150_I2C_ADDRESS); + /*do not need to check the return value for mag 2nd interface*/ + bmi160_bmm150_mag_interface_init(); +#endif + err += bmi160_set_mag_burst(3); + err += bmi160_get_mag_burst(&mag_urst_len); + dev_info(client_data->dev, + "BMI160 mag_urst_len:%d, mag_add:0x%x, mag_op_mode:%d\n", + mag_urst_len, mag_dev_addr, mag_op_mode); +#endif + if (err < 0) + goto exit_err_sysfs; + +#ifdef BMI160_ENABLE_INT1 + client_data->gpio_pin = of_get_named_gpio_flags(dev->of_node, + "bosch,gpio-int1", 0, NULL); + dev_info(client_data->dev, "BMI160 qpio number:%d\n", + client_data->gpio_pin); + err += gpio_request_one(client_data->gpio_pin, + GPIOF_IN, "bmi160_int"); + err += gpio_direction_input(client_data->gpio_pin); + client_data->IRQ = gpio_to_irq(client_data->gpio_pin); + if (err) { + dev_err(client_data->dev, + "can not request gpio to irq number\n"); + client_data->gpio_pin = 0; + } + /* maps interrupt to INT1/InT2 pin */ + BMI_CALL_API(set_intr_any_motion)(BMI_INT0, ENABLE); + BMI_CALL_API(set_intr_fifo_wm)(BMI_INT0, ENABLE); + /*BMI_CALL_API(set_int_drdy)(BMI_INT0, ENABLE);*/ + + /*Set interrupt trige level way */ + BMI_CALL_API(set_intr_edge_ctrl)(BMI_INT0, BMI_INT_LEVEL); + bmi160_set_intr_level(BMI_INT0, 1); + /*set interrupt latch temporary, 5 ms*/ + /*bmi160_set_latch_int(5);*/ + + BMI_CALL_API(set_output_enable)( + BMI160_INTR1_OUTPUT_ENABLE, ENABLE); + sigmotion_init_interrupts(BMI160_MAP_INTR1); + BMI_CALL_API(map_step_detector_intr)(BMI160_MAP_INTR1); + /*close step_detector in init function*/ + BMI_CALL_API(set_step_detector_enable)(0); +#endif + +#ifdef BMI160_ENABLE_INT2 + client_data->gpio_pin = of_get_named_gpio_flags(dev->of_node, + "bosch,gpio-int2", 0, NULL); + dev_info(client_data->dev, "BMI160 qpio number:%d\n", + client_data->gpio_pin); + err += gpio_request_one(client_data->gpio_pin, + GPIOF_IN, "bmi160_int"); + err += gpio_direction_input(client_data->gpio_pin); + client_data->IRQ = gpio_to_irq(client_data->gpio_pin); + if (err) { + dev_err(client_data->dev, + "can not request gpio to irq number\n"); + client_data->gpio_pin = 0; + } + /* maps interrupt to INT1/InT2 pin */ + BMI_CALL_API(set_intr_any_motion)(BMI_INT1, ENABLE); + BMI_CALL_API(set_intr_fifo_wm)(BMI_INT1, ENABLE); + BMI_CALL_API(set_int_drdy)(BMI_INT1, ENABLE); + + /*Set interrupt trige level way */ + BMI_CALL_API(set_intr_edge_ctrl)(BMI_INT1, BMI_INT_LEVEL); + bmi160_set_intr_level(BMI_INT1, 1); + /*set interrupt latch temporary, 5 ms*/ + /*bmi160_set_latch_int(5);*/ + + BMI_CALL_API(set_output_enable)( + BMI160_INTR2_OUTPUT_ENABLE, ENABLE); + sigmotion_init_interrupts(BMI160_MAP_INTR2); + BMI_CALL_API(map_step_detector_intr)(BMI160_MAP_INTR2); + /*close step_detector in init function*/ + BMI_CALL_API(set_step_detector_enable)(0); +#endif + err = request_irq(client_data->IRQ, bmi_irq_handler, + IRQF_TRIGGER_RISING, "bmi160", client_data); + if (err) + dev_err(client_data->dev, "could not request irq\n"); + INIT_WORK(&client_data->irq_work, bmi_irq_work_func); + + client_data->selftest = 0; + + client_data->fifo_data_sel = 0; + BMI_CALL_API(get_accel_output_data_rate)(&client_data->odr.acc_odr); + BMI_CALL_API(get_gyro_output_data_rate)(&client_data->odr.gyro_odr); + BMI_CALL_API(get_mag_output_data_rate)(&client_data->odr.mag_odr); + BMI_CALL_API(set_fifo_time_enable)(1); + BMI_CALL_API(get_accel_range)(&client_data->range.acc_range); + BMI_CALL_API(get_gyro_range)(&client_data->range.gyro_range); + /* now it's power on which is considered as resuming from suspend */ + + /* set sensor PMU into suspend power mode for all */ + if (bmi_pmu_set_suspend(client_data) < 0) { + dev_err(dev, "Failed to set BMI160 to suspend power mode\n"); + goto exit_err_sysfs; + } + + bmi160_power_ctl(client_data, false); + + dev_notice(dev, "sensor_time:%d, %d", + sensortime_duration_tbl[0].ts_delat, + sensortime_duration_tbl[0].ts_duration_lsb); + dev_notice(dev, "sensor %s probed successfully", SENSOR_NAME); + + return 0; + +exit_err_sysfs: + if (err) + bmi_input_destroy(client_data); +disable_power_exit: + bmi160_power_ctl(client_data, false); +deinit_power_exit: + bmi160_power_deinit(client_data); +exit_err_clean: + if (err) { + if (client_data != NULL) { + if (NULL != client_data->bst_pd) { + kfree(client_data->bst_pd); + client_data->bst_pd = NULL; + } + } + } + + return err; +} +EXPORT_SYMBOL(bmi_probe); + +/*! + * @brief remove bmi client + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int bmi_remove(struct device *dev) +{ + int err = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + + if (NULL != client_data) { +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&client_data->early_suspend_handler); +#endif + mutex_lock(&client_data->mutex_enable); + if (BMI_ACC_PM_NORMAL == client_data->pw.acc_pm || + BMI_GYRO_PM_NORMAL == client_data->pw.gyro_pm || + BMI_MAG_PM_NORMAL == client_data->pw.mag_pm) { + cancel_delayed_work_sync(&client_data->work); + } + mutex_unlock(&client_data->mutex_enable); + + err = bmi_pmu_set_suspend(client_data); + + mdelay(5); + + sysfs_remove_group(&client_data->i2c->dev.kobj, + &bmi160_attribute_group); + bmi_input_destroy(client_data); + + if (NULL != client_data->bst_pd) { + kfree(client_data->bst_pd); + client_data->bst_pd = NULL; + } + kfree(client_data); + } + return err; +} +EXPORT_SYMBOL(bmi_remove); + +static int bmi_post_resume(struct bmi_client_data *client_data) +{ + int err = 0; + + mutex_lock(&client_data->mutex_enable); + + if (atomic_read(&client_data->wkqueue_en) == 1) { + bmi160_set_acc_op_mode(client_data, BMI_ACC_PM_NORMAL); + schedule_delayed_work(&client_data->work, + msecs_to_jiffies( + atomic_read(&client_data->delay))); + } + mutex_unlock(&client_data->mutex_enable); + if (client_data->is_timer_running) { + hrtimer_start(&client_data->timer, + ns_to_ktime(client_data->time_odr), + HRTIMER_MODE_REL); + client_data->base_time = 0; + client_data->timestamp = 0; + client_data->is_timer_running = 1; + } + + return err; +} + + +int bmi_suspend(struct device *dev) +{ + int err = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + unsigned char stc_enable; + unsigned char std_enable; + dev_err(client_data->dev, "bmi suspend function entrance"); + + if (client_data->is_timer_running) { + hrtimer_cancel(&client_data->timer); + client_data->base_time = 0; + client_data->timestamp = 0; + client_data->fifo_time = 0; + } + + if (atomic_read(&client_data->wkqueue_en) == 1) { + bmi160_set_acc_op_mode(client_data, BMI_ACC_PM_SUSPEND); + cancel_delayed_work_sync(&client_data->work); + } + BMI_CALL_API(get_step_counter_enable)(&stc_enable); + BMI_CALL_API(get_step_detector_enable)(&std_enable); + if (client_data->pw.acc_pm != BMI_ACC_PM_SUSPEND && + (stc_enable != 1) && (std_enable != 1) && + (client_data->sig_flag != 1)) { + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_SUSPEND]); + /*client_data->pw.acc_pm = BMI_ACC_PM_SUSPEND;*/ + mdelay(3); + } + if (client_data->pw.gyro_pm != BMI_GYRO_PM_SUSPEND) { + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_SUSPEND]); + /*client_data->pw.gyro_pm = BMI_GYRO_PM_SUSPEND;*/ + mdelay(3); + } + + if (client_data->pw.mag_pm != BMI_MAG_PM_SUSPEND) { +#ifdef BMI160_AKM09912_SUPPORT + err += bmi160_set_bst_akm_and_secondary_if_powermode + (BMI160_MAG_SUSPEND_MODE); +#else + err += bmi160_set_bmm150_mag_and_secondary_if_power_mode + (BMI160_MAG_SUSPEND_MODE); +#endif + /*client_data->pw.gyro_pm = BMI160_MAG_SUSPEND_MODE;*/ + mdelay(3); + } + + return err; +} +EXPORT_SYMBOL(bmi_suspend); + +int bmi_resume(struct device *dev) +{ + int err = 0; + struct bmi_client_data *client_data = dev_get_drvdata(dev); + if (client_data->pw.acc_pm != BMI_ACC_PM_SUSPEND) { + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_acc_arr[BMI_ACC_PM_NORMAL]); + mdelay(3); + } + if (client_data->pw.gyro_pm != BMI_GYRO_PM_SUSPEND) { + err += BMI_CALL_API(set_command_register) + (bmi_pmu_cmd_gyro_arr[BMI_GYRO_PM_NORMAL]); + mdelay(3); + } + + if (client_data->pw.mag_pm != BMI_MAG_PM_SUSPEND) { +#ifdef BMI160_AKM09912_SUPPORT + err += bmi160_set_bst_akm_and_secondary_if_powermode + (BMI160_MAG_FORCE_MODE); +#else + err += bmi160_set_bmm150_mag_and_secondary_if_power_mode + (BMI160_MAG_FORCE_MODE); +#endif + mdelay(3); + } + /* post resume operation */ + err += bmi_post_resume(client_data); + + return err; +} +EXPORT_SYMBOL(bmi_resume); + diff --git a/drivers/input/misc/bmi160_driver.h b/drivers/input/misc/bmi160_driver.h new file mode 100755 index 00000000000..70a432a5e17 --- /dev/null +++ b/drivers/input/misc/bmi160_driver.h @@ -0,0 +1,401 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bmi160_driver.h + * @date 2015/08/17 14:40 + * @id "09afbe6" + * @version 1.4 + * + * @brief + * The head file of BMI160 device driver core code +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include "bmi160.h" + +/* sensor specific */ +#define SENSOR_NAME "bmi160" +#define BMI160_ACCEL_INPUT_NAME "bmi160-accel" +#define BMI160_GYRO_INPUT_NAME "bmi160-gyro" +#define ABSMIN -512 +#define ABSMAX 512 +#define GYRO_MIN_VALUE -32768 +#define GYRO_MAX_VALUE 32767 + +#define SENSOR_CHIP_ID_BMI (0xD0) +#define SENSOR_CHIP_ID_BMI_C2 (0xD1) +#define SENSOR_CHIP_ID_BMI_C3 (0xD3) + +#define SENSOR_CHIP_REV_ID_BMI (0x00) + +#define CHECK_CHIP_ID_TIME_MAX 5 + +#define BMI_REG_NAME(name) BMI160_##name##__REG +#define BMI_VAL_NAME(name) BMI160_##name +#define BMI_CALL_API(name) bmi160_##name + +#define BMI_I2C_WRITE_DELAY_TIME (1) + +/* generic */ +#define BMI_MAX_RETRY_I2C_XFER (100) +#define BMI_MAX_RETRY_WAKEUP (5) +#define BMI_MAX_RETRY_WAIT_DRDY (100) + +#define BMI_DELAY_MIN (1) +#define BMI_DELAY_DEFAULT (200) + +#define BMI_VALUE_MAX (32767) +#define BMI_VALUE_MIN (-32768) + +#define BYTES_PER_LINE (16) + +#define BUF_SIZE_PRINT (16) + +#define BMI_FAST_CALI_TRUE (1) +#define BMI_FAST_CALI_ALL_RDY (7) + +/*! FIFO 1024 byte, max fifo frame count not over 150 */ +#define FIFO_FRAME_CNT 20 +#define FIFO_DATA_BUFSIZE 1024 + + +#define FRAME_LEN_ACC 6 +#define FRAME_LEN_GYRO 6 +#define FRAME_LEN_MAG 8 + +/*! BMI Self test */ +#define BMI_SELFTEST_AMP_HIGH 1 + +/* CMD */ +#define CMD_FOC_START 0x03 +#define CMD_PMU_ACC_SUSPEND 0x10 +#define CMD_PMU_ACC_NORMAL 0x11 +#define CMD_PMU_ACC_LP1 0x12 +#define CMD_PMU_ACC_LP2 0x13 +#define CMD_PMU_GYRO_SUSPEND 0x14 +#define CMD_PMU_GYRO_NORMAL 0x15 +#define CMD_PMU_GYRO_FASTSTART 0x17 +#define CMD_PMU_MAG_SUSPEND 0x18 +#define CMD_PMU_MAG_NORMAL 0x19 +#define CMD_PMU_MAG_LP1 0x1A +#define CMD_PMU_MAG_LP2 0x1B +#define CMD_CLR_FIFO_DATA 0xB0 +#define CMD_RESET_INT_ENGINE 0xB1 +#define CMD_RESET_USER_REG 0xB6 + +#define USER_DAT_CFG_PAGE 0x00 + +/*! FIFO Head definition*/ +#define FIFO_HEAD_A 0x84 +#define FIFO_HEAD_G 0x88 +#define FIFO_HEAD_M 0x90 + +#define FIFO_HEAD_G_A (FIFO_HEAD_G | FIFO_HEAD_A) +#define FIFO_HEAD_M_A (FIFO_HEAD_M | FIFO_HEAD_A) +#define FIFO_HEAD_M_G (FIFO_HEAD_M | FIFO_HEAD_G) + +#define FIFO_HEAD_M_G_A (FIFO_HEAD_M | FIFO_HEAD_G | FIFO_HEAD_A) + +#define FIFO_HEAD_SENSOR_TIME 0x44 +#define FIFO_HEAD_SKIP_FRAME 0x40 +#define FIFO_HEAD_OVER_READ_LSB 0x80 +#define FIFO_HEAD_OVER_READ_MSB 0x00 + +/*! FIFO head mode Frame bytes number definition */ +#define A_BYTES_FRM 6 +#define G_BYTES_FRM 6 +#define M_BYTES_FRM 8 +#define GA_BYTES_FRM 12 +#define MG_BYTES_FRM 14 +#define MA_BYTES_FRM 14 +#define MGA_BYTES_FRM 20 + +#define ACC_FIFO_HEAD "acc" +#define GYRO_FIFO_HEAD "gyro" +#define MAG_FIFO_HEAD "mag" + +/*! Bosch sensor unknown place*/ +#define BOSCH_SENSOR_PLACE_UNKNOWN (-1) +/*! Bosch sensor remapping table size P0~P7*/ +#define MAX_AXIS_REMAP_TAB_SZ 8 + +#define ENABLE 1 +#define DISABLE 0 + +/* bmi sensor HW interrupt pin number */ +#define BMI_INT0 0 +#define BMI_INT1 1 + +#define BMI_INT_LEVEL 0 +#define BMI_INT_EDGE 1 + +/*! BMI mag interface */ + + +/* compensated output value returned if sensor had overflow */ +#define BMM050_OVERFLOW_OUTPUT -32768 +#define BMM050_OVERFLOW_OUTPUT_S32 ((s32)(-2147483647-1)) + +/* Trim Extended Registers */ +#define BMM050_DIG_X1 0x5D +#define BMM050_DIG_Y1 0x5E +#define BMM050_DIG_Z4_LSB 0x62 +#define BMM050_DIG_Z4_MSB 0x63 +#define BMM050_DIG_X2 0x64 +#define BMM050_DIG_Y2 0x65 +#define BMM050_DIG_Z2_LSB 0x68 +#define BMM050_DIG_Z2_MSB 0x69 +#define BMM050_DIG_Z1_LSB 0x6A +#define BMM050_DIG_Z1_MSB 0x6B +#define BMM050_DIG_XYZ1_LSB 0x6C +#define BMM050_DIG_XYZ1_MSB 0x6D +#define BMM050_DIG_Z3_LSB 0x6E +#define BMM050_DIG_Z3_MSB 0x6F +#define BMM050_DIG_XY2 0x70 +#define BMM050_DIG_XY1 0x71 + +struct regulator_map { + struct regulator *regulator; + int min_uv; + int max_uv; + char *supply; +}; + +struct bmi160mag_compensate_t { + signed char dig_x1; + signed char dig_y1; + + signed char dig_x2; + signed char dig_y2; + + u16 dig_z1; + s16 dig_z2; + s16 dig_z3; + s16 dig_z4; + + unsigned char dig_xy1; + signed char dig_xy2; + + u16 dig_xyz1; +}; + +/*bmi fifo sensor type combination*/ +enum BMI_FIFO_DATA_SELECT_T { + BMI_FIFO_A_SEL = 1, + BMI_FIFO_G_SEL, + BMI_FIFO_G_A_SEL, + BMI_FIFO_M_SEL, + BMI_FIFO_M_A_SEL, + BMI_FIFO_M_G_SEL, + BMI_FIFO_M_G_A_SEL, + BMI_FIFO_DATA_SEL_MAX +}; + +/*bmi interrupt about step_detector and sgm*/ +#define INPUT_EVENT_STEP_DETECTOR 5 +#define INPUT_EVENT_SGM REL_DIAL/*7*/ +#define INPUT_EVENT_FAST_ACC_CALIB_DONE 6 +#define INPUT_EVENT_FAST_GYRO_CALIB_DONE 4 + + +/*! +* Bst sensor common definition, +* please give parameters in BSP file. +*/ +struct bosch_sensor_specific { + char *name; + /* 0 to 7 */ + unsigned int place:3; + int irq; + int (*irq_gpio_cfg)(void); +}; + +/*! bmi160 sensor spec of power mode */ +struct pw_mode { + u8 acc_pm; + u8 gyro_pm; + u8 mag_pm; +}; + +/*! bmi160 sensor spec of odr */ +struct odr_t { + u8 acc_odr; + u8 gyro_odr; + u8 mag_odr; +}; + +/*! bmi160 sensor spec of range */ +struct range_t { + u8 acc_range; + u8 gyro_range; +}; + +/*! bmi160 sensor error status */ +struct err_status { + u8 fatal_err; + u8 err_code; + u8 i2c_fail; + u8 drop_cmd; + u8 mag_drdy_err; + u8 err_st_all; +}; + +/*! bmi160 fifo frame for all sensors */ +struct fifo_frame_t { + struct bmi160_accel_t *acc_farr; + struct bmi160_gyro_t *gyro_farr; + struct bmi160_mag_xyz_s32_t *mag_farr; + + unsigned char acc_frame_cnt; + unsigned char gyro_frame_cnt; + unsigned char mag_frame_cnt; + + u32 acc_lastf_ts; + u32 gyro_lastf_ts; + u32 mag_lastf_ts; +}; + +/*! bmi160 fifo sensor time */ +struct fifo_sensor_time_t { + u32 acc_ts; + u32 gyro_ts; + u32 mag_ts; +}; + +struct pedometer_data_t { + /*! Fix step detector misinformation for the first time*/ + u8 wkar_step_detector_status; + u_int32_t last_step_counter_value; +}; + +struct bmi_client_data { + struct bmi160_t device; + struct i2c_client *i2c; + struct device *dev; + struct input_dev *input_accel; + struct input_dev *input_gyro; + struct sensors_classdev accel_cdev; + struct sensors_classdev gyro_cdev; + struct regulator *vdd; + struct regulator *vio; + struct delayed_work work; + struct delayed_work gyro_work; + struct work_struct irq_work; + + struct work_struct report_data_work; + int is_timer_running; + struct hrtimer timer; + ktime_t work_delay_kt; + uint64_t timestamp; + uint64_t base_time; + uint64_t fifo_time; + uint64_t gyro_count; + uint64_t time_odr; + + u8 chip_id; + + struct pw_mode pw; + struct odr_t odr; + struct range_t range; /*TO DO*/ + struct err_status err_st; + struct pedometer_data_t pedo_data; + s8 place; + u8 selftest; + + atomic_t wkqueue_en; /*TO DO acc gyro mag*/ + atomic_t gyro_en; + atomic_t delay; + atomic_t selftest_result; + + u8 fifo_data_sel; + u16 fifo_bytecount; + u8 fifo_head_en; + unsigned char fifo_int_tag_en; + struct fifo_frame_t fifo_frame; + + unsigned char *fifo_data; + u8 stc_enable; + uint16_t gpio_pin; + u8 std; + u8 sig_flag; + unsigned char calib_status; + struct mutex mutex_op_mode; + struct mutex mutex_enable; + struct mutex mutex_ring_buf; + struct bosch_sensor_specific *bst_pd; + bool power_enabled; + int IRQ; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend_handler; +#endif +}; + + +/*! + * we use a typedef to hide the detail, + * because this type might be changed + */ +struct bosch_sensor_axis_remap { + /* src means which source will be mapped to target x, y, z axis */ + /* if an target OS axis is remapped from (-)x, + * src is 0, sign_* is (-)1 */ + /* if an target OS axis is remapped from (-)y, + * src is 1, sign_* is (-)1 */ + /* if an target OS axis is remapped from (-)z, + * src is 2, sign_* is (-)1 */ + int src_x:3; + int src_y:3; + int src_z:3; + + int sign_x:2; + int sign_y:2; + int sign_z:2; +}; + + +struct bosch_sensor_data { + union { + int16_t v[3]; + struct { + int16_t x; + int16_t y; + int16_t z; + }; + }; +}; + +s8 bmi_burst_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u16 len); +int bmi_probe(struct bmi_client_data *client_data, struct device *dev); +int bmi_remove(struct device *dev); +int bmi_suspend(struct device *dev); +int bmi_resume(struct device *dev); + + diff --git a/drivers/input/misc/bmi160_i2c.c b/drivers/input/misc/bmi160_i2c.c new file mode 100755 index 00000000000..64648529ce5 --- /dev/null +++ b/drivers/input/misc/bmi160_i2c.c @@ -0,0 +1,366 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bmi160_i2c.c + * @date 2014/11/25 14:40 + * @id "ba266c5" + * @version 1.3 + * + * @brief + * This file implements moudle function, which add + * the driver to I2C core. +*/ + +#include +#include +#include +#include "bmi160_driver.h" + +/*! @defgroup bmi160_i2c_src + * @brief bmi160 i2c driver module + @{*/ + +static struct i2c_client *bmi_client; +/*! + * @brief define i2c wirte function + * + * @param client the pointer of i2c client + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +/* i2c read routine for API*/ +static s8 bmi_i2c_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) + { +#if !defined BMI_USE_BASIC_I2C_FUNC + s32 dummy; + if (NULL == client) + return -EINVAL; + + while (0 != len--) { +#ifdef BMI_SMBUS + dummy = i2c_smbus_read_byte_data(client, reg_addr); + if (dummy < 0) { + dev_err(&client->dev, "i2c smbus read error"); + return -EIO; + } + *data = (u8)(dummy & 0xff); +#else + dummy = i2c_master_send(client, (char *)®_addr, 1); + if (dummy < 0) { + dev_err(&client->dev, "i2c bus master write error"); + return -EIO; + } + + dummy = i2c_master_recv(client, (char *)data, 1); + if (dummy < 0) { + dev_err(&client->dev, "i2c bus master read error"); + return -EIO; + } +#endif + reg_addr++; + data++; + } + return 0; +#else + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < BMI_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, + ARRAY_SIZE(msg)) > 0) + break; + else + mdelay(BMI_I2C_WRITE_DELAY_TIME); + } + + if (BMI_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + + return 0; +#endif + } + + +static s8 bmi_i2c_burst_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u16 len) +{ + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < BMI_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + mdelay(BMI_I2C_WRITE_DELAY_TIME); + } + + if (BMI_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + + return 0; +} + + +/* i2c write routine for */ +static s8 bmi_i2c_write(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ +#if !defined BMI_USE_BASIC_I2C_FUNC + s32 dummy; + +#ifndef BMI_SMBUS + u8 buffer[2]; +#endif + + if (NULL == client) + return -EPERM; + + while (0 != len--) { +#ifdef BMI_SMBUS + dummy = i2c_smbus_write_byte_data(client, reg_addr, *data); +#else + buffer[0] = reg_addr; + buffer[1] = *data; + dummy = i2c_master_send(client, (char *)buffer, 2); +#endif + reg_addr++; + data++; + if (dummy < 0) { + dev_err(&client->dev, "error writing i2c bus"); + return -EPERM; + } + + } + mdelay(2); + return 0; +#else + u8 buffer[2]; + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buffer, + }, + }; + + while (0 != len--) { + buffer[0] = reg_addr; + buffer[1] = *data; + for (retry = 0; retry < BMI_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, + ARRAY_SIZE(msg)) > 0) { + break; + } else { + mdelay(BMI_I2C_WRITE_DELAY_TIME); + } + } + if (BMI_MAX_RETRY_I2C_XFER <= retry) { + dev_err(&client->dev, "I2C xfer error"); + return -EIO; + } + reg_addr++; + data++; + } + + mdelay(2); + return 0; +#endif +} + + +static s8 bmi_i2c_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + int err = 0; + err = bmi_i2c_read(bmi_client, reg_addr, data, len); + return err; +} + +static s8 bmi_i2c_write_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + int err = 0; + err = bmi_i2c_write(bmi_client, reg_addr, data, len); + return err; +} + +s8 bmi_burst_read_wrapper(u8 dev_addr, u8 reg_addr, u8 *data, u16 len) +{ + int err = 0; + err = bmi_i2c_burst_read(bmi_client, reg_addr, data, len); + return err; +} +EXPORT_SYMBOL(bmi_burst_read_wrapper); +/*! + * @brief BMI probe function via i2c bus + * + * @param client the pointer of i2c client + * @param id the pointer of i2c device id + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmi_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct bmi_client_data *client_data = NULL; + + dev_info(&client->dev, "BMI160 i2c function probe entrance"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c_check_functionality error!"); + err = -EIO; + goto exit_err_clean; + } + + if (NULL == bmi_client) { + bmi_client = client; + } else { + dev_err(&client->dev, + "this driver does not support multiple clients"); + err = -EBUSY; + goto exit_err_clean; + } + + client_data = kzalloc(sizeof(struct bmi_client_data), + GFP_KERNEL); + if (NULL == client_data) { + dev_err(&client->dev, "no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + client_data->i2c = client; + client_data->device.bus_read = bmi_i2c_read_wrapper; + client_data->device.bus_write = bmi_i2c_write_wrapper; + + return bmi_probe(client_data, &client->dev); + +exit_err_clean: + if (err) + bmi_client = NULL; + return err; +} + +static int bmi_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int err = 0; + err = bmi_suspend(&client->dev); + return err; +} + +static int bmi_i2c_resume(struct i2c_client *client) +{ + int err = 0; + + /* post resume operation */ + err = bmi_resume(&client->dev); + + return err; +} + + +static int bmi_i2c_remove(struct i2c_client *client) +{ + int err = 0; + err = bmi_remove(&client->dev); + bmi_client = NULL; + + return err; +} + + + +static const struct i2c_device_id bmi_id[] = { + {SENSOR_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bmi_id); + +static const struct of_device_id bmi160_of_match[] = { + { .compatible = "bosch-sensortec,bmi160", }, + { .compatible = "bmi160", }, + { .compatible = "bosch,bmi160", }, + { } +}; +MODULE_DEVICE_TABLE(of, bmi160_of_match); + +static struct i2c_driver bmi_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = bmi160_of_match, + }, + .class = I2C_CLASS_HWMON, + .id_table = bmi_id, + .probe = bmi_i2c_probe, + .remove = bmi_i2c_remove, + .suspend = bmi_i2c_suspend, + .resume = bmi_i2c_resume, +}; + +static int __init BMI_i2c_init(void) +{ + return i2c_add_driver(&bmi_i2c_driver); +} + +static void __exit BMI_i2c_exit(void) +{ + i2c_del_driver(&bmi_i2c_driver); +} + +MODULE_AUTHOR("Contact "); +MODULE_DESCRIPTION("driver for " SENSOR_NAME); +MODULE_LICENSE("GPL v2"); + +module_init(BMI_i2c_init); +module_exit(BMI_i2c_exit); + diff --git a/drivers/input/misc/bmp280.c b/drivers/input/misc/bmp280.c new file mode 100755 index 00000000000..5ebb435904a --- /dev/null +++ b/drivers/input/misc/bmp280.c @@ -0,0 +1,1624 @@ +/*! + * @section LICENSE + * @license$ + * + * @filename $filename$ + * @date 2014/07/21 + * @id $id$ + * + * @brief + * API for accessing the BMP280 sensor + * + * Revision: 2.0(Pressure and Temperature compensation code revision is 1.1 + */ +/****************************************************************************/ + +#include "bmp280.h" +static struct bmp280_t *p_bmp280; /**< pointer to BMP280 */ +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/**************************************************************************** + * Description: *//**\brief This function is used for initialize + * the bus read and bus write functions + * and assign the chip id and I2C address of the BMP280 sensor + * chip id is read in the register 0xD0 bit from 0 to 7 + * + * \param p_bmp280 *bmp280 structure pointer. + * + * While changing the parameter of the p_bmp280 + * consider the following point: + * Changing the reference value of the parameter + * will changes the local copy or local reference + * make sure your changes will not + * affect the reference value of the parameter + * (Better case don't change the reference value of the parameter) + * + * + * + * + * \return results of bus communication function + * + * + ***************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_init(struct bmp280_t *bmp280) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_Zero_U8X; + p_bmp280 = bmp280; /* assign BMP280 ptr */ + comres += p_bmp280->BMP280_BUS_READ_FUNC(p_bmp280->dev_addr, + BMP280_CHIPID_REG, &v_data_u8r, 1); /* read Chip Id */ + p_bmp280->chip_id = v_data_u8r; + + bmp280_get_calib_param(); /* readout bmp280 calibparam structure */ + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to read uncompensated temperature + * in the registers 0xFA, 0xFB and 0xFC + * 0xFA -> MSB -> bit from 0 to 7 + * 0xFB -> LSB -> bit from 0 to 7 + * 0xFC -> LSB -> bit from 4 to 7 + * + * \param s32 utemperature : Pointer holding + * the uncompensated temperature. + * + * + * + * \return results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_ut(s32 *utemperature) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 a_data_u8r[3] = {0, 0, 0}; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_TEMPERATURE_MSB_REG, a_data_u8r, 3); + *utemperature = (s32)((( + (u32) (a_data_u8r[0])) + << SHIFT_LEFT_12_POSITION) | + (((u32)(a_data_u8r[1])) + << SHIFT_LEFT_4_POSITION) + | ((u32)a_data_u8r[2] + >> SHIFT_RIGHT_4_POSITION)); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief Reads actual temperature + * from uncompensated temperature and returns the value in 0.01 degree Centigrade + * Output value of "5123" equals 51.23 DegC. + * + * + * + * \param s32 : value of uncompensated temperature. + * + * + * + * \return + * s32 : actual temperature + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +s32 bmp280_compensate_T_int32(s32 adc_t) +{ + s32 v_x1_u32r = BMP280_Zero_U8X; + s32 v_x2_u32r = BMP280_Zero_U8X; + s32 temperature = BMP280_Zero_U8X; + + v_x1_u32r = ((((adc_t >> 3) - ((s32) + p_bmp280->cal_param.dig_T1 << 1))) * + ((s32)p_bmp280->cal_param.dig_T2)) >> 11; + v_x2_u32r = (((((adc_t >> 4) - + ((s32)p_bmp280->cal_param.dig_T1)) * ((adc_t >> 4) - + ((s32)p_bmp280->cal_param.dig_T1))) >> 12) * + ((s32)p_bmp280->cal_param.dig_T3)) >> 14; + p_bmp280->cal_param.t_fine = v_x1_u32r + v_x2_u32r; + temperature = (p_bmp280->cal_param.t_fine * 5 + 128) >> 8; + + return temperature; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to read uncompensated pressure. + * in the registers 0xF7, 0xF8 and 0xF9 + * 0xF7 -> MSB -> bit from 0 to 7 + * 0xF8 -> LSB -> bit from 0 to 7 + * 0xF9 -> LSB -> bit from 4 to 7 + * + * + * + * \param s32 upressure : Pointer holding the uncompensated pressure. + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_up(s32 *upressure) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 a_data_u8r[3] = {0, 0, 0}; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_PRESSURE_MSB_REG, a_data_u8r, 3); + *upressure = (s32)( + (((u32)(a_data_u8r[0])) + << SHIFT_LEFT_12_POSITION) | + (((u32)(a_data_u8r[1])) + << SHIFT_LEFT_4_POSITION) | + ((u32)a_data_u8r[2] >> + SHIFT_RIGHT_4_POSITION)); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief Reads actual pressure from uncompensated pressure + * and returns the value in Pascal(Pa) + * Output value of "96386" equals 96386 Pa = + * 963.86 hPa = 963.86 millibar + + * + * + * + * \param s32 : value of uncompensated pressure + * + * + * + * \return + * u32 : actual pressure + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +u32 bmp280_compensate_P_int32(s32 adc_p) +{ + s32 v_x1_u32r = BMP280_Zero_U8X; + s32 v_x2_u32r = BMP280_Zero_U8X; + u32 pressure = BMP280_Zero_U8X; + + v_x1_u32r = (((s32)p_bmp280->cal_param.t_fine) >> 1) - + (s32)64000; + v_x2_u32r = (((v_x1_u32r >> 2) * (v_x1_u32r >> 2)) >> 11) * + ((s32)p_bmp280->cal_param.dig_P6); + v_x2_u32r = v_x2_u32r + ((v_x1_u32r * + ((s32)p_bmp280->cal_param.dig_P5)) << 1); + v_x2_u32r = (v_x2_u32r >> 2) + + (((s32)p_bmp280->cal_param.dig_P4) << 16); + v_x1_u32r = (((p_bmp280->cal_param.dig_P3 * (((v_x1_u32r >> 2) * + (v_x1_u32r >> 2)) >> 13)) >> 3) + + ((((s32)p_bmp280->cal_param.dig_P2) * + v_x1_u32r) >> 1)) >> 18; + v_x1_u32r = ((((32768+v_x1_u32r)) * + ((s32)p_bmp280->cal_param.dig_P1)) >> 15); + pressure = (((u32)(((s32)1048576) - adc_p) - + (v_x2_u32r >> 12))) * 3125; + if (pressure < 0x80000000) + /* Avoid exception caused by division by zero */ + if (v_x1_u32r != BMP280_Zero_U8X) + pressure = (pressure << 1) / ((u32)v_x1_u32r); + else + return BMP280_Zero_U8X; + else + /* Avoid exception caused by division by zero */ + if (v_x1_u32r != BMP280_Zero_U8X) + pressure = (pressure / + (u32)v_x1_u32r) * 2; + else + return BMP280_Zero_U8X; + v_x1_u32r = (((s32) + p_bmp280->cal_param.dig_P9) * + ((s32)(((pressure >> 3) + * (pressure >> 3)) >> 13))) + >> 12; + v_x2_u32r = (((s32)(pressure >> 2)) * + ((s32)p_bmp280->cal_param.dig_P8)) >> 13; + pressure = (u32) + ((s32)pressure + + ((v_x1_u32r + v_x2_u32r + + p_bmp280->cal_param.dig_P7) >> 4)); + + return pressure; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief reads uncompensated pressure and temperature + * + * + * \param s32 upressure: Pointer holding + * the uncompensated pressure. + * \param s32 utemperature: Pointer holding + * the uncompensated temperature. + * + * \return: results of bus communication function + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_uput(s32 *upressure, +s32 *utemperature) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 a_data_u8r[6] = {0, 0, 0, 0, 0, 0}; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_PRESSURE_MSB_REG, a_data_u8r, 6); + *upressure = (s32)( + (((u32)(a_data_u8r[0])) + << SHIFT_LEFT_12_POSITION) | + (((u32)(a_data_u8r[1])) + << SHIFT_LEFT_4_POSITION) | + ((u32)a_data_u8r[2] >> + SHIFT_RIGHT_4_POSITION)); + + /* Temperature */ + *utemperature = (s32)((( + (u32) (a_data_u8r[3])) + << SHIFT_LEFT_12_POSITION) | + (((u32)(a_data_u8r[4])) + << SHIFT_LEFT_4_POSITION) + | ((u32)a_data_u8r[5] + >> SHIFT_RIGHT_4_POSITION)); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief reads pressure and temperature + * + * + * \param u32 pressure : Pointer holding the compensated pressure. + * \param s32 temperature : Pointer holding + * the compensated temperature. + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_pt(u32 *pressure, +s32 *temperature) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + s32 upressure = BMP280_Zero_U8X; + s32 utemperature = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += bmp280_read_uput( + &upressure, &utemperature); + *temperature = bmp280_compensate_T_int32( + utemperature); + *pressure = bmp280_compensate_P_int32( + upressure); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to + * calibration parameters used for calculation in the registers + * parameter Register address bit + * dig_T1 0x88/0x89 0 : 7 / 8: 15 + * dig_T2 0x8A/0x8B 0 : 7 / 8: 15 + * dig_T3 0x8C/0x8D 0 : 7 / 8: 15 + * dig_P1 0x8E/0x8F 0 : 7 / 8: 15 + * dig_P2 0x90/0x91 0 : 7 / 8: 15 + * dig_P3 0x92/0x93 0 : 7 / 8: 15 + * dig_P4 0x94/0x95 0 : 7 / 8: 15 + * dig_P5 0x96/0x97 0 : 7 / 8: 15 + * dig_P6 0x98/0x99 0 : 7 / 8: 15 + * dig_P7 0x9A/0x9B 0 : 7 / 8: 15 + * dig_P8 0x9C/0x9D 0 : 7 / 8: 15 + * dig_P9 0x9E/0x9F 0 : 7 / 8: 15 + * + * \param: None + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_calib_param() +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 a_data_u8r[26] = {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}; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_DIG_T1_LSB_REG, a_data_u8r, 24); + + p_bmp280->cal_param.dig_T1 = (u16)((( + (u16)((u8)a_data_u8r[1])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[0]); + p_bmp280->cal_param.dig_T2 = (s16)((( + (s16)((s8)a_data_u8r[3])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[2]); + p_bmp280->cal_param.dig_T3 = (s16)((( + (s16)((s8)a_data_u8r[5])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[4]); + p_bmp280->cal_param.dig_P1 = (u16)((( + (u16)((u8)a_data_u8r[7])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[6]); + p_bmp280->cal_param.dig_P2 = (s16)((( + (s16)((s8)a_data_u8r[9])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[8]); + p_bmp280->cal_param.dig_P3 = (s16)((( + (s16)((s8)a_data_u8r[11])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[10]); + p_bmp280->cal_param.dig_P4 = (s16)((( + (s16)((s8)a_data_u8r[13])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[12]); + p_bmp280->cal_param.dig_P5 = (s16)((( + (s16)((s8)a_data_u8r[15])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[14]); + p_bmp280->cal_param.dig_P6 = (s16)((( + (s16)((s8)a_data_u8r[17])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[16]); + p_bmp280->cal_param.dig_P7 = (s16)((( + (s16)((s8)a_data_u8r[19])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[18]); + p_bmp280->cal_param.dig_P8 = (s16)((( + (s16)((s8)a_data_u8r[21])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[20]); + p_bmp280->cal_param.dig_P9 = (s16)((( + (s16)((s8)a_data_u8r[23])) << + SHIFT_LEFT_8_POSITION) | a_data_u8r[22]); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to get + * the temperature oversampling setting in the register 0xF4 + * bits from 5 to 7 + * + * bit temperature oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 *value : Pointer holding the osrs_t value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_osrs_t( +u8 *value) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_OSRST__REG, + &v_data_u8r, 1); + *value = BMP280_GET_BITSLICE(v_data_u8r, + BMP280_CTRLMEAS_REG_OSRST); + + p_bmp280->osrs_t = *value; + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to set + * the temperature oversampling in the register 0xF4 + * bits from 5 to 7 + * + * bit temperature oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 value : the osrs_t value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_osrs_t( +u8 value) +{ + BMP280_RETURN_FUNCTION_TYPE comres = SUCCESS; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_OSRST__REG, + &v_data_u8r, 1); + if (comres == SUCCESS) { + v_data_u8r = + BMP280_SET_BITSLICE(v_data_u8r, + BMP280_CTRLMEAS_REG_OSRST, value); + comres += + p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_OSRST__REG, + &v_data_u8r, 1); + p_bmp280->osrs_t = value; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to get + * the pressure oversampling setting in the register 0xF4 + * bits from 2 to 4 + * + * bit pressure oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 value : Pointer holding the osrs_p value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_osrs_p( +u8 *value) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_OSRSP__REG, + &v_data_u8r, 1); + *value = BMP280_GET_BITSLICE(v_data_u8r, + BMP280_CTRLMEAS_REG_OSRSP); + + p_bmp280->osrs_p = *value; + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to set + * the pressure oversampling in the register 0xF4 + * bits from 2 to 4 + * + * bit pressure oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 value : the osrs_p value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_osrs_p( + u8 value) +{ + BMP280_RETURN_FUNCTION_TYPE comres = SUCCESS; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_OSRSP__REG, + &v_data_u8r, 1); + if (comres == SUCCESS) { + v_data_u8r = BMP280_SET_BITSLICE( + v_data_u8r, + BMP280_CTRLMEAS_REG_OSRSP, value); + comres += + p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_OSRSP__REG, + &v_data_u8r, 1); + + p_bmp280->osrs_p = value; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API used to get the + * Operational Mode from the sensor in the register 0xF4 bit 0 and 1 + * + * + * + * \param u8 *mode : Pointer holding the mode value. + * 0x00 -> BMP280_SLEEP_MODE + * 0x01 and 0x02 -> BMP280_FORCED_MODE + * 0x03 -> BMP280_NORMAL_MODE + * \return : results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_mode(u8 *mode) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_mode_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_MODE__REG, + &v_mode_u8r, 1); + *mode = BMP280_GET_BITSLICE(v_mode_u8r, + BMP280_CTRLMEAS_REG_MODE); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API used to set the + * Operational Mode from the sensor in the register 0xF4 bit 0 and 1 + * + * + * + * \param u8 mode : the value of mode. + * 0x00 -> BMP280_SLEEP_MODE + * 0x01 and 0x02 -> BMP280_FORCED_MODE + * 0x03 -> BMP280_NORMAL_MODE + * + * + * \return : results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_mode(u8 mode) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_mode_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + if (mode < BMP280_Four_U8X) { + v_mode_u8r = (p_bmp280->osrs_t << + SHIFT_LEFT_5_POSITION) + (p_bmp280->osrs_p << + SHIFT_LEFT_2_POSITION) + mode; + comres += p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + BMP280_CTRLMEAS_REG_MODE__REG, &v_mode_u8r, 1); + } else { + comres = E_BMP280_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief Used to reset the sensor + * The value 0xB6 is written to the 0xE0 register the device is reset using the + * complete power-on-reset procedure. + * Softreset can be easily set using bmp280_set_softreset(). + * + * Usage Hint : bmp280_set_softreset() + * + * \param: None + * + * + * + * \return: result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_softreset() +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_SOFT_RESET_CODE; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + BMP280_RESET_REG, &v_data_u8r, 1); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API used to get the sensor + * SPI mode(communication type) in the register 0xF5 bit 0 + * + * + * + * \param u8 *enable_disable : Pointer holding the + * spi3 enable or disable state. + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_spi3(u8 *enable_disable) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_SPI3WEN__REG, + &v_data_u8r, 1); + *enable_disable = BMP280_GET_BITSLICE( + v_data_u8r, + BMP280_CONFIG_REG_SPI3WEN); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API used to set the sensor + * SPI mode(communication type) in the register 0xF5 bit 0 + * + * + * + * \param u8 enable_disable : the spi3 enable or disable value. + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_spi3(u8 enable_disable) +{ + BMP280_RETURN_FUNCTION_TYPE comres = SUCCESS; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_SPI3WEN__REG, + &v_data_u8r, 1); + if (comres == SUCCESS) { + v_data_u8r = BMP280_SET_BITSLICE( + v_data_u8r, + BMP280_CONFIG_REG_SPI3WEN, + enable_disable); + comres += + p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_SPI3WEN__REG, + &v_data_u8r, 1); + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to reads filter setting + * in the register 0xF5 bit 3 and 4 + * + * + * + * \param u8 *value : Pointer holding the filter value. + * + * value Filter coefficient + * 0x00 Filter Off + * 0x01 2 + * 0x02 4 + * 0x03 8 + * 0x04 16 + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_filter(u8 *value) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_FILTER__REG, + &v_data_u8r, 1); + *value = BMP280_GET_BITSLICE(v_data_u8r, + BMP280_CONFIG_REG_FILTER); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to set filter setting + * in the register 0xF5 bit 3 and 4 + * + * + * + * \param u8 value : The filter coefficient value + * + * value Filter coefficient + * 0x00 Filter Off + * 0x01 2 + * 0x02 4 + * 0x03 8 + * 0x04 16 + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_filter(u8 value) +{ + BMP280_RETURN_FUNCTION_TYPE comres = SUCCESS; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_FILTER__REG, + &v_data_u8r, 1); + if (comres == SUCCESS) { + v_data_u8r = BMP280_SET_BITSLICE( + v_data_u8r, + BMP280_CONFIG_REG_FILTER, value); + comres += + p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_FILTER__REG, + &v_data_u8r, 1); + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API used to Read the + * standby duration time from the sensor in the register 0xF5 bit 5 to 7 + * + * \param u8 *time : Pointer holding + * the standby duration time value. + * 0x00 - BMP280_STANDBYTIME_1_MS + * 0x01 - BMP280_STANDBYTIME_63_MS + * 0x02 - BMP280_STANDBYTIME_125_MS + * 0x03 - BMP280_STANDBYTIME_250_MS + * 0x04 - BMP280_STANDBYTIME_500_MS + * 0x05 - BMP280_STANDBYTIME_1000_MS + * 0x06 - BMP280_STANDBYTIME_2000_MS + * 0x07 - BMP280_STANDBYTIME_4000_MS + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_standbydur(u8 *time) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_TSB__REG, &v_data_u8r, 1); + *time = BMP280_GET_BITSLICE(v_data_u8r, + BMP280_CONFIG_REG_TSB); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API used to write + * standby duration time from the sensor in the register 0xF5 bit 5 to 7 + * Normal mode comprises an automated perpetual cycling between an (active) + * Measurement period and an (inactive) standby period. + * The standby time is determined by the contents of the register t_sb. + * Standby time can be set using BME280_STANDBYTIME_125_MS. + * + * Usage Hint : bme280_set_standbydur(BME280_STANDBYTIME_125_MS) + * + * \param u8 time : Value of the standby duration + * 0x00 - BMP280_STANDBYTIME_1_MS + * 0x01 - BMP280_STANDBYTIME_63_MS + * 0x02 - BMP280_STANDBYTIME_125_MS + * 0x03 - BMP280_STANDBYTIME_250_MS + * 0x04 - BMP280_STANDBYTIME_500_MS + * 0x05 - BMP280_STANDBYTIME_1000_MS + * 0x06 - BMP280_STANDBYTIME_2000_MS + * 0x07 - BMP280_STANDBYTIME_4000_MS + * + * + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_standbydur(u8 time) +{ + BMP280_RETURN_FUNCTION_TYPE comres = SUCCESS; + u8 v_data_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_TSB__REG, &v_data_u8r, 1); + if (comres == SUCCESS) { + v_data_u8r = + BMP280_SET_BITSLICE(v_data_u8r, + BMP280_CONFIG_REG_TSB, time); + comres += + p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + BMP280_CONFIG_REG_TSB__REG, + &v_data_u8r, 1); + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API is used to write + * the working mode of the sensor + * + * + * \param u8 : Mode to be set + * 0 -> BMP280_ULTRALOWPOWER_MODE + * 1 -> BMP280_LOWPOWER_MODE + * 2 -> BMP280_STANDARDRESOLUTION_MODE + * 3 -> BMP280_HIGHRESOLUTION_MODE + * 4 -> BMP280_ULTRAHIGHRESOLUTION_MODE + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_workmode(u8 mode) +{ +BMP280_RETURN_FUNCTION_TYPE comres = SUCCESS; +u8 v_data_u8r = BMP280_Zero_U8X; +if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + if (mode <= BMP280_Four_U8X) { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, BMP280_CTRLMEAS_REG, + &v_data_u8r, 1); + if (comres == SUCCESS) { + switch (mode) { + case BMP280_ULTRALOWPOWER_MODE: + p_bmp280->osrs_t = + BMP280_ULTRALOWPOWER_OSRS_T; + p_bmp280->osrs_p = + BMP280_ULTRALOWPOWER_OSRS_P; + break; + case BMP280_LOWPOWER_MODE: + p_bmp280->osrs_t = + BMP280_LOWPOWER_OSRS_T; + p_bmp280->osrs_p = + BMP280_LOWPOWER_OSRS_P; + break; + case BMP280_STANDARDRESOLUTION_MODE: + p_bmp280->osrs_t = + BMP280_STANDARDRESOLUTION_OSRS_T; + p_bmp280->osrs_p = + BMP280_STANDARDRESOLUTION_OSRS_P; + break; + case BMP280_HIGHRESOLUTION_MODE: + p_bmp280->osrs_t = + BMP280_HIGHRESOLUTION_OSRS_T; + p_bmp280->osrs_p = + BMP280_HIGHRESOLUTION_OSRS_P; + break; + case BMP280_ULTRAHIGHRESOLUTION_MODE: + p_bmp280->osrs_t = + BMP280_ULTRAHIGHRESOLUTION_OSRS_T; + p_bmp280->osrs_p = + BMP280_ULTRAHIGHRESOLUTION_OSRS_P; + break; + } + v_data_u8r = BMP280_SET_BITSLICE(v_data_u8r, + BMP280_CTRLMEAS_REG_OSRST, p_bmp280->osrs_t); + v_data_u8r = BMP280_SET_BITSLICE(v_data_u8r, + BMP280_CTRLMEAS_REG_OSRSP, p_bmp280->osrs_p); + comres += p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, BMP280_CTRLMEAS_REG, + &v_data_u8r, 1); + } + } else { + comres = E_BMP280_OUT_OF_RANGE; + } + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API used to read both + * uncompensated pressure and temperature in forced mode + * + * + * \param s32 upressure: Pointer holding the uncompensated pressure. + * \param s32 utemperature: Pointer holding + * the uncompensated temperature. + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_forced_uput(s32 *upressure, +s32 *utemperature) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + u8 v_data_u8r = BMP280_Zero_U8X; + u8 v_waittime_u8r = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + v_data_u8r = (p_bmp280->osrs_t + << SHIFT_LEFT_5_POSITION) + + (p_bmp280->osrs_p << SHIFT_LEFT_2_POSITION) + + BMP280_FORCED_MODE; + comres += p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, BMP280_CTRLMEAS_REG, + &v_data_u8r, 1); + bmp280_compute_wait_time(&v_waittime_u8r); + p_bmp280->delay_msec(v_waittime_u8r); + comres += bmp280_read_uput(upressure, utemperature); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API gives data to the given register and + * the data is written in the corresponding register + * address + * + * + * + * \param u8 addr, u8 data, u8 len + * addr -> Address of the register + * data -> Data to be written to the register + * len -> Length of the Data + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_write_register(u8 addr, +u8 *data, u8 len) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_WRITE_FUNC( + p_bmp280->dev_addr, + addr, data, len); + } + return comres; +} +/* Compiler Switch if applicable +#ifdef + +#endif +*/ +/******************************************************************************* + * Description: *//**\brief This API reads the data from the given register + * address + * + * + * + * \param u8 addr, u8 *data, u8 len + * addr -> Address of the register + * data -> address of the variable, read value will be kept + * len -> Length of the data + * + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_register(u8 addr, +u8 *data, u8 len) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + if (p_bmp280 == BMP280_NULL) { + return E_BMP280_NULL_PTR; + } else { + comres += p_bmp280->BMP280_BUS_READ_FUNC( + p_bmp280->dev_addr, + addr, data, len); + } + return comres; +} +#ifdef BMP280_ENABLE_FLOAT +/******************************************************************************* + * Description: *//**\brief Reads actual temperature from uncompensated temperature + * and returns the value in Degree centigrade + * Output value of "51.23" equals 51.23 DegC. + * + * + * + * \param s32 : value of uncompensated temperature + * + * + * + * \return + * double : actual temperature in floating point + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +double bmp280_compensate_T_double(s32 adc_t) +{ + double v_x1_u32r = BMP280_Zero_U8X; + double v_x2_u32r = BMP280_Zero_U8X; + double temperature = BMP280_Zero_U8X; + + v_x1_u32r = (((double)adc_t) / 16384.0 - + ((double)p_bmp280->cal_param.dig_T1) / 1024.0) * + ((double)p_bmp280->cal_param.dig_T2); + v_x2_u32r = ((((double)adc_t) / 131072.0 - + ((double)p_bmp280->cal_param.dig_T1) / 8192.0) * + (((double)adc_t) / 131072.0 - + ((double)p_bmp280->cal_param.dig_T1) / 8192.0)) * + ((double)p_bmp280->cal_param.dig_T3); + p_bmp280->cal_param.t_fine = (s32)(v_x1_u32r + v_x2_u32r); + temperature = (v_x1_u32r + v_x2_u32r) / 5120.0; + + + return temperature; +} +/******************************************************************************* + * Description: *//**\brief Reads actual pressure from uncompensated pressure + * and returns pressure in Pa as double. + * Output value of "96386.2" + * equals 96386.2 Pa = 963.862 hPa. + * + * + * + * \param s32 : value of uncompensated pressure + * + * + * + * \return + * double : actual pressure in floating point + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +double bmp280_compensate_P_double(s32 adc_p) +{ + double v_x1_u32r = BMP280_Zero_U8X; + double v_x2_u32r = BMP280_Zero_U8X; + double pressure = BMP280_Zero_U8X; + + v_x1_u32r = ((double)p_bmp280->cal_param.t_fine/2.0) - 64000.0; + v_x2_u32r = v_x1_u32r * v_x1_u32r * + ((double)p_bmp280->cal_param.dig_P6) / 32768.0; + v_x2_u32r = v_x2_u32r + v_x1_u32r * + ((double)p_bmp280->cal_param.dig_P5) * 2.0; + v_x2_u32r = (v_x2_u32r / 4.0) + + (((double)p_bmp280->cal_param.dig_P4) * 65536.0); + v_x1_u32r = (((double)p_bmp280->cal_param.dig_P3) * + v_x1_u32r * v_x1_u32r / 524288.0 + + ((double)p_bmp280->cal_param.dig_P2) * v_x1_u32r) / 524288.0; + v_x1_u32r = (1.0 + v_x1_u32r / 32768.0) * + ((double)p_bmp280->cal_param.dig_P1); + pressure = 1048576.0 - (double)adc_p; + /* Avoid exception caused by division by zero */ + if (v_x1_u32r != 0.0) + pressure = (pressure - (v_x2_u32r / 4096.0)) * + 6250.0 / v_x1_u32r; + else + return 0; + v_x1_u32r = ((double)p_bmp280->cal_param.dig_P9) * + pressure * pressure / 2147483648.0; + v_x2_u32r = pressure * ((double)p_bmp280->cal_param.dig_P8) / 32768.0; + pressure = pressure + (v_x1_u32r + v_x2_u32r + + ((double)p_bmp280->cal_param.dig_P7)) / 16.0; + + return pressure; +} +#endif +#if defined(BMP280_ENABLE_INT64) && defined(BMP280_64BITSUPPORT_PRESENT) +/******************************************************************************* + * Description: *//**\brief Reads actual pressure from uncompensated pressure + * and returns the value in Pa as unsigned 32 bit + * integer in Q24.8 format (24 integer bits and + * 8 fractional bits). Output value of "24674867" + * represents 24674867 / 256 = 96386.2 Pa = 963.862 hPa + * + * + * + * \param s32 : value of uncompensated temperature + * + * + * + * \return + * u32 : actual pressure + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +u32 bmp280_compensate_P_int64(s32 adc_p) +{ + s64 v_x1_s64r = BMP280_Zero_U8X; + s64 v_x2_s64r = BMP280_Zero_U8X; + s64 pressure = BMP280_Zero_U8X; + v_x1_s64r = ((s64)p_bmp280->cal_param.t_fine) - 128000; + v_x2_s64r = v_x1_s64r * v_x1_s64r * + (s64)p_bmp280->cal_param.dig_P6; + v_x2_s64r = v_x2_s64r + ((v_x1_s64r * + (s64)p_bmp280->cal_param.dig_P5) << 17); + v_x2_s64r = v_x2_s64r + + (((s64)p_bmp280->cal_param.dig_P4) << 35); + v_x1_s64r = ((v_x1_s64r * v_x1_s64r * + (s64)p_bmp280->cal_param.dig_P3) >> 8) + + ((v_x1_s64r * (s64)p_bmp280->cal_param.dig_P2) << 12); + v_x1_s64r = (((((s64)1) << 47) + v_x1_s64r)) * + ((s64)p_bmp280->cal_param.dig_P1) >> 33; + pressure = 1048576 - adc_p; + if (v_x1_s64r != BMP280_Zero_U8X) + #if defined __KERNEL__ + pressure = div64_s64((((pressure << 31) - v_x2_s64r) + * 3125), v_x1_s64r); + #else + pressure = (((pressure << 31) - v_x2_s64r) + * 3125) / v_x1_s64r; + #endif + else + return BMP280_Zero_U8X; + v_x1_s64r = (((s64)p_bmp280->cal_param.dig_P9) * + (pressure >> 13) * (pressure >> 13)) >> 25; + v_x2_s64r = (((s64)p_bmp280->cal_param.dig_P8) * + pressure) >> 19; + pressure = ((pressure + v_x1_s64r + v_x2_s64r) >> 8) + + (((s64)p_bmp280->cal_param.dig_P7) << 4); + return (u32)pressure; +} +#endif +/******************************************************************************* + * Description: *//**\brief Computing waiting time for sensor data read + * + * + * + * + * \param + * u8 : value of time + * + * + * \return + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ****************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_compute_wait_time(u8 +*v_delaytime_u8r) +{ + BMP280_RETURN_FUNCTION_TYPE comres = BMP280_Zero_U8X; + + *v_delaytime_u8r = (T_INIT_MAX + T_MEASURE_PER_OSRS_MAX * + (((1 << p_bmp280->osrs_t) >> 1) + ((1 << p_bmp280->osrs_p) + >> 1)) + (p_bmp280->osrs_p ? T_SETUP_PRESSURE_MAX : 0) + 15) + / 16; + return comres; +} diff --git a/drivers/input/misc/bmp280.h b/drivers/input/misc/bmp280.h new file mode 100755 index 00000000000..07625f5cafa --- /dev/null +++ b/drivers/input/misc/bmp280.h @@ -0,0 +1,1366 @@ +/*! + * @section LICENSE + * @license$ + * + * @filename $filename$ + * @date 2014/07/21 + * @id $id$ + * + * @brief + * API Header + * + * Revision: 2.0(Pressure and Temperature compensation code revision is 1.1 + */ +/****************************************************************************/ +#ifndef __BMP280_H__ +#define __BMP280_H__ + +/******************************************************* +* These definition uses for define the data types +******************************************************** +*While porting the API please consider the following +*Please check the version of C standard +*Are you using Linux platform +*******************************************************/ + +/********************************************************* +* This definition uses for the Linux platform support +* Please use the types.h for your data types definitions +*********************************************************/ +#ifdef __KERNEL__ + +#include +#include +#define BMP280_64BITSUPPORT_PRESENT +#else /* ! __KERNEL__ */ +/********************************************************** +* These definition uses for define the C +* standard version data types +***********************************************************/ +# if !defined(__STDC_VERSION__) + +/************************************************ + * compiler is C11 C standard +************************************************/ +#if (__STDC_VERSION__ == 201112L) + +/************************************************/ +#include +/************************************************/ + +/*unsigned integer types*/ +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + +/*signed integer types*/ +#define s8 int8_t +#define s16 int16_t +#define s32 int32_t +#define s64 int64_t +#define BMP280_64BITSUPPORT_PRESENT +/************************************************ + * compiler is C99 C standard +************************************************/ + +#elif (__STDC_VERSION__ == 199901L) + +/* stdint.h is a C99 supported c library. +which is used to fixed the integer size*/ +/************************************************/ +#include +/************************************************/ + +/*unsigned integer types*/ +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + +/*signed integer types*/ +#define s8 int8_t +#define s16 int16_t +#define s32 int32_t +#define s64 int64_t +#define BMP280_64BITSUPPORT_PRESENT +/************************************************ + * compiler is C89 or other C standard +************************************************/ + +#else /* !defined(__STDC_VERSION__) */ +/* By default it is defined as 32 bit machine configuration*/ +/* define the definition based on your machine configuration*/ +/* define the data types based on your + machine/compiler/controller configuration*/ +#define MACHINE_32_BIT + +/* If your machine support 16 bit +define the MACHINE_16_BIT*/ +#ifdef MACHINE_16_BIT +#include +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed long int + +#if defined(LONG_MAX) && LONG_MAX == 0x7fffffffffffffffL +#define s64 long int +#define u64 unsigned long int +#define BMP280_64BITSUPPORT_PRESENT +#elif defined(LLONG_MAX) && (LLONG_MAX == 0x7fffffffffffffffLL) +#define s64 long long int +#define u64 unsigned long long int +#define BMP280_64BITSUPPORT_PRESENT +#else +#warning Either the correct data type for signed 64 bit integer \ +could not be found, or 64 bit integers are not supported in your environment. +#warning The API will only offer 32 bit pressure calculation.This will \ +slightly impede accuracy(noise of ~1 pascal RMS will be added to output). +#warning If 64 bit integers are supported on your platform, \ +please set s64 manually and "#define(BMP280_64BITSUPPORT_PRESENT)" manually. +#endif + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned long int + + +/* If your machine support 32 bit +define the MACHINE_32_BIT*/ +#elif defined MACHINE_32_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long long int +#define BMP280_64BITSUPPORT_PRESENT + + +/* If your machine support 64 bit +define the MACHINE_64_BIT*/ +#elif defined MACHINE_64_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long int +#define BMP280_64BITSUPPORT_PRESENT + +#else +#warning The data types defined above which not supported \ +define the data types manualy +#endif +#endif + +/*** This else will execute for the compilers + * which are not supported the C standards + * Like C89/C99/C11***/ +#else +/* By default it is defined as 32 bit machine configuration*/ +/* define the definition based on your machine configuration*/ +/* define the data types based on your + machine/compiler/controller configuration*/ +#define MACHINE_32_BIT + +/* If your machine support 16 bit +define the MACHINE_16_BIT*/ +#ifdef MACHINE_16_BIT +#include +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed long int + +#if defined(LONG_MAX) && LONG_MAX == 0x7fffffffffffffffL +#define s64 long int +#define u64 unsigned long int +#define BMP280_64BITSUPPORT_PRESENT +#elif defined(LLONG_MAX) && (LLONG_MAX == 0x7fffffffffffffffLL) +#define s64 long long int +#define u64 unsigned long long int +#define BMP280_64BITSUPPORT_PRESENT +#else +#warning Either the correct data type for signed 64 bit integer \ +could not be found, or 64 bit integers are not supported in your environment. +#warning The API will only offer 32 bit pressure calculation.This will \ +slightly impede accuracy(noise of ~1 pascal RMS will be added to output). +#warning If 64 bit integers are supported on your platform, \ +please set s64 manually and "#define(BMP280_64BITSUPPORT_PRESENT)" manually. +#endif + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned long int + +/* If your machine support 32 bit +define the MACHINE_32_BIT*/ +#elif defined MACHINE_32_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long long int +#define BMP280_64BITSUPPORT_PRESENT + +/* If your machine support 64 bit +define the MACHINE_64_BIT*/ +#elif defined MACHINE_64_BIT +/*signed integer types*/ +#define s8 signed char +#define s16 signed short int +#define s32 signed int +#define s64 signed long int + +/*unsigned integer types*/ +#define u8 unsigned char +#define u16 unsigned short int +#define u32 unsigned int +#define u64 unsigned long int +#define BMP280_64BITSUPPORT_PRESENT + +#else +#warning The data types defined above which not supported \ +define the data types manualy +#endif +#endif +#endif + +/* If the user wants to support floating point calculations, please set \ + the following #define. If floating point calculation is not wanted \ + or allowed (e.g. in Linux kernel), please do not set the define. */ +/*#define BMP280_ENABLE_FLOAT*/ + +/* If the user wants to support 64 bit integer calculation (needed for \ + optimal pressure accuracy) please set the following #define. If \ + int64 calculation is not wanted (e.g. because it would include \ + large libraries), please do not set the define. */ +#define BMP280_ENABLE_INT64 + +/** defines the return parameter type of the BMP280_WR_FUNCTION */ +#define BMP280_BUS_WR_RETURN_TYPE s8 + +/**\brief links the order of parameters defined in +BMP280_BUS_WR_PARAM_TYPE to function calls used inside the API*/ +#define BMP280_BUS_WR_PARAM_TYPES u8, u8,\ + u8 *, u8 + +/**\brief links the order of parameters defined in +BMP280_BUS_WR_PARAM_TYPE to function calls used inside the API*/ +#define BMP280_BUS_WR_PARAM_ORDER(device_addr, register_addr,\ + register_data, wr_len) + +/* never change this line */ +#define BMP280_BUS_WRITE_FUNC(device_addr, register_addr,\ +register_data, wr_len) bus_write(device_addr, register_addr,\ + register_data, wr_len) + +/**\brief defines the return parameter type of the BMP280_RD_FUNCTION +*/ +#define BMP280_BUS_RD_RETURN_TYPE s8 + +/**\brief defines the calling parameter types of the BMP280_RD_FUNCTION +*/ +#define BMP280_BUS_RD_PARAM_TYPES (u8, u8,\ + u8 *, u8) + +/**\brief links the order of parameters defined in \ +BMP280_BUS_RD_PARAM_TYPE to function calls used inside the API +*/ +#define BMP280_BUS_RD_PARAM_ORDER (device_addr, register_addr,\ + register_data) + +/* never change this line */ +#define BMP280_BUS_READ_FUNC(device_addr, register_addr,\ + register_data, rd_len)bus_read(device_addr, register_addr,\ + register_data, rd_len) + +/**\brief defines the return parameter type of the BMP280_DELAY_FUNCTION +*/ +#define BMP280_DELAY_RETURN_TYPE void + +/**\brief defines the calling parameter types of the BMP280_DELAY_FUNCTION +*/ +#define BMP280_DELAY_PARAM_TYPES u16 + +/* never change this line */ +#define BMP280_DELAY_FUNC(delay_in_msec)\ + delay_func(delay_in_msec) + +#define BMP280_GET_BITSLICE(regvar, bitname)\ + ((regvar & bitname##__MSK) >> bitname##__POS) + +#define BMP280_SET_BITSLICE(regvar, bitname, val)\ + ((regvar & ~bitname##__MSK) | ((val< MSB -> bit from 0 to 7 + * 0xFB -> LSB -> bit from 0 to 7 + * 0xFC -> LSB -> bit from 4 to 7 + * + * \param s32 utemperature : Pointer holding + * the uncompensated temperature. + * + * + * + * \return results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_ut(s32 *utemperature); +/******************************************************************************* + * Description: *//**\brief Reads actual temperature from uncompensated temperature + * and returns the value in 0.01 degree Centigrade + * Output value of "5123" equals 51.23 DegC. + * + * + * + * \param s32 : value of uncompensated temperature. + * + * + * + * \return + * s32 : actual temperature + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +s32 bmp280_compensate_T_int32(s32 adc_t); +/******************************************************************************* + * Description: *//**\brief This API is used to read uncompensated pressure. + * in the registers 0xF7, 0xF8 and 0xF9 + * 0xF7 -> MSB -> bit from 0 to 7 + * 0xF8 -> LSB -> bit from 0 to 7 + * 0xF9 -> LSB -> bit from 4 to 7 + * + * + * + * \param s32 upressure : Pointer holding the uncompensated pressure. + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_up(s32 *upressure); +/******************************************************************************* + * Description: *//**\brief Reads actual pressure from uncompensated pressure + * and returns the value in Pascal(Pa) + * Output value of "96386" equals 96386 Pa = + * 963.86 hPa = 963.86 millibar + + * + * + * + * \param s32 : value of uncompensated pressure + * + * + * + * \return + * u32 : actual pressure + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +u32 bmp280_compensate_P_int32(s32 adc_p); +/******************************************************************************* + * Description: *//**\brief reads uncompensated pressure and temperature + * + * + * \param s32 upressure: Pointer holding + * the uncompensated pressure. + * \param s32 utemperature: Pointer holding + * the uncompensated temperature. + * + * \return: results of bus communication function + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_uput(s32 *upressure, +s32 *utemperature); +/******************************************************************************* + * Description: *//**\brief reads pressure and temperature + * + * + * \param u32 pressure : Pointer holding the compensated pressure. + * \param s32 temperature : Pointer holding + * the compensated temperature. + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ + +BMP280_RETURN_FUNCTION_TYPE bmp280_read_pt(u32 *pressure, +s32 *temperature); +/******************************************************************************* + * Description: *//**\brief This API is used to + * calibration parameters used for calculation in the registers + * parameter Register address bit + * dig_T1 0x88/0x89 0 : 7 / 8: 15 + * dig_T2 0x8A/0x8B 0 : 7 / 8: 15 + * dig_T3 0x8C/0x8D 0 : 7 / 8: 15 + * dig_P1 0x8E/0x8F 0 : 7 / 8: 15 + * dig_P2 0x90/0x91 0 : 7 / 8: 15 + * dig_P3 0x92/0x93 0 : 7 / 8: 15 + * dig_P4 0x94/0x95 0 : 7 / 8: 15 + * dig_P5 0x96/0x97 0 : 7 / 8: 15 + * dig_P6 0x98/0x99 0 : 7 / 8: 15 + * dig_P7 0x9A/0x9B 0 : 7 / 8: 15 + * dig_P8 0x9C/0x9D 0 : 7 / 8: 15 + * dig_P9 0x9E/0x9F 0 : 7 / 8: 15 + * + * \param: None + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_calib_param(void); +/******************************************************************************* + * Description: *//**\brief This API is used to get + * the temperature oversampling setting in the register 0xF4 + * bits from 5 to 7 + * + * bit temperature oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 value : Pointer holding the osrs_t value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_osrs_t(u8 *value); +/******************************************************************************* + * Description: *//**\brief This API is used to set + * the temperature oversampling in the register 0xF4 + * bits from 5 to 7 + * + * bit temperature oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 value : the osrs_t value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_osrs_t(u8 value); +/******************************************************************************* + * Description: *//**\brief This API is used to get + * the pressure oversampling setting in the register 0xF4 + * bits from 2 to 4 + * + * bit pressure oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 value : Pointer holding the osrs_p value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_osrs_p(u8 *value); +/******************************************************************************* + * Description: *//**\brief This API is used to set + * the pressure oversampling in the register 0xF4 + * bits from 2 to 4 + * + * bit pressure oversampling + * 0x00 Skipped + * 0x01 BMP280_OVERSAMPLING_1X + * 0x02 BMP280_OVERSAMPLING_2X + * 0x03 BMP280_OVERSAMPLING_4X + * 0x04 BMP280_OVERSAMPLING_8X + * 0x05,0x06 and 0x07 BMP280_OVERSAMPLING_16X + * + * + * \param u8 value : the osrs_p value + * + * + * + * \return: results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_osrs_p(u8 value); +/******************************************************************************* + * Description: *//**\brief This API used to get the + * Operational Mode from the sensor in the register 0xF4 bit 0 and 1 + * + * + * + * \param u8 *mode : Pointer holding the mode value. + * 0x00 -> BMP280_SLEEP_MODE + * 0x01 and 0x02 -> BMP280_FORCED_MODE + * 0x03 -> BMP280_NORMAL_MODE + * \return : results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_mode(u8 *mode); +/******************************************************************************* + * Description: *//**\brief This API used to set the + * Operational Mode from the sensor in the register 0xF4 bit 0 and 1 + * + * + * + * \param u8 *mode : Pointer holding the mode value. + * 0x00 -> BMP280_SLEEP_MODE + * 0x01 and 0x02 -> BMP280_FORCED_MODE + * 0x03 -> BMP280_NORMAL_MODE + * + * + * \return : results of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_mode(u8 mode); +/******************************************************************************* + * Description: *//**\brief Used to reset the sensor + * The value 0xB6 is written to the 0xE0 register the device is reset using the + * complete power-on-reset procedure. + * Softreset can be easily set using bmp280_set_softreset(). + * + * Usage Hint : bmp280_set_softreset() + * + * \param: None + * + * + * + * \return: result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_softreset(void); +/******************************************************************************* + * Description: *//**\brief This API used to set the sensor + * SPI mode(communication type) in the register 0xF5 bit 0 + * + * + * + * \param u8 *enable_disable : Pointer holding the + * spi3 enable or disable state. + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_spi3(u8 *enable_disable); +/******************************************************************************* + * Description: *//**\brief This API used to set the sensor + * SPI mode(communication type) in the register 0xF5 bit 0 + * + * + * + * \param u8 enable_disable : the spi3 enable or disable value. + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_spi3(u8 enable_disable); +/******************************************************************************* + * Description: *//**\brief This API is used to reads filter setting + * in the register 0xF5 bit 3 and 4 + * + * + * + * \param u8 *value : Pointer holding the filter value. + * + * value Filter coefficient + * 0x00 Filter Off + * 0x01 2 + * 0x02 4 + * 0x03 8 + * 0x04 16 + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_filter(u8 *value); +/******************************************************************************* + * Description: *//**\brief This API is used to set filter setting + * in the register 0xF5 bit 3 and 4 + * + * + * + * \param u8 value : The filter coefficient value + * + * value Filter coefficient + * 0x00 Filter Off + * 0x01 2 + * 0x02 4 + * 0x03 8 + * 0x04 16 + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_filter(u8 value); +/******************************************************************************* + * Description: *//**\brief This API used to Read the + * standby duration time from the sensor in the register 0xF5 bit 5 to 7 + * + * \param u8 *time : Pointer holding + * the standby duration time value. + * 0x00 - BMP280_STANDBYTIME_1_MS + * 0x01 - BMP280_STANDBYTIME_63_MS + * 0x02 - BMP280_STANDBYTIME_125_MS + * 0x03 - BMP280_STANDBYTIME_250_MS + * 0x04 - BMP280_STANDBYTIME_500_MS + * 0x05 - BMP280_STANDBYTIME_1000_MS + * 0x06 - BMP280_STANDBYTIME_2000_MS + * 0x07 - BMP280_STANDBYTIME_4000_MS + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_standbydur(u8 *time); +/******************************************************************************* + * Description: *//**\brief This API used to write + * standby duration time from the sensor in the register 0xF5 bit 5 to 7 + * Normal mode comprises an automated perpetual cycling between an (active) + * Measurement period and an (inactive) standby period. + * The standby time is determined by the contents of the register t_sb. + * Standby time can be set using BME280_STANDBYTIME_125_MS. + * + * Usage Hint : bme280_set_standbydur(BME280_STANDBYTIME_125_MS) + * + * \param u8 time : Value of the standby duration + * 0x00 - BMP280_STANDBYTIME_1_MS + * 0x01 - BMP280_STANDBYTIME_63_MS + * 0x02 - BMP280_STANDBYTIME_125_MS + * 0x03 - BMP280_STANDBYTIME_250_MS + * 0x04 - BMP280_STANDBYTIME_500_MS + * 0x05 - BMP280_STANDBYTIME_1000_MS + * 0x06 - BMP280_STANDBYTIME_2000_MS + * 0x07 - BMP280_STANDBYTIME_4000_MS + * + * + * + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_standbydur(u8 time); +/******************************************************************************* + * Description: *//**\brief This API is used to write + * the working mode of the sensor + * + * + * \param u8 : Mode to be set + * 0 -> BMP280_ULTRALOWPOWER_MODE + * 1 -> BMP280_LOWPOWER_MODE + * 2 -> BMP280_STANDARDRESOLUTION_MODE + * 3 -> BMP280_HIGHRESOLUTION_MODE + * 4 -> BMP280_ULTRAHIGHRESOLUTION_MODE + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_set_workmode(u8 mode); +/******************************************************************************* + * Description: *//**\brief This API used to read both + * uncompensated pressure and temperature in forced mode + * + * + * \param s32 upressure: Pointer holding the uncompensated pressure. + * \param s32 utemperature: Pointer holding + * the uncompensated temperature. + * + * + * \return result of bus communication function + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_get_forced_uput(s32 *upressure, +s32 *utemperature); +/******************************************************************************* + * Description: *//**\brief This API gives data to the given register and + * the data is written in the corresponding register + * address + * + * + * + * \param u8 addr, u8 data, u8 len + * addr -> Address of the register + * data -> Data to be written to the register + * len -> Length of the Data + * + * + * + * \return communication results. + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_write_register(u8 addr, +u8 *data, u8 len); +/******************************************************************************* + * Description: *//**\brief This API reads the data from the given register + * address + * + * + * + * \param u8 addr, u8 *data, u8 len + * addr -> Address of the register + * data -> address of the variable, read value will be kept + * len -> Length of the data + * + * + * + * + * \return results of communication routine + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_read_register(u8 addr, +u8 *data, u8 len); + +#ifdef BMP280_ENABLE_FLOAT +/******************************************************************************* + * Description: *//**\brief Reads actual temperature from uncompensated temperature + * and returns the value in Degree centigrade + * Output value of "51.23" equals 51.23 DegC. + * + * + * + * \param s32 : value of uncompensated temperature + * + * + * + * \return + * double : actual temperature in floating point + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +double bmp280_compensate_T_double(s32 adc_t); +/******************************************************************************* + * Description: *//**\brief Reads actual pressure from uncompensated pressure + * and returns pressure in Pa as double. + * Output value of "96386.2" + * equals 96386.2 Pa = 963.862 hPa. + * + * + * + * \param s32 : value of uncompensated pressure + * + * + * + * \return + * double : actual pressure in floating point + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +double bmp280_compensate_P_double(s32 adc_p); +#endif +#if defined(BMP280_ENABLE_INT64) && defined(BMP280_64BITSUPPORT_PRESENT) +/******************************************************************************* + * Description: *//**\brief Reads actual pressure from uncompensated pressure + * and returns the value in Pa as unsigned 32 bit + * integer in Q24.8 format (24 integer bits and + * 8 fractional bits). Output value of "24674867" + * represents 24674867 / 256 = 96386.2 Pa = 963.862 hPa + * + * + * + * \param s32 : value of uncompensated temperature + * + * + * + * \return + * u32 : actual pressure + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ******************************************************************************/ +u32 bmp280_compensate_P_int64(s32 adc_p); +#endif +/******************************************************************************* + * Description: *//**\brief Computing waiting time for sensor data read + * + * + * + * + * \param + * u8 : value of time + * + * + * \return results of communication routine + * + * + ******************************************************************************/ +/* Scheduling: + * + * + * + * Usage guide: + * + * + * Remarks: + * + ****************************************************************************/ +BMP280_RETURN_FUNCTION_TYPE bmp280_compute_wait_time(u8 +*v_delaytime_u8r); +#endif diff --git a/drivers/input/misc/bmp280_core.c b/drivers/input/misc/bmp280_core.c new file mode 100755 index 00000000000..20d833b166c --- /dev/null +++ b/drivers/input/misc/bmp280_core.c @@ -0,0 +1,1734 @@ +/*! + * @section LICENSE + * $license$ + * + * @filename $filename$ + * @date 2014/08/26 + * @id $id$ + * @version 1.4 + * + * @brief + * The core code of BMP280 device driver + * + * @detail + * This file implements the core code of BMP280 device driver, + * which includes hardware related functions, input device register, + * device attribute files, etc. + * This file calls some functions defined in BMP280.c and could be + * called by bmp280_i2c.c and bmp280_spi.c separately. + * REVISION: V1.4 + * HISTORY: V1.3.5 --- Driver code history + * V1.4 --- API Update to 2.0 +*/ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include "bmp280_core.h" + +/*! @defgroup bmp280_core_src + * @brief The core code of BMP280 device driver + @{*/ +/*! define sensor chip id [BMP280 = 0x56 or 0x57],[... = ...] */ +#define BMP_SENSOR_CHIP_ID 0x56 +/*! define sensor chip id [BMP280 = 0x58 */ +#define BMP_SENSOR_CHIP_ID_C 0x58 +/*! define max check times for chip id */ +#define CHECK_CHIP_ID_TIME_MAX 5 +/*! define sensor i2c address */ +#define BMP_I2C_ADDRESS BMP280_I2C_ADDRESS1 +/*! define minimum pressure value by input event */ +#define ABS_MIN_PRESSURE 30000 +/*! define maximum pressure value by input event */ +#define ABS_MAX_PRESSURE 110000 +/*! define default delay time used by input event [unit:ms] */ +#define BMP_DELAY_DEFAULT 200 +/*! define maximum temperature oversampling */ +#define BMP_OVERSAMPLING_T_MAX BMP_VAL_NAME(OVERSAMPLING_16X) +/*! define maximum pressure oversampling */ +#define BMP_OVERSAMPLING_P_MAX BMP_VAL_NAME(OVERSAMPLING_16X) +/*! define defalut filter coefficient */ +#define BMP_FILTER_DEFAULT BMP_VAL_NAME(FILTERCOEFF_8) +/*! define maximum filter coefficient */ +#define BMP_FILTER_MAX BMP_VAL_NAME(FILTERCOEFF_16) +/*! define default work mode */ +#define BMP_WORKMODE_DEFAULT BMP_VAL_NAME(STANDARDRESOLUTION_MODE) +/*! define default standby duration [unit:ms] */ +#define BMP_STANDBYDUR_DEFAULT 1 +/*! define i2c interface disable switch */ +#define BMP280_I2C_DISABLE_SWITCH 0x87 +/*! no action to selftest */ +#define BMP_SELFTEST_NO_ACTION -1 +/*! selftest failed */ +#define BMP_SELFTEST_FAILED 0 +/*! selftest success */ +#define BMP_SELFTEST_SUCCESS 1 + +/*! + * @brief Each client has this additional data, this particular + * data structure is defined for bmp280 client +*/ +struct bmp_client_data { + /*!data bus for hardware communication */ + struct bmp_data_bus data_bus; + /*!device information used by sensor API */ + struct bmp280_t device; + /*!device register to kernel device model */ + struct device *dev; + /*!mutex lock variable */ + struct mutex lock; + + /*!temperature oversampling variable */ + uint8_t oversampling_t; + /*!pressure oversampling variable */ + uint8_t oversampling_p; + /*!indicate operation mode */ + uint8_t op_mode; + /*!indicate filter coefficient */ + uint8_t filter; + /*!indicate standby duration */ + uint32_t standbydur; + /*!indicate work mode */ + uint8_t workmode; + //add by liangdi + struct sensors_classdev cdev; + //add end +#ifdef CONFIG_HAS_EARLYSUSPEND + /*!early suspend variable */ + struct early_suspend early_suspend; +#endif + /*!indicate input device; register to input core in kernel */ + struct input_dev *input; + /*!register to work queue */ + struct delayed_work work; + /*!delay time used by input event */ + uint32_t delay; + /*!enable/disable sensor output */ + uint32_t enable; + /*! indicate selftest status + * -1: no action + * 0: failed + * 1: success + */ + int8_t selftest; +}; + +//add by liangdi +static struct sensors_classdev sensors_cdev = { + .name = "bmp280-pressure", + .vendor = "Bosch", + .version = 1, + .handle = SENSORS_PRESSURE_HANDLE, + .type = SENSOR_TYPE_PRESSURE, + .max_range = "1100.0", + .resolution = "0.01", + .sensor_power = "0.67", + .min_delay = 20000, /* microsecond */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, /* millisecond */ + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; +//add end + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void bmp_early_suspend(struct early_suspend *h); +static void bmp_late_resume(struct early_suspend *h); +#endif + +/*! + * @brief list all the standby duration + * that could be set[unit:ms] +*/ +static const uint32_t standbydur_list[] = { + 1, 63, 125, 250, 500, 1000, 2000, 4000}; +/*! + * @brief list all the sensor operation modes +*/ +static const uint8_t op_mode_list[] = { + BMP_VAL_NAME(SLEEP_MODE), + BMP_VAL_NAME(FORCED_MODE), + BMP_VAL_NAME(NORMAL_MODE) +}; +/*! + * @brief list all the sensor work modes +*/ +static const uint8_t workmode_list[] = { + BMP_VAL_NAME(ULTRALOWPOWER_MODE), + BMP_VAL_NAME(LOWPOWER_MODE), + BMP_VAL_NAME(STANDARDRESOLUTION_MODE), + BMP_VAL_NAME(HIGHRESOLUTION_MODE), + BMP_VAL_NAME(ULTRAHIGHRESOLUTION_MODE) +}; + +/*! + * @brief implement delay function + * + * @param msec millisecond numbers + * + * @return no return value +*/ +static void bmp_delay(uint16_t msec) +{ + mdelay(msec); +} + +/*! + * @brief check bmp sensor's chip id + * + * @param data_bus the pointer of data bus + * + * @return zero success, non-zero failed + * @retval zero success + * @retval -EIO communication error + * @retval -ENODEV chip id dismatch +*/ +static int bmp_check_chip_id(struct bmp_data_bus *data_bus) +{ + int err = 0; + uint8_t chip_id = 0; + uint8_t read_count = 0; + + while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { + err = data_bus->bops->bus_read(BMP_I2C_ADDRESS, \ + BMP_REG_NAME(CHIPID_REG), &chip_id, 1); + if (err < 0) { + err = -EIO; + pr_err("bus read failed\n"); + return err; + } + + if ((BMP_SENSOR_CHIP_ID == (chip_id&0xFE)) + || (BMP_SENSOR_CHIP_ID_C == (chip_id&0xFF))) { + pr_info("read %s chip id successfully", BMP_NAME); + return 0; + } + mdelay(1); + } + + pr_err("read %s chip id failed, read value = %d\n", \ + BMP_NAME, chip_id); + return -ENODEV; +} + +/*! + * @brief get compersated temperature value + * + * @param data the pointer of bmp client data + * @param temperature the pointer of temperature value + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_get_temperature(struct bmp_client_data *data, + int32_t *temperature) +{ + int32_t utemperature; + int err = 0; + + err = BMP_CALL_API(read_ut)(&utemperature); + if (err) + return err; + + *temperature = BMP_CALL_API(compensate_T_int32)(utemperature); + return err; +} + +/*! + * @brief get compersated pressure value + * + * @param data the pointer of bmp client data + * @param pressure the pointer of pressure value + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_get_pressure(struct bmp_client_data *data, uint32_t *pressure) +{ + int32_t temperature; + int32_t upressure; + int err = 0; + + /* + *get current temperature to compersate pressure value + *via variable t_fine, which is defined in sensor function API + */ + err = bmp_get_temperature(data, &temperature); + if (err) + return err; + + err = BMP_CALL_API(read_up)(&upressure); + if (err) + return err; + + *pressure = (BMP_CALL_API(compensate_P_int64)(upressure))>>8; + return err; +} + +/*! + * @brief get temperature oversampling + * + * @param data the pointer of bmp client data + * + * @return temperature oversampling value + * @retval 0 oversampling skipped + * @retval 1 oversampling1X + * @retval 2 oversampling2X + * @retval 3 oversampling4X + * @retval 4 oversampling8X + * @retval 5 oversampling16X +*/ +static uint32_t bmp_get_oversampling_t(struct bmp_client_data *data) +{ + int err = 0; + + err = BMP_CALL_API(get_osrs_t)(&data->oversampling_t); + if (err) + return err; + + return data->oversampling_t; +} + +/*! + * @brief set temperature oversampling + * + * @param data the pointer of bmp client data + * @param oversampling temperature oversampling value need to set + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_set_oversampling_t(struct bmp_client_data *data, + uint8_t oversampling) +{ + int err = 0; + + if (oversampling > BMP_OVERSAMPLING_T_MAX) + oversampling = BMP_OVERSAMPLING_T_MAX; + + err = BMP_CALL_API(set_osrs_t)(oversampling); + if (err) + return err; + + data->oversampling_t = oversampling; + return err; +} + +/*! + * @brief get pressure oversampling + * + * @param data the pointer of bmp client data + * + * @return pressure oversampling value + * @retval 0 oversampling skipped + * @retval 1 oversampling1X + * @retval 2 oversampling2X + * @retval 3 oversampling4X + * @retval 4 oversampling8X + * @retval 5 oversampling16X +*/ +static uint32_t bmp_get_oversampling_p(struct bmp_client_data *data) +{ + int err = 0; + + err = BMP_CALL_API(get_osrs_p)(&data->oversampling_p); + if (err) + return err; + + return data->oversampling_p; +} + +/*! + * @brief set pressure oversampling + * + * @param data the pointer of bmp client data + * @param oversampling pressure oversampling value needed to set + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_set_oversampling_p(struct bmp_client_data *data, + uint8_t oversampling) +{ + int err = 0; + + if (oversampling > BMP_OVERSAMPLING_P_MAX) + oversampling = BMP_OVERSAMPLING_P_MAX; + + err = BMP_CALL_API(set_osrs_p)(oversampling); + if (err) + return err; + + data->oversampling_p = oversampling; + return err; +} + +/*! + * @brief get operation mode + * + * @param data the pointer of bmp client data + * + * @return operation mode + * @retval 0 SLEEP MODE + * @retval 1 FORCED MODE + * @retval 3 NORMAL MODE +*/ +static uint32_t bmp_get_op_mode(struct bmp_client_data *data) +{ + int err = 0; + + err = BMP_CALL_API(get_mode)(&data->op_mode); + if (err) + return err; + + if (data->op_mode == 0x01 || data->op_mode == 0x02) + data->op_mode = BMP_VAL_NAME(FORCED_MODE); + + return data->op_mode; +} + +/*! + * @brief set operation mode + * + * @param data the pointer of bmp client data + * @param op_mode operation mode need to set + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_set_op_mode(struct bmp_client_data *data, uint8_t op_mode) +{ + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(op_mode_list); i++) { + if (op_mode_list[i] == op_mode) + break; + } + + if (ARRAY_SIZE(op_mode_list) <= i) + return -1; + + err = BMP_CALL_API(set_mode)(op_mode); + if (err) + return err; + + data->op_mode = op_mode; + return err; +} + +/*! + * @brief get filter coefficient + * + * @param data the pointer of bmp client data + * + * @return filter coefficient value + * @retval 0 filter off + * @retval 1 filter 2 + * @retval 2 filter 4 + * @retval 3 filter 8 + * @retval 4 filter 16 +*/ +static uint32_t bmp_get_filter(struct bmp_client_data *data) +{ + int err = 0; + + err = BMP_CALL_API(get_filter)(&data->filter); + if (err) + return err; + + return data->filter; +} + +/*! + * @brief set filter coefficient + * + * @param data the pointer of bmp client data + * @param filter filter coefficient need to set + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_set_filter(struct bmp_client_data *data, uint8_t filter) +{ + int err = 0; + + if (filter > BMP_FILTER_MAX) + filter = BMP_FILTER_MAX; + + err = BMP_CALL_API(set_filter)(filter); + if (err) + return err; + + data->filter = filter; + return err; +} + +/*! + * @brief get standby duration + * + * @param data the pointer of bmp client data + * + * @return standby duration value + * @retval 1 0.5ms + * @retval 63 62.5ms + * @retval 125 125ms + * @retval 250 250ms + * @retval 500 500ms + * @retval 1000 1000ms + * @retval 2000 2000ms + * @retval 4000 4000ms +*/ +static uint32_t bmp_get_standbydur(struct bmp_client_data *data) +{ + int err = 0; + uint8_t standbydur; + + err = BMP_CALL_API(get_standbydur)(&standbydur); + if (err) + return err; + + data->standbydur = standbydur_list[standbydur]; + return data->standbydur; +} + +/*! + * @brief set standby duration + * + * @param data the pointer of bmp client data + * @param standbydur standby duration need to set + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_set_standbydur(struct bmp_client_data *data, uint32_t standbydur) +{ + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(standbydur_list); i++) { + if (standbydur_list[i] == standbydur) + break; + } + + if (ARRAY_SIZE(standbydur_list) <= i) + return -1; + + err = BMP_CALL_API(set_standbydur)(i); + if (err) + return err; + + data->standbydur = standbydur; + return err; +} + +/*! + * @brief get work mode + * + * @param data the pointer of bmp client data + * + * @return work mode + * @retval 0 ULTRLOWPOWER MODE + * @retval 1 LOWPOWER MODE + * @retval 2 STANDARDSOLUTION MODE + * @retval 3 HIGHRESOLUTION MODE + * @retval 4 ULTRAHIGHRESOLUTION MODE +*/ +static unsigned char bmp_get_workmode(struct bmp_client_data *data) +{ + return data->workmode; +} + +/*! + * @brief set work mode, which is defined by software, not hardware. + * This setting will impact oversampling value of sensor. + * + * @param data the pointer of bmp client data + * @param workmode work mode need to set + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_set_workmode(struct bmp_client_data *data, uint8_t workmode) +{ + int err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(workmode_list); i++) { + if (workmode_list[i] == workmode) + break; + } + + if (ARRAY_SIZE(workmode_list) <= i) + return -1; + + err = BMP_CALL_API(set_workmode)(workmode); + if (err) + return err; + else + data->workmode = workmode; + + bmp_get_oversampling_t(data); + bmp_get_oversampling_p(data); + + return err; +} + +/*! + * @brief verify i2c disable switch status + * + * @param data the pointer of bmp client data + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp280_verify_i2c_disable_switch(struct bmp_client_data *data) +{ + int err = 0; + uint8_t reg_val = 0xFF; + + err = BMP_CALL_API(read_register) + (BMP280_I2C_DISABLE_SWITCH, ®_val, 1); + if (err < 0) { + err = -EIO; + pr_err("bus read failed\n"); + return err; + } + + if (reg_val == 0x00) { + pr_info("bmp280 i2c interface is available\n"); + return 0; + } + + pr_err("verification of i2c interface is failure\n"); + return -1; +} + +/*! + * @brief verify calibration parameters + * + * @param data the pointer of bmp client data + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp280_verify_calib_param(struct bmp_client_data *data) +{ + struct bmp280_calibration_param_t *cali = &(data->device.cal_param); + + /* verify that not all calibration parameters are 0 */ + if (cali->dig_T1 == 0 && cali->dig_T2 == 0 && cali->dig_T3 == 0 + && cali->dig_P1 == 0 && cali->dig_P2 == 0 + && cali->dig_P3 == 0 && cali->dig_P4 == 0 + && cali->dig_P5 == 0 && cali->dig_P6 == 0 + && cali->dig_P7 == 0 && cali->dig_P8 == 0 + && cali->dig_P9 == 0) { + pr_err("all calibration parameters are zero\n"); + return -1; + } + + /* verify whether all the calibration parameters are within range */ + if (cali->dig_T1 < 19000 || cali->dig_T1 > 35000) + return -1; + else if (cali->dig_T2 < 22000 || cali->dig_T2 > 30000) + return -1; + else if (cali->dig_T3 < -3000 || cali->dig_T3 > -1000) + return -1; + else if (cali->dig_P1 < 30000 || cali->dig_P1 > 42000) + return -1; + else if (cali->dig_P2 < -12970 || cali->dig_P2 > -8000) + return -1; + else if (cali->dig_P3 < -5000 || cali->dig_P3 > 8000) + return -1; + else if (cali->dig_P4 < -10000 || cali->dig_P4 > 18000) + return -1; + else if (cali->dig_P5 < -500 || cali->dig_P5 > 1100) + return -1; + else if (cali->dig_P6 < -1000 || cali->dig_P6 > 1000) + return -1; + else if (cali->dig_P7 < -32768 || cali->dig_P7 > 32767) + return -1; + else if (cali->dig_P8 < -30000 || cali->dig_P8 > 10000) + return -1; + else if (cali->dig_P9 < -10000 || cali->dig_P9 > 30000) + return -1; + + pr_info("calibration parameters are OK\n"); + return 0; +} + +/*! + * @brief verify compensated temperature and pressure value + * + * @param data the pointer of bmp client data + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp280_verify_pt(struct bmp_client_data *data) +{ + uint8_t wait_time = 0; + int32_t temperature = 0; + uint32_t pressure; + + bmp_set_workmode(data, BMP_VAL_NAME(ULTRALOWPOWER_MODE)); + bmp_set_op_mode(data, BMP_VAL_NAME(FORCED_MODE)); + BMP_CALL_API(compute_wait_time)(&wait_time); + bmp_delay(wait_time); + bmp_get_temperature(data, &temperature); + if (temperature <= 0 || temperature >= 40*100) { + pr_err("temperature value is out of range:%d*0.01degree\n", + temperature); + return -1; + } + bmp_get_pressure(data, &pressure); + if (pressure <= 900*100 || pressure >= 1100*100) { + pr_err("pressure value is out of range:%d Pa\n", pressure); + return -1; + } + + pr_info("bmp280 temperature and pressure values are OK\n"); + return 0; +} + +/*! + * @brief do selftest + * + * @param data the pointer of bmp client data + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_do_selftest(struct bmp_client_data *data) +{ + int err = 0; + + if (data == NULL) + return -EINVAL; + + err = bmp280_verify_i2c_disable_switch(data); + if (err) { + data->selftest = 0; + return BMP_SELFTEST_FAILED; + } + + err = bmp280_verify_calib_param(data); + if (err) { + data->selftest = 0; + return BMP_SELFTEST_FAILED; + } + + err = bmp280_verify_pt(data); + if (err) { + data->selftest = 0; + return BMP_SELFTEST_FAILED; + } + + /* selftest is OK */ + data->selftest = 1; + return BMP_SELFTEST_SUCCESS; +} + +//add by liangdi +static ssize_t bmp280_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_msec) +{ + struct bmp_client_data *data = container_of(sensors_cdev, + struct bmp_client_data, cdev); + mutex_lock(&data->lock); + data->delay = delay_msec; + mutex_unlock(&data->lock); + pr_err("bmp280_poll_delay_set delay=%d\n",data->delay); + return 0; +} +//add end + +/* sysfs callbacks */ +/*! + * @brief get delay value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of delay buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", data->delay); +} + +/*! + * @brief set delay value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of delay buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_delay(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long delay; + int status = kstrtoul(buf, 10, &delay); + if (status == 0) { + mutex_lock(&data->lock); + data->delay = delay; + mutex_unlock(&data->lock); + return count; + } + return status; +} + +/*! + * @brief get compersated temperature value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of temperature buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_temperature(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int32_t temperature; + int status; + struct bmp_client_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->lock); + status = bmp_get_temperature(data, &temperature); + mutex_unlock(&data->lock); + if (status == 0) + return sprintf(buf, "%d\n", temperature); + + return status; +} + +/*! + * @brief set compersated pressure value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of pressure buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_pressure(struct device *dev, + struct device_attribute *attr, char *buf) +{ + uint32_t pressure; + int status; + struct bmp_client_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->lock); + status = bmp_get_pressure(data, &pressure); + mutex_unlock(&data->lock); + if (status == 0) + return sprintf(buf, "%d\n", pressure); + + return status; +} + +/*! + * @brief get temperature oversampling value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of temperature oversampling buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_oversampling_t(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bmp_get_oversampling_t(data)); +} + +/*! + * @brief set temperature oversampling value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of temperature oversampling buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_oversampling_t(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long oversampling; + int status = kstrtoul(buf, 10, &oversampling); + if (status == 0) { + mutex_lock(&data->lock); + bmp_set_oversampling_t(data, oversampling); + mutex_unlock(&data->lock); + return count; + } + return status; +} + +/*! + * @brief get pressure oversampling value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of pressure oversampling buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_oversampling_p(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bmp_get_oversampling_p(data)); +} + +/*! + * @brief set pressure oversampling value via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of pressure oversampling buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_oversampling_p(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long oversampling; + int status = kstrtoul(buf, 10, &oversampling); + if (status == 0) { + mutex_lock(&data->lock); + bmp_set_oversampling_p(data, oversampling); + mutex_unlock(&data->lock); + return count; + } + return status; +} + +/*! + * @brief get operation mode via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of operation mode buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_op_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bmp_get_op_mode(data)); +} + +/*! + * @brief set operation mode via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of operation mode buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_op_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long op_mode; + int status = kstrtoul(buf, 10, &op_mode); + if (status == 0) { + mutex_lock(&data->lock); + bmp_set_op_mode(data, op_mode); + mutex_unlock(&data->lock); + return count; + } + return status; +} + +/*! + * @brief get filter coefficient via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of filter coefficient buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_filter(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bmp_get_filter(data)); +} + +/*! + * @brief set filter coefficient via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of filter coefficient buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_filter(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long filter; + int status = kstrtoul(buf, 10, &filter); + if (status == 0) { + mutex_lock(&data->lock); + bmp_set_filter(data, filter); + mutex_unlock(&data->lock); + return count; + } + return status; +} + +/*! + * @brief get standby duration via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of standby duration buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_standbydur(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bmp_get_standbydur(data)); +} + +/*! + * @brief set standby duration via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of standby duration buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_standbydur(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long standbydur; + int status = kstrtoul(buf, 10, &standbydur); + if (status == 0) { + mutex_lock(&data->lock); + bmp_set_standbydur(data, standbydur); + mutex_unlock(&data->lock); + return count; + } + return status; +} + +/*! + * @brief get work mode via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of work mode buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_workmode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bmp_get_workmode(data)); +} + +/*! + * @brief set work mode via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of work mode buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_workmode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long workmode; + int status = kstrtoul(buf, 10, &workmode); + if (status == 0) { + mutex_lock(&data->lock); + bmp_set_workmode(data, workmode); + mutex_unlock(&data->lock); + return count; + } + return status; +} + +//add by liangdi +static ssize_t bmp280_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmp_client_data *data = container_of(sensors_cdev, + struct bmp_client_data, cdev); + struct device *dev = data->dev; + + enable = enable ? 1 : 0; + mutex_lock(&data->lock); + if (data->enable != enable) { + if (enable) { + #ifdef CONFIG_PM + bmp_enable(dev); + #endif + bmp_set_op_mode(data, \ + BMP_VAL_NAME(NORMAL_MODE)); + schedule_delayed_work(&data->work, + msecs_to_jiffies(data->delay)); + } else{ + cancel_delayed_work_sync(&data->work); + bmp_set_op_mode(data, \ + BMP_VAL_NAME(SLEEP_MODE)); + #ifdef CONFIG_PM + bmp_disable(dev); + #endif + } + data->enable = enable; + } + mutex_unlock(&data->lock); + pr_err("bmp280_enable_set en_state=%d\n",data->enable); + + return 0; +} + +//add end + +/*! + * @brief get sensor work state via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of enable/disable value buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", data->enable); +} + +/*! + * @brief enable/disable sensor function via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of enable/disable buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long enable; + int status = kstrtoul(buf, 10, &enable); + if (status == 0) { + enable = enable ? 1 : 0; + mutex_lock(&data->lock); + if (data->enable != enable) { + if (enable) { + #ifdef CONFIG_PM + bmp_enable(dev); + #endif + bmp_set_op_mode(data, \ + BMP_VAL_NAME(NORMAL_MODE)); + schedule_delayed_work(&data->work, + msecs_to_jiffies(data->delay)); + } else{ + cancel_delayed_work_sync(&data->work); + bmp_set_op_mode(data, \ + BMP_VAL_NAME(SLEEP_MODE)); + #ifdef CONFIG_PM + bmp_disable(dev); + #endif + } + data->enable = enable; + } + mutex_unlock(&data->lock); + return count; + } + return status; +} + +/*! + * @brief get selftest status via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of selftest buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", data->selftest); +} + +/*! + * @brief do selftest via sysfs node + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of selftest buffer + * @param count buffer size + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t store_selftest(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + unsigned long action; + int status = kstrtoul(buf, 10, &action); + if (0 != status) + return status; + + /* 1 means do selftest */ + if (1 != action) + return -EINVAL; + + mutex_lock(&data->lock); + status = bmp_do_selftest(data); + mutex_unlock(&data->lock); + + if (BMP_SELFTEST_SUCCESS == status) + return count; + else + return status; +} + +#ifdef DEBUG_BMP280 +/*! + * @brief dump significant registers value from hardware + * and copy to use space via sysfs node. This node only for debug, + * which could dump registers from 0xF3 to 0xFC. + * + * @param dev the pointer of device + * @param attr the pointer of device attribute file + * @param buf the pointer of registers value buffer + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static ssize_t show_dump_reg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + #define REG_CALI_NUM (0xA1 - 0x88 + 1) + #define REG_CTRL_NUM (0xFC - 0xF3 + 1) + struct bmp_client_data *data = dev_get_drvdata(dev); + char regsbuf[REG_CALI_NUM + REG_CTRL_NUM]; + char strbuf[REG_CALI_NUM + REG_CTRL_NUM + 256] = {0}; + int err = 0, i; + + sprintf(strbuf + strlen(strbuf), \ + "-----calib regs[0x88 ~ 0xA1]-----\n"); + err = data->data_bus.bops->bus_read(BMP_I2C_ADDRESS, \ + 0x88, regsbuf, REG_CALI_NUM); + if (err) + return err; + + for (i = 0; i < REG_CALI_NUM; i++) + sprintf(strbuf + strlen(strbuf), "%02X%c", \ + regsbuf[i], ((i+1)%0x10 == 0) ? '\n' : ' '); + + sprintf(strbuf + strlen(strbuf), \ + "\n-----ctrl regs[0xF3 ~ 0xFC]-----\n"); + err = data->data_bus.bops->bus_read(BMP_I2C_ADDRESS, \ + 0xF3, regsbuf, REG_CTRL_NUM); + if (err) + return err; + + for (i = 0; i < REG_CTRL_NUM; i++) + sprintf(strbuf + strlen(strbuf), "%02X ", regsbuf[i]); + + return snprintf(buf, 4096, "%s\n", strbuf); +} +#endif/*DEBUG_BMP280*/ + +static DEVICE_ATTR(delay, S_IWUSR | S_IRUGO, + show_delay, store_delay); +static DEVICE_ATTR(temperature, S_IRUGO, + show_temperature, NULL); +static DEVICE_ATTR(pressure, S_IRUGO, + show_pressure, NULL); +static DEVICE_ATTR(oversampling_t, S_IWUSR | S_IRUGO, + show_oversampling_t, store_oversampling_t); +static DEVICE_ATTR(oversampling_p, S_IWUSR | S_IRUGO, + show_oversampling_p, store_oversampling_p); +static DEVICE_ATTR(op_mode, S_IWUSR | S_IRUGO, + show_op_mode, store_op_mode); +static DEVICE_ATTR(filter, S_IWUSR | S_IRUGO, + show_filter, store_filter); +static DEVICE_ATTR(standbydur, S_IWUSR | S_IRUGO, + show_standbydur, store_standbydur); +static DEVICE_ATTR(workmode, S_IWUSR | S_IRUGO, + show_workmode, store_workmode); +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, + show_enable, store_enable); +static DEVICE_ATTR(selftest, S_IWUSR | S_IRUGO, + show_selftest, store_selftest); +#ifdef DEBUG_BMP280 +static DEVICE_ATTR(dump_reg, S_IRUGO, + show_dump_reg, NULL); +#endif + +/*! + * @brief device attribute files +*/ +static struct attribute *bmp_attributes[] = { + /**< delay attribute */ + &dev_attr_delay.attr, + /**< compersated temperature attribute */ + &dev_attr_temperature.attr, + /**< compersated pressure attribute */ + &dev_attr_pressure.attr, + /**< temperature oversampling attribute */ + &dev_attr_oversampling_t.attr, + /**< pressure oversampling attribute */ + &dev_attr_oversampling_p.attr, + /**< operature mode attribute */ + &dev_attr_op_mode.attr, + /**< filter coefficient attribute */ + &dev_attr_filter.attr, + /**< standby duration attribute */ + &dev_attr_standbydur.attr, + /**< work mode attribute */ + &dev_attr_workmode.attr, + /**< enable/disable attribute */ + &dev_attr_enable.attr, + /**< selftest attribute */ + &dev_attr_selftest.attr, + /**< dump registers attribute */ +#ifdef DEBUG_BMP280 + &dev_attr_dump_reg.attr, +#endif + /**< flag to indicate the end */ + NULL +}; + +/*! + * @brief attribute files group +*/ +static const struct attribute_group bmp_attr_group = { + /**< bmp attributes */ + .attrs = bmp_attributes, +}; + +/*! + * @brief workqueue function to report input event + * + * @param work the pointer of workqueue + * + * @return no return value +*/ +static void bmp_work_func(struct work_struct *work) +{ + struct bmp_client_data *client_data = + container_of((struct delayed_work *)work, + struct bmp_client_data, work); + uint32_t delay = msecs_to_jiffies(client_data->delay); + uint32_t j1 = jiffies; + uint32_t pressure; + int status; + + mutex_lock(&client_data->lock); + status = bmp_get_pressure(client_data, &pressure); + mutex_unlock(&client_data->lock); + if (status == 0) { + //pr_err("bmp280 pressure value :%d Pa\n", pressure); + input_event(client_data->input, EV_MSC, MSC_RAW, pressure); + input_sync(client_data->input); + } + + schedule_delayed_work(&client_data->work, delay-(jiffies-j1)); +} + +/*! + * @brief initialize input device + * + * @param data the pointer of bmp client data + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_input_init(struct bmp_client_data *data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + dev->name = BMP_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_MSC, MSC_RAW); + input_set_drvdata(dev, data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + data->input = dev; + + return 0; +} + +/*! + * @brief delete input device + * + * @param data the pointer of bmp client data + * + * @return no return value +*/ +static void bmp_input_delete(struct bmp_client_data *data) +{ + struct input_dev *dev = data->input; + + input_unregister_device(dev); + input_free_device(dev); +} + +/*! + * @brief initialize bmp client + * + * @param data the pointer of bmp client data + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_init_client(struct bmp_client_data *data) +{ + int status; + + data->device.bus_read = data->data_bus.bops->bus_read; + data->device.bus_write = data->data_bus.bops->bus_write; + data->device.delay_msec = bmp_delay; + + status = BMP_CALL_API(init)(&data->device); + if (status) + return status; + + mutex_init(&data->lock); + + data->delay = BMP_DELAY_DEFAULT; + data->enable = 0; + data->selftest = BMP_SELFTEST_NO_ACTION;/* no action to selftest */ + + status = bmp_set_op_mode(data, BMP_VAL_NAME(SLEEP_MODE)); + if (status) + return status; + + status = bmp_set_filter(data, BMP_FILTER_DEFAULT); + if (status) + return status; + + status = bmp_set_standbydur(data, BMP_STANDBYDUR_DEFAULT); + if (status) + return status; + + status = bmp_set_workmode(data, BMP_WORKMODE_DEFAULT); + return status; +} + +/*! + * @brief probe bmp sensor + * + * @param dev the pointer of device + * @param data_bus the pointer of data bus communication + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus) +{ + struct bmp_client_data *data; + int err = 0; + + + if (!dev || !data_bus) { + err = -EINVAL; + goto exit; + } + + /* check chip id */ + err = bmp_check_chip_id(data_bus); + if (err) { + pr_err("Bosch Sensortec Device not found, chip id mismatch!\n"); + goto exit; + } else { + pr_warn("Bosch Sensortec Device %s detected.\n", BMP_NAME); + } + + data = kzalloc(sizeof(struct bmp_client_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + dev_set_drvdata(dev, data); + data->data_bus = *data_bus; + data->dev = dev; + + /* Initialize the BMP chip */ + err = bmp_init_client(data); + if (err != 0) + goto exit_free; + + /* Initialize the BMP input device */ + err = bmp_input_init(data); + if (err != 0) + goto exit_free; + + /* Register sysfs hooks */ + err = sysfs_create_group(&data->input->dev.kobj, &bmp_attr_group); + if (err) + goto error_sysfs; + + //add by liangdi + data->cdev = sensors_cdev; + data->cdev.sensors_enable = bmp280_enable_set; + data->cdev.sensors_poll_delay = bmp280_poll_delay_set; + err = sensors_classdev_register(&data->input->dev, &data->cdev); + if (err) { + pr_err("class device create failed: %d\n", err); + goto error_class_sysfs; + } + //add end + + /* workqueue init */ + INIT_DELAYED_WORK(&data->work, bmp_work_func); + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + data->early_suspend.suspend = bmp_early_suspend; + data->early_suspend.resume = bmp_late_resume; + register_early_suspend(&data->early_suspend); +#endif + + pr_info("Succesfully probe sensor %s\n", BMP_NAME); + return 0; + +error_class_sysfs: + sysfs_remove_group(&data->input->dev.kobj, &bmp_attr_group); + +error_sysfs: + bmp_input_delete(data); +exit_free: + kfree(data); +exit: + return err; +} +EXPORT_SYMBOL(bmp_probe); + +/*! + * @brief remove bmp client + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int bmp_remove(struct device *dev) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif + sysfs_remove_group(&data->input->dev.kobj, &bmp_attr_group); + kfree(data); + + return 0; +} +EXPORT_SYMBOL(bmp_remove); + +#ifdef CONFIG_PM +/*! + * @brief disable power + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int bmp_disable(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL(bmp_disable); + +/*! + * @brief enable power + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int bmp_enable(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL(bmp_enable); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +/*! + * @brief early suspend function of bmp sensor + * + * @param h the pointer of early suspend + * + * @return no return value +*/ +static void bmp_early_suspend(struct early_suspend *h) +{ + struct bmp_client_data *data = + container_of(h, struct bmp_client_data, early_suspend); + + mutex_lock(&data->lock); + if (data->enable) { + cancel_delayed_work_sync(&data->work); + bmp_set_op_mode(data, BMP_VAL_NAME(SLEEP_MODE)); + #ifdef CONFIG_PM + (void) bmp_disable(data->dev); + #endif + } + mutex_unlock(&data->lock); +} + +/*! + * @brief late resume function of bmp sensor + * + * @param h the pointer of early suspend + * + * @return no return value +*/ +static void bmp_late_resume(struct early_suspend *h) +{ + struct bmp_client_data *data = + container_of(h, struct bmp_client_data, early_suspend); + + mutex_lock(&data->lock); + if (data->enable) { + #ifdef CONFIG_PM + (void) bmp_enable(data->dev); + #endif + bmp_set_op_mode(data, BMP_VAL_NAME(NORMAL_MODE)); + schedule_delayed_work(&data->work, + msecs_to_jiffies(data->delay)); + } + mutex_unlock(&data->lock); +} +#endif + +MODULE_AUTHOR("contact@bosch-sensortec.com"); +MODULE_DESCRIPTION("BMP280 PRESSURE SENSOR DRIVER"); +MODULE_LICENSE("GPL v2"); +/*@}*/ diff --git a/drivers/input/misc/bmp280_core.h b/drivers/input/misc/bmp280_core.h new file mode 100755 index 00000000000..ee25a7fb408 --- /dev/null +++ b/drivers/input/misc/bmp280_core.h @@ -0,0 +1,67 @@ +/*! + * @section LICENSE + * $license$ + * + * @filename $filename$ + * @date $date$ + * @id $id$ + * + * @brief + * The head file of BMP280 device driver core code +*/ +#ifndef _BMP280_CORE_H +#define _BMP280_CORE_H + +#include "bmp280.h" +//#include "bs_log.h" + +/*! @defgroup bmp280_core_inc + * @brief The head file of BMP280 device driver core code + @{*/ +/*! define BMP device name */ +#define BMP_NAME "bmp280" + +/*! define BMP register name according to API */ +#define BMP_REG_NAME(name) BMP280_##name +/*! define BMP value name according to API */ +#define BMP_VAL_NAME(name) BMP280_##name +/*! define BMP hardware-related function according to API */ +#define BMP_CALL_API(name) bmp280_##name +/*! only for debug */ +/*#define DEBUG_BMP280*/ + +/*! + * @brief bus communication operation +*/ +struct bmp_bus_ops { + /*!write pointer */ + BMP280_WR_FUNC_PTR; + /*!read pointer */ + BMP280_RD_FUNC_PTR; +}; + +/*! + * @brief bus data client +*/ +struct bmp_data_bus { + /*!bus communication operation */ + const struct bmp_bus_ops *bops; + /*!bmp client */ + //void *client; + struct i2c_client *client; + //add by liangdi 20190817 + struct regulator *vdd; + struct regulator *vio; + bool power_enabled; + //add end +}; + +int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus); +int bmp_remove(struct device *dev); +#ifdef CONFIG_PM +int bmp_enable(struct device *dev); +int bmp_disable(struct device *dev); +#endif + +#endif/*_BMP280_CORE_H*/ +/*@}*/ diff --git a/drivers/input/misc/bmp280_i2c.c b/drivers/input/misc/bmp280_i2c.c new file mode 100755 index 00000000000..196c45a8265 --- /dev/null +++ b/drivers/input/misc/bmp280_i2c.c @@ -0,0 +1,477 @@ +/*! + * @section LICENSE + * $license$ + * + * @filename $filename$ + * @date $date$ + * @id $id$ + * + * @brief + * This file implements module function, which adds + * the driver to I2C core. +*/ + +#include +#include +#include +#include "bmp280_core.h" +#include + +static struct i2c_client *bmp_i2c_client; + +//add by liangdi 20190817 +/*BMP280 power supply VDD 1.62V-3.6V VIO 1.2-3.6V */ +#define BMP280_VDD_MIN_UV 2000000 +#define BMP280_VDD_MAX_UV 3400000 +#define BMP280_VIO_MIN_UV 1500000 +#define BMP280_VIO_MAX_UV 3400000 +//add end + +/*! @defgroup bmp280_i2c_src + * @brief bmp280 i2c driver module + @{*/ +/*! maximum retry times during i2c transfer */ +#define BMP_MAX_RETRY_I2C_XFER 10 +/*! wait time after i2c transfer error occurred */ +#define BMP_I2C_WRITE_DELAY_TIME 1 + +#ifdef BMP_USE_BASIC_I2C_FUNC +/*! + * @brief define i2c wirte function + * + * @param client the pointer of i2c client + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static s8 bmp_i2c_read(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ + int retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + for (retry = 0; retry < BMP_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + else + mdelay(BMP_I2C_WRITE_DELAY_TIME); + } + + if (BMP_MAX_RETRY_I2C_XFER <= retry) { + pr_err("I2C xfer error"); + return -EIO; + } + + return 0; +} + +/*! + * @brief define i2c wirte function + * + * @param client the pointer of i2c client + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static s8 bmp_i2c_write(struct i2c_client *client, u8 reg_addr, + u8 *data, u8 len) +{ + u8 buffer[2]; + int retry; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buffer, + }; + + while (0 != len--) { + msg.buf = buffer; + msg.buf[0] = reg_addr; + msg.buf[1] = *data; + for (retry = 0; retry < BMP_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, &msg, 1) > 0) + break; + mdelay(BMP_I2C_WRITE_DELAY_TIME); + } + if (BMP_MAX_RETRY_I2C_XFER <= retry) { + pr_err("I2C xfer error"); + return -EIO; + } + reg_addr++; + data++; + } + + return 0; +} +#endif/*BMP_USE_BASIC_I2C_FUNC*/ + +/*! + * @brief define i2c block wirte function + * + * @param dev_addr sensor i2c address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static s8 bmp_i2c_write_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + s8 err = 0; + + if (NULL == bmp_i2c_client) + return -1; + +#ifdef BMP_USE_BASIC_I2C_FUNC + err = bmp_i2c_write(bmp_i2c_client, reg_addr, data, len); +#else + err = i2c_smbus_write_i2c_block_data(bmp_i2c_client, \ + reg_addr, len, data); +#endif + if (err < 0) + return err; + + return 0; +} + +/*! + * @brief define i2c block read function + * + * @param dev_addr sensor i2c address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to read + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static s8 bmp_i2c_read_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + s8 err = 0; + + if (NULL == bmp_i2c_client) + return -1; + +#ifdef BMP_USE_BASIC_I2C_FUNC + err = bmp_i2c_read(bmp_i2c_client, reg_addr, data, len); +#else + err = i2c_smbus_read_i2c_block_data(bmp_i2c_client, \ + reg_addr, len, data); +#endif + if (err < 0) + return err; + + return 0; +} + +//add by liangdi 20190817 +static int bmp280_power_ctl(struct bmp_data_bus *data, bool on) +{ + int ret = 0; + int err = 0; + + if (!on && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + pr_err("Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + pr_err("Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = on; + pr_info("bmp280 Power off=%d. enabled=%d\n",on, data->power_enabled); + } else if (on && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + pr_err("Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_enable(data->vio); + if (ret) { + pr_err("Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + data->power_enabled = on; + pr_info("bmp280 Power on=%d. enabled=%d\n",on, data->power_enabled); + } else { + pr_info("Power on=%d. enabled=%d\n", + on, data->power_enabled); + } + + return ret; +} + +static int bmp280_power_init(struct bmp_data_bus *data) +{ + int ret; + //struct i2c_client *bmp280_client = (struct i2c_client *)data->client; + + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + pr_err("Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + BMP280_VDD_MIN_UV, + BMP280_VDD_MAX_UV); + if (ret) { + pr_err("Regulator set failed vdd ret=%d\n",ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + pr_err("Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + BMP280_VIO_MIN_UV, + BMP280_VIO_MAX_UV); + if (ret) { + pr_err("Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, BMP280_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} +/* +static int bmp280_power_deinit(struct bmp_data_bus *data) +{ + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, + 0, BMP280_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, + 0, BMP280_VIO_MAX_UV); + + regulator_put(data->vio); + + return 0; +} +*/ +//add end + + +/*! + * @brief i2c bus operation +*/ +static const struct bmp_bus_ops bmp_i2c_bus_ops = { + /**< i2c block write pointer */ + .bus_write = bmp_i2c_write_block, + /**< i2c block read pointer */ + .bus_read = bmp_i2c_read_block +}; + +/*! + * @brief BMP probe function via i2c bus + * + * @param client the pointer of i2c client + * @param id the pointer of i2c device id + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bmp_data_bus data_bus = { + .bops = &bmp_i2c_bus_ops, + .client = client + }; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_check_functionality error!"); + return -EIO; + } + + if (NULL == bmp_i2c_client) + bmp_i2c_client = client; + else{ + pr_err("This driver does not support multiple clients!\n"); + return -EINVAL; + } + + //add by liangdi 20190817 + data_bus.power_enabled = false; + bmp280_power_init(&data_bus); + bmp280_power_ctl(&data_bus, true); + msleep(100); + //add end + return bmp_probe(&client->dev, &data_bus); +} + +/*! + * @brief shutdown bmp device in i2c driver + * + * @param client the pointer of i2c client + * + * @return no return value +*/ +static void bmp_i2c_shutdown(struct i2c_client *client) +{ +#ifdef CONFIG_PM + bmp_disable(&client->dev); +#endif +} + +/*! + * @brief remove bmp i2c client + * + * @param client the pointer of i2c client + * + * @return zero + * @retval zero +*/ +static int bmp_i2c_remove(struct i2c_client *client) +{ + return bmp_remove(&client->dev); +} + +#ifdef CONFIG_PM +/*! + * @brief suspend bmp device in i2c driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int bmp_i2c_suspend(struct device *dev) +{ + return bmp_disable(dev); +} + +/*! + * @brief resume bmp device in i2c driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int bmp_i2c_resume(struct device *dev) +{ + return bmp_enable(dev); +} + +/*! + * @brief register i2c device power manager hooks +*/ +static const struct dev_pm_ops bmp_i2c_pm_ops = { + /**< device suspend */ + .suspend = bmp_i2c_suspend, + /**< device resume */ + .resume = bmp_i2c_resume +}; +#endif + +/*! + * @brief register i2c device id +*/ +static const struct i2c_device_id bmp_id[] = { + { BMP_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bmp_id); + +/*! + * @brief register i2c driver hooks +*/ +static struct i2c_driver bmp_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = BMP_NAME, +#ifdef CONFIG_PM + .pm = &bmp_i2c_pm_ops, +#endif + }, + .id_table = bmp_id, + .probe = bmp_i2c_probe, + .shutdown = bmp_i2c_shutdown, + .remove = bmp_i2c_remove +}; + +/*! + * @brief initialize bmp i2c module + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int __init bmp_i2c_init(void) +{ + return i2c_add_driver(&bmp_i2c_driver); +} + +/*! + * @brief remove bmp i2c module + * + * @return no return value +*/ +static void __exit bmp_i2c_exit(void) +{ + i2c_del_driver(&bmp_i2c_driver); +} + + +MODULE_DESCRIPTION("BMP280 I2C DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(bmp_i2c_init); +module_exit(bmp_i2c_exit); +/*@}*/ diff --git a/drivers/input/misc/bmp280_spi.c b/drivers/input/misc/bmp280_spi.c new file mode 100755 index 00000000000..aeb54e1a0ac --- /dev/null +++ b/drivers/input/misc/bmp280_spi.c @@ -0,0 +1,258 @@ +/*! + * @section LICENSE + * $license$ + * + * @filename $filename$ + * @date $date$ + * @id $id$ + * + * @brief + * This file implements module function, which adds + * the driver to SPI core. +*/ + +#include +#include +#include +#include "bmp280_core.h" +#include "bs_log.h" + +/*! @defgroup bmp280_spi_src + * @brief bmp280 spi driver module + @{*/ +/*! the maximum of transfer buffer size */ +#define BMP_MAX_BUFFER_SIZE 32 + +static struct spi_device *bmp_spi_client; + +/*! + * @brief define spi wirte function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static s8 bmp_spi_write_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + struct spi_device *client = bmp_spi_client; + u8 buffer[BMP_MAX_BUFFER_SIZE + 1]; + struct spi_transfer xfer = { + .tx_buf = buffer, + .len = len + 1, + }; + struct spi_message msg; + + if (len > BMP_MAX_BUFFER_SIZE) + return -EINVAL; + + buffer[0] = reg_addr&0x7F;/* write: MSB = 0 */ + memcpy(&buffer[1], data, len); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + return spi_sync(client, &msg); +} + +/*! + * @brief define spi read function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to read + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static s8 bmp_spi_read_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + struct spi_device *client = bmp_spi_client; + u8 reg = reg_addr | 0x80;/* read: MSB = 1 */ + struct spi_transfer xfer[2] = { + [0] = { + .tx_buf = ®, + .len = 1, + }, + [1] = { + .rx_buf = data, + .len = len, + } + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer[0], &msg); + spi_message_add_tail(&xfer[1], &msg); + return spi_sync(client, &msg); +} + +/*! + * @brief spi bus operation +*/ +static const struct bmp_bus_ops bmp_spi_bus_ops = { + /**< spi block write pointer */ + .bus_write = bmp_spi_write_block, + /**< spi block read pointer */ + .bus_read = bmp_spi_read_block +}; + +/*! + * @brief BMP probe function via spi bus + * + * @param client the pointer of spi client + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int bmp_spi_probe(struct spi_device *client) +{ + int status; + struct bmp_data_bus data_bus = { + .bops = &bmp_spi_bus_ops, + .client = client + }; + + if (NULL == bmp_spi_client) + bmp_spi_client = client; + else{ + pr_err("This driver does not support multiple clients!\n"); + return -EINVAL; + } + + client->bits_per_word = 8; + status = spi_setup(client); + if (status < 0) { + pr_err("spi_setup failed!\n"); + return status; + } + + return bmp_probe(&client->dev, &data_bus); +} + +/*! + * @brief shutdown bmp device in spi driver + * + * @param client the pointer of spi client + * + * @return no return value +*/ +static void bmp_spi_shutdown(struct spi_device *client) +{ +#ifdef CONFIG_PM + bmp_disable(&client->dev); +#endif +} + +/*! + * @brief remove bmp spi client + * + * @param client the pointer of spi client + * + * @return zero + * @retval zero +*/ +static int bmp_spi_remove(struct spi_device *client) +{ + return bmp_remove(&client->dev); +} + +#ifdef CONFIG_PM +/*! + * @brief suspend bmp device in spi driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int bmp_spi_suspend(struct device *dev) +{ + return bmp_disable(dev); +} + +/*! + * @brief resume bmp device in spi driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int bmp_spi_resume(struct device *dev) +{ + return bmp_enable(dev); +} + +/*! + * @brief register spi device power manager hooks +*/ +static const struct dev_pm_ops bmp_spi_pm_ops = { + /**< device suspend */ + .suspend = bmp_spi_suspend, + /**< device resume */ + .resume = bmp_spi_resume +}; +#endif + +/*! + * @brief register spi device id +*/ +static const struct spi_device_id bmp_id[] = { + { BMP_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, bmp_id); + +/*! + * @brief register spi driver hooks +*/ +static struct spi_driver bmp_spi_driver = { + .driver = { + .owner = THIS_MODULE, + .name = BMP_NAME, +#ifdef CONFIG_PM + .pm = &bmp_spi_pm_ops, +#endif + }, + .id_table = bmp_id, + .probe = bmp_spi_probe, + .shutdown = bmp_spi_shutdown, + .remove = bmp_spi_remove +}; + +/*! + * @brief initialize bmp spi module + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int __init bmp_spi_init(void) +{ + return spi_register_driver(&bmp_spi_driver); +} + +/*! + * @brief remove bmp spi module + * + * @return no return value +*/ +static void __exit bmp_spi_exit(void) +{ + spi_unregister_driver(&bmp_spi_driver); +} + + +MODULE_DESCRIPTION("BMP280 SPI DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(bmp_spi_init); +module_exit(bmp_spi_exit); +/*@}*/ diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig old mode 100644 new mode 100755 index 97fcd88d2d5..d903feec011 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1136,6 +1136,17 @@ config TOUCHSCREEN_MAXIM_STI module will be called maxim_sti. source "drivers/input/touchscreen/gt9xx/Kconfig" +config TOUCHSCREEN_GT1XX + bool "Goodix touchpanel GT1xx series" + depends on I2C + help + Say Y here if you have a Goodix GT1xx touchscreen. + GT1xx controllers are multi touch controllers which can + report 5 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/gt1xx/Kconfig" config TOUCHSCREEN_HIMAX_CHIPSET bool "Himax touchpanel CHIPSET" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile old mode 100644 new mode 100755 index 499b8110fe6..075d17bba8f --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -90,4 +90,4 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ -obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ +obj-$(CONFIG_TOUCHSCREEN_GT1XX) += gt1xx/ diff --git a/drivers/input/touchscreen/gt1xx/Kconfig b/drivers/input/touchscreen/gt1xx/Kconfig new file mode 100755 index 00000000000..98ed93d790f --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/Kconfig @@ -0,0 +1,19 @@ +# +# Goodix GT1xx Touchscreen driver +# + +config GT1XX_TOUCHPANEL_DRIVER + tristate "Goodix GT1xx touchpanel driver" + depends on TOUCHSCREEN_GT1XX + default n + help + This is the main file for touchpanel driver for Goodix GT1xx + touchscreens. + + Say Y here if you have a Goodix GT1xx touchscreen connected + to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called gt1xx_update. \ No newline at end of file diff --git a/drivers/input/touchscreen/gt1xx/Makefile b/drivers/input/touchscreen/gt1xx/Makefile new file mode 100755 index 00000000000..10c7d5cfb31 --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/Makefile @@ -0,0 +1,16 @@ +#gt915 touchpanel driver + +ifeq ($(CONFIG_COMPAT),y) +EXTRA_CFLAGS +=-Wno-error=date-time +EXTRA_CFLAGS +=-Wno-date-time +else +EXTRA_CFLAGS +=-Wno-Werror=date-time +EXTRA_CFLAGS +=-Wno-Wdate-time +endif + +obj-y += gt1x.o +obj-y += gt1x_extents.o +obj-y += gt1x_generic.o +obj-y += gt1x_tools.o +obj-y += gt1x_update.o + diff --git a/drivers/input/touchscreen/gt1xx/gt1x.c b/drivers/input/touchscreen/gt1xx/gt1x.c new file mode 100755 index 00000000000..294dd9efa28 --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x.c @@ -0,0 +1,898 @@ +/* drivers/input/touchscreen/gt1x.c + * + * 2010 - 2014 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ + +#include +#include "gt1x.h" +#if GTP_ICS_SLOT_REPORT +#include +#endif + +static struct work_struct gt1x_work; +static struct input_dev *input_dev; +static struct workqueue_struct *gt1x_wq; +static const char *gt1x_ts_name = "goodix-ts"; +static const char *input_dev_phys = "input/ts"; +#ifdef GTP_CONFIG_OF +int gt1x_rst_gpio; +int gt1x_int_gpio; +#endif +//add by liangdi +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" + +struct pinctrl *ts_pinctrl=NULL; +struct pinctrl_state *pinctrl_state_active; +struct pinctrl_state *pinctrl_state_suspend; +struct pinctrl_state *pinctrl_state_release; +//add end + +static int gt1x_register_powermanger(void); +static int gt1x_unregister_powermanger(void); + +/** + * gt1x_i2c_write - i2c write. + * @addr: register address. + * @buffer: data buffer. + * @len: the bytes of data to write. + *Return: 0: success, otherwise: failed + */ +s32 gt1x_i2c_write(u16 addr, u8 * buffer, s32 len) +{ + struct i2c_msg msg = { + .flags = 0, + .addr = gt1x_i2c_client->addr, + }; + return _do_i2c_write(&msg, addr, buffer, len); +} + +/** + * gt1x_i2c_read - i2c read. + * @addr: register address. + * @buffer: data buffer. + * @len: the bytes of data to write. + *Return: 0: success, otherwise: failed + */ +s32 gt1x_i2c_read(u16 addr, u8 * buffer, s32 len) +{ + u8 addr_buf[GTP_ADDR_LENGTH] = { (addr >> 8) & 0xFF, addr & 0xFF }; + struct i2c_msg msgs[2] = { + { + .addr = gt1x_i2c_client->addr, + .flags = 0, + .buf = addr_buf, + .len = GTP_ADDR_LENGTH}, + { + .addr = gt1x_i2c_client->addr, + .flags = I2C_M_RD} + }; + return _do_i2c_read(msgs, addr, buffer, len); +} + +static spinlock_t irq_lock; +static s32 irq_is_disable = 0; + +/** + * gt1x_irq_enable - enable irq function. + * + */ +void gt1x_irq_enable(void) +{ + unsigned long irqflags = 0; + + GTP_DEBUG_FUNC(); + + spin_lock_irqsave(&irq_lock, irqflags); + if (irq_is_disable) { + enable_irq(gt1x_i2c_client->irq); + irq_is_disable = 0; + } + spin_unlock_irqrestore(&irq_lock, irqflags); +} + +/** + * gt1x_irq_enable - disable irq function. + * + */ +void gt1x_irq_disable(void) +{ + unsigned long irqflags; + + GTP_DEBUG_FUNC(); + + spin_lock_irqsave(&irq_lock, irqflags); + if (!irq_is_disable) { + irq_is_disable = 1; + disable_irq_nosync(gt1x_i2c_client->irq); + } + spin_unlock_irqrestore(&irq_lock, irqflags); +} + +#ifndef GTP_CONFIG_OF +int gt1x_power_switch(s32 state) +{ + return 0; +} +#endif + +int gt1x_debug_proc(u8 * buf, int count) +{ + return -1; +} + +#if GTP_CHARGER_SWITCH +u32 gt1x_get_charger_status(void) +{ +#error Need to get charger status of your platform. +} +#endif + +/** + * gt1x_ts_irq_handler - External interrupt service routine for interrupt mode. + * @irq: interrupt number. + * @dev_id: private data pointer. + * Return: Handle Result. + * IRQ_HANDLED: interrupt handled successfully + */ +static irqreturn_t gt1x_ts_irq_handler(int irq, void *dev_id) +{ + GTP_DEBUG_FUNC(); + gt1x_irq_disable(); + queue_work(gt1x_wq, >1x_work); + return IRQ_HANDLED; +} + +/** + * gt1x_touch_down - Report touch point event . + * @id: trackId + * @x: input x coordinate + * @y: input y coordinate + * @w: input pressure + * Return: none. + */ +void gt1x_touch_down(s32 x, s32 y, s32 size, s32 id) +{ +#if GTP_CHANGE_X2Y + GTP_SWAP(x, y); +#endif + +#if GTP_ICS_SLOT_REPORT + input_mt_slot(input_dev, id); + input_report_abs(input_dev, ABS_MT_PRESSURE, size); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, size); + input_report_abs(input_dev, ABS_MT_TRACKING_ID, id); + input_report_abs(input_dev, ABS_MT_POSITION_X, x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, y); +#else + input_report_key(input_dev, BTN_TOUCH, 1); + if ((!size) && (!id)) { + /* for virtual button */ + input_report_abs(input_dev, ABS_MT_PRESSURE, 100); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 100); + } else { + input_report_abs(input_dev, ABS_MT_PRESSURE, size); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, size); + input_report_abs(input_dev, ABS_MT_TRACKING_ID, id); + } + input_report_abs(input_dev, ABS_MT_POSITION_X, x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + input_mt_sync(input_dev); +#endif +} + +/** + * gt1x_touch_up - Report touch release event. + * @id: trackId + * Return: none. + */ +void gt1x_touch_up(s32 id) +{ +#if GTP_ICS_SLOT_REPORT + input_mt_slot(input_dev, id); + input_report_abs(input_dev, ABS_MT_TRACKING_ID, -1); +#else + input_report_key(input_dev, BTN_TOUCH, 0); + input_mt_sync(input_dev); +#endif +} + +/** + * gt1x_ts_work_func - Goodix touchscreen work function. + * @iwork: work struct of gt1x_workqueue. + * Return: none. + */ +static void gt1x_ts_work_func(struct work_struct *work) +{ + u8 end_cmd = 0; + u8 finger = 0; + s32 ret = 0; + u8 point_data[11] = { 0 }; + + if (update_info.status) { + GTP_DEBUG("Ignore interrupts during fw update."); + return; + } + +#if GTP_GESTURE_WAKEUP + ret = gesture_event_handler(input_dev); + if (ret >= 0) { + goto exit_work_func; + } +#endif + + if (gt1x_halt) { + GTP_DEBUG("Ignore interrupts after suspend..."); + return; + } + + ret = gt1x_i2c_read(GTP_READ_COOR_ADDR, point_data, sizeof(point_data)); + if (ret < 0) { + GTP_ERROR("I2C transfer error!"); +#if !GTP_ESD_PROTECT + gt1x_power_reset(); +#endif + goto exit_work_func; + } + + finger = point_data[0]; + if (finger == 0x00) { + gt1x_request_event_handler(); + } + + if ((finger & 0x80) == 0) { +#if HOTKNOT_BLOCK_RW + if (!hotknot_paired_flag) +#endif + { + //GTP_ERROR("buffer not ready:0x%02x", finger); + goto exit_eint; + } + } +#if HOTKNOT_BLOCK_RW + ret = hotknot_event_handler(point_data); + if (!ret) { + goto exit_work_func; + } +#endif + +#if GTP_PROXIMITY + ret = gt1x_prox_event_handler(point_data); + if (ret > 0) { + goto exit_work_func; + } +#endif + +#if GTP_WITH_STYLUS + ret = gt1x_touch_event_handler(point_data, input_dev, pen_dev); +#else + ret = gt1x_touch_event_handler(point_data, input_dev, NULL); +#endif + +exit_work_func: + if (!gt1x_rawdiff_mode && (ret >= 0 || ret == ERROR_VALUE)) { + ret = gt1x_i2c_write(GTP_READ_COOR_ADDR, &end_cmd, 1); + if (ret < 0) { + GTP_ERROR("I2C write end_cmd error!"); + } + } +exit_eint: + gt1x_irq_enable(); + +} + +/* + * Devices Tree support, +*/ +#ifdef GTP_CONFIG_OF + +static struct regulator *vdd_ana; +static struct regulator *vcc_i2c; + +/** + * gt1x_parse_dt - parse platform infomation form devices tree. + */ +static int gt1x_parse_dt(struct device *dev) +{ + struct device_node *np; + int ret = 0; + + if (!dev) + return -ENODEV; + + np = dev->of_node; + gt1x_int_gpio = of_get_named_gpio(np, "goodix,irq-gpio", 0); + gt1x_rst_gpio = of_get_named_gpio(np, "goodix,rst-gpio", 0); + + if (!gpio_is_valid(gt1x_int_gpio) || !gpio_is_valid(gt1x_rst_gpio)) { + GTP_ERROR("Invalid GPIO, irq-gpio:%d, rst-gpio:%d", + gt1x_int_gpio, gt1x_rst_gpio); + return -EINVAL; + } + + vdd_ana = regulator_get(dev, "vdd_ana"); + if (IS_ERR(vdd_ana)) { + GTP_ERROR("regulator get of vdd_ana failed"); + ret = PTR_ERR(vdd_ana); + vdd_ana = NULL; + return ret; + } + + vcc_i2c = regulator_get(dev, "vcc_i2c"); + if (IS_ERR(vcc_i2c)) { + GTP_ERROR("regulator get of vcc_i2c failed"); + ret = PTR_ERR(vcc_i2c); + vcc_i2c = NULL; + goto ERR_GET_VCC; + } + return 0; +ERR_GET_VCC: + regulator_put(vdd_ana); + vdd_ana = NULL; + return ret; + +} + +/** + * gt1x_power_switch - power switch . + * @on: 1-switch on, 0-switch off. + * return: 0-succeed, -1-faileds + */ +int gt1x_power_switch(int on) +{ + + int ret; + struct i2c_client *client = gt1x_i2c_client; + + if (!client || !vdd_ana || !vcc_i2c) + return -1; + + if (on) { + GTP_DEBUG("GTP power on."); + ret = regulator_enable(vdd_ana); + udelay(2); + ret = regulator_enable(vcc_i2c); + } else { + GTP_DEBUG("GTP power off."); + ret = regulator_disable(vcc_i2c); + udelay(2); + ret = regulator_disable(vdd_ana); + } + return ret; + +} +#endif + +static void gt1x_remove_gpio_and_power(void) +{ + if (gpio_is_valid(gt1x_int_gpio)) + gpio_free(gt1x_int_gpio); + + if (gpio_is_valid(gt1x_rst_gpio)) + gpio_free(gt1x_rst_gpio); + +#ifdef GTP_CONFIG_OF + if (vcc_i2c) + regulator_put(vcc_i2c); + + if (vdd_ana) + regulator_put(vdd_ana); +#endif + + if (gt1x_i2c_client && gt1x_i2c_client->irq) + free_irq(gt1x_i2c_client->irq, gt1x_i2c_client); + +} + + +/** + * gt1x_request_io_port - Request gpio(INT & RST) ports. + */ +static s32 gt1x_request_io_port(void) +{ + s32 ret = 0; + + GTP_DEBUG_FUNC(); + ret = gpio_request(GTP_INT_PORT, "GTP_INT_IRQ"); + if (ret < 0) { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32) GTP_INT_PORT, ret); + ret = -ENODEV; + } else { + GTP_GPIO_AS_INT(GTP_INT_PORT); + gt1x_i2c_client->irq = GTP_INT_IRQ; + } + + ret = gpio_request(GTP_RST_PORT, "GTP_RST_PORT"); + if (ret < 0) { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32) GTP_RST_PORT, ret); + ret = -ENODEV; + } + + GTP_GPIO_AS_INPUT(GTP_RST_PORT); + if (ret < 0) { + gpio_free(GTP_RST_PORT); + gpio_free(GTP_INT_PORT); + } + + return ret; +} + +/** + * gt1x_request_irq - Request interrupt. + * Return + * 0: succeed, -1: failed. + */ +static s32 gt1x_request_irq(void) +{ + s32 ret = -1; + const u8 irq_table[] = GTP_IRQ_TAB; + + GTP_DEBUG_FUNC(); + GTP_DEBUG("INT triggerr type:%x", gt1x_int_type); + + ret = request_irq(gt1x_i2c_client->irq, gt1x_ts_irq_handler, irq_table[gt1x_int_type], gt1x_i2c_client->name, gt1x_i2c_client); + /* + ret = request_threaded_irq(gt1x_i2c_client->irq, NULL, + gt1x_ts_irq_handler, + 0x2002, + gt1x_i2c_client->name, gt1x_i2c_client); + */ + if (ret) { + GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret); + GTP_GPIO_AS_INPUT(GTP_INT_PORT); + gpio_free(GTP_INT_PORT); + + return -1; + } else { + gt1x_irq_disable(); + return 0; + } +} + +/** + * gt1x_request_input_dev - Request input device Function. + * Return + * 0: succeed, -1: failed. + */ +static s8 gt1x_request_input_dev(void) +{ + s8 ret = -1; +#if GTP_HAVE_TOUCH_KEY + u8 index = 0; +#endif + + GTP_DEBUG_FUNC(); + + input_dev = input_allocate_device(); + if (input_dev == NULL) { + GTP_ERROR("Failed to allocate input device."); + return -ENOMEM; + } + + input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +#if GTP_ICS_SLOT_REPORT +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0)) + input_mt_init_slots(input_dev, 16, INPUT_MT_DIRECT); +#else + input_mt_init_slots(input_dev, 16); +#endif +#else + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); +#endif + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + +#if GTP_HAVE_TOUCH_KEY + for (index = 0; index < GTP_MAX_KEY_NUM; index++) { + input_set_capability(input_dev, EV_KEY, gt1x_touch_key_array[index]); + } +#endif + +#if GTP_GESTURE_WAKEUP + input_set_capability(input_dev, EV_KEY, KEY_GES_REGULAR); + input_set_capability(input_dev, EV_KEY, KEY_GES_CUSTOM); +#endif + +#if GTP_CHANGE_X2Y + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, gt1x_abs_y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, gt1x_abs_x_max, 0, 0); +#else + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, gt1x_abs_x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, gt1x_abs_y_max, 0, 0); +#endif + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + input_dev->name = gt1x_ts_name; + input_dev->phys = input_dev_phys; + input_dev->id.bustype = BUS_I2C; + input_dev->id.vendor = 0xDEAD; + input_dev->id.product = 0xBEEF; + input_dev->id.version = 10427; + + ret = input_register_device(input_dev); + if (ret) { + GTP_ERROR("Register %s input device failed", input_dev->name); + return -ENODEV; + } + + return 0; +} + +//add by liangdi +#if 0 +static int gt1x_ts_pinctrl_init(struct i2c_client *client) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts_pinctrl = devm_pinctrl_get(&(client->dev)); + if (IS_ERR_OR_NULL(ts_pinctrl)) { + retval = PTR_ERR(ts_pinctrl); + GTP_ERROR("Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + pinctrl_state_active + = pinctrl_lookup_state(ts_pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(pinctrl_state_active)) { + retval = PTR_ERR(pinctrl_state_active); + GTP_ERROR("Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + pinctrl_state_suspend + = pinctrl_lookup_state(ts_pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(pinctrl_state_suspend)) { + retval = PTR_ERR(pinctrl_state_suspend); + GTP_ERROR("Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + pinctrl_state_release + = pinctrl_lookup_state(ts_pinctrl, + PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(pinctrl_state_release)) { + retval = PTR_ERR(pinctrl_state_release); + GTP_ERROR("Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts_pinctrl); +err_pinctrl_get: + ts_pinctrl = NULL; + return retval; +} +#endif +//add end + +/** + * gt1x_ts_probe - I2c probe. + * @client: i2c device struct. + * @id: device id. + * Return 0: succeed, -1: failed. + */ +static int gt1x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + s32 ret = -1; +#if GTP_AUTO_UPDATE + struct task_struct *thread = NULL; +#endif + //do NOT remove these logs + GTP_INFO("GTP Driver Version: %s", GTP_DRIVER_VERSION); + GTP_INFO("GTP I2C Address: 0x%02x", client->addr); + + gt1x_i2c_client = client; + spin_lock_init(&irq_lock); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + GTP_ERROR("I2C check functionality failed."); + return -ENODEV; + } + +#ifdef GTP_CONFIG_OF /* device tree support */ + if (client->dev.of_node) { + gt1x_parse_dt(&client->dev); + } +#endif + + ret = gt1x_request_io_port(); + if (ret < 0) { + GTP_ERROR("GTP request IO port failed."); + return ret; + } + + gt1x_init(); + + INIT_WORK(>1x_work, gt1x_ts_work_func); + + ret = gt1x_request_input_dev(); + if (ret < 0) { + GTP_ERROR("GTP request input dev failed"); + } + + ret = gt1x_request_irq(); + if (ret < 0) { + GTP_INFO("GTP works in polling mode."); + } else { + GTP_INFO("GTP works in interrupt mode."); + } + + //add by liangdi +/* + ret = gt1x_ts_pinctrl_init(client); + + if (!ret && ts_pinctrl) { + ret = pinctrl_select_state(ts_pinctrl, + pinctrl_state_active); + if (ret < 0) { + GTP_ERROR("failed to select pin to active state"); + return ret; + } + } else { + GTP_ERROR("failed to gt1x_ts_pinctrl_init"); + return ret; + } +*/ + //add end + +#if GTP_GESTURE_WAKEUP + enable_irq_wake(client->irq); +#endif + + gt1x_irq_enable(); + +#if GTP_ESD_PROTECT + // must before auto update + gt1x_init_esd_protect(); + gt1x_esd_switch(SWITCH_ON); +#endif + +#if GTP_AUTO_UPDATE + thread = kthread_run(gt1x_auto_update_proc, (void *)NULL, "gt1x_auto_update"); + if (IS_ERR(thread)) { + ret = PTR_ERR(thread); + GTP_ERROR("Failed to create auto-update thread: %d.", ret); + } +#endif + gt1x_register_powermanger(); + return 0; +} + +/** + * gt1x_ts_remove - Goodix touchscreen driver release function. + * @client: i2c device struct. + * Return 0: succeed, -1: failed. + */ +static int gt1x_ts_remove(struct i2c_client *client) +{ + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver removing..."); + gt1x_unregister_powermanger(); + +#if GTP_GESTURE_WAKEUP + disable_irq_wake(client->irq); +#endif + gt1x_deinit(); + input_unregister_device(input_dev); + gt1x_remove_gpio_and_power(); + + return 0; +} + +#if defined(CONFIG_FB) +/* frame buffer notifier block control the suspend/resume procedure */ +static struct notifier_block gt1x_fb_notifier; + +static int gtp_fb_notifier_callback(struct notifier_block *noti, unsigned long event, void *data) +{ + struct fb_event *ev_data = data; + int *blank; + +#if GTP_INCELL_PANEL + #ifndef FB_EARLY_EVENT_BLANK + #error Need add FB_EARLY_EVENT_BLANK to fbmem.c + #endif + + if (ev_data && ev_data->data && event == FB_EARLY_EVENT_BLANK) { + blank = ev_data->data; + if (*blank == FB_BLANK_UNBLANK) { + GTP_DEBUG("Resume by fb notifier."); + gt1x_resume(); + } + } +#else + if (ev_data && ev_data->data && event == FB_EVENT_BLANK) { + blank = ev_data->data; + if (*blank == FB_BLANK_UNBLANK) { + GTP_DEBUG("Resume by fb notifier."); + gt1x_resume(); + } + } +#endif + + if (ev_data && ev_data->data && event == FB_EVENT_BLANK) { + blank = ev_data->data; + if (*blank == FB_BLANK_POWERDOWN) { + GTP_DEBUG("Suspend by fb notifier."); + gt1x_suspend(); + } + } + + return 0; +} +#elif defined(CONFIG_PM) +/** + * gt1x_ts_suspend - i2c suspend callback function. + * @dev: i2c device. + * Return 0: succeed, -1: failed. + */ +static int gt1x_pm_suspend(struct device *dev) +{ + int ret; + + gt1x_suspend(); + + if (ts_pinctrl) { + ret = pinctrl_select_state(ts_pinctrl, + pinctrl_state_suspend); + if (ret < 0) + GTP_ERROR("failed to select pin to suspend state"); + else + GTP_ERROR("successful to select pin to suspend state"); + } + return ret; +} + +/** + * gt1x_ts_resume - i2c resume callback function. + * @dev: i2c device. + * Return 0: succeed, -1: failed. + */ +static int gt1x_pm_resume(struct device *dev) +{ + int ret; + + gt1x_resume(); + if (ts_pinctrl) { + ret = pinctrl_select_state(ts_pinctrl, + pinctrl_state_active); + if (ret < 0) + GTP_ERROR("failed to select pin to active state"); + else + GTP_ERROR("successful to select pin to active state"); + } + return ret; +} + +/* bus control the suspend/resume procedure */ +static const struct dev_pm_ops gt1x_ts_pm_ops = { + .suspend = gt1x_pm_suspend, + .resume = gt1x_pm_resume, +}; + +#elif defined(CONFIG_HAS_EARLYSUSPEND) +/* earlysuspend module the suspend/resume procedure */ +static void gt1x_ts_early_suspend(struct early_suspend *h) +{ + gt1x_suspend(); +} + +static void gt1x_ts_late_resume(struct early_suspend *h) +{ + gt1x_resume(); +} + +static struct early_suspend gt1x_early_suspend = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1, + .suspend = gt1x_ts_early_suspend, + .resume = gt1x_ts_late_resume, +}; +#endif + + +static int gt1x_register_powermanger(void) +{ +#if defined(CONFIG_FB) + gt1x_fb_notifier.notifier_call = gtp_fb_notifier_callback; + fb_register_client(>1x_fb_notifier); + +#elif defined(CONFIG_HAS_EARLYSUSPEND) + register_early_suspend(>1x_early_suspend); +#endif + return 0; +} + +static int gt1x_unregister_powermanger(void) +{ +#if defined(CONFIG_FB) + fb_unregister_client(>1x_fb_notifier); + +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(>1x_early_suspend); +#endif + return 0; +} + +#ifdef GTP_CONFIG_OF +static const struct of_device_id gt1x_match_table[] = { + {.compatible = "goodix,gt1x",}, + { }, +}; +#endif + +static const struct i2c_device_id gt1x_ts_id[] = { + {GTP_I2C_NAME, 0}, + {} +}; + +static struct i2c_driver gt1x_ts_driver = { + .probe = gt1x_ts_probe, + .remove = gt1x_ts_remove, + .id_table = gt1x_ts_id, + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, +#ifdef GTP_CONFIG_OF + .of_match_table = gt1x_match_table, +#endif +#if !defined(CONFIG_FB) && defined(CONFIG_PM) + .pm = >1x_ts_pm_ops, +#endif + }, +}; + +/** + * gt1x_ts_init - Driver Install function. + * Return 0---succeed. + */ +static int __init gt1x_ts_init(void) +{ + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver installing..."); + gt1x_wq = create_singlethread_workqueue("gt1x_wq"); + if (!gt1x_wq) { + GTP_ERROR("Creat workqueue failed."); + return -ENOMEM; + } + + return i2c_add_driver(>1x_ts_driver); +} + +/** + * gt1x_ts_exit - Driver uninstall function. + * Return 0---succeed. + */ +static void __exit gt1x_ts_exit(void) +{ + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver exited."); + i2c_del_driver(>1x_ts_driver); + if (gt1x_wq) { + destroy_workqueue(gt1x_wq); + } +} + +module_init(gt1x_ts_init); +module_exit(gt1x_ts_exit); + +MODULE_DESCRIPTION("GTP Series Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/gt1xx/gt1x.h b/drivers/input/touchscreen/gt1xx/gt1x.h new file mode 100755 index 00000000000..df7de089ffd --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x.h @@ -0,0 +1,62 @@ +/* drivers/input/touchscreen/gt1x.h + * + * 2010 - 2013 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ + +#ifndef _GOODIX_GT1X_H_ +#define _GOODIX_GT1X_H_ +#include "gt1x_generic.h" +#include +#ifdef GTP_CONFIG_OF +#include +#include +#endif +#ifdef CONFIG_FB +#include +#include +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#define IIC_MAX_TRANSFER_SIZE 250 + +/* Customize your I/O ports & I/O operations */ +#ifdef GTP_CONFIG_OF +extern int gt1x_rst_gpio; +extern int gt1x_int_gpio; +#define GTP_RST_PORT gt1x_rst_gpio +#define GTP_INT_PORT gt1x_int_gpio +#else +#define GTP_RST_PORT 102 //S5PV210_GPJ3(6) +#define GTP_INT_PORT 52 //S5PV210_GPH1(3) +#endif + +#define GTP_INT_IRQ gpio_to_irq(GTP_INT_PORT) +//#define GTP_INT_CFG S3C_GPIO_SFN(0xF) + +#define GTP_GPIO_AS_INPUT(pin) do{\ + gpio_direction_input(pin);\ + }while(0) +#define GTP_GPIO_AS_INT(pin) do{\ + GTP_GPIO_AS_INPUT(pin);\ + }while(0) +#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin) +#define GTP_GPIO_OUTPUT(pin,level) gpio_direction_output(pin,level) +#define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH} + +#endif /* _GOODIX_GT1X_H_ */ diff --git a/drivers/input/touchscreen/gt1xx/gt1x_extents.c b/drivers/input/touchscreen/gt1xx/gt1x_extents.c new file mode 100755 index 00000000000..ac04d8ff935 --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x_extents.c @@ -0,0 +1,930 @@ +/* drivers/input/touchscreen/gt1x_extents.c + * + * 2010 - 2014 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /*proc */ + +#include +#include "gt1x_generic.h" + +#if GTP_GESTURE_WAKEUP + +#define GESTURE_NODE "goodix_gesture" +#define GESTURE_MAX_POINT_COUNT 64 + +#pragma pack(1) +typedef struct { + u8 ic_msg[6]; /*from the first byte */ + u8 gestures[4]; + u8 data[3 + GESTURE_MAX_POINT_COUNT * 4 + 80]; /*80 bytes for extra data */ +} st_gesture_data; +#pragma pack() + +#define SETBIT(longlong, bit) (longlong[bit/8] |= (1 << bit%8)) +#define CLEARBIT(longlong, bit) (longlong[bit/8] &=(~(1 << bit%8))) +#define QUERYBIT(longlong, bit) (!!(longlong[bit/8] & (1 << bit%8))) + +#define CHKBITS_32 32 +#define CHKBITS_16 16 +#define CHKBITS_8 8 + +int gesture_enabled = 0; /* module switch */ +DOZE_T gesture_doze_status = DOZE_DISABLED; /* doze status */ + +static u8 gestures_flag[32]; /* gesture flag, every bit stands for a gesture */ +static st_gesture_data gesture_data; /* gesture data buffer */ +static struct mutex gesture_data_mutex; /* lock for gesture data */ + +static ssize_t gt1x_gesture_data_read(struct file *file, char __user * page, size_t size, loff_t * ppos) +{ + s32 ret = -1; + GTP_DEBUG("visit gt1x_gesture_data_read. ppos:%d", (int)*ppos); + if (*ppos) { + return 0; + } + if (size == 4) { + ret = copy_to_user(((u8 __user *) page), "GT1X", 4); + return 4; + } + ret = simple_read_from_buffer(page, size, ppos, &gesture_data, sizeof(gesture_data)); + + GTP_DEBUG("Got the gesture data."); + return ret; +} + +static ssize_t gt1x_gesture_data_write(struct file *filp, const char __user * buff, size_t len, loff_t * off) +{ + s32 ret = 0; + + GTP_DEBUG_FUNC(); + + ret = copy_from_user(&gesture_enabled, buff, 1); + if (ret) { + GTP_ERROR("copy_from_user failed."); + return -EPERM; + } + + GTP_DEBUG("gesture enabled:%x, ret:%d", gesture_enabled, ret); + + return len; +} + +/** + * calc_checksum - Calc checksum. + * @buf: data to be calc + * @len: length of buf. + * @bits: checkbits + * Return true-pass, false:not pass. + */ +static bool calc_checksum(u8 *buf, int len, int bits) +{ + int i; + + if (bits == CHKBITS_16) { + u16 chksum, *b = (u16 *)buf; + + if (len % 2) { + return false; + } + + len /= 2; + for (i = 0, chksum = 0; i < len; i++) { + if (i == len - 1) + chksum += le16_to_cpu(b[i]); + else + chksum += be16_to_cpu(b[i]); + } + return chksum == 0 ? true : false; + } else if (bits == CHKBITS_8) { + u8 chksum; + + for (i = 0, chksum =0; i < len; i++) { + chksum += buf[i]; + } + return chksum == 0 ? true : false; + } + + return false; +} + +int gesture_enter_doze(void) +{ + int retry = 0; + + GTP_DEBUG_FUNC(); + GTP_DEBUG("Entering doze mode..."); + while (retry++ < 5) { + if (!gt1x_send_cmd(0x08, 0)) { + gesture_doze_status = DOZE_ENABLED; + GTP_DEBUG("Working in doze mode!"); + return 0; + } + msleep(10); + } + GTP_ERROR("Send doze cmd failed."); + return -1; +} + +s32 gesture_event_handler(struct input_dev * dev) +{ + u8 doze_buf[4] = { 0 }, ges_type; + static int err_flag1 = 0, err_flag2 = 0; + int len, extra_len, need_chk; + unsigned int key_code; + s32 ret = 0; + + if (DOZE_ENABLED != gesture_doze_status) { + return -1; + } + + /** package: -head 4B + track points + extra info- + * - head - + * doze_buf[0]: gesture type, + * doze_buf[1]: number of gesture points , + * doze_buf[2]: protocol type, + * doze_buf[3]: gesture extra data length. + */ + ret = gt1x_i2c_read(GTP_REG_WAKEUP_GESTURE, doze_buf, 4); + if (ret < 0) { + return 0; + } + + ges_type = doze_buf[0]; + len = doze_buf[1]; + need_chk = doze_buf[2] & 0x80; + extra_len = doze_buf[3]; + + GTP_DEBUG("0x%x = 0x%02X,0x%02X,0x%02X,0x%02X", GTP_REG_WAKEUP_GESTURE, + doze_buf[0], doze_buf[1], doze_buf[2], doze_buf[3]); + + if (len > GESTURE_MAX_POINT_COUNT) { + GTP_ERROR("Gesture contain too many points!(%d)", len); + len = GESTURE_MAX_POINT_COUNT; + } + + if (extra_len > 32) { + GTP_ERROR("Gesture contain too many extra data!(%d)", extra_len); + extra_len = 32; + } + + /* get gesture extra info */ + if (extra_len >= 0) { + u8 ges_data[extra_len + 1]; + + /* head 4 + extra data * 4 + chksum 1 */ + ret = gt1x_i2c_read(GTP_REG_WAKEUP_GESTURE + 4, + ges_data, extra_len + 1); + if (ret < 0) { + GTP_ERROR("Read extra gesture data failed."); + return 0; + } + + if (likely(need_chk)) { /* calc checksum */ + bool val; + + ges_data[extra_len] += doze_buf[0] + doze_buf[1] + + doze_buf[2] + doze_buf[3]; + + val = calc_checksum(ges_data, extra_len + 1, CHKBITS_8); + if (unlikely(!val)) { /* check failed */ + GTP_ERROR("Gesture checksum error."); + if (err_flag1) { + err_flag1 = 0; + ret = 0; + goto clear_reg; + } else { + /* just return 0 without clear reg, + this will receive another int, we + check the data in the next frame */ + err_flag1 = 1; + return 0; + } + } + + err_flag1 = 0; + } + + mutex_lock(&gesture_data_mutex); + memcpy(&gesture_data.data[4 + len * 4], ges_data, extra_len); + mutex_unlock(&gesture_data_mutex); + } + + /* check gesture type (if available?) */ + if (ges_type == 0 || !QUERYBIT(gestures_flag, ges_type)) { + GTP_INFO("Gesture[0x%02X] has been disabled.", doze_buf[0]); + doze_buf[0] = 0x00; + gt1x_i2c_write(GTP_REG_WAKEUP_GESTURE, doze_buf, 1); + gesture_enter_doze(); + return 0; + } + + /* get gesture point data */ + if (len > 0) { /* coor num * 4 + chksum 2*/ + u8 ges_data[len * 4 + 2]; + + ret = gt1x_i2c_read(GES_BUFFER_ADDR, ges_data, len * 4); + if (ret < 0) { + GTP_ERROR("Read gesture data failed."); + return 0; + } + + /* checksum reg for gesture point data */ + ret = gt1x_i2c_read(0x819F, &ges_data[len * 4], 2); + if (ret < 0) { + GTP_ERROR("Read gesture data failed."); + return 0; + } + + if (likely(need_chk)) { + bool val = calc_checksum(ges_data, + len * 4 + 2, CHKBITS_16); + if (unlikely(!val)) { /* check failed */ + GTP_ERROR("Gesture checksum error."); + if (err_flag2) { + err_flag2 = 0; + ret = 0; + goto clear_reg; + } else { + err_flag2 = 1; + return 0; + } + } + + err_flag2 = 0; + } + + mutex_lock(&gesture_data_mutex); + memcpy(&gesture_data.data[4], ges_data, len * 4); + mutex_unlock(&gesture_data_mutex); + } + + mutex_lock(&gesture_data_mutex); + gesture_data.data[0] = ges_type; // gesture type + gesture_data.data[1] = len; // gesture points number + gesture_data.data[2] = doze_buf[2] & 0x7F; // protocol type + gesture_data.data[3] = extra_len; // gesture date length + mutex_unlock(&gesture_data_mutex); + + /* get key code */ + key_code = ges_type < 16? KEY_GES_CUSTOM : KEY_GES_REGULAR; + GTP_DEBUG("Gesture: 0x%02X, points: %d", doze_buf[0], doze_buf[1]); + + input_report_key(dev, key_code, 1); + input_sync(dev); + input_report_key(dev, key_code, 0); + input_sync(dev); + +clear_reg: + doze_buf[0] = 0; // clear ges flag + gt1x_i2c_write(GTP_REG_WAKEUP_GESTURE, doze_buf, 1); + return ret; +} + +void gesture_clear_wakeup_data(void) +{ + mutex_lock(&gesture_data_mutex); + memset(gesture_data.data, 0, 4); + mutex_unlock(&gesture_data_mutex); +} + +void gt1x_gesture_debug(int on) +{ + if (on) { + gesture_enabled = 1; + memset(gestures_flag, 0xFF, sizeof(gestures_flag)); + } else { + gesture_enabled = 0; + memset(gestures_flag, 0x00, sizeof(gestures_flag)); + gesture_doze_status = DOZE_DISABLED; + } + GTP_DEBUG("Gesture debug %s", on ? "on":"off"); +} + +#endif // GTP_GESTURE_WAKEUP + +//HotKnot module +#if GTP_HOTKNOT +#define HOTKNOT_NODE "hotknot" +#define HOTKNOT_VERSION "GOODIX,GT1X" +u8 hotknot_enabled = 0; +u8 hotknot_transfer_mode = 0; + +static int hotknot_open(struct inode *node, struct file *flip) +{ + GTP_DEBUG("Hotknot is enabled."); + hotknot_enabled = 1; + return 0; +} + +static int hotknot_release(struct inode *node, struct file *filp) +{ + GTP_DEBUG("Hotknot is disabled."); + hotknot_enabled = 0; + return 0; +} + +static s32 hotknot_enter_transfer_mode(void) +{ + int ret = 0; + u8 buffer[5] = { 0 }; + + hotknot_transfer_mode = 1; +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + + gt1x_irq_disable(); + gt1x_send_cmd(GTP_CMD_HN_TRANSFER, 0); + msleep(100); + gt1x_irq_enable(); + + ret = gt1x_i2c_read(0x8140, buffer, sizeof(buffer)); + if (ret) { + hotknot_transfer_mode = 0; + return ret; + } + + buffer[4] = 0; + GTP_DEBUG("enter transfer mode: %s ", buffer); + if (strcmp(buffer, "GHot")) { + hotknot_transfer_mode = 0; + return ERROR_HN_VER; + } + + return 0; +} + +static s32 hotknot_load_hotknot_subsystem(void) +{ + return hotknot_enter_transfer_mode(); +} + +static s32 hotknot_load_authentication_subsystem(void) +{ + s32 ret = 0; + u8 buffer[5] = { 0 }; + ret = gt1x_hold_ss51_dsp_no_reset(); + if (ret < 0) { + GTP_ERROR("Hold ss51 fail!"); + return ERROR; + } + + if (gt1x_chip_type == CHIP_TYPE_GT1X) { + GTP_INFO("hotknot load jump code."); + ret = gt1x_load_patch(gt1x_patch_jump_fw, 4096, 0, 1024 * 8); + if (ret < 0) { + GTP_ERROR("Load jump code fail!"); + return ret; + } + GTP_INFO("hotknot load auth code."); + ret = gt1x_load_patch(hotknot_auth_fw, 4096, 4096, 1024 * 8); + if (ret < 0) { + GTP_ERROR("Load auth system fail!"); + return ret; + } + } else { /* GT2X */ + GTP_INFO("hotknot load auth code."); + ret = gt1x_load_patch(hotknot_auth_fw, 4096, 0, 1024 * 6); + if (ret < 0) { + GTP_ERROR("load auth system fail!"); + return ret; + } + } + + ret = gt1x_startup_patch(); + if (ret < 0) { + GTP_ERROR("Startup auth system fail!"); + return ret; + } + ret = gt1x_i2c_read(GTP_REG_VERSION, buffer, 4); + if (ret < 0) { + GTP_ERROR("i2c read error!"); + return ERROR_IIC; + } + buffer[4] = 0; + GTP_INFO("Current System version: %s", buffer); + return 0; +} + +static s32 hotknot_recovery_main_system(void) +{ + gt1x_irq_disable(); + gt1x_reset_guitar(); + gt1x_irq_enable(); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + hotknot_transfer_mode = 0; + return 0; +} + +#if HOTKNOT_BLOCK_RW +DECLARE_WAIT_QUEUE_HEAD(bp_waiter); +static u8 got_hotknot_state = 0; +static u8 got_hotknot_extra_state = 0; +static u8 wait_hotknot_state = 0; +static u8 force_wake_flag = 0; +static u8 block_enable = 0; +s32 hotknot_paired_flag = 0; + +static s32 hotknot_block_rw(u8 rqst_hotknot_state, s32 wait_hotknot_timeout) +{ + s32 ret = 0; + + wait_hotknot_state |= rqst_hotknot_state; + GTP_DEBUG("Goodix tool received wait polling state:0x%x,timeout:%d, all wait state:0x%x", rqst_hotknot_state, wait_hotknot_timeout, wait_hotknot_state); + got_hotknot_state &= (~rqst_hotknot_state); + + set_current_state(TASK_INTERRUPTIBLE); + if (wait_hotknot_timeout <= 0) { + wait_event_interruptible(bp_waiter, force_wake_flag || rqst_hotknot_state == (got_hotknot_state & rqst_hotknot_state)); + } else { + wait_event_interruptible_timeout(bp_waiter, force_wake_flag || rqst_hotknot_state == (got_hotknot_state & rqst_hotknot_state), wait_hotknot_timeout); + } + + wait_hotknot_state &= (~rqst_hotknot_state); + + if (rqst_hotknot_state != (got_hotknot_state & rqst_hotknot_state)) { + GTP_ERROR("Wait 0x%x block polling waiter failed.", rqst_hotknot_state); + ret = -1; + } + + force_wake_flag = 0; + return ret; +} + +static void hotknot_wakeup_block(void) +{ + GTP_DEBUG("Manual wakeup all block polling waiter!"); + got_hotknot_state = 0; + wait_hotknot_state = 0; + force_wake_flag = 1; + wake_up_interruptible(&bp_waiter); +} + +s32 hotknot_event_handler(u8 * data) +{ + u8 hn_pxy_state = 0; + u8 hn_pxy_state_bak = 0; + static u8 hn_paired_cnt = 0; + u8 hn_state_buf[10] = { 0 }; + u8 finger = data[0]; + u8 id = 0; + + if (block_enable && !hotknot_paired_flag && (finger & 0x0F)) { + id = data[1]; + hn_pxy_state = data[2] & 0x80; + hn_pxy_state_bak = data[3] & 0x80; + if ((32 == id) && (0x80 == hn_pxy_state) && (0x80 == hn_pxy_state_bak)) { +#ifdef HN_DBLCFM_PAIRED + if (hn_paired_cnt++ < 2) { + return 0; + } +#endif + GTP_DEBUG("HotKnot paired!"); + if (wait_hotknot_state & HN_DEVICE_PAIRED) { + GTP_DEBUG("INT wakeup HN_DEVICE_PAIRED block polling waiter"); + got_hotknot_state |= HN_DEVICE_PAIRED; + wake_up_interruptible(&bp_waiter); + } + block_enable = 0; + hotknot_paired_flag = 1; + return 0; + } else { + got_hotknot_state &= (~HN_DEVICE_PAIRED); + hn_paired_cnt = 0; + } + } + + if (hotknot_paired_flag) { + s32 ret = -1; + ret = gt1x_i2c_read(GTP_REG_HN_STATE, hn_state_buf, 6); + if (ret < 0) { + GTP_ERROR("I2C transfer error. errno:%d\n ", ret); + return 0; + } + + got_hotknot_state = 0; + + GTP_DEBUG("wait_hotknot_state:%x", wait_hotknot_state); + GTP_DEBUG("[0x8800~0x8803]=0x%x,0x%x,0x%x,0x%x", hn_state_buf[0], hn_state_buf[1], hn_state_buf[2], hn_state_buf[3]); + + if (wait_hotknot_state & HN_MASTER_SEND) { + if ((0x03 == hn_state_buf[0]) || (0x04 == hn_state_buf[0]) + || (0x07 == hn_state_buf[0])) { + GTP_DEBUG("Wakeup HN_MASTER_SEND block polling waiter"); + got_hotknot_state |= HN_MASTER_SEND; + got_hotknot_extra_state = hn_state_buf[0]; + wake_up_interruptible(&bp_waiter); + } + } else if (wait_hotknot_state & HN_SLAVE_RECEIVED) { + if ((0x03 == hn_state_buf[1]) || (0x04 == hn_state_buf[1]) + || (0x07 == hn_state_buf[1])) { + GTP_DEBUG("Wakeup HN_SLAVE_RECEIVED block polling waiter:0x%x", hn_state_buf[1]); + got_hotknot_state |= HN_SLAVE_RECEIVED; + got_hotknot_extra_state = hn_state_buf[1]; + wake_up_interruptible(&bp_waiter); + } + } else if (wait_hotknot_state & HN_MASTER_DEPARTED) { + if (0x07 == hn_state_buf[0]) { + GTP_DEBUG("Wakeup HN_MASTER_DEPARTED block polling waiter"); + got_hotknot_state |= HN_MASTER_DEPARTED; + wake_up_interruptible(&bp_waiter); + } + } else if (wait_hotknot_state & HN_SLAVE_DEPARTED) { + if (0x07 == hn_state_buf[1]) { + GTP_DEBUG("Wakeup HN_SLAVE_DEPARTED block polling waiter"); + got_hotknot_state |= HN_SLAVE_DEPARTED; + wake_up_interruptible(&bp_waiter); + } + } + return 0; + } + + return -1; +} +#endif //HOTKNOT_BLOCK_RW +#endif //GTP_HOTKNOT + +#define GOODIX_MAGIC_NUMBER 'G' +#define NEGLECT_SIZE_MASK (~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) + +#define GESTURE_ENABLE _IO(GOODIX_MAGIC_NUMBER, 1) // 1 +#define GESTURE_DISABLE _IO(GOODIX_MAGIC_NUMBER, 2) +#define GESTURE_FLAG_SET _IO(GOODIX_MAGIC_NUMBER, 3) +#define GESTURE_FLAG_CLEAR _IO(GOODIX_MAGIC_NUMBER, 4) +//#define SET_ENABLED_GESTURE (_IOW(GOODIX_MAGIC_NUMBER, 5, u8) & NEGLECT_SIZE_MASK) +#define GESTURE_DATA_OBTAIN (_IOR(GOODIX_MAGIC_NUMBER, 6, u8) & NEGLECT_SIZE_MASK) +#define GESTURE_DATA_ERASE _IO(GOODIX_MAGIC_NUMBER, 7) + +//#define HOTKNOT_LOAD_SUBSYSTEM (_IOW(GOODIX_MAGIC_NUMBER, 6, u8) & NEGLECT_SIZE_MASK) +#define HOTKNOT_LOAD_HOTKNOT _IO(GOODIX_MAGIC_NUMBER, 20) +#define HOTKNOT_LOAD_AUTHENTICATION _IO(GOODIX_MAGIC_NUMBER, 21) +#define HOTKNOT_RECOVERY_MAIN _IO(GOODIX_MAGIC_NUMBER, 22) +//#define HOTKNOT_BLOCK_RW (_IOW(GOODIX_MAGIC_NUMBER, 6, u8) & NEGLECT_SIZE_MASK) +#define HOTKNOT_DEVICES_PAIRED _IO(GOODIX_MAGIC_NUMBER, 23) +#define HOTKNOT_MASTER_SEND _IO(GOODIX_MAGIC_NUMBER, 24) +#define HOTKNOT_SLAVE_RECEIVE _IO(GOODIX_MAGIC_NUMBER, 25) +//#define HOTKNOT_DEVICES_COMMUNICATION +#define HOTKNOT_MASTER_DEPARTED _IO(GOODIX_MAGIC_NUMBER, 26) +#define HOTKNOT_SLAVE_DEPARTED _IO(GOODIX_MAGIC_NUMBER, 27) +#define HOTKNOT_VENDOR_VERSION (_IOR(GOODIX_MAGIC_NUMBER, 28, u8) & NEGLECT_SIZE_MASK) +#define HOTKNOT_WAKEUP_BLOCK _IO(GOODIX_MAGIC_NUMBER, 29) + +#define IO_IIC_READ (_IOR(GOODIX_MAGIC_NUMBER, 100, u8) & NEGLECT_SIZE_MASK) +#define IO_IIC_WRITE (_IOW(GOODIX_MAGIC_NUMBER, 101, u8) & NEGLECT_SIZE_MASK) +#define IO_RESET_GUITAR _IO(GOODIX_MAGIC_NUMBER, 102) +#define IO_DISABLE_IRQ _IO(GOODIX_MAGIC_NUMBER, 103) +#define IO_ENABLE_IRQ _IO(GOODIX_MAGIC_NUMBER, 104) +#define IO_GET_VERISON (_IOR(GOODIX_MAGIC_NUMBER, 110, u8) & NEGLECT_SIZE_MASK) +#define IO_PRINT (_IOW(GOODIX_MAGIC_NUMBER, 111, u8) & NEGLECT_SIZE_MASK) +#define IO_VERSION "V1.3-20150420" + +#define CMD_HEAD_LENGTH 20 +static s32 io_iic_read(u8 * data, void __user * arg) +{ + s32 err = ERROR; + s32 data_length = 0; + u16 addr = 0; + + err = copy_from_user(data, arg, CMD_HEAD_LENGTH); + if (err) { + GTP_ERROR("Can't access the memory."); + return ERROR_MEM; + } + + addr = data[0] << 8 | data[1]; + data_length = data[2] << 8 | data[3]; + + err = gt1x_i2c_read(addr, &data[CMD_HEAD_LENGTH], data_length); + if (!err) { + err = copy_to_user(&((u8 __user *) arg)[CMD_HEAD_LENGTH], &data[CMD_HEAD_LENGTH], data_length); + if (err) { + GTP_ERROR("ERROR when copy to user.[addr: %04x], [read length:%d]", addr, data_length); + return ERROR_MEM; + } + err = CMD_HEAD_LENGTH + data_length; + } + //GTP_DEBUG("IIC_READ.addr:0x%4x, length:%d, ret:%d", addr, data_length, err); + //GTP_DEBUG_ARRAY((&data[CMD_HEAD_LENGTH]), data_length); + + return err; +} + +static s32 io_iic_write(u8 * data) +{ + s32 err = ERROR; + s32 data_length = 0; + u16 addr = 0; + + addr = data[0] << 8 | data[1]; + data_length = data[2] << 8 | data[3]; + + err = gt1x_i2c_write(addr, &data[CMD_HEAD_LENGTH], data_length); + if (!err) { + err = CMD_HEAD_LENGTH + data_length; + } + + //GTP_DEBUG("IIC_WRITE.addr:0x%4x, length:%d, ret:%d", addr, data_length, err); + //GTP_DEBUG_ARRAY((&data[CMD_HEAD_LENGTH]), data_length); + return err; +} + +//@return, 0:operate successfully +// > 0: the length of memory size ioctl has accessed, +// error otherwise. +static long gt1x_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + u32 value = 0; + s32 ret = 0; //the initial value must be 0 + u8 *data = NULL; + int cnt = 30; + + /* Blocking when firmwaer updating */ + while (cnt-- && update_info.status) { + ssleep(1); + } + + //GTP_DEBUG("IOCTL CMD:%x", cmd); + /* GTP_DEBUG("command:%d, length:%d, rw:%s", + _IOC_NR(cmd), + _IOC_SIZE(cmd), + (_IOC_DIR(cmd) & _IOC_READ) ? "read" : (_IOC_DIR(cmd) & _IOC_WRITE) ? "write" : "-"); + */ + + if (_IOC_DIR(cmd)) { + s32 err = -1; + s32 data_length = _IOC_SIZE(cmd); + data = (u8 *) kzalloc(data_length, GFP_KERNEL); + memset(data, 0, data_length); + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + err = copy_from_user(data, (void __user *)arg, data_length); + if (err) { + GTP_ERROR("Can't access the memory."); + kfree(data); + return -1; + } + } + } else { + value = (u32) arg; + } + + switch (cmd & NEGLECT_SIZE_MASK) { + case IO_GET_VERISON: + if ((u8 __user *) arg) { + ret = copy_to_user(((u8 __user *) arg), IO_VERSION, sizeof(IO_VERSION)); + if (!ret) { + ret = sizeof(IO_VERSION); + } + GTP_INFO("%s", IO_VERSION); + } + break; + case IO_IIC_READ: + ret = io_iic_read(data, (void __user *)arg); + break; + + case IO_IIC_WRITE: + ret = io_iic_write(data); + break; + + case IO_RESET_GUITAR: + gt1x_irq_disable(); + gt1x_reset_guitar(); + gt1x_irq_enable(); + break; + + case IO_DISABLE_IRQ: + gt1x_irq_disable(); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + break; + + case IO_ENABLE_IRQ: + gt1x_irq_enable(); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + break; + + //print a string to syc log messages between application and kernel. + case IO_PRINT: + if (data) + GTP_INFO("%s", (char *)data); + break; + +#if GTP_GESTURE_WAKEUP + case GESTURE_ENABLE: + GTP_DEBUG("Gesture switch ON."); + gesture_enabled = 1; + break; + + case GESTURE_DISABLE: + GTP_DEBUG("Gesture switch OFF."); + gesture_enabled = 0; + break; + + case GESTURE_FLAG_SET: + SETBIT(gestures_flag, (u8) value); + GTP_DEBUG("Gesture flag: 0x%02X enabled.", value); + break; + + case GESTURE_FLAG_CLEAR: + CLEARBIT(gestures_flag, (u8) value); + GTP_DEBUG("Gesture flag: 0x%02X disabled.", value); + break; + + case GESTURE_DATA_OBTAIN: + GTP_DEBUG("Obtain gesture data."); + mutex_lock(&gesture_data_mutex); + ret = copy_to_user(((u8 __user *) arg), &gesture_data.data, 4 + gesture_data.data[1] * 4 + gesture_data.data[3]); + if (ret) { + GTP_ERROR("ERROR when copy gesture data to user."); + ret = ERROR_MEM; + } else { + ret = 4 + gesture_data.data[1] * 4 + gesture_data.data[3]; + } + mutex_unlock(&gesture_data_mutex); + break; + + case GESTURE_DATA_ERASE: + GTP_DEBUG("ERASE_GESTURE_DATA"); + gesture_clear_wakeup_data(); + break; +#endif // GTP_GESTURE_WAKEUP + +#if GTP_HOTKNOT + case HOTKNOT_VENDOR_VERSION: + ret = copy_to_user(((u8 __user *) arg), HOTKNOT_VERSION, sizeof(HOTKNOT_VERSION)); + if (!ret) { + ret = sizeof(HOTKNOT_VERSION); + } + break; + case HOTKNOT_LOAD_HOTKNOT: + ret = hotknot_load_hotknot_subsystem(); + break; + + case HOTKNOT_LOAD_AUTHENTICATION: +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + ret = hotknot_load_authentication_subsystem(); + break; + + case HOTKNOT_RECOVERY_MAIN: + ret = hotknot_recovery_main_system(); + break; +#if HOTKNOT_BLOCK_RW + case HOTKNOT_DEVICES_PAIRED: + hotknot_paired_flag = 0; + force_wake_flag = 0; + block_enable = 1; + ret = hotknot_block_rw(HN_DEVICE_PAIRED, (s32) value); + break; + + case HOTKNOT_MASTER_SEND: + ret = hotknot_block_rw(HN_MASTER_SEND, (s32) value); + if (!ret) + ret = got_hotknot_extra_state; + break; + + case HOTKNOT_SLAVE_RECEIVE: + ret = hotknot_block_rw(HN_SLAVE_RECEIVED, (s32) value); + if (!ret) + ret = got_hotknot_extra_state; + break; + + case HOTKNOT_MASTER_DEPARTED: + ret = hotknot_block_rw(HN_MASTER_DEPARTED, (s32) value); + break; + + case HOTKNOT_SLAVE_DEPARTED: + ret = hotknot_block_rw(HN_SLAVE_DEPARTED, (s32) value); + break; + + case HOTKNOT_WAKEUP_BLOCK: + hotknot_wakeup_block(); + break; +#endif //HOTKNOT_BLOCK_RW +#endif //GTP_HOTKNOT + + default: + GTP_INFO("Unknown cmd."); + ret = -1; + break; + } + + if (data != NULL) { + kfree(data); + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long gt1x_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *arg32 = compat_ptr(arg); + + if (!file->f_op || !file->f_op->unlocked_ioctl) + return -ENOTTY; + + return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); +} +#endif + +static const struct file_operations gt1x_fops = { + .owner = THIS_MODULE, +#if GTP_GESTURE_WAKEUP + .read = gt1x_gesture_data_read, + .write = gt1x_gesture_data_write, +#endif + .unlocked_ioctl = gt1x_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gt1x_compat_ioctl, +#endif +}; + +#if GTP_HOTKNOT +static const struct file_operations hotknot_fops = { + .open = hotknot_open, + .release = hotknot_release, + .unlocked_ioctl = gt1x_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gt1x_compat_ioctl, +#endif +}; + +static struct miscdevice hotknot_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = HOTKNOT_NODE, + .fops = &hotknot_fops, +}; +#endif + +s32 gt1x_init_node(void) +{ +#if GTP_GESTURE_WAKEUP + struct proc_dir_entry *proc_entry = NULL; + mutex_init(&gesture_data_mutex); + memset(gestures_flag, 0, sizeof(gestures_flag)); + memset((u8 *) & gesture_data, 0, sizeof(st_gesture_data)); + + proc_entry = proc_create(GESTURE_NODE, 0666, NULL, >1x_fops); + if (proc_entry == NULL) { + GTP_ERROR("CAN't create proc entry /proc/%s.", GESTURE_NODE); + return -1; + } else { + GTP_INFO("Created proc entry /proc/%s.", GESTURE_NODE); + } +#endif + +#if GTP_HOTKNOT + if (misc_register(&hotknot_misc_device)) { + GTP_ERROR("CAN't create misc device in /dev/hotknot."); + return -1; + } else { + GTP_INFO("Created misc device in /dev/hotknot."); + } +#endif + return 0; +} + +void gt1x_deinit_node(void) +{ +#if GTP_GESTURE_WAKEUP + remove_proc_entry(GESTURE_NODE, NULL); +#endif + +#if GTP_HOTKNOT + misc_deregister(&hotknot_misc_device); +#endif +} diff --git a/drivers/input/touchscreen/gt1xx/gt1x_firmware.h b/drivers/input/touchscreen/gt1xx/gt1x_firmware.h new file mode 100755 index 00000000000..268f8949810 --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x_firmware.h @@ -0,0 +1,551 @@ +/* drivers/input/touchscreen/gt1x_firmware.h + * + * 2010 - 2014 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ + +#ifndef _GT1X_FIRMWARE_H_ +#define _GT1X_FIRMWARE_H_ + +unsigned char gt1x_default_FW[] = +{ +}; + +#if GTP_HOTKNOT +unsigned char gt1x_patch_jump_fw[] = { + 0xa8,0x3f,0x06,0xec,0xd9,0x50,0xf5,0xbf,0xb9,0xc2,0xec,0x5c,0x94,0x2c,0xd0,0xc0, + 0x56,0x1b,0x01,0xaa,0xea,0x04,0xe0,0xa8,0x36,0x37,0xd4,0xbf,0x33,0xfe,0xea,0x9e, + 0x7b,0xf0,0x20,0x46,0x80,0x73,0x6b,0x4e,0x3f,0x27,0x51,0x1e,0x3d,0x80,0x05,0x01, + 0x2d,0xee,0x85,0x0f,0xa9,0x87,0x11,0x29,0x24,0xef,0x2c,0x47,0xc0,0x75,0x24,0xac, + 0x41,0xb6,0x31,0x8c,0x3f,0xa3,0x95,0x98,0x50,0xe2,0x51,0x2d,0x9a,0xcb,0x14,0x6e, + 0xb7,0x17,0xc1,0x85,0x2e,0x04,0x5d,0xa9,0xc5,0x0d,0x8a,0x46,0x59,0x69,0x13,0x55, + 0xfb,0xbf,0x92,0xcb,0xc2,0xc0,0x63,0xdc,0x0a,0x94,0xfd,0x09,0x76,0x5c,0xd2,0xc6, + 0xf2,0x21,0x03,0x81,0x7f,0xa9,0xe9,0xae,0x5d,0x04,0xff,0x98,0x5a,0x70,0xc3,0xd7, + 0x09,0x0c,0xd1,0x7b,0xc4,0x88,0x81,0x2a,0xe1,0x36,0x78,0xbc,0x93,0x53,0xbf,0x04, + 0x30,0x9f,0xa5,0x01,0xa2,0x98,0x80,0x58,0xe0,0x30,0xb0,0x86,0xbe,0x7c,0x70,0x7b, + 0x39,0x8e,0x24,0x15,0xbb,0xf6,0x7d,0xab,0x06,0xc1,0xba,0xd7,0x28,0x5d,0x58,0xec, + 0x8f,0xef,0x09,0x2b,0xb4,0xff,0xdd,0xe6,0x42,0x79,0xae,0x4b,0x21,0x4d,0xd1,0xa4, + 0x62,0x88,0x0b,0x17,0x8d,0xc5,0x35,0x25,0xbc,0x47,0x2d,0x10,0x52,0x79,0x0a,0x4c, + 0x0b,0x2e,0x7d,0xd2,0x5b,0xde,0x8b,0xe5,0x17,0x2d,0xe8,0xf8,0xf5,0x90,0xd9,0x65, + 0xcf,0x3f,0xf6,0xf1,0xe7,0x10,0x49,0x6f,0xf3,0x22,0xb1,0x11,0x51,0x60,0xda,0x2c, + 0xe7,0x26,0xb8,0xbc,0x70,0xf7,0xd9,0xf1,0x31,0x5f,0x37,0xd9,0x1b,0x1f,0x98,0x80, + 0xeb,0xf2,0xa0,0x60,0x7b,0x06,0xb8,0x1c,0x15,0x54,0xe3,0x54,0x8e,0x24,0x21,0x7b, + 0x4c,0xb0,0x20,0x15,0xec,0x97,0xf0,0x73,0x1c,0xb8,0x06,0x5e,0x5c,0xfe,0xc0,0x77, + 0x01,0x85,0xe0,0x02,0x45,0xcf,0x01,0xcb,0x93,0x49,0x96,0x99,0x43,0x27,0x78,0x7e, + 0x6d,0xd7,0xcc,0x9e,0xa4,0xe7,0x33,0x17,0x44,0x09,0x04,0xac,0xb9,0xe7,0x52,0x75, + 0x51,0xfd,0xc9,0x50,0x1d,0xfa,0x22,0x63,0xc2,0x46,0x09,0x64,0xab,0x06,0xf0,0x3c, + 0xe8,0xab,0x80,0xd5,0x7e,0x66,0xf6,0x28,0xc7,0x3c,0xc3,0x1f,0xa4,0x76,0x72,0x10, + 0x7b,0xe9,0xd4,0xb9,0x9c,0xf4,0xc6,0xa4,0xf1,0xd9,0xf4,0x24,0xc7,0x97,0x51,0x13, + 0xf7,0x59,0x80,0x50,0xa2,0x25,0xed,0x4f,0x88,0x27,0x4d,0x66,0xdf,0x17,0x71,0x7f, + 0xdd,0x89,0xa6,0x11,0xa8,0x6e,0xba,0x1c,0x17,0xde,0x5b,0x10,0xb2,0xef,0x7e,0x64, + 0xd9,0x38,0xc0,0x29,0xee,0x9f,0xfc,0x36,0xe4,0x3c,0xf0,0x7d,0x5e,0xf6,0x98,0x7f, + 0x74,0xae,0x57,0x90,0x2b,0x09,0x29,0x27,0xb8,0x5f,0xf8,0xa7,0xae,0x2f,0x70,0xd6, + 0x45,0x04,0x5e,0x96,0xef,0x9e,0x38,0x79,0xb3,0x51,0x97,0x9d,0xbb,0xeb,0x5a,0x7d, + 0xc4,0xca,0xd6,0x07,0xb1,0xc3,0xae,0x37,0xea,0xd5,0xaa,0x36,0x42,0x8e,0x3b,0x6c, + 0xb4,0x50,0xca,0xde,0x4a,0x2a,0x6f,0x14,0x25,0x5b,0x74,0x04,0xa6,0x7e,0x7e,0x06, + 0xcb,0x39,0xea,0xdf,0x14,0x7e,0xdf,0x26,0x3b,0xe9,0x13,0x5f,0xaf,0x8f,0xb9,0x91, + 0xb5,0xd8,0x30,0x04,0x99,0x08,0x01,0xfb,0xf2,0x47,0xd1,0x07,0x85,0xfc,0x58,0x79, + 0xd8,0x0a,0xdb,0x0f,0xe1,0xe6,0xcf,0x60,0x31,0xd6,0x4c,0x5d,0xb1,0x50,0x35,0x92, + 0x9c,0xf8,0x46,0x61,0x12,0xf8,0x05,0x6c,0x01,0x52,0x4f,0x40,0x05,0xa4,0x47,0xbc, + 0x01,0x2a,0x65,0xe4,0x81,0xc9,0xa7,0x31,0x69,0x17,0x3d,0x43,0x4b,0x06,0x27,0x8c, + 0x3b,0x0b,0x14,0xef,0x54,0x93,0x0c,0x87,0x40,0x53,0x83,0x42,0xa3,0x35,0x17,0xe7, + 0x82,0xb9,0xf3,0x96,0x2b,0x4b,0x89,0xa9,0x42,0x86,0xc7,0x23,0x88,0x04,0x15,0x9b, + 0x7f,0xa1,0x83,0x28,0x6a,0x66,0x44,0xe9,0xaf,0x85,0x96,0x46,0x80,0x51,0xf6,0x6f, + 0x83,0xb9,0x6f,0xb7,0x31,0xeb,0x82,0x9e,0x0e,0xe4,0xa2,0x05,0x89,0x05,0x95,0x59, + 0x78,0xeb,0x6c,0xe3,0x05,0x6d,0xb2,0x81,0x4f,0x00,0x6c,0xec,0x0e,0x95,0x76,0x6d, + 0xf6,0x58,0x4f,0x78,0x8d,0x61,0xc5,0x34,0x72,0xca,0x56,0xd3,0xba,0x62,0x6f,0x7b, + 0x22,0x0a,0xee,0x43,0xfb,0x65,0x4c,0xa2,0xe0,0x98,0xcd,0xcb,0xc5,0xba,0xc4,0xcd, + 0x29,0x2b,0x1d,0xee,0x1a,0x55,0x9a,0x46,0xe0,0xdf,0xcc,0xda,0x09,0xd5,0xcc,0x27, + 0x0b,0x1a,0xc8,0x44,0x32,0xf7,0x94,0x66,0x62,0x87,0xaa,0xcb,0x7b,0x68,0xef,0x56, + 0x5a,0xb1,0x3d,0x24,0x84,0x3c,0x25,0x41,0x1b,0xcb,0x04,0x4c,0x1d,0x8c,0xdc,0xe4, + 0x47,0x77,0xae,0x12,0x84,0x02,0xa7,0x34,0x98,0x6b,0xd9,0x2d,0x82,0x59,0xfe,0x67, + 0xd9,0x7b,0x0f,0xcc,0xca,0xfa,0xe7,0x1a,0xdd,0x4e,0x43,0xdc,0x33,0x0d,0x9d,0x31, + 0x54,0x23,0x74,0x22,0x21,0xad,0x2a,0x06,0xbb,0x79,0x6a,0xb2,0x06,0x9d,0x7e,0x65, + 0xc0,0xa5,0x05,0xb0,0x8d,0xec,0x32,0x8c,0x75,0xd4,0x05,0xd4,0x90,0xe1,0x72,0xec, + 0x3a,0xf0,0x04,0x84,0x17,0x74,0x71,0x7c,0x5d,0xf2,0x61,0xf9,0x7c,0xfd,0x6f,0x2c, + 0xa6,0xdc,0xe7,0x9e,0x28,0x03,0x2d,0x80,0x4c,0xdd,0x85,0xd6,0x8c,0x23,0x6d,0x8a, + 0x25,0x39,0x44,0xf5,0xec,0x77,0xbd,0x73,0xf2,0xcc,0x85,0x4c,0xc5,0xa3,0x10,0xe1, + 0xb7,0xb4,0xd1,0x84,0xc8,0x5f,0xe0,0x99,0x7f,0x2a,0xbb,0xda,0xf8,0x88,0xd7,0x7e, + 0x69,0x91,0x69,0xb9,0x81,0xc8,0xf5,0xc3,0x73,0x57,0xaf,0x7d,0xc1,0x94,0x34,0x2a, + 0xdf,0x3c,0x82,0xba,0x9c,0x4d,0xbc,0x8f,0xca,0xcd,0x59,0xbe,0x8a,0x05,0x74,0xde, + 0x2b,0xd0,0xfb,0x97,0x2e,0xc0,0x0e,0x6b,0x00,0xf7,0x98,0xdd,0x85,0x95,0xb4,0x48, + 0x92,0x64,0xcd,0xfe,0xff,0xdb,0xd9,0x31,0xc9,0xd4,0x0e,0x27,0xee,0xaf,0x38,0xe3, + 0x9a,0xd0,0xe4,0xdd,0x95,0x77,0x3c,0x54,0xc1,0xc4,0x07,0xc8,0xff,0xea,0x5e,0x64, + 0x93,0x61,0x4d,0xfc,0xa5,0x07,0xf9,0xb1,0xcc,0xd4,0x84,0xeb,0x39,0xd9,0x9d,0x7a, + 0x06,0xd5,0x64,0xff,0x54,0x96,0x50,0xa0,0xc4,0x3f,0x74,0x23,0x85,0x57,0xbc,0x34, + 0x4a,0xce,0xa6,0x4d,0xa8,0xe6,0xe1,0x28,0x25,0x75,0xde,0xf6,0x8e,0x6c,0x7b,0xbc, + 0x7a,0x99,0x43,0xb1,0x54,0x9a,0x0e,0x95,0x19,0x52,0x84,0x4a,0x9e,0xba,0x3b,0xf0, + 0x67,0x88,0xce,0xb2,0xd3,0xc4,0xe6,0x49,0xc3,0xab,0x32,0x98,0xcf,0x3f,0x05,0xf1, + 0xaa,0x98,0xd3,0xb6,0x8a,0xe6,0xe3,0xb8,0x8d,0x35,0xc7,0xdd,0xb5,0x04,0x5c,0xf9, + 0x88,0x0c,0xa1,0x8a,0xb8,0xff,0xf9,0x23,0xd4,0x80,0xe1,0x30,0xe8,0x27,0x9e,0x21, + 0x8b,0x72,0x42,0xbe,0xe5,0x65,0x73,0xbe,0x52,0xcb,0xe2,0x4c,0xa2,0xc7,0x77,0xce, + 0x7e,0xe3,0x02,0x4a,0x9f,0xa4,0x96,0x3e,0x71,0x65,0x98,0x4f,0x32,0x85,0x0c,0x41, + 0x71,0x93,0x84,0x23,0xb6,0x6d,0x12,0x67,0x13,0x30,0x62,0x02,0x4d,0x72,0x38,0x00, + 0x28,0x47,0xa1,0x46,0x38,0xac,0xc2,0x69,0x09,0x7a,0xe5,0x5f,0x10,0x33,0x9a,0xe9, + 0x60,0x56,0xa2,0xfa,0x80,0x58,0x15,0x19,0x77,0x16,0xcd,0x9a,0xf6,0x73,0x9a,0x6a, + 0x68,0xb3,0x03,0x62,0x3e,0x02,0x50,0x27,0x72,0x07,0x3d,0x40,0x0d,0x17,0x5c,0x03, + 0x77,0xe0,0xea,0xc4,0xec,0x27,0x30,0x6a,0x99,0x3a,0x5b,0x9a,0xf7,0x72,0x42,0xcb, + 0x3a,0xd8,0xff,0x07,0xea,0x0b,0xbb,0x2e,0x28,0xaa,0xc0,0x44,0xf0,0xac,0xb1,0x2b, + 0x6a,0x5c,0x41,0x04,0x8e,0x98,0x80,0x39,0x7a,0x3b,0xc0,0x44,0x92,0x38,0xd0,0xa0, + 0x3b,0x59,0x8c,0x05,0xa7,0x4e,0x39,0xab,0x6b,0x0e,0x6b,0x26,0x89,0x2f,0x1a,0x6e, + 0x41,0xe7,0x2a,0x06,0xa3,0x1a,0x18,0x6f,0x79,0xb9,0x4b,0x6f,0x5b,0x76,0x9e,0x66, + 0x82,0x02,0x91,0xa5,0xc0,0xaa,0x9a,0x91,0x2a,0x0e,0x0a,0x03,0x72,0x26,0xf9,0x09, + 0x22,0x5e,0x88,0x69,0x7b,0xbe,0xb7,0x22,0x05,0x58,0x38,0x4d,0xf4,0x7b,0xca,0xc1, + 0x96,0xb7,0x77,0xd7,0xa3,0x47,0xba,0xa5,0xeb,0xdb,0xea,0x33,0xfd,0x6a,0x13,0x61, + 0x33,0x2a,0xa5,0x8e,0xf1,0xb5,0xdd,0xe0,0x84,0xb9,0xbc,0x3b,0x7b,0x37,0xff,0xf8, + 0xc2,0xe2,0xdf,0x9c,0xbc,0x7f,0xd9,0x73,0x6a,0x01,0xe2,0x74,0x8a,0x10,0x19,0x93, + 0x5c,0xf2,0x3d,0x17,0xe1,0xe5,0x53,0xae,0x24,0x4b,0x01,0x11,0xf1,0x47,0x4b,0xd8, + 0xc1,0x04,0xe3,0x72,0x9b,0x20,0xb6,0x2e,0x3d,0xc3,0x13,0x37,0xeb,0x0d,0xf6,0x6e, + 0x85,0x90,0x00,0x99,0xb2,0xed,0x32,0x77,0xe0,0xc3,0x93,0x0c,0xcf,0x4a,0x86,0x73, + 0x6d,0x2a,0xa3,0x70,0xfe,0x83,0xe8,0x8b,0x6e,0x50,0xf2,0xfb,0xdc,0xf5,0x81,0xa9, + 0x72,0x65,0x4a,0x96,0x9c,0xa3,0x79,0x72,0x55,0xcc,0x88,0x11,0xa4,0x9f,0x92,0xa9, + 0x6d,0xc7,0x03,0xe9,0xff,0x5f,0x41,0xeb,0xf1,0x83,0x19,0xdd,0xb2,0x1b,0xae,0xd8, + 0x8d,0x9b,0x38,0xbe,0xa3,0xa7,0x3e,0xc1,0x67,0x41,0x69,0xf8,0xa2,0xd1,0x0a,0x68, + 0x79,0x6a,0x89,0x90,0xee,0x8b,0x9b,0x3e,0xa9,0x85,0x83,0x1c,0x29,0xdd,0x1e,0x3a, + 0xca,0x1d,0x27,0x93,0x0a,0x18,0xa0,0x29,0x26,0x4b,0x4f,0xe4,0xe0,0x10,0x90,0x4a, + 0x03,0x6b,0x55,0x96,0xa3,0xce,0x19,0xbb,0xac,0x05,0x03,0x3e,0xbe,0xf2,0x91,0x69, + 0x0b,0x39,0x08,0x6b,0xa7,0x9a,0x38,0x7f,0x0d,0xbc,0x12,0xd6,0x81,0x0c,0x06,0x86, + 0x93,0x36,0xd7,0xc5,0x39,0xbe,0xec,0xe3,0xf2,0x8a,0x9d,0xe1,0xa8,0x0e,0x8f,0xf8, + 0x36,0x28,0x6b,0xbc,0xf4,0x47,0xc0,0xb0,0xc9,0x0b,0xef,0xd0,0xe9,0x1e,0x10,0x72, + 0x2f,0xcf,0x29,0x7a,0x07,0x9a,0x64,0x52,0xcc,0x17,0x89,0x1f,0xc7,0x2b,0xa8,0xa1, + 0x9b,0x2a,0x85,0x92,0xac,0x27,0x3b,0x5f,0x0d,0xf3,0x00,0x3b,0xde,0x82,0x87,0x80, + 0x2a,0x06,0xa7,0x86,0x98,0xfd,0xfd,0x83,0x18,0x40,0x25,0xc4,0xce,0x96,0x52,0xfc, + 0xd3,0xf0,0xa4,0x09,0xc5,0x67,0x77,0x3e,0x0c,0x35,0xe4,0x5e,0x86,0x93,0x35,0xa1, + 0xa9,0x0a,0x25,0x08,0xbf,0xa3,0x92,0xbe,0x53,0x21,0xc5,0x82,0xcb,0x45,0x3f,0x41, + 0xa9,0xf1,0x07,0xcb,0x96,0x6f,0x16,0xe7,0x8d,0x51,0x3e,0x32,0x79,0x7d,0x66,0xee, + 0xe0,0xc6,0x97,0x9b,0x80,0x4c,0x36,0xa9,0xb0,0x20,0xcc,0x10,0xf0,0x6b,0xa0,0xe4, + 0x50,0xad,0xee,0x46,0x5c,0x34,0xf5,0xf0,0x55,0x17,0x41,0x99,0xda,0x89,0xaf,0xea, + 0x49,0x44,0x07,0xc2,0xfb,0x69,0xb7,0x06,0xe3,0x7c,0xaa,0x84,0xe4,0x18,0x0e,0xe9, + 0x77,0xe6,0x81,0x9b,0x68,0xd3,0x42,0x7b,0xaf,0x01,0xf4,0x53,0x69,0x05,0x06,0xf8, + 0x25,0x68,0x4f,0x57,0xca,0x09,0xbf,0xae,0xf2,0x61,0x4a,0xc5,0xcc,0x9a,0xb5,0x8b, + 0x52,0xe7,0x6c,0xcb,0x2a,0x9a,0x84,0xb9,0x3e,0xc1,0xac,0x5a,0xc3,0x5c,0xb6,0x0a, + 0x5b,0x69,0xcd,0xca,0x87,0x4c,0x3d,0x2b,0x4d,0x8b,0x35,0x4b,0xa1,0x2a,0xda,0xf6, + 0x80,0x0d,0x0f,0xc3,0x83,0x18,0x1c,0xef,0xfb,0x70,0x91,0xc6,0x85,0x8f,0xb4,0x48, + 0x0f,0x3b,0x38,0x53,0x3d,0x42,0x18,0x70,0x8a,0x82,0x9e,0x81,0xac,0x8c,0x4e,0x11, + 0x02,0x5d,0xac,0x20,0x42,0x8d,0xee,0xae,0x32,0x43,0xea,0x12,0x01,0x04,0x71,0x72, + 0xdc,0x37,0x0d,0xca,0x41,0x4d,0x27,0xef,0x8c,0x2c,0x0c,0xcc,0x64,0x90,0x2b,0x8d, + 0xbf,0x6b,0x83,0xcd,0x55,0x56,0x39,0x01,0x69,0x5f,0x24,0x8b,0x40,0xe4,0x2e,0xf9, + 0x44,0xc6,0x6c,0x9d,0x9c,0x7d,0xdd,0xd3,0x67,0x26,0xfd,0x20,0xaa,0x13,0x72,0xec, + 0x26,0x93,0x86,0x97,0xc1,0xe7,0x57,0x2e,0x6c,0xc3,0x4f,0x78,0x69,0x32,0xec,0x3b, + 0x6f,0x78,0x07,0x9f,0xbb,0x27,0xb2,0xae,0x0d,0x50,0xca,0x7f,0x1a,0xd6,0xc6,0x5d, + 0xa5,0x07,0x04,0x6c,0x92,0xef,0x36,0xf7,0xed,0xc2,0xcb,0x7c,0x95,0xb0,0x74,0xb7, + 0x32,0x66,0xcd,0xd7,0x24,0x91,0xe8,0xb7,0xcf,0x00,0xc3,0x54,0xcb,0x43,0x8d,0xfc, + 0x4d,0xf2,0x86,0x1c,0x0b,0x29,0xd6,0x63,0x51,0x97,0x61,0xa9,0x92,0x14,0xd0,0xb4, + 0x51,0xd8,0x82,0x90,0x8b,0xd2,0x3b,0x3b,0x8d,0xe1,0x73,0x94,0x73,0x6d,0xf5,0x36, + 0x23,0xb3,0xa3,0xba,0x16,0xf3,0x07,0xf3,0x2c,0x0a,0xe5,0x2c,0x51,0x7d,0x0c,0x07, + 0x76,0xe8,0x30,0x9e,0xce,0x89,0x9f,0xbe,0x64,0x28,0xe4,0xd4,0x8e,0x51,0x95,0x7b, + 0x51,0x78,0x8c,0x11,0xac,0x7c,0xbf,0x9d,0xa9,0x3e,0xf4,0x9b,0xd3,0xcf,0x4b,0x26, + 0xaf,0x82,0x0d,0x10,0x83,0xcc,0x1d,0x3b,0x0f,0x51,0x40,0xd7,0xa9,0x1e,0xfa,0xe6, + 0x2b,0x79,0x50,0xf7,0x87,0xfd,0xdf,0xbb,0x17,0xbc,0x6c,0x9f,0x00,0xc3,0x7e,0xbf, + 0xb0,0xed,0x8f,0x15,0xc0,0xc9,0x9d,0xb2,0xe6,0x16,0xfe,0x9e,0x98,0x0c,0xcb,0xbd, + 0xb8,0x5e,0xb6,0xeb,0x40,0xcd,0x39,0x51,0xc1,0x1c,0xed,0xc9,0xf8,0x1c,0xfd,0xf5, + 0x29,0xab,0xaa,0xb3,0x43,0x0d,0x3a,0xfc,0xdc,0x4d,0xdd,0x6a,0x97,0xaf,0xe3,0x75, + 0x55,0x33,0xe9,0x50,0xc9,0x5b,0x72,0x1b,0xaf,0x19,0x0e,0xcd,0x76,0x8d,0x5c,0xbe, + 0xc0,0x5b,0x37,0x06,0xfe,0x02,0xf9,0x23,0x36,0xc2,0xc2,0x43,0x00,0xcc,0x55,0xad, + 0x0a,0xf2,0x83,0x62,0xf7,0x96,0x99,0x2d,0x78,0x90,0xd9,0x4e,0x08,0xc4,0x52,0x90, + 0x51,0x14,0x21,0x8a,0x52,0xf6,0x1c,0x63,0xb0,0xc3,0x6c,0x4d,0x6a,0x2d,0x35,0x9d, + 0xd9,0x73,0xc2,0xdc,0xb1,0xa5,0x91,0xbc,0x79,0x91,0x45,0x4c,0xe7,0x33,0x30,0xe0, + 0x7b,0x30,0x82,0x82,0xb8,0xc6,0x82,0x24,0x06,0x5c,0xb1,0xb1,0x43,0x66,0xc7,0x26, + 0x6c,0x12,0xa2,0x5a,0x7c,0xb6,0xbf,0x2a,0xf5,0x57,0xbf,0x74,0x8b,0x70,0xce,0x00, + 0x61,0x81,0xfe,0x00,0xfb,0xa7,0x3e,0x29,0x44,0x5f,0xf2,0x04,0x7c,0x7f,0xd4,0x5a, + 0xfd,0x33,0x3c,0xa6,0x96,0x45,0x6c,0xfc,0xea,0x59,0xc5,0xeb,0x82,0xf7,0xa8,0x7d, + 0x7a,0x8a,0x0d,0xf1,0x3d,0x35,0xf3,0x6c,0xa6,0xca,0xca,0x4b,0x37,0xdf,0xd4,0x29, + 0x82,0x64,0xaa,0x0f,0x1a,0xf4,0x54,0xe4,0x90,0xda,0xcb,0x4a,0x98,0xde,0x7d,0x2b, + 0x59,0x08,0x2b,0x0c,0x38,0xb5,0x73,0x4e,0x37,0xcb,0x4a,0x49,0xf3,0x2e,0x59,0x67, + 0x83,0x61,0x68,0x04,0x74,0x2d,0x58,0x84,0x93,0x5b,0x8a,0x94,0xb6,0xd4,0x5b,0x4f, + 0x7a,0xb7,0x69,0x06,0xe3,0xc8,0xcf,0x6b,0x70,0xec,0xdf,0x4b,0x65,0x45,0xae,0x7d, + 0x6f,0xf4,0x0d,0x31,0xb2,0x7b,0x78,0x78,0x22,0x49,0x37,0xe2,0x7d,0x85,0x23,0x98, + 0xd6,0xba,0x0e,0x85,0xa3,0x47,0xda,0xd3,0x93,0x33,0x3f,0xc5,0x13,0x37,0x2f,0xf5, + 0x9f,0x68,0x2a,0x86,0xb3,0x7a,0x38,0xd4,0xcc,0x89,0x34,0xec,0xce,0x43,0xeb,0x2d, + 0x9f,0x7f,0xdf,0xef,0xfb,0xf7,0x04,0x93,0x14,0xa0,0xe2,0x33,0xe6,0xa4,0xef,0x32, + 0xcc,0xc7,0x54,0xee,0x3f,0xbc,0x15,0x37,0x1c,0xb0,0x61,0x51,0xb0,0xd6,0x8e,0xf0, + 0xfa,0x03,0x8e,0x01,0x16,0x7f,0x4c,0x03,0x04,0x25,0x2d,0x8b,0xb8,0x4c,0x72,0x56, + 0xf2,0x6e,0x5e,0x15,0xa9,0xc2,0x12,0xbe,0x9d,0xef,0x64,0xd2,0x8a,0x46,0x75,0xfe, + 0x57,0xcf,0x5a,0xb9,0x65,0xfc,0xae,0x85,0x41,0xde,0x52,0x15,0xb6,0xe6,0x71,0x47, + 0x72,0xe8,0x41,0xea,0x5f,0xd4,0x58,0xc4,0xd2,0x12,0xcf,0xd5,0x7c,0x87,0x51,0xa6, + 0x52,0xf1,0x01,0xe9,0x05,0x8a,0x1e,0x9d,0x35,0xe2,0xe3,0xdd,0xeb,0x44,0x8e,0xd9, + 0xb6,0xae,0xdb,0xa8,0x8d,0xa6,0xcb,0xb6,0x25,0xd6,0x80,0xae,0xa3,0xf2,0x72,0x13, + 0xd2,0xc8,0x2e,0xf4,0xdf,0xd8,0xdf,0x28,0x5e,0x5b,0xec,0x85,0xc4,0xb3,0x93,0x1c, + 0xf1,0x1a,0x07,0x91,0x98,0x39,0xd2,0x7d,0x26,0x88,0x6a,0xf6,0x3e,0xce,0x1b,0x4d, + 0x9c,0x76,0x57,0xe5,0x7d,0xa9,0x51,0x19,0x45,0xa2,0x03,0x3e,0xaf,0x9d,0xf9,0xd5, + 0xcf,0xce,0xdc,0xe4,0xb1,0x3d,0xd3,0x78,0xbf,0xcb,0x8b,0x6f,0x5f,0xf6,0xd7,0xfb, + 0xfd,0x70,0xd9,0xe9,0xbe,0x33,0xd3,0xad,0x2e,0xcf,0x09,0xd7,0xfe,0xea,0xdb,0x83, + 0xe3,0xff,0x2d,0x41,0xf0,0xe1,0xe5,0xe0,0x26,0x8a,0xc7,0x52,0xa5,0xdb,0xda,0xdc, + 0x52,0xf7,0x9a,0x5c,0x95,0x32,0x4d,0x52,0x2f,0xce,0x89,0x7e,0xb7,0xee,0x7b,0x73, + 0x3f,0x5d,0x7a,0xc2,0xd5,0xdf,0x08,0x92,0xeb,0xe9,0x48,0x59,0x0b,0x0e,0x7f,0xd2, + 0x40,0xa2,0x26,0x00,0x00,0x74,0x76,0x84,0x48,0xa0,0x6a,0xa0,0x9c,0x44,0xab,0xa2, + 0x10,0x42,0x0d,0x8e,0xf2,0x54,0x69,0x0e,0x32,0x3a,0xe6,0xc7,0xc6,0x30,0xb4,0x62, + 0x59,0x81,0xa6,0x8a,0xdf,0x00,0x35,0x7d,0xf1,0x7d,0x2c,0xcf,0x98,0x4c,0xb4,0xea, + 0xf6,0xfd,0x83,0x5f,0x09,0x65,0xf7,0x87,0x69,0x73,0x64,0x49,0x98,0xb3,0x4c,0x80, + 0xa5,0xbd,0x65,0x8a,0x3a,0xba,0x12,0xe6,0xe3,0x91,0x32,0xc0,0xdb,0xf9,0x72,0x30, + 0x4d,0xea,0x01,0xb9,0x1e,0xa6,0x1f,0xaa,0xed,0x4d,0x7f,0x10,0x28,0x6d,0x79,0x68, + 0x76,0xb0,0x02,0x0d,0x4a,0xeb,0x14,0xae,0xdf,0x59,0xf2,0x73,0xa1,0x78,0xfc,0x72, + 0xbd,0x43,0x24,0x8c,0xd3,0xbf,0xd1,0x68,0x68,0x77,0x5a,0xa2,0x99,0x74,0x56,0xe8, + 0x80,0x88,0x2e,0xc4,0xdc,0x09,0x38,0x07,0xed,0xc8,0xce,0x80,0xb0,0xcc,0x7f,0x88, + 0x23,0x0a,0xae,0x8f,0x8e,0x5d,0xbc,0xe8,0x5a,0x9f,0x2d,0x8b,0x9e,0x7c,0xfc,0x6e, + 0x19,0xe9,0x0e,0x82,0x07,0x70,0x3f,0xac,0xfc,0xaf,0x19,0x6f,0x73,0x64,0x1e,0xec, + 0xff,0xab,0x8b,0x67,0x95,0x32,0xf5,0x5a,0x95,0x47,0xcd,0xcb,0xbf,0x5d,0x71,0xe6, + 0x48,0xce,0x97,0x0a,0x22,0x10,0xcb,0xee,0x2d,0x2a,0x3d,0xf8,0x46,0x8c,0xdc,0xc8, + 0x7b,0x45,0x37,0x19,0x49,0x76,0xc3,0x9c,0xba,0x20,0x91,0x76,0xc2,0x81,0xd2,0x6b, + 0x43,0xf4,0xaa,0x5a,0x49,0x3a,0x1e,0xb1,0xc4,0x42,0x3a,0xdf,0xdb,0x0d,0x29,0x8b, + 0xfa,0x40,0xb3,0xdb,0xc8,0x73,0x47,0xde,0x73,0x83,0x5f,0x3a,0xbb,0x01,0xbe,0xeb, + 0xdb,0x7d,0xdb,0x96,0xda,0x81,0x10,0xc5,0x4a,0xa5,0xc5,0x91,0xcc,0x46,0x78,0xb2, + 0xb7,0x6d,0xda,0x6e,0xe4,0x6e,0xa9,0x4a,0x04,0x82,0x76,0x7e,0x94,0xd4,0x56,0x71, + 0xf1,0xdb,0xa2,0x7e,0x33,0xa9,0xd0,0x09,0x4d,0x21,0x6c,0x9e,0x98,0x35,0x76,0xd6, + 0xd2,0x11,0x8b,0x99,0x3d,0x6b,0x25,0xf2,0x9d,0xc1,0x87,0xd5,0x09,0xd5,0x94,0xf1, + 0x5a,0xfb,0x46,0x99,0x77,0xb6,0xb6,0xa2,0x78,0x99,0xc7,0x5e,0x24,0x5e,0x9d,0x90, + 0x3e,0x2d,0xcc,0x44,0xcf,0xe9,0x0f,0x60,0x72,0x90,0x26,0x95,0x94,0xf0,0xf4,0x91, + 0x1b,0xfe,0x4f,0x07,0xad,0x5e,0xb0,0xca,0x0a,0x01,0x64,0xd2,0xcd,0x19,0x0b,0x2f, + 0xc1,0xa0,0xdb,0x11,0xfc,0x53,0x76,0xb1,0x05,0xb5,0xed,0x99,0x85,0x75,0x7f,0xdb, + 0xe6,0xdd,0x59,0x67,0x19,0xb7,0xd7,0xfc,0x48,0xad,0xcd,0x99,0xee,0x7c,0x7a,0xc4, + 0x7e,0x8c,0xcc,0x96,0x3e,0xec,0xbf,0x9d,0xc1,0xc8,0x07,0x9a,0x86,0x44,0xd1,0xf4, + 0xd8,0x74,0x53,0x9c,0x9d,0x33,0x57,0xde,0x09,0x0e,0x8c,0xfa,0xea,0x2d,0x74,0xf6, + 0x9b,0x79,0x2f,0x98,0x87,0x7d,0x11,0xb4,0xc4,0xc8,0xc7,0x2a,0xc0,0xf8,0x3f,0xff, + 0x26,0xb9,0x5a,0x15,0x26,0x85,0x4c,0xfe,0xc1,0x6e,0xbb,0x76,0xce,0xfe,0xdd,0xf7, + 0x7d,0xa9,0x13,0x3c,0xf8,0xe3,0xd4,0x4c,0xbe,0xa4,0x31,0xdb,0xc6,0xee,0xdc,0xf9, + 0x47,0x59,0x2e,0x96,0x4a,0xe8,0xdd,0xbc,0xa8,0xeb,0x99,0x5e,0x80,0x6d,0x76,0xf2, + 0xf8,0x20,0x46,0xce,0xd5,0x6e,0xcb,0x10,0x77,0x5c,0x8c,0xff,0x89,0xdb,0x7d,0xb7, + 0xcc,0x62,0x43,0xdf,0xff,0x43,0xd2,0x22,0xd0,0x7e,0x44,0xbb,0xe8,0x46,0x13,0x1f, + 0x70,0x72,0x42,0x7e,0xa8,0xd4,0x6d,0x63,0x78,0x70,0x6f,0xca,0x58,0x6a,0x83,0x6c, + 0x79,0x63,0xc3,0xbd,0xba,0x75,0x10,0xa4,0x38,0xa5,0x15,0x86,0xe9,0xa7,0xd5,0x08, + 0x71,0x73,0xc2,0xec,0xa4,0x95,0x30,0x82,0x1d,0xd3,0x43,0x4b,0xd3,0xda,0x72,0x6e, + 0x45,0xdd,0xdb,0xf9,0x3f,0xbb,0xed,0xdb,0x5a,0x61,0xe1,0x4a,0x2f,0x9b,0xad,0x9b, + 0x73,0x80,0x0f,0x89,0x37,0xab,0xec,0xda,0xee,0x12,0xb4,0x43,0x27,0x8b,0xac,0x9a, + 0x6e,0x1b,0x77,0x9a,0x3e,0xba,0x6d,0xd9,0x39,0x45,0x40,0x4e,0x2e,0x9a,0x2d,0x99, + 0x9d,0xf4,0xc0,0x0b,0x36,0xaa,0x6c,0xd8,0x51,0x46,0x62,0x2b,0x26,0x8a,0x2c,0x98, + 0x7a,0x8a,0x0d,0x42,0xd6,0xff,0x9c,0xa5,0xa6,0x5a,0xeb,0xb3,0xd8,0xdb,0xfb,0x6e, + 0x32,0xc8,0xf2,0x06,0xb2,0xe7,0x9b,0x0d,0x7a,0x78,0xe5,0xc2,0xf9,0x5e,0x1a,0x16, + 0x3b,0xd9,0x7f,0x05,0xd5,0xad,0x73,0x4e,0xc4,0xad,0x1d,0x67,0x1b,0xe9,0xde,0xb6, + 0x33,0xc9,0x36,0x04,0xa3,0x7f,0x2e,0x4e,0x1f,0xdb,0xed,0xdf,0xe3,0x5f,0x9a,0x84, + 0xbd,0xca,0x0f,0xe7,0x3d,0xb3,0xe5,0xd3,0xb1,0x2f,0x94,0x44,0x2d,0x93,0xa5,0x93, + 0x32,0x23,0x89,0x45,0x35,0xa3,0xe4,0xd2,0xf6,0xb8,0xe8,0x0c,0x25,0x83,0xa4,0x92, + 0x7b,0x99,0xf4,0xf6,0x3c,0xb2,0x65,0xd1,0xd7,0xae,0x4a,0x6e,0x2c,0x92,0x25,0x91, + 0xd7,0xbb,0xaf,0x09,0x34,0xa2,0x64,0xd0,0x63,0xa9,0x3c,0x40,0x24,0x82,0x24,0x90, + 0x05,0x62,0xa2,0x13,0xfc,0xa3,0xd1,0x3f,0xac,0x12,0x62,0x3d,0xce,0xde,0xd3,0x76, + 0x04,0xb5,0x80,0x9b,0x27,0x5e,0xb4,0xc4,0x45,0xae,0xc4,0xee,0xe4,0x93,0x12,0x2c, + 0x82,0xf3,0x03,0x14,0x45,0x47,0xb0,0x70,0x2f,0x49,0x34,0x1d,0x36,0xfb,0x93,0xae, + 0xf3,0x73,0x85,0xee,0x4d,0xce,0x0b,0x71,0x0b,0x10,0x0a,0x17,0xe5,0x37,0x25,0xbd, + 0x4c,0x76,0x83,0x9e,0x3b,0x3b,0xcd,0xcb,0xfb,0xc4,0xe0,0x57,0x2b,0x1b,0x8d,0x8b, + 0xcb,0x80,0x22,0x1a,0x33,0x2b,0xcc,0xca,0x24,0x92,0x20,0x8a,0x23,0x0b,0x8c,0x8a, + 0xbe,0x23,0x03,0x9c,0x3a,0x3a,0x4d,0xc9,0xa1,0x83,0xa3,0x76,0x2a,0x1a,0x0d,0x89, + 0x2d,0x91,0x41,0xca,0x32,0x2a,0x4c,0xc8,0x25,0xd5,0x61,0x5f,0x22,0x0a,0x0c,0x88, + 0x44,0xe8,0x2a,0x98,0x2a,0x1b,0x3e,0x44,0x2c,0x19,0x4a,0xf7,0xcc,0xf2,0xdb,0x1d, + 0xda,0xea,0x8a,0x1f,0xee,0xd8,0x0f,0xb4,0x60,0xbe,0x88,0xda,0x3d,0x7c,0x1a,0xa5, + 0x5f,0xc1,0x2a,0x12,0x7c,0x09,0x75,0xb5,0xb3,0xcb,0x88,0x50,0xcd,0xc2,0x5b,0x7c, + 0x07,0xbe,0x0a,0xe0,0xf7,0xba,0xf9,0x34,0xbe,0x4a,0x65,0x56,0xe7,0x9a,0x9a,0x82, + 0x3e,0xef,0xd7,0x13,0x39,0x33,0xc5,0xc3,0xa2,0x8a,0x95,0xd1,0x29,0x13,0x85,0x83, + 0x76,0x26,0xa9,0x39,0x31,0x23,0xc4,0xc2,0x64,0x03,0x98,0xa6,0x21,0x03,0x84,0x82, + 0xd7,0x4b,0x22,0x69,0x38,0x32,0x45,0xc1,0x2f,0x96,0x49,0x1f,0x28,0x12,0x05,0x81, + 0xbe,0xbb,0x50,0xa2,0x30,0x22,0x44,0xc0,0x5b,0x7d,0x3a,0xa7,0x20,0x02,0x04,0x80, + 0x18,0xd2,0xeb,0x8f,0x98,0x3b,0xff,0xe4,0x60,0x39,0x6e,0x4d,0xc8,0xa4,0x51,0xd9, + 0x62,0xe9,0xa6,0x8c,0x97,0xf4,0x97,0x85,0x9b,0x54,0xbe,0x30,0x72,0xb2,0x80,0x77, + 0x41,0x43,0x8a,0x8f,0x1a,0xab,0x7f,0xc6,0x68,0x3d,0x63,0xd9,0x8b,0xc5,0x56,0xaa, + 0x63,0xfc,0x26,0x85,0x85,0x75,0xd5,0xac,0xf9,0x78,0xe2,0xce,0x0d,0xb3,0x00,0x75, + 0x68,0xe5,0xe7,0x8b,0x1f,0xb9,0xe9,0x5b,0x48,0xb2,0xbd,0xcb,0x0f,0x99,0xa9,0x1b, + 0x62,0x53,0xa4,0x88,0x17,0xa9,0xe8,0x5a,0x00,0x10,0x06,0x85,0x07,0x89,0xa8,0x1a, + 0x01,0x03,0x20,0x8b,0x1e,0xb8,0x69,0x59,0xe1,0x01,0x87,0xe6,0x0e,0x98,0x29,0x19, + 0x23,0x4e,0xc6,0x82,0x16,0xa8,0x68,0x58,0x01,0x11,0x86,0x47,0x06,0x88,0x28,0x18, + 0x72,0x17,0x6f,0xa8,0xfa,0x59,0x9e,0x8c,0x49,0xda,0x4f,0x79,0x06,0xaa,0x91,0x31, + 0xdd,0x16,0xfe,0x8f,0x8a,0xa1,0x39,0xaf,0x9b,0xc9,0xc1,0x54,0x2a,0xbc,0x89,0xa3, + 0x5b,0x79,0x73,0x7a,0x8b,0x6d,0xdc,0xa5,0x4d,0x2d,0x2d,0x49,0xb3,0x2f,0xdc,0xea, + 0x23,0x3e,0x2c,0x03,0x0b,0x8c,0xfe,0xa5,0x43,0x5d,0x8d,0x84,0xe1,0x61,0x7e,0x8e, + 0x1a,0xc8,0x0f,0x8b,0x1d,0xb1,0xe1,0x53,0x0a,0x4e,0xaf,0x53,0x0d,0x91,0xa1,0x13, + 0x12,0x7e,0x8d,0x85,0x15,0xa1,0xe0,0x52,0x42,0x42,0xbc,0x70,0x05,0x81,0xa0,0x12, + 0xd8,0xa9,0x22,0x73,0x1c,0xb0,0x61,0x51,0x34,0xef,0x57,0xc5,0x0c,0x90,0x21,0x11, + 0x9d,0x29,0x2c,0x89,0x14,0xa0,0x60,0x50,0x23,0x8d,0x12,0x52,0x04,0x80,0x20,0x10, + 0xa7,0x80,0x02,0x96,0x64,0xd8,0xd9,0x1b,0x4f,0x26,0xfd,0xdb,0xcc,0x82,0xdf,0xf7, + 0x4c,0xd6,0x18,0x11,0xcc,0xd6,0x92,0x3a,0xc4,0xd4,0x87,0xd3,0x04,0xfb,0xdf,0x54, + 0xad,0x42,0x45,0x9d,0xd4,0x9e,0x31,0xa7,0x0e,0x41,0x41,0x52,0x7b,0x59,0x1b,0x4f, + 0x55,0x11,0xa0,0x1a,0xa9,0x75,0x19,0xbc,0xd0,0x97,0x35,0xd0,0xb6,0x8b,0x35,0xb6, + 0x9b,0x40,0xa2,0xa9,0x1b,0x39,0xc9,0x4b,0xe4,0x60,0x67,0xb9,0x0b,0x19,0x89,0x0b, + 0xd3,0x30,0x58,0xb5,0x13,0x29,0xc8,0x4a,0x55,0xf2,0x43,0x94,0x03,0x09,0x88,0x0a, + 0xde,0x21,0x55,0xf3,0x1a,0x38,0x49,0x49,0xca,0x01,0xc2,0x96,0x0a,0x18,0x09,0x09, + 0xed,0x89,0xfa,0x9b,0x12,0x28,0x48,0x48,0xed,0x0c,0x18,0x28,0x02,0x08,0x08,0x08, + 0x1c,0x68,0xae,0xd0,0x0e,0xb0,0xbb,0xcd,0x11,0x0b,0x8d,0xde,0x61,0x4c,0x2f,0x5a, + 0x32,0x78,0xf0,0x24,0x84,0xba,0xbf,0xb1,0x46,0x38,0xe5,0xd5,0x34,0xf2,0x9c,0x54, + 0xec,0x69,0x2e,0xd2,0x4f,0xb5,0xba,0xe6,0x13,0xe9,0x4f,0xbf,0xe6,0xc8,0x8a,0xc2, + 0x80,0xc5,0x5c,0x47,0x6b,0xfd,0xfe,0x04,0x07,0x41,0x41,0xd6,0xac,0x09,0x7c,0x65, + 0x0e,0x3b,0xad,0x8e,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03, + 0x66,0x7d,0xce,0x92,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02, + 0xa7,0x95,0x7b,0x98,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01, + 0x0f,0x9a,0x23,0x92,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x54,0x3c, +}; + +unsigned char hotknot_transfer_fw[] = { + +}; + +unsigned char hotknot_auth_fw[] = { + 0xa8,0x3f,0x06,0xee,0xd9,0x50,0xf5,0xbf,0xb9,0xc2,0xec,0x5c,0x94,0x2c,0xd0,0xc0, + 0x56,0x1b,0x01,0xaa,0xea,0x04,0xe0,0xa8,0x36,0x37,0xd4,0xbf,0x33,0xfe,0xea,0x9e, + 0x7b,0xf0,0x20,0x46,0x80,0x73,0x6b,0x4e,0x3f,0x27,0x51,0x1e,0x3d,0x80,0x05,0x01, + 0x2d,0xee,0x85,0x0d,0xa9,0x87,0x11,0x29,0x24,0xef,0x2c,0x47,0xc0,0x75,0x24,0xac, + 0x41,0xb6,0x31,0x8c,0x3f,0xa3,0x95,0x98,0x50,0xe2,0x51,0x2d,0x9a,0xcb,0x14,0x6e, + 0xb7,0x17,0xc1,0x85,0x2e,0x04,0x5d,0xa9,0xc5,0x0d,0x8a,0x46,0x59,0x69,0x13,0x55, + 0xfb,0xbf,0x92,0xcb,0xc2,0xc0,0x63,0xdc,0x0a,0x94,0xfd,0x09,0x76,0x5c,0xd2,0xc6, + 0xf2,0x21,0x03,0x81,0x7f,0xa9,0xe9,0xae,0x5d,0x04,0xff,0x98,0x5a,0x70,0xc3,0xd7, + 0x09,0x0c,0xd3,0x53,0xc4,0x88,0x83,0x2a,0xe1,0x36,0x78,0xbc,0x93,0x53,0xbf,0x04, + 0x30,0x9f,0xa5,0x01,0xa2,0x98,0x82,0x58,0xe0,0x30,0xb0,0x86,0xbe,0x7c,0x70,0x7b, + 0x39,0x8e,0x24,0x15,0xbb,0xf6,0x7d,0xab,0x06,0xc1,0xba,0xd7,0x28,0x5d,0x58,0xec, + 0x8f,0xef,0x09,0x2b,0xb4,0xff,0xdd,0xe6,0x42,0x79,0xae,0x4b,0x21,0x4d,0xd1,0xa4, + 0x62,0x88,0x0b,0x17,0x8d,0xc5,0x35,0x25,0xbc,0x47,0x2d,0x10,0x52,0x79,0x0a,0x4c, + 0x0b,0x2e,0x7d,0xd2,0x5b,0xde,0x8b,0xe5,0x17,0x2d,0xe8,0xf8,0xb5,0xd1,0xd9,0x65, + 0xcf,0x3f,0xf6,0xf1,0xe7,0x10,0x49,0x6f,0xf3,0x22,0xb1,0x11,0x51,0x60,0xda,0x2c, + 0xe7,0x26,0xb8,0xbc,0x70,0xf7,0xd9,0xf1,0x31,0x5f,0x37,0xd9,0x1b,0x1f,0x98,0x80, + 0xeb,0xf2,0xa0,0x60,0x7b,0x06,0xb8,0x1c,0x15,0x54,0xe3,0x54,0x8e,0x24,0x21,0x7b, + 0x4c,0xb0,0x20,0x15,0xec,0x97,0xf0,0x73,0x1c,0xb8,0x06,0x5e,0x5c,0x7e,0xc0,0x77, + 0x01,0x85,0xe0,0x02,0x45,0x4f,0x01,0xcb,0x93,0x49,0x96,0x99,0x43,0x27,0x78,0x7e, + 0x6d,0x57,0xcc,0x9e,0xe4,0xe7,0x33,0x17,0x44,0x09,0x04,0xac,0xb9,0xe7,0x52,0x75, + 0x51,0xfd,0xc9,0x50,0x1d,0xfa,0x22,0x63,0xc2,0x46,0x09,0x64,0xab,0x06,0xf0,0x3c, + 0xe8,0xab,0x80,0xd5,0x7e,0x66,0xf6,0x28,0xc7,0x3c,0xc3,0x1f,0xa4,0x76,0x72,0x10, + 0x7b,0xe9,0xd4,0xb9,0x9c,0xf4,0xc6,0xa4,0xf1,0xd9,0xf4,0x24,0xc7,0x97,0x51,0x13, + 0xf7,0x59,0x80,0x50,0xa2,0x25,0xed,0x4f,0x88,0x27,0x4d,0x66,0xdf,0x17,0x71,0x7f, + 0xdd,0x89,0xa6,0x11,0xa8,0x6e,0xba,0x1c,0x17,0xde,0x5b,0x10,0xb2,0xef,0x7e,0x66, + 0xd9,0x38,0xc0,0x29,0xee,0x9f,0xfc,0x36,0xe4,0x3c,0xf2,0x7d,0x5e,0x76,0x98,0x7f, + 0x74,0xae,0x57,0x90,0x2b,0x09,0x2b,0x27,0xb8,0x5f,0xf8,0xa7,0xae,0x2f,0x70,0xd6, + 0x45,0x04,0x5e,0x96,0xef,0x9e,0x38,0x79,0xb3,0x51,0x97,0x9d,0xbb,0xeb,0x5a,0x7d, + 0xc4,0xca,0xd6,0x07,0xb1,0xc3,0xae,0x37,0xea,0xd5,0xaa,0x36,0x42,0x8e,0x3b,0x6c, + 0xb4,0x50,0xca,0xde,0x4a,0x2a,0x6f,0x14,0x25,0x5b,0x74,0x04,0xa6,0x7e,0x7e,0x06, + 0xcb,0x39,0xea,0xdf,0x14,0x7e,0xdf,0x26,0x3b,0xe9,0x13,0x5f,0xaf,0x8f,0xb9,0x91, + 0xb5,0xd8,0x30,0x04,0x99,0x08,0x01,0xfb,0xf2,0x47,0xd1,0x07,0x85,0xfc,0x58,0x79, + 0xd8,0x0a,0xdb,0x0f,0xe1,0xe6,0xcf,0x60,0x31,0xd6,0x4c,0x5d,0xb1,0x50,0x35,0x92, + 0x9c,0xf8,0x46,0x61,0x12,0xf8,0x05,0x6c,0x01,0x52,0x4f,0x40,0x05,0xa4,0x47,0xbc, + 0x01,0x2a,0x65,0xe4,0x81,0xc9,0xa7,0x31,0x69,0x17,0x3d,0x43,0x4b,0x06,0x27,0x8c, + 0x3b,0x0b,0x14,0xef,0x54,0x93,0x0e,0x87,0x40,0x53,0x83,0x42,0xa3,0x35,0x17,0xe7, + 0x82,0xb9,0xf3,0x96,0x2b,0x4b,0x89,0xa9,0x42,0x86,0xc7,0x23,0x88,0x04,0x15,0x9b, + 0x7f,0xa1,0x83,0x28,0x6a,0x66,0x44,0xe9,0xaf,0x85,0x96,0x46,0x80,0x51,0xf6,0x6f, + 0x83,0xb9,0x6f,0xb7,0x31,0xeb,0x82,0x9e,0x0e,0xe4,0xa2,0x05,0x89,0x05,0x95,0x59, + 0x78,0xeb,0x6c,0xe3,0x05,0x6d,0xb2,0x81,0x4f,0x00,0x6c,0xec,0x0e,0x95,0x76,0x6d, + 0xf6,0x58,0x4f,0x78,0x8d,0x61,0xc5,0x34,0x72,0xca,0x56,0xd3,0xba,0x62,0x6f,0x7b, + 0x22,0x0a,0xee,0x43,0xfb,0x65,0x4c,0xa2,0xe0,0x98,0xcd,0xcb,0xc5,0xba,0xc6,0xcd, + 0x29,0x2b,0x1d,0xee,0x1a,0x55,0x9a,0x44,0xe0,0xdf,0xcc,0xda,0x09,0xd5,0xcc,0x27, + 0x0b,0x1a,0xc8,0x44,0x32,0xf7,0x94,0x66,0x62,0x87,0xaa,0xcb,0x7b,0xe8,0xef,0x56, + 0x5a,0xb1,0x3d,0x24,0x84,0x3c,0x25,0x41,0x1b,0xcb,0x04,0x4c,0x1d,0x8c,0xdc,0xe4, + 0x07,0x77,0xae,0x12,0x84,0x02,0xa7,0x34,0x98,0x6b,0xd9,0x2d,0x82,0x59,0xfe,0x67, + 0xd9,0x7b,0x0f,0xcc,0xca,0xfa,0xe7,0x1a,0xdd,0x4e,0x43,0xdc,0x33,0x0d,0x9d,0x31, + 0x54,0x23,0x74,0x22,0x21,0xad,0x2a,0x06,0xbb,0x79,0x6a,0xb2,0x06,0x9d,0x7e,0x65, + 0xc0,0xa5,0x05,0xb0,0xcd,0xec,0x32,0x8e,0x75,0xd4,0x05,0xd4,0x90,0xe1,0x72,0xee, + 0x3a,0xf0,0x04,0x84,0x17,0x74,0x71,0x7c,0x5d,0xf2,0x61,0xf9,0x7c,0x7d,0x6f,0x2c, + 0xa6,0xdc,0xe7,0x9e,0x28,0x03,0x2f,0x80,0x4c,0xdd,0x85,0xd6,0x8c,0x23,0x6f,0x8a, + 0x25,0x39,0x44,0xf5,0xec,0x77,0xbd,0x73,0xf2,0xcc,0x85,0x4c,0xc5,0xa3,0x10,0xe1, + 0xb7,0xb4,0xd1,0x84,0xc8,0x5f,0xe0,0x99,0x7f,0x2a,0xbb,0xda,0xf8,0x88,0xd7,0x7e, + 0x69,0x91,0x69,0xb9,0x81,0xc8,0xf5,0xc3,0x73,0x57,0xaf,0x7d,0xc1,0x94,0x34,0x2a, + 0xdf,0x3c,0x82,0xba,0x9c,0x4d,0xbc,0x8f,0xca,0xcd,0x59,0xbe,0x8a,0x05,0x74,0xde, + 0x2b,0xd0,0xfb,0x97,0x2e,0xc0,0x0e,0x6b,0x00,0xf7,0x98,0xdd,0x85,0x95,0xb4,0x48, + 0x92,0x64,0xcd,0xfe,0xff,0xdb,0xd9,0x31,0xc9,0xd4,0x0e,0x27,0xee,0xaf,0x38,0xe3, + 0x9a,0xd0,0xe4,0xdd,0x95,0x77,0x3c,0x54,0xc1,0xc4,0x07,0xc8,0xff,0xea,0x5e,0x64, + 0x93,0x61,0x4d,0xfc,0xa5,0x07,0xf9,0xb1,0xcc,0xd4,0x84,0xeb,0x39,0xd9,0x9d,0x7a, + 0x06,0xd5,0x64,0xff,0x54,0x96,0x50,0xa0,0xc4,0x3f,0x76,0x23,0x85,0x57,0xbc,0x34, + 0x4a,0xce,0xa6,0x4d,0xa8,0xe6,0xe1,0x28,0x25,0x75,0xde,0xf6,0x8e,0x6c,0x7b,0xbc, + 0x7a,0x99,0x43,0xb1,0x54,0x9a,0x0e,0x95,0x19,0x52,0x84,0x4a,0x9e,0xba,0x3b,0xf0, + 0x67,0x88,0xce,0xb2,0xd3,0xc4,0xe6,0x49,0xc3,0xab,0x32,0x98,0xcf,0x3f,0x05,0xf1, + 0xaa,0x98,0xd3,0xb6,0x8a,0xe6,0xe3,0xb8,0x8d,0x35,0xc7,0xdd,0xb5,0x04,0x5c,0xf9, + 0x88,0x0c,0xa1,0x8a,0xb8,0xff,0xf9,0x23,0xd4,0x80,0xe1,0x30,0xe8,0x27,0x9e,0x21, + 0x8b,0x72,0x42,0xbe,0xe5,0x65,0x73,0xbe,0x52,0xcb,0xe2,0x4c,0xa2,0xc7,0x77,0xce, + 0x7e,0xe3,0x02,0x4a,0x9f,0xa4,0x96,0x3c,0x71,0x65,0x98,0x4f,0x32,0x85,0x0c,0x41, + 0x71,0x93,0x84,0x23,0xb6,0x6d,0x12,0x67,0x13,0x30,0x62,0x02,0x4d,0x72,0x38,0x00, + 0x28,0x47,0xa1,0x46,0x38,0xac,0xc2,0x69,0x09,0x7a,0xe5,0x5f,0x10,0xb3,0x9a,0xe9, + 0x60,0x56,0xa2,0xfa,0x80,0x58,0x15,0x1b,0x37,0xa6,0xcd,0x9a,0xf6,0x73,0x9a,0x6a, + 0x28,0xb3,0x03,0x62,0x3e,0x02,0x50,0x27,0x72,0x07,0x3d,0x40,0x0d,0x17,0x5c,0x03, + 0x77,0xe0,0xea,0xc4,0xec,0x27,0x30,0x6a,0x99,0xba,0x5b,0x9a,0xf7,0x72,0x42,0xcb, + 0x3a,0xd8,0xff,0x07,0xea,0x0b,0xbb,0x2e,0x28,0xaa,0xc0,0x44,0xf0,0xac,0xb1,0x2b, + 0x6a,0x5c,0x41,0x04,0x8e,0x98,0x82,0x39,0x7a,0x3b,0xc0,0x44,0x92,0x38,0xd0,0xa0, + 0x3b,0x59,0x8c,0x05,0xa7,0x4e,0x39,0xab,0x6b,0x0e,0x6b,0x26,0x89,0x2f,0x1a,0x6e, + 0x41,0xe7,0x2a,0x06,0xa3,0x1a,0x18,0x6f,0x79,0xb9,0x4b,0x6f,0x5b,0xf6,0x9e,0x66, + 0x82,0x82,0x91,0xa5,0xc0,0xaa,0x9a,0x91,0x2a,0x0e,0x0a,0x03,0x72,0x26,0xf9,0x09, + 0x22,0x5e,0x88,0x69,0x7b,0xbe,0xb7,0x22,0x05,0x58,0x38,0x4d,0xf4,0x7b,0xca,0xc1, + 0x96,0xb7,0x77,0xd7,0xa3,0x47,0xba,0xa5,0xeb,0xdb,0xea,0x33,0xfd,0x6a,0x13,0x61, + 0x33,0x2a,0xa5,0x8e,0xf1,0xb5,0xdd,0xe0,0x84,0xb9,0xbc,0x3b,0x7b,0x37,0xff,0xf8, + 0xc2,0xe2,0xdf,0x9c,0xbc,0x7f,0xd9,0x73,0x6a,0x01,0xe2,0x74,0x8a,0x10,0x19,0x93, + 0x5c,0xf2,0x3d,0x17,0xe1,0xe5,0x53,0xae,0x24,0x4b,0x01,0x11,0xf1,0x47,0x4b,0xd8, + 0xc1,0x04,0xe3,0x72,0x9b,0x20,0xb6,0x2c,0x3d,0xc3,0x13,0x37,0xeb,0x0d,0xf6,0x6c, + 0x85,0x90,0x00,0x99,0xb2,0xed,0x32,0x77,0xe0,0xc3,0x93,0x0c,0xcf,0x4a,0x86,0x73, + 0x2d,0x2a,0xa3,0x70,0xfe,0x83,0xe8,0x8b,0x6e,0x50,0xf2,0xfb,0xdc,0xf5,0x81,0xa9, + 0x72,0x65,0x4a,0x96,0x9c,0xa3,0x79,0x72,0x55,0xcc,0x88,0x11,0xa4,0x9f,0x92,0xa9, + 0x6d,0xc7,0x03,0xe9,0xff,0x5f,0x41,0xeb,0xf1,0x83,0x19,0xdd,0xb2,0x1b,0xae,0xd8, + 0x8d,0x1b,0x38,0xbe,0xa3,0xa7,0x3e,0xc1,0x67,0x41,0x69,0xf8,0xa2,0xd1,0x0a,0x68, + 0x79,0x6a,0x89,0x90,0xee,0x8b,0x9b,0x3e,0xa9,0x85,0x83,0x1c,0x29,0xdd,0x1e,0x3a, + 0xca,0x1d,0x27,0x93,0x0a,0x18,0xa2,0x29,0x26,0x4b,0x4f,0xe4,0xe0,0x10,0x90,0x4a, + 0x03,0x6b,0x55,0x96,0xa3,0xce,0x19,0xbb,0xac,0x05,0x03,0x3e,0xfe,0xf2,0x91,0x69, + 0x0b,0x39,0x08,0x6b,0xa7,0x9a,0x38,0x7f,0x0d,0xbc,0x12,0xd6,0x81,0x0c,0x06,0x86, + 0x93,0x36,0xd7,0xc5,0x39,0xbe,0xec,0xe3,0xf2,0x8a,0x9d,0xe1,0xa8,0x0e,0x8f,0xf8, + 0x36,0x28,0x6b,0xbc,0xf4,0x47,0xc0,0xb0,0xc9,0x0b,0xef,0xd0,0xe9,0x1e,0x10,0x72, + 0x2f,0xcf,0x29,0x7a,0x07,0x1a,0x64,0x52,0xcc,0x17,0x89,0x1f,0xc7,0x2b,0xa8,0xa1, + 0x9b,0x2a,0x85,0x92,0xac,0x27,0x3b,0x5f,0x0d,0xf3,0x00,0x3b,0xde,0x82,0x87,0x80, + 0x2a,0x06,0xa7,0x86,0x98,0xfd,0xfd,0x83,0x18,0x40,0x25,0xc4,0xce,0x96,0x52,0xfe, + 0xd3,0xf0,0xa4,0x09,0xc5,0x67,0x77,0x3e,0x0c,0x35,0xe4,0x5e,0x86,0x93,0x35,0xa1, + 0xa9,0x0a,0x25,0x08,0xbf,0xa3,0x92,0xbc,0x53,0x21,0xc5,0x82,0xcb,0x45,0x3f,0x41, + 0xa9,0xf1,0x07,0xcb,0x96,0x6f,0x16,0xe7,0x8d,0x51,0x3e,0x32,0x79,0xfd,0x66,0xee, + 0xe0,0xc6,0x95,0x9b,0x80,0x4c,0x36,0xa9,0xb0,0xa0,0xcc,0x10,0xf0,0x6b,0xa0,0xe4, + 0x50,0xad,0xee,0x46,0x5c,0x34,0xf5,0xf0,0x15,0x17,0x41,0x9b,0xda,0x89,0xaf,0xea, + 0x49,0x44,0x07,0xc2,0xfb,0x69,0xb7,0x06,0xe3,0x7c,0xaa,0x84,0xe4,0x18,0x0e,0xe9, + 0x77,0xe6,0x81,0x99,0x68,0xd3,0x40,0xeb,0xaf,0x01,0xf4,0x53,0x69,0x05,0x06,0xf8, + 0x25,0x68,0x4f,0x57,0xca,0x09,0xbf,0xae,0xf2,0xe1,0x4a,0xc5,0xcc,0x9a,0xb5,0x8b, + 0x52,0xe7,0x6c,0xcb,0x2a,0x9a,0x86,0xb9,0x3e,0xc1,0xac,0x5a,0xc3,0x5c,0xb6,0x0a, + 0x5b,0x69,0xcd,0xca,0x87,0x4c,0x3d,0x2b,0x4d,0x8b,0x35,0x4b,0xa1,0x2a,0xda,0xf4, + 0xc0,0xf7,0x0f,0xc3,0x83,0x18,0x1c,0xef,0xfb,0xf0,0x91,0xc6,0x85,0x8f,0xb4,0x48, + 0x0f,0x3b,0x38,0x53,0x3d,0x42,0x18,0x72,0x8a,0x82,0x9e,0x81,0xac,0x8c,0x4e,0x11, + 0x02,0x5d,0xac,0x20,0x42,0x8d,0xee,0xae,0x32,0x43,0xea,0x12,0x01,0x04,0x71,0x72, + 0xdc,0x37,0x0d,0xca,0x3a,0x4d,0x27,0xef,0x8c,0x2c,0x0c,0xcc,0x64,0x90,0x2b,0x8d, + 0xbf,0x6b,0x83,0xcd,0x55,0x56,0x39,0x01,0x69,0x5f,0x24,0x8b,0x40,0xe4,0x2e,0xf9, + 0x44,0xc6,0x6c,0x9d,0x9c,0x7d,0xdd,0xd3,0x67,0x26,0xff,0x20,0xaa,0x13,0x72,0xee, + 0x26,0x93,0x86,0x97,0xc1,0xe7,0x57,0x2e,0x6c,0xc3,0x4f,0x78,0x69,0x32,0xee,0x3b, + 0x6f,0x78,0x07,0x9f,0xbb,0x27,0xb2,0xac,0x0d,0x50,0xca,0x7f,0x1a,0xd6,0xc6,0x5d, + 0xa5,0x07,0x04,0x6c,0x92,0xef,0x36,0xf7,0xed,0xc2,0xcb,0x7c,0x95,0xb0,0x74,0xb7, + 0x32,0x66,0xcd,0xd7,0x24,0x11,0xe8,0xb7,0xcf,0x00,0xc3,0x54,0xcb,0x43,0x8d,0xfc, + 0x4d,0xf2,0x86,0x1c,0x0b,0x29,0xd6,0x63,0x11,0x97,0x61,0xab,0x92,0x14,0xd0,0xb4, + 0x51,0xd8,0x82,0x90,0x8b,0xd2,0x3b,0x3b,0x8d,0xe1,0x73,0x94,0x73,0x6d,0xf5,0x36, + 0x23,0xb3,0xa3,0xba,0x16,0xf3,0x07,0xf3,0x2c,0x0a,0xe5,0x2c,0x51,0x7d,0x0c,0x07, + 0x76,0xe8,0x30,0x9e,0xce,0x89,0x9f,0xbe,0x64,0x28,0xe4,0xd4,0x8e,0x51,0x95,0x7b, + 0x51,0x78,0x8c,0x11,0xac,0x7c,0xbf,0x9d,0xa9,0x3e,0xf6,0x9b,0xd3,0xcf,0x4b,0x26, + 0xaf,0x82,0x0d,0x10,0x83,0xcc,0x1d,0x3b,0x0f,0x51,0x40,0xd7,0xa9,0x1e,0xfa,0xe4, + 0x2b,0x79,0x50,0xf7,0x87,0xfd,0xdf,0xbb,0x17,0xbc,0x6c,0x9f,0x00,0xc3,0x7e,0xbf, + 0xb0,0xed,0x8f,0x15,0xc0,0xc9,0x9d,0xb2,0xe6,0x16,0xfe,0x9e,0x98,0x0c,0xcb,0xbd, + 0xb8,0x5e,0xb4,0xeb,0x00,0xcd,0x39,0x53,0xc1,0x1c,0xed,0xc9,0xf8,0x1c,0xfd,0xf5, + 0x29,0xab,0xaa,0xb3,0x43,0x0d,0x3a,0xfc,0x9c,0xdd,0xdd,0x6a,0x97,0xaf,0xe3,0x75, + 0x55,0x33,0xe9,0x50,0xc9,0x5b,0x70,0x1b,0xaf,0x19,0x0e,0xcd,0x76,0x8d,0x5c,0xbe, + 0xc0,0xdb,0x3e,0x06,0xfe,0x02,0xf9,0x23,0x36,0xc2,0xc2,0x43,0x00,0xcc,0x55,0xad, + 0x0a,0xf2,0x83,0x62,0xf7,0x96,0x99,0x2d,0x78,0x90,0xd9,0x4e,0x08,0xc4,0x52,0x90, + 0x51,0x14,0x21,0x8a,0x52,0xf6,0x1c,0x63,0xb0,0xc3,0x6c,0x4d,0x6a,0x2d,0x35,0x9d, + 0xd9,0x73,0xc2,0xdc,0xb1,0xa5,0x91,0xbc,0x79,0x91,0x45,0x4c,0xe7,0x33,0x30,0xe0, + 0x7b,0x30,0x82,0x82,0xb8,0xc6,0x82,0x24,0x06,0x5c,0xb1,0xb1,0x43,0x66,0xc7,0x26, + 0x6c,0x12,0xa2,0x5a,0x7c,0xb6,0xbf,0x2a,0xb5,0x57,0xbf,0x74,0x8b,0x70,0xcc,0x00, + 0x61,0x81,0xfe,0x00,0xfb,0xa7,0x3e,0x29,0x44,0x5f,0xf2,0x04,0x3c,0x7f,0xd4,0x58, + 0xfd,0x33,0x3c,0xa6,0x96,0x45,0x6c,0xfc,0xea,0x59,0xc5,0xe9,0x82,0xf7,0xa8,0x7d, + 0x7a,0x8a,0x0d,0xf1,0x3d,0x35,0xf3,0x6c,0xa6,0xca,0xca,0x4b,0x37,0xdf,0xd4,0x29, + 0x82,0x64,0xaa,0x0f,0x1a,0xf4,0x54,0xe4,0x90,0xda,0xcb,0x4a,0x98,0xde,0x7d,0x2b, + 0x59,0x08,0x2b,0x0c,0x38,0xb5,0x73,0x4e,0x37,0xcb,0x4a,0x49,0xf3,0x2e,0x59,0x67, + 0x83,0x61,0x68,0x04,0x74,0x2d,0x58,0x84,0x93,0x5b,0x8a,0x94,0xf6,0xd4,0x5b,0x4f, + 0x7a,0xb7,0x69,0x06,0xe3,0xc8,0xcd,0xe9,0x70,0xec,0xdd,0x4b,0x65,0x45,0xae,0x7d, + 0x6f,0xf4,0x0d,0x33,0xb2,0x7b,0x78,0x78,0x22,0x49,0x37,0xe2,0x7d,0x85,0x23,0x98, + 0xd6,0xba,0x0e,0x85,0xa3,0x47,0xda,0xd3,0x93,0xb3,0x3f,0xc5,0x13,0xb7,0x2f,0xf5, + 0x9f,0x68,0x2a,0x86,0xb3,0x7a,0x38,0xd4,0xcc,0x89,0x34,0xec,0xce,0x43,0xeb,0x2d, + 0x9f,0x7f,0xdf,0xef,0xfb,0xf7,0x04,0x93,0x14,0xa0,0xe2,0x33,0xe6,0xa4,0xef,0x32, + 0xcc,0x47,0x54,0xee,0x3f,0xbc,0x15,0x37,0x1c,0xb0,0x61,0x51,0xb0,0xd6,0x8e,0xf0, + 0xfa,0x03,0x8e,0x01,0x16,0x7f,0x4c,0x03,0x04,0x25,0x2f,0x8b,0xf8,0x4c,0x72,0x56, + 0xf2,0x6e,0x5e,0x15,0xa9,0xc2,0x12,0xbe,0x9d,0x6f,0x07,0xd2,0x8a,0x46,0x75,0xfe, + 0x57,0xcf,0x5a,0xb9,0x65,0xfc,0xae,0x85,0x41,0xde,0x52,0x15,0xb6,0xe6,0x71,0x47, + 0x72,0xe8,0x41,0xea,0x5f,0xd4,0x58,0xc4,0xd2,0x12,0xcf,0xd5,0x7c,0x87,0x51,0xa6, + 0x52,0xf1,0x01,0xe9,0x05,0x0a,0x1e,0x9d,0x35,0xe2,0xe3,0xdd,0xeb,0x44,0x8e,0xd9, + 0xb6,0xae,0xdb,0xa8,0x8d,0xa6,0xcb,0xb6,0x25,0xd6,0x80,0x7f,0xa3,0xf2,0x72,0x13, + 0xd2,0xc8,0x2e,0xf6,0xdf,0xd8,0xdf,0x28,0x5e,0x5b,0xec,0x85,0xc4,0xb3,0x93,0x1c, + 0xf1,0x1a,0x07,0x91,0x98,0x39,0xd2,0x7d,0x26,0x88,0x6a,0xf6,0x3e,0xce,0x1b,0x4d, + 0x9c,0x76,0x57,0xe5,0x7d,0xa9,0x51,0x19,0x45,0xa2,0x03,0x3e,0xaf,0x9d,0xf9,0xd5, + 0xcf,0x4e,0xdc,0xe4,0xb1,0x3d,0xd3,0x78,0xbf,0xcb,0x8b,0x6f,0x5f,0x76,0xd7,0xfb, + 0xfd,0x70,0xd9,0xe9,0xbe,0x33,0xd3,0xad,0x2e,0xcf,0x09,0xf6,0xfe,0xea,0xdb,0x83, + 0xa3,0xff,0x2d,0x43,0xf0,0xe1,0xe5,0xe0,0x26,0x8a,0xc7,0x52,0xa5,0xdb,0xda,0xdc, + 0x52,0xf7,0x9a,0x5c,0x95,0x32,0x4d,0x52,0x2f,0xce,0x89,0x7e,0xb7,0xee,0x7b,0x73, + 0x3f,0x5d,0x78,0xc2,0xd5,0xdf,0x08,0x92,0xeb,0xe9,0x48,0x59,0x0b,0x0e,0x7f,0xd2, + 0x40,0xa2,0x26,0x00,0x00,0x74,0x76,0x84,0x48,0xa0,0x6a,0xa0,0x9c,0x44,0xab,0xa2, + 0x10,0x42,0x0d,0x8e,0xf2,0x54,0x69,0x0e,0x32,0x3a,0xe6,0xc7,0xc6,0x30,0xb4,0x62, + 0x59,0x81,0xa6,0x8a,0xdf,0x00,0x35,0x7d,0xf1,0xfd,0x5e,0xcf,0xd8,0x4c,0xb4,0xea, + 0xf6,0xfd,0x83,0x5d,0x09,0x65,0xf7,0x87,0x69,0x73,0x64,0x49,0x98,0xb3,0x4e,0x80, + 0xa5,0xbd,0x65,0x8a,0x3a,0xba,0x12,0xe6,0xe3,0x91,0x32,0xc0,0x9b,0xf9,0x72,0x30, + 0x4d,0xea,0x01,0xbb,0x1e,0xa6,0x1f,0xaa,0xed,0x4d,0x7f,0x10,0x28,0x6d,0x79,0x68, + 0x76,0xb0,0x02,0x0d,0x0a,0x7b,0x14,0xae,0xdf,0x59,0xf2,0x73,0xa1,0x78,0xfc,0x72, + 0xbd,0x43,0x24,0x8c,0xd3,0xbf,0xd1,0x68,0x68,0x77,0x58,0xa2,0x99,0x74,0x56,0xe8, + 0xfb,0x88,0x2e,0xc4,0xdc,0x09,0x38,0x07,0xed,0xc8,0xce,0x80,0xb0,0xcc,0x7f,0x88, + 0x23,0x0a,0xae,0x8f,0x8e,0x5d,0xbc,0xe8,0x5a,0x9f,0x2d,0x8b,0x9e,0x7c,0xfc,0x6e, + 0x19,0xe9,0x0e,0x82,0x07,0x70,0x3f,0xac,0xfc,0xaf,0x1b,0xfc,0x73,0xe4,0x1e,0xec, + 0xff,0xab,0x8b,0x65,0x95,0x32,0xf5,0x5a,0xd5,0x47,0xcd,0xcb,0xbf,0x5d,0x71,0xe6, + 0x48,0xce,0x95,0x0a,0x22,0x90,0x9b,0xee,0x2d,0x2a,0x3d,0xf8,0x46,0x8c,0xdc,0xc8, + 0x7b,0x45,0x37,0x19,0x49,0x76,0xc3,0x9c,0xba,0xa0,0x91,0x76,0xc2,0x81,0xd2,0x6b, + 0x43,0xf4,0xaa,0x5a,0x09,0x3a,0x1e,0xb1,0xc4,0x42,0x3a,0xdf,0xdb,0x0d,0x29,0x8b, + 0xfa,0x40,0xb3,0xdb,0xc8,0x73,0x47,0xde,0x73,0x83,0x5f,0x3a,0xbb,0x01,0xbe,0xeb, + 0xdb,0x7d,0xdb,0x96,0xda,0x81,0x10,0xc5,0x4a,0xa5,0xc5,0x91,0xcc,0x46,0x78,0xb2, + 0xb7,0x6d,0xda,0x6e,0xe4,0x6e,0xa9,0x4a,0x04,0x82,0x76,0x7e,0x94,0xd4,0x56,0x71, + 0xf1,0xdb,0xa2,0x7c,0x33,0xa9,0xd0,0x09,0x4d,0x21,0x6c,0x9e,0xd8,0x35,0x76,0xd6, + 0xd2,0x11,0x8b,0x99,0x3d,0x6b,0x25,0xf2,0x9d,0xc1,0x87,0xd5,0x09,0xd5,0x94,0xf1, + 0x5a,0xfb,0x46,0x99,0x77,0xb6,0xb6,0xa2,0x78,0x99,0xc7,0x5e,0x24,0x5e,0x9d,0x90, + 0x3e,0x2d,0xcc,0x44,0xcf,0xe9,0x0f,0x60,0x72,0x90,0x26,0x95,0x94,0xf0,0xf4,0x91, + 0x1b,0xfe,0x4f,0x07,0xad,0x5e,0xb0,0xc8,0x0a,0x01,0x64,0xd2,0xcd,0x19,0x0b,0x2f, + 0xc1,0xa0,0xdb,0x11,0xfc,0x53,0x74,0xb1,0x05,0xb5,0xed,0x99,0x85,0x75,0x7f,0xdb, + 0xe6,0x5d,0x59,0x67,0x19,0xb7,0xd7,0xfc,0x48,0xad,0xcd,0x99,0xee,0x7c,0x7a,0xc6, + 0x7e,0x8c,0xcc,0x96,0x3e,0xec,0xbf,0x9d,0xc1,0xc8,0x07,0x9a,0x86,0x44,0xd1,0xf4, + 0xd8,0x74,0x53,0x9c,0x9d,0x33,0x57,0xde,0x09,0x0e,0x8c,0xfa,0xea,0x2d,0x74,0xf6, + 0x9b,0x79,0x2f,0x98,0x87,0x7d,0x11,0xb4,0xc4,0xc8,0xc7,0x2a,0xc0,0xf8,0x3f,0xff, + 0x26,0xb9,0x5a,0x15,0x26,0x05,0x4c,0xfe,0xc1,0x6e,0xb9,0xe4,0xce,0xfe,0xdd,0xf7, + 0x7d,0xa9,0x13,0x3c,0xf8,0xe3,0xd4,0x4c,0xbe,0x24,0x61,0xdb,0xc6,0xee,0xdc,0xf9, + 0x47,0x59,0x2e,0x96,0x0a,0xe8,0xdd,0xbc,0xa8,0xeb,0x99,0x5e,0x80,0x6d,0x76,0xf2, + 0xf8,0x20,0x46,0xce,0xd5,0x6e,0xcb,0x10,0x77,0x5c,0x8c,0xff,0x89,0xdb,0x7d,0xb7, + 0xcc,0x62,0x43,0xdf,0xff,0x43,0xd2,0x22,0xd0,0xfb,0xa7,0xbb,0xff,0x1f,0x56,0x0e, + 0x70,0x72,0x42,0x7e,0xa8,0xd4,0x6d,0x63,0x78,0x70,0x6f,0xca,0x58,0xe3,0xb2,0x67, + 0x79,0x63,0xc3,0xbd,0xba,0x75,0x10,0xa4,0x38,0xa5,0x17,0x19,0x77,0xa1,0x4f,0xbd, + 0x71,0x73,0xc2,0xec,0xe4,0x95,0x30,0x82,0x1d,0xd3,0x43,0x4b,0x11,0x99,0x30,0x6c, + 0x94,0xe5,0x41,0x08,0x3f,0xbb,0xed,0xdb,0x58,0x57,0xe3,0x28,0x2f,0x9b,0xad,0x9b, + 0x70,0x80,0x7d,0xfd,0x37,0xab,0xec,0xda,0xdc,0xb7,0xc3,0x65,0x27,0x8b,0xac,0x9a, + 0xbe,0xc3,0x87,0xed,0x3e,0xba,0x6d,0xd9,0xb2,0x26,0x1c,0x4e,0x2e,0x9a,0x2d,0x99, + 0x31,0x2a,0x01,0x4f,0x36,0xaa,0x6c,0xd8,0xf5,0xb1,0x60,0x06,0x26,0x8a,0x2c,0x98, + 0x7a,0x8a,0x0d,0x42,0xd6,0xff,0x9c,0xa5,0xa6,0x5a,0xeb,0xb3,0x26,0x3c,0xfb,0x2a, + 0x32,0xc8,0xf2,0x06,0xb2,0xe7,0x9b,0x0d,0x7a,0x78,0xe5,0xc2,0x9d,0x7a,0xe9,0x6f, + 0x3b,0xd9,0x7f,0x05,0xd5,0xad,0x73,0x4e,0xc4,0xad,0x1f,0xe4,0x78,0xe2,0xb3,0x7d, + 0x33,0xc9,0x36,0x04,0xa3,0x7f,0x2e,0x4e,0x1f,0xdb,0xed,0xdf,0x93,0xdb,0xba,0x4b, + 0xde,0xaa,0x2e,0x0a,0x3d,0xb3,0xe5,0xd3,0x6a,0xb8,0xbd,0x43,0x2d,0x93,0xa5,0x93, + 0x2a,0x18,0xad,0x00,0x35,0xa3,0xe4,0xd2,0xca,0x1a,0x0a,0x6d,0x25,0x83,0xa4,0x92, + 0x4b,0xee,0x6b,0x01,0x3c,0xb2,0x65,0xd1,0x6b,0xb9,0x31,0x41,0x2c,0x92,0x25,0x91, + 0x41,0x58,0x28,0x02,0x34,0xa2,0x64,0xd0,0x23,0x1b,0x8a,0x0f,0x24,0x82,0x24,0x90, + 0x05,0x62,0xa2,0x13,0xfb,0x66,0x91,0xba,0xac,0x12,0x62,0x3d,0xec,0x26,0xa4,0xbe, + 0x04,0xb5,0x80,0x9b,0x40,0x10,0xe6,0x37,0x45,0xae,0xc4,0xee,0xc6,0x6b,0xd2,0x77, + 0x82,0xf3,0x03,0x14,0x78,0x67,0x32,0x7a,0x2f,0x49,0x34,0x1d,0xcf,0x7b,0x53,0x17, + 0xf3,0x73,0x85,0xee,0xb5,0x45,0x0e,0x3c,0x0b,0x10,0x0a,0x17,0x3e,0x75,0x92,0xad, + 0x24,0x80,0xc0,0xc9,0x3b,0x3b,0xcd,0xcb,0x2c,0xc4,0xe0,0x5c,0x2b,0x1b,0x8d,0x8b, + 0xdc,0x52,0xab,0x62,0x33,0x2b,0xcc,0xca,0x24,0x8f,0xc0,0x14,0x23,0x0b,0x8c,0x8a, + 0x3d,0xe6,0x5f,0x19,0x3a,0x3a,0x4d,0xc9,0xa1,0x83,0x1d,0xdb,0x2a,0x1a,0x0d,0x89, + 0x75,0x2f,0x21,0x33,0x32,0x2a,0x4c,0xc8,0x67,0x0a,0x10,0xac,0x22,0x0a,0x0c,0x88, + 0x44,0xe8,0x2a,0x98,0xbe,0x5c,0xd7,0x37,0x2c,0x19,0x4a,0xf7,0xee,0x8b,0x1b,0x11, + 0xda,0xea,0x8a,0x1f,0x65,0x1e,0x98,0xb3,0x60,0xbe,0x88,0xda,0x50,0x42,0x96,0xc4, + 0x5f,0xc1,0x2a,0x12,0xe7,0xc9,0xbf,0x78,0xb3,0xcb,0x88,0x50,0xef,0x89,0x53,0x7d, + 0x07,0xbe,0x0a,0xe0,0x72,0x7f,0x18,0xb1,0xbe,0x4a,0x65,0x56,0x27,0xf0,0x53,0xde, + 0xb7,0xaa,0xd1,0xa1,0x39,0x33,0xc5,0xc3,0x52,0x6c,0xb9,0xa4,0x29,0x13,0x85,0x83, + 0xf5,0x3a,0xd8,0x78,0x31,0x23,0xc4,0xc2,0xe1,0x1a,0x4f,0x1d,0x21,0x03,0x84,0x82, + 0xb8,0x4b,0x2e,0xf3,0x38,0x32,0x45,0xc1,0xc7,0x6b,0xeb,0x33,0x28,0x12,0x05,0x81, + 0xf0,0x3b,0xd4,0x3f,0x30,0x22,0x44,0xc0,0x36,0xf9,0xcf,0x1e,0x20,0x02,0x04,0x80, + 0x18,0xd2,0xeb,0x8f,0x98,0x3b,0xff,0xe4,0x60,0x39,0x6e,0x4d,0xc8,0x01,0xf7,0xac, + 0x62,0xe9,0xa6,0x8c,0x97,0xf4,0x97,0x85,0x9b,0x54,0xbe,0x30,0x8b,0xb2,0xc2,0x6d, + 0x41,0x43,0x8a,0x8f,0x1a,0xab,0x7f,0xc6,0x68,0x3d,0x63,0xd9,0x02,0xe1,0x68,0xac, + 0x63,0xfc,0x26,0x85,0x85,0x75,0xd5,0xac,0xf9,0xf8,0xe2,0xce,0x29,0xb5,0x01,0xa9, + 0x2a,0x5f,0x47,0x81,0x1f,0xb9,0xe9,0x5b,0x08,0x00,0x07,0x44,0x0f,0x99,0xa9,0x1b, + 0xd3,0xb0,0xab,0x78,0x17,0xa9,0xe8,0x5a,0x3f,0xf6,0xdc,0xce,0x07,0x89,0xa8,0x1a, + 0x19,0xc1,0x87,0x81,0x1e,0xb8,0x69,0x59,0x09,0x47,0x27,0x59,0x0e,0x98,0x29,0x19, + 0x11,0x77,0x05,0x8f,0x16,0xa8,0x68,0x58,0x41,0x4b,0x34,0x7a,0x06,0x88,0x28,0x18, + 0x72,0x17,0x6f,0xa8,0xfa,0x59,0x9e,0x8c,0x49,0xda,0x4f,0x79,0xe8,0xf0,0xff,0x8d, + 0xdd,0x16,0xfe,0x8f,0x8a,0xa1,0x39,0xaf,0x9b,0xc9,0xc1,0x54,0x19,0x60,0x3e,0x37, + 0x5b,0x79,0x73,0x7a,0x8b,0x6d,0xdc,0xa5,0x4d,0x2d,0x2d,0x49,0xe9,0x4d,0x7f,0xec, + 0x23,0x3e,0x2c,0x03,0xa3,0x9a,0x3c,0x21,0x43,0x5d,0x8d,0x84,0xc3,0x18,0xbe,0x35, + 0x94,0x38,0xad,0x8a,0x1d,0xb1,0xe1,0x53,0x2a,0x9c,0x93,0x51,0x0d,0x91,0xa1,0x13, + 0x91,0xb8,0xae,0x07,0x15,0xa1,0xe0,0x52,0x8e,0x18,0x0e,0xed,0x05,0x81,0xa0,0x12, + 0x6b,0xfd,0x2f,0x04,0x1c,0xb0,0x61,0x51,0xdc,0x4f,0x4c,0xcd,0x0c,0x90,0x21,0x11, + 0xec,0x0b,0x8e,0x80,0x14,0xa0,0x60,0x50,0x03,0x19,0x8c,0x10,0x04,0x80,0x20,0x10, + 0xa7,0x80,0x02,0x96,0x5a,0x64,0xb6,0xf8,0x4f,0x26,0xff,0xdb,0xbf,0x9a,0xb4,0xb5, + 0x4c,0xd6,0x18,0x11,0x24,0x42,0x33,0x6f,0xc4,0xd4,0x87,0xd3,0xed,0xd1,0x03,0xc9, + 0xad,0x42,0x45,0x9d,0xb8,0xf5,0x17,0xb4,0x0e,0x41,0x41,0x52,0x62,0x45,0xa7,0x50, + 0x55,0x11,0xa0,0x1a,0xcd,0xb0,0xb3,0x6d,0xd0,0x97,0x35,0xd0,0x37,0xfb,0x14,0x5e, + 0xe4,0x18,0x7b,0x98,0x1b,0x39,0xc9,0x4b,0xe4,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b, + 0xac,0x0c,0xa2,0x93,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a, + 0x0d,0x32,0x25,0x84,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09, + 0x65,0x74,0x46,0x98,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08, + 0x1c,0x68,0xae,0xd0,0xc6,0xa9,0x3a,0x56,0x11,0x0b,0x8d,0xde,0xa5,0x18,0xfd,0x66, + 0x32,0x78,0xf0,0x24,0xae,0xba,0x3b,0x67,0x46,0x38,0xe5,0xd5,0x91,0xe4,0x88,0x65, + 0xec,0x69,0x2e,0xd2,0x3c,0x8f,0xbc,0xba,0x13,0xe9,0x4f,0xbf,0xb2,0x32,0x25,0x07, + 0x80,0xc5,0x5c,0x47,0x84,0xd9,0x41,0xf9,0x07,0x41,0x41,0xd6,0x84,0x6f,0xf1,0x77, + 0x06,0x8b,0xa2,0x91,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03, + 0x06,0xfe,0xad,0x95,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02, + 0x6d,0xca,0x0d,0x90,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01, + 0xd9,0xb9,0x58,0x99,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x4e,0x0e, +}; +#endif // GTP_HOTKNOT + +#endif // _GT1X_FIRMWARE_H_ diff --git a/drivers/input/touchscreen/gt1xx/gt1x_generic.c b/drivers/input/touchscreen/gt1xx/gt1x_generic.c new file mode 100755 index 00000000000..30d8dc42427 --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x_generic.c @@ -0,0 +1,2472 @@ +/* drivers/input/touchscreen/gt1x_generic.c + * + * 2010 - 2014 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ + +//#include "gt1x_tpd_custom.h" +#include "gt1x.h" +#include "gt1x_generic.h" +#if GTP_PROXIMITY&&defined(PLATFORM_MTK) +#include +#include +#include +#endif +#if GTP_ICS_SLOT_REPORT +#include +#endif + +/*******************GLOBAL VARIABLE*********************/ +struct i2c_client *gt1x_i2c_client = NULL; +static struct workqueue_struct *gt1x_workqueue = NULL; + +u8 gt1x_config[GTP_CONFIG_MAX_LENGTH] = { 0 }; +u32 gt1x_cfg_length = GTP_CONFIG_MAX_LENGTH; + +CHIP_TYPE_T gt1x_chip_type = CHIP_TYPE_NONE; +struct gt1x_version_info gt1x_version = { + .product_id = {0}, + .patch_id = 0, + .mask_id = 0, + .sensor_id = 0, + .match_opt = 0 +}; + +#ifndef TPD_HAVE_BUTTON +#define TPD_HAVE_BUTTON 0 +#endif + +#if GTP_HAVE_TOUCH_KEY +const u16 gt1x_touch_key_array[] = GTP_KEY_TAB; +#elif TPD_HAVE_BUTTON +struct key_map_t { + int x; + int y; +}; +static struct key_map_t tpd_virtual_key_array[]= TPD_KEY_MAP_ARRAY; +#endif + +#if GTP_WITH_STYLUS && GTP_HAVE_STYLUS_KEY +static const u16 gt1x_stylus_key_array[] = GTP_STYLUS_KEY_TAB; +#endif + +#define GOODIX_SYSFS_DIR "goodix" +static struct kobject *sysfs_rootdir = NULL; + +volatile int gt1x_rawdiff_mode = 0; +u8 gt1x_wakeup_level = 0; +u8 gt1x_init_failed = 0; +u8 gt1x_int_type = 0; +u32 gt1x_abs_x_max = 0; +u32 gt1x_abs_y_max = 0; +int gt1x_halt = 0; + +static ssize_t gt1x_debug_read_proc(struct file *, char __user *, size_t, loff_t *); +static ssize_t gt1x_debug_write_proc(struct file *, const char __user *, size_t, loff_t *); + +static struct proc_dir_entry *gt1x_debug_proc_entry = NULL; +static const struct file_operations gt1x_debug_fops = { + .owner = THIS_MODULE, + .read = gt1x_debug_read_proc, + .write = gt1x_debug_write_proc, +}; + +static s32 gt1x_init_debug_node(void) +{ + gt1x_debug_proc_entry = proc_create(GT1X_DEBUG_PROC_FILE, 0660, NULL, >1x_debug_fops); + if (gt1x_debug_proc_entry == NULL) { + GTP_ERROR("Create proc entry /proc/%s FAILED!", GT1X_DEBUG_PROC_FILE); + return -1; + } + GTP_INFO("Created proc entry /proc/%s.", GT1X_DEBUG_PROC_FILE); + return 0; +} + +static void gt1x_deinit_debug_node(void) +{ + if (gt1x_debug_proc_entry != NULL) { + remove_proc_entry(GT1X_DEBUG_PROC_FILE, NULL); + } +} + +static ssize_t gt1x_debug_read_proc(struct file *file, char __user * page, size_t size, loff_t * ppos) +{ + char *ptr = page; + char temp_data[GTP_CONFIG_MAX_LENGTH] = { 0 }; + int i; + + if (*ppos) { + return 0; + } + + ptr += sprintf(ptr, "==== GT1X default config setting in driver====\n"); + + for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) { + ptr += sprintf(ptr, "0x%02X,", gt1x_config[i]); + if (i % 10 == 9) + ptr += sprintf(ptr, "\n"); + } + + ptr += sprintf(ptr, "\n"); + + ptr += sprintf(ptr, "==== GT1X config read from chip====\n"); + i = gt1x_i2c_read(GTP_REG_CONFIG_DATA, temp_data, GTP_CONFIG_MAX_LENGTH); + GTP_INFO("I2C TRANSFER: %d", i); + for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) { + ptr += sprintf(ptr, "0x%02X,", temp_data[i]); + + if (i % 10 == 9) + ptr += sprintf(ptr, "\n"); + } + + ptr += sprintf(ptr, "\n"); + /* Touch PID & VID */ + ptr += sprintf(ptr, "==== GT1X Version Info ====\n"); + + gt1x_i2c_read(GTP_REG_VERSION, temp_data, 12); + ptr += sprintf(ptr, "ProductID: GT%c%c%c%c\n", temp_data[0], temp_data[1], temp_data[2], temp_data[3]); + ptr += sprintf(ptr, "PatchID: %02X%02X\n", temp_data[4], temp_data[5]); + ptr += sprintf(ptr, "MaskID: %02X%02X\n", temp_data[7], temp_data[8]); + ptr += sprintf(ptr, "SensorID: %02X\n", temp_data[10] & 0x0F); + + *ppos += ptr - page; + return (ptr - page); +} + +static ssize_t gt1x_debug_write_proc(struct file *file, const char *buffer, size_t count, loff_t * ppos) +{ + s32 ret = 0; + u8 buf[GTP_CONFIG_MAX_LENGTH] = { 0 }; + char mode_str[50] = { 0 }; + int mode; + int cfg_len; + char arg1[50] = { 0 }; + u8 temp_config[GTP_CONFIG_MAX_LENGTH] = { 0 }; + + GTP_DEBUG("write count %ld\n", (unsigned long)count); + + if (count > GTP_CONFIG_MAX_LENGTH) { + GTP_ERROR("Too much data, buffer size: %d, data:%ld", GTP_CONFIG_MAX_LENGTH, (unsigned long)count); + return -EFAULT; + } + + if (copy_from_user(buf, buffer, count)) { + GTP_ERROR("copy from user fail!"); + return -EFAULT; + } + // send config + if (count == gt1x_cfg_length) { + memcpy(gt1x_config, buf, count); + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + if (ret < 0) { + GTP_ERROR("send gt1x_config failed."); + return -EFAULT; + } + gt1x_abs_x_max = (gt1x_config[RESOLUTION_LOC + 1] << 8) + gt1x_config[RESOLUTION_LOC]; + gt1x_abs_y_max = (gt1x_config[RESOLUTION_LOC + 3] << 8) + gt1x_config[RESOLUTION_LOC + 2]; + + return count; + } + + sscanf(buf, "%s %d", (char *)&mode_str, &mode); + + //force clear gt1x_config + if (strcmp(mode_str, "clear_config") == 0) { + GTP_INFO("Force clear gt1x_config"); + gt1x_send_cmd(GTP_CMD_CLEAR_CFG, 0); + return count; + } + if (strcmp(mode_str, "init") == 0) { + GTP_INFO("Init panel"); + gt1x_init_panel(); + return count; + } + if (strcmp(mode_str, "chip") == 0) { + GTP_INFO("Get chip type:"); + gt1x_get_chip_type(); + return count; + } + if (strcmp(mode_str, "int") == 0) { + if (mode == 0) { + GTP_INFO("Disable irq."); + gt1x_irq_disable(); + } else { + GTP_INFO("Enable irq."); + gt1x_irq_enable(); + } + return count; + } + + if (strcmp(mode_str, "poweron") == 0) { + gt1x_power_switch(1); + return count; + } + + if (strcmp(mode_str, "poweroff") == 0) { + gt1x_power_switch(0); + return count; + } + + if (strcmp(mode_str, "version") == 0) { + gt1x_read_version(NULL); + return count; + } + + if (strcmp(mode_str, "reset") == 0) { + gt1x_irq_disable(); + gt1x_reset_guitar(); + gt1x_irq_enable(); + return count; + } +#if GTP_CHARGER_SWITCH + if (strcmp(mode_str, "charger") == 0) { + gt1x_charger_config(mode); + return count; + } +#endif + sscanf(buf, "%s %s", (char *)&mode_str, (char *)&arg1); + if (strcmp(mode_str, "update") == 0) { + gt1x_update_firmware(arg1); + return count; + } + + if (strcmp(mode_str, "sendconfig") == 0) { + cfg_len = gt1x_parse_config(arg1, temp_config); + if (cfg_len < 0) { + return -1; + } + gt1x_send_cfg(temp_config, gt1x_cfg_length); + return count; + } + + if (strcmp(mode_str, "debug_gesture") == 0) { +#if GTP_GESTURE_WAKEUP + gt1x_gesture_debug(!!mode); +#endif + } + + if (strcmp(mode_str, "force_update") == 0) { + update_info.force_update = !!mode; + } + return gt1x_debug_proc(buf, count); +} + +static u8 ascii2hex(u8 a) +{ + s8 value = 0; + if (a >= '0' && a <= '9') { + value = a - '0'; + } else if (a >= 'A' && a <= 'F') { + value = a - 'A' + 0x0A; + } else if (a >= 'a' && a <= 'f') { + value = a - 'a' + 0x0A; + } else { + value = 0xff; + } + return value; +} + +int gt1x_parse_config(char *filename, u8 * config) +{ + mm_segment_t old_fs; + struct file *fp = NULL; + u8 *buf; + int i; + int len; + int cur_len = -1; + u8 high, low; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(fp)) { + GTP_ERROR("Open config file error!(file: %s)", filename); + goto parse_cfg_fail1; + } + len = fp->f_op->llseek(fp, 0, SEEK_END); + if (len > GTP_CONFIG_MAX_LENGTH * 6 || len < GTP_CONFIG_MAX_LENGTH) { + GTP_ERROR("Config is invalid!(length: %d)", len); + goto parse_cfg_fail2; + } + buf = (u8 *) kzalloc(len, GFP_KERNEL); + if (buf == NULL) { + GTP_ERROR("Allocate memory failed!(size: %d)", len); + goto parse_cfg_fail2; + } + fp->f_op->llseek(fp, 0, SEEK_SET); + if (fp->f_op->read(fp, (char *)buf, len, &fp->f_pos) != len) { + GTP_ERROR("Read %d bytes from file failed!", len); + } + + GTP_INFO("Parse config file: %s (%d bytes)", filename, len); + + for (i = 0, cur_len = 0; i < len && cur_len < GTP_CONFIG_MAX_LENGTH;) { + if (buf[i] == ' ' || buf[i] == '\r' || buf[i] == '\n' || buf[i] == ',') { + i++; + continue; + } + if (buf[i] == '0' && (buf[i + 1] == 'x' || buf[i + 1] == 'X')) { + + high = ascii2hex(buf[i + 2]); + low = ascii2hex(buf[i + 3]); + + if (high != 0xFF && low != 0xFF) { + config[cur_len++] = (high << 4) + low; + i += 4; + continue; + } + } + GTP_ERROR("Illegal config file!"); + cur_len = -1; + break; + } + + if (cur_len < GTP_CONFIG_MIN_LENGTH || config[cur_len - 1] != 0x01) { + cur_len = -1; + } else { + for (i = 0; i < cur_len; i++) { + if (i % 10 == 0) { + printk("\n<>:"); + } + printk("0x%02x,", config[i]); + } + printk("\n"); + } + + kfree(buf); +parse_cfg_fail2: + filp_close(fp, NULL); +parse_cfg_fail1: + set_fs(old_fs); + + return cur_len; +} + +s32 _do_i2c_read(struct i2c_msg * msgs, u16 addr, u8 * buffer, s32 len) +{ + s32 ret = -1; + s32 pos = 0; + s32 data_length = len; + s32 transfer_length = 0; + u8 *data = NULL; + u16 address = addr; + + data = (u8 *) kmalloc(IIC_MAX_TRANSFER_SIZE < (len + GTP_ADDR_LENGTH) ? IIC_MAX_TRANSFER_SIZE : (len + GTP_ADDR_LENGTH), GFP_KERNEL); + if (data == NULL) { + return ERROR_MEM; + } + msgs[1].buf = data; + + while (pos != data_length) { + if ((data_length - pos) > IIC_MAX_TRANSFER_SIZE) { + transfer_length = IIC_MAX_TRANSFER_SIZE; + } else { + transfer_length = data_length - pos; + } + msgs[0].buf[0] = (address >> 8) & 0xFF; + msgs[0].buf[1] = address & 0xFF; + msgs[1].len = transfer_length; + + ret = i2c_transfer(gt1x_i2c_client->adapter, msgs, 2); + if (ret != 2) { + GTP_ERROR("I2c Transfer error! (%d)", ret); + kfree(data); + return ERROR_IIC; + } + memcpy(&buffer[pos], msgs[1].buf, transfer_length); + pos += transfer_length; + address += transfer_length; + } + + kfree(data); + return 0; +} + +s32 _do_i2c_write(struct i2c_msg * msg, u16 addr, u8 * buffer, s32 len) +{ + s32 ret = -1; + s32 pos = 0; + s32 data_length = len; + s32 transfer_length = 0; + u8 *data = NULL; + u16 address = addr; + + data = (u8 *) kmalloc(IIC_MAX_TRANSFER_SIZE < (len + GTP_ADDR_LENGTH) ? IIC_MAX_TRANSFER_SIZE : (len + GTP_ADDR_LENGTH), GFP_KERNEL); + if (data == NULL) { + return ERROR_MEM; + } + msg->buf = data; + + while (pos != data_length) { + if ((data_length - pos) > (IIC_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH)) { + transfer_length = IIC_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH; + } else { + transfer_length = data_length - pos; + } + + msg->buf[0] = (address >> 8) & 0xFF; + msg->buf[1] = address & 0xFF; + msg->len = transfer_length + GTP_ADDR_LENGTH; + memcpy(&msg->buf[GTP_ADDR_LENGTH], &buffer[pos], transfer_length); + + ret = i2c_transfer(gt1x_i2c_client->adapter, msg, 1); + if (ret != 1) { + GTP_ERROR("I2c transfer error! (%d)", ret); + kfree(data); + return ERROR_IIC; + } + pos += transfer_length; + address += transfer_length; + } + + kfree(data); + return 0; +} + +#if !GTP_ESD_PROTECT +/* +//delete by liangdi for I2C error 20190523 +static s32 gt1x_i2c_test(void) +{ + u8 retry = 0; + s32 ret = -1; + u32 hw_info = 0; + GTP_DEBUG_FUNC(); + + while (retry++ < 3) { + ret = gt1x_i2c_read(GTP_REG_HW_INFO, (u8 *) & hw_info, sizeof(hw_info)); + if (!ret) { + GTP_INFO("Hardware Info:%08X", hw_info); + return ret; + } + + msleep(10); + GTP_ERROR("Hardware Info:%08X", hw_info); + GTP_ERROR("I2c failed%d.", retry); + } + + return ERROR_RETRY; +} +*/ +//delete end +#endif + +/** + * gt1x_i2c_read_dbl_check - read twice and double check + * @addr: register address + * @buffer: data buffer + * @len: bytes to read + * Return <0: i2c error, 0: ok, 1:fail + */ +s32 gt1x_i2c_read_dbl_check(u16 addr, u8 * buffer, s32 len) +{ + u8 buf[16] = { 0 }; + u8 confirm_buf[16] = { 0 }; + int ret; + + if (len > 16) { + GTP_ERROR("i2c_read_dbl_check length %d is too long, exceed %zu", len, sizeof(buf)); + return ERROR; + } + + memset(buf, 0xAA, sizeof(buf)); + ret = gt1x_i2c_read(addr, buf, len); + if (ret < 0) { + return ret; + } + + msleep(5); + memset(confirm_buf, 0, sizeof(confirm_buf)); + ret = gt1x_i2c_read(addr, confirm_buf, len); + if (ret < 0) { + return ret; + } + + if (!memcmp(buf, confirm_buf, len)) { + memcpy(buffer, confirm_buf, len); + return 0; + } + GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len); + return 1; +} + +/** + * gt1x_get_info - Get information from ic, such as resolution and + * int trigger type + * Return <0: i2c failed, 0: i2c ok + */ +s32 gt1x_get_info(void) +{ + u8 opr_buf[4] = { 0 }; + s32 ret = 0; + + ret = gt1x_i2c_read(GTP_REG_CONFIG_DATA + 1, opr_buf, 4); + if (ret < 0) { + return ret; + } + + gt1x_abs_x_max = (opr_buf[1] << 8) + opr_buf[0]; + gt1x_abs_y_max = (opr_buf[3] << 8) + opr_buf[2]; + + ret = gt1x_i2c_read(GTP_REG_CONFIG_DATA + 6, opr_buf, 1); + if (ret < 0) { + return ret; + } + gt1x_int_type = opr_buf[0] & 0x03; + + GTP_INFO("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", gt1x_abs_x_max, gt1x_abs_y_max, gt1x_int_type); + + return 0; +} + +/** + * gt1x_send_cfg - Send gt1x_config Function. + * @config: pointer of the configuration array. + * @cfg_len: length of configuration array. + * Return 0--success,non-0--fail. + */ +s32 gt1x_send_cfg(u8 * config, int cfg_len) +{ +#if GTP_DRIVER_SEND_CFG + static DEFINE_MUTEX(mutex_cfg); + int i; + s32 ret = 0; + s32 retry = 0; + u16 checksum = 0; + + if (update_info.status) { + GTP_DEBUG("Ignore cfg during fw update."); + return -1; + } + + mutex_lock(&mutex_cfg); + GTP_DEBUG("Driver send config, length:%d", cfg_len); + for (i = 0; i < cfg_len - 3; i += 2) { + checksum += (config[i] << 8) + config[i + 1]; + } + if (!checksum) { + GTP_ERROR("Invalid config, all of the bytes is zero!"); + mutex_unlock(&mutex_cfg); + return -1; + } + checksum = 0 - checksum; + GTP_DEBUG("Config checksum: 0x%04X", checksum); + config[cfg_len - 3] = (checksum >> 8) & 0xFF; + config[cfg_len - 2] = checksum & 0xFF; + config[cfg_len - 1] = 0x01; + + while (retry++ < 5) { + ret = gt1x_i2c_write(GTP_REG_CONFIG_DATA, config, cfg_len); + if (!ret) { + msleep(200); /* at least 200ms, wait for storing config into flash. */ + mutex_unlock(&mutex_cfg); + GTP_DEBUG("Send config successfully!"); + return 0; + } + } + GTP_ERROR("Send config failed!"); + mutex_unlock(&mutex_cfg); + return ret; +#endif + return 0; +} + +/** + * gt1x_init_panel - Prepare config data for touch ic, don't call this function + * after initialization. + * + * Return 0--success,<0 --fail. + */ +s32 gt1x_init_panel(void) +{ + s32 ret = 0; + u8 cfg_len = 0; + +#if GTP_DRIVER_SEND_CFG + u8 sensor_id = 0; + + const u8 cfg_grp0[] = GTP_CFG_GROUP0; + const u8 cfg_grp1[] = GTP_CFG_GROUP1; + const u8 cfg_grp2[] = GTP_CFG_GROUP2; + const u8 cfg_grp3[] = GTP_CFG_GROUP3; + const u8 cfg_grp4[] = GTP_CFG_GROUP4; + const u8 cfg_grp5[] = GTP_CFG_GROUP5; + const u8 *cfgs[] = { + cfg_grp0, cfg_grp1, cfg_grp2, + cfg_grp3, cfg_grp4, cfg_grp5 + }; + u8 cfg_lens[] = { + CFG_GROUP_LEN(cfg_grp0), + CFG_GROUP_LEN(cfg_grp1), + CFG_GROUP_LEN(cfg_grp2), + CFG_GROUP_LEN(cfg_grp3), + CFG_GROUP_LEN(cfg_grp4), + CFG_GROUP_LEN(cfg_grp5) + }; + + GTP_DEBUG("Config groups length:%d,%d,%d,%d,%d,%d", cfg_lens[0], cfg_lens[1], cfg_lens[2], cfg_lens[3], cfg_lens[4], cfg_lens[5]); + + sensor_id = gt1x_version.sensor_id; + if (sensor_id >= 6 || cfg_lens[sensor_id] < GTP_CONFIG_MIN_LENGTH || cfg_lens[sensor_id] > GTP_CONFIG_MAX_LENGTH) { + sensor_id = 0; + gt1x_version.sensor_id = 0; + } + + cfg_len = cfg_lens[sensor_id]; + + GTP_INFO("Config group%d used, length:%d", sensor_id, cfg_len); + + if (cfg_len < GTP_CONFIG_MIN_LENGTH || cfg_len > GTP_CONFIG_MAX_LENGTH) { + GTP_ERROR("Config group%d is INVALID! You need to check you header file CFG_GROUP section!", sensor_id + 1); + return -1; + } + + memset(gt1x_config, 0, sizeof(gt1x_config)); + memcpy(gt1x_config, cfgs[sensor_id], cfg_len); + + /* clear the flag, avoid failure when send the_config of driver. */ + gt1x_config[0] &= 0x7F; + +#if GTP_CUSTOM_CFG + gt1x_config[RESOLUTION_LOC] = (u8) GTP_MAX_WIDTH; + gt1x_config[RESOLUTION_LOC + 1] = (u8) (GTP_MAX_WIDTH >> 8); + gt1x_config[RESOLUTION_LOC + 2] = (u8) GTP_MAX_HEIGHT; + gt1x_config[RESOLUTION_LOC + 3] = (u8) (GTP_MAX_HEIGHT >> 8); + + if (GTP_INT_TRIGGER == 0) { /* RISING */ + gt1x_config[TRIGGER_LOC] &= 0xfe; + } else if (GTP_INT_TRIGGER == 1) { /* FALLING */ + gt1x_config[TRIGGER_LOC] |= 0x01; + } + set_reg_bit(gt1x_config[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); +#endif /* END GTP_CUSTOM_CFG */ + +#else /* DRIVER NOT SEND CONFIG */ + cfg_len = GTP_CONFIG_MAX_LENGTH; + ret = gt1x_i2c_read(GTP_REG_CONFIG_DATA, gt1x_config, cfg_len); + if (ret < 0) { + return ret; + } +#endif /* END GTP_DRIVER_SEND_CFG */ + + GTP_DEBUG_FUNC(); + /* match resolution when gt1x_abs_x_max & gt1x_abs_y_max have been set already */ + if ((gt1x_abs_x_max == 0) && (gt1x_abs_y_max == 0)) { + gt1x_abs_x_max = (gt1x_config[RESOLUTION_LOC + 1] << 8) + gt1x_config[RESOLUTION_LOC]; + gt1x_abs_y_max = (gt1x_config[RESOLUTION_LOC + 3] << 8) + gt1x_config[RESOLUTION_LOC + 2]; + gt1x_int_type = (gt1x_config[TRIGGER_LOC]) & 0x03; + gt1x_wakeup_level = !(gt1x_config[MODULE_SWITCH3_LOC] & 0x20); + } else { + gt1x_config[RESOLUTION_LOC] = (u8) gt1x_abs_x_max; + gt1x_config[RESOLUTION_LOC + 1] = (u8) (gt1x_abs_x_max >> 8); + gt1x_config[RESOLUTION_LOC + 2] = (u8) gt1x_abs_y_max; + gt1x_config[RESOLUTION_LOC + 3] = (u8) (gt1x_abs_y_max >> 8); + set_reg_bit(gt1x_config[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); + gt1x_config[TRIGGER_LOC] = (gt1x_config[TRIGGER_LOC] & 0xFC) | gt1x_int_type; + } + + GTP_INFO("X_MAX=%d,Y_MAX=%d,TRIGGER=0x%02x,WAKEUP_LEVEL=%d", gt1x_abs_x_max, gt1x_abs_y_max, gt1x_int_type, gt1x_wakeup_level); + + gt1x_cfg_length = cfg_len; + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + return ret; +} + +void gt1x_select_addr(void) +{ + GTP_GPIO_OUTPUT(GTP_RST_PORT, 0); + GTP_GPIO_OUTPUT(GTP_INT_PORT, gt1x_i2c_client->addr == 0x14); + msleep(2); + GTP_GPIO_OUTPUT(GTP_RST_PORT, 1); + msleep(2); +} + +static s32 gt1x_set_reset_status(void) +{ + /* 0x8040 ~ 0x8043 */ + u8 value[] = {0xAA, 0x00, 0x56, 0xAA}; + int ret; + + GTP_DEBUG("Set reset status."); + ret = gt1x_i2c_write(GTP_REG_CMD + 1, &value[1], 3); + if (ret < 0) + return ret; + + return gt1x_i2c_write(GTP_REG_CMD, value, 1); +} + +#if GTP_INCELL_PANEL +int gt1x_write_and_readback(u16 addr, u8 * buffer, s32 len) +{ + int ret; + u8 d[len]; + + ret = gt1x_i2c_write(addr, buffer, len); + if (ret < 0) + return -1; + + ret = gt1x_i2c_read(addr, d, len); + if (ret < 0 || memcmp(buffer, d, len)) + return -1; + + return 0; +} + +int gt1x_incell_reset(void) +{ +#define RST_RETRY 5 + int ret, retry = RST_RETRY; + u8 d[2]; + + + do { + /* select i2c address */ + gt1x_select_addr(); + + /* test i2c */ + ret = gt1x_i2c_read(0x4220, d, 1); + + } while (--retry && ret < 0); + + if (ret < 0) { + return -1; + } + + /* Stop cpu of the touch ic */ + retry = RST_RETRY; + do { + d[0] = 0x0C; + ret = gt1x_write_and_readback(0x4180, d, 1); + + } while (--retry && ret < 0); + + if (ret < 0) { + GTP_ERROR("Hold error."); + return -1; + } + + /* skip sensor id check. [start] */ + retry = RST_RETRY; + do { + d[0] = 0x00; + ret = gt1x_write_and_readback(0x4305, d, 1); + if (ret < 0) + continue; + + d[0] = 0x2B; + d[1] = 0x24; + ret = gt1x_write_and_readback(0x42c4, d, 2); + if (ret < 0) + continue; + + d[0] = 0xE1; + d[1] = 0xD3; + ret = gt1x_write_and_readback(0x42e4, d, 2); + if (ret < 0) + continue; + + d[0] = 0x01; + ret = gt1x_write_and_readback(0x4305, d, 1); + if (ret < 0) + continue; + else + break; + } while (--retry ); + + if (!retry) + return -1; + /* skip sensor id check. [end] */ + + /* release hold of cpu */ + retry = RST_RETRY; + do { + d[0] = 0x00; + ret = gt1x_write_and_readback(0x4180, d, 1); + + } while (--retry && ret < 0); + + if (ret < 0) + return -1; + + return 0; + +} +#endif + +s32 gt1x_reset_guitar(void) +{ + int ret; + + GTP_INFO("GTP RESET!"); + +#if GTP_INCELL_PANEL + ret = gt1x_incell_reset(); + if (ret < 0) + return ret; +#else + gt1x_select_addr(); + msleep(8); //must >= 6ms +#endif + + /* int synchronization */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + msleep(50); + GTP_GPIO_AS_INT(GTP_INT_PORT); + + /* this operation is necessary even when the esd check + fucntion dose not turn on */ + ret = gt1x_set_reset_status(); + return ret; +} + +/** + * gt1x_read_version - Read gt1x version info. + * @ver_info: address to store version info + * Return 0-succeed. + */ +s32 gt1x_read_version(struct gt1x_version_info * ver_info) +{ + s32 ret = -1; + u8 buf[12] = { 0 }; + u32 mask_id = 0; + u32 patch_id = 0; + u8 product_id[5] = { 0 }; + u8 sensor_id = 0; + u8 match_opt = 0; + int i, retry = 3; + u8 checksum = 0; + + GTP_DEBUG_FUNC(); + + while (retry--) { + ret = gt1x_i2c_read_dbl_check(GTP_REG_VERSION, buf, sizeof(buf)); + if (!ret) { + checksum = 0; + + for (i = 0; i < sizeof(buf); i++) { + checksum += buf[i]; + } + + if (checksum == 0 && /* first 3 bytes must be number or char */ + IS_NUM_OR_CHAR(buf[0]) && IS_NUM_OR_CHAR(buf[1]) && IS_NUM_OR_CHAR(buf[2]) && buf[10] != 0xFF) { /*sensor id == 0xFF, retry */ + break; + } else { + GTP_ERROR("Read version failed!(checksum error)"); + } + } else { + GTP_ERROR("Read version failed!"); + } + GTP_DEBUG("Read version : %d", retry); + msleep(100); + } + + if (retry <= 0) { + if (ver_info) + ver_info->sensor_id = 0; + return -1; + } + + mask_id = (u32) ((buf[7] << 16) | (buf[8] << 8) | buf[9]); + patch_id = (u32) ((buf[4] << 16) | (buf[5] << 8) | buf[6]); + memcpy(product_id, buf, 4); + sensor_id = buf[10] & 0x0F; + match_opt = (buf[10] >> 4) & 0x0F; + + GTP_INFO("IC VERSION:GT%s_%06X(Patch)_%04X(Mask)_%02X(SensorID)", product_id, patch_id, mask_id >> 8, sensor_id); + + if (ver_info != NULL) { + ver_info->mask_id = mask_id; + ver_info->patch_id = patch_id; + memcpy(ver_info->product_id, product_id, 5); + ver_info->sensor_id = sensor_id; + ver_info->match_opt = match_opt; + } + return 0; +} + +/** + * gt1x_get_chip_type - get chip type . + * + * different chip synchronize in different way, + */ +s32 gt1x_get_chip_type(void) +{ + u8 opr_buf[4] = { 0x00 }; + u8 gt1x_data[] = { 0x02, 0x08, 0x90, 0x00 }; + u8 gt9l_data[] = { 0x03, 0x10, 0x90, 0x00 }; + s32 ret = -1; + + /* chip type already exist */ + if (gt1x_chip_type != CHIP_TYPE_NONE) { + return 0; + } + + /* read hardware */ + ret = gt1x_i2c_read_dbl_check(GTP_REG_HW_INFO, opr_buf, sizeof(opr_buf)); + if (ret) { + GTP_ERROR("I2c communication error."); + return -1; + } + + /* find chip type */ + if (!memcmp(opr_buf, gt1x_data, sizeof(gt1x_data))) { + gt1x_chip_type = CHIP_TYPE_GT1X; + } else if (!memcmp(opr_buf, gt9l_data, sizeof(gt9l_data))) { + gt1x_chip_type = CHIP_TYPE_GT2X; + } + + if (gt1x_chip_type != CHIP_TYPE_NONE) { + GTP_INFO("Chip Type: %s", (gt1x_chip_type == CHIP_TYPE_GT1X) ? "GT1X" : "GT2X"); + return 0; + } else { + return -1; + } +} + +/** + * gt1x_enter_sleep - Eter sleep function. + * + * Returns 0--success,non-0--fail. + */ +static s32 gt1x_enter_sleep(void) +{ +#if GTP_POWER_CTRL_SLEEP + gt1x_power_switch(SWITCH_OFF); + return 0; +#else + { + s32 retry = 0; + if (gt1x_wakeup_level == 1) { /* high level wakeup */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + } + msleep(5); + + while (retry++ < 3) { + if (!gt1x_send_cmd(GTP_CMD_SLEEP, 0)) { + GTP_INFO("Enter sleep mode!"); + return 0; + } + msleep(10); + } + + GTP_ERROR("Enter sleep mode failed."); + return -1; + } +#endif +} + +/** + * gt1x_wakeup_sleep - wakeup from sleep mode Function. + * + * Return: 0--success,non-0--fail. + */ +static s32 gt1x_wakeup_sleep(void) +{ +#if !GTP_POWER_CTRL_SLEEP + u8 retry = 0; + s32 ret = -1; + int flag = 0; +#endif + + GTP_DEBUG("Wake up begin."); + gt1x_irq_disable(); + +#if GTP_POWER_CTRL_SLEEP /* power manager unit control the procedure */ + gt1x_power_reset(); + GTP_INFO("Wakeup by poweron"); + return 0; +#else /* gesture wakeup & int port wakeup */ + while (retry++ < 2) { +#if GTP_GESTURE_WAKEUP + if (gesture_enabled) { + gesture_doze_status = DOZE_DISABLED; + ret = gt1x_reset_guitar(); + if(!ret) { + break; + } + } else +#endif + { + /* wake up through int port */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, gt1x_wakeup_level); + msleep(5); + + /* Synchronize int IO */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + msleep(50); + GTP_GPIO_AS_INT(GTP_INT_PORT); + flag = 1; + +#if GTP_ESD_PROTECT + ret = gt1x_set_reset_status(); +#else + //ret = gt1x_i2c_test();//delete by liangdi for I2C error 20190523 +#endif + if (!ret) + break; + + } /* end int wakeup */ + } + + if (ret < 0 && flag) { /* int wakeup failed , try waking up by reset */ + while (retry--) { + ret = gt1x_reset_guitar(); + if(!ret) + break; + } + } + + if (ret) { + GTP_ERROR("Wake up sleep failed."); + return -1; + } else { + GTP_INFO("Wake up end."); + return 0; + } +#endif /* END GTP_POWER_CTRL_SLEEP */ +} + +/** + * gt1x_send_cmd - seng cmd + * must write data & checksum first + * byte content + * 0 cmd + * 1 data + * 2 checksum + * Returns 0 - succeed,non-0 - failed + */ +s32 gt1x_send_cmd(u8 cmd, u8 data) +{ + s32 ret; + static DEFINE_MUTEX(cmd_mutex); + u8 buffer[3] = { cmd, data, 0 }; + + mutex_lock(&cmd_mutex); + buffer[2] = (u8) ((0 - cmd - data) & 0xFF); + ret = gt1x_i2c_write(GTP_REG_CMD + 1, &buffer[1], 2); + ret |= gt1x_i2c_write(GTP_REG_CMD, &buffer[0], 1); + msleep(50); + mutex_unlock(&cmd_mutex); + + return ret; +} + +void gt1x_power_reset(void) +{ + static int rst_flag; + s32 i = 0; + + if (rst_flag || update_info.status) { + return; + } + GTP_INFO("force_reset_guitar"); + rst_flag = 1; + gt1x_irq_disable(); + gt1x_power_switch(SWITCH_OFF); + msleep(30); + gt1x_power_switch(SWITCH_ON); + msleep(30); + + for (i = 0; i < 5; i++) { + if(gt1x_reset_guitar()) { + continue; + } + if(gt1x_send_cfg(gt1x_config, gt1x_cfg_length)) { + msleep(500); + continue; + } + break; + } + gt1x_irq_enable(); + rst_flag = 0; +} + +s32 gt1x_request_event_handler(void) +{ + s32 ret = -1; + u8 rqst_data = 0; + + ret = gt1x_i2c_read(GTP_REG_RQST, &rqst_data, 1); + if (ret) { + GTP_ERROR("I2C transfer error. errno:%d", ret); + return -1; + } + GTP_DEBUG("Request state:0x%02x.", rqst_data); + switch (rqst_data & 0x0F) { + case GTP_RQST_CONFIG: + GTP_INFO("Request Config."); + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + if (ret) { + GTP_ERROR("Send gt1x_config error."); + } else { + GTP_INFO("Send gt1x_config success."); + rqst_data = GTP_RQST_RESPONDED; + gt1x_i2c_write(GTP_REG_RQST, &rqst_data, 1); + } + break; + case GTP_RQST_RESET: + GTP_INFO("Request Reset."); + gt1x_reset_guitar(); + rqst_data = GTP_RQST_RESPONDED; + gt1x_i2c_write(GTP_REG_RQST, &rqst_data, 1); + break; + case GTP_RQST_BAK_REF: + GTP_INFO("Request Ref."); + break; + case GTP_RQST_MAIN_CLOCK: + GTP_INFO("Request main clock."); + break; +#if GTP_HOTKNOT + case GTP_RQST_HOTKNOT_CODE: + GTP_INFO("Request HotKnot Code."); + break; +#endif + default: + break; + } + return 0; +} + +/** + * gt1x_touch_event_handler - handle touch event + * (pen event, key event, finger touch envent) + * @data: + * Return <0: failed, 0: succeed + */ +s32 gt1x_touch_event_handler(u8 * data, struct input_dev * dev, struct input_dev * pen_dev) +{ + u8 touch_data[1 + 8 * GTP_MAX_TOUCH + 2] = { 0 }; + static u16 pre_event = 0; + static u16 pre_index = 0; + u8 touch_num = 0; + u8 key_value = 0; + u16 cur_event = 0; + u8 *coor_data = NULL; + u8 check_sum = 0; + s32 input_x = 0; + s32 input_y = 0; + s32 input_w = 0; + s32 id = 0; + s32 i = 0; + s32 ret = -1; + + GTP_DEBUG_FUNC(); + touch_num = data[0] & 0x0f; + if (touch_num > GTP_MAX_TOUCH) { + GTP_ERROR("Illegal finger number!"); + return ERROR_VALUE; + } + + memcpy(touch_data, data, 11); + + /* read the remaining coor data + * 0x814E(touch status) + 8(every coordinate consist of 8 bytes data) * touch num + + * keycode + checksum + */ + if (touch_num > 1) { + ret = gt1x_i2c_read((GTP_READ_COOR_ADDR + 11), &touch_data[11], 1 + 8 * touch_num + 2 - 11); + if (ret) { + return ret; + } + } + + /* cacl checksum */ + for (i = 0; i < 1 + 8 * touch_num + 2; i++) { + check_sum += touch_data[i]; + } + if (check_sum) { /* checksum error*/ + ret = gt1x_i2c_read(GTP_READ_COOR_ADDR, touch_data, 3 + 8 * touch_num); + if (ret) { + return ret; + } + + for (i = 0, check_sum = 0; i < 3 + 8 * touch_num; i++) { + check_sum += touch_data[i]; + } + if (check_sum) { + GTP_ERROR("Checksum error[%x]",check_sum); + return ERROR_VALUE; + } + } +/* + * cur_event , pre_event bit defination + * bits: bit4 bit3 bit2 bit1 bit0 + * event: hover stylus_key stylus key touch + */ + key_value = touch_data[1 + 8 * touch_num]; +/* start check current event */ + if ((touch_data[0] & 0x10) && key_value) { +#if (GTP_HAVE_STYLUS_KEY || GTP_HAVE_TOUCH_KEY || TPD_HAVE_BUTTON) + /* get current key states */ + if (key_value & 0xF0) { + SET_BIT(cur_event, BIT_STYLUS_KEY); + } else if (key_value & 0x0F) { + SET_BIT(cur_event, BIT_TOUCH_KEY); + } +#endif + } +#if GTP_WITH_STYLUS + else if (touch_data[1] & 0x80) { + SET_BIT(cur_event, BIT_STYLUS); + } +#endif + else if (touch_num) { + SET_BIT(cur_event, BIT_TOUCH); + } + +/* start handle current event and pre-event */ +#if GTP_HAVE_STYLUS_KEY + if (CHK_BIT(cur_event, BIT_STYLUS_KEY) || CHK_BIT(pre_event, BIT_STYLUS_KEY)) { + /* + * 0x10 -- stylus key0 down + * 0x20 -- stylus key1 down + * 0x40 -- stylus key0 & stylus key1 both down + */ + u8 temp = (key_value & 0x40) ? 0x30 : key_value; + for (i = 4; i < 6; i++) { + input_report_key(pen_dev, gt1x_stylus_key_array[i - 4], temp & (0x01 << i)); + } + GTP_DEBUG("Stulus key event."); + } +#endif + +#if GTP_WITH_STYLUS + if (CHK_BIT(cur_event, BIT_STYLUS)) { + coor_data = &touch_data[1]; + id = coor_data[0] & 0x7F; + input_x = coor_data[1] | (coor_data[2] << 8); + input_y = coor_data[3] | (coor_data[4] << 8); + input_w = coor_data[5] | (coor_data[6] << 8); + + input_x = GTP_WARP_X(gt1x_abs_x_max, input_x); + input_y = GTP_WARP_Y(gt1x_abs_y_max, input_y); + + GTP_DEBUG("Pen touch DOWN."); + gt1x_pen_down(input_x, input_y, input_w, 0); + } else if (CHK_BIT(pre_event, BIT_STYLUS)) { + GTP_DEBUG("Pen touch UP."); + gt1x_pen_up(0); + } +#endif + +#if GTP_HAVE_TOUCH_KEY + if (CHK_BIT(cur_event, BIT_TOUCH_KEY) || CHK_BIT(pre_event, BIT_TOUCH_KEY)) { + for (i = 0; i < GTP_MAX_KEY_NUM; i++) { + input_report_key(dev, gt1x_touch_key_array[i], key_value & (0x01 << i)); + } + if (CHK_BIT(cur_event, BIT_TOUCH_KEY)) { + GTP_DEBUG("Key Down."); + } else { + GTP_DEBUG("Key Up."); + } + } +#elif TPD_HAVE_BUTTON + if (CHK_BIT(cur_event, BIT_TOUCH_KEY) || CHK_BIT(pre_event, BIT_TOUCH_KEY)) { + for (i = 0; i < TPD_KEY_COUNT; i++) { + if (key_value & (0x01 << i)) { + gt1x_touch_down(tpd_virtual_key_array[i].x, tpd_virtual_key_array[i].y, 0, 0); + GTP_DEBUG("Key Down."); + break; + } + } + if (i == TPD_KEY_COUNT) { + gt1x_touch_up(0); + GTP_DEBUG("Key Up."); + } + } +#endif + +/* finger touch event*/ + if (CHK_BIT(cur_event, BIT_TOUCH)) { + u8 report_num = 0; + coor_data = &touch_data[1]; + id = coor_data[0] & 0x0F; + for (i = 0; i < GTP_MAX_TOUCH; i++) { + if (i == id) { + input_x = coor_data[1] | (coor_data[2] << 8); + input_y = coor_data[3] | (coor_data[4] << 8); + input_w = coor_data[5] | (coor_data[6] << 8); + + input_x = GTP_WARP_X(gt1x_abs_x_max, input_x); + input_y = GTP_WARP_Y(gt1x_abs_y_max, input_y); + + GTP_DEBUG("(%d)(%d,%d)[%d]", id, input_x, input_y, input_w); + gt1x_touch_down(input_x, input_y, input_w, i); + if (report_num++ < touch_num) { + coor_data += 8; + id = coor_data[0] & 0x0F; + } + pre_index |= 0x01 << i; + } else if (pre_index & (0x01 << i)) { +#if GTP_ICS_SLOT_REPORT + gt1x_touch_up(i); +#endif + pre_index &= ~(0x01 << i); + } + } + } else if (CHK_BIT(pre_event, BIT_TOUCH)) { +#if GTP_ICS_SLOT_REPORT + int cycles = pre_index < 3 ? 3 : GTP_MAX_TOUCH; + for (i = 0; i < cycles; i++) { + if (pre_index >> i & 0x01) { + gt1x_touch_up(i); + } + } +#else + gt1x_touch_up(0); +#endif + GTP_DEBUG("Released Touch."); + pre_index = 0; + } + + /* start sync input report */ + if (CHK_BIT(cur_event, BIT_STYLUS_KEY | BIT_STYLUS) + || CHK_BIT(pre_event, BIT_STYLUS_KEY | BIT_STYLUS)) { + input_sync(pen_dev); + } + + if (CHK_BIT(cur_event, BIT_TOUCH_KEY | BIT_TOUCH) + || CHK_BIT(pre_event, BIT_TOUCH_KEY | BIT_TOUCH)) { + input_sync(dev); + } + + if (unlikely(!pre_event && !cur_event)) { + GTP_DEBUG("Additional Int Pulse."); + } else { + pre_event = cur_event; + } + + return 0; +} + +#if GTP_WITH_STYLUS +struct input_dev *pen_dev; + +static void gt1x_pen_init(void) +{ + s32 ret = 0; + + pen_dev = input_allocate_device(); + if (pen_dev == NULL) { + GTP_ERROR("Failed to allocate input device for pen/stylus."); + return; + } + + pen_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + pen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + set_bit(BTN_TOOL_PEN, pen_dev->keybit); + set_bit(INPUT_PROP_DIRECT, pen_dev->propbit); + +#if GTP_HAVE_STYLUS_KEY + input_set_capability(pen_dev, EV_KEY, BTN_STYLUS); + input_set_capability(pen_dev, EV_KEY, BTN_STYLUS2); +#endif + + input_set_abs_params(pen_dev, ABS_MT_POSITION_X, 0, gt1x_abs_x_max, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_POSITION_Y, 0, gt1x_abs_y_max, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + pen_dev->name = "goodix-pen"; + pen_dev->phys = "input/ts"; + pen_dev->id.bustype = BUS_I2C; + + ret = input_register_device(pen_dev); + if (ret) { + GTP_ERROR("Register %s input device failed", pen_dev->name); + return; + } +} + +void gt1x_pen_down(s32 x, s32 y, s32 size, s32 id) +{ + input_report_key(pen_dev, BTN_TOOL_PEN, 1); +#if GTP_CHANGE_X2Y + GTP_SWAP(x, y); +#endif + +#if GTP_ICS_SLOT_REPORT + input_mt_slot(pen_dev, id); + input_report_abs(pen_dev, ABS_MT_PRESSURE, size); + input_report_abs(pen_dev, ABS_MT_TOUCH_MAJOR, size); + input_report_abs(pen_dev, ABS_MT_TRACKING_ID, id); + input_report_abs(pen_dev, ABS_MT_POSITION_X, x); + input_report_abs(pen_dev, ABS_MT_POSITION_Y, y); +#else + input_report_key(pen_dev, BTN_TOUCH, 1); + if ((!size) && (!id)) { + /* for virtual button */ + input_report_abs(pen_dev, ABS_MT_PRESSURE, 100); + input_report_abs(pen_dev, ABS_MT_TOUCH_MAJOR, 100); + } else { + input_report_abs(pen_dev, ABS_MT_PRESSURE, size); + input_report_abs(pen_dev, ABS_MT_TOUCH_MAJOR, size); + input_report_abs(pen_dev, ABS_MT_TRACKING_ID, id); + } + input_report_abs(pen_dev, ABS_MT_POSITION_X, x); + input_report_abs(pen_dev, ABS_MT_POSITION_Y, y); + input_mt_sync(pen_dev); +#endif +} + +void gt1x_pen_up(s32 id) +{ + input_report_key(pen_dev, BTN_TOOL_PEN, 0); +#if GTP_ICS_SLOT_REPORT + input_mt_slot(pen_dev, id); + input_report_abs(pen_dev, ABS_MT_TRACKING_ID, -1); +#else + input_report_key(pen_dev, BTN_TOUCH, 0); + input_mt_sync(pen_dev); +#endif +} +#endif + +/** + * Proximity Module + */ +#if GTP_PROXIMITY +#define GTP_PS_DEV_NAME "goodix_proximity" +#define GTP_REG_PROXIMITY_ENABLE 0x8049 +#define PS_FARAWAY 1 +#define PS_NEAR 0 +struct gt1x_ps_device{ + int enabled; // module enabled/disabled + int state; // Faraway or Near +#ifdef PLATFORM_MTK + struct hwmsen_object obj_ps; +#else + struct input_dev *input_dev; + struct kobject *kobj; +#endif +}; +static struct gt1x_ps_device *gt1x_ps_dev; + +static void gt1x_ps_report(int state) +{ +#ifdef PLATFORM_MTK + s32 ret = -1; + + hwm_sensor_data sensor_data; + //map and store data to hwm_sensor_data + sensor_data.values[0] = !!state; + sensor_data.value_divide = 1; + sensor_data.status = SENSOR_STATUS_ACCURACY_MEDIUM; + //report to the up-layer + ret = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data); + if (ret) { + GTP_ERROR("Call hwmsen_get_interrupt_data fail = %d\n", ret); + } +#else + input_report_abs(gt1x_ps_dev->input_dev, ABS_DISTANCE, !!state); + input_sync(gt1x_ps_dev->input_dev); +#endif /* End PLATFROM_MTK */ + + GTP_INFO("Report proximity state: %s", state == PS_FARAWAY? "FARAWAY":"NEAR"); +} + +static s32 gt1x_ps_enable(s32 enable) +{ + u8 state; + s32 ret = -1; + + GTP_INFO("Proximity function to be %s.", enable ? "on" : "off"); + state = enable ? 1 : 0; + if (gt1x_chip_type == CHIP_TYPE_GT1X) + ret = gt1x_i2c_write(GTP_REG_PROXIMITY_ENABLE, &state, 1); + else if (gt1x_chip_type == CHIP_TYPE_GT2X) + ret = gt1x_send_cmd(state ? 0x12 : 0x13, 0); + if (ret) { + GTP_ERROR("GTP %s proximity cmd failed.", state ? "enable" : "disable"); + } + + if (!ret && enable) { + gt1x_ps_dev->enabled = 1; + } else { + gt1x_ps_dev->enabled = 0; + } + gt1x_ps_dev->state = PS_FARAWAY; + GTP_INFO("Proximity function %s %s.", state ? "enable" : "disable", ret ? "fail" : "success"); + return ret; +} + +int gt1x_prox_event_handler(u8 * data) +{ + u8 ps = 0; + + if (gt1x_ps_dev && gt1x_ps_dev->enabled) { + ps = (data[0] & 0x60) ? 0 : 1; + if (ps != gt1x_ps_dev->state) { + gt1x_ps_report(ps); + gt1x_ps_dev->state = ps; + GTP_DEBUG("REG INDEX[0x814E]:0x%02X\n", data[0]); + } + + return (ps == PS_NEAR? 1 : 0); + } + return -1; +} + +#ifdef PLATFORM_MTK +static inline s32 gt1x_get_ps_value(void) +{ + return gt1x_ps_dev->state; +} + +static s32 gt1x_ps_operate(void *self, u32 command, void *buff_in, s32 size_in, void *buff_out, s32 size_out, s32 * actualout) +{ + s32 err = 0; + s32 value; + hwm_sensor_data *sensor_data; + + GTP_INFO("psensor operator cmd:%d", command); + switch (command) { + case SENSOR_DELAY: + if ((buff_in == NULL) || (size_in < sizeof(int))) { + GTP_ERROR("Set delay parameter error!"); + err = -EINVAL; + } + // Do nothing + break; + + case SENSOR_ENABLE: + if ((buff_in == NULL) || (size_in < sizeof(int))) { + GTP_ERROR("Enable sensor parameter error!"); + err = -EINVAL; + } else { + value = *(int *)buff_in; + err = gt1x_ps_enable(value); + } + + break; + + case SENSOR_GET_DATA: + if ((buff_out == NULL) || (size_out < sizeof(hwm_sensor_data))) { + GTP_ERROR("Get sensor data parameter error!"); + err = -EINVAL; + } else { + sensor_data = (hwm_sensor_data *) buff_out; + sensor_data->values[0] = gt1x_get_ps_value(); + sensor_data->value_divide = 1; + sensor_data->status = SENSOR_STATUS_ACCURACY_MEDIUM; + } + + break; + + default: + GTP_ERROR("proxmy sensor operate function no this parameter %d!\n", command); + err = -1; + break; + } + + return err; +} +#endif + +#ifndef PLATFORM_MTK +static ssize_t gt1x_ps_enable_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { + return scnprintf(buf, PAGE_SIZE, "%d", gt1x_ps_dev->enabled); +} + +static ssize_t gt1x_ps_enable_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) { + unsigned int input; + if(sscanf(buf, "%u", &input) != 1) { + return -EINVAL; + } + if(input == 1) { + gt1x_ps_enable(1); + gt1x_ps_report(PS_FARAWAY); + } else if(input == 0) { + gt1x_ps_report(PS_FARAWAY); + gt1x_ps_enable(0); + } else { + return -EINVAL; + } + return count; +} + +static ssize_t gt1x_ps_state_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) { + return scnprintf(buf, PAGE_SIZE, "%d", gt1x_ps_dev->state); +} + +static ssize_t gt1x_ps_state_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) { + unsigned int input; + if(sscanf(buf, "%u", &input) != 1) { + return -EINVAL; + } + + if (!gt1x_ps_dev->enabled) { + return -EINVAL; + } + + if(input == 1) { + gt1x_ps_dev->state = PS_FARAWAY; + } else if(input == 0) { + gt1x_ps_dev->state = PS_NEAR; + } else { + return -EINVAL; + } + + gt1x_ps_report(gt1x_ps_dev->state); + return count; +} + +static struct kobj_attribute ps_attrs[] = { + __ATTR(enable, S_IWUGO | S_IRUGO, gt1x_ps_enable_show, gt1x_ps_enable_store), + __ATTR(state, S_IWUGO | S_IRUGO, gt1x_ps_state_show, gt1x_ps_state_store) +}; + +#endif /* End PLATFORM_MTK */ + +static int gt1x_ps_init(void) +{ + int err; + + gt1x_ps_dev = kzalloc(sizeof(struct gt1x_ps_device), GFP_KERNEL); + if (!gt1x_ps_dev) { + return -ENOMEM; + } + + gt1x_ps_dev->state = PS_FARAWAY; + +#ifdef PLATFORM_MTK + gt1x_ps_dev->obj_ps.polling = 0; //0--interrupt mode;1--polling mode; + gt1x_ps_dev->obj_ps.sensor_operate = gt1x_ps_operate; + + if ((err = hwmsen_attach(ID_PROXIMITY, >1x_ps_dev->obj_ps))) { + GTP_ERROR("hwmsen attach fail, return:%d.", err); + goto err_exit; + } + + GTP_INFO("hwmsen attach OK."); + return 0; +#else + gt1x_ps_dev->input_dev = input_allocate_device(); + if(!gt1x_ps_dev->input_dev) { + GTP_ERROR("Failed to alloc inpput device for proximity!"); + err = -ENOMEM; + goto err_exit; + } + + gt1x_ps_dev->input_dev->name = GTP_PS_DEV_NAME; + gt1x_ps_dev->input_dev->phys = "goodix/proximity"; + gt1x_ps_dev->input_dev->id.bustype = BUS_I2C; + gt1x_ps_dev->input_dev->id.vendor = 0xDEED; + gt1x_ps_dev->input_dev->id.product = 0xBEEF; + gt1x_ps_dev->input_dev->id.version = 1; + set_bit(EV_ABS, gt1x_ps_dev->input_dev->evbit); + input_set_abs_params(gt1x_ps_dev->input_dev, ABS_DISTANCE, 0, 1, 0, 0); + + err = input_register_device(gt1x_ps_dev->input_dev); + if(err) { + GTP_ERROR("Failed to register proximity input device: %s!", gt1x_ps_dev->input_dev->name); + goto err_register_dev; + } + /* register sysfs interface */ + if (!sysfs_rootdir) { + sysfs_rootdir = kobject_create_and_add("goodix", NULL); + if(!sysfs_rootdir){ + GTP_ERROR("Failed to create and add sysfs interface: goodix."); + err = -ENOMEM; + goto err_register_dev; + } + } + + gt1x_ps_dev->kobj = kobject_create_and_add("proximity", sysfs_rootdir); + if(!gt1x_ps_dev->kobj){ + GTP_ERROR("Failed to create and add sysfs interface: proximity."); + err = -ENOMEM; + goto err_register_dev; + } + // create sysfs files + { + int i; + for(i = 0; i < sizeof(ps_attrs)/sizeof(ps_attrs[0]); i++) { + if((err = sysfs_create_file(gt1x_ps_dev->kobj, &ps_attrs[i].attr))) { + goto err_create_file; + } + } + } + + GTP_INFO("Proximity sensor init OK."); + return 0; +err_create_file: + kobject_put(gt1x_ps_dev->kobj); +err_register_dev: + input_free_device(gt1x_ps_dev->input_dev); +#endif /* End PLATFROM_MTK */ + +err_exit: + kfree(gt1x_ps_dev); + gt1x_ps_dev = NULL; + return err; +} + +static void gt1x_ps_deinit(void) +{ + if(gt1x_ps_dev) { +#ifndef PLATFORM_MTK + int i = 0; + for(; i < sizeof(ps_attrs) / sizeof(ps_attrs[0]); i++) { + sysfs_remove_file(gt1x_ps_dev->kobj, &ps_attrs[i].attr); + } + kobject_del(gt1x_ps_dev->kobj); + input_free_device(gt1x_ps_dev->input_dev); +#endif + kfree(gt1x_ps_dev); + } +} + +#endif /*GTP_PROXIMITY */ + +/** + * ESD Protect Module + */ +#if GTP_ESD_PROTECT +static int esd_work_cycle = 200; +static struct delayed_work esd_check_work; +static int esd_running = 0; +static struct mutex esd_lock; +static void gt1x_esd_check_func(struct work_struct *); + +void gt1x_init_esd_protect(void) +{ + esd_work_cycle = 2 * HZ; // HZ: clock ticks in 1 second generated by system + GTP_DEBUG("Clock ticks for an esd cycle: %d", esd_work_cycle); + INIT_DELAYED_WORK(&esd_check_work, gt1x_esd_check_func); + mutex_init(&esd_lock); +} + +static void gt1x_deinit_esd_protect(void) +{ + gt1x_esd_switch(SWITCH_OFF); +} + +void gt1x_esd_switch(s32 on) +{ + mutex_lock(&esd_lock); + if (SWITCH_ON == on) { /* switch on esd check */ + if (!esd_running) { + esd_running = 1; + GTP_INFO("Esd protector started!"); + queue_delayed_work(gt1x_workqueue, &esd_check_work, esd_work_cycle); + } + } else { /* switch off esd check */ + if (esd_running) { + esd_running = 0; + GTP_INFO("Esd protector stoped!"); + cancel_delayed_work(&esd_check_work); + } + } + mutex_unlock(&esd_lock); +} + +static void gt1x_esd_check_func(struct work_struct *work) +{ + s32 i = 0; + s32 ret = -1; + u8 esd_buf[4] = { 0 }; + + if (!esd_running) { + GTP_INFO("Esd protector suspended!"); + return; + } + + for (i = 0; i < 3; i++) { + ret = gt1x_i2c_read(GTP_REG_CMD, esd_buf, 4); + GTP_DEBUG("[Esd]0x8040 = 0x%02X, 0x8043 = 0x%02X", esd_buf[0], esd_buf[3]); + if (!ret && esd_buf[0] != 0xAA && esd_buf[3] == 0xAA) { + break; + } + msleep(50); + } + + if (likely(i < 3)) { + /* IC works normally, Write 0x8040 0xAA, feed the watchdog */ + gt1x_send_cmd(GTP_CMD_ESD, 0); + } else { + if (esd_running) { + GTP_ERROR("IC works abnormally! Process reset guitar."); + memset(esd_buf, 0x01, sizeof(esd_buf)); + gt1x_i2c_write(0x4226, esd_buf, sizeof(esd_buf)); + msleep(50); + + gt1x_power_reset(); + } else { + GTP_INFO("Esd protector suspended, no need reset!"); + } + } + + mutex_lock(&esd_lock); + if (esd_running) { + queue_delayed_work(gt1x_workqueue, &esd_check_work, esd_work_cycle); + } else { + GTP_INFO("Esd protector suspended!"); + } + mutex_unlock(&esd_lock); +} +#endif + +/** + * Smart Cover Module + */ +#if GTP_SMART_COVER +struct smart_cover_device{ + int enabled; + int state; // 0:cover faraway 1:near + int suspended; // suspended or woring + struct kobject *kobj; + u8 config[GTP_CONFIG_MAX_LENGTH]; + int cfg_len; +}; +static struct smart_cover_device *gt1x_sc_dev; + +/** + * gt1x_smart_cover_update_state - update smart cover config + */ +static int gt1x_smart_cover_update_state(void) +{ + int ret = 0; + struct smart_cover_device *dev = gt1x_sc_dev; + + if (!dev) { + return -ENODEV; + } + + if(!dev->suspended) { + if(dev->state) { /* near */ + ret = gt1x_send_cfg(dev->config, dev->cfg_len); + } else { + #if GTP_CHARGER_SWITCH + gt1x_charger_config(1); // charger detector module check and + // send a config + #else + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + #endif + } + GTP_DEBUG("Update cover state %s.", dev->state ? "Nearby" : "Far away"); + } else { + GTP_DEBUG("TP is suspended, do nothing."); + } + return ret; +} + +static ssize_t smart_cover_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct smart_cover_device *dev = gt1x_sc_dev; + + if (!dev) { + return -ENODEV; + } + + return scnprintf(buf, PAGE_SIZE, "%d", dev->state); +} + +static ssize_t smart_cover_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct smart_cover_device *dev = gt1x_sc_dev; + int s = (buf[0] - '0'); + + if (!dev || !dev->enabled || s > 1 || s == dev->state) { + return count; + } + + dev->state = s; + gt1x_smart_cover_update_state(); + + return count; +} + +/** + * gt1x_parse_sc_cfg - parse smart cover config + * @sensor_id: sensor id of the hardware + */ +int gt1x_parse_sc_cfg(int sensor_id) +{ +#undef _cfg_array_ +#define _cfg_array_(n) GTP_SMART_COVER_CFG_GROUP##n + + u8 *cfg; + int *len; + + if (!gt1x_sc_dev) + return -ENODEV; + cfg = gt1x_sc_dev->config; + len = >1x_sc_dev->cfg_len; + +#if GTP_DRIVER_SEND_CFG + do{ + u8 cfg_grp0[] = _cfg_array_(0); + u8 cfg_grp1[] = _cfg_array_(1); + u8 cfg_grp2[] = _cfg_array_(2); + u8 cfg_grp3[] = _cfg_array_(3); + u8 cfg_grp4[] = _cfg_array_(4); + u8 cfg_grp5[] = _cfg_array_(5); + u8 *cfgs[] = { + cfg_grp0, cfg_grp1, cfg_grp2, + cfg_grp3, cfg_grp4, cfg_grp5 + }; + u8 cfg_lens[] = { + CFG_GROUP_LEN(cfg_grp0), CFG_GROUP_LEN(cfg_grp1), + CFG_GROUP_LEN(cfg_grp2), CFG_GROUP_LEN(cfg_grp3), + CFG_GROUP_LEN(cfg_grp4), CFG_GROUP_LEN(cfg_grp5) + }; + + if (sensor_id >= sizeof(cfgs) / sizeof(cfgs[0])) { + GTP_ERROR("Invalid sensor id."); + return -1; + } + + *len = cfg_lens[sensor_id]; + if (*len == 0 || *len != gt1x_cfg_length) { + memset(cfg, 0, GTP_CONFIG_MAX_LENGTH); + *len = 0; + GTP_ERROR("Length of config is incorrect."); + return -1; + } + + memcpy(cfg, cfgs[sensor_id], cfg_lens[sensor_id]); + + cfg[0] &= 0x7F; + set_reg_bit(cfg[TRIGGER_LOC], 0, gt1x_int_type); + set_reg_bit(cfg[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); + }while(0); +#endif + return 0; +} + + +static struct kobj_attribute sc_attr = + __ATTR(state, S_IWUGO | S_IRUGO, smart_cover_show, smart_cover_store); +static int gt1x_smart_cover_init(void) +{ + int err = 0; + + gt1x_sc_dev = kzalloc(sizeof(struct smart_cover_device), GFP_KERNEL); + if (!gt1x_sc_dev) { + GTP_ERROR("SmartCover init failed in step: 1."); + return -ENOMEM; + } + + gt1x_sc_dev->enabled = 1; + gt1x_parse_sc_cfg(gt1x_version.sensor_id); + + if (!sysfs_rootdir) { + // this kobject is shared between modules, do not free it when error occur + sysfs_rootdir = kobject_create_and_add(GOODIX_SYSFS_DIR, NULL); + if (!sysfs_rootdir) { + err = -2; + goto exit_free_mem; + } + } + + if (!gt1x_sc_dev->kobj) + gt1x_sc_dev->kobj = kobject_create_and_add("smartcover", sysfs_rootdir); + if (!gt1x_sc_dev->kobj) { + err = -3; + goto exit_free_mem; + } + + if(sysfs_create_file(gt1x_sc_dev->kobj, &sc_attr.attr)) { + err = -4; + goto exit_put_kobj; + } + + GTP_INFO("SmartCover module init OK."); + return 0; + +exit_put_kobj: + kobject_put(gt1x_sc_dev->kobj); +exit_free_mem: + kfree(gt1x_sc_dev); + gt1x_sc_dev = NULL; + GTP_ERROR("SmartCover init failed in step:%d", -err); + return err; +} + +static void gt1x_smart_cover_deinit(void) +{ + if (!gt1x_sc_dev) { + return; + } + + kobject_del(gt1x_sc_dev->kobj); + kfree(gt1x_sc_dev); + gt1x_sc_dev = NULL; +} +#endif + +/** + * Charger Detect & Switch Module + */ +#if GTP_CHARGER_SWITCH +static u8 gt1x_config_charger[GTP_CONFIG_MAX_LENGTH] = { 0 }; +static struct delayed_work charger_switch_work; +static int charger_work_cycle = 200; +static spinlock_t charger_lock; +static int charger_running = 0; +static void gt1x_charger_work_func(struct work_struct *); + +/** + * gt1x_parse_chr_cfg - parse charger config + * @sensor_id: sensor id of the hardware + * Return: 0: succeed, <0 error + */ +int gt1x_parse_chr_cfg(int sensor_id) +{ +#undef _cfg_array_ +#define _cfg_array_(n) GTP_CHARGER_CFG_GROUP##n + + u8 *cfg; + int len; + cfg = gt1x_config_charger; + +#if GTP_DRIVER_SEND_CFG + do{ + u8 cfg_grp0[] = _cfg_array_(0); + u8 cfg_grp1[] = _cfg_array_(1); + u8 cfg_grp2[] = _cfg_array_(2); + u8 cfg_grp3[] = _cfg_array_(3); + u8 cfg_grp4[] = _cfg_array_(4); + u8 cfg_grp5[] = _cfg_array_(5); + u8 *cfgs[] = { + cfg_grp0, cfg_grp1, cfg_grp2, + cfg_grp3, cfg_grp4, cfg_grp5 + }; + u8 cfg_lens[] = { + CFG_GROUP_LEN(cfg_grp0), CFG_GROUP_LEN(cfg_grp1), + CFG_GROUP_LEN(cfg_grp2), CFG_GROUP_LEN(cfg_grp3), + CFG_GROUP_LEN(cfg_grp4), CFG_GROUP_LEN(cfg_grp5) + }; + + if (sensor_id >= sizeof(cfgs) / sizeof(cfgs[0])) { + return -1; + } + + len = cfg_lens[sensor_id]; + if (len == 0 || len != gt1x_cfg_length) { + memset(cfg, 0, GTP_CONFIG_MAX_LENGTH); + GTP_ERROR("Length of config is incorrect."); + return -1; + } + + memcpy(cfg, cfgs[sensor_id], cfg_lens[sensor_id]); + + cfg[0] &= 0x7F; + cfg[RESOLUTION_LOC] = (u8) gt1x_abs_x_max; + cfg[RESOLUTION_LOC + 1] = (u8) (gt1x_abs_x_max >> 8); + cfg[RESOLUTION_LOC + 2] = (u8) gt1x_abs_y_max; + cfg[RESOLUTION_LOC + 3] = (u8) (gt1x_abs_y_max >> 8); + + set_reg_bit(cfg[TRIGGER_LOC], 0, gt1x_int_type); + set_reg_bit(cfg[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); + }while(0); +#endif + return 0; +} + + +static void gt1x_init_charger(void) +{ + charger_work_cycle = 2 * HZ; // HZ: clock ticks in 1 second generated by system + GTP_DEBUG("Clock ticks for an charger cycle: %d", charger_work_cycle); + INIT_DELAYED_WORK(&charger_switch_work, gt1x_charger_work_func); + spin_lock_init(&charger_lock); + + if (gt1x_parse_chr_cfg(gt1x_version.sensor_id) < 0) { + GTP_ERROR("Error occured when parse charger config."); + } +} + +/** + * gt1x_charger_switch - switch states of charging work thread + * + * @on: SWITCH_ON - start work thread, SWITCH_OFF: stop . + * + */ +void gt1x_charger_switch(s32 on) +{ + spin_lock(&charger_lock); + if (SWITCH_ON == on) { + if (!charger_running) { + charger_running = 1; + spin_unlock(&charger_lock); + GTP_INFO("Charger checker started!"); + queue_delayed_work(gt1x_workqueue, &charger_switch_work, charger_work_cycle); + } else { + spin_unlock(&charger_lock); + } + } else { + if (charger_running) { + charger_running = 0; + spin_unlock(&charger_lock); + cancel_delayed_work(&charger_switch_work); + GTP_INFO("Charger checker stoped!"); + } else { + spin_unlock(&charger_lock); + } + } +} + +/** + * gt1x_charger_config - check and update charging status configuration + * @dir_update + * 0: check before send charging status configuration + * 1: directly send charging status configuration + * + */ +void gt1x_charger_config(s32 dir_update) +{ + static u8 chr_pluggedin = 0; + +#if GTP_SMART_COVER + if (gt1x_sc_dev && gt1x_sc_dev->enabled + && gt1x_sc_dev->state) { + return; + } +#endif + + if (gt1x_get_charger_status()) { + if (!chr_pluggedin || dir_update) { + GTP_INFO("Charger Plugin."); + if (gt1x_send_cfg(gt1x_config_charger, gt1x_cfg_length)) { + GTP_ERROR("Send config for Charger Plugin failed!"); + } + if (gt1x_send_cmd(GTP_CMD_CHARGER_ON, 0)) { + GTP_ERROR("Update status for Charger Plugin failed!"); + } + chr_pluggedin = 1; + } + } else { + if (chr_pluggedin || dir_update) { + GTP_INFO("Charger Plugout."); + if (gt1x_send_cfg(gt1x_config, gt1x_cfg_length)) { + GTP_ERROR("Send config for Charger Plugout failed!"); + } + if (gt1x_send_cmd(GTP_CMD_CHARGER_OFF, 0)) { + GTP_ERROR("Update status for Charger Plugout failed!"); + } + chr_pluggedin = 0; + } + } +} + +static void gt1x_charger_work_func(struct work_struct *work) +{ + if (!charger_running) { + GTP_INFO("Charger checker suspended!"); + return; + } + + gt1x_charger_config(0); + + GTP_DEBUG("Charger check done!"); + if (charger_running) { + queue_delayed_work(gt1x_workqueue, &charger_switch_work, charger_work_cycle); + } +} +#endif + +int gt1x_suspend(void) +{ + s32 ret = -1; +#if GTP_HOTKNOT && !HOTKNOT_BLOCK_RW + u8 buf[1] = { 0 }; +#endif + + if (update_info.status) { + return 0; + } +#if GTP_SMART_COVER + if (gt1x_sc_dev) { + gt1x_sc_dev->suspended = 1; + } +#endif + GTP_INFO("Suspend start..."); +#if GTP_PROXIMITY + if (gt1x_ps_dev && gt1x_ps_dev->enabled) { + GTP_INFO("proximity is detected!"); + return 0; + } +#endif + +#if GTP_HOTKNOT + if (hotknot_enabled) { +#if HOTKNOT_BLOCK_RW + if (hotknot_paired_flag) { + GTP_INFO("hotknot is paired!"); + return 0; + } +#else + ret = gt1x_i2c_read_dbl_check(GTP_REG_HN_PAIRED, buf, sizeof(buf)); + if ((!ret && buf[0] == 0x55) || hotknot_transfer_mode) { + GTP_DEBUG("0x81AA: 0x%02X", buf[0]); + GTP_INFO("hotknot is paired!"); + return 0; + } +#endif + } +#endif + + gt1x_halt = 1; +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif +#if GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_OFF); +#endif + gt1x_irq_disable(); + +#if GTP_GESTURE_WAKEUP + gesture_clear_wakeup_data(); + if (gesture_enabled) { + gesture_enter_doze(); + gt1x_irq_enable(); + gt1x_halt = 0; + } else +#endif + { + ret = gt1x_enter_sleep(); + if (ret < 0) { + GTP_ERROR("Suspend failed."); + } + } + + /* to avoid waking up while not sleeping + delay 48 + 10ms to ensure reliability */ + msleep(58); + GTP_INFO("Suspend end..."); + return 0; +} + +int gt1x_resume(void) +{ + s32 ret = -1; + + if (update_info.status) { + return 0; + } + +#if GTP_SMART_COVER + if (gt1x_sc_dev) { + gt1x_sc_dev->suspended = 0; + } +#endif + GTP_INFO("Resume start..."); + +#if GTP_PROXIMITY + if (gt1x_ps_dev && gt1x_ps_dev->enabled) { + GTP_INFO("Proximity is on!"); + return 0; + } +#endif + +#if GTP_HOTKNOT + if (hotknot_enabled) { + #if HOTKNOT_BLOCK_RW + if (hotknot_paired_flag) { + hotknot_paired_flag = 0; + GTP_INFO("Hotknot is paired!"); + return 0; + } + #endif + } +#endif + +#if GTP_GESTURE_WAKEUP + /* just return 0 if IC does not suspend */ + if (!gesture_enabled && !gt1x_halt) + return 0; +#else + if (!gt1x_halt) + return 0; +#endif + + ret = gt1x_wakeup_sleep(); + if (ret < 0) { + GTP_ERROR("Resume failed."); + } +#if GTP_HOTKNOT + if (!hotknot_enabled) { + gt1x_send_cmd(GTP_CMD_HN_EXIT_SLAVE, 0); + } +#endif + +#if GTP_CHARGER_SWITCH + gt1x_charger_config(0); + gt1x_charger_switch(SWITCH_ON); +#endif + + gt1x_halt = 0; + gt1x_irq_enable(); + +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + + GTP_DEBUG("Resume end."); + return 0; +} + +s32 gt1x_init(void) +{ + s32 ret = -1; + s32 retry = 0; + u8 reg_val[1]; + + /* power on */ + gt1x_power_switch(SWITCH_ON); + + while (retry++ < 5) { + gt1x_init_failed = 0; + /* reset ic */ + ret = gt1x_reset_guitar(); + if (ret != 0) { + GTP_ERROR("Reset guitar failed!"); + continue; + } + + /* check main system firmware */ + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_MAINSYS, reg_val, 1); + if (ret != 0) { + continue; + } else if (reg_val[0] != 0xBE) { + GTP_ERROR("Check main system not pass[0x%2X].", reg_val[0]); + gt1x_init_failed = 1; + } + +#if !GTP_AUTO_UPDATE + /* debug info */ + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_SUBSYS, reg_val, 1); + if (!ret && reg_val[0] == 0xAA) { + GTP_ERROR("Check subsystem not pass[0x%2X].", reg_val[0]); + } +#endif + break; + } + + /* if the initialization fails, set default setting */ + ret |= gt1x_init_failed; + if (ret) { + GTP_ERROR("Init failed, use default setting"); + gt1x_abs_x_max = GTP_MAX_WIDTH; + gt1x_abs_y_max = GTP_MAX_HEIGHT; + gt1x_int_type = GTP_INT_TRIGGER; + gt1x_wakeup_level = GTP_WAKEUP_LEVEL; + } + + /* get chip type */ + ret = gt1x_get_chip_type(); + if (ret != 0) { + GTP_ERROR("Get chip type failed!"); + } + + /* read version information */ + ret = gt1x_read_version(>1x_version); + if (ret != 0) { + GTP_ERROR("Get verision failed!"); + } + + + /* init and send configs */ + ret = gt1x_init_panel(); + if (ret != 0) { + GTP_ERROR("Init panel failed."); + } + + gt1x_workqueue = create_singlethread_workqueue("gt1x_workthread"); + if (gt1x_workqueue == NULL) { + GTP_ERROR("Create workqueue failed!"); + } + +/* init auxiliary node and functions */ + gt1x_init_debug_node(); + +#if GTP_CREATE_WR_NODE + gt1x_init_tool_node(); +#endif + +#if GTP_GESTURE_WAKEUP || GTP_HOTKNOT + gt1x_init_node(); +#endif + +#if GTP_PROXIMITY + gt1x_ps_init(); +#endif + +#if GTP_CHARGER_SWITCH + gt1x_init_charger(); + gt1x_charger_config(1); + gt1x_charger_switch(SWITCH_ON); +#endif + +#if GTP_SMART_COVER + gt1x_smart_cover_init(); +#endif + +#if GTP_WITH_STYLUS + gt1x_pen_init(); +#endif + + return ret; +} + +void gt1x_deinit(void) +{ + gt1x_deinit_debug_node(); + +#if GTP_GESTURE_WAKEUP || GTP_HOTKNOT + gt1x_deinit_node(); +#endif + +#if GTP_CREATE_WR_NODE + gt1x_deinit_tool_node(); +#endif + +#if GTP_ESD_PROTECT + gt1x_deinit_esd_protect(); +#endif + +#if GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_OFF); +#endif + +#if GTP_PROXIMITY + gt1x_ps_deinit(); +#endif + +#if GTP_SMART_COVER + gt1x_smart_cover_deinit(); +#endif + + if (sysfs_rootdir) { + kobject_del(sysfs_rootdir); + sysfs_rootdir = NULL; + } + + if (gt1x_workqueue) { + destroy_workqueue(gt1x_workqueue); + } + +} + diff --git a/drivers/input/touchscreen/gt1xx/gt1x_generic.h b/drivers/input/touchscreen/gt1xx/gt1x_generic.h new file mode 100755 index 00000000000..c5e03a01eca --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x_generic.h @@ -0,0 +1,604 @@ +/* drivers/input/touchscreen/gt1x_generic.h + * + * 2010 - 2014 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ + +#ifndef _GT1X_GENERIC_H_ +#define _GT1X_GENERIC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +/********* Device Tree Support *********/ +#ifdef CONFIG_OF +#define GTP_CONFIG_OF +#endif +/***************************PART1:ON/OFF define*******************************/ +#define GTP_INCELL_PANEL 0 +#define GTP_DRIVER_SEND_CFG 1 // send config to TP while initializing (for no config built in TP's flash) +#define GTP_CUSTOM_CFG 0 // customize resolution & interrupt trigger mode + +#define GTP_CHANGE_X2Y 0 // exchange xy +#define GTP_WARP_X_ON 0 +#define GTP_WARP_Y_ON 0 + +#define GTP_GESTURE_WAKEUP 0 // gesture wakeup module +/* buffer used to store ges track points coor. */ +#define GES_BUFFER_ADDR 0xA2A0 // GT1151 +//#define GES_BUFFER_ADDR 0x8A40 // GT9L +//#define GES_BUFFER_ADDR 0x9734 // GT1152 +//#define GES_BUFFER_ADDR 0xBDA8 // GT9286 +#ifndef GES_BUFFER_ADDR +#warning [GOODIX] need define GES_BUFFER_ADDR . +#endif +#define KEY_GES_REGULAR KEY_F2 // regular gesture-key +#define KEY_GES_CUSTOM KEY_F3 //customize gesture-key + +#define GTP_HOTKNOT 0 // hotknot module +#define HOTKNOT_TYPE 0 // 0: hotknot in flash; 1: hotknot in driver +#define HOTKNOT_BLOCK_RW 0 // + +#define GTP_AUTO_UPDATE 0 // auto update FW to TP FLASH while initializing +#define GTP_HEADER_FW_UPDATE 0 // firmware in gt1x_firmware.h +#define GTP_FW_UPDATE_VERIFY 0 // verify fw when updating + +#define GTP_HAVE_TOUCH_KEY 0 // touch key support +#define GTP_WITH_STYLUS 0 // pen support +#define GTP_HAVE_STYLUS_KEY 0 // + +#define GTP_POWER_CTRL_SLEEP 0 // turn off power on suspend +#define GTP_ICS_SLOT_REPORT 0 +#define GTP_CREATE_WR_NODE 1 // create the interface to support gtp_tools + +#define GTP_PROXIMITY 0 // proximity module (function as the p-sensor) +#define GTP_SMART_COVER 0 // smart cover module + +#define GTP_ESD_PROTECT 0 // esd-protection module (with a cycle of 2 seconds) +#define GTP_CHARGER_SWITCH 0 // charger plugin & plugout detect + +#define GTP_DEBUG_ON 0 // enable log printed by GTP_DEBUG(...) +#define GTP_DEBUG_ARRAY_ON 0 +#define GTP_DEBUG_FUNC_ON 0 + +/***************************PART2:TODO define**********************************/ +/* Normal Configs + * TODO: puts the config info corresponded to your TP here, the following is just + * a sample config, send this config should cause the chip cannot work normally + */ +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) +/* TODO define your config for Sensor_ID == 0 here, if needed */ +/* +#define GTP_CFG_GROUP0 {\ + 0x44,0xD0,0x02,0x00,0x05,0x05,0x3D,0x10,0x00,0x08,\ + 0x00,0x05,0x3C,0x28,0x5E,0x00,0x11,0x00,0x00,0x00,\ + 0x28,0x82,0x96,0xFC,0xC8,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x26,0x17,0x64,\ + 0x66,0xDF,0x07,0x91,0x31,0x18,0x0C,0x43,0x24,0x00,\ + 0x06,0x28,0x6E,0x80,0x94,0x02,0x05,0x08,0x04,0xDA,\ + 0x33,0xAF,0x3F,0x92,0x4A,0x7F,0x56,0x71,0x62,0x66,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0F,0x19,0x04,\ + 0x0F,0x10,0x42,0xD8,0x0F,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0xFF,0xFF,0x04,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x05,0x1E,0x00,0x70,0x17,0x50,0x1E,\ + 0x08,0x09,0x0A,0x0B,0x0C,0x0F,0x0E,0x10,0x0D,0x12,\ + 0x13,0x1F,0x1E,0x1D,0x1C,0x1B,0x1A,0x19,0x18,0x17,\ + 0x16,0x15,0x14,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,\ + 0x09,0x0A,0x0B,0x0C,0x0D,0xFF,0xFF,0xFF,0xFF,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x00,0x00,\ + 0x00,0x00,0x24,0x1E,0x6D,0x00,0x14,0x28,0x00,0x00,\ + 0x10,0x00,0x00,0x00,0x00,0x00,0x23,0x99,0x01\ +} +*/ +#define GTP_CFG_GROUP0 {\ + 0x43,0xE0,0x01,0x80,0x02,0x0A,0x35,0x30,0x01,0x00,0x00,0x0F,\ + 0x5A,0x3C,0x53,0x00,0x00,0x00,0x00,0x00,0x14,0x17,0x19,0x1D,\ + 0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x1E,0x28,0x86,0x26,\ + 0x09,0x2E,0x30,0x0F,0x0A,0x00,0x00,0x60,0x02,0x03,0x27,0x00,\ + 0x00,0x23,0x46,0xC0,0x14,0x02,0x00,0x00,0x54,0xB5,0x28,0x9E,\ + 0x2E,0x8D,0x34,0x80,0x3A,0x75,0x40,0x6C,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x06,0x0C,0x05,\ + 0x0B,0x04,0x0A,0x03,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x06,0x07,\ + 0x08,0x09,0x0A,0x0B,0x05,0x04,0x03,0x02,0x01,0x00,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x01,0xFF,0xFF,0x86,0x33,0x02,0x00,0x00,0x12,0x00,0x0F,0x00,\ + 0x00,0x00,0x46,0x32,0x50,0x00,0x00,0x00,0x7D,0x8D,0x01\ +} + +/* TODO define your config for Sensor_ID == 1 here, if needed */ +#define GTP_CFG_GROUP1 {\ + } +/* TODO define your config for Sensor_ID == 2 here, if needed */ +#define GTP_CFG_GROUP2 {\ + } +/* TODO define your config for Sensor_ID == 3 here, if needed */ +#define GTP_CFG_GROUP3 {\ + } +/* TODO define your config for Sensor_ID == 4 here, if needed */ +#define GTP_CFG_GROUP4 {\ + } +/* TODO define your config for Sensor_ID == 5 here, if needed */ +#define GTP_CFG_GROUP5 {\ + } + +/* + * Charger Configs +*/ +/* TODO define your config for Sensor_ID == 0 here, if needed */ +#define GTP_CHARGER_CFG_GROUP0 {\ + 0x45,0x1C,0x02,0xC0,0x03,0x05,0x3D,0x10,0x00,0x08,\ + 0x00,0x05,0x50,0x28,0x5E,0x00,0x11,0x00,0x00,0x00,\ + 0x28,0x80,0x87,0xFE,0xC8,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x26,0x17,0x64,\ + 0x66,0xDF,0x07,0x91,0x31,0x18,0x0C,0x43,0x24,0x00,\ + 0x06,0x3C,0x8C,0x80,0x94,0x02,0x05,0x08,0x04,0xC2,\ + 0x49,0xA4,0x56,0x8E,0x63,0x80,0x71,0x75,0x7E,0x6E,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0F,0x23,0x04,\ + 0x0F,0x10,0x42,0xD8,0x0F,0x00,0x0F,0x00,0x00,0x00,\ + 0x00,0x00,0xFF,0xFF,0x04,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x05,0x1E,0x00,0x70,0x17,0x50,0x1E,\ + 0x08,0x09,0x0A,0x0B,0x0C,0x0F,0x0E,0x10,0x0D,0x12,\ + 0x13,0x1F,0x1E,0x1D,0x1C,0x1B,0x1A,0x19,0x18,0x17,\ + 0x16,0x15,0x14,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\ + 0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,\ + 0x09,0x0A,0x0B,0x0C,0x0D,0xFF,0xFF,0xFF,0xFF,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x00,0x00,\ + 0x00,0xD0,0x24,0x1E,0x6D,0x00,0x14,0x28,0x00,0x00,\ + 0x10,0x00,0x00,0x00,0x00,0x00,0x6A,0xC3,0x01\ +} +/* TODO define your config for Sensor_ID == 1 here, if needed */ +#define GTP_CHARGER_CFG_GROUP1 {\ +} +/* TODO define your config for Sensor_ID == 2 here, if needed */ +#define GTP_CHARGER_CFG_GROUP2 {\ +} +/* TODO define your config for Sensor_ID == 3 here, if needed */ +#define GTP_CHARGER_CFG_GROUP3 {\ +} +/* TODO define your config for Sensor_ID == 4 here, if needed */ +#define GTP_CHARGER_CFG_GROUP4 {\ +} +/* TODO define your config for Sensor_ID == 5 here, if needed */ +#define GTP_CHARGER_CFG_GROUP5 {\ +} + +/* + * Smart Cover Configs +*/ +/* TODO define your config for Sendor_ID == 0 here, if needed */ +#define GTP_SMART_COVER_CFG_GROUP0 {\ + 0x46,0xD0,0x02,0x64,0x02,0x05,0xBD,0x10,0x00,0x08,0x00,0x0F,0x50,0x28,0x5E,\ + 0x02,0x11,0x00,0x00,0x00,0x28,0x82,0x96,0xFC,0xC8,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x87,0x26,0x0B,0x64,0x66,0xDF,0x07,0x91,0x31,0x18,0x0E,0x43,0x24,0x00,\ + 0x04,0x28,0x6E,0x80,0x94,0x02,0x05,0x08,0x04,0xDA,0x33,0xAF,0x3F,0x92,0x4A,\ + 0x7F,0x56,0x71,0x62,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0F,0x19,0x04,0x0F,0x10,0x42,0xD8,0x0F,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x04,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x1E,\ + 0x00,0x70,0x17,0x50,0x1E,0x08,0x09,0x0A,0x0B,0x0C,0x0F,0x0E,0x10,0x0D,0x12,\ + 0x13,0x1F,0x1E,0x1D,0x1C,0x1B,0x1A,0x19,0x18,0x17,0x16,0x15,0x14,0xFF,0xFF,\ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,\ + 0x09,0x0A,0x0B,0x0C,0x0D,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x00,0x00,0x00,0x00,0x24,0x1E,0x6D,\ + 0x00,0x14,0x28,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x9E,0x29,0x01\ +} +/* TODO define your config for Sendor_ID == 0 here, if needed */ +#define GTP_SMART_COVER_CFG_GROUP1 {\ +} +/* TODO define your config for Sendor_ID == 0 here, if needed */ +#define GTP_SMART_COVER_CFG_GROUP2 {\ +} +/* TODO define your config for Sendor_ID == 0 here, if needed */ +#define GTP_SMART_COVER_CFG_GROUP3 {\ +} +/* TODO define your config for Sendor_ID == 0 here, if needed */ +#define GTP_SMART_COVER_CFG_GROUP4 {\ +} +/* TODO define your config for Sendor_ID == 0 here, if needed */ +#define GTP_SMART_COVER_CFG_GROUP5 {\ +} + +#if GTP_CUSTOM_CFG +#define GTP_MAX_HEIGHT 1280 +#define GTP_MAX_WIDTH 720 +#define GTP_INT_TRIGGER 1 //0:Rising 1:Falling +#define GTP_WAKEUP_LEVEL 1 +#else +#define GTP_MAX_HEIGHT 4096 +#define GTP_MAX_WIDTH 4096 +#define GTP_INT_TRIGGER 1 +#define GTP_WAKEUP_LEVEL 1 +#endif + +#define GTP_MAX_TOUCH 10 + +#if GTP_WITH_STYLUS +#define GTP_STYLUS_KEY_TAB {BTN_STYLUS, BTN_STYLUS2} +#endif + +#if GTP_HAVE_TOUCH_KEY +#define GTP_KEY_TAB {KEY_BACK, KEY_HOMEPAGE, KEY_MENU, KEY_SEARCH} +#define GTP_MAX_KEY_NUM 4 +#endif + +/****************************PART3:OTHER define*********************************/ +#define GTP_DRIVER_VERSION "V1.4<2015/07/10>" +#define GTP_I2C_NAME "Goodix-TS" +#define GT1X_DEBUG_PROC_FILE "gt1x_debug" +#define GTP_POLL_TIME 10 +#define GTP_ADDR_LENGTH 2 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 240 +#define GTP_MAX_I2C_XFER_LEN 250 +#define SWITCH_OFF 0 +#define SWITCH_ON 1 + +#define GTP_REG_MATRIX_DRVNUM 0x8069 +#define GTP_REG_MATRIX_SENNUM 0x806A +#define GTP_REG_RQST 0x8044 +#define GTP_REG_BAK_REF 0x90EC +#define GTP_REG_MAIN_CLK 0x8020 +#define GTP_REG_HAVE_KEY 0x8057 +#define GTP_REG_HN_STATE 0x8800 + +#define GTP_REG_WAKEUP_GESTURE 0x814C +#define GTP_REG_WAKEUP_GESTURE_DETAIL 0xA2A0 // need change + +#define GTP_BAK_REF_PATH "/data/gt1x_ref.bin" +#define GTP_MAIN_CLK_PATH "/data/gt1x_clk.bin" + +/* request type */ +#define GTP_RQST_CONFIG 0x01 +#define GTP_RQST_BAK_REF 0x02 +#define GTP_RQST_RESET 0x03 +#define GTP_RQST_MAIN_CLOCK 0x04 +#define GTP_RQST_HOTKNOT_CODE 0x20 +#define GTP_RQST_RESPONDED 0x00 +#define GTP_RQST_IDLE 0xFF + +#define HN_DEVICE_PAIRED 0x80 +#define HN_MASTER_DEPARTED 0x40 +#define HN_SLAVE_DEPARTED 0x20 +#define HN_MASTER_SEND 0x10 +#define HN_SLAVE_RECEIVED 0x08 + +/*Register define */ +#define GTP_READ_COOR_ADDR 0x814E +#define GTP_REG_CMD 0x8040 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_CONFIG_DATA 0x8050 +#define GTP_REG_CONFIG_RESOLUTION 0x8051 +#define GTP_REG_CONFIG_TRIGGER 0x8056 +#define GTP_REG_CONFIG_CHECKSUM 0x813C +#define GTP_REG_CONFIG_UPDATE 0x813E +#define GTP_REG_VERSION 0x8140 +#define GTP_REG_HW_INFO 0x4220 +#define GTP_REG_REFRESH_RATE 0x8056 +#define GTP_REG_ESD_CHECK 0x8043 +#define GTP_REG_FLASH_PASSBY 0x8006 +#define GTP_REG_HN_PAIRED 0x81AA +#define GTP_REG_HN_MODE 0x81A8 +#define GTP_REG_MODULE_SWITCH3 0x8058 +#define GTP_REG_FW_CHK_MAINSYS 0x41E4 +#define GTP_REG_FW_CHK_SUBSYS 0x5095 + +#define set_reg_bit(reg,pos,val) ((reg)=((reg) & (~(1<<(pos))))|(!!(val)<<(pos))) + +/* cmd define */ +#define GTP_CMD_SLEEP 0x05 +#define GTP_CMD_CHARGER_ON 0x06 +#define GTP_CMD_CHARGER_OFF 0x07 +#define GTP_CMD_GESTURE_WAKEUP 0x08 +#define GTP_CMD_CLEAR_CFG 0x10 +#define GTP_CMD_ESD 0xAA +#define GTP_CMD_HN_TRANSFER 0x22 +#define GTP_CMD_HN_EXIT_SLAVE 0x28 + +/* define offset in the config*/ +#define RESOLUTION_LOC (GTP_REG_CONFIG_RESOLUTION - GTP_REG_CONFIG_DATA) +#define TRIGGER_LOC (GTP_REG_CONFIG_TRIGGER - GTP_REG_CONFIG_DATA) +#define MODULE_SWITCH3_LOC (GTP_REG_MODULE_SWITCH3 - GTP_REG_CONFIG_DATA) + +#define GTP_I2C_ADDRESS 0xBA + +#if GTP_WARP_X_ON +#define GTP_WARP_X(x_max, x) ( x_max - 1 - x ) +#else +#define GTP_WARP_X(x_max, x) x +#endif + +#if GTP_WARP_Y_ON +#define GTP_WARP_Y(y_max, y) ( y_max - 1 - y ) +#else +#define GTP_WARP_Y(y_max, y) y +#endif + +#define IS_NUM_OR_CHAR(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= '0' && (x) <= '9')) + +//Log define +#define GTP_INFO(fmt,arg...) printk("<>[%s:%d] "fmt"\n", __func__, __LINE__, ##arg) +#define GTP_ERROR(fmt,arg...) printk("<>[%s:%d] "fmt"\n", __func__, __LINE__, ##arg) +#define GTP_DEBUG(fmt,arg...) do{\ + if(GTP_DEBUG_ON)\ + printk("<>[%s:%d]"fmt"\n",__func__, __LINE__, ##arg);\ + }while(0) +#define GTP_DEBUG_ARRAY(array, num) do{\ + s32 i;\ + u8* a = array;\ + if(GTP_DEBUG_ARRAY_ON)\ + {\ + printk("<>");\ + for (i = 0; i < (num); i++)\ + {\ + printk("%02x ", (a)[i]);\ + if ((i + 1 ) %10 == 0)\ + {\ + printk("\n<>");\ + }\ + }\ + printk("\n");\ + }\ + }while(0) +#define GTP_DEBUG_FUNC() do{\ + if(GTP_DEBUG_FUNC_ON)\ + printk("<> Func:%s@Line:%d\n",__func__,__LINE__);\ + }while(0) + +#define GTP_SWAP(x, y) do{\ + typeof(x) z = x;\ + x = y;\ + y = z;\ + }while (0) + +#pragma pack(1) +struct gt1x_version_info { + u8 product_id[5]; + u32 patch_id; + u32 mask_id; + u8 sensor_id; + u8 match_opt; +}; +#pragma pack() + +typedef enum { + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +} DOZE_T; + +typedef enum { + CHIP_TYPE_GT1X = 0, + CHIP_TYPE_GT2X = 1, + CHIP_TYPE_NONE = 0xFF +} CHIP_TYPE_T; + +#define _ERROR(e) ((0x01 << e) | (0x01 << (sizeof(s32) * 8 - 1))) +#define ERROR _ERROR(1) //for common use +//system relevant +#define ERROR_IIC _ERROR(2) //IIC communication error. +#define ERROR_MEM _ERROR(3) //memory error. + +//system irrelevant +#define ERROR_HN_VER _ERROR(10) //HotKnot version error. +#define ERROR_CHECK _ERROR(11) //Compare src and dst error. +#define ERROR_RETRY _ERROR(12) //Too many retries. +#define ERROR_PATH _ERROR(13) //Mount path error +#define ERROR_FW _ERROR(14) +#define ERROR_FILE _ERROR(15) +#define ERROR_VALUE _ERROR(16) //Illegal value of variables + +/* bit operation */ +#define SET_BIT(data, flag) ((data) |= (flag)) +#define CLR_BIT(data, flag) ((data) &= ~(flag)) +#define CHK_BIT(data, flag) ((data) & (flag)) + +/* touch states */ +#define BIT_TOUCH 0x01 +#define BIT_TOUCH_KEY 0x02 +#define BIT_STYLUS 0x04 +#define BIT_STYLUS_KEY 0x08 +#define BIT_HOVER 0x10 + +#include +struct i2c_msg; + +/* Export global variables and functions */ + +/* Export from gt1x_extents.c and gt1x_firmware.h */ +#if GTP_HOTKNOT +extern u8 hotknot_enabled; +extern u8 hotknot_transfer_mode; +extern u8 gt1x_patch_jump_fw[]; +extern u8 hotknot_auth_fw[]; +extern u8 hotknot_transfer_fw[]; +#if HOTKNOT_BLOCK_RW +extern s32 hotknot_paired_flag; +extern s32 hotknot_event_handler(u8 * data); +#endif +#endif //GTP_HOTKNOT + +extern s32 gt1x_init_node(void); +extern void gt1x_deinit_node(void); + +#if GTP_GESTURE_WAKEUP +extern DOZE_T gesture_doze_status; +extern int gesture_enabled; +extern void gt1x_gesture_debug(int on) ; +extern s32 gesture_event_handler(struct input_dev *dev); +extern s32 gesture_enter_doze(void); +extern void gesture_clear_wakeup_data(void); +#endif + +/* Export from gt1x_tpd.c */ +extern void gt1x_touch_down(s32 x, s32 y, s32 size, s32 id); +extern void gt1x_touch_up(s32 id); +extern int gt1x_power_switch(s32 state); +extern void gt1x_irq_enable(void); +extern void gt1x_irq_disable(void); +extern int gt1x_debug_proc(u8 * buf, int count); + +struct fw_update_info { + int update_type; + int status; + int progress; + int max_progress; + int force_update; + struct fw_info *firmware; + u32 fw_length; + + // file update + char *fw_name; + u8 *buffer; + mm_segment_t old_fs; + struct file *fw_file; + + // header update + u8 *fw_data; +}; + +/* Export form gt1x_update.c */ +extern struct fw_update_info update_info; + +extern u8 gt1x_default_FW[]; +extern int gt1x_hold_ss51_dsp(void); +extern int gt1x_auto_update_proc(void *data); +extern int gt1x_update_firmware(void *filename); +extern void gt1x_enter_update_mode(void); +extern void gt1x_leave_update_mode(void); +extern int gt1x_hold_ss51_dsp_no_reset(void); +extern int gt1x_load_patch(u8 * patch, u32 patch_size, int offset, int bank_size); +extern int gt1x_startup_patch(void); + +/* Export from gt1x_tool.c */ +#if GTP_CREATE_WR_NODE +extern int gt1x_init_tool_node(void); +extern void gt1x_deinit_tool_node(void); +#endif + +/* Export from gt1x_generic.c */ +extern struct i2c_client *gt1x_i2c_client; + +extern CHIP_TYPE_T gt1x_chip_type; +extern struct gt1x_version_info gt1x_version; + +extern s32 _do_i2c_read(struct i2c_msg *msgs, u16 addr, u8 * buffer, s32 len); +extern s32 _do_i2c_write(struct i2c_msg *msg, u16 addr, u8 * buffer, s32 len); +extern s32 gt1x_i2c_write(u16 addr, u8 * buffer, s32 len); +extern s32 gt1x_i2c_read(u16 addr, u8 * buffer, s32 len); +extern s32 gt1x_i2c_read_dbl_check(u16 addr, u8 * buffer, s32 len); + +extern u8 gt1x_config[]; +extern u32 gt1x_cfg_length; +extern u8 gt1x_int_type; +extern u8 gt1x_wakeup_level; +extern u32 gt1x_abs_x_max; +extern u32 gt1x_abs_y_max; +extern u8 gt1x_init_failed; +extern int gt1x_halt; +extern volatile int gt1x_rawdiff_mode; + +extern s32 gt1x_init(void); +extern void gt1x_deinit(void); +extern s32 gt1x_read_version(struct gt1x_version_info *ver_info); +extern s32 gt1x_init_panel(void); +extern s32 gt1x_get_chip_type(void); +extern s32 gt1x_request_event_handler(void); +extern int gt1x_send_cmd(u8 cmd, u8 data); +extern s32 gt1x_send_cfg(u8 * config, int cfg_len); +extern void gt1x_select_addr(void); +extern s32 gt1x_reset_guitar(void); +extern void gt1x_power_reset(void); +extern int gt1x_parse_config(char *filename, u8 * gt1x_config); +extern s32 gt1x_touch_event_handler(u8 * data, struct input_dev *dev, struct input_dev *pen_dev); +extern int gt1x_suspend(void); +extern int gt1x_resume(void); + +#if GTP_HAVE_TOUCH_KEY +extern const u16 gt1x_touch_key_array[]; +#endif + +#if GTP_WITH_STYLUS +extern struct input_dev *pen_dev; +extern void gt1x_pen_up(s32 id); +extern void gt1x_pen_down(s32 x, s32 y, s32 size, s32 id); +#endif + +#if GTP_PROXIMITY +extern u8 gt1x_proximity_flag; +extern int gt1x_prox_event_handler(u8 * data); +#endif + +#if GTP_SMART_COVER +extern int gt1x_parse_sc_cfg(int sensor_id); +#endif + +#if GTP_ESD_PROTECT +extern void gt1x_init_esd_protect(void); +extern void gt1x_esd_switch(s32 on); +#endif + +#if GTP_CHARGER_SWITCH +extern u32 gt1x_get_charger_status(void); +extern void gt1x_charger_switch(s32 on); +extern void gt1x_charger_config(s32 dir_update); +extern int gt1x_parse_chr_cfg(int sensor_id); +#endif + +#endif // _GT1X_GENERIC_H_ + diff --git a/drivers/input/touchscreen/gt1xx/gt1x_tools.c b/drivers/input/touchscreen/gt1xx/gt1x_tools.c new file mode 100755 index 00000000000..552a9f970ed --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x_tools.c @@ -0,0 +1,437 @@ +/* drivers/input/touchscreen/goodix_tool.c + * + * 2010 - 2014 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ + +#include +#include +#include +#include +#include "gt1x_generic.h" + +static ssize_t gt1x_tool_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos); +static ssize_t gt1x_tool_write(struct file *filp, const char *buffer, size_t count, loff_t * ppos); + + +static int gt1x_tool_release(struct inode *inode, struct file *filp); +static int gt1x_tool_open(struct inode *inode,struct file *file); + +#pragma pack(1) +typedef struct { + u8 wr; //write read flag£¬0:R 1:W 2:PID 3: + u8 flag; //0:no need flag/int 1: need flag 2:need int + u8 flag_addr[2]; //flag address + u8 flag_val; //flag val + u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:< + u16 circle; //polling cycle + u8 times; //plling times + u8 retry; //I2C retry times + u16 delay; //delay befor read or after write + u16 data_len; //data length + u8 addr_len; //address length + u8 addr[2]; //address + u8 res[3]; //reserved + u8 *data; //data pointer +} st_cmd_head; +#pragma pack() +st_cmd_head cmd_head; + +s32 DATA_LENGTH = 0; +s8 IC_TYPE[16] = "GT1X"; + +#define UPDATE_FUNCTIONS +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*)) + +static char procname[20] = { 0 }; + +static struct proc_dir_entry *gt1x_tool_proc_entry; +static struct file_operations gt1x_tool_fops = { + .read = gt1x_tool_read, + .write = gt1x_tool_write, + .open = gt1x_tool_open, + .release = gt1x_tool_release, + .owner = THIS_MODULE, +}; + +static void set_tool_node_name(char *procname) +{ + + int v0 = 0, v1 = 0, v2 = 0; + + sscanf(UTS_RELEASE, "%d.%d.%d", &v0, &v1, &v2); + sprintf(procname, "gmnode%02d%02d%02d", v0, v1, v2); +} + +int gt1x_init_tool_node(void) +{ + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.wr = 1; //if the first operation is read, will return fail. + cmd_head.data = kzalloc(DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL == cmd_head.data) { + GTP_ERROR("Apply for memory failed."); + return -1; + } + GTP_INFO("Alloc memory size:%d.", DATA_LENGTH_UINT); + DATA_LENGTH = DATA_LENGTH_UINT - GTP_ADDR_LENGTH; + + set_tool_node_name(procname); + + gt1x_tool_proc_entry = proc_create(procname, 0666, NULL, >1x_tool_fops); + if (gt1x_tool_proc_entry == NULL) { + GTP_ERROR("CAN't create proc entry /proc/%s.", procname); + return -1; + } else { + GTP_INFO("Created proc entry /proc/%s.", procname); + } + return 0; +} + +void gt1x_deinit_tool_node(void) +{ + remove_proc_entry(procname, NULL); + kfree(cmd_head.data); + cmd_head.data = NULL; +} + +static s32 tool_i2c_read(u8 * buf, u16 len) +{ + u16 addr = (buf[0] << 8) + buf[1]; + if (!gt1x_i2c_read(addr, &buf[2], len)) { + return 1; + } + return -1; +} + +static s32 tool_i2c_write(u8 * buf, u16 len) +{ + u16 addr = (buf[0] << 8) + buf[1]; + if (!gt1x_i2c_write(addr, &buf[2], len - 2)) { + return 1; + } + return -1; +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32) ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* +Function: + Comfirm function. +Input: + None. +Output: + Return write length. +********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + + memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); + + for (i = 0; i < cmd_head.times; i++) { + if (tool_i2c_read(buf, 1) <= 0) { + GTP_ERROR("Read flag data failed!"); + return -1; + } + + if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation)) { + GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]); + GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) { + GTP_ERROR("Didn't get the flag to continue!"); + return -1; + } + + return 0; +} + +/******************************************************* +Function: + Goodix tool write function. +Input: + standard proc write function param. +Output: + Return write length. +********************************************************/ +static ssize_t gt1x_tool_write(struct file *filp, const char __user * buff, size_t len, loff_t * data) +{ + u64 ret = 0; + GTP_DEBUG_FUNC(); + GTP_DEBUG_ARRAY((u8 *) buff, len); + + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if (ret) { + GTP_ERROR("copy_from_user failed."); + } + + GTP_DEBUG("wr :0x%02x.", cmd_head.wr); + /* + GTP_DEBUG("flag:0x%02x.", cmd_head.flag); + GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]); + GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val); + GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation); + GTP_DEBUG("circle :%d.", (s32)cmd_head.circle); + GTP_DEBUG("times :%d.", (s32)cmd_head.times); + GTP_DEBUG("retry :%d.", (s32)cmd_head.retry); + GTP_DEBUG("delay :%d.", (s32)cmd_head.delay); + GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len); + GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len); + GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); + GTP_DEBUG("len:%d.", (s32)len); + GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]); + */ + + if (1 == cmd_head.wr) { + u16 addr, data_len, pos; + + if (1 == cmd_head.flag) { + if (comfirm()) { + GTP_ERROR("[WRITE]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head.flag) { + //Need interrupt! + } + + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + data_len = cmd_head.data_len; + pos = 0; + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH + pos], len); + if (ret) { + GTP_ERROR("[WRITE]copy_from_user failed."); + return -1; + } + cmd_head.data[0] = ((addr >> 8) & 0xFF); + cmd_head.data[1] = (addr & 0xFF); + + GTP_DEBUG_ARRAY(cmd_head.data, len + GTP_ADDR_LENGTH); + + if (tool_i2c_write(cmd_head.data, len + GTP_ADDR_LENGTH) <= 0) { + GTP_ERROR("[WRITE]Write data failed!"); + return -1; + } + addr += len; + pos += len; + data_len -= len; + } + + if (cmd_head.delay) { + msleep(cmd_head.delay); + } + + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (3 == cmd_head.wr) { //gt1x unused + + memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (5 == cmd_head.wr) { //? + + //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (7 == cmd_head.wr) { //disable irq! + gt1x_irq_disable(); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + return CMD_HEAD_LENGTH; + } else if (9 == cmd_head.wr) { //enable irq! + gt1x_irq_enable(); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + return CMD_HEAD_LENGTH; + } else if (17 == cmd_head.wr) { + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if (ret) { + GTP_ERROR("copy_from_user failed."); + return -1; + } + + if (cmd_head.data[GTP_ADDR_LENGTH]) { + GTP_DEBUG("gtp enter rawdiff."); + gt1x_rawdiff_mode = true; + } else { + gt1x_rawdiff_mode = false; + GTP_DEBUG("gtp leave rawdiff."); + } + + return CMD_HEAD_LENGTH; + } else if (11 == cmd_head.wr) { + gt1x_enter_update_mode(); + } else if (13 == cmd_head.wr) { + gt1x_leave_update_mode(); + } else if (15 == cmd_head.wr) { + struct task_struct *thrd = NULL; + memset(cmd_head.data, 0, cmd_head.data_len + 1); + memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + GTP_DEBUG("update firmware, filename: %s", cmd_head.data); + thrd = kthread_run(gt1x_update_firmware, (void *)cmd_head.data, "GT1x FW Update"); + if (IS_ERR(thrd)) { + return PTR_ERR(thrd); + } + } + return CMD_HEAD_LENGTH; +} + +static u8 devicecount = 0; +static int gt1x_tool_open(struct inode *inode,struct file *file) +{ + if (devicecount > 0) { + return -ERESTARTSYS; + GTP_ERROR("tools open failed!"); + } + + devicecount++; + return 0; +} + +static int gt1x_tool_release(struct inode *inode, struct file *filp) +{ + devicecount--; + return 0; +} +/******************************************************* +Function: + Goodix tool read function. +Input: + standard proc read function param. +Output: + Return read length. +********************************************************/ +static ssize_t gt1x_tool_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) +{ + GTP_DEBUG_FUNC(); + if(*ppos) { + GTP_DEBUG("[PARAM]size: %zd, *ppos: %d", count, (int)*ppos); + *ppos = 0; + return 0; + } + + if (cmd_head.wr % 2) { + GTP_ERROR("[READ] invaild operator fail!"); + return -1; + } else if (!cmd_head.wr) { + /* general i2c read */ + u16 addr, data_len, len, loc; + + if (1 == cmd_head.flag) { + if (comfirm()) { + GTP_ERROR("[READ]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head.flag) { + //Need interrupt! + } + + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + data_len = cmd_head.data_len; + loc = 0; + + GTP_DEBUG("[READ] ADDR:0x%04X.", addr); + GTP_DEBUG("[READ] Length: %d", data_len); + + if (cmd_head.delay) { + msleep(cmd_head.delay); + } + + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + cmd_head.data[0] = (addr >> 8) & 0xFF; + cmd_head.data[1] = (addr & 0xFF); + if (tool_i2c_read(cmd_head.data, len) <= 0) { + GTP_ERROR("[READ]Read data failed!"); + return -1; + } + memcpy(&buffer[loc], &cmd_head.data[GTP_ADDR_LENGTH], len); + data_len -= len; + addr += len; + loc += len; + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len); + } + *ppos += cmd_head.data_len; + return cmd_head.data_len; + } else if (2 == cmd_head.wr) { + GTP_DEBUG("Return ic type:%s len:%d.", buffer, (s32) cmd_head.data_len); + return -1; + } else if (4 == cmd_head.wr) { + /* read fw update progress */ + buffer[0] = update_info.progress >> 8; + buffer[1] = update_info.progress & 0xff; + buffer[2] = update_info.max_progress >> 8; + buffer[3] = update_info.max_progress & 0xff; + *ppos += 4; + return 4; + } else if (6 == cmd_head.wr) { + //Read error code! + return -1; + } else if (8 == cmd_head.wr) { + /* Read driver version */ + s32 tmp_len; + tmp_len = strlen(GTP_DRIVER_VERSION); + memcpy(buffer, GTP_DRIVER_VERSION, tmp_len); + buffer[tmp_len] = 0; + *ppos += tmp_len + 1; + return (tmp_len + 1); + } + *ppos += cmd_head.data_len; + return cmd_head.data_len; +} diff --git a/drivers/input/touchscreen/gt1xx/gt1x_update.c b/drivers/input/touchscreen/gt1xx/gt1x_update.c new file mode 100755 index 00000000000..3a3e925be56 --- /dev/null +++ b/drivers/input/touchscreen/gt1xx/gt1x_update.c @@ -0,0 +1,1472 @@ +/* drivers/input/touchscreen/gt1x_update.c + * + * 2010 - 2014 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.4 + * Release Date: 2015/07/10 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gt1x_generic.h" +#if (GTP_HOTKNOT || GTP_HEADER_FW_UPDATE) +#include "gt1x_firmware.h" +#endif + +#define UPDATE_FILE_PATH_1 "/data/_goodix_update_.bin" +#define UPDATE_FILE_PATH_2 "/sdcard/_goodix_update_.bin" + +#define CONFIG_FILE_PATH_1 "/data/_gt1x_config_.cfg" +#define CONFIG_FILE_PATH_2 "/sdcard/_gt1x_config_.cfg" + +#define FOUND_FW_PATH_1 0x01 +#define FOUND_FW_PATH_2 0x02 +#define FOUND_CFG_PATH_1 0x04 +#define FOUND_CFG_PATH_2 0x08 + +#define PACK_SIZE 256 + +// hardware register define +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 +#define _bRW_MISCTL__DSP_MCU_PWR_ 0x4010 +#define _bRW_MISCTL__PATCH_AREA_EN_ 0x404D + +/* + 1. firmware structure + header: 128b + + offset size content + 0 4 firmware length + 4 2 checksum + 6 6 target MASK name + 12 3 target MASK version + 15 6 TP subsystem PID + 21 3 TP subsystem version + 24 1 subsystem count + 25 1 chip type 0x91: GT1X, 0x92: GT2X + 26 6 reserved + 32 8 subsystem info[0] + 32 8 subsystem info[1] + ..... + 120 8 subsystem info[11] + + body: followed header + + 128 N0 subsystem[0] + 128+N0 N1 subsystem[1] + .... + + 2. subsystem info structure + offset size content + 0 1 subsystem type + 1 2 subsystem length + 3 2 stored address in flash addr = value * 256 + 5 3 reserved + +*/ + +#define FW_HEAD_SIZE 128 +#define FW_HEAD_SUBSYSTEM_INFO_SIZE 8 +#define FW_HEAD_OFFSET_SUBSYSTEM_INFO_BASE 32 + +#define FW_SECTION_TYPE_SS51_ISP 0x01 +#define FW_SECTION_TYPE_SS51_PATCH 0x02 +#define FW_SECTION_TYPE_SS51_PATCH_OVERLAY 0x03 +#define FW_SECTION_TYPE_DSP 0x04 +#define FW_SECTION_TYPE_HOTKNOT 0x05 +#define FW_SECTION_TYPE_GESTURE 0x06 +#define FW_SECTION_TYPE_GESTURE_OVERLAY 0x07 +#define FW_SECTION_TYPE_FLASHLESS_FAST_POWER 0x08 + +#define UPDATE_TYPE_HEADER 0 +#define UPDATE_TYPE_FILE 1 + +#define UPDATE_STATUS_IDLE 0 +#define UPDATE_STATUS_RUNNING 1 +#define UPDATE_STATUS_ABORT 2 + +struct fw_subsystem_info { + int type; + int length; + u32 address; + int offset; +}; + +#pragma pack(1) +struct fw_info { + u32 length; + u16 checksum; + u8 target_mask[6]; + u8 target_mask_version[3]; + u8 pid[6]; + u8 version[3]; + u8 subsystem_count; + u8 chip_type; + u8 reserved[6]; + struct fw_subsystem_info subsystem[12]; +}; +#pragma pack() + +struct fw_update_info update_info = { + .status = UPDATE_STATUS_IDLE, + .progress = 0, + .max_progress = 9, + .force_update = 0 +}; + +int gt1x_update_prepare(char *filename); +int gt1x_check_firmware(void); +u8 *gt1x_get_fw_data(u32 offset, int length); +int gt1x_update_judge(void); +int gt1x_run_ss51_isp(u8 * ss51_isp, int length); +int gt1x_burn_subsystem(struct fw_subsystem_info *subsystem); +u16 gt1x_calc_checksum(u8 * fw, u32 length); +int gt1x_recall_check(u8 * chk_src, u16 start_rd_addr, u16 chk_length); +void gt1x_update_cleanup(void); +int gt1x_check_subsystem_in_flash(struct fw_subsystem_info *subsystem); +int gt1x_read_flash(u32 addr, int length); +int gt1x_error_erase(void); +void dump_to_file(u16 addr, int length, char *filepath); + +int gt1x_update_firmware(void *filename); +int gt1x_auto_update_proc(void *data); + +#if !GTP_HEADER_FW_UPDATE +static int gt1x_search_update_files(void); +#endif + +int gt1x_hold_ss51_dsp(void); +void gt1x_leave_update_mode(void); + +/** + * @return: return 0 if success, otherwise return a negative number + * which contains the error code. + */ +s32 gt1x_check_fs_mounted(char *path_name) +{ + struct path root_path; + struct path path; + s32 err; + + err = kern_path("/", LOOKUP_FOLLOW, &root_path); + if (err) + return ERROR_PATH; + + err = kern_path(path_name, LOOKUP_FOLLOW, &path); + if (err) { + err = ERROR_PATH; + goto check_fs_fail; + } + + if (path.mnt->mnt_sb == root_path.mnt->mnt_sb) { + // not mounted + err = ERROR_PATH; + } else { + err = 0; + } + + path_put(&path); +check_fs_fail: + path_put(&root_path); + return err; +} + +int gt1x_i2c_write_with_readback(u16 addr, u8 * buffer, int length) +{ + u8 buf[100]; + int ret = gt1x_i2c_write(addr, buffer, length); + if (ret) { + return ret; + } + ret = gt1x_i2c_read(addr, buf, length); + if (ret) { + return ret; + } + if (memcmp(buf, buffer, length)) { + return ERROR_CHECK; + } + return 0; +} + +#define getU32(a) ((u32)getUint((u8 *)(a), 4)) +#define getU16(a) ((u16)getUint((u8 *)(a), 2)) +u32 getUint(u8 * buffer, int len) +{ + u32 num = 0; + int i; + for (i = 0; i < len; i++) { + num <<= 8; + num += buffer[i]; + } + return num; +} + +int gt1x_auto_update_proc(void *data) +{ + +#if GTP_HEADER_FW_UPDATE + GTP_INFO("Start auto update thread..."); + gt1x_update_firmware(NULL); +#else + int ret; + char *filename; + u8 config[GTP_CONFIG_MAX_LENGTH] = { 0 }; + + GTP_INFO("Start auto update thread..."); + ret = gt1x_search_update_files(); + if (ret & (FOUND_FW_PATH_1 | FOUND_FW_PATH_2)) { + if (ret & FOUND_FW_PATH_1) { + filename = UPDATE_FILE_PATH_1; + } else { + filename = UPDATE_FILE_PATH_2; + } + gt1x_update_firmware(filename); + } + + if (ret & (FOUND_CFG_PATH_1 | FOUND_CFG_PATH_2)) { + if (ret & FOUND_CFG_PATH_1) { + filename = CONFIG_FILE_PATH_1; + } else { + filename = CONFIG_FILE_PATH_2; + } + + if (gt1x_parse_config(filename, config) > 0) { + if (gt1x_i2c_write(GTP_REG_CONFIG_DATA, config, GTP_CONFIG_MAX_LENGTH)) { + GTP_ERROR("Update config failed!"); + } else { + GTP_INFO("Update config successfully!"); + } + } + } +#endif + return 0; +} +#if !GTP_HEADER_FW_UPDATE +static int gt1x_search_update_files(void) +{ + int retry = 20 * 2; //wait 10s(max) if fs is not ready + struct file *pfile = NULL; + mm_segment_t old_fs; + int found = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + GTP_INFO("Search firmware file..."); + while (retry-- > 0) { + msleep(500); + + // check if rootfs is ready + if (gt1x_check_fs_mounted("/data")) { + GTP_DEBUG("filesystem is not ready"); + continue; + } + // search firmware + pfile = filp_open(UPDATE_FILE_PATH_1, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pfile = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0); + if (!IS_ERR(pfile)) { + found |= FOUND_FW_PATH_2; + } + } else { + found |= FOUND_FW_PATH_1; + } + + if (!IS_ERR(pfile)) { + filp_close(pfile, NULL); + } + // search config file + pfile = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pfile = filp_open(CONFIG_FILE_PATH_2, O_RDONLY, 0); + if (!IS_ERR(pfile)) { + found |= FOUND_CFG_PATH_2; + } + } else { + found |= FOUND_CFG_PATH_1; + } + if (!IS_ERR(pfile)) { + filp_close(pfile, NULL); + } + + if (found) { + break; + } + + GTP_INFO("Not found firmware or config file, retry."); + } + set_fs(old_fs); + + return found; +} +#endif + +void gt1x_enter_update_mode(void) +{ + GTP_DEBUG("Enter FW update mode."); +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif +#if GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_OFF); +#endif + gt1x_irq_disable(); +} + +int gt1x_update_firmware(void *filename) +{ + int i = 0; + int ret = 0; + u8 *p; + + if (update_info.status != UPDATE_STATUS_IDLE) { + GTP_ERROR("Update process is running!"); + return ERROR; + } + update_info.status = UPDATE_STATUS_RUNNING; + update_info.progress = 0; + + gt1x_enter_update_mode(); + + ret = gt1x_update_prepare(filename); + if (ret) { + update_info.status = UPDATE_STATUS_IDLE; + return ret; + } + + ret = gt1x_check_firmware(); + if (ret) { + update_info.status = UPDATE_STATUS_ABORT; + goto gt1x_update_exit; + } +#if GTP_FW_UPDATE_VERIFY + update_info.max_progress = + 6 + update_info.firmware->subsystem_count; +#else + update_info.max_progress = + 3 + update_info.firmware->subsystem_count; +#endif + update_info.progress++; // 1 + + ret = gt1x_update_judge(); + if (ret) { + update_info.status = UPDATE_STATUS_ABORT; + goto gt1x_update_exit; + } + update_info.progress++; // 2 + + p = gt1x_get_fw_data(update_info.firmware->subsystem[0].offset, update_info.firmware->subsystem[0].length); + if (p == NULL) { + GTP_ERROR("get isp fail"); + ret = ERROR_FW; + update_info.status = UPDATE_STATUS_ABORT; + goto gt1x_update_exit; + } + update_info.progress++; // 3 + + ret = gt1x_run_ss51_isp(p, update_info.firmware->subsystem[0].length); + if (ret) { + GTP_ERROR("run isp fail"); + goto gt1x_update_exit; + } + update_info.progress++; // 4 + msleep(800); + + for (i = 1; i < update_info.firmware->subsystem_count; i++) { + GTP_INFO("subsystem: %d", update_info.firmware->subsystem[i].type); + GTP_INFO("Length: %d", update_info.firmware->subsystem[i].length); + GTP_INFO("Address: %d", update_info.firmware->subsystem[i].address); + + ret = gt1x_burn_subsystem(&(update_info.firmware->subsystem[i])); + if (ret) { + GTP_ERROR("burn subsystem fail!"); + goto gt1x_update_exit; + } + update_info.progress++; + } + +#if GTP_FW_UPDATE_VERIFY + gt1x_reset_guitar(); + + p = gt1x_get_fw_data(update_info.firmware->subsystem[0].offset, update_info.firmware->subsystem[0].length); + if (p == NULL) { + GTP_ERROR("get isp fail"); + ret = ERROR_FW; + goto gt1x_update_exit; + } + update_info.progress++; + + ret = gt1x_run_ss51_isp(p, update_info.firmware->subsystem[0].length); + if (ret) { + GTP_ERROR("run isp fail"); + goto gt1x_update_exit; + } + update_info.progress++; + + GTP_INFO("Reset guitar & check firmware in flash."); + for (i = 1; i < update_info.firmware->subsystem_count; i++) { + GTP_INFO("subsystem: %d", update_info.firmware->subsystem[i].type); + GTP_INFO("Length: %d", update_info.firmware->subsystem[i].length); + GTP_INFO("Address: %d", update_info.firmware->subsystem[i].address); + + ret = gt1x_check_subsystem_in_flash(&(update_info.firmware->subsystem[i])); + if (ret) { + gt1x_error_erase(); + break; + } + } + update_info.progress++; +#endif + +gt1x_update_exit: + gt1x_update_cleanup(); + gt1x_leave_update_mode(); + gt1x_read_version(NULL); + if (ret) { + update_info.progress = 2 * update_info.max_progress; + GTP_ERROR("Update firmware failed!"); + return ret; + } else if (gt1x_init_failed) { + gt1x_read_version(>1x_version); + gt1x_init_panel(); + #if GTP_CHARGER_SWITCH + gt1x_parse_chr_cfg(gt1x_version.sensor_id); + #endif + #if GTP_SMART_COVER + gt1x_parse_sc_cfg(gt1x_version.sensor_id); + #endif + } + GTP_INFO("Update firmware succeefully!"); + return ret; +} + +int gt1x_update_prepare(char *filename) +{ + int ret = 0; + int retry = 5; + if (filename == NULL) { +#if GTP_HEADER_FW_UPDATE + update_info.fw_name = NULL; + update_info.update_type = UPDATE_TYPE_HEADER; + update_info.fw_data = gt1x_default_FW; + update_info.fw_length = sizeof(gt1x_default_FW); +#else + GTP_ERROR("No Fw in .h file!"); + return ERROR_FW; +#endif + } else { + GTP_INFO("Firmware: %s", filename); + update_info.old_fs = get_fs(); + set_fs(KERNEL_DS); + update_info.fw_name = filename; + update_info.update_type = UPDATE_TYPE_FILE; + update_info.fw_file = filp_open(update_info.fw_name, O_RDONLY, 0); + if (IS_ERR(update_info.fw_file)) { + GTP_ERROR("Open update file(%s) error!", update_info.fw_name); + set_fs(update_info.old_fs); + return ERROR_FILE; + } + update_info.fw_file->f_op->llseek(update_info.fw_file, 0, SEEK_SET); + update_info.fw_length = update_info.fw_file->f_op->llseek(update_info.fw_file, 0, SEEK_END); + } + + while (retry > 0) { + retry--; + update_info.firmware = (struct fw_info *)kzalloc(sizeof(struct fw_info), GFP_KERNEL); + if (update_info.firmware == NULL) { + GTP_INFO("Alloc %zu bytes memory fail.", sizeof(struct fw_info)); + continue; + } else { + GTP_INFO("Alloc %zu bytes memory success.", sizeof(struct fw_info)); + break; + } + } + if (retry <= 0) { + ret = ERROR_RETRY; + goto gt1x_update_pre_fail1; + } + + retry = 5; + while (retry > 0) { + update_info.buffer = (u8 *) kzalloc(1024 * 4, GFP_KERNEL); + if (update_info.buffer == NULL) { + GTP_ERROR("Alloc %d bytes memory fail.", 1024 * 4); + continue; + } else { + GTP_INFO("Alloc %d bytes memory success.", 1024 * 4); + break; + } + } + if (retry <= 0) { + ret = ERROR_RETRY; + goto gt1x_update_pre_fail0; + } + + return 0; + +gt1x_update_pre_fail0: + kfree(update_info.firmware); +gt1x_update_pre_fail1: + filp_close(update_info.fw_file, NULL); + return ret; +} + +void gt1x_update_cleanup(void) +{ + if (update_info.update_type == UPDATE_TYPE_FILE) { + if (update_info.fw_file != NULL) { + filp_close(update_info.fw_file, NULL); + update_info.fw_file = NULL; + } + set_fs(update_info.old_fs); + } + + if (update_info.buffer != NULL) { + kfree(update_info.buffer); + update_info.buffer = NULL; + } + if (update_info.firmware != NULL) { + kfree(update_info.firmware); + update_info.firmware = NULL; + } +} + +int gt1x_check_firmware(void) +{ + u16 checksum; + u16 checksum_in_header; + u8 *p; + struct fw_info *firmware; + int i; + int offset; + + // compare file length with the length field in the firmware header + if (update_info.fw_length < FW_HEAD_SIZE) { + GTP_ERROR("Bad firmware!(file length: %d)", update_info.fw_length); + return ERROR_CHECK; + } + p = gt1x_get_fw_data(0, 6); + if (p == NULL) { + return ERROR_FW; + } + + if (getU32(p) + 6 != update_info.fw_length) { + GTP_ERROR("Bad firmware!(file length: %d, header define: %d)", update_info.fw_length, getU32(p)); + return ERROR_CHECK; + } + // check firmware's checksum + checksum_in_header = getU16(&p[4]); + checksum = 0; + for (i = 6; i < update_info.fw_length; i++) { + p = gt1x_get_fw_data(i, 1); + if (p == NULL) { + return ERROR_FW; + } + checksum += p[0]; + } + + if (checksum != checksum_in_header) { + GTP_ERROR("Bad firmware!(checksum: 0x%04X, header define: 0x%04X)", checksum, checksum_in_header); + return ERROR_CHECK; + } + // parse firmware + p = gt1x_get_fw_data(0, FW_HEAD_SIZE); + if (p == NULL) { + return ERROR_FW; + } + memcpy((u8 *) update_info.firmware, p, FW_HEAD_SIZE - 8 * 12); + update_info.firmware->pid[5] = 0; + + p = &p[FW_HEAD_OFFSET_SUBSYSTEM_INFO_BASE]; + firmware = update_info.firmware; + offset = FW_HEAD_SIZE; + for (i = 0; i < firmware->subsystem_count; i++) { + firmware->subsystem[i].type = p[i * FW_HEAD_SUBSYSTEM_INFO_SIZE]; + firmware->subsystem[i].length = getU16(&p[i * FW_HEAD_SUBSYSTEM_INFO_SIZE + 1]); + firmware->subsystem[i].address = getU16(&p[i * FW_HEAD_SUBSYSTEM_INFO_SIZE + 3]) * 256; + firmware->subsystem[i].offset = offset; + offset += firmware->subsystem[i].length; + } + + // print update information + GTP_INFO("Update type: %s", update_info.update_type == UPDATE_TYPE_HEADER ? "Header" : "File"); + GTP_INFO("Firmware length: %d", update_info.fw_length); + GTP_INFO("Firmware product: GT%s", update_info.firmware->pid); + GTP_INFO("Firmware patch: %02X%02X%02X", update_info.firmware->version[0], update_info.firmware->version[1], update_info.firmware->version[2]); + GTP_INFO("Firmware chip: 0x%02X", update_info.firmware->chip_type); + GTP_INFO("Subsystem count: %d", update_info.firmware->subsystem_count); + for (i = 0; i < update_info.firmware->subsystem_count; i++) { + GTP_DEBUG("------------------------------------------"); + GTP_DEBUG("Subsystem: %d", i); + GTP_DEBUG("Type: %d", update_info.firmware->subsystem[i].type); + GTP_DEBUG("Length: %d", update_info.firmware->subsystem[i].length); + GTP_DEBUG("Address: 0x%08X", update_info.firmware->subsystem[i].address); + GTP_DEBUG("Offset: %d", update_info.firmware->subsystem[i].offset); + } + + return 0; +} + +/** + * @return: return a pointer pointed at the content of firmware + * if success, otherwise return NULL. + */ +u8 *gt1x_get_fw_data(u32 offset, int length) +{ + int ret; + if (update_info.update_type == UPDATE_TYPE_FILE) { + update_info.fw_file->f_op->llseek(update_info.fw_file, offset, SEEK_SET); + ret = update_info.fw_file->f_op->read(update_info.fw_file, (char *)update_info.buffer, length, &update_info.fw_file->f_pos); + if (ret < 0) { + GTP_ERROR("Read data error!"); + return NULL; + } + return update_info.buffer; + } else { + return &update_info.fw_data[offset]; + } +} + +int gt1x_update_judge(void) +{ + int ret; + u8 reg_val[2] = {0}; + u8 retry = 2; + struct gt1x_version_info ver_info; + struct gt1x_version_info fw_ver_info; + + fw_ver_info.mask_id = (update_info.firmware->target_mask_version[0] << 16) + | (update_info.firmware->target_mask_version[1] << 8) + | (update_info.firmware->target_mask_version[2]); + fw_ver_info.patch_id = (update_info.firmware->version[0] << 16) + | (update_info.firmware->version[1] << 8) + | (update_info.firmware->version[2]); + memcpy(fw_ver_info.product_id, update_info.firmware->pid, 4); + fw_ver_info.product_id[4] = 0; + + /* check fw status reg */ + do { + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_MAINSYS, reg_val, 1); + if (ret < 0) { /* read reg failed */ + goto _reset; + } else if (ret > 0) { + continue; + } + + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_SUBSYS, ®_val[1], 1); + if (ret < 0) { + goto _reset; + } else if (ret > 0) { + continue; + } + + break; +_reset: + gt1x_reset_guitar(); + }while (--retry); + + if (!retry) { + GTP_INFO("Update abort because of i2c error."); + return ERROR_CHECK; + } + if (reg_val[0] != 0xBE || reg_val[1] == 0xAA) { + GTP_INFO("Check fw status reg not pass,reg[0x814E]=0x%2X,reg[0x5095]=0x%2X!", + reg_val[0], reg_val[1]); + return 0; + } + + ret = gt1x_read_version(&ver_info); + if (ret < 0) { + GTP_INFO("Get IC's version info failed, force update!"); + return 0; + } + + if (memcmp(fw_ver_info.product_id, ver_info.product_id, 4)) { + GTP_INFO("Product id is not match!"); + return ERROR_CHECK; + } + if ((fw_ver_info.mask_id & 0xFFFFFF00) != (ver_info.mask_id & 0xFFFFFF00)) { + GTP_INFO("Mask id is not match!"); + return ERROR_CHECK; + } + if ((fw_ver_info.patch_id & 0xFF0000) != (ver_info.patch_id & 0xFF0000)){ + GTP_INFO("CID is not equal, need update!"); + return 0; + } +#if GTP_DEBUG_ON + if (update_info.force_update) { + GTP_DEBUG("Debug mode, force update fw."); + return 0; + } +#endif + if ((fw_ver_info.patch_id & 0xFFFF) <= (ver_info.patch_id & 0xFFFF)) { + GTP_INFO("The version of the fw is not high than the IC's!"); + return ERROR_CHECK; + } + return 0; +} + +int __gt1x_hold_ss51_dsp_20(void) +{ + int ret = -1; + int retry = 0; + u8 buf[1]; + int hold_times = 0; + + while (retry++ < 30) { + + // Hold ss51 & dsp + buf[0] = 0x0C; + ret = gt1x_i2c_write(_rRW_MISCTL__SWRST_B0_, buf, 1); + if (ret) { + GTP_ERROR("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + // Confirm hold + buf[0] = 0x00; + ret = gt1x_i2c_read(_rRW_MISCTL__SWRST_B0_, buf, 1); + if (ret) { + GTP_ERROR("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + if (0x0C == buf[0]) { + if (hold_times++ < 20) { + continue; + } else { + break; + } + } + GTP_ERROR("Hold ss51 & dsp confirm 0x4180 failed,value:%d", buf[0]); + } + if (retry >= 30) { + GTP_ERROR("Hold ss51&dsp failed!"); + return ERROR_RETRY; + } + + GTP_INFO("Hold ss51&dsp successfully."); + return 0; +} + +int gt1x_hold_ss51_dsp(void) +{ + int ret = ERROR, retry = 5; + u8 buffer[2]; + + do { + gt1x_select_addr(); + ret = gt1x_i2c_read(0x4220, buffer, 1); + + } while (retry-- && ret < 0); + + if (ret < 0) + return ERROR; + + //hold ss51_dsp + ret = __gt1x_hold_ss51_dsp_20(); + if (ret) { + return ret; + } + // enable dsp & mcu power + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__DSP_MCU_PWR_, buffer, 1); + if (ret) { + GTP_ERROR("enabel dsp & mcu power fail!"); + return ret; + } + // disable watchdog + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__TMR0_EN, buffer, 1); + if (ret) { + GTP_ERROR("disable wdt fail!"); + return ret; + } + // clear cache + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__CACHE_EN, buffer, 1); + if (ret) { + GTP_ERROR("clear cache fail!"); + return ret; + } + // soft reset + buffer[0] = 0x01; + ret = gt1x_i2c_write(_bWO_MISCTL__CPU_SWRST_PULSE, buffer, 1); + if (ret) { + GTP_ERROR("software reset fail!"); + return ret; + } + // set scramble + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_rRW_MISCTL__BOOT_OPT_B0_, buffer, 1); + if (ret) { + GTP_ERROR("set scramble fail!"); + return ret; + } + + return 0; +} + +int gt1x_run_ss51_isp(u8 * ss51_isp, int length) +{ + int ret; + u8 buffer[10]; + + ret = gt1x_hold_ss51_dsp(); + if (ret) { + return ret; + } + // select bank4 + buffer[0] = 0x04; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__SRAM_BANK, buffer, 1); + if (ret) { + GTP_ERROR("select bank4 fail."); + return ret; + } + // enable patch area access + buffer[0] = 0x01; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__PATCH_AREA_EN_, buffer, 1); + if (ret) { + GTP_ERROR("enable patch area access fail!"); + return ret; + } + + GTP_INFO("ss51_isp length: %d, checksum: 0x%04X", length, gt1x_calc_checksum(ss51_isp, length)); + // load ss51 isp + ret = gt1x_i2c_write(0xC000, ss51_isp, length); + if (ret) { + GTP_ERROR("load ss51 isp fail!"); + return ret; + } + // recall compare + ret = gt1x_recall_check(ss51_isp, 0xC000, length); + if (ret) { + GTP_ERROR("recall check ss51 isp fail!"); + return ret; + } + + memset(buffer, 0xAA, 10); + ret = gt1x_i2c_write_with_readback(0x8140, buffer, 10); + + // disable patch area access + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__PATCH_AREA_EN_, buffer, 1); + if (ret) { + GTP_ERROR("disable patch area access fail!"); + return ret; + } + // set 0x8006 + memset(buffer, 0x55, 8); + ret = gt1x_i2c_write_with_readback(0x8006, buffer, 8); + if (ret) { + GTP_ERROR("set 0x8006[0~7] 0x55 fail!"); + return ret; + } + // release ss51 + buffer[0] = 0x08; + ret = gt1x_i2c_write_with_readback(_rRW_MISCTL__SWRST_B0_, buffer, 1); + if (ret) { + GTP_ERROR("release ss51 fail!"); + return ret; + } + + msleep(100); + // check run state + ret = gt1x_i2c_read(0x8006, buffer, 2); + if (ret) { + GTP_ERROR("read 0x8006 fail!"); + return ret; + } + if (!(buffer[0] == 0xAA && buffer[1] == 0xBB)) { + GTP_ERROR("ERROR: isp is not running! 0x8006: %02X %02X", buffer[0], buffer[1]); + return ERROR_CHECK; + } + + return 0; +} + +u16 gt1x_calc_checksum(u8 * fw, u32 length) +{ + u32 i = 0; + u32 checksum = 0; + + for (i = 0; i < length; i += 2) { + checksum += (((int)fw[i]) << 8); + checksum += fw[i + 1]; + } + return (checksum & 0xFFFF); +} + +int gt1x_recall_check(u8 * chk_src, u16 start_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE]; + s32 ret = 0; + u16 len = 0; + u32 compared_length = 0; + + while (chk_length > 0) { + len = (chk_length > PACK_SIZE ? PACK_SIZE : chk_length); + + ret = gt1x_i2c_read(start_addr + compared_length, rd_buf, len); + if (ret) { + GTP_ERROR("recall i2c error,exit!"); + return ret; + } + + if (memcmp(rd_buf, &chk_src[compared_length], len)) { + GTP_ERROR("Recall frame not equal(addr: 0x%04X)", start_addr + compared_length); + GTP_DEBUG("chk_src array:"); + GTP_DEBUG_ARRAY(&chk_src[compared_length], len); + GTP_DEBUG("recall array:"); + GTP_DEBUG_ARRAY(rd_buf, len); + return ERROR_CHECK; + } + + chk_length -= len; + compared_length += len; + } + + GTP_DEBUG("Recall check %d bytes(address: 0x%04X) success.", compared_length, start_addr); + return 0; +} + +int gt1x_burn_subsystem(struct fw_subsystem_info *subsystem) +{ + int block_len; + u16 checksum; + int burn_len = 0; + u16 cur_addr; + u32 length = subsystem->length; + u8 buffer[10]; + int ret; + int wait_time; + int burn_state; + int retry = 5; + u8 *fw; + + GTP_INFO("Subsystem: %d", subsystem->type); + GTP_INFO("Length: %d", subsystem->length); + GTP_INFO("Address: 0x%08X", subsystem->address); + + while (length > 0 && retry > 0) { + retry--; + + block_len = length > 1024 * 4 ? 1024 * 4 : length; + + GTP_INFO("Burn block ==> length: %d, address: 0x%08X", block_len, subsystem->address + burn_len); + fw = gt1x_get_fw_data(subsystem->offset + burn_len, block_len); + if (fw == NULL) { + return ERROR_FW; + } + + cur_addr = ((subsystem->address + burn_len) >> 8); + + checksum = 0; + checksum += block_len; + checksum += cur_addr; + checksum += gt1x_calc_checksum(fw, block_len); + checksum = (0 - checksum); + + buffer[0] = ((block_len >> 8) & 0xFF); + buffer[1] = (block_len & 0xFF); + buffer[2] = ((cur_addr >> 8) & 0xFF); + buffer[3] = (cur_addr & 0xFF); + + ret = gt1x_i2c_write_with_readback(0x8100, buffer, 4); + if (ret) { + GTP_ERROR("write length & address fail!"); + continue; + } + + ret = gt1x_i2c_write(0x8100 + 4, fw, block_len); + if (ret) { + GTP_ERROR("write fw data fail!"); + continue; + } + + buffer[0] = ((checksum >> 8) & 0xFF); + buffer[1] = (checksum & 0xFF); + ret = gt1x_i2c_write_with_readback(0x8100 + 4 + block_len, buffer, 2); + if (ret) { + GTP_ERROR("write checksum fail!"); + continue; + } + + buffer[0] = 0; + ret = gt1x_i2c_write_with_readback(0x8022, buffer, 1); + if (ret) { + GTP_ERROR("clear control flag fail!"); + continue; + } + + buffer[0] = subsystem->type; + buffer[1] = subsystem->type; + ret = gt1x_i2c_write_with_readback(0x8020, buffer, 2); + if (ret) { + GTP_ERROR("write subsystem type fail!"); + continue; + } + burn_state = ERROR; + wait_time = 200; + msleep(5); + + while (wait_time-- > 0) { + u8 confirm = 0x55; + + ret = gt1x_i2c_read(0x8022, buffer, 1); + if (ret < 0) { + continue; + } + msleep(5); + ret = gt1x_i2c_read(0x8022, &confirm, 1); + if (ret < 0) { + continue; + } + if (buffer[0] != confirm) { + continue; + } + + if (buffer[0] == 0xAA) { + GTP_DEBUG("burning....."); + continue; + } else if (buffer[0] == 0xDD) { + GTP_ERROR("checksum error!"); + break; + } else if (buffer[0] == 0xBB) { + GTP_INFO("burning success."); + burn_state = 0; + break; + } else if (buffer[0] == 0xCC) { + GTP_ERROR("burning failed!"); + break; + } else { + GTP_DEBUG("unknown state!(0x8022: 0x%02X)", buffer[0]); + } + } + + if (!burn_state) { + length -= block_len; + burn_len += block_len; + retry = 5; + } + } + if (length == 0) { + return 0; + } else { + return ERROR_RETRY; + } +} + +int gt1x_check_subsystem_in_flash(struct fw_subsystem_info *subsystem) +{ + int block_len; + int checked_len = 0; + u32 length = subsystem->length; + int ret; + int check_state = 0; + int retry = 5; + u8 *fw; + + GTP_INFO("Subsystem: %d", subsystem->type); + GTP_INFO("Length: %d", subsystem->length); + GTP_INFO("Address: 0x%08X", subsystem->address); + + while (length > 0) { + block_len = length > 1024 * 4 ? 1024 * 4 : length; + + GTP_INFO("Check block ==> length: %d, address: 0x%08X", block_len, subsystem->address + checked_len); + fw = gt1x_get_fw_data(subsystem->offset + checked_len, block_len); + if (fw == NULL) { + return ERROR_FW; + } + ret = gt1x_read_flash(subsystem->address + checked_len, block_len); + if (ret) { + check_state |= ret; + } + + ret = gt1x_recall_check(fw, 0x8100, block_len); + if (ret) { + GTP_ERROR("Block in flash is broken!"); + check_state |= ret; + } + + length -= block_len; + checked_len += block_len; + retry = 5; + } + if (check_state) { + GTP_ERROR("Subsystem in flash is broken!"); + } else { + GTP_INFO("Subsystem in flash is correct!"); + } + return check_state; +} + +int gt1x_read_flash(u32 addr, int length) +{ + int wait_time; + int ret = 0; + u8 buffer[4]; + u16 read_addr = (addr >> 8); + + GTP_INFO("Read flash: 0x%04X, length: %d", addr, length); + + buffer[0] = 0; + ret = gt1x_i2c_write_with_readback(0x8022, buffer, 1); + + buffer[0] = ((length >> 8) & 0xFF); + buffer[1] = (length & 0xFF); + buffer[2] = ((read_addr >> 8) & 0xFF); + buffer[3] = (read_addr & 0xFF); + ret |= gt1x_i2c_write_with_readback(0x8100, buffer, 4); + + buffer[0] = 0xAA; + buffer[1] = 0xAA; + ret |= gt1x_i2c_write(0x8020, buffer, 2); + if (ret) { + GTP_ERROR("Error occured."); //comment + return ret; + } + + wait_time = 200; + while (wait_time > 0) { + wait_time--; + msleep(5); + ret = gt1x_i2c_read_dbl_check(0x8022, buffer, 1); + if (ret) { + continue; + } + if (buffer[0] == 0xBB) { + GTP_INFO("Read success(addr: 0x%04X, length: %d)", addr, length); + break; + } + } + if (wait_time == 0) { + GTP_ERROR("Read Flash FAIL!"); + return ERROR_RETRY; + } + return 0; +} + + +int gt1x_error_erase(void) +{ + int block_len; + u16 checksum; + u16 erase_addr; + u8 buffer[10]; + int ret; + int wait_time; + int burn_state = ERROR; + int retry = 5; + u8 *fw = NULL; + + GTP_INFO("Erase flash area of ss51."); + + gt1x_reset_guitar(); + + fw = gt1x_get_fw_data(update_info.firmware->subsystem[0].offset, + update_info.firmware->subsystem[0].length); + if (fw == NULL) { + GTP_ERROR("get isp fail"); + return ERROR_FW; + } + ret = gt1x_run_ss51_isp(fw, update_info.firmware->subsystem[0].length); + if (ret) { + GTP_ERROR("run isp fail"); + return ERROR_PATH; + } + + fw = kmalloc(1024 * 4, GFP_KERNEL); + if (!fw) { + GTP_ERROR("error when alloc mem."); + return ERROR_MEM; + } + + memset(fw, 0xFF, 1024 * 4); + erase_addr = 0x00; + block_len = 1024 * 4; + + while (retry-- > 0) { + + checksum = 0; + checksum += block_len; + checksum += erase_addr; + checksum += gt1x_calc_checksum(fw, block_len); + checksum = (0 - checksum); + + buffer[0] = ((block_len >> 8) & 0xFF); + buffer[1] = (block_len & 0xFF); + buffer[2] = ((erase_addr >> 8) & 0xFF); + buffer[3] = (erase_addr & 0xFF); + + ret = gt1x_i2c_write_with_readback(0x8100, buffer, 4); + if (ret) { + GTP_ERROR("write length & address fail!"); + continue; + } + + ret = gt1x_i2c_write(0x8100 + 4, fw, block_len); + if (ret) { + GTP_ERROR("write fw data fail!"); + continue; + } + + ret = gt1x_recall_check(fw, 0x8100 + 4, block_len); + if (ret) { + continue; + } + + buffer[0] = ((checksum >> 8) & 0xFF); + buffer[1] = (checksum & 0xFF); + ret = gt1x_i2c_write_with_readback(0x8100 + 4 + block_len, buffer, 2); + if (ret) { + GTP_ERROR("write checksum fail!"); + continue; + } + + buffer[0] = 0; + ret = gt1x_i2c_write_with_readback(0x8022, buffer, 1); + if (ret) { + GTP_ERROR("clear control flag fail!"); + continue; + } + + buffer[0] = FW_SECTION_TYPE_SS51_PATCH; + buffer[1] = FW_SECTION_TYPE_SS51_PATCH; + ret = gt1x_i2c_write_with_readback(0x8020, buffer, 2); + if (ret) { + GTP_ERROR("write subsystem type fail!"); + continue; + } + burn_state = ERROR; + wait_time = 200; + while (wait_time > 0) { + wait_time--; + msleep(5); + ret = gt1x_i2c_read_dbl_check(0x8022, buffer, 1); + if (ret) { + continue; + } + + if (buffer[0] == 0xAA) { + GTP_DEBUG("burning....."); + continue; + } else if (buffer[0] == 0xDD) { + GTP_ERROR("checksum error!"); + break; + } else if (buffer[0] == 0xBB) { + GTP_INFO("burning success."); + burn_state = 0; + break; + } else if (buffer[0] == 0xCC) { + GTP_ERROR("burning failed!"); + break; + } else { + GTP_DEBUG("unknown state!(0x8022: 0x%02X)", buffer[0]); + } + } + } + + kfree(fw); + if (burn_state == 0) { + return 0; + } else { + return ERROR_RETRY; + } +} + +void gt1x_leave_update_mode(void) +{ + GTP_DEBUG("Leave FW update mode."); + if (update_info.status != UPDATE_STATUS_ABORT) + gt1x_reset_guitar(); + +#if GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_ON); +#endif +#if GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + + update_info.status = UPDATE_STATUS_IDLE; + gt1x_irq_enable(); +} + +void dump_to_file(u16 addr, int length, char *filepath) +{ + struct file *flp = NULL; + u8 buf[128]; + const int READ_BLOCK_SIZE = 128; + int read_length = 0; + int len = 0; + + GTP_INFO("Dump(0x%04X, %d bytes) to file: %s\n", addr, length, filepath); + flp = filp_open(filepath, O_RDWR | O_CREAT, 0666); + if (IS_ERR(flp)) { + GTP_ERROR("can not open file: %s\n", filepath); + return; + } + flp->f_op->llseek(flp, 0, SEEK_SET); + + while (length > 0) { + len = (length > READ_BLOCK_SIZE ? READ_BLOCK_SIZE : length); + memset(buf, 0x33, len); + if (gt1x_i2c_read(addr + read_length, buf, len)) { + memset(buf, 0x33, len); + } + flp->f_op->write(flp, (char *)buf, len, &flp->f_pos); + read_length += len; + length -= len; + } + filp_close(flp, NULL); +} + +int gt1x_hold_ss51_dsp_no_reset(void) +{ + int ret = ERROR; + u8 buffer[2]; + + //hold ss51_dsp + ret = __gt1x_hold_ss51_dsp_20(); + if (ret) { + return ret; + } + // enable dsp & mcu power + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__DSP_MCU_PWR_, buffer, 1); + if (ret) { + GTP_ERROR("enabel dsp & mcu power fail!"); + return ret; + } + // disable watchdog + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__TMR0_EN, buffer, 1); + if (ret) { + GTP_ERROR("disable wdt fail!"); + return ret; + } + // clear cache + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__CACHE_EN, buffer, 1); + if (ret) { + GTP_ERROR("clear cache fail!"); + return ret; + } + // soft reset + buffer[0] = 0x01; + ret = gt1x_i2c_write(_bWO_MISCTL__CPU_SWRST_PULSE, buffer, 1); + if (ret) { + GTP_ERROR("software reset fail!"); + return ret; + } + // set scramble + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_rRW_MISCTL__BOOT_OPT_B0_, buffer, 1); + if (ret) { + GTP_ERROR("set scramble fail!"); + return ret; + } + + return 0; +} + +#define GT1X_LOAD_PACKET_SIZE (1024 * 2) + +int gt1x_load_patch(u8 * patch, u32 patch_size, int offset, int bank_size) +{ + s32 loaded_length = 0; + s32 len = 0; + s32 ret = 0; + u8 bank = 0, tmp; + u16 address; + + GTP_INFO("Load patch code(size: %d, checksum: 0x%04X, position: 0x%04X, bank-size: %d", patch_size, gt1x_calc_checksum(patch, patch_size), 0xC000 + offset, bank_size); + while (loaded_length != patch_size) { + if (loaded_length == 0 || (loaded_length + offset) % bank_size == 0) { + // select bank + bank = 0x04 + (loaded_length + offset) / bank_size; + ret = gt1x_i2c_write(_bRW_MISCTL__SRAM_BANK, &bank, 1); + if (ret) { + GTP_ERROR("select bank%d fail!", bank); + return ret; + } + GTP_INFO("Select bank%d success.", bank); + // enable patch area access + tmp = 0x01; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__PATCH_AREA_EN_ + bank - 4, &tmp, 1); + if (ret) { + GTP_ERROR("enable patch area access fail!"); + return ret; + } + } + + len = patch_size - loaded_length > GT1X_LOAD_PACKET_SIZE ? GT1X_LOAD_PACKET_SIZE : patch_size - loaded_length; + address = 0xC000 + (loaded_length + offset) % bank_size; + + ret = gt1x_i2c_write(address, &patch[loaded_length], len); + if (ret) { + GTP_ERROR("load 0x%04X, %dbytes fail!", address, len); + return ret; + } + ret = gt1x_recall_check(&patch[loaded_length], address, len); + if (ret) { + GTP_ERROR("Recall check 0x%04X, %dbytes fail!", address, len); + return ret; + } + GTP_INFO("load code 0x%04X, %dbytes success.", address, len); + + loaded_length += len; + } + + return 0; +} + +int gt1x_startup_patch(void) +{ + s32 ret = 0; + u8 buffer[8] = { 0x55 }; + buffer[0] = 0x00; + buffer[1] = 0x00; + ret |= gt1x_i2c_write(_bRW_MISCTL__PATCH_AREA_EN_, buffer, 2); + + memset(buffer, 0x55, 8); + ret |= gt1x_i2c_write(GTP_REG_FLASH_PASSBY, buffer, 8); + ret |= gt1x_i2c_write(GTP_REG_VERSION, buffer, 5); + + buffer[0] = 0xAA; + ret |= gt1x_i2c_write(GTP_REG_CMD, buffer, 1); + ret |= gt1x_i2c_write(GTP_REG_ESD_CHECK, buffer, 1); + + buffer[0] = 0x00; + ret |= gt1x_i2c_write(_rRW_MISCTL__SWRST_B0_, buffer, 1); + + msleep(200); + + return ret; +} diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c old mode 100644 new mode 100755 index 375ee68608d..a4a33b96837 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -21,6 +21,8 @@ #include #include #include "../../staging/android/timed_output.h" +#include +#include #define QPNP_VIB_VTG_CTL(base) (base + 0x41) #define QPNP_VIB_EN_CTL(base) (base + 0x46) @@ -65,6 +67,11 @@ struct qpnp_vib { int vtg_level; int timeout; struct mutex lock; + //add by liangdi + int vib_gpio; + u32 vib_gpio_flags; + //add end + }; static int qpnp_vib_read_u8(struct qpnp_vib *vib, u8 *data, u16 reg) @@ -157,6 +164,13 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) if (rc < 0) return rc; vib->reg_en_ctl = val; + //add by liangdi + if (gpio_is_valid(vib->vib_gpio)) + { + //dev_err(&vib->spmi->dev, "--->vib on\n"); + gpio_direction_output(vib->vib_gpio, 0); + } + //add end } } else { if (vib->mode != QPNP_VIB_MANUAL) { @@ -169,6 +183,13 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) if (rc < 0) return rc; vib->reg_en_ctl = val; + //add by liangdi + if (gpio_is_valid(vib->vib_gpio)) + { + //dev_err(&vib->spmi->dev, "--->vib off\n"); + gpio_direction_output(vib->vib_gpio, 1); + } + //add end } } @@ -250,7 +271,12 @@ static int qpnp_vib_parse_dt(struct qpnp_vib *vib) int rc; const char *mode; u32 temp_val; - + + //add by liangdi + /* vibrator */ + vib->vib_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "vib-gpios", + 0, &vib->vib_gpio_flags); + //add end vib->timeout = QPNP_VIB_DEFAULT_TIMEOUT; rc = of_property_read_u32(spmi->dev.of_node, "qcom,vib-timeout-ms", &temp_val); diff --git a/include/linux/akm09911.h b/include/linux/akm09911.h new file mode 100755 index 00000000000..59508fc384a --- /dev/null +++ b/include/linux/akm09911.h @@ -0,0 +1,168 @@ +/* + * Definitions for akm09911 compass chip. + */ +#ifndef AKM09911_H +#define AKM09911_H + +#include + +/* Device specific constant values */ +#define AK09911_REG_WIA1 0x00 +#define AK09911_REG_WIA2 0x01 +#define AK09911_REG_INFO1 0x02 +#define AK09911_REG_INFO2 0x03 +#define AK09911_REG_ST1 0x10 +#define AK09911_REG_HXL 0x11 +#define AK09911_REG_HXH 0x12 +#define AK09911_REG_HYL 0x13 +#define AK09911_REG_HYH 0x14 +#define AK09911_REG_HZL 0x15 +#define AK09911_REG_HZH 0x16 +#define AK09911_REG_TMPS 0x17 +#define AK09911_REG_ST2 0x18 +#define AK09911_REG_CNTL1 0x30 +#define AK09911_REG_CNTL2 0x31 +#define AK09911_REG_CNTL3 0x32 + +#define AK09911_FUSE_ASAX 0x60 +#define AK09911_FUSE_ASAY 0x61 +#define AK09911_FUSE_ASAZ 0x62 + +#define AK09911_MODE_SNG_MEASURE 0x01 +#define AK09911_MODE_SELF_TEST 0x10 +#define AK09911_MODE_FUSE_ACCESS 0x1F +#define AK09911_MODE_POWERDOWN 0x00 +#define AK09911_MODE_CONTINUOUS_10HZ 0x02 /* 10Hz */ +#define AK09911_MODE_CONTINUOUS_20HZ 0x04 /* 20Hz */ +#define AK09911_MODE_CONTINUOUS_50HZ 0x06 /* 50Hz */ +#define AK09911_MODE_CONTINUOUS_100HZ 0x08 /* 100Hz */ +#define AK09911_RESET_DATA 0x01 + +#define AK09911_REGS_SIZE 13 +#define AK09911_WIA1_VALUE 0x48 +#define AK09911_WIA2_VALUE 0x05 + +/*** Limit of factory shipment test *******************************************/ +#define TLIMIT_TN_REVISION_09911 "" +#define TLIMIT_TN_RST_WIA1_09911 "RST_WIA1" +#define TLIMIT_LO_RST_WIA1_09911 0x48 +#define TLIMIT_HI_RST_WIA1_09911 0x48 +#define TLIMIT_TN_RST_WIA2_09911 "RST_WIA2" +#define TLIMIT_LO_RST_WIA2_09911 0x05 +#define TLIMIT_HI_RST_WIA2_09911 0x05 + +#define TLIMIT_TN_ASAX_09911 "ASAX" +#define TLIMIT_LO_ASAX_09911 1 +#define TLIMIT_HI_ASAX_09911 254 +#define TLIMIT_TN_ASAY_09911 "ASAY" +#define TLIMIT_LO_ASAY_09911 1 +#define TLIMIT_HI_ASAY_09911 254 +#define TLIMIT_TN_ASAZ_09911 "ASAZ" +#define TLIMIT_LO_ASAZ_09911 1 +#define TLIMIT_HI_ASAZ_09911 254 + +#define TLIMIT_TN_SNG_ST1_09911 "SNG_ST1" +#define TLIMIT_LO_SNG_ST1_09911 1 +#define TLIMIT_HI_SNG_ST1_09911 1 + +#define TLIMIT_TN_SNG_HX_09911 "SNG_HX" +#define TLIMIT_LO_SNG_HX_09911 -8189 +#define TLIMIT_HI_SNG_HX_09911 8189 + +#define TLIMIT_TN_SNG_HY_09911 "SNG_HY" +#define TLIMIT_LO_SNG_HY_09911 -8189 +#define TLIMIT_HI_SNG_HY_09911 8189 + +#define TLIMIT_TN_SNG_HZ_09911 "SNG_HZ" +#define TLIMIT_LO_SNG_HZ_09911 -8189 +#define TLIMIT_HI_SNG_HZ_09911 8189 + +#define TLIMIT_TN_SNG_ST2_09911 "SNG_ST2" +#define TLIMIT_LO_SNG_ST2_09911 0 +#define TLIMIT_HI_SNG_ST2_09911 0 + +#define TLIMIT_TN_SLF_ST1_09911 "SLF_ST1" +#define TLIMIT_LO_SLF_ST1_09911 1 +#define TLIMIT_HI_SLF_ST1_09911 1 + +#define TLIMIT_TN_SLF_RVHX_09911 "SLF_REVSHX" +#define TLIMIT_LO_SLF_RVHX_09911 -30 +#define TLIMIT_HI_SLF_RVHX_09911 30 + +#define TLIMIT_TN_SLF_RVHY_09911 "SLF_REVSHY" +#define TLIMIT_LO_SLF_RVHY_09911 -30 +#define TLIMIT_HI_SLF_RVHY_09911 30 + +#define TLIMIT_TN_SLF_RVHZ_09911 "SLF_REVSHZ" +#define TLIMIT_LO_SLF_RVHZ_09911 -400 +#define TLIMIT_HI_SLF_RVHZ_09911 -50 + +#define TLIMIT_TN_SLF_ST2_09911 "SLF_ST2" +#define TLIMIT_LO_SLF_ST2_09911 0 +#define TLIMIT_HI_SLF_ST2_09911 0 + +/* To avoid device dependency, convert to general name */ +#define AKM_I2C_NAME "akm09911" +#define AKM_MISCDEV_NAME "akm09911_dev" +#define AKM_SYSCLS_NAME "compass" +#define AKM_SYSDEV_NAME "akm09911" +#define AKM_REG_MODE AK09911_REG_CNTL2 +#define AKM_REG_RESET AK09911_REG_CNTL3 +#define AKM_REG_STATUS AK09911_REG_ST1 +#define AKM_MEASURE_TIME_US 10000 +#define AKM_DRDY_IS_HIGH(x) ((x) & 0x01) +#define AKM_DOR_IS_HIGH(x) ((x) & 0x02) +#define AKM_SENSOR_INFO_SIZE 2 +#define AKM_SENSOR_CONF_SIZE 3 +#define AKM_SENSOR_DATA_SIZE 9 + +#define AKM_YPR_DATA_SIZE 16 +#define AKM_RWBUF_SIZE 16 +#define AKM_REGS_SIZE AK09911_REGS_SIZE +#define AKM_REGS_1ST_ADDR AK09911_REG_WIA1 +#define AKM_FUSE_1ST_ADDR AK09911_FUSE_ASAX + +#define AKM_MODE_SNG_MEASURE AK09911_MODE_SNG_MEASURE +#define AKM_MODE_SELF_TEST AK09911_MODE_SELF_TEST +#define AKM_MODE_FUSE_ACCESS AK09911_MODE_FUSE_ACCESS +#define AKM_MODE_POWERDOWN AK09911_MODE_POWERDOWN +#define AKM_MODE_CONTINUOUS_10HZ AK09911_MODE_CONTINUOUS_10HZ +#define AKM_MODE_CONTINUOUS_20HZ AK09911_MODE_CONTINUOUS_20HZ +#define AKM_MODE_CONTINUOUS_50HZ AK09911_MODE_CONTINUOUS_50HZ +#define AKM_MODE_CONTINUOUS_100HZ AK09911_MODE_CONTINUOUS_100HZ +#define AKM_RESET_DATA AK09911_RESET_DATA + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define FUSION_DATA_FLAG 2 +#define AKM_NUM_SENSORS 3 + +#define ACC_DATA_READY (1<<(ACC_DATA_FLAG)) +#define MAG_DATA_READY (1<<(MAG_DATA_FLAG)) +#define FUSION_DATA_READY (1<<(FUSION_DATA_FLAG)) + +#define AKMIO 0xA1 + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_READ _IOWR(AKMIO, 0x01, char) +#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x02, char) +#define ECS_IOCTL_RESET _IO(AKMIO, 0x03) +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x10, char) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x11, int[AKM_YPR_DATA_SIZE]) +#define ECS_IOCTL_GET_INFO _IOR(AKMIO, 0x20, unsigned char[AKM_SENSOR_INFO_SIZE]) +#define ECS_IOCTL_GET_CONF _IOR(AKMIO, 0x21, unsigned char[AKM_SENSOR_CONF_SIZE]) +#define ECS_IOCTL_GET_DATA _IOR(AKMIO, 0x22, unsigned char[AKM_SENSOR_DATA_SIZE]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x23, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x24, int) +#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x25, long long int) +#define ECS_IOCTL_GET_LAYOUT _IOR(AKMIO, 0x26, char) +#define ECS_IOCTL_GET_ACCEL _IOR(AKMIO, 0x30, short[3]) + +struct akm09911_platform_data { + char layout; + int gpio_DRDY; + int gpio_RSTN; +}; + +#endif + -- 2.25.1 From 1ca6e39afef77f336398485b2adb97b4c7fcaace Mon Sep 17 00:00:00 2001 From: vipinbb Date: Sun, 15 Sep 2019 13:14:38 -0400 Subject: [PATCH 02/76] 20190829_meig8909g0 Change-Id: I03466e079b50eadf0eec76c29b7843cfd0705f2d --- Documentation/arm/SH-Mobile/.gitignore | 1 - arch/arm/boot/dts/qcom/msm-pm8909.dtsi | 10 ++++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) delete mode 100644 Documentation/arm/SH-Mobile/.gitignore mode change 100644 => 100755 arch/arm/boot/dts/qcom/msm-pm8909.dtsi diff --git a/Documentation/arm/SH-Mobile/.gitignore b/Documentation/arm/SH-Mobile/.gitignore deleted file mode 100644 index c928dbf3cc8..00000000000 --- a/Documentation/arm/SH-Mobile/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vrl4 diff --git a/arch/arm/boot/dts/qcom/msm-pm8909.dtsi b/arch/arm/boot/dts/qcom/msm-pm8909.dtsi old mode 100644 new mode 100755 index 77ffba06f31..c840c742195 --- a/arch/arm/boot/dts/qcom/msm-pm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm8909.dtsi @@ -40,15 +40,21 @@ qcom,pull-up = <1>; qcom,s1-timer = <10256>; qcom,s2-timer = <2000>; - qcom,s2-type = <1>; + qcom,s2-type = <7>; linux,code = <116>; }; + /*for bug 7859, by mickey.shi, May,17,2017, begin*/ qcom,pon_2 { qcom,pon-type = <1>; + qcom,support-reset = <1>; qcom,pull-up = <1>; - linux,code = <114>; + qcom,s1-timer = <3072>; + qcom,s2-timer = <2000>; + qcom,s2-type = <7>; /* 1 --> 7 bug 5254 & bug 5175, mickey.shi, 11/15/2016*/ + linux,code = <158>; /* KEY_BACK */ }; + /*for bug 7859, by mickey.shi, May,17,2017, end*/ }; pm8909_mpps: mpps { -- 2.25.1 From fed3ad5033a64b61f608dabad4393466e2e8fb74 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Mon, 13 Jan 2020 13:59:18 -0700 Subject: [PATCH 03/76] mege-data 2019-11-22 23:02:11: add new TP(GD917S) driver Change-Id: I51a153911417ee47100c82c151efb8f8f18e87ed --- arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi | 61 +- arch/arm/configs/msm8909-perf_defconfig | 7 +- arch/arm/configs/msm8909_defconfig | 7 +- drivers/gpio/gpiolib.c | 4 +- drivers/input/touchscreen/Makefile | 3 +- drivers/input/touchscreen/gt9xx_2/Kconfig | 51 + drivers/input/touchscreen/gt9xx_2/Makefile | 16 + .../input/touchscreen/gt9xx_2/goodix_tool.c | 598 ++ drivers/input/touchscreen/gt9xx_2/gt9xx.c | 2704 +++++++ drivers/input/touchscreen/gt9xx_2/gt9xx.h | 231 + .../touchscreen/gt9xx_2/gt9xx_firmware.h | 6844 +++++++++++++++++ .../input/touchscreen/gt9xx_2/gt9xx_update.c | 1552 ++++ 12 files changed, 12072 insertions(+), 6 deletions(-) mode change 100644 => 100755 drivers/gpio/gpiolib.c create mode 100644 drivers/input/touchscreen/gt9xx_2/Kconfig create mode 100644 drivers/input/touchscreen/gt9xx_2/Makefile create mode 100644 drivers/input/touchscreen/gt9xx_2/goodix_tool.c create mode 100644 drivers/input/touchscreen/gt9xx_2/gt9xx.c create mode 100644 drivers/input/touchscreen/gt9xx_2/gt9xx.h create mode 100644 drivers/input/touchscreen/gt9xx_2/gt9xx_firmware.h create mode 100644 drivers/input/touchscreen/gt9xx_2/gt9xx_update.c diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi index f4239d6b52b..7b12a7074b9 100755 --- a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi @@ -24,7 +24,7 @@ &soc { i2c@78b9000 { /* BLSP1 QUP5 */ status = "ok"; - goodix@5d { + /*goodix@5d { compatible = "goodix,gt1x"; reg = <0x5d>; interrupt-parent = <&msm_gpio>; @@ -39,6 +39,60 @@ pinctrl-0 = <&ts_int_active &ts_reset_active>; pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; pinctrl-2 = <&ts_release>; + };*/ + goodix@5d { + compatible = "goodix,gt9xx"; + reg = <0x5d>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x00>; + reset-gpios = <&msm_gpio 12 0x00>; + interrupt-gpios = <&msm_gpio 13 0x2002>; + vdd-supply = <&pm8909_l17>; + vcc_i2c-supply = <&pm8909_l6>; + // pins used by touchscreen + pinctrl-names = "pmx_ts_active", + "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + goodix,i2c-pull-up; + goodix,no-force-update; + goodix,panel-coords = <0 0 480 800>; + goodix,display-coords = <0 0 480 800>; + goodix,button-map= <139 172 158>; + goodix,product-id0 = "917S"; + goodix,product-id1 = "917S"; + //goodix,fw_name = "gtp_fw.bin";if open, there is a null pointer in sysfs_remove_group + goodix,enable-power-off; + goodix,cfg-data0 = [ + 01 E0 01 20 03 05 0D 00 00 40 + 00 0F 78 64 53 11 01 00 00 00 + 14 17 19 1D 0F 04 00 00 00 00 + 00 00 04 51 14 00 00 00 00 00 + 32 00 00 50 54 28 85 25 10 37 + 39 A2 07 38 6D 62 93 02 24 00 + 00 28 50 C0 02 02 00 00 53 B1 + 2E 9E 35 8D 3B 80 42 76 49 6D + 00 00 00 00 00 00 00 F0 4C 3C + FF FF 07 14 14 00 00 00 00 00 + 00 00 00 00 00 00 00 00 50 73 + 50 32 FF FF 00 00 00 00 00 00 + 00 00 00 28 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 0D 0E 0F 10 12 13 14 15 1F 1D + 1B 1A 19 18 17 16 FF FF FF FF + FF FF FF FF FF FF FF FF FF FF + FF FF 06 08 0C 12 13 14 15 17 + 18 19 FF FF FF FF FF FF FF FF + FF FF FF FF 00 00 05 00 00 0F + 00 00 00 80 46 08 96 50 32 0A + 0A 64 32 00 00 00 00 00 00 70 + 22 03 0C 08 23 00 14 23 00 28 + 46 30 3C D0 07 50 30 02 01]; + goodix,cfg-data1 = []; + goodix,have-touch-key; + goodix,driver-send-cfg; }; /* focaltech@38 { compatible = "focaltech,5x06"; @@ -76,6 +130,11 @@ }; */ }; + mg_drv{ + compatible = "qcom,mg_drv"; + status = "ok"; + qcom,pwm_gpio = <&msm_gpio 98 0x0>; + }; gen-vkeys { compatible = "qcom,gen-vkeys"; diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index b778f15ca42..fa1c46ebf5c 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -544,4 +544,9 @@ CONFIG_SENSORS_BMI160_ENABLE_INT1=y # CONFIG_SENSORS_BMI160_ENABLE_INT2=y CONFIG_SENSORS_BMP280=y CONFIG_SENSORS_BMP280_I2C=y - +CONFIG_TOUCHSCREEN_GT9XX=y +CONFIG_GT9XX_TOUCHPANEL_DRIVER=yCONFIG_TOUCHSCREEN_GT9XX=y +CONFIG_GT9XX_TOUCHPANEL_DRIVER=y +CONFIG_GT9XX_TOUCHPANEL_UPDATE=y +CONFIG_GT9XX_TOUCHPANEL_DEBUG=y +CONFIG_MG_DRIVER_CONTROL=y \ No newline at end of file diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index f2f16d7ab43..fa4f6a8c503 100755 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -609,4 +609,9 @@ CONFIG_SENSORS_BMI160_ENABLE_INT1=y # CONFIG_SENSORS_BMI160_ENABLE_INT2=y CONFIG_SENSORS_BMP280=y CONFIG_SENSORS_BMP280_I2C=y - +CONFIG_TOUCHSCREEN_GT9XX=y +CONFIG_GT9XX_TOUCHPANEL_DRIVER=y +CONFIG_GT9XX_TOUCHPANEL_UPDATE=y +CONFIG_GT9XX_TOUCHPANEL_DEBUG=y +CONFIG_MG_DRIVER_CONTROL=y +CONFIG_LOG_BUF_SHIFT=20 \ No newline at end of file diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c old mode 100644 new mode 100755 index 164ee9b4646..684d6d9feb6 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -990,12 +990,12 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) int status = -EINVAL; /* GPIOs used for IRQs shall not be set as output */ - if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { +/* if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { gpiod_err(desc, "%s: tried to set a GPIO tied to an IRQ as output\n", __func__); return -EIO; - } + }*/ /* Open drain pin should not be driven to 1 */ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 075d17bba8f..d5508c103f9 100755 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -89,5 +89,6 @@ obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o -obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ +#obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ +obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_2/ obj-$(CONFIG_TOUCHSCREEN_GT1XX) += gt1xx/ diff --git a/drivers/input/touchscreen/gt9xx_2/Kconfig b/drivers/input/touchscreen/gt9xx_2/Kconfig new file mode 100644 index 00000000000..9d3640383a2 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2/Kconfig @@ -0,0 +1,51 @@ +# +# Goodix GT9xx Touchscreen driver +# + +config GT9XX_TOUCHPANEL_DRIVER + tristate "Goodix GT9xx touchpanel driver" + depends on TOUCHSCREEN_GT9XX + default n + help + This is the main file for touchpanel driver for Goodix GT9xx + touchscreens. + + Say Y here if you have a Goodix GT9xx touchscreen connected + to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called gt9xx_update. + +config GT9XX_TOUCHPANEL_UPDATE + tristate "Goodix GT9xx touchpanel auto update support" + depends on GT9XX_TOUCHPANEL_DRIVER + default n + help + This enables support for firmware update for Goodix GT9xx + touchscreens. + + Say Y here if you have a Goodix GT9xx touchscreen connected + to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called gt9xx_update. + +config GT9XX_TOUCHPANEL_DEBUG + tristate "Goodix GT9xx Tools for debuging" + depends on GT9XX_TOUCHPANEL_DRIVER + default n + help + This is application debug interface support for Goodix GT9xx + touchscreens. + + Say Y here if you want to have a Android app debug interface + to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called gt9xx_update. diff --git a/drivers/input/touchscreen/gt9xx_2/Makefile b/drivers/input/touchscreen/gt9xx_2/Makefile new file mode 100644 index 00000000000..9699ef50a48 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2/Makefile @@ -0,0 +1,16 @@ +#gt915 touchpanel driver + +ifeq ($(CONFIG_COMPAT),y) +EXTRA_CFLAGS +=-Wno-error=date-time +EXTRA_CFLAGS +=-Wno-date-time +else +EXTRA_CFLAGS +=-Wno-Werror=date-time +EXTRA_CFLAGS +=-Wno-Wdate-time +endif + +obj-$(CONFIG_GT9XX_TOUCHPANEL_DRIVER) += gt9xx.o +#gt915 update file +obj-$(CONFIG_GT9XX_TOUCHPANEL_UPDATE) += gt9xx_update.o +#debug tool +obj-$(CONFIG_GT9XX_TOUCHPANEL_DEBUG) += goodix_tool.o + diff --git a/drivers/input/touchscreen/gt9xx_2/goodix_tool.c b/drivers/input/touchscreen/gt9xx_2/goodix_tool.c new file mode 100644 index 00000000000..b395e2f3286 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2/goodix_tool.c @@ -0,0 +1,598 @@ +/* drivers/input/touchscreen/goodix_tool.c + * + * 2010 - 2012 Goodix Technology. + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version:1.6 + * V1.0:2012/05/01,create file. + * V1.2:2012/06/08,modify some warning. + * V1.4:2012/08/28,modified to support GT9XX + * V1.6:new proc name + */ + +#include "gt9xx.h" +#include +#include +#include + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *)) +static char procname[20] = {0}; + +struct st_cmd_head { + u8 wr; /* write read flag 0:R 1:W 2:PID 3: */ + u8 flag; /* 0:no need flag/int 1: need flag 2:need int */ + u8 flag_addr[2];/* flag address */ + u8 flag_val; /* flag val */ + u8 flag_relation; /* flag_val:flag 0:not equal 1:equal 2:> 3:< */ + u16 circle; /* polling cycle */ + u8 times; /* plling times */ + u8 retry; /* I2C retry times */ + u16 delay; /* delay befor read or after write */ + u16 data_len; /* data length */ + u8 addr_len; /* address length */ + u8 addr[2]; /* address */ + u8 res[3]; /* reserved */ + u8 *data; /* data pointer */ +} __packed; + +static struct st_cmd_head cmd_head; + +static struct i2c_client *gt_client; + +static struct proc_dir_entry *goodix_proc_entry; + +static struct mutex lock; + +static s32 (*tool_i2c_read)(u8 *, u16); +static s32 (*tool_i2c_write)(u8 *, u16); + +s32 data_length; +s8 ic_type[16] = {0}; + +static void tool_set_proc_name(char *procname) +{ + char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", + "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + char date[20] = {0}; + char month[4] = {0}; + int i = 0, n_month = 1, n_day = 0, n_year = 0; + snprintf(date, 20, "%s", __DATE__); + + /* pr_debug("compile date: %s", date); */ + + sscanf(date, "%s %d %d", month, &n_day, &n_year); + + for (i = 0; i < 12; ++i) { + if (!memcmp(months[i], month, 3)) { + n_month = i+1; + break; + } + } + + snprintf(procname, 20, "gmnode%04d%02d%02d", n_year, n_month, n_day); + /* pr_debug("procname = %s", procname); */ +} + +static s32 tool_i2c_read_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 i = 0; + struct i2c_msg msgs[2] = { + { + .flags = !I2C_M_RD, + .addr = gt_client->addr, + .len = cmd_head.addr_len, + .buf = &buf[0], + }, + { + .flags = I2C_M_RD, + .addr = gt_client->addr, + .len = len, + .buf = &buf[GTP_ADDR_LENGTH], + }, + }; + + for (i = 0; i < cmd_head.retry; i++) { + ret = i2c_transfer(gt_client->adapter, msgs, 2); + if (ret > 0) + break; + } + + if (i == cmd_head.retry) { + dev_err(>_client->dev, "I2C read retry limit over.\n"); + ret = -EIO; + } + + return ret; +} + +static s32 tool_i2c_write_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 i = 0; + struct i2c_msg msg = { + .flags = !I2C_M_RD, + .addr = gt_client->addr, + .len = len, + .buf = buf, + }; + + for (i = 0; i < cmd_head.retry; i++) { + ret = i2c_transfer(gt_client->adapter, &msg, 1); + if (ret > 0) + break; + } + + if (i == cmd_head.retry) { + dev_err(>_client->dev, "I2C write retry limit over.\n"); + ret = -EIO; + } + + return ret; +} + +static s32 tool_i2c_read_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_read_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static s32 tool_i2c_write_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_write_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static void register_i2c_func(void) +{ + if (strcmp(ic_type, "GT8110") && strcmp(ic_type, "GT8105") + && strcmp(ic_type, "GT801") && strcmp(ic_type, "GT800") + && strcmp(ic_type, "GT801PLUS") && strcmp(ic_type, "GT811") + && strcmp(ic_type, "GTxxx")) { + tool_i2c_read = tool_i2c_read_with_extra; + tool_i2c_write = tool_i2c_write_with_extra; + pr_debug("I2C function: with pre and end cmd!"); + } else { + tool_i2c_read = tool_i2c_read_no_extra; + tool_i2c_write = tool_i2c_write_no_extra; + pr_info("I2C function: without pre and end cmd!"); + } +} + +static void unregister_i2c_func(void) +{ + tool_i2c_read = NULL; + tool_i2c_write = NULL; + pr_info("I2C function: unregister i2c transfer function!"); +} + +void uninit_wr_node(void) +{ + cmd_head.data = NULL; + unregister_i2c_func(); + proc_remove(goodix_proc_entry); +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + pr_debug("equal:src:0x%02x dst:0x%02x ret:%d.", + src, dst, (s32)ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* +Function: + Comfirm function. +Input: + None. +Output: + Return write length. +********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + + memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); + + for (i = 0; i < cmd_head.times; i++) { + if (tool_i2c_read(buf, 1) <= 0) { + dev_err(>_client->dev, "Read flag data failed!"); + return FAIL; + } + if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, + cmd_head.flag_relation)) { + pr_debug("value at flag addr:0x%02x.", + buf[GTP_ADDR_LENGTH]); + pr_debug("flag value:0x%02x.", cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) { + dev_err(>_client->dev, "Didn't get the flag to continue!"); + return FAIL; + } + + return SUCCESS; +} + +#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE +static s32 fill_update_info(char __user *user_buf, + size_t count, loff_t *ppos) +{ + u8 buf[4]; + + buf[0] = show_len >> 8; + buf[1] = show_len & 0xff; + buf[2] = total_len >> 8; + buf[3] = total_len & 0xff; + return simple_read_from_buffer(user_buf, count, ppos, + buf, sizeof(buf)); +} +#else +static s32 fill_update_info(char __user *user_buf, + size_t count, loff_t *ppos) +{ + return -ENODEV; +} +#endif + +/******************************************************** +Function: + Goodix tool write function. +nput: + standard proc write function param. +Output: + Return write length. +********************************************************/ +static ssize_t goodix_tool_write(struct file *filp, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + s32 ret = 0; + + mutex_lock(&lock); + ret = copy_from_user(&cmd_head, userbuf, CMD_HEAD_LENGTH); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + ret = -EACCES; + goto exit; + } + + dev_dbg(>_client->dev, "wr:0x%02x, flag:0x%02x, flag addr:0x%02x%02x, flag val:0x%02x, flag rel:0x%02x, circle:%d, times:%d, retry:%d, delay:%d, data len:%d, addr len:%d, addr:0x%02x%02x, write len: %d.", + cmd_head.wr, cmd_head.flag, cmd_head.flag_addr[0], + cmd_head.flag_addr[1], cmd_head.flag_val, + cmd_head.flag_relation, (s32)cmd_head.circle, + (s32)cmd_head.times, (s32)cmd_head.retry, (s32)cmd_head.delay, + (s32)cmd_head.data_len, (s32)cmd_head.addr_len, + cmd_head.addr[0], cmd_head.addr[1], (s32)count); + + if (cmd_head.data_len > (data_length - GTP_ADDR_LENGTH)) { + dev_err(>_client->dev, "data len %d > data buff %d, rejected!\n", + cmd_head.data_len, (data_length - GTP_ADDR_LENGTH)); + ret = -EINVAL; + goto exit; + } + if (cmd_head.addr_len > GTP_ADDR_LENGTH) { + dev_err(>_client->dev, "addr len %d > data buff %d, rejected!\n", + cmd_head.addr_len, GTP_ADDR_LENGTH); + ret = -EINVAL; + goto exit; + } + + if (cmd_head.wr == GTP_RW_WRITE) { + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + goto exit; + } + + memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], + cmd_head.addr, cmd_head.addr_len); + + if (cmd_head.flag == GTP_NEED_FLAG) { + if (comfirm() == FAIL) { + dev_err(>_client->dev, "Comfirm fail!"); + ret = -EINVAL; + goto exit; + } + } else if (cmd_head.flag == GTP_NEED_INTERRUPT) { + /* Need interrupt! */ + } + if (tool_i2c_write( + &cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], + cmd_head.data_len + cmd_head.addr_len) <= 0) { + dev_err(>_client->dev, "Write data failed!"); + ret = -EIO; + goto exit; + } + + if (cmd_head.delay) + msleep(cmd_head.delay); + + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + goto exit; + } else if (cmd_head.wr == GTP_RW_WRITE_IC_TYPE) { /* Write ic type */ + ret = copy_from_user(&cmd_head.data[0], + &userbuf[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + goto exit; + } + + if (cmd_head.data_len > sizeof(ic_type)) { + + ret = -EINVAL; + goto exit; + } + memcpy(ic_type, cmd_head.data, cmd_head.data_len); + + register_i2c_func(); + + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + goto exit; + } else if (cmd_head.wr == GTP_RW_NO_WRITE) { + ret = cmd_head.data_len + CMD_HEAD_LENGTH; + goto exit; + } else if (cmd_head.wr == GTP_RW_DISABLE_IRQ) { /* disable irq! */ + gtp_irq_disable(i2c_get_clientdata(gt_client)); + + #if GTP_ESD_PROTECT + gtp_esd_switch(gt_client, SWITCH_OFF); + #endif + ret = CMD_HEAD_LENGTH; + goto exit; + } else if (cmd_head.wr == GTP_RW_ENABLE_IRQ) { /* enable irq! */ + gtp_irq_enable(i2c_get_clientdata(gt_client)); + + #if GTP_ESD_PROTECT + gtp_esd_switch(gt_client, SWITCH_ON); + #endif + ret = CMD_HEAD_LENGTH; + goto exit; + } else if (cmd_head.wr == GTP_RW_CHECK_RAWDIFF_MODE) { + struct goodix_ts_data *ts = i2c_get_clientdata(gt_client); + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &userbuf[CMD_HEAD_LENGTH], cmd_head.data_len); + if (ret) { + pr_debug("copy_from_user failed."); + goto exit; + } + if (cmd_head.data[GTP_ADDR_LENGTH]) { + pr_debug("gtp enter rawdiff."); + ts->gtp_rawdiff_mode = true; + } else { + ts->gtp_rawdiff_mode = false; + pr_debug("gtp leave rawdiff."); + } + ret = CMD_HEAD_LENGTH; + goto exit; + } else if (cmd_head.wr == GTP_RW_ENTER_UPDATE_MODE) { + /* Enter update mode! */ + if (gup_enter_update_mode(gt_client) == FAIL) { + ret = -EBUSY; + goto exit; + } + } else if (cmd_head.wr == GTP_RW_LEAVE_UPDATE_MODE) { + /* Leave update mode! */ + gup_leave_update_mode(gt_client); + } else if (cmd_head.wr == GTP_RW_UPDATE_FW) { + /* Update firmware! */ + show_len = 0; + total_len = 0; + if (cmd_head.data_len + 1 > data_length) { + dev_err(>_client->dev, "data len %d > data buff %d, rejected!\n", + cmd_head.data_len + 1, data_length); + ret = -EINVAL; + goto exit; + } + memset(cmd_head.data, 0, cmd_head.data_len + 1); + memcpy(cmd_head.data, &userbuf[CMD_HEAD_LENGTH], + cmd_head.data_len); + + if (gup_update_proc((void *)cmd_head.data) == FAIL) { + ret = -EBUSY; + goto exit; + } + } + ret = CMD_HEAD_LENGTH; + +exit: + mutex_unlock(&lock); + return ret; +} + +/******************************************************* +Function: + Goodix tool read function. +Input: + standard seq file read function param. +Output: + Return read length. +********************************************************/ +static ssize_t goodix_tool_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + u16 data_len = 0; + s32 ret; + u8 buf[32]; + + mutex_lock(&lock); + if (cmd_head.wr & 0x1) { + dev_err(>_client->dev, "command head wrong\n"); + ret = -EINVAL; + goto exit; + } + + switch (cmd_head.wr) { + case GTP_RW_READ: + if (cmd_head.flag == GTP_NEED_FLAG) { + if (comfirm() == FAIL) { + dev_err(>_client->dev, "Comfirm fail!"); + ret = -EINVAL; + goto exit; + } + } else if (cmd_head.flag == GTP_NEED_INTERRUPT) { + /* Need interrupt! */ + } + + memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len); + + pr_debug("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], + cmd_head.data[1]); + pr_debug("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], + cmd_head.addr[1]); + + if (cmd_head.delay) + msleep(cmd_head.delay); + + data_len = cmd_head.data_len; + if (data_len <= 0 || (data_len > data_length)) { + dev_err(>_client->dev, "Invalid data length %d\n", + data_len); + ret = -EINVAL; + goto exit; + } + if (data_len > count) + data_len = count; + + if (tool_i2c_read(cmd_head.data, data_len) <= 0) { + dev_err(>_client->dev, "Read data failed!\n"); + ret = -EIO; + goto exit; + } + ret = simple_read_from_buffer(user_buf, count, ppos, + &cmd_head.data[GTP_ADDR_LENGTH], data_len); + break; + case GTP_RW_FILL_INFO: + ret = fill_update_info(user_buf, count, ppos); + break; + case GTP_RW_READ_VERSION: + /* Read driver version */ + data_len = scnprintf(buf, sizeof(buf), "%s\n", + GTP_DRIVER_VERSION); + ret = simple_read_from_buffer(user_buf, count, ppos, + buf, data_len); + break; + default: + ret = -EINVAL; + break; + } + +exit: + mutex_unlock(&lock); + return ret; +} + +static const struct file_operations goodix_proc_fops = { + .write = goodix_tool_write, + .read = goodix_tool_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +s32 init_wr_node(struct i2c_client *client) +{ + u8 i; + + gt_client = client; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = GTP_I2C_RETRY_5; + while ((!cmd_head.data) && i) { + cmd_head.data = devm_kzalloc(&client->dev, + i * DATA_LENGTH_UINT, GFP_KERNEL); + if (cmd_head.data) + break; + i--; + } + if (i) { + data_length = i * DATA_LENGTH_UINT; + dev_dbg(&client->dev, "Applied memory size:%d.", data_length); + } else { + dev_err(&client->dev, "Apply for memory failed."); + return FAIL; + } + + cmd_head.addr_len = 2; + cmd_head.retry = GTP_I2C_RETRY_5; + + register_i2c_func(); + + mutex_init(&lock); + tool_set_proc_name(procname); + goodix_proc_entry = proc_create(procname, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + goodix_proc_entry, + &goodix_proc_fops); + if (goodix_proc_entry == NULL) { + dev_err(&client->dev, "Couldn't create proc entry!"); + return FAIL; + } + + return SUCCESS; +} diff --git a/drivers/input/touchscreen/gt9xx_2/gt9xx.c b/drivers/input/touchscreen/gt9xx_2/gt9xx.c new file mode 100644 index 00000000000..ced035fc6a5 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2/gt9xx.c @@ -0,0 +1,2704 @@ +/* drivers/input/touchscreen/gt9xx.c + * + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * Linux Foundation chooses to take subject only to the GPLv2 license + * terms, and distributes only under these terms. + * + * 2010 - 2013 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.8 + * Authors: andrew@goodix.com, meta@goodix.com + * Release Date: 2013/04/25 + * Revision record: + * V1.0: + * first Release. By Andrew, 2012/08/31 + * V1.2: + * modify gtp_reset_guitar,slot report,tracking_id & 0x0F. + * By Andrew, 2012/10/15 + * V1.4: + * modify gt9xx_update.c. By Andrew, 2012/12/12 + * V1.6: + * 1. new heartbeat/esd_protect mechanism(add external watchdog) + * 2. doze mode, sliding wakeup + * 3. 3 more cfg_group(GT9 Sensor_ID: 0~5) + * 3. config length verification + * 4. names & comments + * By Meta, 2013/03/11 + * V1.8: + * 1. pen/stylus identification + * 2. read double check & fixed config support + * 2. new esd & slide wakeup optimization + * By Meta, 2013/06/08 + */ + +#include +#include "gt9xx.h" + +#include +#include +#include +#include +#include +#include +#include + +#define GOODIX_DEV_NAME "Goodix-CTP" +#define CFG_MAX_TOUCH_POINTS 5 +#define GOODIX_COORDS_ARR_SIZE 4 +#define MAX_BUTTONS 4 + +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" +#define GOODIX_VTG_MIN_UV 2600000 +#define GOODIX_VTG_MAX_UV 3300000 +#define GOODIX_I2C_VTG_MIN_UV 1800000 +#define GOODIX_I2C_VTG_MAX_UV 1800000 +#define GOODIX_VDD_LOAD_MIN_UA 0 +#define GOODIX_VDD_LOAD_MAX_UA 10000 +#define GOODIX_VIO_LOAD_MIN_UA 0 +#define GOODIX_VIO_LOAD_MAX_UA 10000 + +#define RESET_DELAY_T3_US 200 /* T3: > 100us */ +#define RESET_DELAY_T4 20 /* T4: > 5ms */ + +#define PHY_BUF_SIZE 32 +#define PROP_NAME_SIZE 24 + +#define GTP_MAX_TOUCH 5 +#define GTP_ESD_CHECK_CIRCLE_MS 2000 + +static void gtp_int_sync(struct goodix_ts_data *ts, int ms); +static int gtp_i2c_test(struct i2c_client *client); +static int goodix_power_off(struct goodix_ts_data *ts); +static int goodix_power_on(struct goodix_ts_data *ts); + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +static int goodix_ts_suspend(struct device *dev); +static int goodix_ts_resume(struct device *dev); +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void goodix_ts_early_suspend(struct early_suspend *h); +static void goodix_ts_late_resume(struct early_suspend *h); +#endif + +#if GTP_ESD_PROTECT +static struct delayed_work gtp_esd_check_work; +static struct workqueue_struct *gtp_esd_check_workqueue; +static void gtp_esd_check_func(struct work_struct *work); +static int gtp_init_ext_watchdog(struct i2c_client *client); +#endif + +enum doze { + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +}; +static enum doze doze_status = DOZE_DISABLED; +static s8 gtp_enter_doze(struct goodix_ts_data *ts); + +bool init_done; +static u8 chip_gt9xxs; /* true if ic is gt9xxs, like gt915s */ +u8 grp_cfg_version; +struct i2c_client *i2c_connect_client; + +#define GTP_DEBUGFS_DIR "ts_debug" +#define GTP_DEBUGFS_FILE_SUSPEND "suspend" +#define GTP_DEBUGFS_FILE_DATA "data" +#define GTP_DEBUGFS_FILE_ADDR "addr" + +/******************************************************* +Function: + Read data from the i2c slave device. +Input: + client: i2c device. + buf[0~1]: read start address. + buf[2~len-1]: read data buffer. + len: GTP_ADDR_LENGTH + read bytes count +Output: + numbers of i2c_msgs to transfer: + 2: succeed, otherwise: failed +*********************************************************/ +int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + int ret = -EIO; + u8 retries; + struct i2c_msg msgs[2] = { + { + .flags = !I2C_M_RD, + .addr = client->addr, + .len = GTP_ADDR_LENGTH, + .buf = &buf[0], + }, + { + .flags = I2C_M_RD, + .addr = client->addr, + .len = len - GTP_ADDR_LENGTH, + .buf = &buf[GTP_ADDR_LENGTH], + }, + }; + + for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) { + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret == 2) + break; + dev_err(&client->dev, "I2C retry: %d\n", retries + 1); + } + if (retries == GTP_I2C_RETRY_5) { + if (ts->pdata->slide_wakeup) + /* reset chip would quit doze mode */ + if (DOZE_ENABLED == doze_status) + return ret; + + if (init_done) + gtp_reset_guitar(ts, 10); + else + dev_warn(&client->dev, + "gtp_reset_guitar exit init_done=%d:\n", + init_done); + } + return ret; +} + +/******************************************************* +Function: + Write data to the i2c slave device. +Input: + client: i2c device. + buf[0~1]: write start address. + buf[2~len-1]: data buffer + len: GTP_ADDR_LENGTH + write bytes count +Output: + numbers of i2c_msgs to transfer: + 1: succeed, otherwise: failed +*********************************************************/ +int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + int ret = -EIO; + u8 retries; + struct i2c_msg msg = { + .flags = !I2C_M_RD, + .addr = client->addr, + .len = len, + .buf = buf, + }; + + for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + break; + dev_err(&client->dev, "I2C retry: %d\n", retries + 1); + } + if ((retries == GTP_I2C_RETRY_5)) { + if (ts->pdata->slide_wakeup) + if (DOZE_ENABLED == doze_status) + return ret; + + if (init_done) + gtp_reset_guitar(ts, 10); + else + dev_warn(&client->dev, + "gtp_reset_guitar exit init_done=%d:\n", + init_done); + } + return ret; +} + +/******************************************************* +Function: + i2c read twice, compare the results +Input: + client: i2c device + addr: operate address + rxbuf: read data to store, if compare successful + len: bytes to read +Output: + FAIL: read failed + SUCCESS: read successful +*********************************************************/ +int gtp_i2c_read_dbl_check(struct i2c_client *client, + u16 addr, u8 *rxbuf, int len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + u8 retry = 0; + + while (retry++ < GTP_I2C_RETRY_3) { + memset(buf, 0xAA, 16); + buf[0] = (u8)(addr >> 8); + buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, buf, len + 2); + + memset(confirm_buf, 0xAB, 16); + confirm_buf[0] = (u8)(addr >> 8); + confirm_buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, confirm_buf, len + 2); + + if (!memcmp(buf, confirm_buf, len + 2)) + break; + } + if (retry < GTP_I2C_RETRY_3) { + memcpy(rxbuf, confirm_buf + 2, len); + return SUCCESS; + } else { + dev_err(&client->dev, + "i2c read 0x%04X, %d bytes, double check failed!", + addr, len); + return FAIL; + } +} + +/******************************************************* +Function: + Send config data. +Input: + client: i2c device. +Output: + result of i2c write operation. + > 0: succeed, otherwise: failed +*********************************************************/ +int gtp_send_cfg(struct goodix_ts_data *ts) +{ + int ret = 0; + int retry; + + if (ts->pdata->driver_send_cfg) { + if (ts->fixed_cfg) { + dev_dbg(&ts->client->dev, + "Ic fixed config, no config sent!"); + ret = 2; + } else { + for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) { + ret = gtp_i2c_write(ts->client, + ts->config_data, + GTP_CONFIG_MAX_LENGTH + + GTP_ADDR_LENGTH); + if (ret > 0) + break; + } + } + } + + return ret; +} + +/******************************************************* +Function: + Disable irq function +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +void gtp_irq_disable(struct goodix_ts_data *ts) +{ + unsigned long irqflags; + + spin_lock_irqsave(&ts->irq_lock, irqflags); + if (!ts->irq_is_disabled) { + ts->irq_is_disabled = true; + disable_irq_nosync(ts->client->irq); + } + spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} + +/******************************************************* +Function: + Enable irq function +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +void gtp_irq_enable(struct goodix_ts_data *ts) +{ + unsigned long irqflags = 0; + + spin_lock_irqsave(&ts->irq_lock, irqflags); + if (ts->irq_is_disabled) { + enable_irq(ts->client->irq); + ts->irq_is_disabled = false; + } + spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} + +/******************************************************* +Function: + Report touch point event +Input: + ts: goodix i2c_client private data + id: trackId + x: input x coordinate + y: input y coordinate + w: input pressure +Output: + None. +*********************************************************/ +static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y, + int w) +{ + if (ts->pdata->change_x2y) + swap(x, y); + + //printk(KERN_ERR"gtp_touch_down---\n"); + + input_mt_slot(ts->input_dev, id); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); +} + +/******************************************************* +Function: + Report touch release event +Input: + ts: goodix i2c_client private data +Output: + None. +*********************************************************/ +static void gtp_touch_up(struct goodix_ts_data *ts, int id) +{ + //printk(KERN_ERR"gtp_touch_up---\n"); + + input_mt_slot(ts->input_dev, id); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); +} + + + +/******************************************************* +Function: + Goodix touchscreen work function +Input: + work: work struct of goodix_workqueue +Output: + None. +*********************************************************/ +static void goodix_ts_work_func(struct work_struct *work) +{ + u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, + GTP_READ_COOR_ADDR & 0xFF, 0}; + u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = { + GTP_READ_COOR_ADDR >> 8, + GTP_READ_COOR_ADDR & 0xFF}; + u8 touch_num = 0; + u8 finger = 0; + static u16 pre_touch; + static u8 pre_key; + static u8 pre_pen; + u8 key_value = 0; + u8 *coor_data = NULL; + s32 input_x = 0; + s32 input_y = 0; + s32 input_w = 0; + s32 id = 0; + s32 i = 0; + int ret = -1; + struct goodix_ts_data *ts = NULL; + u8 doze_buf[3] = {0x81, 0x4B}; + + ts = container_of(work, struct goodix_ts_data, work); +#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE + if (ts->enter_update) + return; +#endif + if (ts->pdata->slide_wakeup) { + if (DOZE_ENABLED == doze_status) { + ret = gtp_i2c_read(ts->client, doze_buf, 3); + if (ret > 0) { + if (doze_buf[2] == 0xAA) { + dev_dbg(&ts->client->dev, + "Slide(0xAA) To Light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key( + ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key( + ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + } else if (doze_buf[2] == 0xBB) { + dev_dbg(&ts->client->dev, + "Slide(0xBB) To Light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, + KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, + KEY_POWER, 0); + input_sync(ts->input_dev); + /* clear 0x814B*/ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + } else if (0xC0 == (doze_buf[2] & 0xC0)) { + dev_dbg(&ts->client->dev, + "double click to light up the screen!"); + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, + KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, + KEY_POWER, 0); + input_sync(ts->input_dev); + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + } else { + gtp_enter_doze(ts); + } + } + if (ts->use_irq) + gtp_irq_enable(ts); + + return; + } + } + + ret = gtp_i2c_read(ts->client, point_data, 12); + + if (ret < 0) { + dev_err(&ts->client->dev, + "I2C transfer error. errno:%d\n ", ret); + goto exit_work_func; + } + + finger = point_data[GTP_ADDR_LENGTH]; + + if ((finger & 0x80) == 0) + goto exit_work_func; + + touch_num = finger & 0x0f; + if (touch_num > GTP_MAX_TOUCH) + goto exit_work_func; + + if (touch_num > 1) { + u8 buf[8 * GTP_MAX_TOUCH] = { (GTP_READ_COOR_ADDR + 10) >> 8, + (GTP_READ_COOR_ADDR + 10) & 0xff }; + + ret = gtp_i2c_read(ts->client, buf, + 2 + 8 * (touch_num - 1)); + memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); + } + + + key_value = point_data[3 + 8 * touch_num]; + + if (key_value || pre_key) { + for (i = 0; i < ts->pdata->num_button; i++) { + input_report_key(ts->input_dev, + ts->pdata->button_map[i], + key_value & (0x01<pdata->with_pen) { + if (pre_pen && (touch_num == 0)) { + dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!"); + input_report_key(ts->input_dev, BTN_TOOL_PEN, 0); + input_mt_slot(ts->input_dev, 5); + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); + pre_pen = 0; + } + } + + if (pre_touch || touch_num) { + s32 pos = 0; + u16 touch_index = 0; + + coor_data = &point_data[3]; + if (touch_num) { + id = coor_data[pos] & 0x0F; + if (ts->pdata->with_pen) { + id = coor_data[pos]; + if (id == 128) { + dev_dbg(&ts->client->dev, + "Pen touch DOWN(Slot)!"); + input_x = coor_data[pos + 1] + | (coor_data[pos + 2] << 8); + input_y = coor_data[pos + 3] + | (coor_data[pos + 4] << 8); + input_w = coor_data[pos + 5] + | (coor_data[pos + 6] << 8); + + input_report_key(ts->input_dev, + BTN_TOOL_PEN, 1); + input_mt_slot(ts->input_dev, 5); + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 5); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, input_x); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, input_y); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, input_w); + dev_dbg(&ts->client->dev, + "Pen/Stylus: (%d, %d)[%d]", + input_x, input_y, input_w); + pre_pen = 1; + pre_touch = 0; + } + } + + touch_index |= (0x01<pdata->with_pen) + if (pre_pen == 1) + break; + + if (touch_index & (0x01<input_dev); + +exit_work_func: + if (!ts->gtp_rawdiff_mode) { + ret = gtp_i2c_write(ts->client, end_cmd, 3); + if (ret < 0) + dev_warn(&ts->client->dev, "I2C write end_cmd error!\n"); + + } + if (ts->use_irq) + gtp_irq_enable(ts); + + return; +} + +/******************************************************* +Function: + External interrupt service routine for interrupt mode. +Input: + irq: interrupt number. + dev_id: private data pointer +Output: + Handle Result. + IRQ_HANDLED: interrupt handled successfully +*********************************************************/ +static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) +{ + struct goodix_ts_data *ts = dev_id; + //printk(KERN_ERR"..........goodix_ts_irq_handler..........\n"); + gtp_irq_disable(ts); + + queue_work(ts->goodix_wq, &ts->work); + + return IRQ_HANDLED; +} +/******************************************************* +Function: + Synchronization. +Input: + ms: synchronization time in millisecond. +Output: + None. +*******************************************************/ +void gtp_int_sync(struct goodix_ts_data *ts, int ms) +{ + gpio_direction_output(ts->pdata->irq_gpio, 0); + msleep(ms); + gpio_direction_input(ts->pdata->irq_gpio); +} + +/******************************************************* +Function: + Reset chip. +Input: + ms: reset time in millisecond, must >10ms +Output: + None. +*******************************************************/ +void gtp_reset_guitar(struct goodix_ts_data *ts, int ms) +{ + /* This reset sequence will selcet I2C slave address */ + gpio_direction_output(ts->pdata->reset_gpio, 0); + msleep(ms); + + if (ts->client->addr == GTP_I2C_ADDRESS_HIGH) + gpio_direction_output(ts->pdata->irq_gpio, 1); + else + gpio_direction_output(ts->pdata->irq_gpio, 0); + + usleep_range(200, 250); + gpio_direction_output(ts->pdata->reset_gpio, 1); + msleep(RESET_DELAY_T4); + + gpio_direction_input(ts->pdata->reset_gpio); + + gtp_int_sync(ts, 50); + +#if GTP_ESD_PROTECT + gtp_init_ext_watchdog(ts->client); +#endif +} + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB) +/******************************************************* +Function: + Enter doze mode for sliding wakeup. +Input: + ts: goodix tp private data +Output: + 1: succeed, otherwise failed +*******************************************************/ +static s8 gtp_enter_doze(struct goodix_ts_data *ts) +{ + int ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = { + (u8)(GTP_REG_SLEEP >> 8), + (u8)GTP_REG_SLEEP, 8}; + + if (ts->pdata->dbl_clk_wakeup) + i2c_control_buf[2] = 0x09; + + gtp_irq_disable(ts); + + while (retry++ < GTP_I2C_RETRY_3) { + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x46; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret < 0) { + dev_err(&ts->client->dev, + "failed to set doze flag into 0x8046, %d", + retry); + continue; + } + i2c_control_buf[0] = 0x80; + i2c_control_buf[1] = 0x40; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) { + doze_status = DOZE_ENABLED; + dev_dbg(&ts->client->dev, + "GTP has been working in doze mode!"); + gtp_irq_enable(ts); + return ret; + } + msleep(20); + } + dev_err(&ts->client->dev, "GTP send doze cmd failed.\n"); + gtp_irq_enable(ts); + return ret; +} +/** + * gtp_enter_sleep - Enter sleep mode + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static u8 gtp_enter_sleep(struct goodix_ts_data *ts) +{ + int ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = { + (u8)(GTP_REG_SLEEP >> 8), + (u8)GTP_REG_SLEEP, 5}; + + ret = gpio_direction_output(ts->pdata->irq_gpio, 0); + if (ret) + dev_err(&ts->client->dev, + "GTP sleep: Cannot reconfig gpio %d.\n", + ts->pdata->irq_gpio); + if (ts->pdata->enable_power_off) { + ret = gpio_direction_output(ts->pdata->reset_gpio, 0); + if (ret) + dev_err(&ts->client->dev, + "GTP sleep: Cannot reconfig gpio %d.\n", + ts->pdata->reset_gpio); + ret = goodix_power_off(ts); + if (ret) { + dev_err(&ts->client->dev, "GTP power off failed.\n"); + return ret; + } + return 0; + } else { + usleep_range(5000, 5500); + while (retry++ < GTP_I2C_RETRY_5) { + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret == 1) { + dev_dbg(&ts->client->dev, "GTP enter sleep!"); + return 0; + } + msleep(20); + } + dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n"); + return ret; + } +} + +/******************************************************* +Function: + Wakeup from sleep. +Input: + ts: private data. +Output: + Executive outcomes. + >0: succeed, otherwise: failed. +*******************************************************/ +static s8 gtp_wakeup_sleep(struct goodix_ts_data *ts) +{ + u8 retry = 0; + s8 ret = -1; + + if (ts->pdata->enable_power_off) { + ret = gpio_direction_output(ts->pdata->irq_gpio, 0); + if (ret) + dev_err(&ts->client->dev, + "GTP wakeup: Cannot reconfig gpio %d.\n", + ts->pdata->irq_gpio); + ret = gpio_direction_output(ts->pdata->reset_gpio, 0); + if (ret) + dev_err(&ts->client->dev, + "GTP wakeup: Cannot reconfig gpio %d.\n", + ts->pdata->reset_gpio); + ret = goodix_power_on(ts); + if (ret) { + dev_err(&ts->client->dev, "GTP power on failed.\n"); + return 0; + } + gtp_reset_guitar(ts, 20); + + ret = gtp_send_cfg(ts); + if (ret <= 0) { + dev_err(&ts->client->dev, + "GTP wakeup sleep failed.\n"); + return ret; + } + + dev_dbg(&ts->client->dev, + "Wakeup sleep send config success."); + } else { +err_retry: + if (ts->pdata->slide_wakeup) { /* wakeup not by slide */ + if (DOZE_WAKEUP != doze_status) + gtp_reset_guitar(ts, 10); + else + /* wakeup by slide */ + doze_status = DOZE_DISABLED; + } else { + if (chip_gt9xxs == 1) { + gtp_reset_guitar(ts, 10); + } else { + ret = gpio_direction_output( + ts->pdata->irq_gpio, 1); + usleep_range(5000, 5500); + } + } + ret = gtp_i2c_test(ts->client); + if (ret == 2) { + dev_dbg(&ts->client->dev, "GTP wakeup sleep."); + if (!ts->pdata->slide_wakeup) { + if (chip_gt9xxs == 0) { + gtp_int_sync(ts, 25); + msleep(20); +#if GTP_ESD_PROTECT + gtp_init_ext_watchdog(ts->client); +#endif + } + } + return ret; + } + gtp_reset_guitar(ts, 20); + if (retry++ < GTP_I2C_RETRY_10) + goto err_retry; + dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n"); + } + return ret; +} +#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/ + +/******************************************************* +Function: + Initialize gtp. +Input: + ts: goodix private data +Output: + Executive outcomes. + > =0: succeed, otherwise: failed +*******************************************************/ +static int gtp_init_panel(struct goodix_ts_data *ts) +{ + struct i2c_client *client = ts->client; + unsigned char *config_data = NULL; + int ret = -EIO; + int i; + u8 check_sum = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + + if (ts->pdata->driver_send_cfg) { + for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) + dev_dbg(&client->dev, "Config Groups(%d) Lengths: %d", + i, ts->pdata->config_data_len[i]); + + ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); + if (SUCCESS == ret) { + if (opr_buf[0] != 0xBE) { + ts->fw_error = 1; + dev_err(&client->dev, + "Firmware error, no config sent!"); + return -EINVAL; + } + } + + for (i = 2; i < GOODIX_MAX_CFG_GROUP; i++) { + if (ts->pdata->config_data_len[i]) + break; + } + + if (i == GOODIX_MAX_CFG_GROUP) { + if (!strcmp(ts->compatiable_id, ts->pdata->product_id1)){ + sensor_id = 1; + } + else{ + sensor_id = 0; + } + } else { + ret = gtp_i2c_read_dbl_check(ts->client, + GTP_REG_SENSOR_ID, &sensor_id, 1); + if (SUCCESS == ret) { + if (sensor_id >= GOODIX_MAX_CFG_GROUP) { + dev_err(&client->dev, + "Invalid sensor_id(0x%02X), No Config Sent!", + sensor_id); + return -EINVAL; + } + } else { + dev_err(&client->dev, + "Failed to get sensor_id, No config sent!"); + return -EINVAL; + } + } + + dev_info(&client->dev, "Sensor ID selected: %d", sensor_id); + + if (ts->pdata->config_data_len[sensor_id] < + GTP_CONFIG_MIN_LENGTH || + !ts->pdata->config_data[sensor_id]) { + dev_err(&client->dev, + "Sensor_ID(%d) matches with NULL or invalid config group!\n", + sensor_id); + return -EINVAL; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + if (opr_buf[0] < 90) { + /* backup group config version */ + grp_cfg_version = + ts->pdata-> + config_data[sensor_id][GTP_ADDR_LENGTH]; + ts->pdata-> + config_data[sensor_id][GTP_ADDR_LENGTH] + = 0x00; + ts->fixed_cfg = 0; + } else { + /* treated as fixed config, not send config */ + dev_warn(&client->dev, + "Ic fixed config with config version(%d, 0x%02X)", + opr_buf[0], opr_buf[0]); + ts->fixed_cfg = 1; + } + } else { + dev_err(&client->dev, + "Failed to get ic config version!No config sent!"); + return -EINVAL; + } + + config_data = ts->pdata->config_data[sensor_id]; + ts->config_data = ts->pdata->config_data[sensor_id]; + ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id]; + +#if GTP_CUSTOM_CFG + config_data[RESOLUTION_LOC] = + (unsigned char)(GTP_MAX_WIDTH && 0xFF); + config_data[RESOLUTION_LOC + 1] = + (unsigned char)(GTP_MAX_WIDTH >> 8); + config_data[RESOLUTION_LOC + 2] = + (unsigned char)(GTP_MAX_HEIGHT && 0xFF); + config_data[RESOLUTION_LOC + 3] = + (unsigned char)(GTP_MAX_HEIGHT >> 8); + + if (GTP_INT_TRIGGER == 0) + config_data[TRIGGER_LOC] &= 0xfe; + else if (GTP_INT_TRIGGER == 1) + config_data[TRIGGER_LOC] |= 0x01; +#endif /* !GTP_CUSTOM_CFG */ + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) + check_sum += config_data[i]; + + config_data[ts->gtp_cfg_len] = (~check_sum) + 1; + + } + else { /* DRIVER NOT SEND CONFIG */ + ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH; + ret = gtp_i2c_read(ts->client, config_data, + ts->gtp_cfg_len + GTP_ADDR_LENGTH); + if (ret < 0) { + dev_err(&client->dev, + "Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n"); + ts->abs_x_max = GTP_MAX_WIDTH; + ts->abs_y_max = GTP_MAX_HEIGHT; + ts->int_trigger_type = GTP_INT_TRIGGER; + } + } /* !DRIVER NOT SEND CONFIG */ + + if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) { + ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8) + + config_data[RESOLUTION_LOC]; + ts->abs_y_max = (config_data[RESOLUTION_LOC + 3] << 8) + + config_data[RESOLUTION_LOC + 2]; + ts->int_trigger_type = (config_data[TRIGGER_LOC]) & 0x03; + } + ret = gtp_send_cfg(ts); + if (ret < 0) + dev_err(&client->dev, "%s: Send config error.\n", __func__); + + msleep(20); + return ret; +} + +/******************************************************* +Function: + Read firmware version +Input: + client: i2c device + version: buffer to keep ic firmware version +Output: + read operation return. + 0: succeed, otherwise: failed +*******************************************************/ +static int gtp_read_fw_version(struct i2c_client *client, u16 *version) +{ + int ret = 0; + u8 buf[GTP_FW_VERSION_BUFFER_MAXSIZE] = { + GTP_REG_FW_VERSION >> 8, GTP_REG_FW_VERSION & 0xff }; + + ret = gtp_i2c_read(client, buf, sizeof(buf)); + if (ret < 0) { + dev_err(&client->dev, "GTP read version failed.\n"); + return -EIO; + } + + if (version) + *version = (buf[3] << 8) | buf[2]; + + return ret; +} +/******************************************************* +Function: + Read and check chip id. +Input: + client: i2c device +Output: + read operation return. + 0: succeed, otherwise: failed +*******************************************************/ +static int gtp_check_product_id(struct i2c_client *client) +{ + int ret = 0; + char product_id[GTP_PRODUCT_ID_MAXSIZE]; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + /* 04 bytes are used for the Product-id in the register space.*/ + u8 buf[GTP_PRODUCT_ID_BUFFER_MAXSIZE] = { + GTP_REG_PRODUCT_ID >> 8, GTP_REG_PRODUCT_ID & 0xff }; + + ret = gtp_i2c_read(client, buf, sizeof(buf)); + if (ret < 0) { + dev_err(&client->dev, "GTP read product_id failed.\n"); + return -EIO; + } + + if (buf[5] == 0x00) { + /* copy (GTP_PRODUCT_ID_MAXSIZE - 1) from buffer. Ex: 915 */ + strlcpy(product_id, &buf[2], GTP_PRODUCT_ID_MAXSIZE - 1); + } else { + if (buf[5] == 'S' || buf[5] == 's') + chip_gt9xxs = 1; + /* copy GTP_PRODUCT_ID_MAXSIZE from buffer. Ex: 915s */ + strlcpy(product_id, &buf[2], GTP_PRODUCT_ID_MAXSIZE); + } + + dev_info(&client->dev, "Goodix Product ID = %s\n", product_id); + strlcpy(ts->compatiable_id, product_id, sizeof(product_id)); + //compatible gt915L + ret = strcmp(product_id, ts->pdata->product_id0); + if (ret != 0){ + if(ts->pdata->product_id1 != 0){ + ret = strcmp(product_id, ts->pdata->product_id1); + if (ret != 0){ + return -EINVAL; + } + }else + return ret; + } + return ret; +} + +/******************************************************* +Function: + I2c test Function. +Input: + client:i2c client. +Output: + Executive outcomes. + 2: succeed, otherwise failed. +*******************************************************/ +static int gtp_i2c_test(struct i2c_client *client) +{ + u8 buf[3] = { GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff }; + int retry = GTP_I2C_RETRY_5; + int ret = -EIO; + + while (retry--) { + ret = gtp_i2c_read(client, buf, 3); + if (ret > 0) + return ret; + dev_err(&client->dev, "GTP i2c test failed time %d.\n", retry); + msleep(20); + } + return ret; +} + +/******************************************************* +Function: + Request gpio(INT & RST) ports. +Input: + ts: private data. +Output: + Executive outcomes. + = 0: succeed, != 0: failed +*******************************************************/ +static int gtp_request_io_port(struct goodix_ts_data *ts) +{ + struct i2c_client *client = ts->client; + struct goodix_ts_platform_data *pdata = ts->pdata; + int ret; + + if (gpio_is_valid(pdata->irq_gpio)) { + ret = gpio_request(pdata->irq_gpio, "goodix_ts_irq_gpio"); + if (ret) { + dev_err(&client->dev, "Unable to request irq gpio [%d]\n", + pdata->irq_gpio); + goto err_pwr_off; + } + ret = gpio_direction_input(pdata->irq_gpio); + ts->client->irq = gpio_to_irq(pdata->irq_gpio); + if (ret) { + dev_err(&client->dev, "Unable to set direction for irq gpio [%d]\n", + pdata->irq_gpio); + goto err_free_irq_gpio; + } + } else { + dev_err(&client->dev, "Invalid irq gpio [%d]!\n", + pdata->irq_gpio); + ret = -EINVAL; + goto err_pwr_off; + } + + if (gpio_is_valid(pdata->reset_gpio)) { + ret = gpio_request(pdata->reset_gpio, "goodix_ts_reset_gpio"); + if (ret) { + dev_err(&client->dev, "Unable to request reset gpio [%d]\n", + pdata->reset_gpio); + goto err_free_irq_gpio; + } + + ret = gpio_direction_output(pdata->reset_gpio, 0); + if (ret) { + dev_err(&client->dev, "Unable to set direction for reset gpio [%d]\n", + pdata->reset_gpio); + goto err_free_reset_gpio; + } + } else { + dev_err(&client->dev, "Invalid irq gpio [%d]!\n", + pdata->reset_gpio); + ret = -EINVAL; + goto err_free_irq_gpio; + } + /* IRQ GPIO is an input signal, but we are setting it to output + * direction and pulling it down, to comply with power up timing + * requirements, mentioned in power up timing section of device + * datasheet. + */ + ret = gpio_direction_output(pdata->irq_gpio, 0); + if (ret) + dev_warn(&client->dev, + "pull down interrupt gpio failed\n"); + ret = gpio_direction_output(pdata->reset_gpio, 0); + if (ret) + dev_warn(&client->dev, + "pull down reset gpio failed\n"); + + return ret; + +err_free_reset_gpio: + if (gpio_is_valid(pdata->reset_gpio)) + gpio_free(pdata->reset_gpio); +err_free_irq_gpio: + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); +err_pwr_off: + return ret; +} + +/******************************************************* +Function: + Request interrupt. +Input: + ts: private data. +Output: + Executive outcomes. + 0: succeed, -1: failed. +*******************************************************/ +static int gtp_request_irq(struct goodix_ts_data *ts) +{ + int ret = 0; + //const u8 irq_table[] = GTP_IRQ_TAB;//irq_table[ts->int_trigger_type],ts->pdata->irq_gpio_flags + + ret = request_threaded_irq(ts->client->irq, NULL, + goodix_ts_irq_handler, + ts->pdata->irq_gpio_flags, + ts->client->name, ts); + if (ret) { + ts->use_irq = false; + return ret; + } else { + gtp_irq_disable(ts); + ts->use_irq = true; + return ret; + } +} + +/******************************************************* +Function: + Request input device Function. +Input: + ts:private data. +Output: + Executive outcomes. + 0: succeed, otherwise: failed. +*******************************************************/ +static int gtp_request_input_dev(struct goodix_ts_data *ts) +{ + int ret; + char phys[PHY_BUF_SIZE]; + int index = 0; + + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + dev_err(&ts->client->dev, + "Failed to allocate input device.\n"); + return -ENOMEM; + } + + ts->input_dev->evbit[0] = + BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ; + set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + /* in case of "out of memory" */ + input_mt_init_slots(ts->input_dev, 10, 0); + + if (ts->pdata->have_touch_key) { + for (index = 0; index < ts->pdata->num_button; index++) { + input_set_capability(ts->input_dev, + EV_KEY, ts->pdata->button_map[index]); + } + } + + if (ts->pdata->slide_wakeup) + input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); + + if (ts->pdata->with_pen) { /* pen support */ + __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit); + } + + if (ts->pdata->change_x2y) + swap(ts->abs_x_max, ts->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, + 0, ts->abs_x_max, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, + 0, ts->abs_y_max, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, + 0, 255, 0, 0); + + snprintf(phys, PHY_BUF_SIZE, "input/ts"); + ts->input_dev->name = GOODIX_DEV_NAME; + if(strcmp(ts->client->name,"gt9xx")==0) + ts->input_dev->name = "TouchScreenMain"; + if(strcmp(ts->client->name,"gt9xx_2")==0) + ts->input_dev->name = "TouchScreenSub"; + ts->input_dev->phys = phys; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0xDEAD; + ts->input_dev->id.product = 0xBEEF; + ts->input_dev->id.version = 10427; + + ret = input_register_device(ts->input_dev); + if (ret) { + dev_err(&ts->client->dev, + "Register %s input device failed.\n", + ts->input_dev->name); + goto exit_free_inputdev; + } + + return 0; + +exit_free_inputdev: + input_free_device(ts->input_dev); + ts->input_dev = NULL; + return ret; +} + +static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA) +{ + return (regulator_count_voltages(reg) > 0) ? + regulator_set_optimum_mode(reg, load_uA) : 0; +} + +/** + * goodix_power_on - Turn device power ON + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int goodix_power_on(struct goodix_ts_data *ts) +{ + int ret; + + if (ts->power_on) { + dev_info(&ts->client->dev, + "Device already power on\n"); + return 0; + } + + if (!IS_ERR(ts->avdd)) { + ret = reg_set_optimum_mode_check(ts->avdd, + GOODIX_VDD_LOAD_MAX_UA); + if (ret < 0) { + dev_err(&ts->client->dev, + "Regulator avdd set_opt failed rc=%d\n", ret); + goto err_set_opt_avdd; + } + ret = regulator_enable(ts->avdd); + if (ret) { + dev_err(&ts->client->dev, + "Regulator avdd enable failed ret=%d\n", ret); + goto err_enable_avdd; + } + } + + if (!IS_ERR(ts->vdd)) { + ret = regulator_set_voltage(ts->vdd, GOODIX_VTG_MIN_UV, + GOODIX_VTG_MAX_UV); + if (ret) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vdd ret=%d\n", ret); + goto err_set_vtg_vdd; + } + ret = reg_set_optimum_mode_check(ts->vdd, + GOODIX_VDD_LOAD_MAX_UA); + if (ret < 0) { + dev_err(&ts->client->dev, + "Regulator vdd set_opt failed rc=%d\n", ret); + goto err_set_opt_vdd; + } + ret = regulator_enable(ts->vdd); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vdd enable failed ret=%d\n", ret); + goto err_enable_vdd; + } + } + + if (!IS_ERR(ts->vcc_i2c)) { + ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV, + GOODIX_I2C_VTG_MAX_UV); + if (ret) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vcc_i2c ret=%d\n", + ret); + goto err_set_vtg_vcc_i2c; + } + ret = reg_set_optimum_mode_check(ts->vcc_i2c, + GOODIX_VIO_LOAD_MAX_UA); + if (ret < 0) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c set_opt failed rc=%d\n", + ret); + goto err_set_opt_vcc_i2c; + } + ret = regulator_enable(ts->vcc_i2c); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c enable failed ret=%d\n", + ret); + regulator_disable(ts->vdd); + goto err_enable_vcc_i2c; + } + } + + ts->power_on = true; + return 0; + +err_enable_vcc_i2c: +err_set_opt_vcc_i2c: + if (!IS_ERR(ts->vcc_i2c)) + regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV); +err_set_vtg_vcc_i2c: + if (!IS_ERR(ts->vdd)) + regulator_disable(ts->vdd); +err_enable_vdd: +err_set_opt_vdd: + if (!IS_ERR(ts->vdd)) + regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV); +err_set_vtg_vdd: + if (!IS_ERR(ts->avdd)) + regulator_disable(ts->avdd); +err_enable_avdd: +err_set_opt_avdd: + ts->power_on = false; + return ret; +} + +/** + * goodix_power_off - Turn device power OFF + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int goodix_power_off(struct goodix_ts_data *ts) +{ + int ret; + + if (!ts->power_on) { + dev_info(&ts->client->dev, + "Device already power off\n"); + return 0; + } + + if (!IS_ERR(ts->vcc_i2c)) { + ret = regulator_set_voltage(ts->vcc_i2c, 0, + GOODIX_I2C_VTG_MAX_UV); + if (ret < 0) + dev_err(&ts->client->dev, + "Regulator vcc_i2c set_vtg failed ret=%d\n", + ret); + ret = regulator_disable(ts->vcc_i2c); + if (ret) + dev_err(&ts->client->dev, + "Regulator vcc_i2c disable failed ret=%d\n", + ret); + } + + if (!IS_ERR(ts->vdd)) { + ret = regulator_set_voltage(ts->vdd, 0, GOODIX_VTG_MAX_UV); + if (ret < 0) + dev_err(&ts->client->dev, + "Regulator vdd set_vtg failed ret=%d\n", ret); + ret = regulator_disable(ts->vdd); + if (ret) + dev_err(&ts->client->dev, + "Regulator vdd disable failed ret=%d\n", ret); + } + + if (!IS_ERR(ts->avdd)) { + ret = regulator_disable(ts->avdd); + if (ret) + dev_err(&ts->client->dev, + "Regulator avdd disable failed ret=%d\n", ret); + } + + ts->power_on = false; + return 0; +} + +/** + * goodix_power_init - Initialize device power + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int goodix_power_init(struct goodix_ts_data *ts) +{ + int ret; + + ts->avdd = regulator_get(&ts->client->dev, "avdd"); + if (IS_ERR(ts->avdd)) { + ret = PTR_ERR(ts->avdd); + dev_info(&ts->client->dev, + "Regulator get failed avdd ret=%d\n", ret); + } + + ts->vdd = regulator_get(&ts->client->dev, "vdd"); + if (IS_ERR(ts->vdd)) { + ret = PTR_ERR(ts->vdd); + dev_info(&ts->client->dev, + "Regulator get failed vdd ret=%d\n", ret); + } + + ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c"); + if (IS_ERR(ts->vcc_i2c)) { + ret = PTR_ERR(ts->vcc_i2c); + dev_info(&ts->client->dev, + "Regulator get failed vcc_i2c ret=%d\n", ret); + } + + return 0; +} + +/** + * goodix_power_deinit - Deinitialize device power + * @ts: driver private data + * + * Returns zero on success, else an error. + */ +static int goodix_power_deinit(struct goodix_ts_data *ts) +{ + regulator_put(ts->vdd); + regulator_put(ts->vcc_i2c); + regulator_put(ts->avdd); + + return 0; +} + +static ssize_t gtp_fw_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + + if (!strlen(ts->fw_name)) + return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1, + "No fw name has been given."); + else + return snprintf(buf, GTP_FW_NAME_MAXSIZE - 1, + "%s\n", ts->fw_name); +} + +static ssize_t gtp_fw_name_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + + if (size > GTP_FW_NAME_MAXSIZE - 1) { + dev_err(dev, "FW name size exceeds the limit."); + return -EINVAL; + } + + strlcpy(ts->fw_name, buf, size); + if (ts->fw_name[size-1] == '\n') + ts->fw_name[size-1] = '\0'; + + return size; +} + +static ssize_t gtp_fw_upgrade_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + return snprintf(buf, 2, "%d\n", ts->fw_loading); +} + +static ssize_t gtp_fw_upgrade_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (size > 2) + return -EINVAL; + + if (sscanf(buf, "%u", &val) != 1) + return -EINVAL; + + if (ts->gtp_is_suspend) { + dev_err(&ts->client->dev, + "Can't start fw upgrade. Device is in suspend state."); + return -EBUSY; + } + + mutex_lock(&ts->input_dev->mutex); + if (!ts->fw_loading && val) { + disable_irq(ts->client->irq); + ts->fw_loading = true; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_update_proc(NULL); + if (ret == FAIL) + dev_err(&ts->client->dev, + "Fail to update GTP firmware.\n"); + } + ts->fw_loading = false; + enable_irq(ts->client->irq); + } + mutex_unlock(&ts->input_dev->mutex); + + return size; +} + +static ssize_t gtp_force_fw_upgrade_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (size > 2) + return -EINVAL; + + if (sscanf(buf, "%u", &val) != 1) + return -EINVAL; + + if (ts->gtp_is_suspend) { + dev_err(&ts->client->dev, + "Can't start fw upgrade. Device is in suspend state."); + return -EBUSY; + } + + mutex_lock(&ts->input_dev->mutex); + if (!ts->fw_loading && val) { + disable_irq(ts->client->irq); + ts->fw_loading = true; + ts->force_update = true; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_update_proc(NULL); + if (ret == FAIL) + dev_err(&ts->client->dev, + "Fail to force update GTP firmware.\n"); + } + ts->force_update = false; + ts->fw_loading = false; + enable_irq(ts->client->irq); + } + mutex_unlock(&ts->input_dev->mutex); + + return size; +} + +static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP), + gtp_fw_name_show, + gtp_fw_name_store); +static DEVICE_ATTR(fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), + gtp_fw_upgrade_show, + gtp_fw_upgrade_store); +static DEVICE_ATTR(force_fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), + gtp_fw_upgrade_show, + gtp_force_fw_upgrade_store); + +static struct attribute *gtp_attrs[] = { + &dev_attr_fw_name.attr, + &dev_attr_fw_upgrade.attr, + &dev_attr_force_fw_upgrade.attr, + NULL +}; + +static const struct attribute_group gtp_attr_grp = { + .attrs = gtp_attrs, +}; + +static int gtp_debug_addr_is_valid(u16 addr) +{ + if (addr < GTP_VALID_ADDR_START || addr > GTP_VALID_ADDR_END) { + pr_err("GTP reg address is invalid: 0x%x\n", addr); + return false; + } + + return true; +} + +static int gtp_debug_data_set(void *_data, u64 val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + if (gtp_debug_addr_is_valid(ts->addr)) + dev_err(&ts->client->dev, + "Writing to GTP registers not supported.\n"); + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +static int gtp_debug_data_get(void *_data, u64 *val) +{ + struct goodix_ts_data *ts = _data; + int ret; + u8 buf[3] = {0}; + + mutex_lock(&ts->input_dev->mutex); + buf[0] = ts->addr >> 8; + buf[1] = ts->addr & 0x00ff; + + if (gtp_debug_addr_is_valid(ts->addr)) { + ret = gtp_i2c_read(ts->client, buf, 3); + if (ret < 0) + dev_err(&ts->client->dev, + "GTP read register 0x%x failed (%d)\n", + ts->addr, ret); + else + *val = buf[2]; + } + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, gtp_debug_data_get, + gtp_debug_data_set, "%llx\n"); + +static int gtp_debug_addr_set(void *_data, u64 val) +{ + struct goodix_ts_data *ts = _data; + + if (gtp_debug_addr_is_valid(val)) { + mutex_lock(&ts->input_dev->mutex); + ts->addr = val; + mutex_unlock(&ts->input_dev->mutex); + } + + return 0; +} + +static int gtp_debug_addr_get(void *_data, u64 *val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + if (gtp_debug_addr_is_valid(ts->addr)) + *val = ts->addr; + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, gtp_debug_addr_get, + gtp_debug_addr_set, "%llx\n"); + +static int gtp_debug_suspend_set(void *_data, u64 val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + if (val) + goodix_ts_suspend(&ts->client->dev); + else + goodix_ts_resume(&ts->client->dev); + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +static int gtp_debug_suspend_get(void *_data, u64 *val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + *val = ts->gtp_is_suspend; + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, gtp_debug_suspend_get, + gtp_debug_suspend_set, "%lld\n"); + +static int gtp_debugfs_init(struct goodix_ts_data *data) +{ + data->debug_base = debugfs_create_dir(GTP_DEBUGFS_DIR, NULL); + + if (IS_ERR_OR_NULL(data->debug_base)) { + dev_err(&data->client->dev, "Failed to create debugfs dir.\n"); + return -EINVAL; + } + + if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_SUSPEND, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + data->debug_base, + data, + &debug_suspend_fops)))) { + dev_err(&data->client->dev, "Failed to create suspend file.\n"); + debugfs_remove_recursive(data->debug_base); + return -EINVAL; + } + + if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_DATA, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + data->debug_base, + data, + &debug_data_fops)))) { + dev_err(&data->client->dev, "Failed to create data file.\n"); + debugfs_remove_recursive(data->debug_base); + return -EINVAL; + } + + if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_ADDR, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + data->debug_base, + data, + &debug_addr_fops)))) { + dev_err(&data->client->dev, "Failed to create addr file.\n"); + debugfs_remove_recursive(data->debug_base); + return -EINVAL; + } + + return 0; +} + +static int goodix_ts_get_dt_coords(struct device *dev, char *name, + struct goodix_ts_platform_data *pdata) +{ + struct property *prop; + struct device_node *np = dev->of_node; + int rc; + u32 coords[GOODIX_COORDS_ARR_SIZE]; + + prop = of_find_property(np, name, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + rc = of_property_read_u32_array(np, name, coords, + GOODIX_COORDS_ARR_SIZE); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read %s\n", name); + return rc; + } + + if (!strcmp(name, "goodix,panel-coords")) { + pdata->panel_minx = coords[0]; + pdata->panel_miny = coords[1]; + pdata->panel_maxx = coords[2]; + pdata->panel_maxy = coords[3]; + } else if (!strcmp(name, "goodix,display-coords")) { + pdata->x_min = coords[0]; + pdata->y_min = coords[1]; + pdata->x_max = coords[2]; + pdata->y_max = coords[3]; + } else { + dev_err(dev, "unsupported property %s\n", name); + return -EINVAL; + } + + return 0; +} + +static int goodix_parse_dt(struct device *dev, + struct goodix_ts_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + struct property *prop; + u32 temp_val, num_buttons; + u32 button_map[MAX_BUTTONS]; + char prop_name[PROP_NAME_SIZE]; + int i, read_cfg_num; + + rc = goodix_ts_get_dt_coords(dev, "goodix,panel-coords", pdata); + if (rc && (rc != -EINVAL)) + return rc; + + rc = goodix_ts_get_dt_coords(dev, "goodix,display-coords", pdata); + if (rc) + return rc; + + pdata->i2c_pull_up = of_property_read_bool(np, + "goodix,i2c-pull-up"); + + pdata->force_update = of_property_read_bool(np, + "goodix,force-update"); + + pdata->enable_power_off = of_property_read_bool(np, + "goodix,enable-power-off"); + + pdata->have_touch_key = of_property_read_bool(np, + "goodix,have-touch-key"); + + pdata->driver_send_cfg = of_property_read_bool(np, + "goodix,driver-send-cfg"); + + pdata->change_x2y = of_property_read_bool(np, + "goodix,change-x2y"); + + pdata->with_pen = of_property_read_bool(np, + "goodix,with-pen"); + + pdata->slide_wakeup = of_property_read_bool(np, + "goodix,slide-wakeup"); + + pdata->dbl_clk_wakeup = of_property_read_bool(np, + "goodix,dbl_clk_wakeup"); + + /* reset, irq gpio info */ + pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", + 0, &pdata->reset_gpio_flags); + if (pdata->reset_gpio < 0) + return pdata->reset_gpio; + + pdata->irq_gpio = of_get_named_gpio_flags(np, "interrupt-gpios", + 0, &pdata->irq_gpio_flags); + if (pdata->irq_gpio < 0) + return pdata->irq_gpio; + + printk(KERN_ERR"goodix_parse_dt pdata->irq_gpio=%d,pdata->irq_gpio_flags=%d\n",pdata->irq_gpio,pdata->irq_gpio_flags); + rc = of_property_read_string(np, "goodix,product-id0", + &pdata->product_id0); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Failed to parse product_id0."); + return -EINVAL; + } + + rc = of_property_read_string(np, "goodix,product-id1", + &pdata->product_id1); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Failed to parse product_id1."); + return -EINVAL; + } + + rc = of_property_read_string(np, "goodix,fw_name", + &pdata->fw_name); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Failed to parse firmware name.\n"); + return -EINVAL; + } + + prop = of_find_property(np, "goodix,button-map", NULL); + if (prop) { + num_buttons = prop->length / sizeof(temp_val); + if (num_buttons > MAX_BUTTONS) + return -EINVAL; + + rc = of_property_read_u32_array(np, + "goodix,button-map", button_map, + num_buttons); + if (rc) { + dev_err(dev, "Unable to read key codes\n"); + return rc; + } + pdata->num_button = num_buttons; + memcpy(pdata->button_map, button_map, + pdata->num_button * sizeof(u32)); + } + + read_cfg_num = 0; + for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) { + snprintf(prop_name, sizeof(prop_name), "goodix,cfg-data%d", i); + prop = of_find_property(np, prop_name, + &pdata->config_data_len[i]); + if (!prop || !prop->value) { + pdata->config_data_len[i] = 0; + pdata->config_data[i] = NULL; + continue; + } + pdata->config_data[i] = devm_kzalloc(dev, + GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!pdata->config_data[i]) { + dev_err(dev, + "Not enough memory for panel config data %d\n", + i); + return -ENOMEM; + } + pdata->config_data[i][0] = GTP_REG_CONFIG_DATA >> 8; + pdata->config_data[i][1] = GTP_REG_CONFIG_DATA & 0xff; + memcpy(&pdata->config_data[i][GTP_ADDR_LENGTH], + prop->value, pdata->config_data_len[i]); + read_cfg_num++; + } + dev_dbg(dev, "%d config data read from device tree.\n", read_cfg_num); + + return 0; +} + +#if 1 +static int goodix_ts_pinctrl_init(struct goodix_ts_data *ts) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); + if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { + retval = PTR_ERR(ts->ts_pinctrl); + dev_dbg(&ts->client->dev, + "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + ts->pinctrl_state_active + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { + retval = PTR_ERR(ts->pinctrl_state_active); + dev_err(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + ts->pinctrl_state_suspend + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { + retval = PTR_ERR(ts->pinctrl_state_suspend); + dev_err(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + ts->pinctrl_state_release + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + retval = PTR_ERR(ts->pinctrl_state_release); + dev_dbg(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts->ts_pinctrl); +err_pinctrl_get: + ts->ts_pinctrl = NULL; + return retval; +} +#endif + +/******************************************************* +Function: + I2c probe. +Input: + client: i2c device struct. + id: device id. +Output: + Executive outcomes. + 0: succeed. +*******************************************************/ + +static int goodix_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct goodix_ts_platform_data *pdata; + struct goodix_ts_data *ts; + u16 version_info; + int ret; + int sys_success_flag = 0; + printk(KERN_ERR "eliot 2222goodix_ts_probe name = %s\n",client->name); + dev_dbg(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct goodix_ts_platform_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, + "GTP Failed to allocate memory for pdata\n"); + return -ENOMEM; + } + + ret = goodix_parse_dt(&client->dev, pdata); + if (ret) + return ret; + } else { + pdata = client->dev.platform_data; + } + + if (!pdata) { + dev_err(&client->dev, "GTP invalid pdata\n"); + return -EINVAL; + } + + i2c_connect_client = client; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "GTP I2C not supported\n"); + return -ENODEV; + } + + ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) { + dev_err(&client->dev, "GTP not enough memory for ts\n"); + return -ENOMEM; + } + + memset(ts, 0, sizeof(*ts)); + ts->client = client; + ts->pdata = pdata; + /* For 2.6.39 & later use spin_lock_init(&ts->irq_lock) + * For 2.6.39 & before, use ts->irq_lock = SPIN_LOCK_UNLOCKED + */ + spin_lock_init(&ts->irq_lock); + i2c_set_clientdata(client, ts); + ts->gtp_rawdiff_mode = 0; + ts->power_on = false; + + ret = gtp_request_io_port(ts); + if (ret) { + dev_err(&client->dev, "GTP request IO port failed.\n"); + goto exit_free_client_data; + } + + ret = goodix_power_init(ts); + if (ret) { + dev_err(&client->dev, "GTP power init failed\n"); + goto exit_free_io_port; + } + + ret = goodix_power_on(ts); + if (ret) { + dev_err(&client->dev, "GTP power on failed\n"); + goto exit_deinit_power; + } + +#if 1 + if(strcmp(client->name,"gt9xx")==0) + { + printk(KERN_ERR "2222goodix_ts_probe name = %s\n",client->name); + ret = goodix_ts_pinctrl_init(ts); + + if (!ret && ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) { + dev_err(&client->dev, + "failed to select pin to active state"); + goto exit_power_off; + } + } else { + goto exit_power_off; + } + }else + { + printk(KERN_ERR "1111goodix_ts_probe name = %s\n",client->name); + ts->ts_pinctrl = NULL ; + } +#endif + + gtp_reset_guitar(ts, 20); + + ret = gtp_i2c_test(client); + if (ret != 2) { + dev_err(&client->dev, "I2C communication ERROR!\n"); + goto exit_power_off; + } + + if (pdata->force_update) + ts->force_update = true; + + ret = gtp_check_product_id(client); + if (ret != 0) { + dev_err(&client->dev, "GTP Product id doesn't match.\n"); + goto exit_free_irq; + } + +#if 0//modified by lidan for shutdown charging + if (pdata->fw_name) + strlcpy(ts->fw_name, pdata->fw_name, + strlen(pdata->fw_name) + 1); + + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_init_update_proc(ts); + if (ret < 0) { + dev_err(&client->dev, + "GTP Create firmware update thread error.\n"); + goto exit_power_off; + } + } +#endif + ret = gtp_init_panel(ts); + if (ret < 0) { + dev_err(&client->dev, "GTP init panel failed.\n"); + ts->abs_x_max = GTP_MAX_WIDTH; + ts->abs_y_max = GTP_MAX_HEIGHT; + ts->int_trigger_type = GTP_INT_TRIGGER; + } + + ret = gtp_request_input_dev(ts); + if (ret) { + dev_err(&client->dev, "GTP request input dev failed.\n"); + goto exit_free_inputdev; + } + input_set_drvdata(ts->input_dev, ts); + + mutex_init(&ts->lock); +#if defined(CONFIG_FB) + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if (ret) + dev_err(&ts->client->dev, + "Unable to register fb_notifier: %d\n", + ret); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = goodix_ts_early_suspend; + ts->early_suspend.resume = goodix_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + ts->goodix_wq = create_singlethread_workqueue("goodix_wq"); + INIT_WORK(&ts->work, goodix_ts_work_func); + + ret = gtp_request_irq(ts); + if (ret) + dev_info(&client->dev, "GTP request irq failed %d.\n", ret); + else + dev_info(&client->dev, "GTP works in interrupt mode.\n"); + + ret = gtp_read_fw_version(client, &version_info); + if (ret != 2) + dev_err(&client->dev, "GTP firmware version read failed.\n"); + + + if (ts->use_irq) + gtp_irq_enable(ts); + +#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG + init_wr_node(client); +#endif + +#if GTP_ESD_PROTECT + gtp_esd_switch(client, SWITCH_ON); +#endif + ret = sysfs_create_group(&client->dev.kobj, >p_attr_grp); + if (ret < 0) { + dev_err(&client->dev, "sys file creation failed.\n"); + goto exit_free_irq; + } + + sys_success_flag = 1; + if(strcmp(client->name,"gt9xx")==0) + { + ret = gtp_debugfs_init(ts); + if (ret != 0) { + dev_err(&client->dev, "Failed to create debugfs entries, %d\n", + ret); + goto exit_remove_sysfs; + } + } + + init_done = true; + return 0; +exit_free_irq: + mutex_destroy(&ts->lock); +#if defined(CONFIG_FB) + if (fb_unregister_client(&ts->fb_notif)) + dev_err(&client->dev, + "Error occurred while unregistering fb_notifier.\n"); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + if (ts->use_irq) + free_irq(client->irq, ts); + cancel_work_sync(&ts->work); + flush_workqueue(ts->goodix_wq); + destroy_workqueue(ts->goodix_wq); + + input_unregister_device(ts->input_dev); + if (ts->input_dev) { + input_free_device(ts->input_dev); + ts->input_dev = NULL; + } +exit_remove_sysfs: + if (sys_success_flag) + sysfs_remove_group(&ts->input_dev->dev.kobj, >p_attr_grp); +exit_free_inputdev: + if (ts->config_data) + kfree(ts->config_data); +exit_power_off: + goodix_power_off(ts); +exit_deinit_power: + goodix_power_deinit(ts); +exit_free_io_port: + if (gpio_is_valid(pdata->reset_gpio)) + gpio_free(pdata->reset_gpio); + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); +exit_free_client_data: + i2c_set_clientdata(client, NULL); + return ret; +} + +/******************************************************* +Function: + Goodix touchscreen driver release function. +Input: + client: i2c device struct. +Output: + Executive outcomes. 0---succeed. +*******************************************************/ +static int goodix_ts_remove(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + sysfs_remove_group(&ts->input_dev->dev.kobj, >p_attr_grp); + +#if defined(CONFIG_FB) + if (fb_unregister_client(&ts->fb_notif)) + dev_err(&client->dev, + "Error occurred while unregistering fb_notifier.\n"); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + mutex_destroy(&ts->lock); + +#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG + uninit_wr_node(); +#endif + +#if GTP_ESD_PROTECT + cancel_work_sync(gtp_esd_check_workqueue); + flush_workqueue(gtp_esd_check_workqueue); + destroy_workqueue(gtp_esd_check_workqueue); +#endif + + if (ts) { + if (ts->use_irq) + free_irq(client->irq, ts); + + cancel_work_sync(&ts->work); + flush_workqueue(ts->goodix_wq); + destroy_workqueue(ts->goodix_wq); + + input_unregister_device(ts->input_dev); + if (ts->input_dev) { + input_free_device(ts->input_dev); + ts->input_dev = NULL; + } + + if (gpio_is_valid(ts->pdata->reset_gpio)) + gpio_free(ts->pdata->reset_gpio); + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); + + goodix_power_off(ts); + goodix_power_deinit(ts); + i2c_set_clientdata(client, NULL); + } + debugfs_remove_recursive(ts->debug_base); + + return 0; +} + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_FB) +/******************************************************* +Function: + Early suspend function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static int goodix_ts_suspend(struct device *dev) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + int ret = 0, i; + + if (ts->gtp_is_suspend) { + dev_dbg(&ts->client->dev, "Already in suspend state.\n"); + return 0; + } + + mutex_lock(&ts->lock); + + if (ts->fw_loading) { + dev_info(&ts->client->dev, + "Fw upgrade in progress, can't go to suspend."); + mutex_unlock(&ts->lock); + return 0; + } + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_suspend); + if (ret < 0) + dev_dbg(&ts->client->dev, "failed to select pin to suspend state"); + } +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_OFF); +#endif + + if (ts->pdata->slide_wakeup) { + ret = gtp_enter_doze(ts); + } else { + if (ts->use_irq) + gtp_irq_disable(ts); + + for (i = 0; i < GTP_MAX_TOUCH; i++) + gtp_touch_up(ts, i); + + input_sync(ts->input_dev); + + ret = gtp_enter_sleep(ts); + if (ret < 0) + dev_err(&ts->client->dev, "GTP early suspend failed.\n"); + } + /* to avoid waking up while not sleeping, + * delay 48 + 10ms to ensure reliability + */ + msleep(58); + mutex_unlock(&ts->lock); + ts->gtp_is_suspend = 1; + + return ret; +} + +/******************************************************* +Function: + Late resume function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static int goodix_ts_resume(struct device *dev) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + int ret = 0; + + if (!ts->gtp_is_suspend) { + dev_dbg(&ts->client->dev, "Already in awake state.\n"); + return 0; + } + mutex_lock(&ts->lock); + ret = gtp_wakeup_sleep(ts); + + if (ts->pdata->slide_wakeup) + doze_status = DOZE_DISABLED; + + if (ret <= 0) + dev_err(&ts->client->dev, "GTP resume failed.\n"); + + if (ts->use_irq) + gtp_irq_enable(ts); + + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) + dev_dbg(&ts->client->dev, "failed to select pin to active state"); + } + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_ON); +#endif + mutex_unlock(&ts->lock); + ts->gtp_is_suspend = 0; + + return ret; +} + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct goodix_ts_data *ts = + container_of(self, struct goodix_ts_data, fb_notif); + + if (evdata && evdata->data && event == FB_EVENT_BLANK && + ts && ts->client) { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK) + goodix_ts_resume(&ts->client->dev); + else if (*blank == FB_BLANK_POWERDOWN) + goodix_ts_suspend(&ts->client->dev); + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) +/******************************************************* +Function: + Early suspend function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static void goodix_ts_early_suspend(struct early_suspend *h) +{ + struct goodix_ts_data *ts; + + ts = container_of(h, struct goodix_ts_data, early_suspend); + goodix_ts_suspend(&ts->client->dev); + return; +} + +/******************************************************* +Function: + Late resume function. +Input: + h: early_suspend struct. +Output: + None. +*******************************************************/ +static void goodix_ts_late_resume(struct early_suspend *h) +{ + struct goodix_ts_data *ts; + + ts = container_of(h, struct goodix_ts_data, early_suspend); + goodix_ts_late_resume(ts); + return; +} +#endif +#endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/ + +#if GTP_ESD_PROTECT +/******************************************************* +Function: + switch on & off esd delayed work +Input: + client: i2c device + on: SWITCH_ON / SWITCH_OFF +Output: + void +*********************************************************/ +void gtp_esd_switch(struct i2c_client *client, int on) +{ + struct goodix_ts_data *ts; + + ts = i2c_get_clientdata(client); + if (SWITCH_ON == on) { + /* switch on esd */ + if (!ts->esd_running) { + ts->esd_running = 1; + dev_dbg(&client->dev, "Esd started\n"); + queue_delayed_work(gtp_esd_check_workqueue, + >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); + } + } else { + /* switch off esd */ + if (ts->esd_running) { + ts->esd_running = 0; + dev_dbg(&client->dev, "Esd cancelled\n"); + cancel_delayed_work_sync(>p_esd_check_work); + } + } +} + +/******************************************************* +Function: + Initialize external watchdog for esd protect +Input: + client: i2c device. +Output: + result of i2c write operation. + 1: succeed, otherwise: failed +*********************************************************/ +static int gtp_init_ext_watchdog(struct i2c_client *client) +{ + /* in case of recursively reset by calling gtp_i2c_write*/ + struct i2c_msg msg; + u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA}; + int ret; + int retries = 0; + + msg.flags = !I2C_M_RD; + msg.addr = client->addr; + msg.len = 4; + msg.buf = opr_buffer; + + while (retries < GTP_I2C_RETRY_5) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + return 1; + retries++; + } + if (retries == GTP_I2C_RETRY_5) + dev_err(&client->dev, "init external watchdog failed!"); + return 0; +} + +/******************************************************* +Function: + Esd protect function. + Added external watchdog by meta, 2013/03/07 +Input: + work: delayed work +Output: + None. +*******************************************************/ +static void gtp_esd_check_func(struct work_struct *work) +{ + s32 retry; + s32 ret = -1; + struct goodix_ts_data *ts = NULL; + u8 test[4] = {0x80, 0x40}; + + ts = i2c_get_clientdata(i2c_connect_client); + + if (ts->gtp_is_suspend) { + dev_dbg(&ts->client->dev, "Esd terminated!\n"); + ts->esd_running = 0; + return; + } +#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE + if (ts->enter_update) + return; +#endif + + for (retry = 0; retry < GTP_I2C_RETRY_3; retry++) { + ret = gtp_i2c_read(ts->client, test, 4); + + if ((ret < 0)) { + /* IC works abnormally..*/ + continue; + } else { + if ((test[2] == 0xAA) || (test[3] != 0xAA)) { + /* IC works abnormally..*/ + retry = GTP_I2C_RETRY_3; + break; + } else { + /* IC works normally, Write 0x8040 0xAA*/ + test[2] = 0xAA; + gtp_i2c_write(ts->client, test, 3); + break; + } + } + } + if (retry == GTP_I2C_RETRY_3) { + dev_err(&ts->client->dev, + "IC Working ABNORMALLY, Resetting Guitar...\n"); + gtp_reset_guitar(ts, 50); + } + + if (!ts->gtp_is_suspend) + queue_delayed_work(gtp_esd_check_workqueue, + >p_esd_check_work, GTP_ESD_CHECK_CIRCLE); + else { + dev_dbg(&ts->client->dev, "Esd terminated!\n"); + ts->esd_running = 0; + } + + return; +} +#endif + +#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND)) +static const struct dev_pm_ops goodix_ts_dev_pm_ops = { + .suspend = goodix_ts_suspend, + .resume = goodix_ts_resume, +}; +#else +static const struct dev_pm_ops goodix_ts_dev_pm_ops = { +}; +#endif + +static const struct i2c_device_id goodix_ts_id[] = { + { GTP_I2C_NAME, 0 }, + { } +}; + +static struct of_device_id goodix_match_table[] = { + { .compatible = "goodix,gt9xx", }, + { .compatible = "goodix,gt9xx_2", }, + { }, +}; + +static struct i2c_driver goodix_ts_driver = { + .probe = goodix_ts_probe, + .remove = goodix_ts_remove, +#ifdef CONFIG_HAS_EARLYSUSPEND + .suspend = goodix_ts_early_suspend, + .resume = goodix_ts_late_resume, +#endif + .id_table = goodix_ts_id, + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = goodix_match_table, +#if CONFIG_PM + .pm = &goodix_ts_dev_pm_ops, +#endif + }, +}; + +/******************************************************* +Function: + Driver Install function. +Input: + None. +Output: + Executive Outcomes. 0---succeed. +********************************************************/ +static int __init goodix_ts_init(void) +{ + int ret; + +#if GTP_ESD_PROTECT + INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func); + gtp_esd_check_workqueue = create_workqueue("gtp_esd_check"); +#endif + ret = i2c_add_driver(&goodix_ts_driver); + return ret; +} + +/******************************************************* +Function: + Driver uninstall function. +Input: + None. +Output: + Executive Outcomes. 0---succeed. +********************************************************/ +static void __exit goodix_ts_exit(void) +{ + i2c_del_driver(&goodix_ts_driver); +} + +module_init(goodix_ts_init); +module_exit(goodix_ts_exit); + +MODULE_DESCRIPTION("GTP Series Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/gt9xx_2/gt9xx.h b/drivers/input/touchscreen/gt9xx_2/gt9xx.h new file mode 100644 index 00000000000..93a36b67d69 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2/gt9xx.h @@ -0,0 +1,231 @@ +/* drivers/input/touchscreen/gt9xx.h + * + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * Linux Foundation chooses to take subject only to the GPLv2 license + * terms, and distributes only under these terms. + * + * 2010 - 2013 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef _GOODIX_GT9XX_H_ +#define _GOODIX_GT9XX_H_ + +#include +#include +#include +#include +#include + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#define GOODIX_SUSPEND_LEVEL 1 +#endif + +#define MAX_BUTTONS 4 +#define GOODIX_MAX_CFG_GROUP 6 +#define GTP_FW_NAME_MAXSIZE 50 + +struct goodix_ts_platform_data { + int irq_gpio; + u32 irq_gpio_flags; + int reset_gpio; + u32 reset_gpio_flags; + const char *product_id0; + const char *product_id1; + const char *fw_name; + u32 x_max; + u32 y_max; + u32 x_min; + u32 y_min; + u32 panel_minx; + u32 panel_miny; + u32 panel_maxx; + u32 panel_maxy; + bool force_update; + bool i2c_pull_up; + bool enable_power_off; + int config_data_len[GOODIX_MAX_CFG_GROUP]; + u8 *config_data[GOODIX_MAX_CFG_GROUP]; + u32 button_map[MAX_BUTTONS]; + u8 num_button; + bool have_touch_key; + bool driver_send_cfg; + bool change_x2y; + bool with_pen; + bool slide_wakeup; + bool dbl_clk_wakeup; +}; +struct goodix_ts_data { + spinlock_t irq_lock; + struct i2c_client *client; + struct input_dev *input_dev; + struct goodix_ts_platform_data *pdata; + struct hrtimer timer; + struct workqueue_struct *goodix_wq; + struct work_struct work; + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; + char fw_name[GTP_FW_NAME_MAXSIZE]; + struct delayed_work goodix_update_work; + char compatiable_id[10]; + s32 irq_is_disabled; + s32 use_irq; + u16 abs_x_max; + u16 abs_y_max; + u16 addr; + u8 max_touch_num; + u8 int_trigger_type; + u8 green_wake_mode; + u8 chip_type; + u8 *config_data; + u8 enter_update; + u8 gtp_is_suspend; + u8 gtp_rawdiff_mode; + u8 gtp_cfg_len; + u8 fixed_cfg; + u8 esd_running; + u8 fw_error; + bool power_on; + struct mutex lock; + bool fw_loading; + bool force_update; + struct regulator *avdd; + struct regulator *vdd; + struct regulator *vcc_i2c; +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + struct dentry *debug_base; +}; + +extern u16 show_len; +extern u16 total_len; + +/***************************PART1:ON/OFF define*******************************/ +#define GTP_CUSTOM_CFG 0 +#define GTP_ESD_PROTECT 0 + +#define GTP_IRQ_TAB {\ + IRQ_TYPE_EDGE_RISING,\ + IRQ_TYPE_EDGE_FALLING,\ + IRQ_TYPE_LEVEL_LOW,\ + IRQ_TYPE_LEVEL_HIGH\ + } + + +#define GTP_IRQ_TAB_RISING 0 +#define GTP_IRQ_TAB_FALLING 1 +#if GTP_CUSTOM_CFG +#define GTP_MAX_HEIGHT 800 +#define GTP_MAX_WIDTH 480 +#define GTP_INT_TRIGGER GTP_IRQ_TAB_RISING +#else +#define GTP_MAX_HEIGHT 800 +#define GTP_MAX_WIDTH 480 +#define GTP_INT_TRIGGER GTP_IRQ_TAB_FALLING +#endif + +#define GTP_PRODUCT_ID_MAXSIZE 5 +#define GTP_PRODUCT_ID_BUFFER_MAXSIZE 6 +#define GTP_FW_VERSION_BUFFER_MAXSIZE 4 +#define GTP_MAX_TOUCH 5 +#define GTP_ESD_CHECK_CIRCLE 2000 /* jiffy: ms */ + +/***************************PART3:OTHER define*********************************/ +#define GTP_DRIVER_VERSION "V1.8.1<2013/09/01>" +#define GTP_I2C_NAME "Goodix-TS" +#define GTP_POLL_TIME 10 /* jiffy: ms*/ +#define GTP_ADDR_LENGTH 2 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 240 +#define FAIL 0 +#define SUCCESS 1 +#define SWITCH_OFF 0 +#define SWITCH_ON 1 + +/* Registers define */ +#define GTP_READ_COOR_ADDR 0x814E +#define GTP_REG_SLEEP 0x8040 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_FW_VERSION 0x8144 +#define GTP_REG_PRODUCT_ID 0x8140 + +#define GTP_I2C_RETRY_3 3 +#define GTP_I2C_RETRY_5 5 +#define GTP_I2C_RETRY_10 10 + +#define RESOLUTION_LOC 3 +#define TRIGGER_LOC 8 + +/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ +#define GTP_I2C_ADDRESS_HIGH 0x14 +#define GTP_I2C_ADDRESS_LOW 0x5D +#define GTP_VALID_ADDR_START 0x8040 +#define GTP_VALID_ADDR_END 0x8177 + +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) + +/* GTP CM_HEAD RW flags */ +#define GTP_RW_READ 0 +#define GTP_RW_WRITE 1 +#define GTP_RW_READ_IC_TYPE 2 +#define GTP_RW_WRITE_IC_TYPE 3 +#define GTP_RW_FILL_INFO 4 +#define GTP_RW_NO_WRITE 5 +#define GTP_RW_READ_ERROR 6 +#define GTP_RW_DISABLE_IRQ 7 +#define GTP_RW_READ_VERSION 8 +#define GTP_RW_ENABLE_IRQ 9 +#define GTP_RW_ENTER_UPDATE_MODE 11 +#define GTP_RW_LEAVE_UPDATE_MODE 13 +#define GTP_RW_UPDATE_FW 15 +#define GTP_RW_CHECK_RAWDIFF_MODE 17 + +/* GTP need flag or interrupt */ +#define GTP_NO_NEED 0 +#define GTP_NEED_FLAG 1 +#define GTP_NEED_INTERRUPT 2 + +/*****************************End of Part III********************************/ + +void gtp_esd_switch(struct i2c_client *client, int on); + +int gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, + u8 *rxbuf, int len); +int gtp_send_cfg(struct goodix_ts_data *ts); +void gtp_reset_guitar(struct goodix_ts_data *ts, int ms); +void gtp_irq_disable(struct goodix_ts_data *ts); +void gtp_irq_enable(struct goodix_ts_data *ts); + +#ifdef CONFIG_GT9XX_TOUCHPANEL_DEBUG +s32 init_wr_node(struct i2c_client *client); +void uninit_wr_node(void); +#endif + +u8 gup_init_update_proc(struct goodix_ts_data *ts); +s32 gup_enter_update_mode(struct i2c_client *client); +void gup_leave_update_mode(struct i2c_client *client); +s32 gup_update_proc(void *dir); +extern struct i2c_client *i2c_connect_client; +#endif /* _GOODIX_GT9XX_H_ */ diff --git a/drivers/input/touchscreen/gt9xx_2/gt9xx_firmware.h b/drivers/input/touchscreen/gt9xx_2/gt9xx_firmware.h new file mode 100644 index 00000000000..c049d897f2a --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2/gt9xx_firmware.h @@ -0,0 +1,6844 @@ +/* Copyright Statement: +*This firmware are protected under relevant copyright laws,this information contained +*herein is confidential and proprietary to Goodix. +* +*GOODIX (C) 2013. All rights reserved. +* +*WARNING:The GTP_COMPATIBLE_MODE part of this file was generated by the specialized tools, +*please do not modify it manually! +* +*/ + + +#ifndef _GT9XX_FIRMWARE_H_ +#define _GT9XX_FIRMWARE_H_ + +#if GTP_HEADER_FW_UPDATE +unsigned char gtp_default_FW[] = +{ +0x00,0x01,0x60,0x00,0x39,0x31,0x35,0x38,0x00,0x00,0x00,0x00,0x10,0x30,0x80,0x00,0x55,0x40,0xBD,0xDA, +0xFD,0x24,0x34,0xDF,0x44,0x40,0x41,0x56,0xF3,0x05,0xC8,0xB4,0x25,0x41,0x81,0xE9,0x19,0x63,0x22,0xB7, +0xED,0x5E,0x67,0xC9,0x6F,0x23,0x01,0x88,0x86,0x02,0x72,0x43,0xA8,0x99,0x39,0x25,0xC8,0xE2,0x93,0xC7, +0xD6,0xD9,0x09,0x05,0x87,0x03,0xD5,0x98,0x13,0x29,0x23,0xB6,0x6D,0x4B,0x1E,0xDF,0xBA,0x74,0x94,0x66, +0xEC,0x67,0x47,0x75,0xB3,0x85,0x68,0x88,0xE2,0x0B,0x68,0x9A,0x42,0x29,0x88,0x50,0x67,0xDB,0x82,0x16, +0xD2,0x47,0x4C,0x79,0xC5,0xF7,0x60,0xEB,0x41,0x28,0xE9,0xE3,0x5D,0x89,0xF9,0xB6,0xFF,0x2B,0x31,0x63, +0x97,0x04,0x2E,0xA2,0xE1,0xFE,0x76,0x9E,0x3A,0x4B,0x0D,0x85,0x9F,0x3C,0x82,0x3F,0xBC,0xE3,0x3A,0xB5, +0xCB,0x9A,0xC1,0xAC,0x2C,0x48,0x64,0x6E,0x79,0x7D,0x96,0xDE,0xC8,0x68,0x91,0xEA,0xE8,0x6E,0xD5,0xBC, +0x2F,0x49,0x2E,0x7E,0x58,0x39,0x3A,0x11,0xA8,0x2F,0xE2,0x7A,0xAD,0x27,0x5E,0xD6,0x8C,0x58,0x9B,0x50, +0x1A,0x02,0xEB,0x21,0x17,0xC5,0x9B,0xCB,0xBB,0x4A,0x99,0x65,0xC1,0x9B,0xF3,0x9F,0x98,0x53,0xAF,0xD3, +0x8A,0xAB,0x2E,0xFB,0x29,0x6D,0x32,0x8E,0xA0,0x4D,0x76,0xAA,0x98,0x28,0x8F,0xD0,0x31,0xB3,0xC0,0xEC, +0x4A,0x23,0xAA,0xEE,0x8C,0x0A,0x93,0x73,0xBC,0x60,0x77,0x85,0xC0,0x36,0x83,0x31,0xFE,0xB2,0xFC,0xB4, +0x9A,0x6D,0x8C,0x2F,0xD9,0xDE,0x93,0x90,0x72,0x95,0xE9,0xD1,0xC8,0x21,0xE3,0xFB,0x54,0xE0,0x93,0x58, +0xF8,0xAF,0x08,0x80,0x34,0x0D,0xDA,0x1B,0x24,0x03,0x04,0x80,0x78,0xF8,0x5B,0x84,0x47,0x3C,0x74,0x48, +0x19,0xDD,0x6B,0x5A,0x76,0x4B,0xDE,0xB0,0x26,0xE9,0x07,0xF4,0x21,0x37,0x6F,0x97,0x9E,0xDB,0x3B,0x01, +0xA1,0x62,0x4F,0x28,0x82,0x11,0x45,0xF1,0xFC,0xCF,0xCE,0xA0,0x6E,0x5B,0x39,0x81,0x24,0xB1,0x02,0x1D, +0x24,0xE6,0x81,0xE2,0xD2,0xAC,0xCA,0x11,0x08,0x63,0xBA,0x1C,0x76,0xD4,0x3A,0x08,0x11,0x81,0x99,0x29, +0x9D,0x99,0x0C,0xF1,0x09,0xC5,0x7D,0x36,0x74,0x55,0x0E,0x38,0x97,0x5A,0x41,0xA6,0x94,0x25,0x4F,0x37, +0xA1,0x95,0x75,0xB3,0x75,0x54,0xBD,0x32,0xBD,0x5A,0xBD,0x4C,0x1D,0x2D,0x51,0xE3,0xF6,0xFB,0x95,0x0D, +0xB7,0x70,0xE5,0xCD,0x26,0xB7,0x97,0x35,0x14,0x31,0x55,0xF4,0x88,0xC6,0x9D,0x77,0x73,0x72,0xC6,0x55, +0xCB,0x03,0xFE,0x8E,0xCF,0x7A,0x5C,0x35,0x9F,0xD5,0x3E,0x0A,0xFD,0x5F,0x71,0x1A,0xA9,0x11,0x2A,0xFE, +0x7A,0xD6,0x9D,0xE7,0x2A,0x55,0xDC,0xCE,0x86,0x3B,0xF8,0xFB,0x4F,0x04,0x48,0x7F,0x3A,0x12,0xF3,0x8E, +0xC9,0x7A,0x48,0x00,0xFE,0x3A,0xD0,0xDB,0xDE,0xE3,0xF7,0x1F,0xBA,0xDD,0x09,0xDB,0xC8,0x4E,0x1F,0x2D, +0x05,0xB8,0xEE,0xC9,0x19,0x1C,0xE6,0x53,0x9B,0xB6,0xD4,0x9B,0x1A,0xDC,0xEE,0x13,0xBB,0xF6,0xCA,0x3E, +0x5C,0x39,0xDA,0x1C,0x00,0xA5,0x07,0xB0,0xCC,0x5B,0xDC,0x13,0x9A,0x1E,0xBF,0x21,0xFC,0x95,0x40,0xAD, +0xAE,0x7C,0xA8,0xBB,0xA9,0x51,0x50,0x1E,0x8A,0xFF,0x90,0x8D,0xD8,0x1B,0x33,0xAE,0x18,0x0D,0x7F,0xA4, +0x4A,0xD3,0x26,0xA2,0x46,0x83,0xB0,0xA6,0x04,0xC0,0xFA,0x02,0xB7,0xA6,0x22,0x3A,0xD5,0xAC,0xBC,0x33, +0x37,0x20,0xB8,0x12,0x05,0xC1,0xC8,0x52,0x69,0xAE,0x32,0x12,0xD4,0xA5,0xC0,0xB4,0x5C,0x41,0x21,0x1F, +0x27,0xE7,0xA9,0x4B,0xD6,0xAD,0xE5,0x71,0x87,0x32,0xC9,0xA5,0xDD,0x22,0x29,0x9F,0x85,0x83,0xC9,0x53, +0xE1,0x2E,0x31,0x23,0x26,0x09,0xE3,0x2A,0x76,0xE5,0xF0,0x04,0x32,0x5F,0x18,0xC4,0x96,0x8E,0x2F,0x49, +0x31,0x98,0xA9,0x33,0xF3,0x12,0xA1,0xAB,0xF8,0xC7,0xD2,0xA9,0x11,0x96,0x42,0x89,0x41,0x7E,0xFE,0x08, +0xF0,0xF5,0xC8,0xBE,0x41,0xFD,0xD9,0xAF,0xAD,0xE9,0xAE,0x30,0xF9,0x36,0xB0,0x01,0x00,0xEC,0x36,0x78, +0x66,0x9C,0x62,0xBF,0xA0,0x2A,0x4C,0x8F,0x12,0x3C,0x46,0x91,0xE4,0xBC,0x22,0x0A,0x0C,0xC8,0xDA,0xE3, +0x3C,0x17,0x12,0x2B,0x09,0x07,0xBE,0x3E,0xFF,0xAA,0x2A,0x1A,0x0D,0xC9,0x8A,0x9A,0x15,0x65,0x3E,0x3E, +0x0D,0xD9,0xE2,0x33,0xA2,0x36,0x23,0x2A,0x8C,0x8A,0xF8,0x4D,0x63,0x71,0xDC,0x59,0x4C,0xBA,0xAF,0x84, +0xFD,0x5A,0xF1,0x3B,0x8D,0x8B,0xF4,0x3F,0xEE,0xAB,0x7B,0x1B,0xCC,0xCF,0x7B,0xC7,0xD1,0x66,0x57,0xAC, +0x8B,0x1E,0x1A,0x46,0x7D,0xA4,0xB9,0x87,0x12,0x41,0x4A,0x94,0x4E,0xA1,0x33,0x6C,0xA8,0x96,0xD2,0x8E, +0x43,0xA4,0x1A,0x78,0x12,0xC0,0xC1,0x9C,0xF3,0x50,0x8B,0x53,0x09,0x6E,0x1B,0xCD,0x1E,0x78,0x0C,0xEF, +0xB5,0xFB,0x8C,0xED,0x47,0x35,0x59,0xBD,0x9F,0xC0,0x6A,0xDB,0xB7,0xA5,0x31,0x66,0x24,0x5E,0x83,0x97, +0xC2,0xE9,0x1E,0x60,0x88,0x6E,0xFE,0xA8,0x97,0xFE,0x3C,0x08,0x85,0xB6,0x74,0xA2,0x36,0x05,0x2C,0x6F, +0x25,0x1C,0x04,0xA9,0x33,0x4B,0x88,0x58,0x84,0xB7,0x63,0xBE,0xF2,0xF6,0x5E,0x5D,0x13,0x89,0xB0,0x03, +0xC6,0x8C,0x81,0x4D,0x05,0xB4,0x63,0x23,0xF0,0x70,0xD5,0x9B,0x7A,0x0C,0xD7,0x15,0xBC,0xDE,0x89,0xF9, +0x2C,0x97,0x15,0x15,0x2A,0xAC,0x3B,0x8A,0x19,0x14,0x18,0x2E,0x73,0x39,0x3E,0xFF,0x26,0xCF,0x0F,0x62, +0x52,0x34,0x48,0x2F,0x76,0xEE,0x14,0x54,0xB7,0x43,0x66,0xF3,0x46,0xA5,0x38,0x3C,0xCC,0xF3,0xA5,0x36, +0xA7,0x4D,0x1D,0xCF,0xD5,0xBA,0xC5,0x05,0x43,0x09,0x5E,0xA0,0xF8,0x2A,0x37,0xA1,0x5C,0xD5,0xD5,0x85, +0xF4,0x47,0x43,0xCB,0xE1,0xD6,0x54,0xB4,0xF1,0xB6,0x78,0xA8,0xF9,0x33,0x9E,0xDE,0x38,0xB7,0x1F,0xE4, +0xA5,0xBC,0x1E,0x1D,0xB4,0xCB,0x1E,0x6B,0x3D,0xB2,0xAC,0x7C,0xBF,0xB3,0x10,0xBC,0xFC,0x85,0x65,0xBC, +0x02,0x79,0x7B,0xD0,0xC7,0xD1,0xC7,0x4F,0x70,0x31,0x9E,0x49,0x40,0xC6,0x17,0xBC,0xCE,0x9E,0x71,0x90, +0xAD,0x30,0x0D,0x7D,0x3F,0xF3,0x11,0xBC,0x78,0x25,0x57,0x1D,0x59,0x7C,0x39,0xE1,0x28,0xD5,0xFE,0xD6, +0x9F,0x36,0xEC,0x94,0x68,0xDD,0xF1,0x06,0x63,0xB1,0xAE,0xFB,0x6B,0xDB,0x60,0x39,0xDE,0xDE,0xCE,0x85, +0xC8,0xDB,0x51,0x91,0xA2,0x21,0xF3,0x4F,0x99,0x78,0x9F,0xFE,0x1F,0x85,0x68,0xAB,0xAE,0xC5,0x8C,0xE7, +0x5B,0x41,0xAB,0x59,0x2F,0x07,0xAA,0x38,0x8C,0xE4,0x5F,0x3B,0x4E,0x55,0x46,0xA1,0xF9,0xBE,0x82,0x5E, +0x8D,0x62,0xA4,0xE3,0xA1,0x81,0x30,0x5C,0xE1,0xBF,0xE8,0x62,0xE4,0x66,0x68,0x5B,0xA1,0x43,0xA8,0x5D, +0xB0,0xFE,0x66,0x3C,0x61,0xB1,0xB8,0xCD,0xF0,0x02,0xAA,0x84,0x13,0x3D,0xB9,0x8C,0x3F,0x24,0xD5,0xA4, +0x83,0xB0,0xC1,0x20,0x73,0x64,0x99,0x08,0x68,0x92,0xE9,0x17,0x80,0x2E,0x9E,0x22,0x95,0x13,0x79,0x3C, +0xF3,0x53,0x78,0xB3,0x36,0x61,0xF8,0xAC,0x82,0xEB,0xD4,0x52,0x29,0x4B,0xD1,0x82,0xD0,0xC8,0x52,0xAC, +0x03,0x47,0x80,0x50,0x74,0x24,0x20,0x92,0xC1,0x41,0x07,0x68,0x60,0x97,0x79,0xB2,0xBE,0xFD,0x7B,0x02, +0x50,0x36,0x57,0x73,0x40,0xEA,0x24,0x87,0xA5,0x7A,0x90,0xAD,0xB0,0x57,0xA9,0x57,0xFC,0x2A,0x82,0x13, +0x3C,0xCB,0x61,0x8E,0xEC,0xA1,0x10,0x18,0xF7,0x85,0xFD,0x72,0x2B,0xDB,0x2C,0x31,0xC7,0xEE,0x58,0xAE, +0xD8,0x99,0xB2,0xE2,0x19,0x44,0xEA,0x1E,0x04,0x24,0x1D,0x34,0xC9,0x19,0xBA,0x00,0xF8,0x90,0xD7,0xF7, +0xBB,0xC2,0x7B,0x76,0x88,0x65,0x90,0x69,0x94,0xEE,0xAB,0xDF,0x27,0x6C,0x74,0x9D,0xAD,0xCB,0x70,0x9F, +0x19,0x73,0x25,0x35,0x46,0xCD,0xC3,0x21,0x78,0x09,0x7C,0x60,0xAD,0x1C,0x9B,0x42,0xFD,0xE1,0x18,0x75, +0x79,0x9C,0x12,0x95,0xE2,0xB7,0x08,0x2B,0x3F,0x42,0x4A,0xA8,0x7A,0xF6,0x5C,0xB8,0x47,0xC6,0xDB,0x85, +0x5F,0x2F,0x7D,0x60,0x2D,0x15,0x6F,0xDF,0x8E,0x24,0xAB,0x0F,0x47,0xC8,0x7D,0x90,0x69,0x15,0x12,0xC8, +0x62,0x7E,0xE2,0xA0,0x22,0x5A,0x5D,0x9F,0x49,0x4B,0x84,0x56,0x3A,0xC0,0x10,0x78,0xA0,0xAB,0xFC,0x06, +0xB0,0x19,0x4D,0x27,0x87,0x12,0x6E,0xD7,0x44,0x1C,0xD2,0xD0,0xA3,0x15,0xF4,0x10,0x58,0xC9,0xDC,0x44, +0xB7,0xFC,0xA2,0x99,0xBB,0x01,0xF3,0x6C,0xF6,0x50,0xBD,0x07,0x75,0x3E,0x41,0xDC,0x01,0xAD,0xF3,0xA8, +0xF1,0x10,0x95,0xF3,0xE2,0xE1,0xB7,0x66,0xE1,0x28,0x85,0xA2,0xCC,0x5C,0x95,0xAC,0x14,0x8C,0x14,0x2F, +0xDA,0x7D,0xE5,0xC0,0xD9,0xC4,0x36,0x1F,0x63,0x14,0x96,0x06,0x74,0x55,0x66,0xA2,0x03,0x65,0xBE,0xC3, +0x23,0x77,0x75,0x74,0x5B,0x00,0xF2,0x5B,0xD2,0xF5,0xF2,0xCD,0xA4,0xAD,0xA5,0xC7,0xC2,0x3B,0x8F,0x1F, +0xE4,0x9D,0x08,0x05,0xB6,0x70,0xCB,0x22,0xA0,0x62,0xD9,0x25,0xD0,0x03,0x9D,0xC4,0x08,0x15,0xA5,0xE4, +0x83,0x73,0x78,0x91,0x89,0x7B,0x84,0x6A,0x0B,0x8D,0x24,0xBB,0xCB,0xF1,0xA8,0x80,0xF7,0x8E,0x44,0x05, +0xC2,0xC9,0xB6,0x4C,0x65,0xB8,0x06,0xB5,0xE6,0xF4,0x79,0xFC,0x31,0x3B,0xE7,0x94,0x04,0x17,0x7F,0x0F, +0x38,0xF0,0x69,0xDD,0xA1,0xF3,0xDF,0xBC,0x11,0x0B,0x37,0xBF,0x40,0x5D,0x89,0x75,0xAB,0x74,0x85,0x2B, +0x18,0xF6,0xC0,0x4F,0x79,0x9B,0xDA,0x33,0xAA,0xDC,0x06,0xED,0xE4,0x27,0x4E,0x8A,0xE8,0xF0,0xBE,0x04, +0x6E,0x31,0x79,0xD4,0xD7,0x4D,0xBD,0x3E,0xB6,0x9B,0xDB,0x10,0x75,0x12,0x71,0x8E,0xA6,0x72,0x39,0x09, +0x16,0x77,0x85,0xAB,0x38,0x92,0xEC,0x8B,0x67,0xF8,0x28,0xE5,0x5F,0x78,0x8F,0x20,0x28,0x19,0x4A,0x1D, +0xF3,0x92,0x65,0x11,0x31,0x90,0x6B,0x82,0x58,0x31,0x8B,0x45,0x0A,0x5C,0x98,0xFD,0xE1,0xBB,0xB5,0x62, +0x48,0x6B,0x50,0x3A,0x76,0x30,0x48,0x59,0x85,0x5C,0x50,0x94,0x95,0x7B,0x94,0xA1,0x11,0xC9,0x7C,0xB3, +0xD3,0x41,0xE5,0xC9,0x3F,0x7D,0x29,0xE1,0x6D,0xB2,0xB0,0x2E,0x2D,0x72,0x37,0x45,0x2B,0x8E,0x51,0x34, +0x78,0x8C,0x91,0x95,0x50,0xC4,0x3F,0x20,0x9D,0x52,0xD9,0x35,0xF3,0xEE,0x98,0xC6,0x27,0x84,0x78,0x34, +0xED,0xE6,0xAB,0x00,0x05,0x34,0xE3,0x15,0x26,0x88,0xB4,0x52,0x01,0xAE,0xCD,0x24,0x95,0x99,0x21,0xEF, +0xE0,0xC3,0xA2,0x57,0x3F,0x74,0xA1,0x83,0x4D,0xC4,0xBE,0x6C,0xFD,0x56,0x67,0x01,0xAE,0xCB,0x97,0x02, +0xD5,0xD7,0x4C,0x75,0xDB,0x0A,0x6D,0xB5,0x15,0xBB,0x59,0x71,0x66,0xC1,0x80,0x11,0x5A,0x85,0xF9,0x5C, +0x73,0xB3,0xDA,0x8C,0x9C,0x52,0x12,0x2F,0x84,0x18,0xCC,0x02,0xF0,0xE5,0xF7,0x36,0x0B,0x62,0xD2,0x9C, +0x9D,0xA0,0xBB,0xAA,0xA6,0x58,0x63,0x5C,0xB6,0x99,0x78,0x09,0xF7,0x24,0x9B,0x8D,0x59,0x2D,0x20,0x58, +0xBC,0x6B,0xCD,0x02,0x5E,0xEE,0x23,0xE7,0x58,0x70,0x93,0x9D,0x58,0x0C,0x1D,0x37,0x6E,0x4F,0x0F,0x5D, +0xEE,0x7D,0xB6,0xA2,0x8E,0x44,0xDB,0xAC,0x9C,0xA8,0x5C,0xC4,0xED,0xC1,0x8C,0x42,0xD3,0x6A,0x91,0x08, +0x21,0xEE,0x11,0x79,0xBE,0x74,0xFE,0x8A,0xB0,0xC2,0x87,0x4F,0x6B,0x42,0x9C,0xA3,0x94,0xC3,0xF0,0x2D, +0x61,0x21,0xDF,0xF9,0xDA,0xC4,0x75,0x2F,0x9A,0x65,0x21,0x19,0xD2,0x07,0xB3,0xCE,0x62,0x28,0x22,0xE1, +0x2A,0xA3,0x6A,0xFB,0xF7,0x94,0xA1,0xA5,0x85,0x1A,0x1C,0x79,0x07,0x90,0x2A,0x30,0x24,0xD8,0x74,0xDA, +0x6F,0xFA,0x0C,0x66,0xA5,0x3C,0x54,0xE9,0x5E,0xBE,0x04,0xD2,0x61,0xF9,0x9C,0xDE,0xD4,0x2E,0xA2,0x70, +0x89,0x89,0x5D,0xF5,0x87,0x02,0xB4,0x21,0x6C,0xD2,0x35,0x61,0xC0,0xF4,0x2A,0xA2,0xF1,0x3C,0x7A,0xA5, +0x4A,0x66,0xF4,0xB1,0x02,0x7E,0xDD,0xB5,0x98,0xFE,0x34,0xC7,0x45,0xB4,0x61,0x24,0xB6,0x44,0x0A,0xEB, +0xE3,0x64,0x43,0xC2,0xD7,0x55,0x3C,0xDB,0x0C,0x93,0x8C,0x85,0xC5,0xB8,0x46,0x1A,0xB3,0x1A,0x87,0x31, +0x8A,0x43,0x1D,0x47,0xE9,0xB9,0xBC,0x5D,0x53,0x49,0x8A,0x67,0x95,0x25,0xCD,0x1C,0x17,0x95,0x4D,0x2B, +0x06,0x1B,0x41,0x48,0xB6,0xD7,0x24,0xE1,0x00,0xC7,0x46,0x6D,0xF6,0x17,0xBE,0x62,0x22,0xD7,0xDE,0x0A, +0x0B,0x1A,0xAA,0x40,0x8D,0xE3,0xC9,0xD0,0x97,0xE9,0x29,0xE8,0xC6,0x49,0xAA,0x7C,0xB8,0x4C,0x06,0x33, +0xC2,0x74,0x2F,0xA7,0x7B,0x42,0x37,0x86,0xBC,0x35,0xC7,0xCF,0x52,0x31,0xE8,0x4C,0x5D,0x7B,0x88,0x5C, +0xC4,0xFB,0x76,0x99,0x4A,0x9D,0xCF,0xDF,0x03,0x36,0xA7,0x51,0x0C,0xE0,0xC5,0x3D,0x7D,0x52,0xA2,0x4F, +0x6D,0xFC,0x59,0x5E,0x9D,0x31,0x8C,0x02,0xE6,0x13,0x49,0x75,0x81,0x21,0x24,0x67,0x1C,0x9C,0xB7,0xC3, +0x98,0xAD,0x84,0xBC,0x25,0x91,0xC1,0x61,0x80,0x60,0x3E,0x5F,0x09,0x93,0x87,0x9C,0x01,0xB1,0x76,0x1D, +0xDD,0xAA,0x94,0x11,0xDA,0x92,0x97,0xBD,0xC4,0x90,0x17,0x37,0xB5,0xF0,0x3A,0x79,0x6F,0x14,0x1C,0x01, +0xDB,0xFF,0x59,0xEC,0xE5,0xAB,0xFE,0x03,0xB1,0xFF,0x90,0x01,0x8E,0xCD,0xF2,0x20,0x53,0xA0,0x68,0x5B, +0x0D,0x0C,0x77,0x67,0x7F,0xF2,0x66,0x84,0xAA,0xE2,0xC1,0x34,0xAD,0x70,0xD4,0x01,0x6B,0x91,0x35,0x67, +0xF8,0x31,0x6F,0x80,0x2B,0x01,0xC1,0xAC,0xDC,0x20,0x51,0x18,0xB2,0x8B,0x72,0xB0,0x5B,0x2E,0x67,0x81, +0x2A,0x20,0xB9,0x31,0xAE,0x93,0x3E,0x78,0xEB,0x95,0x23,0x04,0x60,0xA9,0x58,0x74,0x8A,0x67,0x95,0x66, +0x12,0xE9,0x12,0x49,0x6B,0x94,0xDC,0xF6,0xD9,0x76,0x02,0x69,0x2B,0xA4,0x9D,0x69,0x24,0x39,0xED,0xDA, +0x81,0x94,0x98,0x46,0x75,0x64,0xC6,0x72,0xE4,0x45,0x88,0x7A,0x35,0x67,0x89,0x70,0x42,0x0A,0xF7,0xFC, +0x95,0x06,0x99,0x50,0x02,0x4A,0x06,0x66,0xEC,0xF4,0xBA,0xFB,0x36,0x18,0xFD,0xF6,0xF1,0xEB,0x6C,0x10, +0xA1,0x59,0x52,0xCC,0x6E,0xC8,0xD6,0x7E,0xE2,0xBA,0xDC,0xA0,0xF2,0x8A,0x62,0x1F,0xEA,0xE4,0xE4,0x14, +0xB0,0x78,0xBB,0xFA,0xFA,0x11,0x14,0xFE,0xFE,0x87,0xD3,0x09,0x0B,0xC7,0x82,0x2C,0xE3,0xE7,0x0A,0x7F, +0x62,0xD8,0xB5,0xAD,0xE3,0x84,0x0A,0x08,0x68,0xEA,0x37,0xAE,0x82,0x63,0x5C,0x7D,0x29,0x9C,0xB1,0x8C, +0x46,0x40,0x2C,0x5D,0x4C,0x4D,0x8D,0xEC,0x29,0x19,0x8A,0x79,0x1A,0x00,0xF4,0xF1,0x1D,0x2C,0x62,0x87, +0xC6,0xEB,0x88,0x94,0xD7,0xA0,0x19,0x81,0xE2,0x9F,0xFD,0xE9,0x50,0xBD,0x39,0x0B,0x3D,0x2B,0x13,0x98, +0xDB,0x4A,0x49,0xBB,0x0B,0x8F,0xC0,0x9D,0x97,0x2E,0x0B,0x07,0x01,0xBE,0xC3,0x78,0x9D,0x6B,0xD8,0x7A, +0x1F,0x23,0xFB,0x7E,0x8C,0xF3,0x2A,0x89,0xEF,0xF6,0xAA,0x8D,0xFF,0xD6,0x96,0xAA,0x48,0xEA,0xBD,0x31, +0xBE,0x73,0x09,0xA3,0x4C,0x5E,0x57,0xC7,0x49,0xD5,0x5B,0xD1,0x8A,0xA7,0x34,0x34,0x08,0xB1,0x09,0x61, +0xCB,0xFF,0x89,0xE5,0xF4,0x5A,0x06,0x6D,0x1D,0x51,0x0A,0x9C,0xB0,0xE0,0x2F,0x8F,0x42,0xC8,0x01,0x57, +0x11,0x8C,0xE4,0x30,0x9E,0x56,0xD5,0xE5,0xA4,0x58,0x41,0x64,0x42,0x67,0x7C,0x7D,0x41,0xD0,0x6A,0x65, +0x09,0xB1,0xB2,0xF9,0x00,0xCC,0x62,0x54,0xC0,0xA0,0xD8,0x60,0x40,0xD1,0x55,0x62,0xA3,0xD6,0xFB,0x1C, +0x78,0xBF,0x6B,0x40,0x41,0x33,0x6F,0x71,0xE0,0x7D,0x1C,0x75,0xEB,0x46,0x75,0x2B,0xA3,0x7A,0x48,0x75, +0xD4,0x5A,0x67,0x7D,0xB6,0x7C,0x9D,0x1F,0x2E,0x39,0xDF,0x8B,0xDD,0x31,0x16,0x99,0x3F,0xF7,0x25,0x4E, +0x91,0xA2,0x2F,0xEE,0x1A,0x6D,0xD7,0x60,0xFF,0x2B,0x09,0xAB,0x3E,0x08,0x0D,0xD2,0x0F,0xD6,0xC6,0xC9, +0xEC,0x01,0x80,0x09,0x90,0x3D,0x84,0xD3,0x9E,0xF5,0x4E,0xAD,0x84,0xD5,0xF5,0xEB,0x42,0x92,0x35,0x19, +0x91,0xAC,0x21,0x95,0x66,0xFD,0x88,0xAE,0xAE,0x2A,0x40,0xF4,0xC3,0xCD,0x39,0x8B,0xDB,0xCA,0x68,0xDD, +0x6C,0x5D,0xC3,0x68,0x52,0xBC,0x5A,0xBA,0x63,0x2C,0x22,0xA3,0xF1,0xEE,0xEA,0x8B,0x49,0x52,0xCA,0xF5, +0xFD,0xCF,0x1F,0xCD,0xE2,0xAF,0x38,0xBF,0x6C,0xE1,0x3D,0x9A,0x96,0x51,0x37,0x68,0x56,0x3C,0x5B,0x9B, +0x52,0x14,0xF1,0x64,0xBD,0x1E,0x9F,0xD8,0x3A,0xF2,0x77,0x74,0x7E,0xDD,0x06,0x73,0x4D,0x24,0xF2,0x75, +0x3A,0x33,0x08,0x12,0xF0,0x6F,0x30,0x47,0x59,0x4B,0xF1,0x3D,0x7E,0x8A,0xAE,0x3A,0x5D,0x70,0xF8,0x12, +0xED,0x83,0x8A,0x06,0x57,0x4E,0xBB,0x57,0xBB,0x1A,0xDF,0xA2,0xDC,0x33,0x91,0x51,0xA6,0xDE,0xC9,0x37, +0x3D,0xF3,0x72,0x04,0xFA,0x81,0x97,0x2B,0xB6,0x36,0xBE,0xCF,0x2C,0x19,0x19,0x44,0x76,0x60,0x66,0x7A, +0x86,0x5A,0xA5,0xDF,0x10,0xA5,0x78,0x66,0x6F,0x37,0x72,0x14,0x65,0x5F,0x28,0xA2,0x5F,0x34,0xE0,0x46, +0xC3,0x86,0xF3,0x12,0x57,0x87,0xA1,0x2F,0xF0,0xE3,0x5F,0x7B,0xFF,0x8D,0x37,0xC3,0xBE,0xB8,0x57,0x13, +0xFE,0x3B,0x0B,0x6F,0x31,0x6B,0xA9,0x72,0x46,0x2A,0x4E,0xF3,0x7E,0x2E,0x6D,0x29,0x66,0x68,0xD9,0x2B, +0x76,0x18,0xF9,0xA5,0x0A,0xD1,0xA4,0x37,0x9C,0xBD,0x2C,0xF7,0x6F,0xF8,0x07,0xAA,0x7C,0xCD,0x51,0x35, +0x68,0xDC,0x6A,0x3E,0x54,0xA1,0x62,0x3F,0x4B,0xD2,0xC4,0x9F,0xB6,0xAA,0xD6,0xF7,0x72,0x71,0xA5,0x26, +0x94,0xA6,0x0D,0x4B,0xA5,0xE3,0x73,0x32,0xAB,0x67,0x35,0xE2,0x72,0xC9,0xE7,0x6D,0x62,0x74,0x3B,0x28, +0xEC,0xFA,0xC4,0x2C,0xFC,0xDA,0xF4,0xA8,0x08,0xAD,0x22,0x6E,0x24,0x01,0x67,0xFB,0x2F,0x8E,0xD8,0xBE, +0x02,0xED,0x6D,0xDE,0x2B,0x9C,0x3A,0xBC,0xE3,0x24,0x13,0x3A,0x0F,0x19,0x45,0x2C,0x51,0x67,0x6D,0xBB, +0x86,0x81,0xB7,0xAD,0x32,0x03,0x63,0xDE,0xC8,0xEF,0xCB,0x6B,0x5B,0x8C,0x31,0x03,0xF3,0x20,0x2B,0xB3, +0x3E,0x0F,0x2F,0x64,0xE9,0x62,0x7D,0x5F,0x7E,0xAF,0x1A,0x5B,0x07,0xD0,0xAC,0x27,0xBB,0x1D,0xFB,0x62, +0x6F,0x92,0x8A,0x8A,0xFB,0x56,0x73,0x81,0x4D,0x9C,0xED,0xE0,0x33,0xB0,0xAB,0x41,0xE1,0x5A,0xC7,0x87, +0x01,0x5E,0x39,0xC6,0xD7,0xCE,0x75,0x6F,0xC3,0x74,0xA5,0x8B,0x87,0xD0,0x7A,0x67,0xDB,0x79,0x3B,0xF1, +0x1A,0x68,0xA6,0xD7,0xF9,0xA8,0xC8,0x37,0xC5,0xF4,0x1D,0x47,0x0B,0x50,0xE4,0x83,0xC7,0x19,0x97,0x86, +0x16,0x19,0x61,0x00,0x4F,0x27,0xCA,0x96,0x55,0x36,0x78,0x83,0x86,0x6A,0x7C,0x72,0x31,0xB4,0xBD,0xD2, +0x7D,0xBF,0x2F,0x85,0x0D,0x7C,0x1B,0xFB,0xFC,0xD4,0xFF,0xF7,0xBE,0xF4,0xB5,0xC3,0xAF,0xDC,0x19,0x94, +0xE1,0x50,0x81,0x40,0xD7,0x9F,0xB5,0x97,0xF5,0xAC,0x43,0x4B,0x8F,0x04,0xDD,0x1D,0x1E,0xCD,0x66,0x76, +0x90,0xDA,0xF9,0xB8,0x16,0xA8,0x3E,0xBE,0xA4,0x3B,0xA1,0x5D,0xF0,0xF5,0x3F,0xE9,0x1D,0xF5,0x42,0x0C, +0x25,0xB1,0x64,0xE2,0x11,0x76,0xA6,0x6E,0x94,0x18,0xF9,0xCB,0x4D,0x35,0x15,0x2B,0x55,0x2B,0x63,0xB8, +0xDE,0x99,0xC9,0x9A,0x9D,0x0A,0x76,0x85,0x6B,0x93,0xA8,0x77,0x69,0x76,0x9F,0x4B,0x51,0x08,0xC5,0xDF, +0xCB,0x76,0x64,0xD5,0x5E,0x28,0x41,0xDA,0xDB,0xD2,0x89,0x99,0x50,0x7F,0xEC,0xEC,0xEC,0xF4,0x10,0xE7, +0xE7,0x0C,0xB7,0xCC,0x58,0xCD,0xA8,0x98,0x9C,0xB8,0x70,0x10,0x96,0x74,0xF1,0xB0,0x8D,0x43,0x85,0xCA, +0xBF,0x4E,0x20,0x15,0xE8,0xDF,0xF1,0x9D,0x01,0xBC,0x3F,0x5F,0x8F,0x37,0xEE,0x2B,0x0D,0xF1,0x47,0x3C, +0x31,0x42,0xA7,0xEE,0xCC,0xDB,0x82,0x02,0x40,0x8D,0x06,0x8E,0x13,0xE0,0xEF,0xA4,0x0D,0x1F,0x74,0xD7, +0xF3,0xEB,0x1C,0x9C,0x00,0x43,0x24,0x9E,0xEA,0xD1,0x9A,0xD8,0xD9,0x8C,0x9C,0xB4,0xB8,0x25,0x58,0x02, +0x67,0x40,0xEF,0xE7,0x37,0x63,0x31,0x24,0xF3,0x36,0x95,0xA2,0xF4,0x15,0x37,0x61,0xE1,0x43,0xE7,0xF7, +0x24,0x62,0x01,0x30,0x87,0x02,0x8C,0xC6,0x55,0xCE,0x53,0xBA,0xB7,0xD0,0xEF,0xAB,0xF3,0xB8,0x6B,0x6F, +0xE1,0xC0,0xD1,0x1F,0xB5,0x74,0x30,0x5F,0xA0,0x80,0x58,0x3B,0xCD,0x8A,0x66,0x92,0xDE,0x7A,0x22,0x50, +0xA2,0x6A,0x39,0x73,0x5B,0x13,0x38,0x37,0x03,0x19,0xFE,0x3F,0x1B,0xD9,0x6A,0x93,0xC2,0x9B,0x5E,0x0B, +0xB1,0xA6,0xB1,0x3B,0x45,0x6F,0x00,0xF9,0x3E,0xB6,0x6D,0x0E,0x70,0x02,0xC2,0x2C,0x2E,0x4A,0x2A,0xDF, +0xE9,0x2B,0xE7,0x29,0x0C,0x7C,0x36,0x80,0xB3,0x0C,0xE2,0x89,0x3A,0x6D,0xB0,0x5B,0xC3,0x96,0x8A,0xF8, +0x4D,0xA4,0xA2,0x18,0x5A,0x59,0x13,0xE9,0x89,0xCA,0x3D,0x04,0x3E,0x84,0xB3,0x27,0x44,0x47,0xAB,0xDE, +0x7B,0x0F,0xD1,0x89,0x41,0x82,0xB1,0x87,0x6A,0xF6,0x8B,0x96,0x3E,0x0B,0xA6,0x0C,0x5D,0x74,0x3A,0xB3, +0xB3,0xF8,0xBA,0x27,0xC0,0x64,0xAD,0x16,0x64,0x93,0x69,0x8E,0xF6,0x91,0x1C,0xBA,0xF8,0x70,0xE3,0x2C, +0x9B,0x3B,0x8E,0x82,0xF6,0x2E,0xDB,0x07,0xFC,0x7D,0x3B,0x7B,0xFA,0xB2,0xBB,0x37,0xFB,0x2A,0x6C,0xCC, +0x31,0xD3,0xAB,0x49,0x2B,0x21,0xE8,0xBB,0x6B,0xD0,0xC5,0xBF,0xBF,0x52,0xA6,0xF9,0x04,0x2F,0x60,0x9B, +0xCB,0x92,0x4C,0x89,0xDD,0x7C,0x63,0x7B,0xD1,0xE6,0x01,0xDF,0xB8,0x5F,0x61,0xA5,0x7A,0xDD,0x5C,0x01, +0x1F,0x0A,0xF5,0xB3,0x90,0x20,0x8C,0xC2,0xB0,0x4E,0xA2,0xB3,0x47,0xDE,0x67,0x89,0xA1,0xC1,0x7E,0xA1, +0x79,0x3D,0x37,0x5E,0x18,0x5D,0x35,0x8C,0x1B,0x36,0xAE,0xA7,0xC0,0xC8,0xF5,0xC6,0x12,0x2C,0x43,0x53, +0xF1,0xAE,0x39,0xDF,0x52,0xDE,0x44,0xBF,0x5E,0xEB,0xAD,0x27,0x16,0x29,0x52,0x6F,0xDB,0x02,0xFA,0xE3, +0xE3,0xD8,0x98,0x8B,0xF2,0x76,0x18,0x2B,0xC6,0x56,0x27,0x9B,0xF5,0x6A,0xF2,0xF3,0xBA,0x7A,0xFE,0x64, +0x55,0xAA,0xDD,0xD8,0x4F,0x5A,0x5D,0xF4,0x13,0x20,0x75,0xAF,0x51,0x13,0x66,0x82,0x27,0x74,0x36,0xAE, +0x9D,0x88,0xDA,0x3B,0x42,0xDA,0xF3,0xF2,0x62,0xDB,0x2F,0x75,0x9C,0x83,0xB8,0x8A,0x72,0x7C,0x81,0x57, +0x9D,0x3B,0xEE,0x8B,0xDB,0x39,0x14,0xA9,0x88,0xB8,0xB6,0x34,0x9A,0x78,0xA5,0x23,0x98,0x4F,0x3E,0xF6, +0x9E,0x69,0xAE,0x70,0x60,0xB7,0xDF,0x89,0xF2,0x5E,0xEC,0xD3,0xC6,0xC5,0xDF,0xA4,0x41,0xDB,0x37,0x76, +0xAF,0xF0,0x7A,0x9C,0xAD,0x0F,0x17,0xA8,0x1A,0x86,0x2D,0x5F,0xDD,0x0C,0x68,0xCE,0xB4,0xA1,0xFD,0x69, +0xC9,0x22,0x7B,0x06,0x8B,0xC0,0x76,0xA6,0x5E,0x72,0xEE,0x52,0x2A,0x8D,0xCF,0xAA,0xC0,0x2D,0x1E,0x87, +0x17,0xA2,0x3A,0x1A,0x6B,0xF6,0xA6,0xB3,0x30,0xB3,0xBB,0xE9,0x5F,0xA1,0xAA,0xCD,0x81,0x51,0x73,0x2F, +0x7E,0xF3,0x31,0xDF,0x5E,0x69,0x75,0x23,0xAB,0xF2,0xE4,0x5C,0x1C,0xE2,0xDB,0x7A,0x5C,0x6F,0x6F,0xEA, +0x80,0x4D,0xF0,0x71,0x5E,0xE7,0x8C,0x06,0xDC,0x84,0x12,0xC4,0x44,0x2D,0x30,0x1E,0x36,0xFA,0x57,0x64, +0xC3,0x7E,0xA8,0x4D,0x9D,0xCE,0x85,0x07,0xD1,0xFE,0x39,0x1F,0xED,0x38,0xCF,0x75,0x19,0x54,0x90,0x24, +0x25,0xA4,0x21,0x88,0x23,0xB2,0x93,0x54,0x47,0xE3,0x69,0x0F,0x2B,0xCF,0x0B,0x19,0x66,0x3F,0x01,0xC4, +0x76,0xF3,0x55,0xA0,0xBB,0x70,0x07,0xB5,0xB5,0xF9,0x15,0x22,0x06,0xB9,0x08,0x42,0xE6,0xA0,0x10,0x6E, +0xDE,0xB6,0x8F,0x12,0xB4,0xB8,0x46,0x00,0xFC,0x9A,0x5C,0xB4,0xD3,0xA7,0x19,0x71,0x5B,0x2A,0x02,0x03, +0x35,0x9B,0x14,0x8C,0x9A,0xD8,0xD7,0x60,0x75,0xE8,0x92,0x21,0xF5,0x18,0x8A,0x06,0x34,0xE6,0xE9,0x9B, +0xD5,0x3A,0x7E,0xDC,0xD1,0x17,0x6A,0x0E,0x48,0xC9,0x98,0x95,0xE7,0x25,0x11,0xC8,0xAC,0xD9,0x0A,0x0A, +0xB5,0x8C,0x73,0x15,0xE8,0x76,0x6A,0x06,0xA3,0xAA,0xA9,0xC4,0x69,0x5E,0x5E,0xCD,0xFE,0x8C,0x19,0xE3, +0xB3,0x45,0xC0,0xF5,0x1C,0xCA,0x98,0x30,0x6F,0x4F,0x22,0xDC,0x50,0xD7,0x87,0xF3,0x1D,0x4D,0xC5,0x0A, +0x10,0x26,0x3B,0x36,0x3B,0xCB,0x86,0xB8,0xF9,0xF4,0xDB,0x78,0x76,0x50,0xDB,0x2E,0x42,0x31,0xE5,0x95, +0xBB,0xAF,0x87,0xEA,0x02,0xDB,0x39,0xA0,0x2B,0x26,0x2E,0xA5,0xEA,0xCF,0x41,0xDF,0xBC,0xF1,0x26,0x0C, +0xD1,0x88,0x35,0xA9,0x75,0x03,0x4F,0xCA,0x6D,0x13,0x88,0x10,0xE0,0x71,0x33,0x72,0x64,0x63,0x13,0x53, +0xE4,0xCB,0x10,0x20,0x91,0x50,0xAF,0x30,0xCD,0x21,0xD5,0x78,0x16,0xE0,0x2C,0xAD,0x41,0xC5,0x04,0x88, +0xB8,0xBD,0x53,0x5C,0x38,0x7E,0x4F,0xAF,0xCD,0x51,0x8A,0x6F,0x27,0x4A,0x3C,0x56,0x71,0x55,0x43,0x96, +0x9C,0xCE,0xC4,0xBE,0xD2,0xB0,0x3B,0x7A,0x87,0x09,0xDB,0x65,0x18,0xBF,0x4D,0xC8,0x05,0x0E,0x15,0xED, +0x53,0x5F,0xD8,0x17,0xD0,0x3D,0xD5,0x9E,0x58,0x81,0x43,0x51,0x10,0x57,0x84,0xA8,0x56,0x76,0x9F,0xB9, +0xB0,0x2B,0x1B,0xE2,0x97,0x2B,0xA0,0x19,0xB7,0xB7,0xAE,0xE2,0xF8,0xBB,0x02,0x30,0xE0,0x18,0xD4,0x28, +0x9B,0xB8,0x3C,0x25,0x2B,0xA3,0x04,0x06,0x37,0x9E,0x5E,0x48,0x55,0x66,0x51,0xA5,0x4D,0xD3,0x5E,0xA9, +0xC8,0xCA,0xF4,0x17,0xFA,0x90,0xC6,0x3C,0x46,0x2B,0x12,0xF3,0x56,0xD1,0x46,0x7D,0x56,0xE1,0xCF,0xC6, +0x73,0x58,0x1C,0x62,0xB0,0x57,0x36,0x21,0xCB,0x58,0x26,0x6C,0x3E,0x07,0x9D,0xA1,0xDF,0x7D,0x6F,0x0C, +0x2C,0x29,0x12,0x17,0x19,0x8D,0x3F,0xC5,0x11,0x26,0xC6,0x8C,0x0D,0x66,0x7A,0x88,0x41,0xF4,0x1B,0x7C, +0x1F,0x8A,0x00,0x49,0x87,0xD5,0xA4,0x55,0x45,0x2E,0x15,0x73,0x25,0x54,0x0F,0x91,0x31,0x36,0x00,0x1E, +0x16,0xD3,0x1E,0x5D,0x04,0x7E,0x9F,0xB8,0xFF,0xA3,0x9D,0x3E,0x36,0xDA,0x7E,0xE6,0x97,0xAA,0x56,0x9D, +0xDD,0x5F,0x6E,0x99,0x95,0x9D,0x15,0x2E,0x33,0xDB,0x47,0x71,0xDC,0x2D,0x9E,0xBE,0xD2,0x00,0x56,0xCD, +0x8A,0x89,0x98,0x3F,0xBA,0xD8,0x08,0x91,0x78,0x41,0x53,0x1C,0x72,0xBF,0x22,0x75,0xAF,0x2E,0x10,0xFB, +0x4E,0x70,0x11,0x19,0x78,0x52,0x87,0xDB,0xFF,0xFF,0x59,0x1A,0xE5,0x0B,0x92,0xFA,0xEF,0x8D,0x6E,0x80, +0xA9,0x63,0x7A,0x57,0x3E,0x69,0x57,0xA7,0xD5,0x72,0x08,0x55,0x3D,0x63,0x8F,0x0E,0x35,0x5A,0xE7,0x47, +0x63,0x0D,0x81,0x60,0xA0,0x40,0x57,0x42,0x4E,0x2A,0xD5,0xD2,0xEA,0xEF,0x52,0x56,0xF5,0xE0,0xAE,0xA9, +0x87,0x19,0xC4,0x98,0xFB,0x50,0x99,0x6F,0x65,0xAE,0xFE,0xF5,0x93,0x21,0x95,0x33,0x6C,0x0F,0xD4,0x7B, +0x60,0xF1,0xD0,0x01,0x10,0xE9,0xF0,0xF6,0xD2,0x6E,0x19,0xB0,0x07,0x2C,0xE8,0xD0,0x9C,0x88,0x66,0xC9, +0x45,0x5F,0x86,0xC0,0x2C,0x10,0xC1,0x20,0xD0,0xAB,0x14,0xC1,0xAD,0x18,0x82,0x50,0x63,0xB9,0x53,0x94, +0xB8,0x66,0x0A,0xD5,0x98,0x75,0x1B,0xC6,0xBD,0x8A,0x3C,0x82,0xB3,0x22,0x41,0x07,0x28,0x9C,0xE2,0xFB, +0x32,0x6D,0xFC,0xB5,0x11,0x49,0xD6,0x76,0x46,0x56,0xDF,0xA1,0x32,0x1B,0x96,0xF7,0x3E,0x09,0x98,0x1D, +0xE6,0xA4,0xCA,0x4A,0xA2,0xCA,0xC9,0xA3,0xB2,0x61,0x3B,0xFA,0xBE,0xA7,0x85,0xBD,0x71,0x43,0x6A,0xDA, +0xE6,0x9E,0xED,0x94,0x55,0xC7,0xB8,0xB4,0x75,0x98,0x4B,0xD5,0x08,0x86,0x25,0x89,0x44,0xCD,0xA5,0x90, +0x0F,0xC4,0x14,0xE5,0xE1,0xBF,0x12,0xC8,0x09,0x6B,0x6A,0x9B,0x32,0xE1,0xC8,0x90,0xAE,0x2E,0x5C,0x3D, +0xE0,0x05,0x3F,0xD8,0x15,0x0C,0x64,0xC5,0x4D,0x57,0x4C,0x0F,0x37,0x01,0x98,0x49,0x63,0x9D,0xCB,0x59, +0x9C,0x34,0x5B,0x58,0x6B,0xB1,0x8C,0x46,0x3B,0xC1,0xF0,0xE8,0xB5,0xA0,0xCD,0xED,0x93,0xB9,0x3E,0x87, +0x67,0x42,0xBD,0x19,0xDA,0x2F,0x40,0x04,0x33,0x2F,0xD6,0x7B,0xC7,0x72,0x00,0x0C,0x48,0x4A,0xDD,0xD7, +0xFD,0xDD,0x39,0x69,0x31,0x53,0x94,0x8C,0xBE,0xB7,0x08,0x43,0x67,0x4B,0x94,0xC7,0x4F,0xF7,0x5A,0x95, +0xA6,0x82,0xCC,0x4B,0x59,0xD1,0x01,0x92,0xC8,0x3C,0xC6,0x36,0xDD,0xDD,0x44,0x77,0xDA,0x73,0x89,0x55, +0xB5,0x1B,0xF7,0xC2,0xC4,0xD1,0x9D,0x46,0x8F,0x5B,0xBC,0x81,0x99,0x7A,0x9D,0x28,0xD7,0xC5,0x99,0x9E, +0xC6,0xB9,0x67,0x17,0xFE,0xFF,0x72,0x74,0x25,0x0F,0xB2,0x71,0xB1,0x31,0x23,0x83,0x13,0x10,0x58,0x1B, +0xC7,0x7A,0x7B,0x75,0x68,0x75,0xBB,0x75,0x53,0x55,0x91,0x1B,0x1F,0x34,0xD1,0x07,0xF4,0xB5,0xBD,0x11, +0xA7,0x3E,0x97,0xB7,0xD8,0x94,0xE3,0x74,0x14,0xFA,0x31,0x66,0x8B,0x2A,0x26,0x94,0x2E,0x02,0x12,0x08, +0x2B,0x95,0x69,0xDB,0x5A,0x34,0xCB,0xBD,0x1A,0xD5,0x0D,0xB3,0x71,0x5B,0xB0,0xA0,0x9D,0xD4,0x86,0x88, +0x9E,0xE6,0x88,0xDE,0x86,0xE4,0x7A,0x70,0xE4,0x58,0x8B,0xA8,0xF0,0xB9,0x70,0x69,0xA2,0xF7,0x0B,0x56, +0x8B,0x7A,0x46,0x7F,0xD2,0xBB,0x4B,0x6E,0x9F,0x96,0x21,0x11,0x64,0xED,0x5F,0x75,0x68,0xD6,0x05,0xBB, +0x5C,0x93,0xC6,0x3F,0x5C,0x59,0x41,0x6D,0x12,0xF3,0xB0,0xD4,0x7B,0x6C,0x34,0xB8,0x79,0x96,0x89,0xD8, +0xB2,0x9C,0x08,0x3F,0x82,0x9E,0x87,0x04,0x9F,0x9C,0x1F,0xCC,0x43,0xAD,0xFF,0x3E,0xD4,0x3F,0x85,0x97, +0x98,0xF1,0x76,0xD5,0x66,0xCF,0x0F,0xE8,0xDD,0xB0,0xF5,0x2E,0xA0,0x90,0x39,0x58,0x02,0x5C,0x86,0x11, +0x1E,0x80,0x5F,0xFA,0x04,0xC2,0xF1,0x66,0x5E,0xCE,0x31,0x62,0x40,0xE0,0x67,0x67,0x6F,0x40,0x9B,0xBF, +0xF9,0x12,0xA4,0x33,0xFC,0x32,0x6F,0xC1,0x33,0x6C,0xEB,0xC5,0x27,0x6C,0x26,0x83,0x58,0x91,0xC3,0x06, +0x97,0xE2,0x31,0xD3,0x3B,0x6D,0xE3,0xD7,0xD0,0x43,0x06,0x7C,0x5C,0x18,0xCF,0x72,0x7E,0x70,0x6B,0x81, +0xD5,0xC3,0xEF,0x9A,0x3E,0x90,0xB7,0x03,0x3D,0xC6,0x70,0xB6,0x1E,0xAB,0x8F,0xA5,0xAF,0x97,0xD4,0x36, +0xB7,0x4B,0x6C,0xB2,0x03,0xAC,0x28,0x2E,0x89,0xE4,0x62,0x70,0xF4,0x68,0x9E,0x13,0x54,0xCC,0x28,0xEC, +0x27,0x0F,0x56,0xFF,0x62,0xD5,0x17,0x5A,0x2F,0x57,0xE0,0x14,0xE6,0x8A,0x2A,0xD7,0x94,0xC1,0xD3,0xA4, +0xAF,0x08,0x2C,0x03,0x47,0xD1,0x39,0xC3,0xDB,0x89,0x22,0x8E,0x54,0x8A,0x9C,0xA3,0xDE,0xA8,0x3A,0x2E, +0x45,0xA9,0x72,0xE7,0x5A,0xE2,0x6F,0xF2,0xD9,0x44,0xAC,0xAE,0xF4,0xC0,0x02,0xDF,0x45,0x95,0x45,0x4D, +0x6F,0x85,0x04,0xBE,0xAE,0x28,0xDD,0xB6,0x95,0xCB,0x53,0xAB,0x7A,0x6B,0xF0,0x5C,0xF9,0x68,0x87,0x89, +0x89,0x81,0xB9,0xE0,0x62,0x26,0x3F,0x45,0xE5,0x09,0x5C,0xFF,0xDB,0xA9,0xA2,0x82,0xE2,0x84,0xF1,0xBD, +0x66,0x07,0x7A,0x06,0xC1,0x61,0x94,0xDE,0xB7,0xE3,0x22,0x4F,0xE6,0x2E,0x1F,0xAF,0x39,0xAF,0x5A,0x90, +0xA6,0xFE,0xA0,0x0E,0x37,0x0C,0xE0,0xCF,0x95,0x8E,0xB3,0x4E,0xF5,0x8D,0xA2,0xF4,0x3B,0x47,0x95,0xCA, +0xDF,0x3E,0x93,0x53,0x66,0x4C,0xB2,0x44,0x7A,0x50,0x61,0x79,0x5D,0xC7,0x85,0x79,0x3E,0x6C,0xE4,0x9A, +0x9C,0x2B,0x33,0x03,0xDF,0xD3,0x3C,0xA6,0x6D,0xB1,0xE5,0xC6,0x76,0xB2,0x8F,0x32,0xF9,0xB2,0xF5,0x93, +0xE0,0xF4,0xEF,0xCC,0xE5,0x90,0x7C,0x7E,0x9C,0x5C,0x24,0x07,0xFC,0x90,0x9B,0xBA,0x40,0x63,0x0B,0x1B, +0x98,0x7D,0xF8,0x23,0xF7,0x82,0x74,0xBD,0x00,0x98,0x13,0x12,0x60,0xD1,0x3B,0x03,0x0C,0xBA,0xEE,0x8E, +0x1E,0xFB,0xC4,0x32,0x98,0x37,0x2D,0x3B,0x34,0x6F,0xB4,0x2A,0xC0,0xDC,0x2F,0xE6,0x86,0x57,0x93,0x15, +0xCE,0x56,0xD2,0xB2,0x5F,0xB8,0xBC,0x3A,0x8B,0xDD,0x9C,0xB6,0x73,0xBB,0x32,0x30,0x2A,0x9B,0x10,0x43, +0xA3,0x21,0xA3,0x67,0xF5,0x90,0xC2,0x53,0xF0,0x35,0x8A,0x23,0x27,0x88,0x10,0x2E,0xB5,0x2C,0x3A,0x77, +0xFC,0xD7,0xB9,0x73,0x91,0x97,0xA7,0x62,0x17,0xD5,0xCF,0x64,0xC3,0xD4,0x24,0x55,0x93,0x55,0x8D,0xAC, +0x48,0x58,0xC9,0xDA,0x7D,0x34,0x39,0xED,0x49,0x6F,0x13,0x3E,0x76,0x9B,0xED,0x4D,0x0F,0x72,0xD8,0xF8, +0xFF,0xF4,0x99,0xB2,0x62,0x15,0x65,0x54,0xEA,0xC0,0xE5,0x5F,0x0B,0x5B,0x7F,0xBD,0x40,0xF9,0xD1,0xA3, +0xBB,0xA1,0x77,0x2F,0x04,0xB2,0x40,0x0E,0xC3,0x54,0x78,0x7B,0xBC,0x96,0x53,0x33,0x3C,0x67,0x3E,0xFF, +0x87,0x7F,0x0B,0xC0,0xDD,0x51,0xAC,0x5E,0x3C,0xEA,0x42,0xAD,0x59,0x3B,0x86,0xEB,0x3C,0x9F,0xC4,0x4F, +0x15,0x22,0xE7,0xAA,0xFC,0xB7,0xD4,0x4B,0xD1,0xB6,0x8F,0xE3,0x07,0x1D,0x25,0xDF,0xF6,0x01,0x57,0xAB, +0xA7,0x94,0x6B,0xAC,0xD5,0x36,0x36,0x54,0xE9,0xBD,0xA6,0x13,0x1A,0x40,0x5B,0x00,0x06,0xC3,0x8F,0x62, +0x33,0x50,0xA4,0x42,0xBF,0x2C,0xBD,0xA0,0x3A,0xBC,0xCA,0x01,0x31,0x28,0x0F,0x32,0x11,0x21,0x8B,0xF0, +0x17,0x03,0x67,0x73,0x8B,0xCE,0x61,0x41,0x84,0x4C,0xE1,0x4F,0x78,0x60,0x77,0x1C,0x35,0xE4,0xA9,0xDB, +0x7C,0x6F,0x3F,0x3E,0xA3,0x56,0x89,0x15,0xB5,0x25,0x4F,0x67,0x34,0x4C,0x8E,0x4B,0x03,0xCC,0x7E,0x75, +0x23,0x34,0x00,0xBC,0x00,0xA9,0xD5,0x82,0xA3,0x42,0xD2,0x82,0xB3,0x7F,0x88,0x6C,0x64,0x01,0xCA,0x26, +0x20,0x63,0xDF,0x96,0x53,0x0A,0x60,0x64,0xF4,0x09,0x07,0x74,0x7E,0xE7,0x98,0xD0,0x35,0x22,0x7F,0x8E, +0x61,0x5D,0x51,0x83,0xE1,0xF6,0xB5,0xD5,0xE9,0xE9,0x33,0xBD,0xB3,0x6A,0x00,0xF0,0x64,0x57,0xBB,0x65, +0xD2,0xA6,0x56,0x23,0x2E,0x4A,0xAB,0x3F,0x1E,0xD8,0xA6,0x57,0xEB,0xE3,0x81,0x6B,0xB1,0x19,0x82,0xD8, +0x55,0x4B,0x8A,0xED,0xBA,0x69,0xDA,0x89,0xD4,0xE4,0xD2,0x7C,0xD4,0xC4,0x04,0xD1,0x8E,0xC9,0x33,0x0D, +0x98,0x2A,0x6B,0x2D,0x21,0x5B,0x76,0x5E,0xEC,0x3C,0xD9,0x71,0x55,0x4F,0xB5,0x79,0x79,0xAA,0x88,0xDB, +0x65,0xE6,0x8C,0xB2,0x30,0xFA,0x82,0xDC,0x6E,0xA1,0x3D,0xA4,0x54,0x61,0xAA,0xEA,0x97,0xC1,0xB2,0x6E, +0x21,0x61,0x02,0x51,0xF7,0xEC,0x82,0x58,0xB2,0xA1,0x4F,0x87,0x78,0x8B,0x9A,0xFC,0xB2,0x17,0xD5,0x0E, +0x40,0x47,0xC1,0xAB,0x15,0xD8,0x93,0xBC,0x83,0xE5,0x99,0xCD,0x25,0x99,0x8B,0x65,0xEC,0xAF,0xF1,0xBB, +0x9D,0x36,0xE1,0x86,0xF4,0x7E,0x83,0x6C,0xE8,0x5A,0x02,0xB5,0x09,0x26,0xFF,0x00,0x68,0x32,0x27,0xC6, +0x43,0xA0,0x29,0xFF,0xA1,0x2D,0x73,0xD7,0xC8,0x4B,0x37,0xDA,0xD0,0x9E,0x9D,0xF6,0x27,0x1D,0x5C,0x00, +0xE6,0x72,0x5C,0x9A,0x45,0xED,0x28,0xFA,0x2D,0x6E,0x4C,0xF8,0x45,0x59,0xBE,0x21,0xA0,0x47,0x6A,0x61, +0x21,0x0C,0x1E,0x66,0xCD,0x98,0x59,0xF7,0xF7,0x1F,0x5F,0x35,0x4C,0xD2,0xD5,0x44,0x41,0xA3,0xC7,0x22, +0x01,0xD2,0x2C,0xFD,0x82,0x4F,0x50,0x60,0x1D,0xC0,0xB4,0x58,0x86,0xC6,0x92,0x36,0x6F,0xB1,0x86,0xBC, +0x96,0xFA,0x1A,0x1C,0x23,0x38,0x1C,0x45,0x07,0xE7,0x77,0xED,0x5B,0x27,0x34,0xD5,0x1D,0x14,0x8C,0x63, +0x17,0x7D,0xB5,0x53,0x6A,0x68,0xB3,0xE0,0x80,0x61,0xCC,0x19,0xB7,0x1A,0x85,0x71,0xF5,0xDC,0x18,0x41, +0xBA,0x12,0x10,0x8D,0xD1,0x71,0x42,0xAA,0x42,0x59,0xAE,0x53,0xCD,0x1B,0x50,0x6C,0x29,0xB6,0x22,0x03, +0x38,0x79,0xA9,0x85,0x1A,0x59,0xBE,0xAC,0x31,0x98,0x06,0xF6,0x25,0x78,0xC5,0x72,0x51,0xDB,0x43,0x00, +0x1C,0x8B,0x6C,0x29,0x9E,0x24,0xD1,0xEB,0x42,0xFA,0xBB,0x43,0xD2,0x34,0x40,0xA8,0xEF,0xCB,0xAB,0x79, +0x76,0xD6,0x7E,0xD8,0x89,0x1A,0x5C,0xAC,0x78,0x91,0xA9,0x9B,0x52,0x30,0x17,0xF3,0x16,0x67,0x1F,0x5A, +0xE2,0x62,0xD6,0xC5,0x08,0xAD,0x4B,0x8B,0x5F,0x3F,0xC6,0xE8,0x9F,0x9C,0x69,0x66,0x0B,0x17,0x51,0x25, +0x7C,0xF7,0xB0,0x29,0xEE,0xAA,0x35,0x9B,0x93,0x9F,0x77,0xA9,0xEB,0x14,0x95,0xDC,0x1C,0x24,0x9B,0x29, +0x95,0x33,0xE5,0x15,0xFF,0x30,0x5E,0x05,0x02,0x30,0x23,0x82,0x7E,0x7C,0xA7,0xC0,0xAD,0x21,0x51,0x66, +0x3A,0xA2,0x20,0x03,0x27,0xA3,0x57,0x94,0xE5,0xA3,0x2D,0x23,0x75,0xC5,0x94,0x71,0x53,0x22,0x87,0x87, +0xE2,0xCA,0x99,0xF9,0x38,0xAF,0x69,0x26,0x0C,0xD3,0xE7,0x71,0xD2,0x21,0xA9,0xD5,0x93,0xC1,0x91,0xED, +0x39,0xAE,0xCE,0x22,0xA9,0xE7,0x70,0xF7,0xCD,0xA1,0xF6,0x40,0xA5,0xCA,0x1A,0x59,0x2E,0x70,0x2F,0xE3, +0x40,0x5C,0x48,0x06,0x1A,0xFF,0x33,0x69,0x01,0x5C,0xEB,0x30,0x36,0x45,0x99,0x04,0xB8,0xBE,0xD8,0x6E, +0xB6,0xFE,0x35,0x67,0xFD,0x84,0xF0,0x35,0x69,0xBD,0xAA,0x7C,0xF6,0xDD,0xF2,0x01,0x94,0xA9,0x07,0x40, +0xBF,0x66,0x45,0xBF,0x59,0x6A,0x6C,0x01,0x3C,0x85,0xFA,0x91,0x3E,0xF6,0xF0,0x79,0x64,0xCB,0xDD,0x49, +0xE1,0x1E,0x2A,0x39,0x62,0x19,0x60,0x65,0x5A,0x4B,0x52,0x09,0x2F,0x8A,0x94,0x7A,0x7D,0x76,0x73,0xDA, +0x5F,0x64,0xEA,0xBF,0x71,0x1C,0x5E,0x78,0xA6,0x29,0x5C,0x71,0x4E,0x75,0x15,0x9B,0xB0,0x67,0x18,0xAB, +0xBA,0xC6,0x55,0xBA,0x15,0xC8,0xD4,0x6D,0xFF,0x54,0xF6,0xDB,0x8F,0xD0,0x6D,0xC3,0xDD,0x57,0xF2,0x0C, +0x3A,0xCE,0x84,0x66,0xE1,0x51,0x79,0x96,0x92,0x2D,0xE4,0x63,0xA1,0xAE,0xD2,0x67,0xA8,0x9F,0xEF,0x21, +0xDD,0x72,0xFE,0x69,0x23,0xDC,0x0B,0x1C,0xA0,0x40,0x39,0xF0,0xBD,0x8C,0x0F,0xDD,0x9A,0xA6,0x4D,0x5E, +0x2D,0xC7,0xBC,0xD8,0x5C,0x42,0xD3,0xE7,0x28,0xC1,0xA3,0x4F,0x7E,0xB4,0x22,0xF5,0x2A,0x64,0xEE,0xB8, +0x01,0xE7,0x1A,0xB7,0xA9,0x36,0x24,0xF5,0x58,0x35,0x01,0x4A,0x53,0x1D,0x23,0x35,0x1B,0x5D,0xBA,0x82, +0xCE,0x80,0x07,0xF4,0xC2,0xD4,0xC7,0xC0,0x9E,0xD7,0xF8,0xC5,0x09,0x50,0xBD,0x43,0xB1,0x3F,0xB7,0x9B, +0xB2,0x11,0xA2,0x5C,0x15,0x01,0x26,0x34,0x93,0xFA,0x13,0xBB,0x28,0x35,0x95,0x68,0xB3,0x10,0x14,0x80, +0x44,0xCC,0x63,0x48,0x1C,0x22,0x34,0x2A,0x7A,0xD9,0x06,0xF0,0x5A,0x39,0x12,0xCB,0x67,0x75,0xCA,0x2B, +0x57,0xC4,0xAC,0xA7,0x9D,0x8E,0x2B,0xB0,0x5F,0x84,0xEA,0x81,0x57,0xB9,0xA5,0xF2,0xD2,0x04,0x9E,0xCB, +0x03,0x69,0xBC,0xC3,0x11,0xAD,0xB5,0x36,0xFA,0x79,0xAC,0xDC,0x53,0x09,0x29,0xB5,0x50,0x87,0x12,0x90, +0x7D,0x86,0x1B,0xC6,0xE4,0x65,0x05,0x75,0x3E,0xF8,0xBE,0x4A,0x1A,0xDA,0x0C,0xEC,0xCF,0xDD,0x82,0xC8, +0xD7,0xBD,0xE0,0x5A,0xF1,0x9A,0x02,0xE9,0x1D,0xDB,0xD0,0xB3,0xCC,0x6F,0xC3,0xFD,0x6B,0x29,0xC0,0x4B, +0x7B,0x5A,0x71,0xDD,0xAA,0x59,0x9F,0x74,0x31,0x4C,0x0F,0x45,0x40,0xD7,0xC9,0x5B,0x01,0x98,0x79,0xD1, +0x0C,0x44,0xD1,0xB3,0xBB,0x78,0xF8,0x7B,0xEF,0xC0,0x51,0x3B,0xBB,0x3A,0xDE,0x35,0x28,0x75,0xAE,0xCA, +0x41,0x43,0x2F,0x6C,0x2A,0x11,0xCE,0x11,0x4D,0xBC,0x56,0x9D,0x1C,0x0B,0xE6,0x66,0x0C,0x2D,0x40,0xD2, +0x07,0xAD,0xF8,0x8C,0xD8,0xBF,0x12,0x49,0x67,0x09,0xD9,0xE3,0x31,0x48,0x15,0xEA,0xEF,0x7C,0x4F,0xA8, +0x20,0xF6,0x8D,0x9B,0xA3,0x32,0x57,0x3F,0xF3,0xF2,0x80,0x7F,0xB4,0x38,0xA4,0x77,0xDB,0xFF,0x3A,0xF3, +0x78,0xFF,0x47,0x08,0x16,0x48,0x2A,0xC8,0xE4,0x8F,0x7C,0x5B,0x8A,0xEB,0xA4,0x95,0xEA,0xD0,0x5D,0x17, +0x91,0xD3,0x41,0x13,0xA4,0x9E,0x90,0x38,0x62,0xCF,0x58,0x1A,0x65,0xDD,0x08,0xC5,0xD8,0x60,0x50,0xD7, +0x40,0x60,0xB1,0xCF,0xA5,0x74,0x50,0x2A,0x24,0x0A,0xD0,0x3E,0xF6,0x63,0xF5,0xAE,0xC0,0xE3,0x21,0x0C, +0x76,0x71,0x8D,0xA0,0x64,0x1F,0x99,0x73,0xB7,0xDB,0x54,0x65,0x44,0x9D,0x7C,0xE0,0x72,0x1E,0x11,0xBC, +0xE6,0xFA,0x67,0xB2,0x03,0xD8,0x5C,0xF4,0x24,0x93,0x59,0x34,0x5F,0x64,0x4E,0x27,0xA1,0x25,0xC0,0x23, +0xA1,0xED,0x94,0x27,0xCA,0xBD,0x8B,0x67,0xD4,0x67,0xE5,0x22,0x94,0xF1,0x31,0x57,0xDE,0x3C,0x99,0x90, +0x3D,0x05,0x89,0x41,0x51,0x5B,0x04,0xF9,0x70,0x28,0xA2,0x91,0x1E,0x5B,0xA9,0xB7,0xAF,0x4C,0x2A,0x94, +0xD8,0xEA,0x8E,0xB8,0x21,0xD9,0x9D,0x28,0xFE,0xE4,0xE0,0xD0,0xE1,0x84,0x5A,0x90,0xD6,0x63,0xDC,0x0D, +0xAA,0x8B,0xA7,0xE5,0x20,0x87,0x11,0x5B,0xFB,0x6F,0x3F,0x5F,0x12,0xBB,0x35,0x20,0x72,0x67,0x67,0x8F, +0x91,0x23,0xF7,0xAB,0xDD,0x43,0xDB,0x7A,0xEA,0xC5,0x82,0xE4,0xED,0x04,0xE5,0x3A,0xE5,0xF7,0xC2,0xD0, +0x82,0x43,0x56,0x0E,0xB8,0x2C,0x20,0xDC,0x3D,0x81,0x32,0x54,0xE6,0x62,0x7E,0x85,0xCA,0x16,0x25,0x94, +0x7C,0x20,0xC3,0x4B,0xB8,0x15,0xC3,0xA5,0xB5,0xF3,0x5D,0x9A,0x8F,0x95,0x14,0x85,0x22,0x23,0xA7,0xDD, +0xBD,0x31,0x92,0xE6,0x3E,0x90,0xAE,0x94,0xC9,0xF4,0x4C,0x9B,0xC9,0x22,0xFC,0xA0,0x44,0xBA,0xBA,0x48, +0xEE,0x72,0x10,0x84,0x40,0x11,0xCE,0xA6,0xC3,0xA9,0x52,0x72,0x69,0x94,0xD5,0xBE,0xD4,0x53,0x0C,0x2D, +0x04,0x13,0xAE,0x40,0x57,0x72,0x5C,0xC0,0x05,0xCD,0x54,0x73,0xB3,0xAB,0x97,0x81,0x8C,0x32,0xF4,0x65, +0xB0,0x69,0x1F,0x80,0x5A,0x08,0x49,0x45,0xCF,0x5D,0x56,0xF9,0x08,0x29,0x5A,0xA4,0xD1,0x32,0x1D,0xDB, +0xC7,0xAB,0x40,0xE4,0x10,0x76,0x94,0x18,0x0D,0x8F,0xB5,0x24,0x0C,0x6F,0x9D,0x17,0x20,0xF5,0x94,0xCC, +0x73,0x3A,0xC6,0xDE,0x0A,0xD8,0x85,0x66,0xD6,0x83,0xE9,0xB3,0x78,0x54,0xA5,0x8E,0xBE,0x3B,0xA2,0x1C, +0x11,0x23,0xA2,0x83,0x0D,0x1A,0x8D,0x7C,0x8B,0x0C,0xF7,0x57,0x2A,0x3F,0x22,0x75,0xCC,0xC8,0x87,0xF7, +0xF5,0x76,0x8D,0xEE,0xDB,0x76,0x46,0x20,0x93,0x32,0x4E,0xE8,0x5B,0xA1,0x16,0xED,0x0F,0x14,0xBE,0xEE, +0xA6,0x9F,0x86,0x99,0x19,0x98,0xE1,0xC6,0x4B,0xB4,0x89,0x4A,0x4A,0xCD,0x60,0xC9,0xF8,0x01,0x86,0x09, +0x8E,0x3E,0xAF,0x57,0xF8,0x17,0xCE,0x9F,0x1D,0xDC,0x0B,0x59,0x81,0xD0,0x41,0xDA,0x8A,0xBE,0x99,0xFE, +0x08,0xAD,0x25,0x42,0x02,0xE0,0x74,0x3C,0x3E,0x07,0xBE,0x24,0x11,0x73,0xBA,0x00,0xF8,0x1E,0x57,0xAC, +0x76,0x7D,0x10,0x30,0x2F,0x5C,0x29,0x58,0x1B,0x5D,0x07,0x77,0xCE,0x82,0x5A,0x9E,0x99,0x5D,0x75,0xBF, +0x89,0x9E,0xC6,0x2B,0x35,0x25,0x47,0xEC,0xEB,0x9C,0x87,0xD5,0x78,0x42,0x16,0xC2,0x4E,0x73,0xC7,0xC9, +0x52,0x45,0x5E,0x7D,0xCB,0x25,0xC9,0x15,0x03,0x32,0x79,0x4D,0xA1,0x36,0xE0,0x74,0xF3,0xA3,0x32,0xE4, +0x20,0x4D,0x08,0xB5,0x20,0xAF,0x28,0xF4,0x36,0xDD,0x21,0xD6,0x51,0x0A,0x61,0x11,0xAC,0x70,0x40,0xDE, +0xB5,0x2A,0xD9,0x8B,0x21,0x04,0x66,0x0A,0x92,0xCA,0xCB,0x83,0xA0,0x90,0xF0,0x41,0x16,0xE2,0x91,0x1B, +0xA7,0x6E,0xF0,0x07,0x10,0x52,0xAB,0xC5,0x2C,0xB9,0x38,0xDF,0x35,0x2E,0x68,0x4B,0x00,0xF7,0xBB,0x46, +0x25,0x6F,0x11,0x9A,0xDA,0x86,0xA2,0x66,0xF1,0xA6,0xB8,0x50,0x37,0xEB,0x10,0x11,0xFE,0xFF,0xFC,0xF6, +0x78,0xD4,0x40,0xE9,0x45,0xA8,0x75,0xAB,0x66,0x4D,0xDA,0xA1,0x86,0x1B,0xE8,0xCC,0xE4,0x56,0xE5,0x4B, +0xE5,0xAD,0xD6,0xC0,0xF3,0x0C,0x0E,0xA7,0x17,0xB8,0xB9,0xCF,0xCB,0x3C,0x1A,0x37,0x9F,0x6A,0x62,0xAA, +0x6C,0xC8,0x32,0x2E,0x42,0xE8,0x2A,0x2E,0xAD,0x07,0xEA,0xA7,0x55,0xF2,0x73,0x54,0x6E,0xA9,0x2A,0x3F, +0x80,0xB2,0x58,0x32,0x4C,0x09,0x8B,0x48,0xD0,0x8B,0xCB,0x2E,0x0B,0x0B,0xB7,0x40,0xBE,0xEB,0x6A,0x08, +0x29,0xA4,0x73,0x83,0x59,0xF1,0xD3,0x13,0xEE,0x1A,0x72,0x69,0x62,0xC7,0x01,0xCD,0xA6,0xD0,0xC4,0x78, +0x20,0x5D,0x42,0xA0,0x7B,0x9A,0xFC,0x87,0x8C,0xA6,0xF2,0xEE,0x29,0x1A,0x92,0x25,0x52,0xE3,0x7E,0x58, +0x4D,0x96,0x52,0xC5,0x7C,0xA9,0xA7,0x7D,0x6D,0xCE,0x43,0x0E,0xDF,0xF2,0x6B,0x5A,0x88,0xFD,0xF7,0x08, +0xAD,0x28,0xB3,0xEE,0xBE,0x8C,0x5F,0x1C,0xC9,0x98,0x01,0xDF,0xB9,0x03,0x2B,0x7F,0x8B,0xA7,0xFF,0xFF, +0xC4,0xFA,0xC5,0xB6,0xBE,0xEB,0x20,0x80,0x62,0x0D,0x1E,0x15,0x4C,0x7F,0xCB,0xD0,0xB2,0x0F,0xB4,0x61, +0x72,0xA3,0x3E,0x83,0xDE,0x4C,0xFC,0xBE,0x14,0xF3,0x02,0x7B,0x63,0x82,0x6D,0xB4,0x76,0xC1,0x7B,0x61, +0xEC,0x17,0xFD,0x83,0x33,0xA3,0x99,0xDC,0x2E,0x88,0x49,0x67,0xBC,0xB0,0xC1,0x08,0xA4,0x81,0x7C,0xD1, +0x86,0x3D,0x56,0x73,0xA5,0x06,0xE4,0x85,0x10,0xFA,0xA4,0x6E,0x8D,0x9E,0xBC,0xC2,0xB3,0x36,0xCF,0x66, +0x46,0xC4,0x0B,0x64,0xEF,0xFA,0x24,0x52,0x14,0x30,0xB4,0xD2,0xBF,0xF5,0x7A,0x81,0x3B,0x52,0xD1,0xA9, +0xD6,0x76,0x23,0x47,0x90,0x92,0x85,0xC5,0xCB,0xBB,0x7D,0xE6,0xC6,0xD5,0xCD,0xDA,0x55,0xF0,0x53,0xEA, +0xC3,0x58,0xB4,0xCC,0x52,0xC8,0x5C,0xD2,0x06,0xD1,0xFD,0x15,0xF1,0xD6,0x7F,0xAC,0xC9,0x11,0x1E,0x74, +0x2C,0xF5,0x7B,0x95,0x7B,0xC3,0xB4,0xE9,0xB6,0x49,0xAE,0x12,0xC4,0x28,0x51,0xE0,0xEF,0x66,0x76,0x3E, +0x98,0x96,0xE6,0xBA,0xFA,0xE8,0x23,0xEB,0xB4,0x51,0xD8,0xC8,0x41,0x0C,0xD9,0x2F,0xDA,0x8E,0x4D,0x47, +0x1C,0x37,0xBD,0x6D,0x2D,0xA9,0x98,0xA3,0xCE,0xBB,0x3E,0xC4,0x4A,0xD8,0xEF,0x97,0xA6,0x56,0xDC,0x8D, +0xEC,0x3C,0x3F,0xCE,0xB3,0x11,0x5B,0xEF,0xCD,0xC7,0x67,0x6C,0xE7,0xF2,0xEA,0xFE,0xCE,0x86,0x97,0xAF, +0x24,0xAB,0xC6,0x12,0x40,0x21,0x51,0x9C,0xA9,0xF5,0x6F,0xC3,0xC5,0x85,0x2E,0x40,0xDD,0xBA,0x94,0x8D, +0x11,0xCE,0xCF,0x70,0x7C,0xC2,0x59,0x2D,0x8B,0x9E,0xA7,0x6B,0x8C,0x08,0x87,0xF3,0x12,0x90,0xF9,0x8D, +0x7D,0xC3,0x08,0xE2,0x06,0x0B,0xDE,0x54,0x68,0xD5,0x12,0x53,0x71,0x2C,0x06,0xD7,0xD4,0xED,0xC8,0x38, +0x01,0x07,0x13,0x83,0xF0,0x8E,0x1E,0x58,0x61,0xD1,0xA0,0xD4,0x15,0x67,0xDD,0x85,0xAF,0xCB,0xD3,0x3B, +0xBE,0x60,0x73,0x31,0xC3,0xE2,0xC3,0x0B,0x3B,0x06,0x29,0x4D,0x20,0xFC,0xDD,0xE6,0xB7,0x8C,0x54,0x20, +0xF0,0x58,0x33,0xF2,0x70,0xE3,0x26,0x25,0x01,0xD4,0x73,0xA6,0x7A,0xA7,0xD7,0x1B,0x02,0xEB,0x04,0x97, +0x7C,0xC9,0x47,0xD4,0x69,0x5A,0x1C,0xA7,0x3D,0x85,0xBF,0xB0,0x23,0xCE,0x08,0x07,0x7D,0xB0,0x81,0xF0, +0x65,0x87,0xBF,0xF5,0x67,0x85,0x40,0x12,0xF2,0x28,0x81,0xF6,0xF4,0xC9,0x4B,0xB3,0xCB,0x16,0x5F,0x56, +0x30,0x21,0x52,0xF5,0xA9,0x58,0x09,0x9D,0xD7,0xBB,0xC6,0x8D,0x06,0x82,0x93,0x7F,0x28,0x44,0x21,0x4E, +0xA3,0x71,0xEA,0xA8,0x3E,0xF5,0x1A,0x99,0x03,0x4B,0x4A,0xA8,0x7D,0x89,0x37,0x3D,0xE8,0xB6,0x5A,0xA1, +0x54,0x2B,0xC4,0x29,0x29,0x88,0xE5,0x68,0x9B,0xCA,0xD3,0x0D,0x87,0x4C,0xA4,0x11,0x28,0xDB,0x0A,0x19, +0xBA,0x70,0x9A,0x1F,0x3E,0x9E,0x43,0x28,0xE9,0xC9,0x49,0x8E,0xAA,0x6B,0x62,0x27,0x87,0x81,0x68,0x8B, +0xBB,0x42,0x2D,0x98,0x57,0x0E,0x7E,0xE9,0x8F,0x0E,0x70,0xCB,0x73,0xA2,0xF0,0xBE,0x99,0xE1,0x00,0x21, +0x4D,0xEE,0x79,0xCC,0x5D,0x87,0x25,0x75,0x61,0x4D,0xA1,0x07,0x9B,0x7F,0x05,0x83,0xB2,0xF1,0xBA,0x86, +0x31,0xCD,0x1F,0xAA,0xF7,0xAB,0x21,0x3F,0x6C,0x4A,0x22,0x40,0x20,0x7E,0xF3,0xF9,0x94,0xA4,0x22,0xF4, +0x31,0x52,0x2E,0x57,0x91,0x96,0x96,0xD2,0x53,0x7B,0x50,0x57,0x40,0xD0,0xD3,0x10,0x9D,0xD8,0xB4,0x07, +0x4D,0x3B,0x92,0x08,0x67,0xC0,0x4E,0x5C,0x02,0x04,0x1A,0x1C,0xD7,0x65,0xD5,0x07,0x75,0xBC,0xED,0xA9, +0x47,0x10,0x04,0xA7,0x53,0x30,0xBC,0xE0,0xDA,0x11,0xDD,0x11,0xD7,0x94,0xA2,0x35,0x9C,0x59,0x2A,0x05, +0x05,0x10,0x42,0xB2,0xC9,0xA5,0x70,0x26,0x16,0x41,0x02,0x16,0x9D,0x38,0xC5,0x60,0x3D,0xCA,0x1C,0xA7, +0x6B,0x98,0x9E,0xEA,0x1D,0x77,0x62,0xDC,0x03,0x15,0xF4,0x0A,0xCE,0xDA,0x3B,0xFD,0x4B,0x67,0x97,0xEB, +0x9C,0xC3,0x33,0xCD,0xE3,0xA6,0xDD,0x41,0xF4,0x9C,0x33,0xFC,0x48,0x86,0xD2,0x48,0x97,0x0B,0xA6,0x8E, +0x6C,0x81,0x7D,0x50,0x39,0x7A,0x5D,0x27,0x2E,0xA1,0xDF,0x97,0xDD,0x54,0xD6,0x54,0x66,0x5B,0x56,0xD0, +0xB3,0xD5,0xCE,0xE8,0xDC,0x5B,0xE9,0x6C,0xB9,0x26,0xA6,0x28,0xCE,0x14,0xA9,0x90,0x06,0x7B,0xE4,0xFB, +0x43,0x00,0x43,0x76,0x35,0xC7,0xD1,0xB0,0xDB,0x41,0x0B,0x42,0xCF,0x7A,0xC2,0xC8,0x8B,0xCB,0x14,0x17, +0xBA,0x89,0x47,0xA8,0x6C,0xB9,0x44,0x92,0xFF,0x82,0x78,0xF4,0xDE,0xAD,0xF9,0x87,0x87,0x5F,0x1E,0xF9, +0x6C,0x9F,0xA8,0xEB,0x87,0xDD,0xCC,0x86,0x8F,0xF0,0xE1,0xA7,0x02,0x36,0x4F,0xFA,0xB0,0xF0,0x7A,0x78, +0x34,0xB6,0x76,0xE5,0xBA,0x1A,0x27,0xE1,0x63,0xC3,0xC5,0xF8,0xD2,0xFE,0x77,0x12,0x0F,0xDD,0x8B,0x87, +0xA5,0x01,0x4F,0xBE,0x08,0x7D,0x4A,0x3E,0x29,0x5F,0x24,0xDA,0x5A,0x13,0x9A,0x62,0x4C,0x83,0x3C,0x82, +0x72,0x56,0xB0,0xD1,0x5B,0xDB,0xEF,0x66,0x52,0x50,0x71,0x14,0xE1,0x3B,0x8E,0xB7,0x69,0x05,0x20,0x3E, +0xE0,0x40,0xAD,0x71,0x97,0x61,0x22,0x07,0x0C,0x4F,0x02,0xA6,0x48,0xE1,0x6F,0x45,0x87,0xCD,0xF1,0x58, +0x94,0x4D,0xF0,0xBC,0xBA,0x81,0x79,0xB7,0x7C,0x52,0x41,0xD5,0x60,0x49,0xF1,0x32,0xBE,0xD2,0xB0,0xE2, +0x84,0x48,0xD8,0xB9,0x94,0x68,0x9C,0xFC,0x47,0x24,0x8E,0xC6,0xFA,0xE9,0x50,0xAD,0x6F,0xC6,0x88,0x00, +0xD4,0xA8,0x3A,0x81,0x73,0x65,0x2C,0x05,0x75,0x43,0x8B,0x21,0x71,0xE3,0x8F,0x25,0xEA,0x59,0xC2,0x4A, +0x2F,0xD7,0x8F,0xC6,0x5B,0x40,0x17,0x6B,0x6E,0xA4,0x3A,0x10,0x99,0x78,0x68,0x71,0x00,0x4A,0x29,0xB7, +0x96,0xE4,0x8D,0x65,0xD1,0x54,0xF2,0x79,0x00,0xC4,0xB5,0xC2,0xF4,0x87,0xB0,0x5C,0xB7,0xB9,0xE2,0x78, +0xF6,0x12,0xFA,0x6C,0xD7,0x58,0x63,0x11,0xE8,0xC0,0xAB,0xF9,0x9F,0xE9,0x9A,0x55,0x0E,0x8E,0x99,0x9C, +0xBE,0x05,0x0D,0xE6,0xEF,0x6A,0x95,0x06,0xEC,0x47,0x2B,0x08,0xE4,0x63,0xD5,0x22,0x10,0xAD,0xBA,0x44, +0x2F,0x8B,0xB3,0x36,0x34,0xFA,0xB1,0xB9,0x32,0xE0,0x5D,0xCB,0xE1,0xAA,0x0C,0xCB,0xA5,0x8F,0x63,0x7A, +0xA7,0x80,0xF9,0x29,0x25,0x5B,0x5E,0x21,0xBC,0x20,0x44,0x52,0xC2,0x6B,0xEA,0x52,0x2B,0x50,0x5D,0xEF, +0x50,0x21,0x49,0x99,0x6B,0xA1,0x0D,0x42,0x25,0xDF,0x91,0x6B,0xDD,0xDE,0x15,0x62,0xAD,0x62,0x8B,0x09, +0x5C,0xA0,0xE7,0xBB,0x9D,0x8D,0x17,0xED,0xC3,0xE5,0xF0,0xF1,0x1D,0x99,0x9A,0xBB,0x97,0xD5,0xF4,0x53, +0x4B,0x92,0x97,0x22,0x12,0xEB,0xD3,0xF2,0x45,0x38,0xCC,0xC0,0xFA,0xBC,0xE8,0x1D,0x0E,0x52,0x67,0x99, +0x73,0x48,0xB4,0x6B,0x54,0xDF,0x9B,0x27,0x17,0xDE,0x6C,0x01,0xC0,0x79,0xEE,0x88,0x8B,0xF0,0x30,0xF3, +0xB1,0x3E,0xCB,0x37,0x37,0x7F,0x7D,0xC1,0x0E,0x32,0x72,0x5A,0xF0,0xA8,0x1D,0x39,0xCF,0x05,0x2A,0x1E, +0xCF,0xF6,0x7C,0xEF,0x9E,0xE5,0x92,0x47,0x83,0x52,0x6D,0xD0,0x63,0x49,0xBC,0xF1,0x96,0x1A,0x28,0xED, +0x41,0xD1,0xFA,0x72,0x38,0x4B,0xD6,0xEE,0x16,0xC7,0x62,0xBD,0x17,0x19,0xB5,0x57,0x38,0x02,0xA5,0x27, +0xFC,0xF2,0xDD,0xA4,0xA9,0x4B,0xB9,0xE9,0x95,0xAC,0xFF,0xE0,0x9B,0xF4,0xF5,0xFB,0x4A,0x46,0x3F,0x4D, +0xEE,0x18,0x4C,0xEC,0xF6,0x49,0x08,0x9F,0xE1,0x7E,0xB6,0xDC,0x87,0x03,0x37,0xE5,0x44,0xA0,0xD6,0xB9, +0xD4,0xBA,0xB9,0xC9,0x40,0x66,0x62,0x44,0x9C,0x56,0x2F,0x8E,0x4D,0x35,0xEF,0x9A,0x55,0x4B,0xAF,0xEB, +0xE8,0xF7,0xBC,0x53,0x40,0xB8,0x77,0x9E,0xC6,0x82,0xD7,0x6F,0x3B,0x1A,0x64,0xBB,0xD2,0xAA,0xAE,0xCC, +0xCD,0x97,0xA2,0x00,0x9D,0x63,0x62,0x90,0xB3,0xDE,0x50,0x4A,0x48,0x9E,0x89,0xEC,0x36,0x81,0xEE,0x27, +0x51,0x10,0x90,0x7B,0xEB,0xFE,0x4D,0x5B,0x69,0x2F,0x51,0x85,0xA2,0xBC,0xCB,0x59,0xAF,0x96,0x4C,0x4A, +0x2D,0x81,0xA5,0x91,0x16,0x9D,0xE0,0x14,0x57,0xC4,0x94,0x2A,0x9B,0x60,0x43,0xAC,0x95,0x19,0xF3,0x7F, +0x89,0x72,0xFF,0xFF,0xFF,0xFF,0xAC,0xE8,0xC6,0x4D,0x78,0x8C,0xB5,0xF3,0x2E,0xC2,0x28,0x91,0x30,0x56, +0x32,0x8C,0x12,0x12,0xEA,0x0E,0x87,0x76,0x1F,0x43,0x0F,0xC3,0x39,0x2F,0xE0,0x46,0xD3,0x7D,0x67,0xCD, +0x69,0x38,0x79,0x21,0x12,0x26,0x6F,0x1D,0x21,0xE1,0xEF,0x22,0x71,0x23,0x48,0x77,0xE0,0x07,0xC3,0xA8, +0x9F,0x62,0x27,0x0D,0x03,0xBC,0xAC,0xD7,0xF5,0x65,0x38,0x22,0x8F,0x82,0x3F,0x34,0x16,0x2D,0x48,0x71, +0x60,0xD6,0x89,0x5E,0xF7,0x6D,0x7D,0x2F,0x30,0x45,0xA8,0x1E,0xAB,0x28,0x6D,0x16,0xBC,0x4C,0xCC,0x9B, +0x50,0x25,0xC1,0x65,0x84,0x96,0x45,0xFA,0xD2,0xE6,0xD1,0x62,0xA4,0x5D,0x51,0x66,0xE5,0x24,0xD9,0xAE, +0x76,0x08,0xCB,0xB7,0x11,0x3B,0xDD,0x99,0xA8,0x08,0xFD,0x99,0xD5,0x46,0x64,0xEA,0x2C,0x45,0x3A,0xF3, +0x08,0x65,0x2C,0x11,0x8A,0x48,0xB2,0x75,0xF9,0xE2,0x1B,0xE8,0x08,0xD8,0xF2,0x38,0x96,0x84,0xE5,0x1F, +0xE8,0xB5,0x41,0x3C,0xC8,0xF4,0xFC,0x37,0xB8,0xAA,0x2C,0xEF,0x34,0xD7,0x83,0xC1,0xFF,0x47,0x17,0xD2, +0xFC,0x67,0x75,0x1F,0x68,0x88,0x5A,0x8E,0xEB,0x86,0xE3,0x31,0x34,0x04,0xB2,0x35,0xFD,0x6D,0xF6,0x37, +0xA9,0x4D,0xFB,0x2E,0xF8,0xAC,0x6C,0xA5,0x2B,0x6C,0x88,0x84,0x0D,0xE7,0x9A,0x7F,0xAA,0xA2,0xC2,0x55, +0x99,0x31,0x3A,0x32,0xFA,0x40,0x80,0x83,0xD3,0x06,0x3D,0x4E,0x2B,0xA1,0xC5,0xC9,0xBA,0x2E,0x4B,0x6D, +0xE3,0xD8,0xD5,0x8B,0xE9,0x4B,0x9F,0x7D,0x16,0xF2,0xFE,0x3F,0x14,0xA9,0x11,0x9B,0xEA,0x0F,0x82,0x8C, +0x7E,0x64,0x56,0xCB,0xCB,0x74,0xD6,0xCA,0xDB,0x54,0x0E,0xA2,0xD3,0xFD,0x8E,0xA6,0xE2,0x31,0x6A,0x2C, +0xC8,0xA2,0xF2,0x92,0xD0,0xB2,0x8C,0xD2,0xDA,0x2E,0x35,0x47,0xFD,0x30,0x95,0x46,0x49,0x51,0x15,0x75, +0xA3,0x83,0xC3,0xD1,0x60,0x44,0xEB,0xA3,0x11,0xF1,0x17,0x93,0x12,0xBE,0x24,0x66,0x3D,0x72,0x22,0x3E, +0x82,0x57,0xC7,0xC9,0x99,0x92,0x7A,0xA5,0xFE,0x1B,0x8C,0xFD,0xD3,0xCB,0xD1,0x62,0xE2,0x3F,0xF9,0xBB, +0xD1,0x11,0x75,0xB2,0x60,0xE5,0xE5,0xA3,0x92,0xC4,0x54,0xF4,0xEB,0x0E,0xE4,0x0B,0x40,0x50,0x77,0xE5, +0x20,0x0A,0x05,0x25,0x0E,0x30,0x6D,0x1E,0x17,0xA0,0xAD,0x67,0x72,0x1D,0xDD,0xB3,0x5C,0x72,0xB5,0x57, +0x22,0xFA,0x3D,0xBB,0x52,0x5A,0x65,0xB2,0x2D,0x7F,0x52,0xF8,0xA8,0x0E,0xBE,0x5C,0x64,0x93,0x6F,0xD0, +0xFA,0x19,0xE8,0xAA,0x99,0xFB,0xF5,0x90,0xA6,0x54,0xB0,0xA9,0x51,0x34,0x60,0xBE,0x88,0xDA,0xA6,0x42, +0xD5,0x74,0x97,0x61,0x32,0x57,0xFF,0xAD,0x58,0x7B,0x01,0xCB,0x88,0xB3,0xBA,0x5E,0x74,0x3B,0xF0,0x71, +0x6B,0x56,0x9D,0x05,0x52,0x7F,0xB6,0x4A,0x65,0x1A,0x60,0x7A,0x33,0x38,0x7E,0x97,0x8D,0x0C,0xFE,0x70, +0x99,0x3A,0x24,0xE9,0x7E,0x1E,0x56,0xEF,0x4D,0x7A,0x63,0xDD,0x8A,0x94,0x62,0x5E,0xAA,0xD0,0x04,0xFC, +0x6D,0x7C,0x9E,0xE0,0x7D,0x7C,0xF8,0x2F,0x8E,0x18,0xE7,0x2C,0x1B,0xC1,0x47,0xE9,0xEB,0xFE,0xFE,0x87, +0x5B,0xF9,0x4B,0xB9,0xEF,0x92,0xF7,0x42,0x39,0x23,0x7E,0x7B,0x7A,0x42,0x91,0x83,0xFD,0x7E,0x04,0xF1, +0x88,0xC1,0x75,0x76,0x94,0xBF,0xA0,0xD1,0xC8,0xCD,0x90,0x1E,0xF7,0x6F,0x90,0xE8,0x15,0xCC,0xC9,0x32, +0x97,0xA5,0x8C,0x50,0xB2,0xA4,0x38,0xCE,0xE9,0x5A,0x9C,0xFC,0xF3,0x82,0x9F,0xAE,0xF5,0xA6,0x4A,0x04, +0x65,0x7D,0x05,0xC5,0xF0,0x99,0x56,0x97,0xD5,0xB6,0x36,0x75,0x6A,0x78,0x01,0xCC,0xF6,0x19,0xF9,0xCA, +0xD5,0xA2,0xCD,0x0C,0xF3,0xD8,0xE6,0x06,0x12,0x80,0x54,0xD6,0xC4,0xD8,0x70,0x65,0x61,0xA6,0x56,0x6E, +0x6F,0x88,0xD0,0xA9,0x76,0x85,0xB8,0x52,0x47,0xCF,0xDC,0xC2,0xD5,0xF9,0x5B,0xA8,0x35,0xC7,0x33,0xC5, +0x07,0xBB,0x48,0x01,0xE5,0x96,0x61,0x33,0xF7,0xA6,0x96,0x20,0xFF,0xE4,0xF1,0x46,0x6A,0x2E,0x7F,0x83, +0xCF,0x85,0xC0,0x15,0xF4,0x37,0x99,0xF5,0x22,0x2E,0xA2,0xF6,0x1C,0x13,0xA2,0x96,0xA7,0xAC,0x8C,0x8A, +0x34,0xE5,0x3B,0x2B,0xAC,0x08,0x46,0x3A,0x7E,0x0D,0x02,0xC9,0x7F,0xA7,0x41,0x79,0xA0,0xA8,0x1B,0xF5, +0xA8,0x27,0x22,0x8B,0xCC,0x9F,0x0B,0xD8,0xA2,0xAF,0x4C,0x5C,0xF6,0x89,0x8B,0xE8,0x09,0x06,0x38,0xEC, +0x19,0x26,0x5D,0x9F,0x24,0xE8,0xA1,0x3D,0x6E,0x36,0x99,0x6E,0xF1,0x01,0x66,0xAE,0x6C,0xB7,0x66,0x18, +0xAF,0xCA,0x32,0x4E,0x15,0x31,0xFF,0xC5,0xFA,0xCC,0x8A,0x5C,0x3C,0xA0,0x02,0xF8,0xCF,0xC6,0xFC,0x8E, +0x5D,0xAF,0xB7,0xB5,0x01,0x23,0xD7,0x29,0xDE,0xE1,0x5E,0x34,0x6D,0xAB,0x33,0x4F,0xCE,0xE6,0x32,0xDE, +0x2A,0x70,0x14,0x39,0x10,0x59,0xBB,0x5B,0x24,0xC7,0xEF,0x0D,0x3E,0xE9,0xC3,0xA6,0xCF,0xF4,0x9E,0x36, +0xA1,0x1F,0xCB,0xD0,0xC3,0xC0,0x0F,0x35,0x5E,0xB1,0x53,0xE0,0x0B,0x0E,0xBA,0xF4,0x55,0xE2,0x49,0x4E, +0xE5,0x2A,0x44,0x34,0xE4,0x3C,0x1D,0x68,0xC4,0xB2,0x01,0xA3,0x5D,0x53,0x8A,0x45,0xC0,0x69,0xCD,0xD5, +0xC7,0xD7,0xBD,0x54,0x7F,0x0E,0xD3,0x91,0x54,0x30,0xB3,0x37,0xDA,0x5F,0xC5,0x90,0x56,0xB2,0x04,0x88, +0x97,0x9B,0x5E,0xA4,0xF4,0xB4,0x4C,0x50,0x62,0xC4,0xF5,0x26,0x3E,0x7F,0x93,0x15,0xE5,0xB5,0xB6,0x3E, +0x9F,0x3E,0xF8,0x02,0x6B,0xDA,0x9C,0xBC,0xC6,0xF8,0xF5,0x2B,0x56,0xDB,0xED,0xCE,0xB0,0x97,0xB5,0xC3, +0xE6,0xDC,0xE5,0x63,0xDE,0xE2,0x25,0x77,0x94,0x7B,0x12,0x31,0x93,0xF5,0x1D,0xB9,0x56,0xDA,0x8F,0xD7, +0xA7,0xB5,0x3C,0x88,0x9F,0x13,0x0F,0x7D,0xB0,0xF9,0x89,0x8E,0xEE,0xDC,0xEC,0xB9,0x08,0x57,0x70,0xA3, +0x2D,0x36,0x2E,0x7C,0x19,0x32,0x0A,0xDC,0x9A,0xB5,0xC0,0xB9,0x59,0xFF,0x07,0x01,0x88,0x57,0xC7,0xC4, +0xB0,0x31,0xEF,0xC9,0x13,0xC1,0x17,0xDD,0x9E,0xA6,0xBC,0x94,0x0E,0x1E,0xD6,0xAE,0x89,0x14,0xD8,0x9F, +0x48,0x2A,0x92,0xFF,0x5C,0x7B,0xDE,0xBA,0x66,0x95,0xF6,0x28,0x3D,0xFC,0x04,0xEF,0x7A,0x9E,0xE6,0x3F, +0x8B,0xBE,0x6A,0x1A,0x47,0x30,0x11,0xA0,0xB0,0x4B,0x24,0xEA,0x69,0xFC,0xA4,0x5E,0xDC,0xFB,0xF2,0xB8, +0xB1,0x18,0xC3,0x23,0x12,0xB3,0x67,0xEB,0xEF,0x7E,0xE7,0xE7,0xFF,0x9E,0xA2,0x3B,0xA3,0x62,0xE7,0xDB, +0x37,0xE4,0x5E,0x7F,0xCB,0x17,0xD6,0x95,0x5E,0x78,0x50,0x1C,0x06,0x01,0xF8,0xF4,0x47,0x81,0xA8,0xC0, +0x0C,0x46,0x50,0x8C,0x78,0x9D,0x09,0xD0,0x49,0x8A,0x70,0xE4,0x90,0x80,0x46,0xD6,0xA0,0xEE,0x58,0x9C, +0x63,0xEC,0x4F,0x7F,0x86,0x03,0x17,0xEF,0x79,0x13,0x38,0x4B,0x63,0x59,0xE9,0xD5,0x19,0x53,0x01,0x95, +0xA9,0x17,0x1F,0x91,0xA3,0xE9,0xD4,0xD9,0x79,0x0C,0xE1,0x24,0xCE,0xE8,0x80,0xE8,0x2A,0xF9,0xC6,0x22, +0xE9,0x8F,0x90,0x89,0x3F,0xFF,0xEA,0x17,0x4A,0x0A,0x59,0xD4,0x31,0x85,0x08,0xAD,0x90,0x3E,0x02,0x0A, +0xC4,0x05,0xE2,0x8B,0x55,0xFE,0x39,0xB1,0xF6,0xA7,0x89,0x45,0x2E,0x4F,0x71,0x13,0x3D,0x04,0xB7,0x69, +0xD3,0x2F,0x13,0x50,0x20,0xAC,0xAD,0x23,0x2C,0x8A,0x65,0x1F,0x41,0x44,0x0E,0x84,0xCB,0x67,0xC2,0x2C, +0x4D,0xF7,0x3D,0xEE,0x50,0xC9,0x82,0xC0,0x7F,0x85,0x5F,0x1D,0x34,0x2A,0xFD,0x58,0x4D,0x0F,0xD2,0x9F, +0xF8,0x86,0x8F,0xBA,0xD0,0x29,0xE2,0x3E,0x19,0xC9,0x19,0x29,0xA9,0x6A,0xBD,0x38,0xF9,0xDA,0x4D,0x05, +0xC8,0xE5,0xC2,0x3D,0xBB,0x95,0x22,0x32,0x28,0x8B,0x1D,0x6E,0xF5,0x47,0x23,0xD9,0xD1,0x50,0x8A,0x3F, +0x37,0x70,0x3A,0x4C,0xE3,0xED,0x43,0x43,0xB9,0xA9,0xF2,0x0A,0xBD,0x29,0x3A,0x75,0xDD,0x2C,0x74,0x70, +0x0D,0x1E,0x35,0xB4,0x5F,0x80,0x74,0x1A,0x37,0x42,0xBE,0x0B,0xD6,0x76,0x83,0xE1,0xCC,0xF1,0xE5,0x28, +0x39,0xAB,0x6B,0x96,0x48,0xA2,0x8A,0xEE,0x9E,0x55,0x14,0x27,0x28,0x6A,0xB3,0xBB,0x8B,0xD2,0x3B,0x2E, +0x0A,0x42,0x3F,0xEB,0xDA,0x37,0x1C,0x90,0xDD,0x97,0x91,0x6E,0x95,0x9F,0xDF,0x91,0x0C,0x4F,0x89,0xF0, +0x13,0x34,0xB4,0x80,0x86,0x53,0x73,0xFF,0xBC,0xC7,0x34,0x81,0x0D,0x13,0x63,0x44,0xB8,0x40,0x55,0x90, +0x93,0x37,0x90,0x6D,0x10,0x7F,0xAD,0x52,0xD8,0xD9,0x83,0x90,0x43,0x3F,0x1D,0x77,0xA0,0x42,0x85,0x4C, +0x58,0x02,0x4C,0x65,0x40,0xAC,0x5D,0x1D,0xC3,0x8E,0xBB,0x30,0xD6,0xB5,0xBF,0xAB,0x5A,0x39,0xD7,0x64, +0x11,0x19,0x78,0x7B,0x71,0xC4,0x16,0x0C,0x4B,0x04,0x33,0x93,0xCA,0xC3,0x7C,0x74,0x9F,0x85,0x17,0xCC, +0x40,0xC7,0x54,0x2B,0x5F,0x59,0xE3,0xC9,0x11,0xB3,0x0C,0xF0,0x1F,0x19,0x15,0x1C,0x2A,0x34,0x34,0xBB, +0x22,0x1A,0x32,0xAF,0x79,0x38,0x9D,0x08,0x9C,0x4C,0x65,0xE5,0x54,0x73,0xB2,0xEA,0xD7,0xC5,0xCC,0x6E, +0x1B,0xD2,0x28,0x81,0x4B,0x0A,0xEE,0x5C,0x2F,0x49,0x57,0xB3,0x8C,0x12,0x36,0x63,0xD0,0x28,0x9E,0x30, +0xCC,0x50,0xB2,0xD5,0x1A,0x03,0xEB,0x16,0xAB,0x5B,0xF9,0xA5,0x8B,0x3F,0x4E,0x9A,0x4D,0x51,0xEE,0xDE, +0xC0,0x35,0x48,0x71,0xC2,0x56,0x23,0x02,0xBA,0xC8,0x9B,0xC6,0xC8,0xBB,0x89,0x88,0xFF,0x68,0xFE,0x37, +0x19,0x04,0x3D,0xF7,0x17,0xA7,0x50,0x97,0xCD,0xA9,0xD3,0x04,0x20,0xF1,0xB1,0x1A,0x8A,0x02,0x97,0xD4, +0xCE,0x72,0x07,0xFD,0x96,0x12,0x00,0x37,0x7D,0x47,0xFF,0x37,0x57,0xC6,0xC7,0x49,0xEA,0x0B,0x50,0x6D, +0x99,0x13,0x2F,0x2B,0xFE,0x3C,0xF0,0x3F,0x2B,0x2F,0xCE,0xA2,0x1C,0x94,0x9F,0x1C,0xEB,0x1A,0x4B,0x15, +0xA1,0x32,0x58,0x80,0x95,0x9D,0xC6,0xCE,0x15,0xE0,0x3A,0x44,0xAF,0x91,0x80,0x40,0xAB,0x4D,0xE8,0x32, +0x05,0x89,0xBE,0x23,0xA6,0xEC,0x02,0xC1,0x29,0x4A,0x38,0x75,0x6C,0x4C,0x19,0xB1,0x85,0x22,0x8D,0x7E, +0xF7,0xE6,0x30,0x45,0x2F,0xB3,0xA0,0x60,0x0A,0xE8,0x2C,0x91,0x14,0xB6,0xF1,0x13,0x1C,0x9A,0x17,0x02, +0xA9,0x81,0xAC,0xE7,0x89,0xEA,0xDF,0xA0,0x6D,0x8B,0x18,0x68,0x42,0xBF,0xA3,0x80,0x75,0x76,0xA9,0xE5, +0x31,0xE4,0xDD,0xC5,0x01,0x96,0x59,0x4F,0x24,0xC3,0x8A,0x01,0x5F,0x4C,0xFD,0x36,0x64,0x57,0xE1,0x30, +0xEA,0x80,0xA4,0x21,0xB5,0xE6,0xC9,0x03,0xC2,0xEB,0xA8,0xFC,0x92,0xE5,0x2C,0xAC,0x6E,0x96,0x53,0x67, +0x68,0x58,0x7D,0x13,0xC3,0xEA,0xA3,0x76,0x70,0xAB,0x1A,0xCD,0xCE,0x28,0xF8,0xC3,0x74,0x49,0x63,0x82, +0xED,0xC1,0x36,0xEB,0x64,0xE7,0x70,0x98,0x9C,0x94,0xD7,0xEC,0x3E,0xE9,0xAC,0xBE,0x7F,0x49,0xE3,0xFD, +0x84,0xD4,0x2B,0x0E,0x88,0x41,0x63,0xA7,0xDC,0xA7,0x7C,0xDB,0xB8,0x6B,0x1C,0x44,0x01,0xA8,0x13,0xE4, +0xEC,0x89,0x9F,0xD1,0xFE,0x71,0x03,0xDB,0xC2,0x40,0x94,0x00,0xB1,0xA9,0xA2,0xE2,0x92,0x51,0xD8,0xFE, +0xE1,0x73,0x68,0x82,0x54,0x81,0x72,0xEA,0x2D,0x7D,0x30,0xE9,0x67,0x6C,0x2A,0x46,0xA7,0x50,0xBA,0x83, +0x30,0xD6,0xE9,0x96,0x19,0xA0,0x1B,0x6C,0x73,0x81,0xD4,0x43,0xED,0xAE,0x2B,0xFB,0x32,0x7E,0xD3,0xDF, +0xD8,0x75,0xAB,0xF3,0xCF,0x82,0x7A,0xA4,0x6E,0x7C,0xFF,0x04,0x68,0x3A,0x04,0x97,0x85,0xA2,0xDB,0xE2, +0x6A,0xD2,0x64,0x2E,0x56,0xBD,0x6D,0x84,0xC1,0x98,0xB6,0xC4,0x97,0xF9,0xEC,0xB3,0x46,0x6C,0xB9,0x12, +0x07,0x31,0x29,0xB3,0x84,0x2E,0x2A,0x32,0x4F,0xC3,0x31,0x6C,0xA5,0xD0,0xFD,0x36,0xD7,0x63,0x20,0xA1, +0xF2,0x79,0x35,0xE4,0xCD,0x5F,0x27,0x53,0x02,0x88,0x95,0x07,0x16,0x38,0x1D,0x36,0x0C,0xE2,0x46,0x90, +0x54,0x9D,0x62,0xEA,0xCF,0x85,0x69,0xC6,0xB6,0x64,0xF3,0x90,0x48,0xCF,0xAC,0xEE,0xF4,0x58,0x08,0xC3, +0x4B,0xB0,0xB4,0xC7,0x5C,0xCD,0x39,0x94,0x90,0x59,0x20,0x7D,0xF4,0xFB,0xC9,0x51,0xFA,0x9E,0xDB,0xCE, +0xDF,0xE6,0x55,0xB7,0x19,0xCD,0x86,0x85,0x09,0xB4,0x2A,0xF7,0x26,0x9A,0x69,0xD5,0xBB,0x1C,0xA9,0x56, +0xA4,0xDB,0x95,0xF1,0x74,0x93,0x12,0x7A,0xDB,0xD7,0x35,0xBF,0x0C,0xFA,0x7C,0x48,0x4D,0x68,0xD0,0x83, +0x89,0x5E,0x56,0xBE,0xC4,0xE3,0xD6,0xA5,0x51,0x4C,0x64,0xE9,0x05,0x38,0xC0,0x96,0x7B,0xEA,0x1D,0x09, +0x35,0x92,0xF6,0x9F,0x1D,0x3A,0x0D,0x58,0xD4,0x25,0x26,0xEF,0xDB,0x77,0x77,0x83,0x9E,0xAE,0xBE,0x1B, +0x9A,0x5D,0xFF,0x13,0xDF,0x56,0xED,0xDD,0xDE,0xF2,0x4E,0x28,0xAF,0xF8,0x6B,0xCF,0xD7,0x8C,0xF9,0xBA, +0x4C,0xA3,0x9E,0x0C,0xFD,0xF1,0x30,0x18,0x2D,0x9E,0x71,0xE5,0x22,0xFF,0xBE,0x03,0xAE,0xC6,0x06,0x16, +0xF9,0x32,0x4F,0xCD,0x2F,0x90,0xA5,0x30,0xB8,0x85,0x40,0x8E,0x12,0x8E,0x27,0x9D,0xCD,0x6E,0xED,0x5B, +0x28,0xFF,0xB5,0xA5,0xB9,0x47,0xFB,0x9D,0x10,0xC4,0xA6,0x6A,0x58,0xBE,0xC0,0xAD,0xF8,0xAD,0x00,0x8C, +0xB5,0x2B,0xD0,0x7D,0x6E,0x48,0x5A,0xD4,0x98,0xC1,0x30,0xE3,0x39,0x8C,0x47,0x65,0x46,0x2A,0x80,0xA0, +0x28,0xA0,0xC2,0x24,0x39,0x50,0x4E,0x30,0x21,0xA3,0x01,0x24,0x5E,0x8F,0x91,0x00,0x0E,0xEF,0x84,0xA1, +0x8D,0x9E,0x50,0x48,0x26,0x05,0x8A,0x52,0x78,0x0A,0x01,0xA1,0xB6,0x43,0xE7,0x1C,0x99,0xD9,0x10,0x37, +0x1A,0x8B,0x9A,0x65,0x7A,0x27,0x08,0x64,0x02,0x0B,0x47,0x6C,0xF7,0x9E,0x2D,0xA6,0x84,0x85,0x08,0x49, +0x1E,0x2B,0x3A,0x6D,0x42,0x25,0xCE,0x59,0x55,0x76,0x43,0xA7,0x23,0x1D,0xB8,0x23,0x29,0x39,0x08,0xED, +0x67,0x28,0xAF,0xC5,0xB1,0xB7,0x89,0x84,0x28,0x1C,0xF1,0xBE,0x10,0x2A,0x03,0x6C,0x64,0x5C,0xDB,0x17, +0x38,0x44,0x2F,0x0D,0xA9,0x03,0xE4,0x6C,0x97,0xAE,0x2C,0x05,0x20,0x21,0xAC,0xF5,0xD5,0xEE,0x85,0x59, +0x08,0x49,0x6C,0x5B,0xF0,0xD3,0xDA,0x65,0x43,0x0B,0x8B,0x2D,0x65,0xC4,0x06,0xE1,0x56,0x48,0x81,0x4D, +0x9C,0x0B,0xEC,0x57,0xA2,0x1B,0x14,0xED,0xDE,0xCA,0x1F,0x32,0x68,0xA4,0xED,0xC1,0x66,0x45,0x94,0x9C, +0xC8,0x0B,0x0E,0x5D,0xDD,0x4B,0x27,0x3E,0x85,0xAA,0xBB,0x23,0x47,0xD3,0x93,0x0E,0xB5,0xE1,0xE8,0x9F, +0x2A,0xC1,0xCF,0x48,0xEC,0x16,0xC5,0xA7,0xAA,0xB5,0x24,0x45,0xA2,0x24,0xC9,0x3B,0x85,0x65,0xC6,0x89, +0xCA,0xA3,0x7A,0x11,0x6D,0x13,0xCF,0x76,0x69,0xCA,0x87,0xFD,0x25,0xC3,0x08,0x3F,0x74,0x63,0xB0,0x9F, +0x1F,0x21,0xFC,0x9B,0x0B,0xE2,0x5B,0x7E,0x43,0xC2,0x22,0x62,0x14,0xBF,0x84,0xC4,0x24,0x2B,0x2A,0x8D, +0xAA,0x39,0x4E,0xB9,0x99,0x81,0x32,0xB8,0xAC,0xB7,0xD5,0xBA,0x52,0xB3,0x1C,0x34,0x3C,0x73,0x7F,0xA0, +0x42,0xA7,0x90,0xF3,0x4B,0x03,0x8A,0x75,0xB8,0x7D,0xEA,0xD2,0xD4,0xD4,0x8D,0xB5,0x17,0x69,0x91,0xD1, +0xA5,0x32,0x75,0xE6,0xE2,0x5D,0xDD,0xEC,0xCF,0x5B,0x27,0x72,0x33,0x23,0x14,0xD0,0x36,0x59,0x7C,0xE3, +0x91,0x51,0x94,0x34,0xCF,0x16,0xCD,0xE4,0xEF,0x89,0x29,0xA6,0x10,0xB7,0x06,0x02,0x92,0x2E,0x5C,0xF0, +0xEE,0xF8,0xE2,0xD9,0x1B,0x78,0x1C,0x51,0x05,0x0D,0x9F,0xC4,0x11,0x74,0xD2,0xC7,0xE2,0x56,0x78,0xAB, +0x07,0x2A,0xB5,0x39,0xE1,0x5A,0xAC,0xE1,0x31,0xFB,0xC1,0x62,0x9F,0xA8,0xCB,0x97,0x18,0xA6,0x30,0x0C, +0x75,0xDF,0xDF,0x87,0xFE,0x30,0x96,0x89,0xA6,0x1A,0x9E,0xB8,0x1F,0x28,0xE8,0xEB,0x15,0xB8,0xD5,0xFA, +0xCE,0x29,0x66,0xAB,0x59,0x83,0x5E,0x69,0x72,0x7F,0x3F,0xE9,0xAC,0x3B,0x07,0xBB,0xEB,0x21,0x98,0x1F, +0x8B,0x7A,0xCE,0x2F,0x9F,0x8A,0x37,0x66,0x40,0x4A,0x37,0x62,0xBF,0xC3,0x39,0x91,0xB6,0xFF,0xCF,0xB4, +0x58,0x60,0x26,0x68,0x32,0x13,0x7B,0x2E,0x1E,0xC8,0x68,0x48,0xE5,0xAA,0x16,0x44,0xD1,0xFA,0x1E,0xC5, +0x88,0x71,0x05,0xE1,0x88,0x70,0x64,0x0B,0x1F,0xF0,0x8F,0x87,0xB9,0xDD,0x1E,0x58,0x0F,0x18,0x52,0x0B, +0x8E,0xB5,0x5F,0xED,0x36,0x5D,0xD1,0x2D,0xB6,0x3C,0x16,0x52,0x4E,0xB9,0x85,0x3F,0x34,0xB9,0xCC,0xBE, +0x21,0xAE,0xD7,0xE1,0x74,0x64,0xB6,0x71,0x68,0xEC,0xC2,0x16,0x15,0x60,0x24,0xB5,0xAD,0xD1,0xB9,0x37, +0x60,0xC0,0x3C,0x39,0x66,0xC7,0xB0,0x6F,0x98,0x0C,0x2E,0x50,0xBA,0x6C,0xAC,0x12,0xB4,0xFA,0x47,0x67, +0x85,0xC2,0x9F,0x66,0xFD,0xAB,0x29,0xB2,0x2D,0xB3,0xB8,0x36,0xB8,0xC2,0x3F,0x26,0x6E,0xC7,0xB5,0x84, +0xB4,0x23,0xA8,0x96,0x32,0x48,0xFE,0xD1,0x58,0xF8,0x39,0xD8,0xE3,0x72,0x44,0xC2,0x4A,0xF0,0x08,0x02, +0x42,0x64,0xE3,0x76,0xBD,0x55,0x0D,0x24,0x8A,0x53,0xC8,0xF5,0x5F,0x14,0xEF,0xE2,0x8F,0x34,0xAC,0x36, +0x53,0xC1,0x9E,0xD3,0x71,0x9D,0xE7,0xE7,0xDE,0x77,0xE6,0x10,0xEB,0x67,0xCF,0x5E,0x5B,0x40,0x61,0x43, +0x7A,0x06,0xE5,0xE1,0x15,0x6B,0x01,0x61,0xF4,0x95,0xDF,0x87,0xD5,0x46,0x18,0xBA,0xB8,0x27,0x59,0x71, +0x5C,0x7C,0xB1,0xAE,0x11,0xBA,0xD1,0x58,0x96,0x98,0x3E,0x29,0xE4,0x68,0xF7,0x78,0xE6,0xC5,0xBA,0x1B, +0x83,0x64,0x7A,0xEB,0x47,0x4D,0x87,0x69,0xAF,0xCA,0xDB,0x3D,0x63,0xB1,0xF3,0x76,0xE2,0xC2,0xCD,0x16, +0xEF,0x3C,0x0D,0x7E,0x2E,0x0E,0x14,0x84,0x7C,0x2D,0xAD,0x5B,0x8F,0xA7,0xC3,0x02,0xEE,0xED,0x99,0xBC, +0x3D,0xBA,0x58,0x3D,0x02,0xA3,0x8A,0x18,0xA5,0xCF,0xE1,0xEA,0x6C,0x6C,0x92,0xB2,0x5D,0xC0,0x92,0xB7, +0x0B,0xC0,0xC2,0x85,0xA6,0x7C,0xEC,0x47,0x59,0xFE,0xD9,0xB4,0xBD,0x0C,0xBA,0xD5,0x7B,0xCB,0x0D,0x52, +0xFD,0x9C,0xCB,0x90,0xBD,0xEC,0xFC,0xB3,0xC5,0xC0,0x5F,0xBD,0xAC,0xDF,0xD7,0xE4,0xCC,0x16,0xF9,0x1D, +0x24,0xAD,0xE4,0xDF,0x6A,0x0F,0x95,0xF8,0x97,0x4D,0xA2,0xC2,0xAC,0x31,0xD1,0x50,0xF1,0x70,0x75,0x62, +0x80,0x27,0xCE,0x69,0xC0,0x38,0x67,0xC8,0xC2,0xC1,0xE5,0x30,0x92,0xEA,0x91,0xE1,0x5F,0xFC,0x65,0xDA, +0x39,0x4F,0x29,0x50,0xB7,0xC9,0x8F,0x4F,0xA6,0xBD,0x16,0x17,0xF8,0x7B,0x8D,0x05,0x35,0xB9,0x02,0x55, +0x04,0xC8,0x7B,0x51,0xD7,0x83,0xE1,0x31,0x5E,0x8F,0xA4,0x86,0x32,0x90,0x3C,0xAA,0x60,0x1E,0x7A,0x80, +0xE8,0xE6,0x35,0x58,0xCE,0x9A,0x75,0x26,0x54,0x95,0xDC,0x90,0xD4,0xB0,0x54,0xDA,0xF7,0x65,0x84,0x47, +0xE9,0xA4,0x5E,0xF8,0x8A,0xF4,0xC9,0xA1,0x6A,0xDA,0x4D,0x69,0xF7,0xF4,0x97,0x57,0xCC,0xC5,0x36,0xD7, +0x07,0xC6,0x45,0x18,0x4B,0xDA,0x11,0x1F,0xA6,0xBA,0x2E,0x8E,0x04,0x7E,0x23,0x66,0x47,0xF5,0x15,0x5C, +0x90,0xA9,0x73,0x2C,0x5E,0x08,0x3F,0xFA,0x7D,0x12,0xE1,0x74,0xC0,0xF6,0x53,0x3E,0x6F,0xD9,0x5C,0x57, +0x2F,0x96,0x19,0xEE,0xEE,0x33,0x58,0x7F,0x38,0x1B,0x84,0x87,0xEA,0xA1,0x8F,0xE8,0xCF,0xCC,0xEF,0x1F, +0xF0,0xE9,0xF6,0x43,0xBB,0x4B,0x66,0x42,0x48,0xD0,0xE6,0x27,0x58,0x04,0x3F,0x5C,0xD3,0x53,0xE7,0xCC, +0x76,0xD0,0x8F,0xCD,0xCF,0xA3,0x13,0x66,0xDB,0xAA,0x0E,0xD8,0xAB,0x90,0x87,0x35,0xC0,0xA6,0x56,0x98, +0x8E,0x26,0xC0,0x5F,0x1E,0xBD,0x5D,0x23,0x30,0x51,0x33,0x91,0x90,0x62,0x4E,0xA9,0x4F,0xE3,0xFF,0xEB, +0x7B,0xAF,0x36,0x57,0x08,0xD2,0xDD,0xB9,0xE8,0x10,0x7B,0x05,0x14,0x40,0xA7,0xB7,0x03,0x2E,0xC0,0xE9, +0x9C,0xFD,0xF8,0xE8,0x4C,0x72,0x0F,0x31,0x38,0x69,0x2F,0xD5,0xDC,0x60,0x1B,0x94,0x33,0xBC,0x30,0xF4, +0x15,0x0D,0xFC,0x90,0x75,0x03,0xA6,0x33,0x3B,0x10,0xAD,0x93,0xC0,0x0A,0xDB,0x58,0xA4,0x3D,0x23,0x30, +0xB0,0x6B,0x87,0x1D,0x3B,0x26,0x6B,0x01,0x80,0xA2,0xD1,0x2A,0xFC,0x61,0x27,0x91,0x22,0xBC,0xE7,0x32, +0x5E,0xDE,0x73,0x79,0xFE,0x15,0x00,0xF0,0xBD,0x2A,0xCC,0x82,0xA2,0xE0,0x69,0xFA,0xD1,0x20,0x36,0x4E, +0x6F,0xF1,0x33,0xD0,0x62,0xA7,0x06,0x30,0x4F,0xEE,0x67,0x96,0x55,0xC6,0xF2,0x74,0x84,0x2D,0xF9,0xBA, +0x11,0x2B,0x29,0xDD,0x29,0xB5,0xB9,0x62,0x71,0x03,0x58,0xD5,0xC0,0x46,0xE6,0x2A,0x4A,0xBB,0x21,0x75, +0x2A,0x54,0xEC,0x17,0x24,0x02,0x5F,0xE4,0xA5,0xD7,0xC8,0x28,0xB9,0x23,0x2C,0x15,0xAB,0x97,0xF4,0x2A, +0xA9,0xCE,0xA6,0xBD,0xDC,0x6A,0xC8,0x7C,0x05,0xAB,0xE2,0x30,0xEC,0xB3,0x90,0x3D,0xC0,0x94,0x06,0x6E, +0xBB,0x4A,0x16,0xE5,0x34,0x67,0x4A,0x1B,0x6D,0x90,0x37,0x6D,0xD2,0x56,0xA0,0xD3,0x32,0xF4,0x93,0x05, +0xF9,0x6B,0xE3,0x1D,0x4B,0x3E,0xE5,0x3B,0x20,0xCD,0x18,0x49,0xA9,0x51,0x79,0x16,0x1C,0xEF,0x92,0xDC, +0x5C,0x41,0xEA,0x93,0xD5,0xEA,0xEE,0x2B,0x67,0x02,0x9C,0x77,0xBA,0xB2,0x24,0xD5,0xA2,0xBE,0xB8,0x7E, +0x5A,0x4F,0x83,0x8C,0x70,0xA1,0xE3,0x8D,0x8A,0x6C,0x2D,0xC5,0x66,0x43,0xD3,0x13,0xBB,0x6A,0xFF,0x2A, +0xBB,0x00,0x7F,0x3F,0x60,0x2C,0x4D,0x1B,0x34,0xE2,0x82,0x91,0xDD,0xAC,0x54,0xD1,0x5C,0x1B,0x44,0x41, +0xCD,0x3D,0x02,0x99,0x66,0x43,0x83,0x5F,0x91,0xE3,0xB4,0x6A,0x31,0x5C,0xF2,0xA8,0x37,0x5B,0x46,0x8C, +0x09,0x20,0x84,0x2A,0xA1,0x40,0x56,0xA5,0x93,0x49,0xFB,0xBC,0x1C,0x3F,0x17,0x51,0x1F,0x5D,0xEE,0xDB, +0x91,0x52,0x72,0xA0,0x00,0xEC,0xF6,0xF7,0x5A,0xC2,0xDD,0x19,0xA1,0x5E,0xBA,0x99,0x48,0x78,0x3C,0x30, +0xD6,0x45,0xB6,0xC5,0x22,0x2F,0xD1,0x93,0x47,0xD5,0x4F,0x37,0x86,0xE7,0xB3,0x20,0x7E,0x44,0xF6,0x6C, +0xC0,0x77,0xB0,0x6F,0x62,0x35,0x87,0xF4,0x75,0xC5,0x3C,0xA7,0x2F,0x74,0xE2,0xB3,0xCA,0x89,0xA8,0x1E, +0x0B,0x45,0x62,0x5C,0x0A,0x1F,0x34,0xB7,0x2E,0x75,0x9B,0xFE,0x32,0x53,0x03,0xB1,0xAB,0xDA,0x9D,0xEB, +0x81,0x83,0x3D,0x2D,0xDF,0x76,0x32,0xEE,0xD3,0x3B,0x54,0x4A,0x20,0xC9,0x15,0xBF,0x00,0x99,0x06,0x90, +0xC0,0x1A,0x42,0x27,0x3F,0xB3,0xDE,0x44,0x33,0xD2,0x09,0x95,0xB1,0x7A,0xBA,0x16,0x1D,0xCC,0xBD,0x66, +0x0D,0x78,0x37,0x6A,0x14,0x8B,0xB1,0x91,0xC8,0xDE,0x01,0xA4,0x8A,0x5B,0xC1,0x66,0x71,0x8A,0x1B,0x45, +0xE9,0x4E,0x0E,0xBF,0x9B,0x46,0xD1,0x37,0x2C,0x96,0xEE,0xCA,0x9B,0x63,0x28,0x41,0x83,0x6F,0x81,0x9F, +0x04,0xDD,0xFD,0xF4,0x98,0x50,0xB6,0xD8,0xD2,0x0E,0xDE,0x9B,0xC1,0x1F,0x0A,0x02,0x86,0xFC,0x16,0x35, +0xAA,0x95,0x73,0xAF,0x05,0x95,0xFB,0x7A,0xC7,0x56,0xEF,0x12,0x13,0xAD,0x30,0x21,0xAB,0xB2,0xFD,0xED, +0xB9,0x90,0x09,0xD2,0x4A,0x80,0x9F,0x12,0x0E,0xFC,0x7B,0x02,0x7F,0xE0,0xF8,0x1E,0x6B,0x7B,0x70,0x40, +0xAF,0x11,0x10,0xDD,0xA5,0x66,0x95,0x8D,0xB0,0x57,0x88,0x1F,0x6A,0x62,0x2B,0x75,0x8F,0xE2,0x07,0x0F, +0xBE,0xA5,0xE1,0x1B,0x3A,0xEC,0x81,0x1E,0xEB,0xF8,0x6F,0x1B,0xCC,0x6F,0xB1,0xDD,0x54,0x50,0x21,0xD6, +0x6C,0x80,0x89,0x06,0x7C,0x4A,0x71,0x1B,0xA6,0xC1,0x83,0x8F,0x3E,0x87,0xD9,0xC6,0x09,0xD8,0x21,0x6F, +0xFF,0x97,0xA3,0xE6,0x2C,0xB9,0xBB,0xA6,0x42,0x19,0x10,0x75,0xEE,0xD4,0x78,0x25,0x3A,0x24,0xCB,0xF6, +0x32,0x6B,0x43,0xC7,0x25,0x4A,0x1F,0x44,0x6F,0xB7,0x0D,0xD5,0x92,0xAE,0xB1,0xD7,0xF5,0x5D,0xE7,0xDE, +0x3D,0x55,0x11,0xD7,0x88,0x7A,0x12,0xA8,0x7E,0x94,0x20,0x8B,0x22,0x78,0xAA,0x66,0xED,0xCB,0x2C,0x37, +0x2F,0x30,0x0E,0x8B,0xE3,0xAE,0x24,0x12,0x4A,0xDB,0x1E,0x5D,0xD8,0x4E,0x92,0x95,0x1F,0xC4,0xC8,0xF6, +0x1E,0x29,0x45,0x05,0x39,0x8B,0x2F,0xFE,0x49,0xD5,0xB3,0x4C,0xBF,0xF1,0x09,0xE7,0x3D,0xC6,0x31,0x49, +0x27,0x7B,0xA0,0x5C,0x50,0x4C,0xCA,0xDB,0x88,0x26,0xF1,0x67,0xE1,0x54,0xA5,0x26,0xAE,0xB1,0xB1,0x3E, +0x44,0x16,0x5C,0x7F,0xAD,0xE9,0x4E,0xD1,0x1D,0x4E,0xC5,0xC2,0x48,0x77,0x1A,0xEA,0x38,0xE8,0xA6,0xA0, +0xE6,0xBC,0x94,0x58,0xFE,0x2E,0x7C,0x3A,0x0D,0x60,0xA3,0x86,0xA7,0x16,0x5D,0x63,0x2D,0xCC,0xB9,0x3F, +0xF6,0xBD,0x96,0x14,0x41,0x48,0xBB,0x77,0xD8,0x2D,0x13,0x7C,0x66,0xDE,0x58,0xAC,0x13,0xA2,0x2A,0xE9, +0x8F,0xC7,0xBB,0x83,0x2B,0xAF,0x00,0xFC,0xDD,0x4C,0x31,0x95,0x40,0x21,0xA1,0xAA,0xE4,0x70,0xA4,0xC4, +0x7A,0xEB,0x80,0x37,0xF0,0xF2,0x91,0xA7,0x94,0x8E,0x97,0x78,0xDE,0x93,0xEC,0x8C,0x09,0x04,0x1E,0xDD, +0x97,0xD2,0x7E,0x86,0x34,0xA0,0x99,0x06,0x31,0xB1,0x00,0xC1,0x4B,0x47,0x86,0x59,0x1E,0x6C,0x8E,0xA2, +0x6D,0xA2,0x6C,0xF9,0xC1,0x7E,0x2C,0x89,0xCD,0xB1,0xFA,0x85,0x28,0xEB,0x44,0xB5,0x95,0x37,0xC0,0x80, +0xD9,0x96,0x01,0x08,0xAB,0x89,0x26,0x7A,0x44,0x40,0xFB,0x29,0xC2,0x26,0xCB,0x07,0x92,0xB6,0xC7,0xCD, +0x0D,0x60,0xA5,0x22,0x4D,0xD4,0xD2,0x43,0xD0,0xD8,0xA7,0x04,0x12,0x1D,0x5A,0x19,0xF0,0x35,0xFC,0x39, +0x5A,0xD8,0x16,0x2F,0xB7,0x0C,0x1B,0x91,0x1C,0x48,0xAE,0x73,0x8E,0x05,0xCA,0xE5,0xF2,0xC5,0x1F,0x0A, +0x33,0xE4,0xFB,0xCA,0x74,0xDE,0xEA,0x5D,0xA8,0xC9,0x1D,0xFC,0xD2,0x34,0x88,0xA3,0x01,0x1D,0xBF,0x58, +0xED,0x79,0x82,0x3B,0x4E,0x8C,0xC4,0xCB,0xB8,0x81,0x67,0x5F,0xF7,0x05,0x9D,0x43,0x4D,0x5B,0x10,0x83, +0x45,0xFB,0x66,0x5C,0x73,0x91,0xFF,0xA7,0x5C,0x64,0x05,0x39,0x28,0xC0,0x07,0x50,0x05,0x2A,0xDF,0xAA, +0x2A,0xB9,0x62,0x4A,0x6E,0x89,0xB6,0xF3,0x9F,0x01,0x66,0x06,0xA6,0x31,0x54,0x29,0x5D,0x32,0x91,0x5A, +0x67,0xBF,0x46,0xC4,0x59,0x28,0x19,0x0E,0xFF,0xE2,0xE3,0xEF,0x72,0x8D,0xD9,0x8F,0xD6,0xB3,0x5F,0x89, +0x13,0xD2,0x08,0x28,0x17,0xA4,0x38,0xA8,0x9D,0x3B,0x43,0xB0,0x61,0x40,0xAA,0xB4,0x12,0xA3,0xE1,0x36, +0x6D,0xBE,0x60,0x03,0x55,0x0D,0x40,0x25,0x03,0x8D,0x06,0x08,0x46,0x41,0x3A,0x6F,0xF3,0x05,0x32,0xF8, +0x7E,0xCE,0x1D,0xF6,0x17,0x00,0x78,0x7B,0x4D,0x4C,0xA0,0xB1,0xD7,0x62,0x19,0x05,0xA8,0x68,0x10,0xE7, +0x3C,0x8F,0x52,0x52,0xAC,0x4D,0xE9,0xA7,0x50,0xBA,0x37,0xDC,0xA2,0x11,0x13,0x66,0xE1,0x2C,0x6B,0x35, +0xDD,0xC8,0x89,0x95,0xD5,0x4B,0x60,0x51,0x8F,0x67,0x40,0x47,0x18,0xAF,0x30,0x36,0xCF,0x4B,0xE0,0x1A, +0x90,0x64,0x35,0xB9,0xD1,0x6A,0x99,0x44,0xB2,0x8A,0x12,0x6D,0x03,0x43,0xBA,0x36,0xBA,0x34,0xEA,0xE4, +0x57,0x18,0x0C,0x74,0xFE,0x64,0x31,0x63,0x5C,0x4B,0x99,0x7D,0x3B,0x17,0xF2,0xD8,0x2C,0x01,0xDC,0xA7, +0xB0,0x67,0xF3,0x23,0x60,0xCA,0xBB,0x70,0xD2,0x27,0x5B,0x23,0xAD,0x03,0x36,0x7F,0x60,0x27,0x1A,0x19, +0x78,0x0A,0xF9,0xAE,0xD8,0x7E,0x52,0x1D,0x0D,0x52,0xD3,0x37,0x1F,0x28,0x3A,0xDA,0x01,0x58,0x2E,0x5E, +0x6A,0xDE,0xC7,0xE1,0xDE,0x47,0x85,0x38,0x90,0xE2,0x03,0xB1,0x69,0xC2,0xAB,0xC5,0x26,0x25,0xED,0xF1, +0xF6,0xC0,0x4F,0x62,0x3A,0x86,0xDB,0x19,0x83,0xE6,0x63,0x5B,0x22,0x70,0x62,0x6F,0xAB,0x05,0xE6,0x55, +0x79,0xF6,0xAD,0x17,0x39,0x4C,0xF2,0xC9,0xD5,0xC1,0x6A,0x49,0x86,0x6E,0xB4,0x74,0x1D,0x3E,0x27,0x02, +0x29,0x49,0x39,0x3C,0x0B,0xD1,0x83,0xCD,0xC5,0x5A,0xD5,0x64,0x29,0x63,0x8E,0x68,0xAA,0x28,0x46,0xF2, +0x33,0x3F,0xE0,0xFC,0x5E,0x11,0x03,0x3F,0x70,0x9E,0xA2,0xFD,0x9B,0x49,0x64,0x26,0x0A,0xB2,0x84,0xA1, +0x32,0x9D,0x06,0xFB,0xD7,0x2B,0x12,0x88,0x28,0x41,0x3F,0x6E,0xCB,0x4B,0xB4,0x6F,0xC8,0xF0,0x53,0xE2, +0xD3,0x11,0x67,0x97,0xC0,0xEE,0x60,0x36,0xF1,0x54,0x7B,0xB4,0x93,0x17,0x5A,0x71,0xB8,0x29,0xD5,0x80, +0xF3,0x5F,0x1C,0x42,0x05,0x40,0xA1,0x0E,0xA0,0x53,0x0F,0x17,0x39,0xEB,0xAA,0x9C,0x15,0x02,0xA5,0xD5, +0xF7,0x31,0xC3,0x28,0xD4,0x5B,0xA6,0x26,0xDB,0x65,0xE3,0x84,0x15,0x54,0x38,0x76,0xF0,0x7C,0x12,0x32, +0x37,0x90,0x73,0x46,0x90,0xE8,0x9C,0xE8,0xDB,0xA8,0xC9,0x70,0x41,0xF5,0x7D,0x93,0xE1,0xE6,0xA7,0xC5, +0xB1,0x26,0x62,0x84,0x91,0x56,0x17,0x15,0x86,0xD7,0x5F,0xDD,0x90,0x1B,0xAF,0xD5,0xB2,0x77,0x4B,0x93, +0x1C,0x8A,0xE5,0x65,0x50,0xFC,0x12,0x00,0x4B,0xE0,0xB8,0xB9,0x9B,0x3B,0xD6,0xBD,0xD1,0x5E,0x58,0xA2, +0xF8,0xD8,0x56,0x9C,0x01,0x9B,0x34,0xEC,0x31,0x30,0xB2,0xC7,0xB3,0x84,0x35,0x76,0xC2,0x42,0x11,0xBC, +0x1B,0x57,0x84,0x98,0x8B,0xC1,0x37,0x7C,0x49,0xE5,0x3B,0x08,0x2D,0x19,0x35,0x62,0x55,0xFA,0x0C,0xEE, +0xA6,0x30,0x7D,0xB9,0xEA,0xC9,0xAE,0x5A,0x0C,0x49,0xBE,0x4A,0xAA,0x8A,0x2E,0x44,0xD3,0x2D,0x82,0x16, +0x97,0xDD,0x1B,0xDD,0x16,0x3E,0xB1,0x08,0x88,0x16,0x08,0x34,0x2A,0x70,0x0C,0x57,0x80,0xD6,0xA6,0xFE, +0x5D,0xD0,0x7F,0xC1,0x0D,0x53,0x8D,0x2F,0x41,0x37,0x17,0x1A,0x81,0x83,0x86,0xFD,0x99,0x81,0x4D,0xA6, +0xEA,0x16,0xDD,0xBF,0x48,0x82,0xCF,0x59,0xF1,0x0F,0xC8,0xDD,0x56,0xCE,0x24,0xEA,0x52,0xCD,0xB5,0x56, +0x94,0x0F,0xA5,0xC0,0xAD,0x91,0x06,0xA2,0x1B,0x7C,0x71,0x8E,0x66,0xE1,0x24,0x23,0x17,0xA7,0x40,0xB6, +0x65,0x63,0xB5,0xB2,0x1A,0x7D,0x63,0xE5,0x04,0x22,0x37,0x78,0xB5,0xC2,0xF1,0x03,0x86,0x3F,0xE8,0x98, +0x71,0xF9,0xD1,0xE2,0xB5,0x73,0x80,0x25,0x34,0x0A,0x07,0x0A,0x66,0x6E,0xD9,0x7C,0xAE,0xEE,0x1D,0xAB, +0x90,0xEB,0xD7,0x6F,0xEA,0x45,0x0B,0xB2,0x0A,0xCD,0xDB,0x59,0x6A,0x31,0x65,0x34,0xF0,0x95,0x79,0x49, +0x2B,0xC9,0xF8,0xB4,0x33,0x4E,0x6D,0x4C,0x63,0xA7,0xDA,0xCA,0x29,0x9D,0x21,0xA7,0x96,0x72,0xF3,0x19, +0x25,0xCF,0x60,0x65,0x96,0x53,0xD1,0xAC,0x08,0x9C,0xD7,0x7A,0x55,0xAF,0x57,0x4E,0xC1,0x2D,0xA4,0x40, +0x0B,0x76,0x18,0xF9,0x34,0x8E,0xB7,0x6E,0x54,0x05,0x21,0xAE,0x6C,0x4A,0xC9,0xAC,0xDC,0xAD,0x2E,0xFA, +0x09,0xA8,0xF3,0x35,0xB8,0x56,0x2C,0x0F,0xFE,0x8B,0x74,0x30,0xDD,0x49,0x0E,0x0E,0x2D,0x03,0xB6,0xED, +0x1C,0xDA,0x8C,0xC9,0xAF,0x32,0x8B,0x4F,0xDA,0xA8,0x6A,0x68,0x92,0x80,0xF2,0xF6,0xF8,0xA2,0x2B,0xBE, +0x30,0xC4,0x17,0x9A,0x08,0x88,0x01,0xCE,0x41,0x95,0xDC,0x62,0xDC,0xAC,0x02,0x10,0xED,0x3C,0xCC,0x57, +0x7E,0x81,0x6B,0x25,0xA8,0x8B,0x5D,0x77,0x19,0xA6,0xE9,0x6A,0xAE,0xD6,0x98,0x4E,0x5E,0x1F,0x6B,0x5A, +0x7B,0xC1,0xAB,0x4B,0xB7,0xD0,0x84,0x7B,0x59,0xCF,0xF6,0x1C,0xAE,0x80,0x4B,0xCC,0x2E,0x05,0x5E,0x98, +0x76,0xDE,0x88,0x9D,0x85,0x86,0xDB,0x6A,0x36,0x7E,0xE4,0xD2,0x63,0x44,0xA3,0x6E,0x8C,0xFD,0xF4,0x83, +0x01,0xDD,0x48,0x4E,0x98,0xBD,0x28,0xAD,0x49,0xD3,0x14,0xF6,0x39,0xF3,0x8B,0x8B,0x91,0x40,0x59,0xE9, +0xD2,0xE1,0xB4,0x9C,0x98,0x29,0xFD,0x8F,0x87,0x60,0x4E,0x84,0x45,0x6D,0x4A,0xAF,0x51,0xE9,0x27,0x47, +0x71,0x02,0xF6,0x9C,0x91,0x68,0xFD,0xA6,0x5C,0xD5,0x02,0x51,0x0C,0x0C,0x9C,0x40,0xA6,0xC2,0x48,0x5C, +0x37,0x24,0x2D,0xE9,0x83,0xBA,0xCE,0x09,0x8E,0xC5,0x6E,0x50,0xE2,0xB9,0x8E,0xD6,0x34,0x35,0x58,0xA3, +0x58,0x25,0xBC,0xB6,0x63,0x85,0x5D,0x91,0xE5,0x66,0x5A,0x55,0xE4,0x6B,0x17,0xEA,0xE7,0x96,0x42,0xD2, +0xF0,0x0C,0x15,0x51,0x27,0xC1,0x36,0xD7,0xC8,0x25,0x22,0xCF,0x94,0xA2,0xCA,0xDE,0x0B,0x16,0x81,0xB3, +0x4F,0x60,0x0D,0x73,0xB9,0xC3,0x16,0x62,0xCD,0x67,0xEF,0x25,0x9D,0xB7,0x76,0x9E,0x05,0x1B,0xF1,0xB5, +0xB8,0x48,0x5C,0xBA,0x6C,0xCB,0x9E,0x8C,0xDC,0xF0,0x31,0xBE,0x1F,0xD7,0xA6,0xFD,0x47,0xF8,0x9B,0xD4, +0x36,0x07,0xB6,0xD0,0x5B,0xFC,0x29,0xB2,0xCE,0x93,0x07,0xA3,0x5C,0xBD,0x66,0x46,0x8A,0xFB,0x7F,0x3B, +0xB2,0xAF,0x5E,0x1A,0x72,0x1C,0x0A,0xBD,0x02,0x3A,0xA9,0xB8,0x19,0xA9,0x36,0x33,0x7C,0xF6,0x0E,0xD8, +0xB1,0x90,0xEB,0x9E,0x3B,0xB9,0x00,0xCF,0x86,0x3C,0x40,0xEF,0x72,0x4C,0x07,0x9D,0x2B,0x91,0xFF,0xBC, +0x8A,0x38,0xB7,0x1E,0xEF,0x53,0x70,0x9C,0x86,0xFF,0x45,0x0B,0xF3,0x1F,0xE6,0x98,0x42,0x39,0xD3,0x68, +0xFC,0xD7,0xDF,0xFD,0xEF,0x97,0x17,0x08,0x80,0x60,0x10,0x76,0xA7,0x7D,0xBC,0x5B,0x8A,0x31,0x07,0x1A, +0x24,0xD5,0x59,0xD4,0xE8,0xB0,0x0B,0x90,0x5E,0xBB,0x19,0xD8,0x8C,0x0C,0x1C,0xB0,0x0D,0x09,0xCD,0x38, +0xFF,0x40,0x2D,0x96,0xFC,0x28,0x2A,0xB2,0xF4,0x48,0x86,0x1F,0xA0,0x79,0x71,0x00,0xED,0x2B,0x49,0xC0, +0x17,0x2B,0x41,0x34,0xBE,0xBC,0x3E,0x08,0x05,0xB2,0xE4,0x22,0x26,0x71,0xC4,0x03,0x93,0x2A,0xBC,0x13, +0x7C,0xE2,0xB7,0x95,0x80,0x24,0x98,0xA1,0xA0,0x45,0xEF,0x52,0xC3,0x41,0x78,0x9A,0xAA,0x16,0xA6,0x47, +0x38,0xE0,0x11,0x6F,0xA8,0x33,0x62,0xEC,0x4E,0x75,0x8F,0x12,0xA5,0xCF,0x72,0x53,0x0E,0x83,0x77,0x79, +0x63,0xA8,0xF3,0xA6,0x55,0x88,0x43,0x73,0x51,0x06,0x59,0x33,0x41,0x33,0xFB,0x7A,0xE3,0xE9,0x06,0xF1, +0xEF,0x69,0x82,0x08,0x3C,0x80,0xB5,0x15,0x88,0xF9,0xCA,0xB0,0x49,0x04,0x8D,0x72,0x96,0x5F,0x9D,0xC7, +0x3E,0x49,0x37,0x43,0xC4,0x35,0x59,0x5B,0xE0,0xEB,0x02,0x0F,0x69,0x71,0x4A,0x6A,0x6D,0xC0,0x20,0x01, +0x24,0x1B,0x13,0x39,0xEA,0xDA,0x83,0x01,0x9F,0xC1,0x42,0xBE,0x6C,0xD4,0x20,0x73,0x38,0x54,0xE2,0x5B, +0xA9,0x68,0x24,0xBD,0xD0,0x3C,0x92,0x70,0xF2,0x22,0xF1,0x63,0x82,0xC7,0x32,0x5C,0xEB,0x8C,0x6D,0xC3, +0xF0,0x9B,0x7A,0x92,0xFE,0xC4,0x8A,0xE2,0xA0,0xC9,0xC3,0x50,0x46,0xA5,0xBD,0xDF,0x4E,0xF8,0xEE,0xF6, +0x3F,0xC7,0x76,0x68,0x5D,0x78,0x0B,0xAA,0x0F,0xA2,0x95,0xC7,0x9F,0xDA,0x7B,0xF3,0xEF,0x9A,0x2C,0xC1, +0x13,0xB8,0x3A,0xB5,0xC2,0xE0,0x44,0x51,0x63,0x6D,0x72,0x88,0x63,0x60,0xCE,0x0B,0x06,0xDF,0xB4,0x61, +0x15,0x11,0xF2,0xBC,0x9D,0x3C,0xA7,0x23,0x55,0x59,0xC2,0x56,0x75,0xF4,0xAA,0xA5,0x93,0xE5,0x45,0x98, +0x41,0x3F,0xB9,0xDE,0x2A,0x23,0x31,0x81,0x19,0x93,0x73,0xBC,0x23,0x2F,0xF3,0xBC,0xD9,0x42,0x99,0x4C, +0x16,0x12,0x8F,0x35,0x1A,0x37,0x10,0xE4,0xD9,0x81,0x22,0xB6,0xD9,0x92,0xC4,0x82,0x89,0x85,0x54,0xFA, +0x96,0x80,0x12,0x32,0x27,0x90,0x6C,0xEA,0xBF,0xE1,0xCC,0x83,0x0F,0xFE,0x82,0xC6,0x77,0x39,0x3D,0x29, +0x95,0xDB,0x9B,0x57,0xB6,0xC3,0xE1,0x83,0x09,0xA7,0x63,0x14,0x1A,0x36,0xB2,0x16,0x5A,0xE1,0x2E,0xCA, +0x6D,0x9C,0x25,0xF5,0x03,0xD6,0xBC,0xFB,0x23,0x03,0x82,0xEA,0x0B,0x2A,0xF8,0xA1,0xD1,0x29,0x4F,0xEE, +0xCD,0xD8,0xA8,0x4E,0x1A,0xED,0x9F,0x90,0x8C,0xB6,0x37,0x8C,0x82,0xC6,0xE1,0x9C,0x5A,0x15,0x8B,0x40, +0x79,0xD4,0x5E,0xC0,0x0D,0xB5,0xD1,0xA1,0x53,0x6B,0x49,0x4B,0xF8,0xDF,0xE9,0xAA,0xDC,0x8F,0x9A,0x71, +0x45,0x56,0x54,0x9D,0x49,0x2A,0xA7,0x46,0xD6,0xA4,0x03,0x52,0xCE,0x7B,0x78,0x2A,0x4B,0x18,0xA1,0xC8, +0x51,0xAA,0x96,0xCC,0x1C,0xF3,0xF1,0x1D,0xE6,0xBE,0x2F,0xFC,0x18,0xA9,0x78,0x2D,0xD3,0x7D,0x66,0xDC, +0x96,0xFC,0xA1,0x8F,0x0D,0xDC,0x3E,0xB3,0xCB,0x1A,0x47,0xD3,0x5E,0xCA,0xF3,0x8B,0x1D,0x3B,0x3F,0x67, +0xD8,0xA8,0xF5,0x22,0x56,0xA9,0x91,0xEF,0xBF,0x73,0xC8,0x0A,0x97,0x82,0x28,0x0E,0x8D,0xD2,0x36,0x37, +0x02,0x93,0xEB,0x82,0x5B,0xE6,0x31,0x44,0xBF,0x82,0xC9,0x19,0x28,0x35,0x72,0xCE,0x6D,0x60,0x38,0x9A, +0x95,0x1C,0x5E,0x50,0xBE,0x5E,0x28,0xCA,0x55,0x4C,0x23,0x61,0xA7,0x40,0xA9,0x02,0xEB,0x7D,0x32,0x08, +0x31,0xA1,0x22,0xA3,0x80,0x09,0x50,0x75,0x6E,0x92,0x93,0xE4,0xA1,0x0C,0x60,0x23,0xC3,0x33,0x6E,0x06, +0xEF,0x1C,0x18,0xF2,0xBA,0x2B,0x40,0x78,0x9A,0x70,0x24,0x5D,0x60,0x5F,0xA7,0x75,0xAC,0x77,0xC8,0x41, +0x29,0xE1,0xDE,0x52,0x7C,0x20,0x40,0x8C,0xEB,0xC8,0xAD,0xE0,0x9F,0xB6,0xC5,0x67,0x4E,0x05,0x53,0x58, +0x7A,0x0D,0x71,0x67,0x9E,0xC4,0xD7,0xDD,0xE8,0x42,0x37,0xB1,0x83,0x2A,0x69,0x11,0x05,0xF3,0x95,0xE1, +0xD7,0x1A,0x1F,0x05,0x3C,0x41,0x68,0xE8,0x2F,0xD8,0x37,0xFD,0x60,0x07,0x62,0x34,0x7C,0x3C,0x09,0x9F, +0x2A,0x37,0xEA,0xB2,0x8C,0x02,0xB9,0x30,0x71,0xF4,0xC1,0x32,0xE8,0x36,0x01,0x9B,0xAA,0x62,0x79,0x39, +0xE4,0x6B,0x30,0xFC,0xE4,0x05,0x26,0xC3,0xB5,0x87,0x0C,0x1E,0x7D,0x15,0x2F,0xF9,0xC5,0x6A,0x47,0x90, +0x9E,0x58,0xD7,0xA8,0xF5,0x16,0xFB,0x02,0x36,0xAF,0x73,0xCE,0x52,0x11,0xC1,0x41,0xC6,0x07,0x68,0x68, +0x8C,0xC8,0xAC,0xFC,0x5A,0x19,0x7C,0xFE,0xE4,0xCE,0xBA,0xC0,0xE4,0x09,0x1C,0x46,0xB0,0x60,0x19,0x61, +0x81,0x46,0x5B,0xB5,0x22,0x83,0x46,0xCE,0x19,0xB8,0xE3,0x2C,0x27,0x5F,0x53,0x51,0x52,0x3A,0xD0,0xEA, +0xA5,0x20,0xBE,0xC9,0x57,0xFC,0xEE,0xE8,0xB7,0x10,0x9C,0x7B,0xB4,0x79,0xDF,0x8A,0x81,0x6F,0x93,0xAF, +0x32,0x20,0x0E,0x59,0x62,0x22,0xCB,0x5E,0x74,0xB2,0x64,0x97,0x5A,0x6E,0x92,0xAB,0x49,0x1E,0x94,0xD4, +0x9A,0xAA,0x84,0x49,0x80,0x92,0x89,0x07,0xEB,0x5B,0x90,0xF5,0x47,0x0D,0xBA,0xBC,0x88,0xC9,0xB6,0x8C, +0x09,0x53,0xBD,0x17,0xEA,0x84,0x3A,0xE4,0xC1,0x60,0x39,0x4A,0xBD,0x91,0x46,0xC8,0x95,0xF1,0x3E,0xC0, +0x95,0x49,0x85,0xC8,0xE6,0xC0,0x22,0xDE,0x8D,0x05,0xA3,0x57,0x80,0x5B,0x52,0xB7,0x47,0x6A,0x04,0x5C, +0x15,0x63,0x04,0xF6,0x87,0x94,0x8B,0x05,0x05,0x58,0x7F,0xC1,0x34,0xD7,0xC2,0x36,0x2A,0x54,0xE5,0x90, +0xCB,0x7D,0xA2,0x94,0x84,0x55,0x92,0xA1,0xC5,0x68,0x92,0xA5,0x5C,0x71,0x23,0xA6,0xE7,0x73,0x28,0x46, +0x05,0x58,0x7F,0x0D,0x89,0x07,0xD8,0xB2,0xC5,0x1B,0xF1,0xF7,0xF1,0x25,0x49,0xD0,0x1E,0x8F,0xEE,0x4F, +0xA2,0x93,0xF8,0xA6,0xD6,0x28,0xA8,0x7D,0xAF,0xB9,0xA8,0x96,0x96,0xBD,0x26,0xED,0x57,0xF6,0xB0,0x7C, +0xC4,0x27,0x9A,0xEC,0x51,0x7C,0x4C,0x8B,0x9F,0xF8,0xAB,0x66,0x52,0xDA,0x2E,0x9D,0x4F,0x4E,0x37,0xBE, +0x92,0x04,0x85,0x0F,0x41,0x54,0x9D,0xB5,0x46,0x91,0x98,0x59,0x55,0x1A,0xEA,0xA2,0x4A,0x80,0x23,0xD1, +0x08,0x29,0x50,0xBF,0x90,0xC6,0x4E,0xE0,0xB3,0x69,0x18,0x98,0xD4,0xC2,0x96,0x3C,0xF9,0x08,0x98,0xB5, +0x80,0xDF,0xE6,0x3C,0x7C,0x4B,0xCC,0xA5,0x5B,0xBD,0xA0,0xD4,0x8C,0x61,0x6F,0x22,0xAD,0xDE,0x0C,0xC0, +0x61,0x10,0xEF,0x3C,0xED,0x2A,0x6F,0xFF,0xFF,0xFF,0x5A,0x3C,0x68,0xE1,0x96,0x66,0x70,0xA0,0x22,0x10, +0xD3,0xEF,0x9A,0x56,0xF7,0x70,0xBD,0xE3,0x8D,0x40,0xA5,0xE7,0x9D,0x60,0x66,0x37,0x65,0xEA,0xC7,0x56, +0xA2,0x67,0x7F,0x07,0x61,0x81,0xFF,0x03,0x71,0xA1,0xB1,0x53,0xA2,0x1E,0x2E,0xC3,0x52,0x5E,0x22,0x6A, +0x50,0x7F,0x36,0x24,0x30,0xA2,0x61,0x25,0x21,0xC2,0xB9,0x92,0x70,0x6A,0x29,0xAB,0x39,0xC2,0x21,0xBA, +0xEB,0x12,0xFC,0x12,0x9C,0xBB,0x40,0x16,0x61,0xAA,0x11,0x00,0xA6,0xDA,0xF2,0xB9,0x63,0x7E,0x01,0x90, +0xCE,0x08,0xB8,0x22,0xCE,0x27,0xBD,0x3F,0x98,0x69,0xBE,0x3F,0x00,0xB9,0x6B,0xF3,0xC2,0x99,0x29,0x6D, +0x75,0x27,0x48,0x37,0x7C,0x69,0xCD,0xBE,0x20,0x49,0xBE,0x0F,0xA2,0x43,0x5E,0x7B,0x51,0xAB,0xBD,0x47, +0xB5,0xA3,0x12,0xFF,0x9C,0xA5,0xC2,0xDB,0xCC,0xC5,0x52,0xA8,0x70,0x8E,0x57,0x9C,0x55,0x94,0x1A,0x2D, +0xB8,0xA8,0x8A,0xDA,0xB0,0xE2,0x31,0x99,0x8C,0x77,0x7B,0x0D,0x0A,0x7F,0xD1,0x46,0x73,0x4E,0x41,0x66, +0x23,0x2E,0xB3,0x3C,0x55,0x09,0x33,0xE7,0x25,0x06,0x2B,0xEE,0x1D,0xA6,0x63,0x3D,0x4B,0x3E,0xE6,0xD4, +0x90,0x04,0x1B,0xC2,0xAF,0xFA,0x42,0x51,0x44,0x2A,0x2C,0x8A,0x58,0x01,0x7D,0x48,0xC7,0x91,0x42,0x49, +0xFE,0x42,0x7E,0x3E,0xE0,0x48,0xCA,0xFC,0x17,0x8B,0x4A,0x74,0xBA,0xAC,0xF8,0xCD,0xAA,0x1E,0x69,0x02, +0x3B,0xB1,0x49,0x6B,0x00,0x41,0x7E,0x23,0x2F,0x32,0x4A,0x26,0x2C,0x72,0xF3,0xA3,0x37,0x22,0x02,0xBB, +0x6E,0xD0,0x21,0xF5,0xB8,0x4F,0xBB,0x71,0x83,0x50,0x7F,0xA0,0x36,0x29,0x6A,0xA6,0x81,0xD3,0x2C,0x4C, +0xBE,0x8C,0x8B,0xEA,0x9C,0xBA,0x34,0x0B,0x23,0x7C,0xE3,0x58,0x81,0x1C,0xA3,0x4B,0x42,0xD7,0x65,0xAE, +0xDA,0x52,0x85,0x42,0x83,0x49,0xBF,0x52,0x6C,0x13,0x6D,0xAD,0x0D,0x3D,0x75,0x95,0x23,0x66,0x6E,0xB1, +0x2C,0xCE,0x96,0x57,0xF1,0x1E,0xA7,0x53,0xE1,0x8E,0xBB,0x28,0x15,0xB9,0x9A,0x26,0x36,0xB1,0x2D,0xC4, +0x51,0xAD,0xAA,0x44,0x11,0xD8,0x8C,0xF0,0x43,0x0E,0x66,0x9B,0x92,0x2A,0xA3,0xB7,0x8A,0x0F,0xE6,0x44, +0xE6,0xDA,0xD6,0x37,0x91,0xC0,0x76,0x27,0x96,0x30,0xED,0x1F,0xF2,0x1B,0xC3,0x45,0x19,0x32,0xAA,0x55, +0x83,0xC8,0x79,0xB7,0x08,0x52,0xBA,0x0E,0x0A,0x6D,0x79,0x97,0xD0,0x37,0xE0,0xAC,0x4B,0x14,0x2B,0x0E, +0xB8,0xB2,0x99,0x4E,0x4C,0x55,0x6E,0x2E,0xF8,0xDF,0x34,0x28,0xB0,0xB6,0xEE,0x9E,0x36,0x34,0xDE,0xAD, +0xD0,0x37,0x8A,0x2B,0xF9,0xD9,0x11,0xA0,0x43,0x5E,0xBF,0x65,0x60,0xF5,0x6C,0x8E,0x49,0xE5,0xAF,0xCD, +0xFE,0x38,0xAB,0xBD,0xCA,0x33,0xD6,0x71,0x5E,0x3D,0xA0,0x2B,0xE9,0x86,0x33,0x18,0x2C,0x18,0x1F,0x98, +0x2C,0x1D,0xFE,0x22,0x96,0x31,0xB5,0x16,0x4E,0xE3,0xF2,0x67,0x9B,0xD3,0x5E,0x26,0x96,0xE2,0x26,0xED, +0xDA,0x26,0xF2,0x87,0xB1,0xC0,0x8E,0xCD,0xDA,0xDC,0x55,0x21,0xE3,0x5C,0x3A,0xE9,0x3D,0xCC,0x6D,0x7B, +0xEA,0xC1,0xC4,0x1E,0x82,0xD3,0x94,0xD9,0x98,0xB9,0xFF,0x2B,0x9F,0x9E,0x45,0xFB,0x58,0x82,0xE7,0xCD, +0x70,0xD0,0xB0,0x39,0x34,0x75,0xF2,0x4D,0xFF,0xC4,0xD6,0x06,0xAF,0xA4,0x0B,0xAF,0xFB,0xE6,0x9F,0x3A, +0x03,0x9A,0x92,0xA6,0x8C,0x0E,0x2D,0xB6,0x19,0x5C,0x78,0xB2,0x7D,0x07,0xB7,0x87,0xBD,0x4A,0x99,0x23, +0x7F,0xE6,0x6F,0xC1,0xC0,0x6F,0x91,0x81,0x75,0xEB,0x45,0xE3,0x01,0x22,0x0D,0x33,0x7E,0xE7,0x01,0xC9, +0x69,0xCE,0x99,0x26,0x58,0x80,0x78,0x93,0x35,0x30,0x70,0xAE,0xD5,0x09,0x71,0x04,0xBD,0xD4,0x22,0x90, +0x72,0x12,0xEA,0xA3,0x7F,0x85,0x21,0xB0,0x33,0xC9,0x87,0x56,0xE6,0x5A,0x41,0x06,0xD7,0xF3,0xA1,0x63, +0xE9,0x8E,0xAC,0xA1,0x86,0x0B,0xC9,0x9D,0xD6,0x8B,0x4A,0x17,0x56,0xF9,0x37,0x6F,0x78,0x9C,0xB0,0x61, +0x72,0x21,0xCD,0x11,0x3C,0xA2,0x69,0x05,0x3C,0x5D,0xB4,0xE0,0xA9,0x77,0x98,0xBE,0x85,0x07,0x4D,0x0E, +0x2F,0x6C,0x19,0x8B,0x89,0xF6,0x54,0x1C,0xEC,0x0A,0xD4,0xFC,0xFD,0x18,0x68,0x74,0xA6,0xAD,0x01,0xB7, +0xF2,0xF2,0x79,0x58,0xE4,0x9B,0x07,0x2B,0x6C,0xA5,0xA4,0xD8,0x48,0x47,0xCE,0xC6,0x02,0x85,0x82,0xE8, +0x01,0xCA,0x54,0x6C,0x3E,0x38,0xAB,0xCB,0x2D,0xFA,0x58,0x59,0x22,0xFB,0x45,0x39,0x7A,0x43,0xE6,0x6A, +0x7D,0x91,0x4A,0x94,0xE2,0xC1,0x92,0x6C,0x84,0xE1,0xB4,0x1A,0x4B,0x26,0xD0,0xEE,0x8E,0x02,0xC2,0x91, +0x5F,0x80,0xDE,0xB4,0x7D,0xDF,0x3A,0xA7,0x88,0x8F,0xF5,0x76,0x75,0xEA,0x8C,0x0D,0x71,0xDE,0x8D,0xCE, +0xFD,0xAE,0x7C,0x5B,0xE4,0x5E,0x4F,0x7B,0x76,0xC6,0x82,0x73,0x6A,0xB3,0x7B,0x7C,0x3F,0x62,0xB1,0x71, +0xA0,0x1D,0x84,0xA4,0x95,0x3A,0x56,0xA6,0x40,0xDD,0x1F,0x6C,0xCF,0xCB,0xBC,0x62,0x7A,0xE0,0xD4,0xF4, +0xBA,0x37,0x83,0x41,0xC6,0x54,0x40,0x34,0xF5,0x76,0x77,0xC8,0x4F,0xF6,0x22,0x05,0x2D,0x09,0x4A,0x27, +0x9F,0xA4,0xD4,0x40,0x01,0xC0,0x53,0x95,0x44,0x10,0x2F,0xD7,0xB9,0x38,0xAD,0xC0,0x91,0x52,0x85,0xD7, +0xEF,0xFE,0xA4,0xE2,0x16,0x8F,0xDC,0xF6,0xC4,0x1B,0x6E,0xE0,0xF4,0x95,0x54,0x94,0x14,0xC8,0xC3,0xBD, +0xFA,0x4E,0x92,0xD1,0x13,0x4A,0xEB,0x01,0xE3,0x5E,0xED,0x05,0x5E,0x21,0x87,0x47,0x86,0x49,0x45,0xB5, +0xD4,0xE3,0xA1,0x1D,0x85,0xD4,0x8B,0xE0,0xF0,0x0E,0x6D,0x3B,0x69,0xD5,0xD3,0x73,0x69,0x3C,0xC8,0x4F, +0x0C,0xB3,0xE5,0xEC,0xA8,0x63,0x0B,0x79,0xA0,0xD9,0x24,0x6C,0x0F,0x0C,0xB6,0x55,0x6A,0xE3,0x6D,0xAE, +0xA5,0x65,0x9B,0x73,0x29,0x69,0x6E,0xBE,0x9C,0xA2,0x60,0x58,0x69,0xDF,0xBF,0xBC,0x35,0x95,0x79,0x69, +0xA8,0x9C,0x1D,0x74,0x8F,0x6C,0x92,0xD4,0x61,0x9B,0x98,0xE5,0x05,0xE6,0x14,0x6A,0x0E,0x5B,0x76,0xE9, +0x42,0xA0,0x8A,0x2C,0xC9,0x26,0x6B,0xE1,0xD3,0x27,0x76,0xE2,0x1D,0x8A,0xC6,0x24,0x57,0x9F,0xE6,0x15, +0x95,0x71,0x3D,0x11,0x97,0x46,0x49,0xAC,0x1C,0xF6,0x58,0xA8,0xFD,0x1D,0x07,0x8B,0x74,0xCB,0xEC,0xED, +0x79,0x05,0xA7,0xEB,0x59,0x85,0x86,0xEB,0x33,0xA5,0xBE,0x70,0x8D,0xDA,0xE1,0x8D,0x96,0xF3,0xAF,0xFB, +0x0E,0xDE,0xAE,0xA9,0x7D,0xBF,0xEF,0x74,0x10,0x02,0x50,0xD0,0xDE,0x82,0xEC,0x93,0x29,0x0A,0xF8,0x86, +0x15,0xEA,0xD0,0x7D,0xCD,0xED,0x9C,0x4A,0xF1,0xEA,0xE4,0x83,0x5E,0x0B,0xB0,0xC4,0x6E,0x2E,0x0B,0x40, +0xC1,0xC7,0xA5,0xB0,0x36,0xCE,0xCF,0x2F,0xD7,0x5F,0xF9,0x87,0x95,0x26,0x06,0xB3,0x3F,0xEF,0xEE,0xC7, +0x52,0x4A,0x02,0x7E,0x7E,0x41,0x3D,0x77,0xD2,0xFC,0x39,0xF1,0xD1,0xC8,0xF9,0x71,0xD5,0x6E,0x9E,0x55, +0x26,0x05,0xF8,0x34,0x1A,0x2D,0x02,0x2B,0xA9,0x20,0xB6,0xC0,0x51,0xA4,0x11,0x7B,0xA6,0x0C,0x92,0x55, +0xB0,0x3E,0xBD,0x6F,0x73,0x07,0xFD,0x49,0x4B,0x52,0x11,0x45,0x2B,0x17,0x43,0xC7,0x57,0x1A,0x69,0x9A, +0xC4,0xFD,0x72,0xC1,0x0E,0x05,0xC9,0x32,0xB3,0xAA,0x67,0x33,0xB0,0x35,0x97,0x52,0x34,0x22,0x5E,0xC3, +0x3A,0x44,0x8D,0x0A,0xBD,0xF9,0xFA,0x8E,0x19,0x6A,0xB2,0x19,0x13,0x57,0xD8,0xD7,0xFB,0x6E,0x99,0x3F, +0xA8,0xA6,0xB2,0xCC,0xE2,0x26,0x55,0x29,0x6B,0xE4,0xE5,0xDE,0xDB,0x21,0xC3,0x54,0xDC,0xA5,0xBB,0xDD, +0x27,0x25,0x2D,0x10,0x6F,0xEA,0x1B,0x39,0x79,0xE0,0x9C,0xDE,0x43,0xBA,0x3F,0x7F,0xDA,0xDC,0x4B,0x7E, +0x0B,0xBB,0x1A,0x5F,0x9A,0xD4,0x8F,0xA8,0x16,0x17,0xA2,0x1A,0x83,0x21,0x6A,0x80,0x06,0x90,0xA8,0x8C, +0x56,0xC1,0x2A,0x0E,0x92,0x00,0x93,0x1F,0xBE,0xA1,0x33,0x93,0xB4,0xC6,0x36,0x0F,0x71,0xEB,0x4C,0x2F, +0xA9,0xCE,0xDB,0xC9,0x7B,0x21,0xFF,0xEC,0x1F,0x2C,0x83,0x9F,0xFB,0xA7,0x53,0x49,0x6A,0x14,0x81,0x40, +0xA8,0x43,0x94,0x48,0xA7,0xE0,0xCB,0x0E,0xF9,0xE9,0xFF,0x20,0xCD,0xF0,0xFC,0x06,0x35,0x69,0xEB,0xDA, +0x66,0xA8,0x4B,0xD4,0x76,0x0B,0x36,0x0E,0xD6,0x7D,0x2C,0xF6,0x70,0x71,0xE1,0x34,0x3C,0x6F,0xA4,0x4B, +0xB0,0x13,0xA9,0xF3,0x7E,0xED,0xBF,0x67,0x32,0x1A,0xD3,0x4F,0x4C,0x5F,0x8A,0x27,0xF5,0x90,0xB2,0x02, +0x8B,0x98,0xF5,0x65,0xB9,0x71,0xA4,0x53,0x4D,0x2E,0x59,0x65,0xFD,0x70,0x7C,0xB0,0x2A,0x1F,0xBA,0x61, +0xD3,0x0B,0x33,0x68,0xC7,0xC2,0xAC,0xE0,0x9B,0xE5,0x32,0xE5,0x10,0x10,0x9D,0x7C,0x92,0x3C,0xF0,0x62, +0x67,0x5F,0xA7,0xD3,0xD2,0xD4,0xC5,0x82,0x75,0x9B,0x9F,0x96,0x8A,0x74,0x1D,0x71,0x0B,0x47,0x15,0x4D, +0xB3,0x7B,0xF5,0x2E,0x4A,0xF6,0x9A,0x51,0x81,0x80,0xDF,0x8E,0x6E,0xD1,0x09,0x0E,0x1A,0x34,0x26,0x62, +0x5D,0x0E,0x58,0x0C,0x7B,0x87,0x6E,0xB1,0x92,0x58,0xAE,0xB8,0xFA,0x30,0xBD,0x95,0xA9,0x7C,0xB6,0xCC, +0x79,0x36,0x8E,0x3A,0x6C,0xC0,0x21,0xEE,0x77,0x1B,0x4F,0xCC,0xBC,0x1E,0xFF,0x0F,0x9A,0x4F,0x13,0xB1, +0x68,0xA6,0x93,0x29,0x97,0x9A,0xA3,0x71,0x77,0x56,0xB7,0xCD,0xB8,0x34,0x25,0x5B,0x6B,0x13,0x5B,0x6D, +0xF1,0x78,0xEA,0x57,0x2B,0x5C,0xFE,0x2C,0x54,0xB7,0xD6,0xA8,0x26,0xD1,0x85,0x16,0xF5,0xC1,0x58,0xED, +0x98,0x50,0xCC,0xBE,0x18,0xEC,0x7E,0xE8,0x23,0xBC,0xD9,0xEF,0x03,0x6E,0x6B,0x17,0xC9,0xE6,0x54,0xE4, +0xBC,0x2D,0x37,0xBF,0x7F,0x51,0x30,0x97,0x2C,0x76,0x57,0x21,0x42,0xFE,0xE0,0xB6,0x62,0xCA,0x73,0xB5, +0x02,0x25,0x6A,0xC1,0x03,0x5C,0x1E,0x3A,0x65,0x84,0xD8,0x64,0x57,0x5E,0x78,0x26,0x6D,0x8C,0xC8,0xA4, +0x51,0x30,0x08,0x98,0x04,0x41,0x90,0xC6,0xE2,0xAE,0x07,0xA1,0x20,0x5C,0xD8,0x72,0x5D,0xA3,0x58,0x70, +0xF0,0x0B,0xD9,0x85,0x95,0xE0,0x0B,0xD8,0x37,0xAE,0x89,0xF7,0x2F,0xED,0x0F,0x2F,0xF5,0x27,0x1D,0x75, +0xD6,0xDC,0x5F,0x42,0xC6,0xD2,0x63,0xC9,0x57,0xAB,0xCC,0xA4,0x35,0xA8,0x18,0xC2,0x59,0x49,0xD0,0x10, +0x24,0xF8,0xF4,0xA6,0x49,0x49,0x97,0xBA,0x8A,0xC8,0x78,0x49,0x2B,0xE7,0xB8,0x8B,0xD9,0x68,0x28,0xE4, +0x5F,0xEF,0xD9,0x11,0xC5,0x76,0x81,0x11,0x03,0xA9,0x0F,0x64,0x67,0x79,0x25,0xF5,0xF6,0x4B,0xC5,0xCC, +0x84,0x37,0x70,0xA7,0x15,0xD2,0xB4,0x13,0xFB,0x85,0xB5,0x86,0x74,0xA7,0xB5,0x33,0x0A,0x70,0xDA,0x6C, +0x5F,0x17,0x68,0xD0,0x34,0x67,0xB4,0xAA,0x3B,0x37,0x12,0x5D,0xC7,0x78,0x90,0xFC,0xB1,0xA6,0x44,0x3D, +0xEC,0xC2,0x60,0xC0,0xDF,0xA1,0x4E,0x69,0x7B,0xEF,0xDB,0x8D,0x99,0x2B,0x93,0xDB,0x32,0x59,0xD3,0x6B, +0xC4,0xA8,0xD4,0x65,0x47,0x5A,0xCB,0x5F,0x31,0x2B,0x79,0x40,0xA5,0xC6,0xBC,0xBB,0xBA,0x34,0x3B,0x71, +0xAB,0x73,0xA2,0x2C,0xF5,0x3D,0xBC,0x49,0xBD,0xA9,0xCC,0x57,0xDC,0x99,0x92,0x28,0x3C,0x41,0xB0,0xA1, +0xF4,0xAE,0x41,0xCA,0x43,0x52,0xEC,0xDF,0xA0,0x40,0x3A,0x0C,0x2B,0x7F,0x57,0x2D,0x75,0x1F,0x4B,0x5B, +0xCE,0x71,0xA4,0xEB,0xEC,0xDC,0x93,0xD9,0x16,0xEF,0x95,0xFE,0x74,0xEC,0x97,0x93,0x47,0x82,0xAB,0xC3, +0x28,0x44,0x42,0xBB,0xCD,0x01,0x9C,0x56,0x8B,0xBF,0x29,0x26,0x03,0xFF,0x8C,0xB2,0xF6,0xB8,0x7C,0x62, +0x72,0x30,0xA8,0x74,0xB7,0xB2,0x76,0x49,0xC6,0xD7,0xDC,0xF2,0x33,0xFC,0xE5,0xDE,0xE9,0x98,0xC5,0xC3, +0x78,0x39,0x55,0xE7,0x6C,0xDF,0xB3,0x23,0x9B,0x12,0x7D,0x79,0x00,0x19,0xAB,0xE5,0x16,0xB5,0x6D,0x9C, +0x44,0x59,0x42,0x17,0x54,0x33,0x72,0xA0,0x46,0x14,0xF7,0x42,0x61,0x62,0x2C,0xCB,0x60,0x3E,0xC7,0x46, +0x8A,0x65,0x41,0x21,0xAB,0x98,0x57,0x45,0x15,0xBF,0xD5,0x90,0xEA,0x23,0xAD,0xD9,0x0B,0x40,0x1B,0xC5, +0x47,0x15,0x49,0xB8,0x7C,0x95,0xCB,0x1C,0x64,0x1A,0xD5,0xEA,0x3E,0x67,0x96,0xF4,0x06,0x8C,0x6F,0xC9, +0x95,0x43,0x35,0x6A,0xD4,0x62,0x29,0xCD,0xD1,0x02,0xA1,0x6A,0x48,0x63,0xF6,0x27,0x9F,0xBE,0xC1,0x48, +0xEE,0x90,0xD6,0xEA,0x64,0xBA,0xEE,0xC7,0x9D,0x34,0xFE,0x93,0x9E,0xBF,0x8A,0x4A,0x61,0xD6,0x7A,0x1E, +0xDC,0x39,0x23,0x0F,0x8F,0xC9,0xF7,0x16,0x1F,0xBC,0x2F,0x5B,0xED,0xD5,0x69,0xBA,0x01,0x96,0x3C,0x79, +0x44,0x2A,0xFF,0xAA,0x1E,0xBD,0x5F,0xFF,0xFA,0x56,0xDF,0xFB,0xA5,0xB9,0xE0,0x94,0xA3,0xFE,0xB2,0xC5, +0x4A,0x00,0xCE,0x15,0xCF,0x2D,0xE1,0x6A,0x53,0xA6,0x91,0x2A,0x26,0x3C,0x2E,0x02,0xE9,0xD1,0x86,0xF2, +0xCA,0xD4,0x3E,0x56,0x3F,0x76,0xCC,0x4E,0x3D,0xA1,0xDA,0x94,0x42,0x0F,0x0F,0x99,0xDD,0x12,0xAD,0xD3, +0x96,0x8F,0xF9,0x28,0x2B,0x12,0x50,0x4C,0x91,0x62,0xFC,0x79,0x76,0xBF,0xFB,0x1D,0xDB,0xFF,0x60,0x56, +0xB2,0x42,0xB8,0x56,0x53,0xD0,0xD0,0x51,0xB8,0xED,0x87,0xA0,0x6E,0x9A,0x08,0x10,0x83,0xCD,0x7A,0x6A, +0xB2,0x44,0xD7,0x77,0x9F,0x4B,0xE0,0x47,0x25,0xDE,0x86,0x27,0x80,0x02,0x88,0xFA,0x12,0xEE,0x8D,0xB1, +0x3F,0xEF,0x2A,0xC7,0x7C,0x9F,0x7A,0x95,0xDD,0x46,0x36,0xF7,0x1C,0xA5,0x1A,0x22,0x9E,0x3A,0xC2,0x35, +0xEE,0x40,0x48,0x55,0x04,0x77,0xA7,0xBB,0xE7,0xB2,0x90,0xD4,0xF2,0x4C,0xEF,0x23,0x8C,0x6E,0x30,0x41, +0x7B,0x24,0x24,0x2F,0xD1,0x25,0xCE,0x83,0xC7,0xC8,0x27,0x06,0x7D,0xBA,0x91,0x23,0xC3,0x46,0xEE,0x3A, +0x4B,0xB9,0xD2,0x91,0x48,0xE7,0x89,0x1E,0xB2,0x26,0x04,0xAD,0x37,0xFC,0xF2,0x25,0x13,0xA1,0x0B,0x5F, +0x28,0x23,0x66,0x44,0x72,0x98,0x02,0x08,0x08,0x08,0x79,0x72,0xDA,0x28,0xCF,0x29,0xA9,0xF7,0xCC,0x7C, +0x36,0x93,0x72,0x3F,0xAA,0xAD,0x75,0x38,0x9B,0xE5,0x2D,0x29,0x7C,0x69,0x01,0xAB,0xD4,0x72,0x39,0x8B, +0x4D,0xCD,0x8B,0x1D,0xF3,0xB3,0xCC,0x28,0xCE,0xE3,0xBB,0xD1,0x2E,0x28,0x13,0x75,0x60,0x52,0x7D,0x7F, +0x72,0xB2,0xD8,0xBB,0x0C,0x5C,0x74,0x5B,0x13,0x28,0x31,0x73,0x2F,0x97,0xE2,0x0C,0x7E,0x81,0x08,0x69, +0xE9,0xE1,0x69,0xC9,0xAD,0xC1,0xED,0xEC,0xDF,0xAE,0xF4,0x75,0x1D,0x8E,0xCC,0x3F,0x95,0x47,0xE4,0xCC, +0x2D,0xC2,0x43,0xCD,0xAD,0x27,0x52,0x7C,0x3B,0xD1,0xCB,0xF9,0x35,0xE3,0x85,0x50,0x31,0x2A,0x6C,0xE9, +0x5B,0x6C,0xBE,0x1F,0x17,0x23,0x9E,0x0A,0xA7,0x0D,0x7F,0x1F,0x2C,0x0A,0x9D,0xF1,0x09,0x1B,0x0E,0x69, +0x81,0x6B,0xD4,0xFD,0x08,0xAF,0x41,0xC9,0x73,0xD3,0x8F,0x63,0x14,0xBC,0x39,0x69,0x80,0xEA,0x90,0x32, +0xA4,0xC6,0x98,0x56,0x98,0xC0,0x90,0xF2,0x81,0x1B,0xF7,0x7C,0xB2,0xA9,0x4C,0xA8,0xE6,0xA2,0x55,0x08, +0xD6,0xF9,0x91,0x63,0xE1,0xEC,0xFF,0x11,0x84,0x44,0xDD,0xEC,0xE6,0x11,0xBB,0xD0,0x52,0xF6,0x9D,0xC0, +0xC3,0xAB,0x44,0xD5,0x0A,0x30,0x7D,0x13,0xEE,0x59,0xC6,0x64,0x99,0x30,0x32,0xE5,0xCA,0xF4,0x45,0xF0, +0xB6,0x44,0x62,0x95,0xAB,0xB4,0xA2,0xF3,0xD2,0x2A,0x85,0x24,0x51,0x9B,0xA1,0xD4,0xDE,0x1E,0x4F,0xE4, +0xC1,0xED,0xEB,0x07,0x90,0x03,0xE1,0x42,0x86,0x1F,0x94,0x4E,0x16,0x98,0x25,0xC3,0x2B,0x58,0x69,0x97, +0x4C,0x1B,0x3C,0x67,0x53,0xE7,0xB8,0xE9,0x58,0xE7,0x99,0x99,0x97,0x1A,0xB0,0x4E,0x16,0xD7,0x96,0x08, +0xD6,0xB4,0x99,0xEF,0x41,0x55,0x60,0x58,0x9C,0xDA,0xA0,0x09,0x57,0xE6,0xC7,0xF8,0x50,0xB7,0xF9,0xB1, +0x59,0x95,0x94,0x5C,0x09,0xAB,0xC6,0x9C,0x59,0xC5,0x13,0xDE,0x77,0x11,0xE9,0xF9,0xB8,0x7B,0x1B,0x4A, +0x94,0x19,0xA0,0x8D,0x6B,0x84,0xC6,0xA9,0x33,0xB1,0x51,0x3C,0xC5,0x73,0x43,0x1B,0x5E,0xD1,0x69,0x63, +0x91,0x1F,0x76,0x26,0x87,0x10,0x56,0x9C,0x33,0x7C,0xF2,0x6B,0x46,0x57,0x8E,0x8B,0x67,0x11,0xD1,0x4D, +0xCC,0xFC,0xF9,0xF0,0x37,0x98,0x29,0xC1,0x03,0x4F,0x6C,0x63,0x11,0x3D,0xB0,0x1E,0xAD,0xDC,0xF5,0x2E, +0x99,0x90,0x46,0x8A,0xDF,0xFE,0xE5,0x6E,0xD5,0xD0,0xCC,0x91,0x2D,0x8A,0xA6,0x7E,0x30,0x2D,0xF0,0x7F, +0x74,0x3F,0x8E,0x87,0x52,0xB3,0x16,0x7F,0x8A,0x27,0xF1,0xC8,0xB2,0xB1,0xB4,0xB0,0x80,0xD6,0xEC,0xD0, +0x45,0x4C,0x78,0x10,0xD3,0xFB,0xDF,0x3A,0x7F,0xA1,0x68,0x2A,0xC2,0x32,0x12,0xE7,0x98,0x4F,0xE6,0xD3, +0xCC,0xC1,0x51,0xEB,0x21,0x58,0xF9,0x6E,0xC2,0xA6,0x69,0xD1,0x3C,0x32,0xD3,0x33,0xFA,0x4D,0x40,0x01, +0xBA,0xA9,0xA2,0x2D,0x40,0x07,0xC8,0x99,0x9E,0x47,0x15,0xB8,0xFB,0x46,0x86,0x50,0x13,0x07,0x70,0x6E, +0x24,0xA3,0xA6,0x94,0x53,0x58,0xA1,0xEE,0x00,0x0B,0x86,0xB8,0xDE,0xE2,0x36,0xE7,0xA0,0xD3,0x51,0x74, +0xB4,0x82,0xDA,0xE2,0x81,0x57,0x4D,0xC6,0x13,0xAA,0x6F,0x46,0x2C,0x83,0x39,0x6A,0x26,0xEA,0xAD,0xF6, +0xF1,0x29,0xD1,0xE3,0x5F,0xF7,0xF2,0x77,0x7C,0x37,0xA4,0x8E,0xB7,0xEB,0xD1,0x3D,0xAC,0x76,0xF3,0x7D, +0xB8,0x06,0xAD,0xC9,0x38,0x14,0x2D,0xD6,0xED,0x24,0xBE,0x8F,0xD1,0x5A,0xDC,0x8B,0xB3,0x35,0xF3,0x37, +0xA3,0x47,0x89,0x9E,0xA0,0x45,0xEB,0xCB,0xDE,0x26,0xA5,0x17,0x38,0x04,0x69,0x3A,0x26,0x72,0x17,0xBA, +0x50,0xA9,0xBC,0xA2,0x9D,0x51,0x81,0x8C,0x9A,0xA2,0x48,0xDA,0xFA,0x63,0x0B,0x49,0xFF,0x93,0xFA,0xA6, +0xBB,0x76,0x92,0x4F,0x2F,0x0D,0x20,0x11,0x27,0x2C,0x41,0xF0,0xA8,0x46,0x9B,0x43,0x73,0xC1,0x47,0xAD, +0x32,0x53,0xD7,0x9B,0xC6,0xC1,0x5F,0x10,0x40,0x11,0x8B,0x28,0xAA,0xF0,0x7A,0x2C,0xAB,0xA4,0x05,0x7D, +0x2E,0x4C,0x83,0x7B,0x26,0x6A,0x27,0x91,0x0D,0xC9,0xA8,0x9F,0xDD,0xB3,0xA9,0x60,0x62,0x28,0x8F,0x16, +0xB4,0x2F,0x9B,0xF7,0x23,0x38,0x3B,0x33,0xC2,0x4C,0x90,0x36,0x39,0x23,0x1C,0x46,0xFD,0x62,0x1F,0x6C, +0xDF,0xB2,0xB3,0xE5,0x4B,0x1F,0x50,0x27,0xB9,0x5B,0xEF,0xE5,0x8C,0x5D,0x1A,0x80,0x8C,0xCA,0xBF,0xFD, +0x4A,0x6E,0x75,0xA7,0xE3,0x2B,0x8A,0xB1,0x06,0x5E,0xAD,0x02,0x22,0xBD,0xB0,0x37,0x54,0x21,0x4C,0x1D, +0x8F,0xE5,0x20,0x94,0xBC,0xB7,0xFA,0x21,0xA3,0x18,0xAC,0x2E,0x8B,0x40,0xEB,0x01,0xE3,0x5E,0xEA,0x57, +0x9C,0xD6,0x6B,0x33,0x20,0x37,0xBB,0x76,0xB4,0x0D,0xA1,0x1D,0x85,0xC0,0x8B,0x43,0x1F,0x95,0x3F,0xFD, +0x4C,0xF3,0x7A,0x53,0x88,0x81,0x5F,0x4F,0x0C,0xB3,0xC3,0x53,0x9D,0xF4,0x20,0xE7,0xAC,0x1F,0xF4,0x3C, +0xCB,0x15,0x53,0x2E,0x30,0x8C,0x2A,0x9F,0x51,0x87,0x50,0xF7,0x12,0x66,0xF1,0xDC,0x4E,0x6E,0x14,0x50, +0x2E,0xD6,0xFE,0x56,0xCD,0x34,0x19,0x57,0x8D,0xEA,0x34,0x60,0x8B,0xBA,0x57,0xFD,0x0A,0xD7,0x77,0x5A, +0xFD,0xFE,0x15,0x60,0xD2,0x64,0x6F,0x2B,0x46,0x16,0x16,0xD3,0x1A,0xBE,0x53,0x3B,0xC3,0x82,0x3C,0xCB, +0x8D,0x31,0xD1,0xF3,0xC2,0x1F,0x4E,0x10,0xC2,0xD1,0x88,0x4E,0x26,0xF8,0x16,0xDE,0xCF,0x1C,0x7B,0xAC, +0xC4,0x10,0x00,0xFC,0x0C,0xF9,0x2B,0x23,0xDE,0x62,0xF1,0xAB,0xFC,0x35,0x54,0x7F,0xB8,0xF5,0x08,0x1B, +0x6F,0x2F,0x55,0x9C,0x82,0xBC,0xEC,0x5F,0xC9,0x2D,0x73,0xEF,0x48,0x40,0xBF,0x4F,0x68,0xB3,0x4B,0x9D, +0x04,0x62,0xAC,0x85,0xF7,0xBD,0xD6,0x34,0xEF,0x8F,0x87,0x4B,0x46,0x61,0x16,0xC6,0xD2,0x63,0x5C,0x8F, +0xE8,0x02,0x77,0xE7,0x37,0x4D,0x66,0x91,0xC3,0x45,0xF8,0x94,0x5F,0xEA,0xC5,0xFE,0x0D,0xAF,0x55,0x76, +0xF2,0xA1,0x5D,0x32,0x63,0x41,0xD7,0xD5,0xD8,0x6D,0xEA,0xD1,0x85,0x4D,0xB7,0xB0,0x5B,0xD2,0x16,0x53, +0xCF,0x21,0x1F,0xD7,0x53,0x60,0xC8,0xA9,0xA1,0x02,0x92,0x6B,0xE5,0x89,0xE5,0x91,0x6C,0x46,0x9A,0xF1, +0xB9,0x00,0x28,0x14,0x74,0x85,0x97,0x3E,0x60,0xA2,0x0E,0xF0,0x8B,0x66,0xE0,0x87,0x6B,0xD1,0xC9,0xBC, +0x63,0x09,0x95,0xAA,0xA5,0x26,0x0F,0xD1,0x7E,0xED,0xE9,0x96,0xE2,0x03,0x31,0xD3,0x86,0x03,0x09,0xE1, +0x68,0x29,0xCE,0x02,0xBF,0x4E,0x79,0x6F,0x5F,0x6A,0x97,0xF8,0xB1,0xA9,0xBC,0xA8,0xD2,0xF9,0xD6,0xF8, +0x40,0xF1,0x91,0xDC,0x54,0x67,0x32,0xAA,0x05,0x69,0x5A,0x0F,0x65,0x4A,0x22,0x08,0x6D,0xE6,0x90,0x3D, +0xFA,0x6F,0x94,0x8D,0xB6,0xC9,0xCB,0x19,0x50,0xFB,0x0B,0xA8,0x39,0xEB,0xF3,0x69,0x87,0x67,0xBB,0x34, +0xAD,0x67,0x27,0x6E,0xB7,0x8D,0xBB,0x4B,0xAB,0x77,0xCB,0x12,0x78,0xE3,0x7A,0x98,0xD5,0x03,0xFA,0xA3, +0x99,0x21,0x03,0x1B,0x20,0xCD,0x2B,0x4B,0xFB,0xE3,0x00,0xB7,0xA8,0x00,0xA2,0x3E,0xA8,0x50,0x08,0x82, +0x20,0xE5,0x82,0x35,0x30,0x8C,0x23,0xFC,0xA4,0x03,0x3A,0x8F,0x3B,0x11,0xD3,0x92,0x2B,0xED,0x8B,0x69, +0x6F,0xE1,0x41,0x58,0x28,0x02,0x5C,0xA2,0x2E,0xFC,0x5B,0x6A,0xE9,0x87,0x5F,0xF9,0x98,0x5F,0x12,0x00, +0x13,0x8C,0x52,0x7E,0xCB,0x72,0x72,0x01,0x8B,0xF3,0xEC,0xC6,0x33,0xCF,0xCC,0x3C,0xCB,0x7F,0xB4,0xEB, +0xB0,0x3C,0x62,0x00,0x88,0x32,0xA6,0x56,0xF3,0x39,0xC5,0x2D,0x76,0x02,0x82,0xFF,0x45,0x3E,0x2B,0x11, +0x2A,0x51,0xED,0x27,0xF5,0xB8,0xCD,0x8C,0xFF,0x1B,0x3E,0x25,0x4D,0x90,0x0F,0xFB,0x1E,0xDE,0x54,0x57, +0x73,0x3B,0x4D,0xD0,0x81,0x99,0xB7,0xFF,0xB6,0xAB,0xEF,0x51,0x00,0xFB,0x67,0xCD,0xC1,0xC9,0x76,0x2F, +0x27,0x4E,0x6C,0x27,0x07,0xC1,0x76,0x82,0x88,0x96,0x1C,0x24,0x1B,0xF8,0xBA,0x45,0xD1,0xE5,0x05,0x00, +0x2B,0xC3,0x07,0x70,0x9E,0x52,0x2D,0x15,0x8A,0x47,0x3D,0x55,0x9D,0x51,0x58,0x25,0xEE,0x06,0x23,0x44, +0xD0,0x59,0xA5,0x9E,0xF5,0x1D,0x02,0xAC,0xA7,0x59,0x46,0xA8,0x6E,0x36,0x40,0x0C,0x9F,0x34,0x48,0x5C, +0x44,0x77,0x25,0xE3,0x08,0xC9,0x75,0x18,0x6D,0xD2,0x78,0x84,0x68,0x1B,0xD4,0xEB,0x38,0x69,0xAB,0xAD, +0x79,0xE7,0xBF,0x72,0x3B,0x37,0xA8,0x3A,0x94,0x87,0xF7,0xCD,0x84,0x77,0x56,0xDD,0x0C,0xB4,0x1F,0x1F, +0xB8,0x59,0x21,0x08,0x89,0x47,0xE7,0xDF,0xBA,0x64,0x78,0xAD,0x68,0xB3,0xBF,0xAA,0x19,0x2D,0x96,0xF5, +0xE5,0x5C,0xAE,0x92,0xD9,0x19,0x30,0x79,0xC2,0x74,0xF6,0x22,0x97,0x30,0x20,0xC5,0x82,0xAC,0x12,0x07, +0x92,0x6C,0x17,0xBA,0x8F,0x9C,0xE0,0xCB,0x6A,0x5A,0x57,0xE9,0xEA,0xD3,0x68,0x0F,0x43,0x3C,0x11,0x3B, +0xAF,0x9A,0xB5,0x3D,0xBF,0xE2,0xF3,0x6A,0xC9,0x55,0xA7,0xDA,0x12,0x4E,0x1F,0x91,0x2E,0x2F,0x37,0xF5, +0x3A,0x0D,0xF0,0x06,0x06,0xDB,0xB8,0xC4,0xD6,0xE3,0x56,0xB6,0x36,0x35,0x78,0x51,0xFC,0x02,0x2E,0x50, +0x25,0x41,0xC0,0x11,0x36,0x11,0xF5,0x79,0x4E,0x81,0x71,0x94,0xE0,0x0D,0x11,0x21,0x98,0x5F,0xB7,0x45, +0x95,0xF2,0x93,0xEC,0x0A,0x2E,0xCF,0x2A,0x7E,0x00,0x47,0x35,0x24,0x40,0xC1,0xB5,0xF7,0x93,0x6A,0x46, +0xA5,0x7F,0x1B,0x2D,0x6C,0x1B,0xC5,0xC7,0xF2,0x87,0x4B,0x84,0xFA,0x19,0x08,0xE7,0x67,0x08,0x80,0xD2, +0x4B,0x63,0xB8,0x1E,0xF9,0x68,0xDE,0x5A,0xDB,0xA7,0x98,0xC7,0xB9,0x3F,0xD8,0xFF,0x65,0xBD,0xC6,0xD2, +0x32,0x45,0x89,0x74,0xEA,0xA2,0x11,0x74,0xE4,0x78,0xD7,0xF6,0xFF,0x44,0x29,0xF7,0xF9,0xCF,0xB3,0x6A, +0x3E,0xF6,0xF6,0x95,0x6F,0x8C,0x9C,0xBE,0xD6,0x79,0x1F,0xAE,0x68,0x4A,0x8A,0xFE,0xFF,0xE7,0x22,0x1E, +0x8A,0xF8,0x1D,0xBB,0x1B,0xE8,0x68,0x32,0xE8,0x66,0xFD,0xDC,0xDF,0xA1,0x5A,0x7A,0xAA,0x9C,0xDD,0xBF, +0x68,0xE9,0x6A,0xD7,0x69,0x65,0xD3,0x8F,0xD6,0x61,0x7B,0x36,0xC7,0x8A,0x68,0x21,0xFB,0x5E,0x6D,0x7C, +0x24,0x68,0x77,0x5D,0x9E,0x34,0x1A,0x6D,0x6D,0x6C,0x9C,0xFB,0xFF,0x0F,0x64,0xCF,0xA5,0xAF,0x8A,0x49, +0xB7,0xDD,0x12,0xD8,0x2D,0xCC,0x7D,0x5C,0xC1,0xEC,0xAA,0xFE,0x71,0x1E,0xC0,0x8E,0x02,0xDC,0x1B,0x6C, +0xED,0x71,0x31,0xBC,0xF8,0x0E,0xC8,0xDA,0xE8,0x61,0x8B,0x1C,0xB2,0xE5,0x51,0xB9,0x0D,0x87,0xD1,0xB4, +0x99,0xC5,0x6D,0xCA,0x24,0x6C,0x82,0x19,0x24,0x64,0xF6,0x8A,0x81,0x3F,0x9C,0x56,0xCF,0xBF,0xCB,0xD0, +0x0E,0x53,0xCC,0x24,0x1A,0x93,0x0C,0x8A,0x16,0x62,0xCC,0x36,0x89,0xBC,0xDB,0xC1,0x43,0x07,0xDC,0xF2, +0x54,0x7C,0xF3,0x01,0x24,0xE8,0x9D,0x57,0x0B,0xBD,0xCE,0x64,0x0D,0xB1,0x8D,0x77,0x2B,0xFD,0x95,0x60, +0xC3,0x83,0xA7,0x87,0x16,0xBE,0x35,0xA7,0x86,0x2B,0xC5,0x90,0x56,0xF5,0xF1,0x39,0xCF,0x9B,0x9E,0x26, +0x32,0x99,0xBD,0x0A,0xE5,0x96,0x8C,0xE4,0x22,0xB6,0x4A,0xB7,0x84,0x10,0x2C,0x06,0x2F,0x3E,0x44,0x99, +0xE6,0xD8,0xCF,0xDA,0x8B,0xC4,0xB4,0x39,0x4F,0xB5,0x99,0x36,0xDA,0xD6,0xA4,0x50,0x57,0xDA,0x3D,0x9B, +0x0E,0x87,0x4B,0x31,0xEE,0x38,0x12,0x35,0x1B,0xB8,0xC4,0xB1,0x46,0xAA,0x4E,0xDF,0xF1,0xBD,0x9E,0x79, +0x42,0x9E,0xEC,0x61,0x9F,0xBE,0x25,0x40,0x8D,0x97,0x3E,0x72,0x3C,0xF7,0x04,0x1E,0x05,0xB3,0xD6,0x1C, +0x1F,0xEC,0x68,0xC9,0x4B,0x7F,0xC6,0x3C,0x78,0xA2,0x07,0x53,0x0D,0xA5,0xF7,0x0F,0xDF,0x4A,0x9B,0xD8, +0xC2,0x7C,0x03,0xCD,0xBD,0xBA,0x09,0x79,0xD9,0x34,0x97,0x4F,0x1E,0x33,0x6D,0xFB,0xBD,0x76,0xE5,0xBE, +0x5E,0xFD,0xEC,0x95,0x93,0x60,0xD8,0xFB,0x1D,0x33,0x5E,0x88,0x87,0x3F,0x6D,0xE7,0xC7,0x75,0x2E,0x36, +0x93,0xDF,0xD4,0x38,0x96,0x92,0xAC,0x5F,0x98,0x20,0x2D,0xDA,0x82,0x7C,0xCC,0xA5,0x7B,0xE5,0xBD,0xF1, +0x86,0xA1,0x61,0x89,0x11,0x73,0x70,0x8F,0xFA,0xD3,0xF6,0x74,0xC4,0xDC,0x2F,0x1A,0x78,0xFD,0x6D,0x7B, +0x10,0x02,0x79,0x0C,0xCC,0xBE,0xA8,0x9D,0x85,0x41,0xA0,0x05,0x9D,0x28,0xC1,0x2F,0x41,0x00,0xF0,0x60, +0xD0,0x6D,0xC8,0x74,0xD1,0x43,0x0A,0x52,0x1D,0x3A,0xA2,0x77,0x83,0x01,0x9F,0x52,0x30,0x41,0xA9,0x20, +0x05,0xE3,0x01,0x24,0x57,0x6E,0x31,0x70,0xF3,0x47,0x9B,0x27,0x73,0x79,0x97,0x61,0x87,0x2B,0xCE,0x73, +0xB0,0x63,0x51,0x70,0xA6,0x03,0xC1,0x9C,0x53,0x6B,0x3C,0xC4,0x65,0xAB,0x42,0x57,0x24,0xB7,0x28,0xE2, +0x47,0x8E,0x03,0xE0,0x34,0x86,0x92,0xA3,0x81,0x2D,0x11,0x22,0xEC,0x49,0xD0,0xBC,0xE0,0x43,0xE6,0xCD, +0xF0,0x27,0x21,0x00,0x69,0x44,0xE7,0xE8,0xE8,0x3D,0x0B,0x64,0x61,0x40,0xEF,0xDD,0x71,0x03,0x36,0xD5, +0xE4,0xA8,0xF7,0xEC,0x4D,0xAC,0xD1,0x11,0xA0,0xBC,0x0B,0x06,0x27,0x68,0x96,0x7B,0x3B,0x64,0x96,0xDA, +0x3A,0x98,0x32,0x91,0x7B,0x9E,0xBA,0x4E,0xAF,0x0D,0x5A,0x3D,0x11,0x08,0xB2,0xAE,0x15,0x49,0xE7,0xC0, +0x49,0xF2,0x6C,0x4E,0xFA,0x6F,0x61,0x0C,0x8B,0x9A,0xC7,0x8F,0x45,0x25,0xAB,0xC7,0xD8,0x07,0xAB,0xD2, +0x5A,0x62,0x1D,0x0D,0xA9,0xAB,0x67,0x1F,0x91,0x47,0x9B,0xC6,0x1C,0x16,0x93,0x8F,0x78,0xF4,0x22,0x09, +0x8E,0x01,0xE2,0xA6,0x73,0xBF,0x2A,0x4F,0x29,0xB3,0xC4,0xC5,0xB1,0x5F,0x8A,0xAD,0x09,0x87,0x18,0x34, +0xEC,0x80,0x62,0xA8,0xB5,0x42,0x8B,0x6D,0x2D,0x45,0x49,0x4D,0x29,0x83,0xA2,0x8D,0x91,0x6C,0x2B,0xEB, +0xE8,0x3B,0x68,0xDC,0xE8,0xC1,0x34,0xBB,0x09,0x47,0x9E,0x60,0x70,0x6B,0x3B,0x3D,0xC4,0x42,0x77,0x59, +0x5E,0x3E,0xE8,0x04,0x1E,0x75,0x6C,0x84,0xB5,0x70,0x97,0x24,0x5E,0x21,0xEC,0xD6,0x8B,0x8F,0xCE,0x56, +0x05,0x15,0x08,0x76,0xB3,0x79,0xD6,0xB2,0x21,0x4A,0xDC,0x90,0x98,0x41,0x0D,0x94,0x82,0xE0,0xE5,0xC1, +0xF7,0xB9,0x1D,0xA8,0xE6,0x21,0x55,0x44,0xEE,0x3E,0xCD,0x69,0xA1,0xA8,0x44,0x77,0x33,0x7B,0x2D,0x45, +0xE9,0x11,0xC5,0xB0,0xF7,0xC8,0x4C,0x44,0x83,0x9C,0x9E,0xC6,0x81,0x9D,0x6E,0x13,0x14,0xF9,0xAC,0xB5, +0x99,0xBC,0x4E,0x32,0xA1,0x5D,0x95,0x88,0xB3,0x07,0x54,0xF4,0x4A,0xE3,0x05,0x5B,0x4C,0x77,0xC5,0x23, +0x03,0x9E,0x14,0x4F,0xB3,0xB6,0x86,0xA6,0x28,0x1F,0x0E,0xE6,0x8D,0x7A,0x5F,0x21,0xAB,0x18,0x61,0xA7, +0x6D,0xC8,0x63,0x94,0x18,0xCC,0x82,0x7F,0x80,0x03,0x86,0x0C,0x70,0x1A,0x9E,0x7C,0x47,0x37,0xC3,0x85, +0x69,0xF8,0xD0,0x28,0x25,0xF5,0xBA,0xD8,0x2D,0x57,0xEE,0xD8,0x36,0x34,0x9E,0x7E,0x41,0x82,0x16,0xAB, +0x98,0x76,0xEB,0xE6,0xAE,0x69,0x33,0x7D,0x47,0x35,0x4E,0x8B,0x0D,0x53,0x3F,0xA9,0xDC,0x7C,0x99,0x5F, +0xF7,0x59,0x85,0x9C,0x1A,0x3D,0xEA,0x44,0xEB,0xF6,0xFF,0xFC,0x0C,0x76,0x26,0x88,0x87,0x13,0xFC,0x5E, +0x3A,0xE3,0x56,0x05,0x18,0xF7,0x16,0x80,0xC4,0xA7,0x36,0x5A,0x2A,0x7A,0x75,0xAC,0xBB,0x22,0xDE,0xC7, +0x51,0x88,0x57,0x46,0x7D,0x8C,0x27,0x89,0x06,0x93,0x6B,0xBE,0x84,0xC8,0x5D,0x45,0x81,0xF6,0x22,0x10, +0xF8,0x3C,0x37,0x5B,0xAA,0x58,0xF1,0x71,0xDA,0x3B,0x0E,0x7D,0xCE,0x30,0xA3,0x3D,0x9B,0x7C,0xA4,0x86, +0x17,0x80,0xA8,0x02,0x3C,0x6E,0x9B,0xA6,0x1C,0xC2,0x04,0x44,0xD9,0x16,0x4A,0x13,0x17,0x4C,0x12,0xF6, +0x11,0x80,0xE9,0x3D,0x46,0xA0,0x07,0xDE,0x51,0x3D,0xCD,0xEB,0x68,0x4F,0x09,0x1E,0xA7,0x14,0x9D,0xCB, +0x1B,0x80,0x4E,0x5D,0x02,0x3D,0x4B,0x13,0x86,0xC3,0x00,0xB7,0x8D,0xA1,0x62,0x33,0xBE,0x43,0x15,0xB2, +0x00,0x81,0xF9,0xB2,0x0E,0x8B,0xDE,0xEE,0x10,0x67,0x7A,0x66,0xE5,0xC9,0xCE,0x7E,0x75,0x1E,0x62,0x56, +0xA4,0x88,0x48,0x45,0x25,0xC1,0xF0,0x1B,0x24,0xE5,0xB6,0xD6,0x57,0xAF,0x01,0x03,0x88,0x8B,0x09,0xB8, +0x5E,0x95,0x7B,0x62,0x65,0xC0,0xA8,0x7E,0x73,0xEF,0x63,0x43,0x24,0x81,0xD1,0xAD,0x3B,0xAA,0x01,0xF1, +0xC2,0x5E,0xE9,0x5B,0x8A,0xA9,0x26,0x55,0x3F,0x5E,0x4A,0x02,0x2F,0x2A,0x9D,0x45,0x91,0x14,0xDB,0xC5, +0xA3,0xEE,0xD5,0xF2,0xDA,0xC4,0xD2,0xF6,0x57,0xE4,0x7A,0x7D,0x7E,0xF7,0x0E,0x41,0xFE,0xEF,0x9B,0xF5, +0x9C,0xC7,0x1B,0x8D,0xBE,0x9A,0x8A,0x75,0xCA,0x7A,0xBB,0x9D,0x29,0xE5,0xD2,0x13,0x28,0xF4,0xCB,0xBF, +0xC1,0xA4,0xFB,0x97,0x51,0xC1,0xB3,0x88,0xBE,0xCB,0x6A,0xCE,0xAF,0x04,0x75,0xBD,0x20,0x31,0x0A,0xE8, +0x47,0x2A,0x63,0xEA,0x2B,0x9E,0x60,0x7A,0xAC,0x80,0xCD,0x28,0xE0,0x12,0xEF,0xEA,0xEC,0x8C,0x42,0x81, +0xB6,0x84,0x67,0xA9,0x22,0x83,0x30,0xBC,0xA8,0xB5,0x71,0x89,0x4C,0x86,0x1B,0x6E,0xED,0x8C,0x61,0x1B, +0x2C,0x89,0x07,0x2C,0xA1,0x19,0xD8,0xD3,0x13,0xFC,0x5C,0x9D,0x3F,0x4B,0xF1,0x76,0x25,0x79,0xA8,0x81, +0x95,0x38,0xAE,0x93,0xC5,0xAF,0xFE,0x5D,0xD7,0xF6,0x3E,0xBA,0x16,0x47,0x68,0xF4,0x74,0xF1,0x06,0x49, +0x61,0xBA,0xC3,0x54,0xF7,0xD9,0x35,0xB2,0x95,0x91,0xE5,0x65,0x36,0xBA,0x0B,0xD2,0xCA,0x8D,0xB9,0x41, +0x55,0x78,0x95,0x6D,0xB5,0xDE,0xD5,0xF5,0xF4,0x33,0x46,0x93,0xE1,0x93,0x47,0xD5,0xB6,0x4C,0x5C,0x12, +0x7A,0x1C,0x85,0x06,0x7E,0xAF,0x4A,0x4E,0x44,0x39,0xA4,0x7E,0x70,0xDE,0x1C,0xA8,0x84,0xF0,0x00,0xA5, +0x4D,0x13,0xA9,0x01,0x59,0x58,0x03,0x31,0x44,0x73,0x75,0x21,0x24,0x9E,0xE9,0xA1,0xF6,0xF9,0xE5,0xA4, +0x07,0x70,0xC0,0x0F,0x0C,0xBB,0x52,0x31,0x25,0x9F,0x24,0xA4,0xAC,0x3E,0x1B,0x5F,0x0C,0x84,0x45,0x68, +0x94,0xF3,0xD9,0x72,0x2C,0x23,0xDE,0xEC,0x7D,0xB9,0x22,0x7C,0x4E,0x18,0xCE,0x2C,0x75,0x27,0x69,0x1E, +0x75,0x9B,0xD6,0x1C,0x38,0x9D,0x5E,0xE5,0xCE,0xD4,0xDE,0xFF,0x84,0xBB,0xA3,0x0F,0xFC,0xAF,0xDF,0xED, +0xFD,0xB2,0xF5,0x0B,0xE0,0xB8,0x8F,0x7F,0x07,0xF5,0xC3,0x73,0x72,0xD9,0x97,0xCF,0xB5,0xB4,0x4D,0xBE, +0xE1,0xB5,0x65,0x41,0x7F,0xD3,0xA0,0xB5,0x8D,0x9A,0xC6,0x24,0xD7,0x2F,0x9A,0x99,0x50,0x7A,0x88,0x0C, +0x6C,0xB1,0x6A,0x38,0xAD,0xD5,0x6C,0xCD,0x4D,0x87,0x5E,0x10,0x86,0x8E,0xF6,0xEE,0xF8,0x6F,0xEF,0xC8, +0x0F,0x16,0xFD,0xCD,0x2C,0xB6,0x20,0x98,0x9C,0x57,0xED,0xED,0x34,0xF1,0x4F,0xB9,0xEE,0x9B,0xC9,0x66, +0xA8,0x12,0x65,0xF9,0x7D,0xD7,0xDF,0xEE,0xF9,0x64,0x6C,0x02,0xDA,0xFB,0xFE,0xA0,0xE5,0x29,0x37,0x18, +0xDC,0xF1,0xDA,0xDF,0xF3,0x66,0x50,0x00,0x32,0x13,0x48,0xC0,0xEE,0x2C,0xD2,0xFF,0xE0,0xEE,0x18,0xD6, +0x3A,0x80,0x10,0xE9,0xD8,0x4F,0x05,0xF4,0xB6,0xDD,0x4B,0x83,0xBC,0x00,0x9D,0xDE,0x71,0xEA,0xB1,0xEE, +0x68,0x93,0x76,0x66,0xB7,0x4D,0xCD,0x76,0x0B,0x33,0x18,0xB1,0x84,0x72,0xC4,0xBD,0xFD,0x45,0x60,0x79, +0xA1,0xA9,0x40,0x14,0xAB,0x4D,0x0B,0x64,0xAA,0x0D,0xCC,0x2F,0x20,0xE5,0xE4,0xE0,0x4F,0x09,0xD8,0x13, +0x57,0xE8,0xED,0x9E,0xEE,0x94,0xFE,0x31,0x86,0x0F,0x39,0xBA,0xDA,0x3C,0x91,0x41,0xBB,0x4E,0x8A,0x65, +0xD6,0xF6,0x29,0x10,0x38,0x0A,0x1B,0x71,0x6C,0xBA,0x45,0xF5,0xE3,0x8E,0x26,0x1B,0xA5,0xB8,0xA5,0xEA, +0xE8,0xF7,0x65,0x4C,0x5C,0x6A,0x6C,0x15,0x23,0x4B,0x82,0x4E,0x5C,0xC8,0x08,0x7E,0x75,0x46,0xF2,0x6F, +0x65,0x20,0x58,0x49,0x75,0x42,0xD0,0x29,0x79,0x64,0x5A,0x08,0x2F,0x11,0x49,0xF2,0x71,0x69,0x94,0xC1, +0x1E,0x87,0x82,0x52,0x19,0x08,0x31,0xEA,0xD9,0x46,0xCA,0x5A,0x53,0x88,0x1D,0xD1,0x4B,0x86,0x1B,0x2C, +0xE1,0xC5,0x48,0x4C,0xA9,0xD1,0x11,0xB2,0xE7,0x8D,0x92,0x49,0xE9,0x41,0xEF,0xD5,0xA1,0x71,0x46,0xA3, +0xAA,0x85,0x31,0xAC,0x19,0xDC,0x71,0x38,0x36,0xE0,0x7B,0xFE,0x9E,0xAA,0x39,0x29,0xC6,0x08,0xFB,0xB2, +0x6F,0x4D,0xAE,0x2E,0xCC,0x4F,0x80,0x97,0xDE,0x9E,0xCB,0xBB,0x75,0xF0,0xB5,0x5B,0xF8,0x58,0x90,0xFD, +0xEB,0x86,0xE3,0x83,0x77,0x62,0x40,0xF2,0x13,0x10,0xBA,0x34,0xBF,0xC6,0xA0,0xC2,0xDF,0x0C,0x14,0xB5, +0x44,0x8D,0x73,0x6D,0x29,0x53,0x70,0xE7,0x53,0x3E,0xA4,0x4F,0x88,0xA0,0xCC,0xD6,0x75,0xD1,0xFD,0x69, +0x7E,0xDF,0x8D,0x91,0xB6,0xF8,0xAE,0xEF,0xD3,0x20,0xBF,0x20,0xB3,0x92,0x51,0x1C,0x40,0xEC,0xBC,0xAC, +0x54,0xCC,0xB1,0x2E,0xE0,0x23,0x08,0x66,0x9D,0x0E,0xD3,0x2A,0x87,0x1F,0x54,0x03,0x97,0x92,0x1C,0xF0, +0xDB,0xD4,0xAA,0xE3,0x56,0x11,0xF3,0xE1,0x82,0xB4,0xEC,0x27,0x90,0x27,0x9C,0xD0,0x06,0x17,0x93,0x1E, +0x10,0x8A,0xC1,0xDC,0x22,0xCB,0x0C,0xB6,0xA9,0xBF,0x2B,0x3C,0x0B,0x5F,0xAD,0x15,0x76,0xD7,0x75,0x2F, +0xC3,0xD3,0x75,0xA5,0x33,0x91,0x49,0x13,0x6C,0x15,0x25,0xB2,0xD7,0xD8,0x26,0xA9,0x1B,0xA8,0xB8,0x3C, +0xB7,0xCE,0x06,0xB4,0x78,0x43,0xF6,0xED,0xC3,0x75,0x2E,0x49,0x88,0x93,0x1E,0xAA,0x5B,0xCC,0x24,0x14, +0xDE,0xAC,0x92,0x47,0xD8,0xF3,0xBF,0x69,0xF6,0x1C,0x8F,0x88,0xC7,0xC5,0xD0,0xCF,0xD4,0x25,0xDD,0x53, +0x5B,0x7C,0x88,0x68,0x0A,0x4B,0xDB,0xB9,0x58,0x94,0xCB,0xA8,0xC7,0x19,0x64,0x5F,0x86,0x84,0x38,0xCE, +0xCB,0x9F,0xBE,0xE8,0x3C,0xCC,0x46,0xA3,0x6B,0xDC,0x76,0x9E,0x18,0x20,0x8E,0xF8,0x4E,0xB0,0xF6,0x22, +0x97,0x30,0x04,0xF2,0x1F,0xF2,0x7F,0x0C,0x6A,0x8C,0xEE,0x3A,0x26,0x13,0x66,0x4F,0x7F,0xF9,0x6A,0x79, +0x01,0x57,0xA9,0xEA,0xFE,0x8E,0x84,0x5D,0x8B,0xA6,0x32,0x93,0x4E,0x63,0xFF,0x8B,0x89,0x03,0xA1,0xFB, +0x98,0x59,0xCC,0x90,0x65,0x88,0xE8,0x83,0xE8,0x51,0x4E,0x82,0xC9,0x82,0x26,0x49,0xD6,0xC8,0xD0,0xFA, +0xFD,0x0A,0xD6,0xB2,0x98,0x07,0x6E,0xC3,0x27,0x3E,0xC0,0x54,0x14,0xC1,0x61,0x65,0xE4,0x14,0x61,0xF3, +0x81,0x7F,0xFF,0x2E,0x86,0x6D,0xCC,0x45,0x97,0x5D,0x2D,0xF5,0xB6,0x83,0xFB,0xD7,0xD1,0x07,0x67,0x92, +0x3A,0x4E,0xC1,0xB5,0xDC,0x5C,0xE4,0xBF,0xF9,0xC5,0x33,0xB5,0x9A,0xA9,0x4D,0x8D,0xC9,0x86,0x0F,0x14, +0xA5,0x5B,0xB7,0x22,0x01,0xFE,0xD0,0xAC,0xBB,0xA8,0xB8,0x53,0x71,0xC8,0xC6,0xAF,0x3F,0xE8,0xDA,0x7E, +0x79,0xC7,0x71,0xC5,0x53,0x31,0x61,0x39,0xC7,0x26,0x91,0x2D,0x3E,0xA7,0x76,0xD1,0x82,0x65,0x96,0x70, +0x36,0x78,0x3B,0x80,0x90,0x4C,0xEB,0x71,0x3C,0xA3,0x9A,0x1A,0xAB,0x8C,0x72,0xBE,0xD4,0x59,0x4C,0x16, +0xA5,0x19,0x8A,0xFE,0xA7,0xE7,0xD2,0x9E,0x71,0xA6,0x3D,0x1D,0xBB,0xEB,0xBA,0x19,0x73,0x8B,0xE4,0x0B, +0x49,0xAB,0x21,0x79,0xBF,0x3F,0xF7,0x1E,0xE8,0x0A,0x9F,0xB8,0xEE,0xC2,0x8B,0x7F,0xD4,0xE5,0x63,0x1E, +0xAF,0x19,0x61,0xF8,0x3C,0x54,0xF1,0x6D,0x6C,0x14,0x30,0x17,0xFF,0xE6,0x5A,0xB5,0xCF,0x06,0x56,0x2C, +0x3A,0x73,0xD0,0x56,0xA5,0x88,0xC8,0xDE,0xC7,0x43,0x0C,0x83,0x0E,0xCD,0xD1,0x2E,0x9F,0xB2,0x6A,0x1E, +0xC2,0x60,0xEC,0x53,0xB4,0xA9,0xE4,0x6F,0x73,0xE2,0x57,0x2D,0x11,0x18,0x49,0xDB,0x5B,0x8C,0x57,0x4B, +0xBD,0x71,0x57,0x42,0xEC,0xCB,0x50,0x2F,0x1F,0xB9,0xB4,0xFF,0xEF,0x16,0xA1,0xC0,0xB5,0xBE,0x16,0x7D, +0x17,0x90,0xB5,0x75,0x0C,0x1F,0x6D,0xEB,0xB8,0x93,0x8A,0x8E,0x37,0xEF,0x54,0xE2,0xA5,0x8E,0x24,0xD3, +0x94,0x3B,0x43,0x4C,0x63,0x61,0x2D,0x66,0xC6,0xF8,0x9D,0x44,0x7A,0x3F,0x34,0x74,0x88,0xB4,0x0F,0x48, +0x57,0x4D,0xAD,0xA6,0xA8,0x5F,0x77,0x91,0x37,0x9B,0x56,0x75,0x37,0x9B,0x06,0x5B,0xA9,0x91,0x3D,0xAA, +0xA9,0x5E,0x6C,0xC6,0x8F,0xC4,0xDE,0x2D,0x85,0xF5,0xB4,0xC2,0x43,0xB8,0x27,0x15,0xFA,0xB5,0xF6,0x56, +0x0F,0xC6,0x91,0xF1,0x96,0xEA,0xE7,0x32,0x27,0xE8,0x7D,0xB6,0x7B,0xF6,0x5B,0x1E,0xA0,0x97,0xDD,0x2D, +0x1A,0xBB,0x4B,0x82,0xE0,0xD7,0xCB,0xEE,0x7B,0x50,0xC1,0x57,0x87,0xAB,0x59,0xB5,0x08,0xF6,0x7F,0x00, +0xCE,0x7A,0x7F,0xEF,0xF1,0xAC,0x20,0x77,0x24,0xDA,0x5F,0xEC,0x7F,0x07,0xB1,0x0A,0xF9,0x05,0xA3,0x7E, +0xCF,0xF1,0x2C,0xE8,0x1E,0x99,0x96,0xCE,0x39,0xB6,0xFE,0x6E,0xA8,0x84,0x2B,0x6E,0xCE,0xF0,0xFB,0xC4, +0x8C,0x0A,0xDF,0x0D,0xB5,0x85,0x9E,0xE4,0x11,0xA6,0xB4,0xDD,0x0B,0x57,0xD7,0xBF,0x71,0xEA,0xCF,0xDE, +0x4A,0xB6,0x47,0x9C,0x50,0xD4,0x39,0x43,0xF1,0xFF,0x2E,0xCE,0x87,0xCC,0x1D,0xAC,0xC5,0x27,0xBD,0x4A, +0x83,0xBC,0xE8,0x6A,0x05,0x48,0xCE,0xA8,0x4D,0xC1,0x8E,0x88,0xBE,0xB0,0x66,0x5A,0x82,0xBD,0xA1,0x4F, +0x5F,0x3D,0x3D,0xC1,0xDA,0x31,0xE7,0x4B,0xEE,0x8B,0x4D,0x18,0xB9,0x73,0x37,0x87,0xBD,0xBC,0x11,0xDC, +0x0E,0xDD,0x90,0xFB,0x43,0xE6,0x45,0x08,0xCE,0x54,0x7F,0xEE,0xE7,0xBE,0x26,0x1D,0x30,0x06,0xD0,0x1A, +0x6C,0x94,0x70,0x22,0x34,0x4D,0xEE,0x22,0xB1,0xE3,0xE4,0x82,0x4D,0x09,0xF6,0xB5,0xF8,0x02,0x12,0x34, +0xE2,0x4C,0xE0,0x25,0x7B,0x65,0x21,0x41,0x21,0xFD,0x12,0x1F,0xE8,0xAF,0x1B,0x20,0x63,0x4F,0xBF,0xD6, +0x5C,0x9F,0x49,0x6E,0x43,0x00,0x25,0x86,0x85,0x29,0x63,0xB3,0x41,0xB2,0x36,0x47,0x3A,0x40,0x1E,0x75, +0x5E,0xAF,0x0C,0x2E,0x14,0xAE,0x47,0x1E,0x88,0xD5,0x6B,0x82,0x76,0x7F,0x5E,0xA0,0x8A,0xF4,0xF6,0x6C, +0x65,0x49,0x7B,0x77,0x45,0xCF,0xBA,0x64,0x52,0xE5,0x50,0xBE,0xA2,0xD7,0x95,0x74,0xEA,0xD9,0x59,0x7D, +0x1A,0x02,0x7F,0x03,0x2D,0x08,0x37,0x57,0x62,0x84,0x0D,0xAB,0x6E,0x45,0x57,0xB6,0x3E,0xF1,0xE3,0xFD, +0x74,0x26,0x4A,0x05,0x8A,0x0C,0xD4,0x7F,0x3A,0xA2,0x6A,0xAA,0xC8,0x53,0xCB,0xA9,0xFD,0x97,0x91,0x78, +0x0D,0x29,0x77,0xEC,0xEA,0x88,0xB2,0x24,0xCB,0x4D,0xD2,0x20,0x5F,0x90,0x89,0x6B,0x7F,0xF7,0x87,0xF2, +0x65,0xAA,0x2B,0xD6,0x48,0xE8,0xAD,0x8C,0x55,0x9C,0x61,0x6B,0x0B,0x0F,0xDF,0x99,0xE4,0xF6,0x88,0x5B, +0x8A,0x94,0x35,0xB9,0xA4,0xC5,0xE8,0xBB,0x86,0x01,0x3D,0xC8,0x15,0x31,0xE9,0xF2,0x49,0xFE,0x6D,0x8C, +0x1A,0x77,0x5B,0xA0,0x0B,0x4F,0xB2,0x78,0x28,0x98,0xA1,0x5F,0xEA,0xB2,0x74,0x1A,0x2E,0x64,0x3C,0x77, +0xE6,0xFB,0x78,0xAF,0x36,0xD3,0x93,0xAC,0x7B,0x43,0x7D,0x13,0x7D,0x75,0x48,0x72,0x7E,0x83,0x73,0xA6, +0xA8,0x83,0xF7,0xEA,0xB3,0x92,0xDA,0x0F,0xC9,0x20,0x00,0x3A,0x28,0xBC,0xA7,0xBD,0x78,0x13,0x15,0x42, +0x66,0xD9,0xEA,0x91,0x9B,0x61,0xE4,0x88,0xA1,0x2A,0x5C,0x67,0x1F,0xEA,0x0D,0xD0,0x79,0x57,0xD7,0xDB, +0x77,0x81,0x01,0x27,0xA8,0xF5,0xA5,0xD7,0x51,0x9D,0x36,0xD2,0xBC,0xFB,0x99,0xF4,0xF6,0x98,0xA5,0x89, +0x21,0xB8,0xA3,0x68,0x4B,0x48,0x3D,0x89,0x08,0xA3,0xA6,0xD7,0x1A,0x92,0xD2,0xE9,0xEA,0x05,0x33,0x3A, +0x72,0xEF,0x98,0x8A,0x64,0xDE,0xE6,0xD4,0xB5,0xDB,0xF1,0x54,0x7F,0x88,0x4E,0xA6,0xC8,0xBE,0x67,0x6E, +0xFE,0xA8,0x4C,0x9F,0x18,0x7A,0xD4,0x45,0xED,0x8C,0xC3,0xC7,0xC2,0xED,0x5B,0xA6,0x3C,0xA9,0x75,0x97, +0x90,0x2A,0x73,0xE4,0x00,0x72,0xE3,0xEC,0xB5,0xDD,0xF0,0x1F,0x1A,0x26,0x5F,0xC7,0x93,0x74,0x58,0x60, +0x64,0x54,0x95,0x75,0xC7,0x7A,0x6E,0x5A,0xC4,0x57,0x22,0xCE,0x93,0x69,0xD3,0x18,0xA9,0x20,0xDC,0xEE, +0xD2,0x1A,0xE6,0x18,0x75,0xC9,0x0B,0xCC,0xF9,0x66,0x90,0x8B,0xDD,0x58,0xD8,0xA6,0x9A,0x4A,0x87,0xDB, +0xDB,0x68,0x3B,0x3E,0x88,0xD7,0x6F,0x9B,0xD4,0x16,0xD6,0x18,0x1C,0xC4,0x7F,0xEF,0xD2,0x56,0xA1,0x88, +0x98,0x7F,0x78,0xE0,0x89,0x6C,0xB6,0xAE,0xC9,0x35,0xA9,0x92,0x5C,0x83,0xA8,0xEA,0x9B,0xFF,0xCE,0xF9, +0x85,0x06,0x33,0xA6,0xB4,0xCB,0xE5,0x54,0x80,0x5E,0xE6,0xCC,0x3B,0xD2,0xFA,0xB9,0xFE,0x17,0x06,0x8A, +0x47,0xA8,0xE8,0xC4,0x01,0x7D,0x7A,0xC9,0x43,0xDF,0xAB,0xAA,0x93,0x50,0xC7,0xD8,0x4A,0xC9,0x9F,0x3C, +0x5A,0x52,0x7F,0x8F,0x99,0x43,0xAA,0xE0,0xF9,0x07,0x1D,0xE4,0xFD,0x83,0x48,0x40,0x07,0x7F,0xCE,0x21, +0xA9,0xEF,0x2C,0x41,0x87,0x8B,0x68,0x6B,0xE0,0xDC,0x18,0x0F,0xE6,0x4C,0x28,0x44,0xBE,0xD0,0x22,0x03, +0x85,0xC2,0xB7,0x0B,0xF4,0x3D,0x49,0x41,0x27,0xC4,0xB7,0x86,0x54,0xFF,0x79,0x22,0x24,0xE8,0xD1,0x28, +0xB7,0x76,0xC6,0xB7,0xFF,0x1B,0xC7,0x1B,0x3E,0x92,0x19,0x92,0xA5,0x98,0x58,0x7F,0xB1,0xBF,0x16,0x5A, +0x45,0x34,0xF1,0x96,0x12,0xAB,0x42,0x82,0x5B,0x9D,0xC6,0x30,0x9A,0x13,0x32,0x23,0xCA,0x38,0xE8,0x01, +0x5B,0xA8,0x78,0xB0,0xEA,0x7B,0xC9,0x21,0x6D,0xBD,0xB1,0xA6,0x77,0x84,0x61,0x8F,0x13,0xAB,0x17,0x7B, +0x08,0x2A,0xE1,0x5F,0x76,0xE8,0x1E,0x0D,0x15,0xCD,0xFB,0x91,0xE4,0x2B,0x26,0x42,0x04,0x10,0x35,0x35, +0x68,0x3D,0x12,0xAF,0x27,0x38,0xCC,0x16,0xE3,0x14,0x2E,0xCF,0x05,0x13,0x2D,0xBE,0xC1,0xAA,0xBD,0x31, +0xCD,0xF9,0x51,0x41,0xD2,0x6F,0x27,0x53,0x84,0x80,0xB4,0xE7,0x94,0xE8,0x12,0x29,0x98,0x61,0x0E,0x70, +0xDA,0x73,0x2F,0xE3,0x85,0x9D,0x08,0x22,0x45,0x7A,0x5B,0xFB,0x03,0x40,0x3F,0x7F,0x91,0x66,0x73,0xD9, +0x3A,0x21,0xE3,0xA8,0x0E,0xE3,0xF2,0x68,0x1F,0x61,0x4A,0x91,0xD1,0x6A,0x54,0x6F,0x6E,0x89,0x6C,0x2C, +0xE8,0xB6,0xDA,0x08,0x25,0x1C,0xF0,0x7C,0xF8,0xAC,0x76,0x3B,0x0E,0x91,0x4B,0x72,0x60,0x51,0xE4,0x5B, +0x8E,0x61,0x73,0x2F,0x9E,0x13,0x0A,0x1B,0xCB,0x2B,0xC5,0xB9,0x1F,0xCC,0xBB,0xBE,0x6E,0x8D,0xC6,0x8E, +0x7C,0x2F,0x7C,0x9A,0xA6,0xAC,0x9A,0x27,0xB9,0x46,0x98,0x30,0x2E,0xD8,0xD5,0x66,0x30,0x54,0x2A,0x62, +0xE9,0xD3,0x02,0xD1,0xF7,0x13,0x6C,0xAF,0x7A,0x93,0xAF,0xC5,0x19,0xF2,0xA1,0xE1,0x46,0xD2,0xED,0xC3, +0xB2,0x4B,0xB1,0x53,0xEC,0x9D,0x23,0x8A,0x3C,0xE3,0x39,0x0C,0xA3,0x3A,0xE5,0x86,0xB3,0x4A,0x66,0xC2, +0x18,0x72,0x03,0xA6,0x14,0x5C,0x65,0xB1,0x12,0xDB,0x19,0x2E,0xC0,0xF9,0x0F,0xC5,0xC7,0x6B,0x8A,0xE1, +0xD7,0x2B,0x94,0xDA,0xCE,0x04,0xA4,0xC7,0xCE,0x35,0xC7,0xBC,0xFA,0x28,0xDA,0xCB,0xF3,0x51,0x3C,0x40, +0x4F,0xE7,0x9E,0xA8,0x39,0x20,0xB5,0x1B,0xE1,0x8A,0x41,0x85,0x09,0xB7,0x95,0xF7,0x73,0x06,0x16,0xD5, +0xF7,0x07,0xD0,0xC9,0x97,0x62,0x6E,0xF0,0xD3,0xAA,0xA9,0x73,0x2C,0x03,0xC8,0x8C,0x3A,0x45,0x0E,0x9B, +0xCD,0x59,0x20,0x5D,0x4C,0x96,0x23,0x4D,0xAD,0xA1,0xEE,0xA0,0x13,0x19,0x6C,0x5B,0x86,0xBD,0x80,0x8B, +0x1C,0xFD,0x3F,0x76,0xA4,0xD8,0x0B,0x1D,0x80,0xB0,0x6A,0x58,0x68,0x57,0x89,0x87,0x3E,0x05,0xC7,0x87, +0x2A,0x3B,0x7B,0x6F,0x32,0x6A,0xFF,0xA6,0x98,0x2F,0xDD,0xA0,0xFC,0x3B,0xC1,0xF3,0xFE,0x4D,0x91,0xDE, +0xAD,0x61,0x61,0xD5,0x44,0x09,0xE0,0x8C,0x1E,0x6F,0x57,0xB8,0xD8,0xF8,0xEC,0x9E,0x2F,0x30,0xD2,0x95, +0xB1,0x80,0x54,0x0D,0xF3,0xBC,0x40,0xF6,0xA8,0xF4,0xFF,0xDE,0x31,0x38,0x27,0x6F,0x9D,0x94,0x89,0xE9, +0x1F,0x7D,0x57,0x24,0x20,0x39,0xB6,0x89,0x18,0xAF,0x9C,0xBB,0xF9,0x9D,0x46,0xCE,0x5E,0x7E,0xC9,0xF3, +0x84,0x8D,0x16,0xEE,0xB5,0x8F,0xC2,0xA2,0x85,0x57,0xCA,0xF8,0x38,0x81,0x98,0x81,0x6D,0xB5,0x1C,0x85, +0x21,0x8C,0x30,0x52,0xF8,0x4D,0x9E,0x01,0xB8,0x80,0x53,0x57,0x6B,0x66,0x90,0xD5,0xCC,0x2B,0xD1,0x7C, +0xA1,0x5F,0xE8,0x56,0xE0,0x2D,0xA9,0x0B,0x0D,0xA8,0x98,0xC5,0xCD,0x2A,0x21,0x5F,0x40,0x4E,0x35,0xA7, +0x8D,0x69,0x19,0x8E,0x04,0x57,0xFB,0x75,0x6E,0x8B,0x42,0x65,0xB7,0xC7,0x47,0x97,0xD6,0xC9,0xE4,0x2F, +0x05,0x56,0xB6,0x53,0x37,0x3E,0x58,0x8C,0xE0,0x07,0xE0,0x50,0xF2,0xBE,0xA2,0x83,0x23,0x19,0x61,0x37, +0xF0,0xEA,0x55,0x92,0xBE,0xBD,0x8B,0xD9,0x39,0x02,0x36,0x91,0xD7,0x1C,0xAA,0x23,0x59,0x57,0x07,0x24, +0xA8,0x44,0xD9,0x3F,0x22,0x7B,0x7A,0x0C,0xE1,0xE9,0x04,0x2C,0x02,0xB1,0xAF,0x6A,0xE9,0x9D,0x12,0x2F, +0xA3,0x29,0x1C,0x7A,0x69,0x48,0xD0,0x4F,0x71,0xC8,0xA5,0x77,0x4F,0xB1,0xCA,0xF4,0xDB,0x55,0x83,0x14, +0x79,0x37,0xB9,0xF6,0x30,0xF3,0xC1,0x16,0xA6,0x36,0xCD,0x10,0xDC,0xC1,0x75,0x1F,0x68,0x88,0x4B,0xB5, +0xAB,0xA6,0x54,0x06,0xF4,0xD4,0x1F,0x5F,0xFA,0x39,0xAB,0xCC,0x3C,0xAB,0x3D,0xA4,0x48,0x61,0xE7,0x99, +0x60,0x4E,0xD3,0x48,0xEF,0x2E,0x8A,0xF4,0xF0,0x05,0x5A,0xAD,0xB8,0xDD,0x8E,0x78,0xA2,0xBC,0x6E,0x1E, +0xD6,0xCB,0x83,0xE4,0x84,0x62,0x38,0x0A,0x67,0xF8,0x0D,0xCD,0x69,0xE5,0x54,0x17,0x7B,0xB1,0xCC,0x2A, +0x94,0x61,0xE9,0xAB,0x72,0x9E,0x43,0x4C,0x2A,0x30,0x4E,0x03,0x11,0x3E,0x95,0x6A,0x85,0xEF,0xDE,0x7B, +0x93,0xBB,0x3C,0xC2,0xD5,0x5C,0x41,0xF1,0xFD,0x32,0x77,0xB7,0x80,0xAE,0x9D,0x44,0x92,0x3A,0xAF,0x04, +0x9D,0xB2,0xFC,0xE2,0xEC,0x7C,0x95,0xA6,0x0C,0x1F,0xFD,0xB4,0x80,0x9D,0x2D,0xCE,0x61,0x5F,0x12,0x38, +0xF3,0x31,0x9D,0x62,0x2D,0xCE,0x59,0x11,0x83,0x71,0xB0,0xCE,0x7C,0x11,0xE4,0x92,0x5D,0x16,0xF6,0xB6, +0xD1,0x04,0x96,0x8E,0xD9,0x50,0x84,0x71,0x1E,0x50,0x69,0x1B,0x5C,0xD2,0x5A,0xB2,0xDC,0xB8,0x33,0xDC, +0x96,0xC9,0x4A,0xCC,0x0B,0x58,0x23,0x86,0x05,0x34,0xFF,0x3A,0x4B,0xB5,0x55,0x2D,0xA6,0x7B,0x3B,0xC5, +0x0B,0xC7,0xED,0x1B,0x0B,0x87,0x1F,0x55,0x95,0x9A,0xB5,0xF2,0x4E,0x38,0x4F,0x89,0x08,0x13,0x22,0x87, +0x54,0x67,0x7E,0xAF,0xD5,0x17,0x79,0xFF,0x54,0x7A,0x99,0x71,0x94,0x01,0xAF,0xEE,0xD9,0x63,0x75,0xBF, +0x88,0x58,0x62,0x5C,0x33,0x7B,0x19,0xC2,0xEA,0x54,0xF6,0xDE,0xCA,0x15,0x97,0x7A,0x24,0x17,0xD6,0x74, +0xBE,0x29,0x6C,0x52,0x1F,0x18,0xBC,0x29,0xCE,0xAC,0xAC,0x2D,0x75,0xF8,0xDE,0xD1,0xBF,0x28,0xE2,0x7B, +0x48,0x04,0x20,0x32,0x46,0xA6,0x7D,0x2A,0x86,0xA1,0x56,0x4E,0x18,0x2C,0x6C,0x58,0xA3,0xF3,0x69,0x0A, +0x5E,0x8A,0x4A,0x23,0xCA,0xBE,0x9E,0xC0,0x98,0x7C,0xE4,0xC8,0xC9,0xF2,0xE5,0x8C,0xFB,0x6B,0x3F,0xBA, +0xC0,0x9F,0x9D,0xCC,0x19,0x38,0xF3,0xCD,0xD9,0x08,0x6C,0x9D,0x7A,0x61,0x1D,0x23,0xD4,0x1D,0xE9,0x2C, +0x3F,0x9B,0xFF,0x8B,0x89,0xF3,0x4F,0x3A,0x12,0x5C,0x0D,0x26,0x67,0x31,0xD8,0xF6,0x95,0x01,0x4F,0xDC, +0x42,0x70,0xD0,0x6D,0x2F,0xED,0x7A,0x44,0xEE,0xE5,0x92,0xF4,0xBD,0xA5,0x50,0x50,0xF2,0xCF,0x38,0x7C, +0xA8,0xFD,0xB0,0xF0,0x00,0x0F,0x37,0x83,0xA6,0x68,0x0A,0xE1,0x65,0xBD,0x4E,0xD7,0xC7,0x39,0xB9,0x1C, +0x01,0xD7,0x97,0x3F,0xD6,0xAC,0x01,0xD8,0x46,0xCE,0xB8,0x35,0x9D,0x8F,0x02,0x43,0x05,0x44,0xBE,0xA4, +0x4A,0x20,0x47,0xC7,0xB6,0x87,0x60,0x15,0x3A,0x45,0x6C,0x56,0x88,0xC4,0x13,0x71,0xB6,0x5A,0xB8,0x0B, +0x9C,0x48,0x58,0x04,0x35,0xD9,0x38,0x1A,0x23,0x01,0x71,0xB4,0x1A,0xAB,0xC6,0xC2,0x32,0xC5,0xC9,0x57, +0xF2,0x49,0xC5,0x77,0xB4,0xAA,0xD7,0x0E,0xFF,0xAA,0x6F,0xD2,0x2C,0xE4,0x87,0x70,0x76,0xA6,0x86,0x2D, +0xA0,0x85,0xBA,0x52,0xE0,0x49,0x52,0x7C,0xFE,0x8A,0x66,0x70,0x72,0x34,0x70,0x47,0x39,0x96,0x15,0x51, +0x7E,0xD3,0x49,0xBE,0x10,0x40,0x19,0x03,0x6E,0x75,0xD8,0x2C,0x2D,0xCB,0x63,0x63,0xFF,0xD6,0xBC,0x20, +0x4E,0x06,0xDA,0xC4,0x37,0xE9,0x94,0xFD,0xEE,0x73,0x3E,0x9B,0xAF,0x2B,0x02,0x79,0x6C,0xF6,0x7B,0x93, +0x0B,0xA9,0xDA,0xB9,0x6C,0x9C,0x72,0xBF,0xBD,0xEC,0x28,0x6B,0x24,0xCF,0x8C,0x68,0xBF,0x6F,0xDC,0x4E, +0xEA,0x9F,0x4A,0x4D,0xBC,0xC9,0xAE,0x89,0x61,0x46,0xA3,0x8A,0xFA,0x32,0xDB,0xB8,0xE4,0x95,0xDD,0x17, +0x7E,0x01,0x0D,0xCB,0x2F,0x6F,0x59,0x9C,0x52,0xAF,0x33,0x5A,0xCB,0x94,0x7B,0xAC,0x1B,0x22,0x7F,0xCA, +0xE9,0x60,0xFA,0x19,0x20,0xAE,0x7D,0x08,0x22,0x68,0xE1,0x79,0xDD,0x51,0x5C,0xC0,0xDF,0xDE,0x55,0x48, +0x8D,0xC6,0x01,0x6B,0x84,0x6E,0xFD,0x51,0x34,0xC1,0xFC,0xEF,0xFD,0xD7,0x0F,0x8B,0x89,0xF2,0x29,0x43, +0xB2,0x94,0x65,0x2F,0x28,0xF0,0x0D,0x21,0x21,0x45,0xC8,0xDD,0x66,0xED,0x35,0x16,0x4C,0x70,0xF2,0x96, +0x49,0x52,0x97,0x04,0x44,0x72,0x87,0x4D,0x0E,0x9D,0xBF,0xED,0x20,0xDF,0xBE,0xC1,0x5D,0xBB,0x0A,0xE5, +0x42,0x79,0x92,0x57,0x9F,0xF7,0x13,0xA0,0xF1,0x0A,0x54,0x49,0xC2,0x3C,0x44,0xC2,0x45,0x7A,0xDC,0x2F, +0xD6,0x7F,0x79,0x84,0x47,0x60,0x65,0xE3,0x85,0x30,0x62,0xD2,0x47,0x77,0x93,0x57,0xD2,0xF0,0x53,0x62, +0xCF,0x9A,0xCD,0x24,0x14,0xA5,0xDD,0x81,0x85,0x7B,0x85,0xA5,0xB4,0x07,0x0F,0xF5,0xBD,0x88,0x66,0xF3, +0x32,0x18,0xE0,0x48,0xEE,0x14,0x76,0xB3,0x22,0xF0,0xEA,0xC4,0x23,0x87,0x63,0xB3,0x3B,0xAA,0x46,0x9E, +0x8C,0x76,0x52,0x9A,0x7B,0x8A,0x07,0x9A,0x79,0xF6,0x6A,0x8D,0xA4,0x31,0xC5,0xC9,0x86,0x19,0xB1,0x8F, +0xE6,0xBA,0x52,0x68,0xC3,0x4F,0xAD,0xEC,0xD1,0xB4,0xA9,0x4B,0xBA,0x7A,0x31,0xD5,0x7C,0xF6,0x99,0xB9, +0x4C,0xFF,0x5E,0xBE,0xBE,0x1A,0x08,0xED,0x4A,0x57,0x66,0x9C,0x95,0xCC,0xBF,0xB0,0xDE,0x92,0xF8,0xBC, +0xC0,0x60,0xDE,0x88,0x0D,0x71,0xF6,0x51,0xDC,0x7D,0x9C,0x3B,0xA8,0xDC,0x9F,0xEB,0x49,0x43,0x0B,0xDA, +0xD2,0x71,0xAE,0x6C,0x19,0xF8,0xDB,0xA0,0x0C,0x62,0x3B,0x21,0x56,0x14,0x01,0xFC,0xCB,0x54,0x87,0x39, +0x4B,0xBE,0x5E,0x39,0xE2,0xAB,0xD9,0xFD,0xB5,0x86,0x94,0x34,0xC0,0x30,0x33,0xA0,0x1F,0x43,0x51,0x27, +0xE4,0x13,0xA8,0xE7,0xB2,0x33,0xCD,0x1D,0x42,0x21,0x74,0x4B,0x8B,0xBC,0x92,0x6B,0x05,0x63,0x53,0x76, +0xFA,0xAB,0xD1,0x8C,0x87,0x00,0x51,0x3C,0x1C,0xDD,0x83,0xF1,0x91,0x41,0x31,0x65,0x11,0x85,0xD9,0x9C, +0x5B,0x03,0xFF,0xD7,0xD0,0x53,0x8D,0x7D,0x04,0x17,0xD7,0xC0,0x7F,0xD4,0xC1,0xAC,0x71,0xF2,0x0B,0x4B, +0x54,0xDF,0x88,0xF8,0x03,0x08,0x08,0xFC,0x53,0xAE,0x01,0x90,0xE6,0xE3,0x9E,0xF0,0x74,0xF9,0x43,0xB1, +0x7D,0x09,0x9B,0x88,0xFA,0xF7,0x6F,0x54,0x65,0x28,0xE4,0x16,0xC1,0x6F,0x0B,0xB3,0xDF,0x03,0x36,0xB7, +0x6F,0x96,0x4A,0x02,0xFF,0xCE,0x19,0xAC,0xA5,0x25,0x9C,0x78,0x0E,0x93,0xFA,0x28,0xF1,0x41,0xD8,0x14, +0xA1,0xDB,0x52,0xF9,0x72,0xB5,0x36,0x7E,0xFE,0x19,0x26,0x83,0x3D,0x84,0xCF,0x9D,0xBE,0xC2,0x6D,0x2D, +0x08,0xC4,0xF4,0x08,0x54,0x11,0xC1,0xF2,0x71,0xC9,0x05,0x4B,0x37,0xE7,0x34,0xCF,0xDE,0xDA,0xB3,0xE2, +0x58,0xD6,0xD8,0x2D,0x91,0x84,0x5B,0x04,0x22,0x0F,0x90,0x7A,0x1B,0x9B,0xEE,0xCC,0x38,0x0C,0x02,0xB0, +0x40,0x81,0x72,0x9B,0xE9,0x5E,0x9F,0x52,0x5C,0xC7,0x42,0x49,0xF7,0xEC,0x48,0x2F,0x6F,0x84,0x22,0x38, +0x5F,0xE0,0x1A,0x95,0x71,0x2F,0x7B,0x8E,0x48,0x2E,0xD4,0x3C,0xEA,0x27,0xEB,0x19,0x4A,0xE8,0x7A,0xE9, +0xFC,0xD0,0x8B,0x74,0x84,0x4D,0xD8,0xBD,0x95,0xA4,0xCE,0x9F,0xDB,0xE2,0x14,0x7B,0x3A,0x90,0x3B,0xB1, +0x81,0xEF,0x96,0xC4,0xDB,0x74,0xB4,0x50,0x9E,0xF3,0x85,0x20,0x42,0x78,0xB5,0x9F,0x82,0x53,0xC1,0xB3, +0xD8,0xA9,0xC8,0x4E,0xEC,0xFC,0xA4,0x47,0x45,0xC4,0x3E,0x05,0x96,0x9F,0xBF,0x35,0x08,0x70,0xC0,0x52, +0x6C,0x13,0xAD,0x56,0xC8,0x17,0x0A,0xC5,0x58,0x8B,0x4D,0x41,0x24,0x3E,0x4E,0x2E,0x0A,0xC0,0x8C,0x8A, +0x9D,0x31,0x8D,0x33,0x4E,0xB9,0xC2,0xFD,0x3B,0xF8,0xC1,0xFB,0x12,0xD9,0x9C,0x66,0xB7,0x11,0x04,0x0D, +0xCA,0xC4,0xAA,0x1C,0xB1,0xF9,0x1E,0x0F,0x8A,0xE4,0x4C,0xEB,0x43,0xFE,0xD3,0x86,0x68,0x5F,0x55,0x82, +0x5B,0x8C,0x2B,0xD8,0x0B,0x4C,0xED,0x0D,0x02,0x39,0x5B,0xB3,0x5C,0xBA,0x79,0x37,0x7B,0x8D,0xF1,0x6E, +0xE0,0xDC,0x4E,0xC8,0xF5,0x64,0x5E,0xD7,0x2E,0x6B,0xFD,0xAB,0x99,0x54,0x28,0x05,0xBE,0xF7,0x5F,0x13, +0x99,0x87,0x3F,0xEE,0xD6,0x7B,0x0F,0xEF,0x68,0x7B,0xC5,0xB8,0x94,0xF8,0xD6,0x09,0x1A,0x03,0xDD,0xC9, +0x9A,0x01,0x60,0xF7,0x6E,0x30,0xC2,0x8D,0x14,0x33,0x28,0xEA,0x32,0x60,0x70,0xDE,0x9A,0xE5,0x45,0xD3, +0x4C,0x34,0x4C,0x4A,0x9B,0x86,0x08,0x39,0xCB,0xFB,0x51,0x4C,0x40,0x61,0x8F,0x30,0xEF,0xC7,0x0C,0x25, +0x02,0xED,0xD4,0x8E,0x91,0x4D,0x93,0xF1,0x40,0x95,0xB1,0x58,0x40,0x08,0x40,0xD5,0x48,0xD4,0x25,0x82, +0xF6,0xDB,0x70,0xAC,0xD9,0x1E,0x48,0x20,0xE6,0xB3,0x97,0x41,0xAA,0x53,0x17,0x81,0x99,0xF3,0xDA,0x5D, +0xDE,0xF9,0x96,0xE7,0x1E,0xC0,0x61,0xC0,0xAB,0xF0,0xCA,0x3D,0xD3,0xF4,0x0B,0x79,0x5E,0x8B,0x73,0x74, +0x30,0x2D,0x6A,0x8D,0x32,0x6F,0xB8,0x34,0x70,0x4F,0x10,0xED,0xF4,0xE2,0xA7,0xB6,0x05,0x61,0x6E,0x15, +0xE4,0x6E,0x80,0xCD,0x53,0xF8,0x25,0x9B,0x7D,0x23,0xDF,0x5F,0x5C,0x3A,0x95,0x41,0xE0,0x6D,0x15,0x45, +0x27,0x87,0xD2,0x60,0xF1,0x72,0xF3,0x57,0xFD,0x1B,0xEB,0xF4,0x0F,0x32,0x8F,0x13,0x34,0x4C,0x31,0x42, +0xA7,0x03,0xE4,0xBA,0x16,0xB1,0x63,0x84,0x8E,0x25,0xAA,0x35,0x2A,0xA6,0xA8,0xEF,0x3F,0x25,0x44,0xF3, +0xC2,0xC6,0x99,0x9A,0x9F,0x08,0xF9,0x86,0xB7,0x14,0xE1,0x52,0x7A,0x67,0x74,0x4F,0x16,0x06,0x60,0x72, +0xAA,0xC2,0xA0,0xCF,0x77,0xED,0xFF,0x20,0xEB,0xEB,0x42,0x9D,0x2C,0xE5,0x86,0x34,0x2E,0x9D,0x39,0xDF, +0x56,0x6A,0x5C,0x0C,0xE5,0x39,0xDC,0x57,0xF5,0x10,0x0C,0x16,0x2D,0xCC,0x24,0xAA,0x6E,0xE8,0x9A,0x6D, +0x03,0xD6,0xD4,0x18,0xFC,0x2A,0x1A,0xB0,0x69,0x42,0xB2,0xDF,0xA1,0x08,0xF0,0xF8,0x00,0x87,0xB5,0x6D, +0xFC,0xAB,0x4A,0x58,0xA6,0x43,0x8B,0xE8,0x1E,0xCA,0x9F,0x79,0x83,0xF4,0x9E,0x9B,0xD2,0x0A,0x40,0x0A, +0xBF,0x64,0x7B,0x53,0xBE,0x1F,0x00,0x57,0x0D,0xCC,0xB3,0x04,0x7D,0x7D,0x95,0x9A,0xCE,0xD3,0x8A,0x73, +0xA0,0x1C,0x14,0x63,0xE4,0x5C,0xE8,0x3C,0x5D,0xA2,0x7C,0x92,0x95,0x60,0x3A,0x0A,0x76,0xAF,0x77,0xE8, +0xAA,0x03,0xF5,0x62,0x98,0xBD,0x6D,0xA2,0x5C,0xC4,0x4E,0xEB,0xBE,0xC8,0x35,0x92,0x0F,0x20,0xED,0x63, +0x1F,0x8A,0x6A,0x9D,0xEB,0x3B,0xB1,0x91,0xD9,0xD4,0x9C,0x19,0x47,0x94,0x10,0xF9,0x97,0x1D,0x62,0x0F, +0x8F,0xA3,0x8C,0xD7,0x18,0xFB,0xBE,0xED,0x2B,0xF3,0xB4,0x65,0xB1,0x3C,0xC3,0x41,0x13,0x7C,0x84,0x4C, +0xD9,0xFC,0xE5,0x2F,0x26,0x98,0xAA,0xB6,0x15,0x33,0xA5,0xD0,0x96,0x53,0xA0,0x23,0xC6,0xFA,0x67,0x2E, +0x5A,0xFF,0xFF,0xBC,0xB3,0x59,0xE8,0x03,0x1A,0x7C,0xC2,0x5F,0xB8,0xBE,0x5A,0xA7,0x4E,0x45,0xFA,0x0E, +0x17,0xF4,0xE7,0x91,0x12,0xB8,0xB4,0xDA,0x70,0xE7,0x7B,0x21,0x5F,0xFB,0xB4,0xCA,0xDE,0xCF,0x26,0x3F, +0x0F,0x04,0xE4,0x73,0x14,0x8F,0x1B,0xFF,0x47,0x35,0x4D,0x53,0x5F,0xAC,0x13,0x2B,0xE5,0xCC,0xF7,0x85, +0x0D,0x0F,0x53,0xFF,0x6D,0xCD,0xB5,0xDB,0x4A,0xBC,0xBD,0x5B,0xA7,0xDA,0xEA,0x73,0xC5,0x77,0x7F,0x41, +0x89,0x6E,0xB0,0xBE,0xBC,0x17,0x61,0x8E,0x6A,0x68,0xA0,0x82,0xC3,0xEA,0xEC,0x72,0x8D,0x54,0x6E,0x57, +0x91,0xC2,0xA9,0x84,0x57,0x2C,0x52,0xC5,0xE3,0x64,0xE7,0x27,0x2A,0x90,0x07,0xFD,0xDE,0x8F,0x77,0xB5, +0x98,0x2E,0x0F,0x1E,0xC4,0xA5,0x83,0x09,0xA1,0x91,0xAB,0x73,0x74,0x80,0xEE,0x43,0xED,0x9A,0x5E,0xFF, +0xA1,0x70,0x58,0x03,0x4F,0x98,0x60,0x26,0xDE,0xF3,0x68,0xC7,0x4D,0xC4,0xAC,0x11,0xDD,0x77,0x4E,0x50, +0x2E,0xED,0xD4,0x2D,0x20,0xC6,0xBE,0x53,0x6A,0xD5,0xAF,0xEE,0xDE,0x7F,0x1E,0xB8,0x96,0x17,0xE6,0x29, +0x3B,0xCC,0x40,0xD7,0x12,0x6F,0x64,0xDE,0xCE,0xBC,0x49,0xF2,0xB4,0x3B,0x68,0x24,0xC0,0x6E,0xA8,0xC0, +0x9B,0x2A,0x87,0xE3,0x7F,0xC1,0x5A,0xDC,0x68,0x11,0x17,0x6A,0x66,0x4C,0x49,0x30,0x46,0xB0,0x2B,0xB7, +0x68,0x6A,0xF3,0xF8,0x10,0x4C,0xC0,0x90,0x22,0x94,0xD8,0x2D,0xE5,0x41,0x09,0x3F,0x61,0x51,0x78,0x67, +0xC3,0x0D,0x9B,0x07,0x52,0x26,0x41,0xA5,0xFE,0x56,0x13,0x3B,0xE8,0x96,0x1B,0xF3,0xF4,0x08,0x31,0xEA, +0xA2,0x1F,0x19,0x31,0xC1,0xCE,0xEC,0x28,0x16,0xCE,0x7E,0x78,0xA1,0x46,0xF7,0xF5,0xE6,0xA7,0xB5,0x16, +0x9E,0x4B,0x7C,0x40,0xB3,0xCB,0xF3,0x90,0x07,0x49,0xFD,0x2B,0x2F,0xDA,0x92,0x03,0xE2,0xDA,0xBE,0xBC, +0x50,0x8C,0x1F,0xB2,0x84,0x7D,0x76,0xF4,0x94,0xB6,0x73,0x12,0x61,0x04,0x47,0x16,0xBE,0x0A,0x5F,0xD3, +0x03,0xBC,0x72,0xF9,0x64,0x66,0xED,0x13,0x38,0x22,0x83,0x73,0xBB,0x86,0xD0,0x77,0x0E,0x1B,0x3A,0x31, +0xBF,0x65,0x4B,0x0F,0xAF,0x4E,0x83,0xDE,0x79,0x29,0x32,0xE3,0xE0,0x18,0x98,0x5A,0x65,0x68,0xDA,0x94, +0xFD,0x27,0x5A,0x94,0x19,0xC4,0x59,0x6B,0x7B,0x6F,0x6F,0x9F,0xCE,0x22,0xB9,0x66,0xFB,0x14,0xC9,0xE0, +0xB0,0x8B,0xCB,0xB1,0xF2,0x96,0x4B,0xC8,0x2B,0xB0,0xDB,0x24,0x97,0x43,0x8A,0xDF,0xB9,0xBA,0x7A,0x68, +0xE3,0x5C,0x65,0x70,0xA7,0x27,0x6A,0x96,0xE6,0x41,0xAB,0x0A,0x7B,0x16,0xB3,0xA5,0x0F,0x4F,0x75,0xD8, +0x29,0xEF,0x9A,0x65,0xDF,0x0D,0x1A,0xD4,0x1B,0x60,0x9C,0x4D,0x8C,0xE6,0x57,0xBC,0x39,0x6E,0xAC,0xEB, +0xEC,0xC6,0x89,0xA0,0xB2,0x8F,0x90,0x6C,0x8D,0xEE,0x92,0x48,0x4E,0x43,0x04,0xC8,0x56,0xF2,0xA1,0x9D, +0xD8,0xC0,0x5E,0xBE,0x48,0x01,0xDB,0x7B,0x4F,0x4A,0x4D,0xC2,0xC7,0x11,0xB2,0x89,0x00,0x73,0xD3,0x10, +0x56,0x64,0xB9,0xE6,0xDA,0xD0,0x46,0x34,0x2E,0x46,0x24,0x85,0x4D,0xDE,0x7C,0xFE,0x07,0x53,0x5E,0xAA, +0xB6,0x89,0x4C,0xF6,0x45,0x59,0x10,0x25,0xC3,0xE0,0xCD,0x7D,0xBC,0xE8,0xB3,0xA0,0x3C,0x95,0x44,0x37, +0x44,0xA2,0x8E,0x15,0xB1,0xB3,0x3C,0x42,0xA2,0xAD,0x9D,0xD1,0xE7,0x58,0x94,0x48,0x35,0x16,0x42,0xDB, +0x42,0x36,0xA0,0x42,0x2F,0x1D,0xB1,0x3F,0x50,0xCF,0xFB,0x41,0xD6,0x17,0x1C,0x08,0x29,0xFE,0x7D,0x11, +0xFE,0xE9,0x01,0x9B,0xBC,0x28,0xD3,0x87,0x36,0xD5,0x4B,0xF8,0x0E,0x67,0xCD,0x2C,0xAF,0xE7,0xDA,0x51, +0x81,0xAE,0x0C,0xBC,0xE5,0x44,0x10,0xC4,0xC3,0x35,0x46,0x74,0x94,0x5A,0xCF,0x4C,0x15,0xB3,0x57,0xCE, +0x1E,0x34,0x21,0x81,0x93,0x09,0xB4,0xDF,0xEB,0x1B,0x36,0xFC,0x76,0xB2,0x56,0x3C,0x5A,0xEC,0xA0,0x91, +0xDE,0x7F,0x8D,0xD0,0x9B,0x7F,0x27,0xBC,0xD4,0x25,0x0D,0xAB,0x2A,0x5E,0x30,0x95,0xCB,0xF8,0x47,0x14, +0xED,0x1D,0x70,0x6E,0x81,0x94,0xA7,0x42,0xDA,0x47,0xCF,0xB4,0x5A,0x60,0xC1,0x4A,0x08,0x6E,0xFE,0x36, +0x59,0x1B,0x13,0x00,0x26,0x80,0x87,0xFC,0xDB,0x83,0xCC,0x30,0xE1,0xD0,0x9C,0x97,0xD0,0x59,0x37,0x13, +0x94,0xD6,0xDA,0x00,0x7B,0x61,0xF8,0x2B,0x99,0x68,0xD0,0x3E,0x3E,0xB3,0xFB,0x6C,0x3F,0x3C,0xAD,0x8D, +0xB8,0xF5,0xB4,0x2B,0x8A,0x6D,0xF7,0x33,0x4A,0xBE,0x2B,0xD4,0xED,0x6C,0x60,0xB7,0xEB,0x7B,0x58,0x25, +0xFD,0x8F,0xA0,0xFF,0x10,0xE2,0x35,0xA6,0x7A,0xA2,0x70,0x8E,0x14,0xED,0x48,0x3D,0xCB,0xC3,0xCA,0x70, +0x8B,0x1E,0xBF,0xA4,0x43,0x6B,0x78,0x9E,0x5C,0x4C,0x7F,0xE1,0x80,0x7F,0xA6,0x87,0x19,0xB9,0xCE,0xCB, +0x53,0x80,0xB3,0xC5,0x3D,0x03,0x78,0x38,0x6C,0x92,0xE8,0x71,0x03,0x3C,0x5B,0xF3,0xC7,0xD8,0xAC,0xD5, +0x79,0x4E,0x1E,0xBE,0x97,0x7F,0x24,0x18,0x18,0xBA,0xDD,0x2C,0xBB,0x98,0xE1,0x15,0x66,0x88,0x17,0x56, +0x7C,0xB0,0xFF,0xD2,0x25,0x8C,0x21,0x67,0x92,0xA9,0xC6,0x43,0x3E,0xF4,0x5C,0x6C,0xA3,0x0B,0x9C,0xAC, +0xF5,0x8E,0xC8,0xE7,0xF4,0xA4,0x97,0xAF,0xD5,0x0E,0xA9,0x86,0x8C,0xC5,0xD1,0xAD,0xF4,0xE2,0xBD,0x2D, +0xC9,0xD9,0xE1,0xCE,0xB4,0xA3,0xE2,0xA2,0x90,0x15,0x0E,0x75,0x1A,0x42,0x0A,0x4C,0x0C,0x87,0x23,0xCC, +0x14,0x09,0x70,0xA9,0x71,0xCB,0xF3,0x54,0xBA,0xB9,0xBB,0xCB,0x7E,0x09,0x2F,0xBA,0x6E,0xD1,0x5B,0x2C, +0x75,0x85,0x4F,0xCF,0xD8,0x27,0x8B,0xB9,0xC4,0xC2,0x87,0x77,0xF8,0x1E,0x7A,0x0B,0x2C,0x74,0x53,0x3B, +0xA2,0x5B,0x93,0x06,0xE9,0x46,0xE2,0xAD,0x20,0x24,0xA8,0x9C,0xAF,0x8A,0xF5,0xBD,0x9A,0x21,0x0F,0x95, +0x2D,0x89,0xE4,0x46,0xED,0xA1,0x88,0xDE,0x48,0x93,0xD4,0x62,0x19,0xBE,0x42,0x82,0x4F,0x3C,0x4D,0x4B, +0x59,0xDE,0x33,0x42,0x2D,0x95,0xB1,0x04,0x1E,0xEF,0xE6,0xEF,0xF4,0x0F,0xEB,0xDE,0x26,0xFF,0x53,0xD9, +0xAD,0x7F,0x92,0xDB,0xAD,0x9D,0x84,0x01,0xB9,0x10,0x73,0x3F,0xAF,0x5A,0x8E,0xDD,0x17,0x9E,0x35,0x75, +0x04,0x3D,0x8C,0x9B,0xC3,0x9D,0xF2,0xD5,0x04,0xBF,0xB9,0x6D,0xD0,0xC2,0x6C,0x3E,0x07,0xBC,0x76,0xF4, +0x19,0x90,0xE5,0xBA,0xD0,0x2E,0xE5,0x2F,0x10,0x6F,0xD8,0x77,0x7D,0x83,0xD9,0x31,0xAC,0xDA,0xD5,0x07, +0xA8,0xFD,0xD6,0xE8,0x9F,0x2C,0xB5,0x0E,0xB3,0xA0,0x66,0xB3,0x9E,0x53,0xBC,0xD1,0x0A,0xB1,0x3D,0x4E, +0x83,0x2B,0x60,0x39,0x8F,0xDA,0xE7,0x80,0x15,0xD4,0xF2,0xA1,0x58,0x28,0x4E,0x2D,0xCE,0xFC,0xFE,0xD3, +0xC0,0x28,0x87,0x76,0x55,0xEC,0x3C,0x5E,0xE6,0x55,0x5B,0xA6,0x7E,0x99,0x02,0x87,0xAE,0xEB,0xE2,0x1C, +0x17,0x05,0x21,0xB9,0x65,0xC9,0x4A,0x31,0x67,0x3A,0x01,0x49,0xB4,0x67,0xBD,0xE6,0x42,0x6B,0xEC,0xF5, +0x51,0x57,0x1D,0x22,0xDF,0x9E,0xD1,0xEC,0x1F,0x5A,0xF6,0xB3,0x6E,0xB6,0xEF,0x48,0x7A,0xC9,0x8F,0x18, +0xE8,0x65,0x38,0x1A,0x6A,0x6F,0x7A,0x52,0xE7,0x94,0x7E,0x6B,0x34,0x9C,0x8D,0xD4,0xA8,0x6A,0x88,0xE4, +0x65,0x4F,0xF7,0x7E,0x89,0xD0,0x06,0x2D,0x7C,0xF9,0xEF,0x36,0xEB,0x64,0x03,0xE0,0x77,0xEA,0xC6,0xB3, +0x48,0xA4,0x81,0x92,0x5E,0x9E,0x1E,0xAA,0x26,0x6C,0xDB,0xFE,0x32,0x63,0xC9,0xB1,0xBF,0x01,0x60,0x8D, +0xB6,0xBD,0x37,0x55,0xC8,0x86,0x68,0xB0,0xB0,0x4B,0xD7,0x84,0xFA,0xA1,0x7A,0x1C,0xFD,0xF5,0xDC,0xD4, +0x0D,0x1A,0xDC,0x08,0x68,0xB6,0x5C,0x6F,0xBE,0xEB,0x97,0xAF,0xE3,0x75,0xAE,0xBD,0x50,0x84,0xE7,0xDB, +0x30,0xFE,0xC0,0xB4,0x1F,0x5C,0x76,0x8D,0x5C,0xBE,0x60,0x02,0x79,0x0D,0x12,0x3D,0xFB,0x64,0xCD,0x72, +0xBD,0x4B,0xAA,0xDA,0xAF,0x64,0xCD,0xF2,0x32,0x51,0x2C,0x6E,0xB2,0xD5,0x20,0xD0,0x09,0xCA,0xFE,0x9D, +0xB8,0xE2,0x4B,0x1C,0x02,0x01,0xBB,0xB5,0x55,0x8D,0x18,0xA3,0x40,0xAA,0x45,0xE2,0x39,0xC1,0xB1,0xEF, +0x91,0x4E,0x29,0x0B,0x1D,0x46,0x15,0xD3,0x41,0xF3,0xFF,0x9D,0xD0,0x72,0x00,0x06,0x16,0x48,0xE7,0x00, +0xFB,0x8C,0x4A,0xC8,0x63,0xA4,0x64,0x06,0xB9,0x20,0x88,0xA8,0x88,0xA8,0xDE,0x14,0xEC,0x88,0xD8,0x72, +0xB4,0x04,0xF0,0x07,0xDF,0xE3,0x41,0x61,0x82,0x56,0x9F,0xA7,0x96,0xA3,0xEE,0x11,0xCD,0x4F,0xF0,0x62, +0x5D,0xE0,0x4A,0x16,0x41,0x57,0xB1,0xE4,0xED,0x88,0x00,0x12,0x66,0xE8,0xD9,0xB5,0xC1,0xEC,0xFD,0x8C, +0x3B,0x47,0x36,0x6E,0x70,0x25,0x72,0x07,0x4A,0x45,0xAC,0x9D,0x92,0x5B,0x6A,0xB8,0x11,0x06,0xF4,0x1A, +0xF8,0xAA,0x22,0x7F,0x97,0x41,0xCB,0xC2,0x5F,0x00,0x5A,0x99,0x2D,0xF5,0xF8,0xFD,0x29,0x9B,0xEC,0xAB, +0x48,0xA2,0x6C,0x5E,0xBA,0xCC,0x52,0x88,0xAB,0x7B,0xA5,0xEE,0x15,0x26,0x8F,0x4B,0x36,0xC0,0xB3,0x4E, +0xE3,0x9A,0x4A,0xAF,0x0C,0xD7,0x20,0x53,0xD4,0xA1,0x45,0x60,0xEF,0xE3,0x1F,0x5D,0x68,0x2E,0x8A,0xA4, +0x21,0x4F,0x4A,0x4F,0x65,0xFB,0x64,0x41,0x65,0x92,0xA2,0x8D,0xF8,0x2D,0x46,0xCD,0xF1,0x25,0xBD,0xDE, +0xF1,0xA8,0xC0,0x58,0x6B,0xB1,0x82,0x7D,0xB9,0x91,0x4B,0xCD,0x8D,0x77,0xED,0x1D,0x45,0x80,0xE4,0x49, +0x47,0xB0,0xE5,0xD5,0xDD,0x7C,0x8C,0x4D,0x83,0xED,0x3B,0x66,0x03,0x06,0xCF,0xA2,0x1F,0xB8,0xF4,0xE4, +0xDE,0xFB,0x4F,0x72,0xA3,0x59,0x81,0x7C,0xF3,0xCC,0x47,0x9F,0x65,0xBA,0x57,0xCB,0x92,0x78,0x4F,0x94, +0x22,0x11,0x3F,0x7A,0xB6,0x29,0xC8,0x0A,0x9B,0x50,0x91,0x47,0xF6,0xCA,0x41,0x61,0xAD,0x1C,0x77,0xB1, +0x65,0xB0,0x15,0x77,0xAF,0x48,0xE0,0x37,0x79,0x2B,0xDF,0x3F,0xA0,0x61,0xA5,0x64,0xE4,0x8B,0x94,0x4C, +0x83,0x59,0xFB,0x9B,0xAB,0xE8,0xC4,0x52,0x9F,0x37,0xBE,0xDC,0xD7,0x92,0xEE,0xAF,0x84,0x45,0x25,0x33, +0x8A,0xF3,0x07,0xA3,0xDF,0x1D,0xEC,0xAA,0x23,0xF3,0xAA,0xC6,0x43,0x4D,0x6E,0xBF,0x13,0x09,0x75,0x2E, +0xC2,0x7F,0xFC,0x85,0x57,0xA2,0xE2,0x07,0x0A,0x86,0xDD,0x8F,0x31,0x37,0x66,0x8A,0x59,0x15,0x21,0x3D, +0xE8,0xFB,0x4F,0x58,0x2A,0x17,0x29,0x4E,0x7E,0x13,0xCA,0x48,0x21,0x1F,0x58,0x6F,0x03,0x94,0x7E,0xBA, +0x1D,0x56,0xA6,0x6C,0x82,0x76,0xF8,0xDB,0xA6,0x78,0xA0,0x38,0x59,0x9B,0xD7,0x50,0x0B,0xD7,0x43,0x2F, +0xF1,0xA7,0x87,0x41,0x0A,0xE6,0x5D,0x2D,0x4A,0x94,0xDF,0xBD,0xC1,0x1A,0xFF,0xFC,0x00,0x76,0x1E,0x61, +0xA8,0x69,0xC7,0xFA,0xC2,0xC7,0x44,0xEC,0x91,0xD1,0xDE,0x65,0x9B,0xCD,0xD5,0x27,0xA9,0x68,0x79,0xF8, +0x50,0x32,0x1E,0x04,0xD7,0x1F,0xBE,0xAA,0x91,0x3F,0x83,0xAB,0x5D,0xE3,0xC7,0x0F,0x39,0x78,0x01,0xD0, +0x19,0xA5,0x28,0x97,0x98,0xA1,0x09,0xBB,0xD6,0x14,0x4F,0xAE,0x89,0x7D,0x87,0x98,0x16,0x87,0x50,0x1D, +0xFD,0xEF,0x23,0x64,0x86,0x83,0x5D,0x41,0xE5,0xD6,0x70,0x1F,0xAF,0x84,0x4F,0x55,0x66,0x33,0x2F,0x60, +0xA6,0x85,0xD6,0x10,0xF4,0x22,0x9C,0x50,0xB2,0x4A,0x6E,0x48,0x9F,0x22,0xA6,0xE1,0x06,0x81,0xDA,0xF7, +0x2D,0x13,0x0B,0x93,0x78,0x6D,0x4A,0x60,0x29,0x44,0x28,0x6C,0x22,0x85,0x87,0xE4,0x19,0x3E,0xB7,0x0E, +0x2E,0x87,0xB1,0x3B,0x3C,0x00,0x83,0x40,0xA3,0xFF,0x87,0xB7,0xC4,0xE4,0x4A,0xDE,0xB1,0x39,0xFA,0x96, +0xA9,0xEB,0xB3,0x90,0x01,0xA5,0xB6,0x65,0x07,0x0A,0xBC,0x2C,0x49,0xDB,0x35,0x4B,0x51,0xF6,0x65,0xC7, +0xAE,0xB3,0x9F,0x71,0x7D,0x43,0x28,0x76,0x13,0xAA,0x45,0x85,0xF2,0x6D,0xC3,0xBB,0x59,0x4C,0xDB,0x11, +0x05,0xCB,0x04,0x9C,0xBC,0xC5,0xFB,0x18,0x74,0x66,0x72,0x13,0x6F,0xA8,0xDA,0x17,0x7F,0xC8,0x08,0x9A, +0xCC,0x67,0xA0,0xD1,0xA3,0x45,0x12,0xE5,0x03,0xEB,0x51,0x1C,0xF3,0xB2,0x38,0x27,0xB3,0xDE,0x2A,0xC3, +0x5D,0x32,0x5B,0x89,0x0C,0xF3,0x34,0xF0,0x7D,0x79,0x97,0x49,0xB9,0xC1,0x61,0x9F,0x23,0x35,0xEF,0xCB, +0x81,0x8D,0xC8,0x69,0x1F,0x07,0x83,0x84,0x7F,0x7B,0xB9,0xBB,0xE6,0xB4,0x6B,0xC8,0xB2,0x8E,0xDC,0x0A, +0xD4,0x04,0x29,0x45,0x31,0xCC,0x61,0xEA,0x6C,0x6C,0x32,0x9B,0x8D,0xF8,0x88,0x5E,0xF4,0x39,0xD0,0x09, +0x3B,0x6C,0xAB,0x3E,0xAE,0xE2,0x5B,0xB4,0xEF,0x46,0x9D,0x54,0x77,0x86,0xA8,0x89,0xC8,0xEE,0xA9,0x6E, +0x7D,0xAC,0xAB,0x39,0x78,0x72,0xB5,0x50,0x93,0xE1,0x43,0x84,0x26,0x7E,0x4F,0x04,0x7C,0xAE,0x0E,0x07, +0x67,0xF0,0xF5,0xC1,0xDD,0x33,0xEF,0xA0,0x1B,0x94,0xBE,0xA2,0xD7,0x0B,0x37,0xF0,0x66,0x71,0x00,0xE4, +0xFF,0x12,0x1C,0x50,0xE7,0x7D,0x7C,0x4A,0x6D,0xF7,0x91,0x61,0x26,0x96,0xC7,0x97,0xB7,0x00,0x55,0xF5, +0x80,0x59,0x65,0x23,0xCB,0x4B,0x4D,0xD7,0x80,0x9C,0x52,0x67,0xF5,0x15,0x00,0xC0,0xF9,0xDC,0x35,0x22, +0x54,0x0C,0xF5,0x2A,0xF8,0x49,0xB5,0x96,0x97,0xAB,0x2C,0xEA,0x60,0xA7,0x01,0x89,0x0A,0x8B,0xAC,0x33, +0x39,0x93,0xCD,0xD1,0xBA,0x33,0xBB,0xD6,0x86,0xCE,0x7C,0x0F,0x77,0x9B,0x9F,0x38,0xD9,0xB6,0x51,0xA5, +0x5D,0xF2,0xE0,0xA3,0xFA,0x98,0x4C,0x5B,0x41,0x6D,0xD8,0x5F,0x06,0x1E,0x8D,0xA4,0x3B,0x31,0xCF,0x05, +0xF7,0x18,0xC2,0x65,0xF7,0x6A,0xB6,0x0E,0x04,0x7D,0xF4,0x70,0x3A,0xD1,0x69,0xAB,0x95,0xB4,0x1A,0x2B, +0x5C,0xF5,0x84,0x63,0x97,0x62,0x51,0x6E,0x7D,0x6F,0x99,0xBC,0xB9,0xBD,0x86,0x6E,0x86,0xF6,0xFC,0xE9, +0xAA,0xBA,0x8F,0xC8,0x5D,0x4C,0x55,0xBE,0xEF,0xB2,0x8F,0x2D,0xF5,0x47,0x6F,0x67,0x11,0xD9,0x54,0x3F, +0x50,0xA8,0x8B,0xD9,0x1E,0x50,0x7F,0xD3,0xC9,0xB5,0x33,0x2A,0x68,0xF9,0xE6,0x8E,0x5C,0x01,0xDE,0x77, +0x4A,0xB2,0x94,0xEF,0x7F,0xCE,0xDA,0xB8,0xCD,0x3E,0xEE,0x9E,0x4F,0xFF,0x56,0x38,0xBB,0x2E,0xAC,0x01, +0xFD,0x31,0x5F,0x79,0x84,0xBC,0x85,0x4D,0x4F,0x38,0x37,0xD4,0xE6,0xB2,0xCD,0xD6,0x01,0x63,0x6C,0xFC, +0x0E,0x60,0xBE,0x9F,0x1E,0xA0,0xD8,0xBB,0x3F,0xF7,0x8D,0x7B,0xA2,0xF4,0xC0,0x18,0xBE,0xFD,0xBA,0xF7, +0x7C,0x8D,0x2E,0x15,0xE3,0x25,0x59,0xC6,0xD2,0x28,0xF1,0xE8,0x09,0xBA,0xC0,0x44,0x72,0x65,0x0D,0x0F, +0x75,0x00,0xB8,0x56,0x12,0x9A,0x94,0xEE,0x75,0x51,0x17,0x42,0x5A,0x98,0x2F,0x09,0x63,0x97,0x5B,0xC7, +0x52,0x2A,0x09,0x93,0x44,0x64,0x9F,0x20,0x22,0x6E,0xB1,0x0E,0x43,0x6B,0xE1,0x12,0x70,0xE9,0x56,0x2D, +0xE9,0x7D,0xA9,0xAF,0x2E,0x9B,0xAB,0x1F,0x44,0x77,0xEE,0xC4,0x32,0xE4,0x08,0x6F,0x0B,0x69,0x17,0xAB, +0x37,0xD9,0x27,0x98,0x02,0x08,0x23,0x85,0x1A,0x65,0xC1,0x91,0xD1,0x68,0x7A,0xE9,0xB3,0x46,0x14,0x9B, +0x6E,0x4B,0x2E,0x17,0xB8,0x97,0x61,0x93,0x57,0xC1,0xF6,0x0A,0xB7,0x21,0xA0,0x79,0x66,0x38,0xFF,0xC5, +0x96,0x12,0x3A,0xF7,0x7F,0x08,0x9A,0xA4,0xE4,0xC9,0xB6,0x4A,0x09,0x58,0x69,0xCE,0xDA,0x60,0x0A,0x9C, +0x59,0x7E,0xB4,0xC1,0xD3,0xF3,0x20,0xDA,0xCB,0x41,0xE2,0x5E,0x1A,0x97,0xC3,0x54,0xE3,0x91,0x43,0xF5, +0x06,0x46,0x6B,0xAB,0xC9,0x52,0x57,0x4F,0x9B,0x9D,0xB4,0x34,0x36,0xD6,0x89,0xE2,0x14,0x86,0xEF,0xDB, +0x4B,0x43,0xE3,0x5F,0x9A,0x14,0xE5,0xDF,0x61,0xAA,0x68,0x6B,0xBB,0xAE,0xBE,0x13,0xD4,0xD1,0x02,0x42, +0x70,0xD9,0x70,0xAB,0xDD,0xA2,0xB3,0x3A,0xEC,0xA6,0x18,0x7A,0x5D,0x90,0x43,0xD3,0xB2,0xEE,0xC3,0xB8, +0x48,0x4E,0xBB,0xBD,0x1E,0x9F,0xB2,0x29,0x8A,0x00,0x83,0x57,0xA6,0x2C,0xAC,0xA8,0x51,0x1F,0x6B,0x60, +0x28,0x62,0x21,0x19,0x8D,0xC4,0x1B,0xD0,0xDA,0xCE,0xFF,0xEF,0x40,0x90,0x9A,0x66,0xA2,0x38,0x14,0x5D, +0x60,0x8B,0xEF,0xDF,0x18,0x7D,0xCC,0x40,0x6A,0xE0,0x07,0x20,0x79,0xD0,0xA3,0xEC,0x40,0x41,0x5A,0x92, +0x9C,0x13,0x7B,0x87,0x41,0x41,0x83,0xBA,0xDC,0x70,0x3D,0x25,0x85,0xB2,0x6A,0xDF,0xF6,0x8A,0xF2,0xEB, +0xD7,0xCC,0xAD,0x26,0x95,0x32,0x7D,0xF0,0x0C,0xD8,0x66,0x92,0x50,0x11,0xC4,0x06,0xB0,0x17,0xD3,0x40, +0x00,0x93,0xE9,0x1F,0x93,0xD7,0xEC,0xA3,0xB8,0x04,0x42,0x62,0x00,0xD5,0x3C,0xB6,0xBC,0xA3,0x22,0xF7, +0xC2,0x39,0x12,0x4D,0xD2,0x2A,0xA6,0x3A,0x4B,0xB1,0xFD,0x3F,0xB4,0x25,0xFF,0x1F,0x3E,0x12,0x28,0xD5, +0xA6,0x34,0x17,0x8B,0x14,0x68,0xC5,0xC5,0x8C,0x17,0x99,0x0A,0x4F,0x5A,0xBD,0xA6,0x4D,0x7A,0x5D,0x88, +0x53,0x78,0xC6,0x40,0xBF,0x3A,0x6D,0x4A,0xE8,0x87,0x6B,0xE2,0x8D,0x24,0x1B,0x87,0x1D,0x5B,0x8A,0x08, +0x0A,0xCF,0x16,0x3D,0xC8,0xD3,0xF8,0xDE,0x8E,0x84,0xC7,0x91,0x16,0xCE,0xDE,0x94,0x1D,0xBD,0xD7,0x74, +0x0B,0x5C,0x20,0x1D,0x05,0x19,0x45,0xA0,0x56,0x66,0x35,0x66,0xC6,0x1B,0xE8,0x5B,0x48,0xD1,0x88,0x46, +0x0C,0xE8,0x66,0xD8,0x9E,0xCB,0xE6,0xC8,0x05,0x3C,0x41,0x13,0x9B,0x3F,0x88,0x0E,0x3A,0xF9,0xE1,0x86, +0x9E,0xC1,0xD6,0xCD,0x3D,0x2E,0xFA,0xDF,0xC7,0x50,0xCD,0x78,0x2B,0x0A,0xF2,0x76,0x77,0x63,0x7C,0x1D, +0xB2,0x47,0x2C,0xF6,0x6E,0x8A,0xA8,0xD7,0x59,0x8B,0x27,0x1B,0x2D,0xEA,0x3F,0xA7,0x18,0xCF,0xF3,0x7C, +0x9C,0x5F,0x66,0xC0,0x04,0xF2,0xF1,0xFC,0xD9,0xFD,0xBC,0x95,0x35,0x20,0xBD,0xD2,0x40,0xCF,0xC8,0x44, +0x17,0x5F,0x8F,0x3A,0x98,0x3C,0xA9,0xD6,0x03,0x7C,0x40,0xB0,0x40,0x30,0x80,0xE6,0xA8,0xEE,0x8E,0x27, +0x50,0x63,0x5A,0x78,0x19,0x24,0x51,0x63,0xD1,0x40,0xC9,0xA5,0xDD,0x86,0x84,0x5D,0x74,0xDF,0x05,0x85, +0x85,0xA9,0x41,0xB1,0xC0,0x12,0x29,0x28,0xB7,0x57,0x1E,0xD8,0xED,0x41,0x4C,0xD8,0x15,0x64,0x5E,0x5E, +0x40,0xD7,0x20,0x95,0x70,0x39,0xE9,0xA1,0xE7,0xC9,0x53,0xB0,0x74,0xE1,0x50,0x4E,0x41,0xD6,0x38,0xDB, +0x21,0x44,0x1F,0x74,0xED,0x23,0xBB,0x41,0xEA,0xB9,0x20,0x11,0x65,0x4D,0xA7,0xC6,0x3D,0xC5,0x08,0x28, +0x52,0x1A,0xFE,0xBD,0x76,0xE8,0xB3,0x01,0x64,0x4C,0xA9,0x84,0xF5,0x3A,0xE2,0xDA,0x74,0x77,0xE0,0x71, +0xC8,0xA7,0x08,0xC8,0x73,0xCA,0xE4,0x65,0xE1,0xD4,0x12,0xE0,0xA1,0x84,0x12,0xE5,0x90,0x54,0xE1,0xB0, +0x4B,0xE9,0xAC,0x53,0xA2,0x74,0x86,0x0D,0x18,0xEE,0x91,0xF0,0xAF,0x91,0x4C,0xD3,0x4D,0x35,0x73,0x72, +0xAB,0x17,0xBC,0xE4,0x7C,0x58,0xCC,0xEF,0x1D,0xB4,0x91,0xC2,0xCF,0x50,0x68,0x64,0x20,0x57,0xC9,0xA2, +0x4A,0xE0,0x5D,0x7F,0xBF,0x0D,0xB9,0x56,0xFD,0x41,0xA4,0x53,0xB5,0x1D,0x03,0xB1,0xE4,0x39,0xD2,0x6F, +0xBE,0x12,0xEA,0x31,0xB2,0xF1,0x6A,0x60,0x63,0x19,0xB7,0x15,0xA0,0x52,0xDB,0xB0,0x67,0x0F,0x8B,0x76, +0x4E,0x49,0xF5,0xCA,0x5E,0xC2,0xC8,0x41,0xE4,0xFB,0x30,0x4F,0xFC,0x0B,0x46,0x83,0xCF,0x4E,0xE8,0xFD, +0x16,0x78,0x36,0x92,0xCF,0xD4,0x64,0x67,0x2A,0x4B,0xDB,0x40,0xE6,0xF8,0xCF,0xDD,0x1C,0xFD,0x23,0x9D, +0xA1,0xC5,0x75,0x07,0xB7,0xB9,0x44,0xD0,0x24,0x51,0x7A,0x48,0xD9,0xFC,0x1F,0x2F,0xA2,0x18,0xCC,0x7B, +0xAC,0xF0,0x91,0xC1,0xA7,0x3D,0x4A,0xDD,0xF2,0x0A,0x89,0xF1,0x5A,0xF6,0x5B,0x67,0xBD,0xBC,0x45,0x97, +0xD6,0x86,0x42,0x70,0x6B,0x2E,0xF4,0x40,0xBF,0xF4,0xE3,0x18,0xA9,0xF5,0x63,0x1D,0x93,0x47,0x27,0xA1, +0x78,0x2B,0x2E,0x8E,0xC6,0x6A,0xBC,0x94,0x5C,0x96,0x26,0xEE,0x5F,0x97,0xE4,0xE6,0x40,0x0A,0x5D,0x23, +0xAD,0x97,0xBB,0xFA,0x3E,0x1D,0x5A,0x9C,0x3F,0x49,0x4A,0x62,0x09,0x2B,0xD2,0x94,0x6D,0x8D,0x9F,0x26, +0x91,0xAA,0xB3,0x4A,0x46,0x76,0xDD,0xF2,0x62,0x0A,0x1E,0x85,0xA8,0xCC,0xC6,0xCA,0x33,0xB5,0x8E,0xCA, +0x7C,0x95,0x57,0xEE,0x38,0x24,0x56,0xBD,0xD0,0x96,0x26,0xFE,0xDC,0xB6,0x66,0xBB,0xCA,0xC2,0x11,0xCD, +0x17,0x58,0x83,0xAC,0x00,0x66,0xED,0x71,0x1F,0xBC,0x75,0x4D,0x05,0x60,0x0E,0xF1,0x21,0x87,0x8A,0x9D, +0x39,0xFF,0x1B,0x7D,0x3F,0xF3,0x30,0xDD,0xCC,0x03,0x26,0x4C,0xC8,0xC6,0x2E,0x9E,0x4D,0xD8,0xD8,0xAB, +0x5E,0x63,0x4E,0x05,0x9B,0xBF,0x5F,0x1E,0x2A,0x8D,0x3D,0x2A,0x30,0x6C,0x3A,0xAD,0x11,0xD1,0xD5,0x12, +0x6B,0x01,0x86,0x7C,0xB6,0x6A,0xF0,0x21,0x0B,0x97,0x99,0x7F,0x5F,0x11,0x8E,0x90,0x3B,0x43,0x37,0x3A, +0x84,0xA3,0xAF,0x73,0xEF,0x92,0x89,0xBB,0xBC,0xAC,0xD3,0x7E,0x3A,0xBD,0xC7,0xEF,0x5C,0xBE,0xC0,0xA8, +0x50,0x1B,0x63,0x72,0x7B,0x2F,0x58,0x29,0x37,0xEC,0x50,0x39,0x75,0x1D,0xA3,0x95,0x92,0x3E,0x1A,0x24, +0xB2,0x8E,0xD3,0x32,0x51,0x42,0x8A,0xF7,0xBA,0x25,0x87,0x5F,0x0D,0x60,0x06,0x37,0xA3,0x24,0xCE,0x9A, +0xC6,0xC9,0x87,0x47,0xB8,0x6F,0xF0,0xE0,0x22,0x43,0x9A,0xB5,0x8D,0x73,0x9B,0x20,0x20,0xBC,0xA3,0x85, +0x48,0xCC,0x64,0xBD,0x83,0x46,0x50,0x83,0x10,0xD1,0x02,0x1A,0xCF,0xE2,0x38,0xEE,0x70,0xB2,0x2B,0xB8, +0xD2,0x47,0x6B,0xC2,0xCF,0xC3,0x95,0x48,0x45,0x56,0xB0,0xF2,0xAF,0x24,0xCB,0x18,0x84,0x55,0xC5,0x02, +0x13,0x28,0x18,0xA1,0xE0,0xCD,0xAE,0x98,0xD2,0x68,0xCE,0xC7,0x85,0x1F,0x97,0xC6,0x97,0x8C,0x5B,0x13, +0xFA,0x4C,0xF6,0x0A,0x0A,0xDA,0x39,0x8C,0x3A,0xCA,0xDB,0x94,0xBD,0xD7,0xD2,0xD0,0x36,0x4B,0x36,0x28, +0x04,0x3C,0xCE,0x46,0x07,0x17,0xF4,0x24,0x72,0x58,0xB6,0xAB,0x1D,0x43,0xE4,0x09,0xB2,0x78,0x5A,0x1C, +0x5D,0x66,0x2F,0x7E,0xE8,0xDC,0x96,0x35,0x21,0x7A,0xA9,0xC5,0x5D,0x25,0x76,0xE2,0x54,0x56,0x8F,0x6E, +0xA5,0x47,0x9D,0xC5,0x00,0xB0,0xE5,0x14,0xEA,0xD2,0x42,0xCC,0x3D,0x13,0xA0,0x48,0xC7,0x91,0xC6,0x47, +0x28,0xEC,0x98,0x69,0x31,0x63,0xDA,0x41,0x29,0x3F,0x6D,0xC3,0x70,0x9B,0x9A,0xD0,0x0B,0xD0,0x52,0x7E, +0xFA,0x32,0x13,0xD4,0x88,0x0F,0x6C,0xBC,0x4C,0x2E,0x01,0x99,0xC8,0x3F,0x93,0x5F,0x25,0x68,0xCD,0xB1, +0x4B,0xC4,0x4E,0x2F,0x70,0xB9,0x23,0xFD,0xF9,0x67,0x6F,0x1F,0x98,0x93,0xAF,0xC7,0x2E,0xCC,0xBA,0xB8, +0xCF,0xAD,0xE9,0xB8,0x42,0x4F,0x6C,0xBE,0x40,0xC4,0xA3,0xFF,0xFC,0x53,0x21,0xCF,0xCC,0x8D,0x3F,0x4E, +0xB9,0xAE,0x64,0xB6,0x2D,0x1D,0xC1,0x4B,0x1B,0xAD,0x7E,0xA1,0x2D,0x8F,0x6A,0x50,0x5F,0x00,0x80,0x4D, +0x75,0x8F,0x5C,0xE2,0x5A,0x2E,0xD3,0x77,0xB5,0x8E,0x43,0x5E,0xDB,0x50,0xC4,0xC9,0x54,0xC5,0xC2,0x3C, +0x9E,0xEF,0x1B,0xC4,0xB1,0x3A,0x7C,0x22,0xB6,0x92,0xD1,0xA4,0x36,0x89,0x91,0x82,0xDE,0x1C,0x8C,0xEB, +0x3B,0x59,0x3A,0x01,0xA1,0x15,0x5E,0x76,0x76,0x0C,0x05,0x38,0x18,0x54,0x25,0xFA,0x96,0x58,0xF2,0x76, +0x03,0xF9,0x39,0x77,0x41,0x7E,0x8F,0xF1,0xEF,0x76,0xE5,0x17,0x4E,0xB6,0xF6,0x8B,0x36,0xAB,0xE5,0xC8, +0x50,0x36,0xC6,0x21,0x4E,0x59,0x46,0x24,0x7E,0x23,0xED,0xAD,0x03,0x27,0xD7,0xCA,0xAA,0x72,0x8C,0xB9, +0x5E,0xB5,0x25,0x19,0xAA,0x06,0x40,0x57,0x23,0xF2,0xA1,0x5A,0x25,0x8E,0x57,0x94,0xC8,0x1B,0x01,0xD3, +0x35,0x58,0x15,0x58,0x57,0x18,0x91,0xD7,0x5F,0x6A,0xD0,0x22,0x9A,0x29,0x70,0x19,0x8B,0xE1,0xE2,0xA5, +0xCB,0x44,0x1C,0xEB,0xDD,0xD6,0x86,0x34,0x32,0xB1,0x46,0x3F,0xF4,0xB1,0x69,0xB7,0xBE,0x8A,0xB6,0xEE, +0x23,0x71,0x06,0xC8,0x63,0xFC,0xA8,0xD8,0x50,0xBB,0x00,0x62,0x6F,0x81,0x5A,0x9C,0x39,0x7B,0xD1,0x8E, +0x68,0x5E,0x14,0x3E,0x7C,0x95,0xF0,0x76,0x01,0xE8,0xFD,0x3D,0xF6,0xF7,0x6F,0x12,0xAD,0xF4,0xCD,0xAF, +0x50,0xE9,0xE6,0xA7,0x36,0x22,0x75,0x5A,0x98,0x9D,0x8F,0x86,0x7F,0xF6,0xC6,0x3E,0x17,0x92,0xDC,0xA6, +0x27,0x1A,0x48,0x2E,0xF3,0x1F,0x79,0x5E,0x03,0x92,0x21,0x51,0xE8,0x07,0x3C,0x75,0xC4,0xCF,0x78,0x2B, +0xA4,0xEC,0x0C,0x7C,0x1D,0xC0,0x16,0x2A,0x92,0x69,0xA1,0xE4,0xC6,0x37,0x71,0xF2,0x87,0x1F,0x6C,0xFB, +0xC9,0x5F,0x3E,0x69,0x5F,0x72,0x9A,0xCD,0x19,0x3C,0xC2,0x10,0x74,0x5C,0x60,0x4A,0x61,0xA4,0x4B,0x28, +0xC3,0x58,0x48,0x8C,0xEA,0xC9,0x0D,0x08,0x1F,0xEB,0xAB,0x76,0xE6,0x2A,0x4F,0x61,0x7C,0x00,0x9B,0xB2, +0x5F,0x19,0x98,0x32,0xD7,0x38,0xC9,0xDF,0xA2,0xC8,0x5C,0x18,0x42,0x63,0x8C,0x24,0x18,0x9B,0x0A,0x08, +0x8B,0x19,0xFF,0xD1,0x0F,0x87,0xC9,0xA6,0x77,0x27,0xC0,0x2D,0x1A,0xBA,0x81,0x50,0x2A,0xE8,0x8E,0x8F, +0xD9,0xEA,0xEA,0x1B,0xC8,0x79,0x6C,0xC5,0x76,0xCB,0x5E,0xBD,0x64,0x75,0xEA,0xB2,0x93,0xCB,0xBD,0x0F, +0x21,0xAD,0x38,0xCB,0xF2,0x8B,0xE3,0x47,0xB4,0xF8,0x4A,0xE0,0x33,0x17,0x04,0x32,0x54,0xDB,0xC8,0x2E, +0xA7,0xB5,0xD5,0x07,0xDD,0x88,0x7A,0x92,0xBE,0x6B,0x93,0x6C,0xE5,0x34,0x65,0xD4,0x87,0x60,0x43,0x37, +0x34,0xDA,0x1A,0xC8,0x8E,0x84,0x4A,0xC4,0xD6,0x7D,0xDD,0x31,0xBF,0x70,0xCD,0xEB,0x50,0x66,0x7E,0x6D, +0x78,0x80,0xB4,0x51,0x5B,0xE3,0x45,0x25,0x6B,0xA3,0x82,0xFC,0xDF,0x49,0x39,0xB4,0x2D,0xCC,0xC0,0x5C, +0xE2,0x1A,0x70,0x69,0x5B,0x32,0x24,0xED,0xDB,0x97,0xAB,0x5A,0x4A,0xC3,0x8A,0xFF,0x49,0x10,0x3B,0x44, +0xC7,0xA3,0xC3,0x80,0x52,0x69,0x9C,0xB2,0xDB,0xD6,0x1B,0x02,0x06,0x86,0x4B,0x53,0xDB,0x42,0xED,0xC6, +0x31,0x9E,0x7C,0x9F,0x1F,0x4A,0x2A,0xC8,0xB8,0xD3,0xC1,0x12,0x47,0xCE,0x67,0x19,0x0A,0xF3,0x32,0x07, +0xD5,0x88,0x65,0x2F,0xAE,0xA9,0x6B,0x4C,0xE8,0x79,0xD7,0xB2,0xF5,0xF0,0x03,0x6E,0x2A,0x88,0x06,0x12, +0x26,0x8C,0x42,0x8D,0x12,0x26,0x60,0x7D,0xC2,0xC3,0x21,0xC0,0x93,0x4F,0x9A,0x59,0x5D,0x02,0xDB,0xFC, +0x82,0x20,0x8C,0xC1,0x15,0xC6,0xD9,0x2B,0x25,0xEE,0xD7,0x88,0xEA,0x08,0x4E,0xF6,0xE2,0xC3,0x84,0x74, +0xB2,0xF9,0x45,0x3E,0xEB,0x0D,0xE4,0x34,0x64,0x6A,0xC3,0x10,0x0E,0x7D,0x8D,0xC0,0x95,0x64,0x18,0x57, +0xC8,0x9F,0x42,0xC9,0x53,0x43,0x5B,0xA2,0x37,0x73,0xA7,0x67,0x54,0xEC,0x63,0xEC,0x4D,0xB8,0x59,0x0A, +0x0E,0x81,0xC9,0x68,0xEF,0x9E,0x8C,0x55,0x7A,0x93,0xAE,0xE2,0x3E,0x34,0x96,0xAF,0x9C,0x38,0x3A,0x4A, +0x92,0x76,0x65,0xBD,0x02,0xF5,0x35,0x74,0x2A,0x2B,0x18,0x6D,0x45,0x1B,0x80,0x8F,0x87,0x6B,0xCC,0x3E, +0xCF,0xBB,0x2A,0xDC,0x67,0x2B,0x89,0x1B,0x8F,0x1C,0xAC,0x48,0x91,0xC0,0x7F,0x53,0xE0,0x20,0xA6,0xCE, +0x06,0xDD,0x50,0x3F,0xD6,0xFC,0xFC,0xF1,0x05,0xA8,0x2D,0x88,0x8D,0xEC,0x91,0x25,0xD8,0x28,0x8F,0xD0, +0xEF,0xC9,0x9D,0x01,0x10,0xDD,0x4D,0x87,0x79,0xD4,0x4A,0xB4,0x37,0x15,0xB9,0xFD,0xBA,0xF2,0xF3,0x2D, +0x7C,0xDD,0x4F,0x14,0x02,0x27,0x26,0xA9,0x5C,0x30,0xC8,0x2E,0x23,0xFF,0x17,0x39,0x69,0x2A,0x74,0xE1, +0x86,0x0B,0x9B,0xE8,0x80,0x4D,0x40,0x14,0xE3,0x9D,0x6E,0x27,0xE1,0x3F,0x22,0x3B,0xBC,0xCB,0xBF,0xF0, +0xF5,0xF8,0x24,0x8F,0x10,0x51,0xA5,0x6F,0x22,0xDE,0x9C,0x72,0xC3,0x35,0x7A,0x09,0x25,0xBD,0x99,0x04, +0xCA,0xDF,0x6B,0x41,0xCE,0xBE,0xA7,0x20,0xBB,0xE7,0xC9,0x70,0xD4,0xD7,0x36,0xD2,0x43,0x29,0x8A,0xB5, +0xBC,0x9E,0xBA,0x3A,0x09,0xC8,0xC0,0xD0,0xCA,0xE7,0x61,0x5E,0x8E,0x90,0xFC,0x44,0xBF,0x4F,0x42,0xE0, +0x11,0x86,0x70,0x77,0xFC,0x47,0xA9,0xF4,0xC5,0x9A,0x08,0x89,0x03,0xDA,0xAD,0x69,0x9E,0x24,0xE1,0x52, +0xE4,0x62,0x9F,0x4A,0x96,0x68,0x69,0x9D,0x42,0xBD,0x11,0xB5,0x8B,0x56,0xC9,0xC1,0x1C,0x18,0x16,0x55, +0x10,0x29,0x99,0x95,0xEA,0xBA,0x35,0xF5,0x2F,0x47,0x9D,0x17,0x2B,0x49,0x00,0x0E,0x08,0xD5,0x2A,0xD3, +0x4E,0xF3,0x37,0x28,0xDF,0x7E,0xB4,0x05,0xAF,0xA7,0x79,0x0C,0xD0,0xD5,0x3A,0xF7,0x6D,0x35,0x9A,0xFE, +0xDA,0x2F,0xAB,0xDA,0x39,0x09,0x9C,0x6D,0xD8,0xFA,0x11,0xA0,0x98,0x9A,0xC3,0xB3,0x23,0x91,0x31,0x5E, +0x17,0x74,0x30,0x42,0xBD,0x45,0xA4,0x76,0x5C,0x96,0x2C,0x19,0x56,0x69,0xEA,0xEA,0x8D,0x2B,0x22,0x73, +0x3E,0x98,0xD9,0x08,0x4E,0x20,0x7E,0x2E,0xD9,0x98,0x15,0x32,0x2F,0x0E,0x48,0x6E,0x7B,0xE3,0x1A,0x47, +0x43,0x21,0x7E,0xEA,0x93,0x29,0x83,0xA5,0xA8,0x4C,0xD6,0x32,0xF1,0x21,0xC3,0xAE,0xEE,0x20,0x73,0x73, +0x56,0xCA,0x4E,0xF5,0xB8,0x89,0xB5,0x5B,0x7A,0xAC,0x73,0xBB,0x1F,0x89,0x3D,0x06,0x1A,0xE5,0x65,0x6A, +0xA0,0x70,0x36,0x9B,0xDC,0x9F,0xBF,0xCE,0xB5,0xAC,0x33,0x93,0x1B,0xD5,0x62,0x89,0xC0,0x7D,0x24,0x1E, +0xF9,0xD9,0xE9,0xEF,0x98,0xAD,0x34,0x3E,0xE5,0xE5,0xC5,0x9D,0xCF,0x11,0xB3,0x74,0x50,0x72,0xA8,0xFE, +0xE6,0xC2,0x15,0x54,0x10,0x32,0xEA,0x6E,0x40,0xC5,0xAE,0x86,0xA0,0x87,0xA2,0x76,0x2B,0xA9,0x38,0xAE, +0x9A,0x07,0xF1,0xE8,0x96,0xF5,0x70,0xBF,0x91,0xBF,0xE9,0xAA,0x86,0xD3,0x0B,0xE4,0xF1,0x7A,0x5B,0x2C, +0x9F,0xEE,0x37,0x24,0x6E,0xC4,0x56,0xC6,0x93,0x45,0x81,0xC5,0x59,0xDA,0x1A,0xD4,0xA4,0x9D,0x76,0xF8, +0x01,0x7B,0x54,0xD7,0x08,0x43,0x35,0xDA,0xD6,0xFD,0x0D,0xFE,0x93,0x42,0xB4,0xAB,0x14,0x76,0xEF,0xCA, +0x9C,0x57,0x7D,0x87,0x91,0xBB,0xFD,0xFA,0xF2,0xA7,0xD8,0x83,0x34,0x76,0x1E,0xAD,0xB4,0xA2,0x16,0x6A, +0xEA,0x7B,0xAD,0xC1,0xF5,0xC1,0x51,0x9C,0xBA,0x37,0xD5,0x78,0x6D,0xAD,0xF6,0x7E,0xFF,0x8C,0x3D,0x13, +0x5B,0x5B,0xE6,0x2D,0x6E,0x85,0x87,0xD6,0x65,0xFC,0x74,0x56,0x87,0x7A,0x1F,0xA0,0xE1,0x00,0x6F,0xA2, +0x9D,0x55,0xD4,0x9D,0x08,0x84,0x0F,0xA3,0x9F,0x8F,0xD0,0x31,0xB8,0x87,0xFC,0x27,0x59,0xC4,0x3E,0x2A, +0xEC,0xA9,0xA8,0xEB,0xDB,0x83,0xDE,0x5A,0xAB,0x9E,0x5D,0x58,0x34,0xF3,0x5A,0xBF,0xEA,0x53,0x0E,0x0C, +0x81,0xAC,0xE2,0x4D,0x97,0xF6,0xD2,0x27,0x1F,0x37,0xC7,0x2E,0xE8,0xAB,0x47,0xD3,0xDC,0xDE,0x77,0xA9, +0x1F,0x16,0x0F,0x18,0x49,0x8A,0xFC,0x6F,0x37,0xB9,0xA1,0xFB,0x1A,0xFC,0x1A,0x8C,0xB3,0x0D,0xE0,0x39, +0x1C,0xCC,0x99,0x51,0x69,0x7F,0x07,0x27,0xD9,0xEC,0x51,0x68,0x27,0x6C,0x0F,0x81,0xF4,0x0E,0xCD,0x4D, +0xCA,0x67,0x5E,0x44,0xBE,0x47,0x44,0xE8,0x65,0x94,0x89,0xC5,0x40,0x64,0x6A,0x23,0xC2,0x52,0xD9,0x39, +0x12,0x16,0xEF,0xB5,0x4E,0xC1,0xCF,0xE6,0x57,0xE3,0x25,0x73,0x85,0x37,0xE7,0xA5,0xD1,0x4C,0xDA,0xB9, +0x27,0x07,0x49,0xC2,0x24,0xE1,0xD7,0xF5,0xA7,0x6B,0x88,0x36,0x52,0x4B,0x10,0x67,0xEC,0x94,0x90,0x71, +0xEE,0xAA,0x06,0x44,0xAC,0x20,0x5B,0x40,0x8B,0x00,0xA1,0x67,0xF4,0x22,0x21,0xEF,0x69,0x3B,0x17,0x92, +0x04,0x86,0x97,0x96,0x14,0xA6,0xB0,0x7C,0xB8,0x85,0x56,0xA6,0x34,0x67,0x27,0x40,0xD7,0x68,0xA7,0x44, +0xD3,0x4C,0x39,0x46,0x0A,0x58,0x81,0x90,0xC4,0x5E,0x2E,0x28,0x5C,0x35,0x51,0xDD,0x82,0x43,0xD7,0x68, +0x9B,0xD6,0xC9,0x40,0xA8,0x75,0xBA,0x25,0x6C,0x64,0x11,0x44,0x88,0x15,0xFD,0x79,0x01,0xFC,0xFD,0x94, +0x8C,0x05,0x9F,0xB8,0xED,0xC0,0xD4,0x27,0x37,0x7C,0x11,0x90,0x36,0x06,0x04,0x70,0x40,0x7F,0xA7,0xC0, +0xBE,0xCB,0x84,0x60,0x09,0x2E,0x44,0x7F,0x7A,0x23,0xD0,0x7E,0x3C,0x03,0x40,0x2C,0xDC,0x58,0xC0,0x6A, +0xDB,0xFA,0xCF,0xDE,0x32,0xAD,0x2A,0xF6,0xBB,0xEF,0xDF,0xF2,0xC8,0xDB,0xA4,0x71,0x4D,0xA3,0xF4,0xB6, +0x1C,0x55,0x43,0x3D,0xFC,0xD2,0x50,0x70,0x16,0x65,0x52,0x75,0x42,0x5A,0xB0,0x74,0xF0,0x8D,0xBE,0x47, +0x6E,0xA0,0x2B,0xE5,0x34,0xD3,0x9A,0xDF,0x09,0x50,0x40,0xF4,0xA4,0x80,0xE4,0xB9,0x3C,0xDC,0x6E,0xF1, +0x10,0x92,0x62,0xBC,0x46,0x44,0x75,0x11,0xE3,0x13,0x0B,0x01,0xD4,0x1E,0x24,0x8B,0xE8,0x57,0x4C,0x32, +0x0E,0x6F,0x89,0x6A,0x2A,0x7F,0x8D,0x45,0x60,0x74,0xFB,0x01,0x45,0x6D,0xE0,0x61,0x1E,0xBE,0x0B,0x9F, +0x06,0x16,0xCB,0x66,0x77,0xF3,0x3F,0x73,0xA5,0x48,0x15,0x14,0x8A,0xB3,0xE4,0x85,0x02,0x6F,0x44,0x3C, +0x30,0x3D,0x4E,0x11,0xAC,0x7F,0xDA,0xC2,0x8B,0x45,0xFB,0x21,0xA3,0x18,0xFE,0xC6,0xDC,0xF1,0x02,0x6D, +0x0C,0x63,0x82,0xF1,0x96,0x93,0x64,0x5E,0xC5,0x85,0x77,0xAC,0xDE,0xBB,0x17,0xE7,0x0D,0x00,0x8B,0xE1, +0x17,0x25,0x3F,0xD1,0x4C,0xF3,0xD7,0x67,0x2E,0xF5,0x7C,0x00,0x35,0x0B,0x86,0xD3,0x1C,0xB3,0x5D,0xB4, +0x34,0xAD,0xD8,0x10,0xD7,0x4E,0x36,0xA8,0x2C,0x65,0x76,0xAA,0x3E,0x75,0x10,0xC6,0x5D,0x36,0xCD,0xC0, +0xCC,0x65,0xFA,0x3F,0x63,0x53,0x09,0x16,0x7B,0xB9,0xA6,0xE0,0x8D,0xDB,0xF9,0x14,0xAC,0x15,0x25,0x51, +0x1F,0x47,0x48,0x2B,0xF8,0x78,0x8F,0xE9,0xC7,0x23,0x00,0xE4,0x60,0x6F,0xF8,0x40,0xCF,0x0A,0xFD,0x80, +0xC7,0xB9,0x5E,0x34,0x4D,0x9F,0xAC,0x97,0x38,0x36,0x4D,0xB4,0xB3,0x61,0xCC,0x5E,0xB7,0x53,0x3C,0xD8, +0xC4,0xF9,0x2E,0x1B,0xA6,0x08,0xC8,0x09,0x87,0x76,0xC4,0x4E,0xCB,0x52,0xF0,0x38,0x2A,0x13,0x21,0x4B, +0xB1,0xB3,0xD8,0xF5,0x0A,0x2A,0x53,0xCB,0x15,0xBA,0x57,0xA7,0x8E,0xDF,0x4F,0x25,0xB9,0x36,0x4D,0xFF, +0x6A,0xC9,0x5B,0x85,0x5C,0xBE,0xC0,0xA8,0x50,0x1B,0x3A,0xEC,0xA0,0xEF,0xD4,0xA2,0xD9,0x9B,0x83,0x24, +0x50,0x40,0xA3,0x95,0x92,0x3E,0x14,0x24,0xE6,0xDE,0xB1,0xE2,0x72,0x39,0xFC,0xB0,0x22,0xC8,0x87,0x5F, +0x0D,0x60,0x41,0xE9,0x23,0x8F,0xD1,0x01,0x0A,0x44,0x88,0x25,0xD0,0xA2,0xF6,0xE1,0x88,0x92,0xB7,0x71, +0x4D,0x2C,0xD9,0x11,0x0F,0x45,0x26,0x04,0x70,0xE2,0x7E,0x46,0xDC,0xA9,0x99,0x65,0xB7,0x48,0x77,0x7B, +0x29,0x30,0x93,0x1B,0x70,0x89,0xF5,0xAF,0xEA,0x41,0xB0,0xA9,0x1B,0xD8,0xBB,0x8B,0xBF,0xB2,0x27,0x84, +0x5B,0x79,0xE5,0xDF,0x83,0x96,0x05,0xC7,0x26,0xAD,0x10,0xA7,0x50,0x45,0x15,0x6D,0x77,0xE4,0xAE,0xAE, +0x6A,0x63,0x65,0xC6,0xBE,0x2D,0xEA,0xCF,0x3B,0xF0,0x66,0x3F,0xC3,0x63,0xC2,0xA0,0x21,0x05,0xB0,0xF3, +0x2B,0x05,0xBB,0x6F,0xC8,0x6A,0xCE,0xDF,0xDC,0xE5,0xA3,0x67,0x9C,0x4B,0x35,0xFA,0x3D,0xF5,0x0A,0xAB, +0xCB,0x75,0xA0,0xBB,0xAE,0xE2,0x7C,0x8D,0xF3,0x7C,0xBD,0xEF,0x3F,0x3A,0x73,0x67,0x41,0x08,0xC1,0xCC, +0x33,0x0E,0x5A,0x55,0x8F,0x18,0xB4,0x43,0x64,0xA9,0x2B,0xD1,0xD4,0x09,0x9F,0xBA,0x26,0xE6,0x20,0x48, +0xFD,0x4D,0xD6,0xBC,0x3A,0xDD,0x61,0xD2,0xC9,0x42,0x52,0x2B,0x74,0x72,0x70,0xE9,0x87,0xD2,0xDE,0x61, +0xA8,0x60,0x22,0x7C,0xB2,0x0F,0x4A,0x63,0x0A,0x23,0xFE,0x78,0x0E,0xF1,0xBA,0x2B,0x6D,0xA5,0xB3,0x56, +0xEE,0xE5,0xA8,0x85,0x62,0x21,0xE7,0x26,0x51,0xD2,0x67,0xC3,0x6C,0x6A,0x0A,0x8C,0x6A,0x10,0x59,0x3B, +0xDF,0x74,0xE8,0x13,0x09,0x1A,0xFC,0xA3,0x36,0xFB,0xF1,0xFA,0x9D,0xCC,0xC4,0x00,0x50,0x81,0x74,0xA2, +0x16,0x11,0x4C,0xF9,0xE1,0x37,0x49,0x8C,0xC0,0xAE,0xA4,0x4F,0x98,0xD8,0x12,0xFB,0x68,0x7B,0xF9,0xDA, +0x45,0xCE,0x4F,0x02,0x94,0x10,0x02,0xD6,0x95,0xD3,0x1B,0x4D,0x5E,0x4E,0x85,0x30,0xD2,0x13,0x47,0x6C, +0x95,0x11,0x49,0x4F,0x92,0x7F,0xFF,0x70,0x9C,0xBB,0xBC,0xE3,0x51,0x27,0x94,0x48,0x22,0x59,0xEA,0xBC, +0xD1,0xF4,0x32,0xD6,0x40,0x31,0xB4,0xF3,0x50,0x37,0x25,0x8E,0xC4,0x14,0x5C,0xA9,0x92,0x81,0x14,0x31, +0x23,0xE7,0xBD,0xE2,0xD1,0x35,0xAE,0x11,0xBF,0xA7,0xB5,0x45,0xAE,0x79,0x9E,0xEE,0x27,0xC8,0xB5,0x28, +0xB5,0xC5,0x80,0xEC,0x02,0xE8,0x4B,0x1D,0xAB,0x3A,0x50,0x6A,0xDF,0x6D,0xFE,0xA8,0x30,0x18,0x47,0xD0, +0x6E,0x4B,0x81,0x5F,0xFC,0xF3,0xC1,0x58,0x6B,0x92,0x8E,0x9C,0xC6,0x39,0x25,0x4B,0xCA,0xDC,0x65,0xC7, +0x19,0x6F,0xCC,0xE6,0x27,0xBC,0x83,0x72,0x47,0xC5,0xAB,0x46,0x5C,0x55,0xB3,0x15,0x04,0x3E,0x74,0xA4, +0x42,0x5F,0x70,0x62,0x4E,0xC4,0x8A,0x46,0x00,0x54,0xE0,0xC7,0x9B,0x0F,0x18,0x99,0x2A,0xB8,0x79,0x4E, +0x49,0x89,0x89,0x5B,0x1D,0x29,0xC8,0xD9,0x5B,0x9D,0xFF,0x6C,0xD3,0x2E,0x59,0x2F,0xBF,0xB0,0x20,0xCD, +0x82,0xBC,0x87,0x74,0xDE,0xD6,0xDB,0x9D,0x16,0xFD,0x23,0x33,0xD9,0x3E,0x97,0x10,0x52,0xD3,0xE9,0xD8, +0xD9,0xEE,0x7C,0x71,0xAF,0x46,0x9D,0xDF,0x50,0x5B,0xF3,0x6A,0xB0,0x55,0xA7,0x40,0x1B,0x80,0x65,0xEA, +0x48,0x5C,0xB8,0x0F,0x54,0xAB,0xA0,0x7B,0xC6,0xFC,0xCF,0x5D,0xD9,0x46,0x41,0xF9,0xFA,0x0A,0x92,0xF4, +0x31,0xA7,0xA8,0x6B,0x61,0x1D,0x27,0x50,0x36,0xE0,0x8D,0x86,0x51,0xE0,0xB2,0x85,0x95,0xC1,0x11,0xCB, +0x81,0x80,0x30,0xE7,0x9A,0xA0,0xE6,0x2B,0x83,0x90,0x21,0xD2,0x34,0x29,0x86,0x6D,0xA6,0x86,0xAE,0xB3, +0xA8,0x2C,0x03,0x82,0x0E,0xC5,0x5E,0xC3,0xED,0x2F,0xC4,0x00,0xF9,0x86,0xB5,0x00,0x97,0x87,0x57,0x0D, +0x23,0x51,0xD2,0xE6,0xA3,0x0A,0xCC,0x1D,0x41,0xD6,0x88,0x99,0xAF,0x8C,0xCA,0x39,0x53,0x7A,0xBB,0x7A, +0x7D,0xE2,0x20,0x9C,0x73,0xC9,0x25,0xB7,0x57,0x6E,0xBB,0x4C,0xE9,0x2A,0x4D,0x2C,0x34,0x57,0x1C,0xF7, +0x9B,0x5A,0x4E,0x7B,0xD1,0x5C,0x39,0x8E,0x3E,0xE5,0x4D,0xEC,0x9E,0xE0,0xA1,0xAE,0x76,0x09,0x72,0x53, +0xF9,0x45,0xF8,0x3E,0xD4,0x74,0xCA,0x5A,0x6C,0x24,0xA9,0xBE,0x7F,0xE0,0x7A,0x43,0xBA,0x59,0x5C,0x65, +0x8A,0xB9,0x7F,0xFF,0x94,0xA5,0x0B,0xD4,0xAF,0xE2,0x32,0x16,0xBC,0xEB,0x04,0x21,0xAC,0x16,0xD3,0x9D, +0x98,0x92,0x03,0xC0,0xCB,0x70,0x9B,0x58,0xF9,0xE8,0xFE,0x51,0xAD,0x09,0xC2,0x85,0x3A,0xAA,0x4A,0x84, +0xE2,0xC1,0xD8,0x1C,0xB5,0xE6,0x12,0xFF,0xF8,0x70,0x92,0x79,0x7C,0x8E,0xC3,0x98,0xE3,0xB0,0x4D,0x72, +0x59,0x56,0x75,0x29,0x71,0x23,0xC7,0x0F,0xFD,0x9D,0x8E,0xEF,0xF4,0x5E,0x46,0x0A,0x26,0xBE,0x79,0xDB, +0x64,0xBC,0x93,0x78,0xFC,0x0C,0x03,0x8B,0x25,0x7E,0x93,0xFD,0xFD,0xDF,0x7E,0x3D,0x52,0x3F,0xA0,0x86, +0xCB,0x4F,0xE5,0x5C,0x40,0x9C,0xCF,0x4B,0x26,0xB2,0xAB,0x2D,0x25,0xB1,0x53,0x69,0x35,0x4E,0x2E,0xF4, +0x49,0x93,0x04,0x04,0x65,0x91,0x81,0xF8,0x07,0xE2,0xA5,0x86,0xB4,0x4D,0x25,0xE5,0x8C,0x9E,0x6B,0xE7, +0xC7,0x7E,0xAE,0x91,0x40,0x03,0x52,0x97,0x4A,0xB3,0xE8,0xB0,0xD6,0x86,0x55,0x8A,0xD1,0xE8,0x91,0x05, +0x24,0x61,0x5F,0x24,0xCB,0xBF,0x30,0x12,0xE2,0x75,0x47,0x04,0xF6,0xC4,0xCF,0x44,0xFB,0x73,0x7B,0x52, +0x64,0x39,0x7A,0xCD,0x0B,0x97,0xFB,0x0B,0xF7,0x2E,0x61,0x84,0x27,0x98,0x5C,0xE3,0x94,0xB5,0xE3,0x09, +0x43,0xDF,0xCB,0xD2,0x14,0xD6,0x33,0x40,0xA3,0x3C,0x2D,0xBE,0x75,0xF5,0xA6,0x6A,0xAF,0x36,0x7D,0x73, +0xC0,0x55,0x06,0xD1,0x08,0x9E,0xA6,0x6F,0x3B,0x93,0xCC,0x42,0xF9,0x53,0x9C,0xC8,0x3C,0xB7,0xEB,0x5D, +0x1E,0x6F,0x34,0x9E,0x3D,0xB9,0x77,0x5C,0x8C,0xC2,0x1A,0xD1,0x05,0x06,0x0A,0x8E,0x0D,0x91,0x6D,0x6E, +0xE7,0x91,0xB7,0x4D,0xFC,0x51,0x27,0xB0,0x78,0x2E,0xEF,0xBB,0xA1,0x91,0x29,0x9F,0xBD,0xBB,0x0F,0x4D, +0xDE,0x6F,0x85,0x07,0x0A,0x95,0x04,0xCE,0xCF,0x33,0xB4,0x9A,0x38,0xD6,0x56,0x80,0x5D,0x7A,0x96,0xAE, +0x90,0x77,0x58,0xD6,0xC4,0x18,0x16,0x36,0xFA,0xF0,0x66,0xEB,0x86,0x64,0xC0,0xCB,0xD8,0xBC,0xD5,0x38, +0x42,0x35,0x26,0xBD,0x8D,0x8B,0xAD,0x14,0x07,0x64,0xF3,0x0D,0xCD,0x4E,0xC7,0x51,0x7F,0x0B,0x10,0xEF, +0x40,0xF9,0xD3,0x7E,0x08,0x9E,0x13,0x7F,0x03,0xDF,0xAC,0x42,0x83,0xAB,0x4C,0xE6,0xAD,0xAC,0x15,0xD3, +0xC4,0xCD,0x4F,0xA4,0x23,0x64,0x56,0x83,0x1D,0x8C,0x87,0xEA,0xF8,0xD9,0xE7,0xC9,0x45,0x01,0x58,0xC1, +0x50,0x9A,0xE3,0x01,0x58,0xE4,0x55,0xA0,0xD3,0x2E,0xC0,0xD2,0x4C,0x4F,0xCE,0x70,0xEF,0x55,0x77,0x83, +0x55,0xC6,0xA3,0xB0,0xD2,0x2E,0x46,0x21,0x43,0x40,0x99,0xC9,0x70,0x21,0xC4,0xB8,0x02,0x46,0x3B,0xA6, +0xB3,0xAC,0x8F,0x3D,0x7D,0xB4,0xD4,0x86,0x70,0x9B,0xAF,0xAF,0xE2,0xD3,0x82,0xAF,0xB0,0x28,0x83,0x3E, +0x3C,0xE9,0xE0,0x54,0xF2,0x5A,0x99,0x20,0x0F,0x8B,0x41,0xA7,0xB6,0x2B,0x2E,0xE5,0xB9,0x73,0xAE,0xE7, +0xD3,0x99,0x29,0x53,0xE5,0x08,0xC3,0x54,0x30,0x66,0x84,0x6C,0x22,0xF8,0x49,0x07,0x28,0xEC,0xA5,0x3F, +0x63,0xAD,0x09,0xF7,0xD0,0x02,0xD5,0x4A,0x09,0x08,0xCC,0x79,0x2F,0x1D,0xA2,0x92,0x9D,0x9D,0x54,0x69, +0x66,0xD6,0x40,0x39,0xEA,0x4F,0xC5,0x3C,0x2A,0x64,0x87,0xF8,0x68,0x2A,0x4D,0x22,0x9B,0x6A,0x6B,0xAB, +0xEA,0xF8,0x4C,0xAD,0xE7,0x3D,0xAE,0x02,0xE2,0x7F,0xB1,0xE3,0x62,0x30,0x4B,0xA4,0x68,0xC3,0x1B,0x44, +0x02,0x9F,0xF6,0x37,0xA9,0xD7,0xA2,0x0C,0x34,0x23,0x92,0x91,0xF2,0x97,0xE9,0x55,0x5C,0x86,0x6A,0xA1, +0x29,0x76,0x5A,0xDE,0x9B,0x25,0xDD,0x0A,0xB0,0x0D,0x5C,0x4E,0xAF,0x62,0x63,0xB4,0xB8,0x95,0xA3,0x0C, +0x1E,0x23,0xF8,0x94,0x9D,0x35,0x57,0x0F,0xB1,0x61,0x4A,0x5D,0xE4,0x07,0xF3,0xAF,0xBA,0xFF,0x04,0x52, +0x36,0xCD,0x82,0x78,0x0E,0x03,0xB6,0x9F,0xCC,0xBB,0x83,0x86,0xE3,0xCC,0x6B,0x00,0x54,0x90,0xE2,0x95, +0x5E,0x32,0x0E,0xD6,0xB3,0x45,0x5E,0x8B,0x5F,0x7F,0x0B,0x4B,0xE3,0xFD,0xE4,0x90,0xF3,0xBD,0x33,0x87, +0xCB,0x97,0x3E,0xDA,0x94,0xE6,0x75,0xF2,0x5E,0x5F,0xC4,0xB5,0x19,0xEB,0x2E,0x9E,0x79,0xB8,0xFB,0xD3, +0x17,0x71,0xE8,0xD3,0x99,0xCC,0x29,0xD7,0x90,0x53,0x2C,0x02,0xA6,0x1A,0x67,0x79,0xEE,0x3C,0xBB,0xE4, +0x5D,0x56,0x05,0x6F,0x41,0xE8,0x74,0x74,0xFF,0xD6,0x71,0xB4,0x2D,0x47,0xEB,0xFD,0x82,0x8A,0x09,0xFE, +0x75,0x85,0xE1,0x03,0x01,0x18,0xE6,0x84,0x6A,0x7E,0x95,0x18,0x8A,0x17,0x15,0x49,0x68,0x34,0x8D,0xA5, +0x19,0xE3,0xF3,0x91,0x8F,0x98,0x07,0x53,0x97,0x15,0x6D,0xF5,0xF3,0x77,0xA3,0x10,0xAF,0x0E,0xD9,0x56, +0xBD,0x1F,0x29,0xEF,0xBA,0x52,0xCE,0x88,0x93,0x99,0x0E,0x5A,0xAA,0x5F,0xCC,0xEE,0xC6,0x7B,0x19,0x48, +0x69,0x28,0xD7,0x7C,0x63,0xF2,0x57,0x17,0x53,0xE1,0x58,0xAD,0xBE,0x7A,0xD5,0xE6,0x11,0x26,0xA9,0x98, +0x75,0xDC,0xB8,0xBD,0x34,0xE6,0x0F,0x0D,0x45,0xF8,0x61,0xBF,0x08,0xD8,0x3F,0x8C,0x95,0x64,0x90,0xB7, +0x55,0x1C,0x66,0xBE,0x50,0x14,0x9C,0x27,0x97,0x53,0xD6,0x9E,0x49,0x19,0x17,0x40,0x8E,0xBC,0xF0,0x9C, +0x07,0x92,0x94,0x0F,0x8A,0x52,0x4E,0x7E,0x59,0x8F,0xBC,0x69,0xB6,0x6C,0xB9,0xCA,0x1B,0xC1,0x0D,0x0A, +0x9E,0x1C,0x2D,0x05,0x5B,0x31,0x9D,0x26,0xAD,0xD6,0x6F,0xAF,0xD1,0xCC,0x05,0xE4,0x97,0xA0,0xE7,0x2D, +0x0C,0x70,0x61,0xC4,0x96,0x83,0x43,0x70,0xE7,0x1D,0x34,0xC0,0xC6,0xC3,0x64,0xA2,0x55,0xE0,0x40,0xD0, +0x83,0x74,0xF1,0x98,0xF0,0x18,0xB0,0xE6,0x26,0xA1,0xE2,0x45,0x2C,0xEE,0xC2,0xF8,0xFB,0x82,0x0D,0x9D, +0x97,0xD0,0xF2,0x51,0x67,0xC4,0x8F,0x82,0xD2,0xF1,0xB9,0xD4,0x87,0x76,0xB1,0x93,0xF6,0x8C,0x41,0x41, +0x3A,0x81,0x0D,0x44,0xA0,0xEC,0x48,0x20,0x87,0x8B,0x20,0x86,0x16,0xA2,0x68,0xE2,0x04,0xCD,0x34,0x38, +0x58,0xFA,0x40,0x90,0x6C,0x8B,0x59,0x36,0x1B,0x2E,0x3A,0x12,0x5D,0x44,0xEF,0xF2,0x18,0x85,0x49,0x44, +0x07,0xC2,0xC1,0x07,0x37,0x2F,0xB5,0xF3,0xE7,0xF4,0x8C,0x98,0xB5,0x7B,0x28,0xD7,0x87,0xD7,0x16,0xB5, +0x15,0x83,0x7B,0x93,0xD5,0x87,0x46,0x95,0x8F,0x50,0x26,0x4D,0x8D,0x86,0xB5,0x8A,0x5B,0x47,0x69,0x97, +0x3B,0x64,0x8C,0x8B,0x5A,0xFB,0x20,0x12,0xE6,0x2F,0xE2,0x0A,0xC0,0x34,0x00,0xC1,0x49,0x72,0x84,0x43, +0xFE,0x8C,0x1C,0x59,0xCF,0x85,0x9B,0xF5,0x11,0x5C,0xEC,0x53,0xF3,0x42,0xCA,0xAB,0x80,0x77,0x75,0x80, +0x9D,0x5F,0x04,0x41,0x64,0x77,0x0E,0x49,0x32,0x14,0x85,0xDF,0x7E,0x60,0xA2,0xB6,0x16,0x8A,0xE2,0x2C, +0xFC,0x8C,0x2A,0x0D,0x6E,0xCD,0x10,0xB5,0x7A,0x37,0x0A,0x1B,0x83,0x80,0xFA,0x29,0x3C,0xCD,0x2A,0x5A, +0x1F,0x8F,0x70,0x27,0x59,0xBE,0x6B,0xEC,0x6F,0x81,0x62,0x3D,0x3D,0xEC,0xB3,0x6F,0xF1,0x04,0xD7,0x92, +0x5F,0xAC,0x61,0x5A,0x2C,0x81,0x2B,0x3F,0xB4,0xEE,0x3A,0x7B,0xCB,0xF6,0x98,0x97,0x48,0xAD,0x89,0xCC, +0xD1,0xCC,0x64,0x82,0x76,0x45,0x1D,0x51,0xE8,0xDD,0x0C,0xC6,0x2C,0x05,0x3E,0x6D,0xDA,0x1C,0x04,0x34, +0xB2,0x96,0xC7,0xB0,0x8C,0x90,0x7C,0x5E,0x75,0x04,0x1B,0x8A,0x85,0x50,0x73,0x03,0xB0,0x30,0xA2,0x5C, +0x05,0x01,0x23,0x23,0x87,0x84,0x7F,0x6C,0x52,0xEE,0x6D,0x7B,0x97,0xF1,0x5D,0xEC,0x46,0x58,0x2B,0xB3, +0x9E,0x05,0x11,0x99,0xDB,0x28,0x9A,0xC1,0xCB,0xBB,0xF7,0x5C,0x72,0xC9,0x94,0xA2,0x31,0x79,0x91,0xBD, +0xD8,0xFB,0x43,0x39,0xCA,0xBA,0xA1,0x64,0x50,0xD5,0xC4,0x26,0x8C,0xFA,0x5A,0x3D,0x4F,0x75,0xC5,0xA1, +0x92,0xB0,0xAE,0xB5,0x99,0x4B,0x8D,0x65,0xD4,0x04,0x0A,0x93,0xE7,0xEA,0x8D,0x88,0x00,0x0A,0x47,0x08, +0xE3,0xBC,0x9D,0x57,0xAD,0x7A,0xB1,0x79,0xA8,0xC5,0xF9,0xE4,0x18,0x03,0x32,0x48,0xEE,0x24,0xB0,0x9B, +0xFC,0xF5,0xD1,0xE8,0xD6,0xDB,0xD4,0x8E,0xBF,0xBD,0x5E,0xE5,0x8A,0x74,0xE4,0x90,0xDE,0x22,0xF4,0x78, +0x20,0x97,0xD6,0x0B,0x9C,0x87,0x4D,0x5B,0x3F,0xD5,0x27,0x2D,0x7C,0x79,0x70,0x8B,0x10,0x3A,0x50,0x7D, +0xCA,0xCE,0xF7,0x59,0x41,0x76,0x9F,0x42,0xDF,0x40,0x9D,0xB1,0xD1,0xDD,0x9E,0x4C,0xE3,0x83,0x0D,0x08, +0xEC,0x94,0x8E,0x6C,0xFE,0x45,0x16,0x29,0x30,0x86,0x97,0xAD,0x70,0xB2,0x06,0x98,0x2C,0x62,0xAE,0x73, +0xDC,0xBD,0x5D,0x49,0x37,0xFE,0x5A,0x2D,0x3C,0x42,0xBB,0x89,0xAD,0x01,0xCF,0x3F,0xA2,0xF8,0x5A,0x3D, +0xD8,0x43,0x8F,0x9F,0x02,0x34,0x07,0xDF,0x4E,0x55,0xA4,0x18,0xFF,0xFF,0x3E,0xDC,0x21,0x40,0x59,0xAB, +0x2B,0x30,0xFA,0x20,0x40,0x08,0xDC,0xCC,0x40,0x2D,0x4A,0xEF,0xE8,0xFB,0xCA,0x96,0x33,0xE3,0x14,0x66, +0xCE,0x41,0xE6,0xF1,0x75,0xEA,0x47,0xDD,0x69,0x6B,0xD8,0x05,0x96,0xBB,0xBB,0xF3,0xC0,0x42,0xEF,0xE1, +0xC0,0x2F,0xA5,0x8E,0x82,0x43,0xB3,0xF7,0x3D,0xDE,0x35,0x90,0xC1,0x01,0xF5,0x08,0x3A,0x27,0x48,0xE6, +0xA3,0x8C,0xC1,0xB2,0x21,0xAA,0xA5,0x12,0xE1,0x42,0x98,0x86,0x76,0x26,0xCF,0x00,0xA3,0x0A,0xFE,0xA2, +0x96,0x34,0xA3,0x92,0xE2,0xCF,0x03,0xDB,0x55,0x3D,0x45,0xA3,0x23,0x8C,0x39,0x4D,0x35,0x3D,0x59,0xCF, +0x63,0xCC,0x0C,0xD8,0xAD,0x64,0x29,0x11,0x21,0xDA,0x88,0xA1,0xB5,0x66,0xDE,0x93,0x41,0x4F,0xAA,0xF1, +0xD6,0x54,0x04,0xD5,0xE1,0x01,0xFA,0x28,0x9A,0x0C,0xCF,0x17,0x7B,0x8C,0xA8,0x9C,0xC1,0xC7,0x34,0x7C, +0x4B,0xF6,0xF2,0x98,0x6A,0x1D,0x65,0x7F,0xB4,0xFF,0x72,0x01,0xB2,0x2D,0x1B,0x0D,0xC2,0x03,0x08,0x6F, +0xD9,0x2E,0xA9,0xD3,0xD8,0x87,0x37,0x4F,0x2F,0xE1,0x35,0x78,0x04,0xFD,0xEB,0x1E,0xCC,0x26,0x64,0x47, +0x1B,0xD4,0xA1,0x8D,0x40,0xC4,0x3A,0x6F,0xF7,0x03,0x02,0xE1,0x26,0x26,0x23,0x16,0xE9,0x29,0x82,0xE9, +0x56,0x2E,0x70,0xBA,0x89,0x05,0x62,0x78,0x9E,0x0C,0x87,0x47,0x78,0x89,0x0C,0x0F,0x76,0xEC,0xD3,0xCB, +0x8B,0xE9,0x47,0xC9,0xA4,0x18,0xEC,0x8B,0xEE,0x0C,0x90,0x1A,0xDE,0x34,0xB9,0x3B,0xC8,0xD0,0x0B,0xF0, +0xDC,0x6D,0xE0,0x8F,0xDB,0xB2,0x20,0x4C,0x7A,0x9B,0x0C,0x90,0xDD,0xA6,0x82,0xBB,0x5C,0x72,0x76,0x30, +0x61,0xC0,0x6B,0x80,0x54,0x1E,0x9C,0x6C,0x29,0x9A,0xB2,0xA1,0xBC,0xB7,0x16,0xB1,0xC2,0x10,0xB4,0x76, +0x8C,0xFB,0xFA,0xA5,0xDF,0x12,0x48,0xCE,0xF8,0xD3,0x75,0xE0,0x6C,0x5F,0xD5,0x9A,0xF8,0x1E,0x30,0xAD, +0x4A,0x57,0x0A,0xD5,0x58,0x72,0x27,0x59,0x05,0x1C,0x19,0xD5,0xED,0xF8,0x34,0xE6,0xC0,0x52,0x89,0xC6, +0x59,0x6E,0xF0,0x9F,0xC1,0x84,0x47,0xDB,0x0E,0x35,0xD9,0xA6,0x07,0x57,0x13,0x32,0x23,0xBE,0x3C,0xB1, +0x9A,0x58,0xCB,0x07,0xF7,0xF8,0xD0,0x87,0x00,0x17,0xC5,0x2D,0xCF,0xBD,0xA6,0x61,0x5F,0x17,0xEF,0x1F, +0xA8,0x8B,0x98,0x57,0xC8,0xE6,0x32,0x33,0x52,0x2C,0x17,0x0F,0x40,0x32,0x0E,0x06,0x7F,0x7A,0x3C,0x38, +0xE1,0xB7,0xBC,0x76,0xC9,0x54,0x86,0x58,0x61,0xA9,0x12,0x91,0x87,0xF5,0xA2,0x03,0x28,0x99,0xD4,0x51, +0x49,0x7B,0xE5,0x48,0xCD,0xA8,0xE5,0xE3,0xFA,0x77,0xA3,0xEB,0x53,0xE7,0xE1,0x45,0xBB,0xF8,0xD7,0x01, +0xC1,0x57,0x44,0x53,0x25,0xF0,0x8C,0x27,0xED,0x66,0xDE,0x8D,0x18,0xC4,0xDF,0x10,0x8D,0x86,0x7F,0x82, +0xDD,0x77,0x62,0x39,0x08,0x10,0x4D,0x2A,0x09,0x14,0x6E,0x38,0x9D,0x53,0xC5,0x16,0x83,0x77,0x68,0xA9, +0x62,0xB9,0x4C,0x58,0x40,0x74,0x3E,0xB9,0x9E,0x50,0x4E,0x14,0xAB,0xB0,0x18,0x49,0xD9,0x69,0x3F,0xE9, +0x89,0x6B,0xE3,0x19,0xB6,0x51,0xAB,0xB2,0x0B,0x82,0xD5,0x8D,0x57,0x1C,0x96,0xF3,0x5E,0x51,0x55,0xFD, +0x48,0x1E,0x73,0x6F,0xAD,0x75,0x68,0x06,0x4C,0xA9,0xB8,0x1E,0xFD,0x30,0x9C,0x59,0x86,0x8E,0x14,0x44, +0xD9,0x36,0x17,0x3F,0xBA,0x0C,0xAE,0x92,0x62,0x91,0x82,0xBA,0xB0,0x0E,0x33,0xD6,0x1D,0x11,0xB1,0x70, +0x90,0xFD,0x4D,0x95,0xF5,0xA8,0x0A,0xB1,0xC4,0xCA,0xB3,0xD8,0xF0,0x1F,0xFD,0xFD,0x78,0xEF,0x89,0x69, +0x91,0xD8,0x38,0x4C,0x22,0x82,0x4E,0x37,0xDD,0x33,0x18,0x20,0x45,0x74,0x7E,0x36,0x10,0x3F,0x8A,0xE6, +0x6E,0x30,0x88,0x54,0x36,0xE4,0x60,0xE0,0xF2,0x8A,0x28,0x27,0x4A,0xE9,0xFC,0x76,0x70,0xD9,0x80,0x88, +0x68,0xC5,0x6B,0x03,0x25,0x80,0x16,0x43,0xD1,0x77,0x69,0x66,0x38,0xA6,0x0E,0x14,0x75,0x65,0xDD,0x2C, +0x24,0xC6,0xE8,0x25,0xA4,0x81,0xB9,0x8A,0x86,0x86,0x79,0x76,0x12,0x89,0xC7,0x64,0x6D,0x8C,0xB3,0x7C, +0xF7,0x49,0xF2,0x0A,0xA1,0xC1,0x8D,0x76,0x7F,0x48,0x22,0x1F,0xF1,0xD9,0x6A,0xB6,0x5D,0xA4,0xC5,0xD2, +0xA9,0x84,0xB9,0xBA,0x0D,0x9E,0x5A,0xFB,0x0C,0x9C,0xF9,0x33,0xF4,0x4B,0xF5,0xC3,0x34,0x87,0xB4,0x94, +0xDC,0xCA,0xBB,0x64,0x00,0x3D,0x47,0x8D,0x95,0xA3,0xAC,0xDD,0x68,0xA5,0x00,0x5F,0xD1,0x10,0xCA,0xE9, +0x71,0x2C,0x18,0x08,0x46,0xE0,0x48,0x94,0xBB,0x4D,0xB2,0x51,0x56,0x80,0xEC,0x9C,0xAD,0xC1,0x8D,0xA8, +0x9A,0xAD,0xAA,0x80,0xB6,0x44,0x84,0x42,0x97,0x13,0xA3,0x4F,0xCC,0x75,0x61,0xBC,0x86,0xB5,0x60,0x90, +0x2F,0x4D,0x93,0x2F,0x3A,0xE3,0x1B,0x84,0x38,0xC1,0x03,0x5B,0xBB,0x04,0xFF,0x88,0x4B,0x5B,0x6C,0xF9, +0x23,0x3A,0x7E,0xB6,0x50,0x3F,0xDE,0xE6,0x24,0x0C,0x4C,0x52,0x3B,0x21,0x8C,0xE4,0xD7,0xFC,0x52,0x95, +0x84,0x6E,0x4A,0x87,0x2A,0x21,0xC7,0x42,0xCF,0x20,0xD4,0x47,0xF6,0xF3,0x85,0xF1,0xC6,0x5E,0x9E,0xDC, +0xB2,0xF9,0xF5,0x0B,0x95,0xDF,0x11,0xE5,0x70,0xFE,0xBD,0xD0,0xB5,0xBF,0x8D,0xE5,0x91,0xF6,0xFD,0x1A, +0x91,0x0E,0x7D,0xFF,0x0C,0xFD,0xD7,0xFF,0x22,0xCD,0x86,0xCE,0x37,0xA4,0xD9,0x9D,0xFB,0xCF,0xF7,0x0E, +0xA6,0x39,0x3C,0xDA,0x3F,0x1E,0x32,0x71,0xB0,0xB4,0xC1,0xC3,0xC6,0x74,0x47,0x14,0xDB,0x08,0x90,0x41, +0x84,0x84,0x25,0x8F,0xB6,0xF4,0xBE,0x67,0xBA,0x1C,0x77,0x63,0x8D,0x9C,0x58,0x31,0x0B,0x1C,0x7D,0x55, +0xB6,0x52,0x45,0xC3,0x2F,0x95,0x85,0xD3,0xD7,0x76,0xA0,0xC9,0xA8,0xBC,0xA7,0x29,0xDD,0xDB,0x4E,0x8E, +0x8D,0x47,0xDE,0x6C,0xF8,0xF6,0x02,0x16,0xA4,0xBB,0xF7,0x8A,0x98,0x16,0xA8,0x51,0xDE,0x9B,0x86,0x1A, +0xFF,0xF1,0x28,0x8B,0x25,0x58,0x5A,0x7E,0xE1,0xBA,0x48,0x46,0xEE,0x81,0x13,0x6D,0x5F,0xF4,0x03,0x0E, +0xA8,0x57,0xE7,0x97,0x18,0x14,0x38,0xC1,0xD2,0x6A,0x4B,0xCD,0x5E,0xFD,0x56,0x28,0xAE,0x7C,0xDE,0x30, +0xBC,0xB4,0x62,0x53,0x68,0x2C,0xB6,0x29,0x4D,0x80,0x34,0xFA,0x8C,0xDA,0x42,0x41,0x3E,0xDD,0x44,0x09, +0x5C,0xC6,0x46,0x8E,0xFF,0x7B,0x3D,0xE0,0x0D,0xFB,0x51,0xAD,0x33,0x68,0xD6,0xFA,0x8F,0x9F,0x4F,0x7D, +0x8E,0xEC,0x6E,0xFF,0x2D,0x97,0x03,0xDD,0xB7,0xD3,0x4B,0x0D,0x6A,0x1E,0xDB,0xBF,0xFB,0x91,0x90,0x47, +0x24,0x6E,0xCE,0xD5,0x5B,0x61,0xC9,0x6A,0xBE,0x60,0xF4,0x52,0xA7,0xCD,0x20,0xD2,0xFC,0x02,0xB2,0x29, +0xEE,0xAC,0x88,0xB4,0x72,0xB5,0xE7,0xB0,0x62,0xC0,0x41,0x3E,0x88,0x6E,0x2E,0x75,0x9C,0xDE,0x95,0xA5, +0xBB,0xCA,0x10,0x3B,0x73,0xE7,0x31,0x00,0xDD,0xF4,0xDB,0xB1,0x4D,0x67,0xD9,0x10,0x1D,0x4A,0x09,0xB7, +0xD4,0x27,0x4E,0x99,0x7D,0xCF,0x3F,0xBB,0xED,0xDB,0xAF,0x9F,0xBD,0xBB,0x2F,0x9B,0xAD,0x9B,0x93,0xD2, +0x02,0x62,0x37,0xAB,0xEC,0xDA,0xA7,0x8F,0xBC,0xBA,0x27,0x8B,0xAC,0x9A,0x9A,0x45,0x86,0x5D,0x3E,0xBA, +0x6D,0xD9,0xAE,0x9E,0x3D,0xB9,0x2E,0x9A,0x2D,0x99,0x71,0xAE,0x62,0x08,0x36,0xAA,0x6C,0xD8,0xA6,0x8E, +0x3C,0xB8,0x26,0x8A,0x2C,0x98,0x02,0x09,0x5C,0x06,0xFC,0x0B,0xE1,0x27,0x96,0x97,0x44,0x28,0xA8,0xCE, +0xDA,0x2B,0x30,0xE7,0x6A,0x26,0xD0,0x19,0xBA,0x6B,0xC3,0x72,0x6D,0xB4,0x1A,0xC4,0xF6,0x94,0x6B,0x8F, +0x74,0x4B,0x13,0x8F,0x9D,0xD0,0x93,0xD0,0x89,0x08,0x1B,0xCF,0x74,0x65,0x9C,0x9D,0xCE,0xE4,0x93,0x1D, +0x1B,0x63,0x0D,0x5B,0xA1,0x46,0x77,0xA6,0xD8,0xEB,0xFD,0xAA,0x2E,0x4E,0x3D,0xB3,0xE5,0xD3,0xAD,0x97, +0xB5,0xB3,0x2D,0x93,0xA5,0x93,0xCE,0xDC,0x30,0x4F,0x35,0xA3,0xE4,0xD2,0xA5,0x87,0xB4,0xB2,0x25,0x83, +0xA4,0x92,0x13,0x49,0xAA,0x9E,0x3C,0xB2,0x65,0xD1,0xAC,0x96,0x35,0xB1,0x2C,0x92,0x25,0x91,0xDB,0x46, +0xAD,0x4D,0x34,0xA2,0x64,0xD0,0xA4,0x86,0x34,0xB0,0x24,0x82,0x24,0x90,0xBB,0xDE,0xC1,0x8F,0xDE,0x85, +0x93,0x71,0x28,0xC6,0xD7,0x40,0x20,0xC6,0x8F,0x31,0xB7,0xCB,0x27,0xAA,0xC6,0x6F,0x92,0x37,0x47,0x9F, +0x1E,0x4C,0xE4,0xBB,0x3E,0x0A,0xAA,0xFB,0x7D,0xAE,0xE5,0xC4,0x45,0x3F,0xAD,0x4E,0x9B,0x50,0xF5,0xFA, +0x13,0xFF,0x0F,0x89,0x53,0x62,0x81,0xEE,0x10,0xBB,0xC6,0x03,0xE5,0x8A,0x99,0xB1,0x9E,0x9A,0xBB,0x3F, +0xDD,0xEB,0x3B,0x3B,0xCD,0xCB,0xAB,0x1F,0x9D,0xAB,0x2B,0x1B,0x8D,0x8B,0xB3,0x2F,0xDC,0xEA,0x33,0x2B, +0xCC,0xCA,0xA3,0x0F,0x9C,0xAA,0x23,0x0B,0x8C,0x8A,0xBA,0x3E,0x5D,0xE9,0x3A,0x3A,0x4D,0xC9,0xAA,0x1E, +0x1D,0xA9,0x2A,0x1A,0x0D,0x89,0xB2,0x2E,0x5C,0xE8,0x32,0x2A,0x4C,0xC8,0xA2,0x0E,0x1C,0xA8,0x22,0x0A, +0x0C,0x88,0xFA,0xAC,0xA5,0xE5,0x82,0x6E,0x1C,0x93,0x78,0x6F,0x6A,0xAD,0xF6,0xF3,0x9B,0xF3,0xF5,0x38, +0xC4,0x09,0x9F,0x6F,0xBD,0x94,0x1E,0x49,0xA5,0x79,0x50,0xB8,0x16,0x90,0x60,0x76,0x5D,0x8C,0xFF,0x89, +0x58,0xBB,0x13,0xEE,0x69,0x54,0x93,0x4F,0x30,0x70,0xA3,0xEB,0x77,0xE4,0xF7,0x2D,0x0F,0x94,0x1F,0x7B, +0x6A,0x1D,0x37,0x1E,0x86,0xBB,0xB9,0x37,0xD5,0xE3,0x39,0x33,0xC5,0xC3,0xA9,0x17,0x95,0xA3,0x29,0x13, +0x85,0x83,0xB1,0x27,0xD4,0xE2,0x31,0x23,0xC4,0xC2,0xA1,0x07,0x94,0xA2,0x21,0x03,0x84,0x82,0xB8,0x36, +0x55,0xE1,0x38,0x32,0x45,0xC1,0xA8,0x16,0x15,0xA1,0x28,0x12,0x05,0x81,0xB0,0x26,0x54,0xE0,0x30,0x22, +0x44,0xC0,0xA0,0x06,0x14,0xA0,0x20,0x02,0x04,0x80,0x18,0xFC,0x89,0xE2,0x04,0xF6,0x54,0xAF,0x22,0x31, +0xAF,0x84,0x0F,0xBD,0xAB,0xA1,0x54,0x16,0x6A,0x35,0xD0,0x92,0x7E,0x49,0x28,0x11,0x41,0x31,0x28,0x29, +0xD1,0x35,0x59,0x1E,0x7A,0xD2,0x31,0xFA,0x94,0x79,0x0B,0x93,0x51,0x80,0x1D,0x5C,0x0A,0x1D,0xE9,0xFF, +0xEC,0x2E,0x93,0xFF,0x71,0x6C,0xE2,0x66,0x98,0x3B,0x1D,0x58,0xF4,0x23,0x3B,0xCD,0xFA,0xC7,0x1F,0xB9, +0xE9,0x5B,0x8F,0x9D,0xB9,0x3B,0x0F,0x99,0xA9,0x1B,0xFF,0x15,0x64,0x95,0x17,0xA9,0xE8,0x5A,0x87,0x8D, +0xB8,0x3A,0x07,0x89,0xA8,0x1A,0xE1,0xB2,0x58,0xCA,0x1E,0xB8,0x69,0x59,0x8E,0x9C,0x39,0x39,0x0E,0x98, +0x29,0x19,0x8E,0xBB,0x46,0xC8,0x16,0xA8,0x68,0x58,0x86,0x8C,0x38,0x38,0x06,0x88,0x28,0x18,0x27,0xEA, +0x10,0x2A,0xA3,0xF8,0x99,0x5A,0x38,0x63,0x5F,0x32,0x77,0x55,0xFF,0x8D,0xEA,0xE3,0xD5,0xCB,0x90,0xFC, +0x3F,0x56,0x6A,0xE7,0x67,0xCA,0x99,0xAA,0xB8,0xAB,0x26,0x8F,0xEF,0x5E,0x33,0x8D,0xBE,0xCA,0xBD,0xFB, +0xF6,0xC9,0x93,0xD8,0xF8,0xF1,0xE0,0x23,0xA9,0x57,0xD4,0x9D,0xBF,0xCB,0xEF,0x9B,0xCD,0xD0,0xE4,0xFA, +0x7C,0x34,0xF2,0xEA,0x1A,0x2C,0x1D,0xB1,0xE1,0x53,0x8D,0x95,0xB1,0x33,0x0D,0x91,0xA1,0x13,0xEB,0x7E, +0xF0,0x72,0x15,0xA1,0xE0,0x52,0x85,0x85,0xB0,0x32,0x05,0x81,0xA0,0x12,0xA3,0xDF,0xA4,0xC2,0x1C,0xB0, +0x61,0x51,0x8C,0x94,0x31,0x31,0x0C,0x90,0x21,0x11,0x94,0xA4,0x70,0x70,0x14,0xA0,0x60,0x50,0x84,0x84, +0x30,0x30,0x04,0x80,0x20,0x10,0x1E,0x1C,0xD3,0xD1,0x00,0xA2,0x47,0x94,0x83,0x86,0xE9,0xEB,0x74,0xA2, +0x36,0xBC,0x4E,0x83,0x26,0xF1,0x1D,0xE7,0x4A,0xA7,0xDE,0x22,0xAD,0x81,0x14,0x15,0x0A,0x71,0xB5,0xF0, +0xB0,0xFE,0xFA,0xC5,0x08,0x7B,0xD1,0xD4,0xD7,0xF4,0xC5,0x61,0x5E,0xB3,0x17,0x91,0xE1,0x3E,0x76,0x98, +0xB1,0x6A,0x45,0x81,0x1E,0x91,0x7D,0xB3,0xB7,0xBF,0x9B,0x3D,0xD9,0x6B,0x1B,0x39,0xC9,0x4B,0x8B,0x1D, +0x99,0x2B,0x0B,0x19,0x89,0x0B,0x93,0x2D,0xD8,0x6A,0x13,0x29,0xC8,0x4A,0x83,0x0D,0x98,0x2A,0x03,0x09, +0x88,0x0A,0x9A,0x3C,0x59,0x69,0x1A,0x38,0x49,0x49,0x8A,0x1C,0x19,0x29,0x0A,0x18,0x09,0x09,0x92,0x2C, +0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0C,0x18,0x28,0x02,0x08,0x08,0x08,0xA7,0xBA,0x93,0xF4,0xC8,0x0A, +0x53,0x8A,0x6F,0x9B,0x48,0xDE,0xC6,0x68,0xD6,0xB9,0x77,0x85,0x2B,0xB8,0xDC,0xB0,0x31,0x32,0x46,0x38, +0x4B,0x51,0x63,0xB6,0x06,0x53,0xE3,0x74,0x88,0xD8,0xC7,0x8D,0xBD,0xB7,0xBF,0x52,0x8F,0x9A,0x6C,0xAD, +0x83,0xF9,0x88,0x7B,0xA1,0xDB,0x50,0x7D,0x99,0xA0,0xFF,0xA6,0x49,0x79,0x3F,0x46,0x45,0xB9,0x99,0x35, +0xD1,0x63,0x19,0x31,0xC1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25,0xD0,0x62,0x11,0x21, +0xC0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34,0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14, +0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24,0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00, +0x98,0x76,0x80,0x19,0x0D,0x40,0xD0,0x08,0x50,0xDB,0x16,0x7E,0xCD,0x22,0x2B,0x94,0xCC,0xCF,0xBF,0x11, +0x8C,0x0D,0x8C,0x0B,0x7D,0x8A,0x0E,0x88,0xAA,0xD2,0x0C,0xC8,0x51,0xD4,0x04,0x2D,0x0F,0x00,0x01,0x07, +0x94,0xD9,0xBA,0xA4,0x53,0x7D,0x86,0x27,0x82,0x97,0x61,0x6E,0xC2,0x63,0x9F,0x11,0x78,0x82,0xA2,0x80, +0xFF,0xEC,0x17,0xCD,0xD1,0x21,0x78,0xBF,0xF7,0x67,0x10,0x03,0x71,0x64,0x7D,0x8D,0x4A,0x40,0xC5,0x62, +0x9A,0x75,0x36,0x6C,0xF6,0x86,0xDE,0x36,0x73,0x6D,0xE9,0x99,0x20,0x31,0xE0,0x33,0x99,0xC6,0xBA,0x3E, +0xE2,0x10,0xA7,0x74,0x79,0x75,0xD3,0x8C,0xCA,0x1D,0x75,0x07,0x25,0x03,0xEC,0xA2,0xFB,0x03,0xB0,0x23, +0x60,0x37,0x0E,0x7F,0xB5,0x73,0x26,0x0B,0x19,0xE4,0x1A,0x05,0x6B,0x68,0x6E,0x9F,0x7C,0x22,0xC7,0x7A, +0xFB,0xC2,0x91,0xA3,0xA5,0xC9,0xF1,0x47,0x4A,0x96,0xB4,0xCD,0x38,0x89,0x49,0x6A,0x0A,0xB9,0x61,0x43, +0x39,0x7F,0x94,0xF6,0x69,0xD9,0x07,0x09,0xD8,0xA3,0x6B,0x63,0xF9,0xE7,0xAB,0xD2,0x2D,0x09,0xA4,0xDB, +0x0A,0x4D,0xD5,0x20,0x91,0x2F,0x12,0xCA,0xFF,0xE6,0xE5,0x01,0x2C,0xE8,0x52,0x3B,0x26,0xAD,0x78,0xB7, +0x25,0xBC,0x85,0x47,0x30,0x19,0x29,0x43,0x6E,0x39,0xB1,0x63,0x46,0x96,0x0A,0x45,0xD4,0xF0,0x59,0x7E, +0xB4,0x2E,0xD9,0x3B,0xD6,0xCB,0x8B,0xB6,0x6B,0x6D,0x74,0xE8,0x6E,0x6D,0x80,0x42,0xB4,0x0C,0x46,0x46, +0xAA,0x2C,0x4B,0xDD,0xDB,0x79,0xE3,0x3F,0x66,0x23,0x3D,0x1B,0x3C,0xB2,0x0D,0x86,0x32,0x60,0x16,0x73, +0xA4,0x9D,0x91,0xA6,0x5B,0x61,0x91,0x87,0x89,0xD1,0x38,0x37,0x7F,0x78,0x36,0x72,0x69,0x90,0xD2,0xAC, +0xB0,0x35,0x65,0xE6,0x94,0x9D,0xA2,0x64,0x53,0x7C,0x57,0xCB,0x4B,0x76,0x81,0x74,0x8C,0x07,0x03,0xC3, +0x80,0xC8,0x11,0xA1,0xB0,0xFB,0x33,0xA1,0x43,0xC3,0x0A,0x64,0x81,0x06,0x1C,0xE7,0x1C,0x9F,0xD9,0x44, +0xC1,0x46,0x52,0xFC,0xC9,0xC5,0x68,0xBF,0xEC,0x9B,0x6E,0x13,0x02,0xF9,0x85,0x04,0x76,0xD4,0x5B,0xF0, +0x7B,0xCC,0x9E,0xA7,0x05,0x94,0x54,0xF5,0x67,0xD5,0xFF,0xF3,0x9A,0xE6,0xFE,0x70,0xDA,0xB9,0x93,0xBF, +0x64,0x99,0x47,0xA6,0x20,0xB6,0x84,0x75,0x19,0x32,0x73,0x00,0x81,0x1A,0xF5,0xE5,0xE0,0x28,0x92,0x01, +0x50,0xF6,0xA5,0xE4,0x93,0xFC,0x39,0xFA,0xC3,0x99,0xD8,0xA5,0x18,0x93,0xCD,0xA4,0x17,0x3D,0xC8,0x85, +0xD9,0xD3,0x8E,0xAA,0x49,0x49,0xBB,0x6D,0x49,0x31,0xDE,0xB5,0xC5,0xF4,0x2F,0x4D,0x09,0x79,0x39,0xB9, +0xC3,0x15,0x16,0x8C,0xD3,0x4B,0xA2,0x9C,0x10,0x09,0x06,0xAC,0x93,0x0B,0xF0,0xEA,0x0A,0x98,0xDF,0x84, +0xB5,0x7B,0x0D,0x88,0x48,0xDA,0xBF,0xA0,0x92,0x6A,0x52,0x68,0x7A,0x0C,0x7C,0x36,0x2A,0xF1,0x44,0x1B, +0xEE,0xD1,0x56,0xDD,0x42,0xD3,0x13,0x28,0xAB,0xCD,0x1E,0x58,0x63,0xD3,0x66,0x98,0x67,0x1D,0xA0,0xD4, +0x18,0x3D,0x9A,0xC8,0x9D,0x4B,0xB8,0xF2,0x94,0xEB,0x05,0xBE,0x01,0x3A,0xC2,0x9F,0x90,0x6F,0x71,0x85, +0xCB,0x94,0x74,0x9F,0x1A,0xC2,0xDB,0xA2,0x02,0x6E,0xC9,0xC5,0x10,0xEE,0x97,0x26,0x22,0xC0,0x24,0x74, +0xFF,0x51,0x63,0xF2,0x18,0x6F,0x15,0xD5,0x2C,0x15,0x9F,0x13,0x88,0x8D,0xB0,0x13,0x11,0x81,0x5A,0x8F, +0x44,0xB1,0x80,0xC8,0xA8,0x40,0x21,0x27,0x0B,0x80,0x9F,0x36,0xF5,0xE2,0xA7,0x50,0xF2,0xAC,0x26,0x58, +0xFA,0x44,0x41,0x0C,0xA9,0x82,0x5A,0x64,0xB9,0xCF,0x60,0x58,0xA6,0x3C,0x81,0xC8,0x20,0x80,0xDF,0x73, +0xA7,0x7B,0xD8,0x35,0x20,0x05,0x66,0x00,0xB9,0x19,0x96,0xD2,0xA5,0xA6,0x7A,0xD8,0xEC,0x54,0x52,0xAC, +0x07,0x68,0x6D,0x81,0x7F,0x18,0x5F,0xCE,0xD8,0x48,0xDA,0xE6,0x71,0x7B,0xD9,0x77,0xC5,0xB9,0xA5,0x9D, +0x3B,0x67,0x72,0xF8,0x02,0x95,0xD2,0xE3,0x1B,0x28,0x96,0x68,0xBD,0x72,0x2F,0x5B,0x2C,0xD6,0xAA,0xE5, +0x28,0x4A,0x25,0x0F,0x08,0x88,0xC4,0xCA,0x1D,0xC8,0xCA,0xC2,0xA9,0x87,0x49,0x51,0x34,0x39,0x74,0xB3, +0x0D,0x04,0xE0,0xBE,0xBC,0x8B,0xBF,0xC7,0x61,0xBC,0xAD,0xCD,0x25,0xA9,0x5D,0xFA,0xBE,0x96,0x23,0x1F, +0xC3,0x07,0xB3,0x3B,0xAD,0x11,0xCD,0x13,0x29,0x49,0x55,0x2B,0x6C,0x2A,0xF5,0x37,0x25,0x00,0xAD,0x00, +0xFB,0x89,0x3B,0x76,0x34,0x8A,0x75,0x75,0x72,0x71,0xB2,0xCA,0x46,0x42,0xCD,0x5B,0x3E,0x63,0x27,0xFC, +0x5E,0xE4,0xD5,0x6B,0xAE,0x72,0x55,0x05,0x9C,0xA0,0x04,0x57,0x6F,0x7D,0xA4,0xC6,0xA0,0x4D,0xB7,0xD8, +0x2F,0x51,0xC8,0x31,0x4F,0x12,0x60,0x15,0xA4,0xBF,0x71,0x9E,0xE0,0xEE,0xD0,0xFE,0x78,0x72,0x14,0x9D, +0x3E,0x70,0xFF,0x7F,0xC3,0xD2,0xAE,0x0C,0xE5,0x7A,0x74,0x7C,0xD9,0x19,0x24,0xCF,0x16,0xC0,0xBC,0x48, +0xA1,0x0D,0x81,0x57,0x4C,0xF9,0x88,0xF0,0xDE,0x0A,0x60,0x69,0xD4,0xD2,0x96,0xA3,0x05,0x7C,0x29,0x9D, +0x1E,0x60,0xA1,0x70,0x20,0x46,0x35,0xF4,0x98,0x13,0x9F,0xAB,0x21,0x2F,0xEB,0x8B,0xFC,0x59,0x2D,0x7B, +0x44,0xDE,0x56,0xAC,0xF8,0x28,0x2F,0xF4,0x27,0x93,0x9D,0x97,0xAD,0xC9,0x9B,0xB0,0x44,0xC1,0xCC,0xA4, +0xDF,0xE7,0x66,0xFE,0x8D,0x90,0xCE,0x57,0x4A,0x5B,0xB1,0xD3,0xBB,0x26,0x95,0xA0,0xC4,0xA5,0xD8,0x90, +0x8C,0xD6,0xDA,0xAF,0x17,0x58,0x9C,0x88,0x5B,0xAA,0xF3,0xA5,0xD6,0xFE,0x4F,0x52,0xD6,0x79,0x60,0xE3, +0xF2,0x9A,0xCC,0x6F,0x3F,0x64,0x57,0x2C,0x4B,0x94,0xC9,0x91,0x0C,0xF4,0xEF,0x30,0x35,0xF7,0xDD,0x82, +0x89,0x67,0xA6,0x0A,0x6C,0xCE,0x7E,0xAF,0x68,0xD8,0xE6,0xA3,0x2A,0x0D,0xC0,0x84,0x13,0x6D,0x15,0x3B, +0xCA,0x44,0xE1,0xBA,0xED,0x99,0x30,0x46,0x7D,0xBB,0xFA,0x87,0xAA,0x2A,0x18,0xBE,0x1D,0x45,0x7D,0x0B, +0xFC,0x5A,0x23,0x53,0xFC,0x4F,0x7C,0xE8,0xDF,0x80,0xBD,0x15,0x56,0x6A,0xE0,0xBA,0x31,0x1A,0xBC,0x30, +0x00,0x5A,0x46,0x57,0x0C,0x0C,0x55,0x6E,0x38,0x0C,0xC3,0xC6,0xDA,0xAD,0xFE,0x97,0xB6,0xCD,0x34,0x25, +0xCE,0x1E,0x90,0x6B,0xBC,0xB0,0xFD,0x7E,0x3F,0x00,0xC6,0x00,0xD3,0xF0,0x27,0xB8,0xFB,0x1F,0x09,0x0D, +0x1F,0x4F,0x42,0xD3,0x6C,0xDE,0x57,0xFC,0xCE,0x9A,0xDE,0x35,0x36,0x62,0x3C,0x2C,0xD9,0x1B,0x01,0x5E, +0x27,0xD0,0x00,0xD0,0xCB,0xAA,0x95,0x2B,0x70,0x42,0x00,0x06,0x14,0xDB,0xCB,0x20,0xB8,0x58,0x27,0x68, +0x27,0x60,0x70,0x94,0x55,0xF7,0x08,0x7B,0x9E,0x87,0xFD,0x4F,0x29,0x4C,0x58,0x2C,0xCF,0x9C,0x02,0x46, +0x7B,0x97,0x85,0x1A,0xBC,0x59,0x4A,0x21,0xC6,0xD2,0xA6,0x6D,0xA3,0x62,0x2F,0x2D,0x05,0xA7,0x9A,0xD5, +0x9D,0x63,0xE6,0x4F,0xEF,0xFF,0xC0,0x31,0x5C,0x00,0x00,0x33,0x3E,0x0F,0xE6,0xFE,0xE3,0x8F,0x31,0xC0, +0x40,0x3D,0xEE,0xB4,0x70,0x69,0xFF,0x69,0xFE,0x66,0x4A,0x3C,0x09,0x65,0x58,0x30,0x6D,0x46,0xE8,0x76, +0x13,0xBE,0xC5,0x45,0xCE,0xA5,0x3C,0xCD,0x84,0x66,0x6F,0x4D,0x4D,0xC0,0x53,0x99,0x6A,0x9D,0x2F,0x33, +0x74,0xFA,0x4B,0x35,0x7A,0x76,0x5E,0xF1,0x0B,0xE6,0xEC,0x88,0xF3,0xB3,0x15,0x0F,0xFD,0x07,0x04,0xA5, +0xF1,0x82,0xAD,0x73,0xBB,0x4B,0x39,0x89,0x8D,0x76,0x0E,0x29,0x77,0xA6,0x9D,0x1D,0x99,0x49,0x22,0xC3, +0xB8,0x2A,0x8F,0x42,0x33,0x78,0xB7,0x76,0x2B,0x81,0xD3,0x6F,0xD0,0x81,0x12,0x3C,0x31,0xEB,0xEE,0x1C, +0xE0,0xC5,0xDC,0x6B,0xE3,0xD8,0xB1,0xEE,0xE1,0x56,0x60,0x4A,0xCA,0xC7,0xE5,0x15,0x11,0x01,0x54,0x2A, +0xF5,0xD1,0x2E,0xDE,0x1A,0x24,0xF2,0x7B,0x2A,0x28,0x44,0x73,0x6A,0xC7,0x5C,0xAB,0x63,0xD0,0xEC,0x6D, +0x9F,0x89,0x22,0xFC,0x1B,0xF8,0x82,0x7E,0x30,0xDA,0x97,0xB7,0x77,0xAF,0xD3,0xED,0xC2,0x2C,0x6D,0x17, +0x02,0xB3,0xC6,0xFE,0xB1,0x3F,0x1D,0x69,0x60,0x8E,0xD9,0x5A,0x72,0xF2,0x7B,0x60,0x03,0xEE,0x5F,0xF0, +0x32,0xE5,0xBB,0xB1,0x50,0xBF,0x92,0xE6,0xCF,0xED,0x44,0x3E,0x9B,0xFB,0x71,0xDB,0x18,0x7D,0x72,0xBD, +0xC8,0xF0,0x1A,0x67,0x5D,0xEC,0xC4,0xC2,0x8A,0xF7,0x23,0x85,0x1D,0xDE,0x16,0xFF,0xCA,0x63,0x51,0x7B, +0x4D,0x93,0xF7,0x32,0x8B,0xB4,0x6A,0xDB,0xDE,0xAD,0x53,0x73,0xA5,0x96,0xDB,0xA1,0x5A,0xF2,0x43,0x23, +0xA1,0xFC,0x0B,0xCB,0x9B,0xB2,0x45,0x33,0xC2,0x58,0x73,0xC5,0xBF,0x38,0x5D,0x00,0x12,0xF0,0x56,0x18, +0xCA,0x8F,0x6B,0xD4,0x48,0x61,0xDE,0xAB,0x53,0x34,0x02,0x12,0x67,0xD0,0xE9,0x09,0x52,0xA1,0x24,0x32, +0x72,0xBD,0xAD,0xDA,0x9E,0x82,0x5A,0xCD,0x0B,0xBE,0xED,0xE7,0xB2,0xAD,0xCF,0x17,0x31,0x14,0xB3,0xED, +0x52,0xB4,0xEE,0x13,0x8B,0xB6,0x4B,0xEA,0xC3,0xDA,0xB5,0x6A,0x40,0xC9,0xA6,0x09,0xD1,0x22,0xF5,0x5B, +0xB6,0xF3,0xE8,0x98,0xF8,0x1A,0x19,0x6B,0x51,0xBB,0x40,0x39,0xCE,0xC4,0x40,0x8E,0xA3,0xF2,0x61,0xCF, +0x36,0x1A,0x79,0xB5,0x5D,0xB9,0x91,0xEF,0x47,0x97,0x70,0xA1,0x03,0xCC,0xA9,0x65,0x90,0x77,0x1D,0x9B, +0x79,0xB9,0x99,0xA8,0x52,0xDA,0xA9,0x59,0x02,0xFE,0x64,0xC2,0x91,0x9A,0xA5,0x33,0xE2,0xEB,0x77,0x3F, +0x06,0x3F,0x28,0xDD,0x9F,0xFF,0x41,0xD2,0x0E,0x67,0x68,0x63,0xD0,0xB9,0xEE,0xD8,0x44,0x7D,0x49,0x87, +0x45,0xFB,0x0A,0xA2,0xE8,0x42,0xB8,0xDA,0x5C,0xC1,0xC6,0xDD,0xC5,0x3E,0xC5,0x1A,0x8E,0xAB,0x57,0xAA, +0xD4,0xA2,0x3C,0x23,0x13,0x6E,0x68,0xE4,0x47,0x67,0x67,0x07,0x16,0xFE,0xCD,0x1D,0x10,0x2E,0x5E,0xBE, +0xB8,0x33,0xBA,0x02,0x37,0x3A,0x7A,0xC0,0x05,0xD0,0x25,0x86,0x48,0xF0,0x2B,0x14,0xFA,0xE2,0xBD,0xF6, +0xDD,0xEB,0x39,0xC3,0xA1,0x67,0x2E,0xBC,0xD5,0x92,0xD8,0x28,0xFA,0xC0,0xFF,0x2F,0x5E,0x09,0x4F,0xB0, +0xAF,0x74,0xEF,0x13,0x48,0x49,0x4F,0x71,0x72,0x7E,0x3C,0xB7,0x89,0x00,0x67,0x04,0xE6,0x68,0xE7,0x03, +0x49,0x48,0x46,0x1B,0x32,0x51,0xC6,0x39,0xB5,0xE6,0xD0,0x71,0x26,0xA0,0xA0,0x04,0x12,0x3F,0x8A,0x4D, +0xC9,0x08,0xCE,0x67,0x93,0x01,0x46,0x0D,0xE4,0x67,0xFA,0x8A,0xEF,0x1E,0x70,0x7C,0xBE,0x52,0xE2,0x7C, +0x16,0x16,0x4F,0x1D,0x65,0xA3,0xC4,0x9A,0x57,0xE2,0x17,0xC0,0xEC,0x01,0xFB,0x50,0x7E,0x7A,0xE8,0x00, +0xEB,0x6C,0xF1,0x69,0xBB,0x13,0x34,0x68,0xF3,0x55,0x9C,0xC6,0x55,0x42,0x04,0x28,0x27,0x4D,0x24,0xA4, +0xB5,0xF2,0x3F,0xE9,0x35,0x54,0x51,0x25,0x12,0x36,0x19,0x21,0x95,0x62,0x0D,0x6B,0xAA,0x5C,0xF7,0xF5, +0x71,0x2B,0xFB,0x97,0x60,0x42,0x31,0x6D,0x5E,0x5E,0xBD,0xFA,0xFF,0x78,0x7D,0x33,0x66,0x9A,0x6B,0x07, +0x03,0x56,0x9E,0xA3,0x4A,0xDD,0x73,0xC5,0xDB,0x7B,0xE2,0x54,0xD8,0x78,0x9A,0x69,0xF7,0x51,0x0A,0x6E, +0xAE,0x19,0xE3,0x9F,0x66,0x4A,0x09,0x5E,0xE4,0x48,0xEF,0x9C,0x9C,0xEB,0x6C,0x04,0x25,0x4C,0x34,0xC5, +0x5B,0x9C,0x84,0xB8,0x54,0x25,0x9B,0xC2,0x9A,0x0E,0x0B,0x5A,0xA6,0x61,0xAD,0x43,0xBD,0xEA,0x15,0x6C, +0xE4,0x2A,0x5C,0x7B,0x10,0xAD,0x05,0x4B,0x7A,0x66,0xC5,0xAF,0xFD,0xE2,0x32,0x86,0x2C,0x40,0x1F,0x37, +0x50,0x1F,0x6A,0x90,0x60,0x9C,0xCA,0x93,0x81,0x53,0xBC,0x55,0x27,0x64,0x94,0x69,0xDC,0x8B,0x1B,0x43, +0xF9,0x91,0x75,0x87,0xD4,0x0E,0x4D,0x41,0x22,0x67,0x37,0xF4,0xA3,0x13,0x54,0xB9,0x34,0x66,0x27,0x54, +0x90,0x5F,0x29,0xD4,0x24,0x9D,0x79,0x69,0x48,0x12,0xD5,0x39,0xC7,0x05,0x83,0x7E,0xDB,0x2C,0x59,0x22, +0x2A,0xD4,0x3F,0xC6,0xCE,0xAC,0x4C,0x1D,0x93,0xB7,0x4F,0x56,0xBC,0x5B,0xD5,0x32,0x2B,0xD5,0x09,0xA9, +0x5F,0xB8,0x02,0xC3,0x92,0x76,0xB6,0x56,0xD6,0x35,0xE3,0xDF,0x12,0x8E,0xBE,0xC7,0xB0,0x26,0x8E,0x9C, +0x8E,0x37,0xE0,0xE5,0xCE,0x5B,0xEB,0xDF,0xCC,0xE8,0x93,0xEA,0x42,0xD4,0xEF,0x00,0x87,0x99,0x26,0xD9, +0x88,0xF7,0x78,0xBA,0xB0,0x33,0x30,0x7D,0x50,0x65,0x49,0x0A,0x7C,0x58,0x09,0x9F,0x10,0x57,0x8B,0x6B, +0x41,0x8F,0xD0,0xAE,0xF5,0x58,0xE1,0xBB,0xB1,0x48,0xC0,0x8A,0x96,0x78,0x31,0x01,0xC7,0x5B,0xF1,0xBB, +0x57,0x7B,0xE8,0xAB,0x6C,0x9A,0x21,0xD1,0x96,0x3B,0x87,0x1B,0x51,0xC3,0xB9,0x9B,0xF9,0x9B,0x6F,0xB7, +0xAD,0x20,0x99,0x8A,0x95,0xB7,0xE2,0x3B,0x91,0x9F,0x98,0xF2,0x45,0x3C,0x36,0x4A,0xB8,0x63,0xD6,0xFE, +0x09,0xC9,0x6E,0x2B,0xF7,0xDD,0xA6,0xDB,0x3B,0x8D,0x89,0x85,0xA7,0x0A,0x59,0xD6,0x96,0x0C,0xCF,0x41, +0xC5,0x0A,0xD8,0x08,0x74,0x0F,0x27,0x01,0x15,0x7A,0x28,0xED,0x2A,0x1F,0x31,0xD4,0xEB,0xD1,0xF9,0x64, +0xFF,0xCD,0xC4,0xE8,0x15,0x62,0x4C,0xC3,0xCC,0xBF,0xAC,0xA5,0xD5,0x63,0xFE,0x31,0x73,0x30,0x23,0x68, +0xB1,0x2E,0xE9,0x42,0xAF,0x63,0x52,0xE3,0x35,0xDC,0xB2,0xA5,0x29,0x8E,0x98,0x39,0x69,0xE5,0x9C,0x73, +0xD7,0x51,0xAA,0xCB,0x3B,0x83,0x97,0x29,0x7B,0x73,0x73,0x21,0xC3,0x22,0xAF,0x20,0x5F,0x66,0x5B,0x82, +0x6A,0x32,0x9C,0x06,0xA1,0x67,0x8C,0xA7,0x09,0xD2,0x26,0xE5,0x87,0x0F,0x3E,0x1C,0x10,0x49,0xFE,0xA7, +0xA8,0x0B,0x76,0x3D,0x1B,0x40,0x73,0x71,0x68,0xA4,0x5E,0x95,0xE8,0x3D,0xC0,0xB7,0x41,0x2A,0x90,0xB1, +0x8B,0x9D,0x0C,0x65,0xC4,0xC5,0x3F,0x1C,0x6B,0x4C,0x66,0xA6,0xF7,0x09,0x50,0x63,0xCE,0xE2,0x6D,0x71, +0x4E,0xA6,0x77,0x0D,0xEB,0xFF,0x30,0xB7,0x04,0x28,0x56,0xB7,0xC3,0x41,0xF9,0x64,0xB7,0xE7,0x3C,0xD9, +0x2A,0x05,0xA4,0x39,0x94,0x25,0xF4,0xD9,0x82,0x68,0x56,0xDF,0x1D,0x6E,0xD7,0x19,0x3E,0x5C,0xF4,0x28, +0x3B,0xFF,0x0C,0xA6,0x81,0x88,0x24,0x2C,0xDE,0xF9,0x17,0xA9,0xD8,0x1A,0xFD,0x3C,0x34,0x27,0x4D,0xBB, +0xC0,0xEE,0x22,0xDD,0x79,0x69,0x56,0xE9,0x09,0xDB,0xF4,0x85,0x9D,0x3B,0xFC,0xC8,0x13,0x5B,0xBB,0x39, +0x5C,0xFB,0x3C,0x1D,0xE3,0x46,0xB1,0xAE,0xBA,0x23,0x5A,0x06,0x29,0x6C,0x7F,0x7C,0x27,0xEC,0x48,0x67, +0x0C,0x09,0x03,0xBE,0x56,0x22,0x32,0xBA,0xC8,0x09,0x14,0x78,0xE0,0x2D,0xAF,0xDA,0x85,0x06,0x65,0xAF, +0xE7,0x21,0x2B,0xC9,0x35,0xF1,0x13,0x68,0x30,0x0E,0xCB,0x66,0x84,0xFB,0x1D,0xBF,0xAB,0x20,0x33,0x7E, +0x48,0x40,0x3A,0x79,0xE5,0x4F,0xB5,0x6E,0xB9,0xED,0xE5,0x6C,0xD3,0x7D,0x37,0xA0,0xA8,0x08,0xED,0x83, +0xD1,0x4F,0x8E,0x7D,0x29,0x4A,0x89,0x67,0x51,0x90,0xF4,0x3A,0xE1,0xE1,0xA4,0x5B,0xFC,0x33,0x28,0x6C, +0xA8,0x16,0xC7,0x65,0xBC,0x72,0x32,0x50,0x7C,0x92,0x21,0xC7,0x47,0x17,0xBC,0x78,0xC2,0x67,0xD5,0x90, +0xB5,0x63,0xB5,0x3B,0x8A,0xC7,0x9A,0x81,0xD2,0xF3,0x9B,0xC0,0xFE,0x9E,0xD2,0xD9,0x7A,0xE4,0xBA,0x0E, +0x11,0x0B,0xF2,0xA4,0xFE,0xDF,0x1C,0xA3,0x63,0xCE,0xAD,0xC8,0x10,0xE5,0x00,0x1B,0x75,0x4A,0xDB,0x41, +0x92,0x13,0x1C,0x2F,0x07,0xE9,0x79,0xD9,0x4C,0xE6,0xC1,0x0A,0x77,0x69,0xAD,0xE1,0x0B,0x34,0x49,0xD3, +0xA7,0xCC,0xC3,0xC9,0xA9,0x87,0x77,0x1B,0x9E,0x48,0xA3,0x63,0x90,0x57,0x56,0x86,0x02,0x2C,0x10,0xBC, +0xEB,0x31,0x16,0xBB,0x7D,0xEC,0xE8,0xF4,0xF8,0xC0,0x5A,0xB3,0x0F,0x5B,0xD7,0x73,0x9C,0x96,0x7F,0x48, +0x61,0xF8,0xC1,0x3E,0x0A,0x79,0xD7,0xA6,0x8A,0x4F,0x03,0x89,0xAC,0xCE,0x49,0xA6,0xA4,0x14,0x48,0xAC, +0x8F,0xBA,0x0C,0x9F,0x56,0x78,0x02,0x15,0x1C,0x94,0xCF,0x4A,0xCF,0xD6,0xFF,0xF9,0xD9,0x76,0x46,0xD6, +0x61,0xE1,0x7B,0xD5,0x8C,0x8C,0x93,0x1F,0xFB,0xB3,0x32,0x1F,0xB4,0xD7,0x17,0x33,0x8E,0xB2,0x0D,0xC4, +0xDE,0xAD,0xB4,0x0E,0xFB,0x92,0xBC,0x93,0x84,0x11,0x0D,0x54,0x41,0x64,0xE6,0xD4,0xF9,0x8E,0x8D,0x1E, +0x82,0x91,0xB1,0xE5,0x1B,0xD1,0x02,0x51,0x0E,0xB0,0xFC,0xC5,0x98,0xAF,0x8A,0x0A,0x48,0xF0,0x85,0x7D, +0x25,0xD0,0x1E,0x5E,0x64,0x0B,0x00,0x9F,0x10,0x40,0x0A,0xD1,0x96,0x64,0xD0,0x08,0x37,0xED,0xD1,0x59, +0xF8,0xBD,0x1F,0x32,0x94,0xAC,0x8E,0xC3,0xAD,0xC5,0x39,0x34,0x51,0xAD,0xDE,0x71,0xE6,0xD7,0xFB,0xC5, +0x17,0xE4,0x24,0x15,0x0C,0x93,0xE1,0x51,0x94,0xAC,0xF4,0x12,0x19,0x80,0x81,0xF5,0x14,0xC7,0x07,0x7B, +0xAE,0xCC,0x38,0xB5,0x61,0x68,0xE9,0xAA,0xA5,0x09,0xA3,0xA4,0x10,0xA6,0x18,0x00,0x60,0xC4,0x9B,0x67, +0x25,0x30,0x95,0x34,0xEC,0x4F,0x15,0x4B,0xF0,0x55,0x70,0x8C,0xE6,0x1A,0xA0,0xF3,0x8B,0xA1,0x99,0x41, +0xB7,0x9D,0xE1,0x5A,0x69,0x56,0x71,0x9C,0x66,0x39,0xF9,0x78,0xDF,0x9B,0x28,0x35,0x78,0x84,0x52,0x4A, +0x76,0x57,0x59,0x8D,0xEF,0x78,0x5A,0x70,0xBC,0xE8,0x83,0xAB,0x94,0xCB,0x8A,0x08,0x9D,0xA6,0x33,0x18, +0xA7,0x4D,0x8A,0xFE,0x22,0xE7,0x6A,0x69,0x58,0x08,0xA2,0xE1,0xBC,0xA8,0x04,0x0A,0x6D,0xC4,0xE5,0xBC, +0x2E,0xE9,0x03,0x96,0xAE,0x1A,0xFD,0xCD,0x8C,0xAC,0x0D,0x0E,0xEF,0x48,0x6C,0x2F,0xAB,0x2A,0x71,0xE4, +0x6C,0x08,0x93,0x1A,0x99,0xFB,0xBC,0x7D,0x5F,0x60,0xDB,0x7B,0xFD,0xE6,0xDC,0x4F,0x81,0x88,0x0C,0x53, +0x87,0x5C,0x5E,0x91,0x6B,0x73,0x72,0x15,0x58,0x5C,0xD5,0xFA,0xEA,0x0D,0x8A,0x43,0x2C,0x5D,0x73,0x95, +0xF2,0xB2,0xA0,0x7F,0xD1,0x12,0x67,0x0C,0x08,0x3E,0x92,0x52,0x76,0x5E,0x71,0x91,0x2A,0x51,0x25,0x1D, +0x50,0x31,0xB4,0x5A,0x0F,0xCF,0x24,0x42,0x92,0x5F,0xD8,0x94,0xE9,0x90,0x6B,0x6C,0xD6,0xAB,0x42,0xE0, +0xD3,0x6D,0xAD,0x0E,0x91,0x1F,0x62,0x03,0x8F,0xF3,0xCD,0x81,0xD5,0xCF,0xF8,0x6C,0xD8,0x30,0x68,0x10, +0x61,0x4C,0xEC,0x36,0x35,0x95,0x84,0x59,0xF8,0xB3,0x33,0xE1,0x5B,0x4F,0xED,0x0F,0x11,0x4D,0x80,0x03, +0x53,0xE7,0x01,0xC5,0x43,0x97,0x3C,0x60,0x95,0x4E,0xFD,0xE0,0xB9,0xDD,0xC2,0x16,0x2F,0xDE,0xBA,0x83, +0xD6,0xD0,0xAD,0x2A,0xC1,0xD9,0x30,0xCB,0xD5,0xC4,0xC6,0x11,0x3D,0x7B,0x13,0x94,0xB4,0xF4,0x12,0x1A, +0x05,0x85,0xFB,0xDA,0xDA,0xE5,0x5B,0x00,0x72,0x5A,0xFD,0x84,0x9C,0x63,0x1B,0x16,0xB6,0xDB,0x11,0xCA, +0x9D,0xC6,0xB7,0x11,0x6D,0x59,0x8B,0x79,0x9D,0x40,0xAC,0xA0,0xEC,0x94,0xDD,0xDB,0xA4,0xE7,0xFC,0x14, +0x7A,0xB8,0xA3,0xC1,0x2A,0x5C,0x70,0xBF,0xC7,0x79,0x86,0x8F,0xB1,0xFE,0xCD,0xD5,0x04,0xD5,0xE8,0xF6, +0x74,0xFC,0x8A,0xF8,0xC6,0x38,0x2A,0x59,0xBD,0x99,0x81,0x8B,0x5D,0x76,0xC0,0x7A,0x6F,0xB4,0x01,0xA3, +0x28,0x35,0xA6,0xF0,0x9E,0x77,0xC8,0xD5,0xC2,0x05,0xA4,0x47,0x43,0xB7,0x9B,0xF9,0x46,0x5A,0x03,0x19, +0xA1,0xA0,0x2E,0xC5,0x87,0x3A,0xC1,0x7A,0xEF,0xB6,0x5E,0xC2,0xE6,0xF6,0x65,0xC7,0xBB,0x8C,0xD5,0x0D, +0x69,0xB3,0x40,0x8C,0x15,0x59,0x4E,0x5A,0xE7,0xD7,0x87,0xD6,0xF3,0xAD,0xCF,0x1C,0x08,0x92,0x56,0x74, +0x94,0x69,0x2B,0x6B,0xFE,0x8E,0xB9,0xC6,0xD2,0xAE,0x36,0x0D,0x4F,0x91,0xD7,0x1E,0x1E,0x7E,0x23,0x7B, +0xFF,0x3F,0xB9,0xCA,0x1A,0x5F,0x75,0x1D,0xAD,0xF0,0xA1,0xE4,0xF7,0x54,0xA5,0x14,0x87,0x16,0x10,0xC4, +0x08,0x1D,0xEF,0x04,0xFE,0x60,0xEA,0xF0,0xD0,0x40,0x1A,0x11,0xFE,0x8C,0xF0,0x1C,0xF4,0x60,0xBC,0x52, +0x65,0x4B,0xB8,0x39,0x59,0x21,0x51,0x9F,0x7B,0xBF,0x97,0x03,0x23,0xE6,0x93,0x2A,0x44,0x16,0x1B,0xD3, +0x0F,0xEF,0xDD,0xEF,0x7C,0xA2,0x7C,0xEB,0x85,0x1E,0x99,0x46,0xE5,0x34,0x9B,0x3D,0xD3,0x62,0x63,0xB1, +0xDA,0x24,0x39,0x57,0x18,0x60,0xD1,0xE4,0x1E,0x02,0xB0,0x24,0xA9,0x69,0x29,0xF0,0xD5,0xBA,0x90,0x51, +0x9C,0x21,0xA3,0xF4,0x1F,0xBB,0xDC,0x76,0x57,0x9E,0x1F,0x4E,0xC6,0x48,0xE7,0xC5,0x1E,0x2B,0x6B,0x8E, +0x39,0xB9,0xA3,0x7C,0x92,0x9D,0xF4,0x31,0xE7,0x8B,0xCD,0x12,0x15,0xD7,0x63,0x8E,0x34,0x05,0xD9,0xB7, +0x50,0x21,0x3A,0xF7,0xFD,0x6B,0x94,0x0A,0xAB,0x65,0xE9,0x2C,0xE5,0x09,0x9A,0x2E,0xDA,0x98,0x74,0x1E, +0xE0,0x01,0x1A,0x6F,0x95,0x78,0x20,0xBF,0x6D,0xB4,0x7E,0x5C,0xAB,0x0C,0xF8,0x7A,0x81,0xFB,0xFD,0xEF, +0x88,0x67,0x36,0x2F,0x5C,0x2E,0xEF,0x5F,0xAF,0x4A,0xD8,0xEA,0x05,0x86,0xF5,0x1A,0x20,0x4D,0x3C,0xDB, +0x29,0x5E,0x64,0xED,0xA7,0x68,0x08,0xAA,0x4B,0x1C,0x92,0x51,0x02,0x88,0xD1,0x8A,0xAB,0xB3,0x65,0x48, +0xD8,0x64,0x4B,0xA9,0xEF,0xF1,0x6E,0xAC,0x13,0x22,0x60,0x87,0xBC,0x0F,0xD2,0x4B,0xFA,0x01,0x3D,0xDA, +0xE1,0xB8,0x87,0x4B,0x52,0x2C,0xA8,0xED,0x96,0xF9,0x65,0x0F,0x2D,0x68,0x15,0x6E,0x2A,0xA4,0x0B,0x40, +0x26,0x6A,0x5B,0x6D,0xEF,0x21,0x38,0x3A,0x05,0x67,0x5A,0xB3,0xA0,0xBB,0xFA,0x83,0x14,0x7C,0x45,0x42, +0x44,0x27,0xBA,0xA2,0xE1,0x2C,0x72,0x8A,0x4A,0xA5,0x76,0x5E,0xCA,0x9A,0xBD,0xB7,0xC0,0xFE,0x28,0xFE, +0xB8,0x35,0x37,0x91,0x25,0x04,0x32,0x6D,0x4F,0xBF,0x11,0xAD,0x78,0x16,0xBB,0xA2,0x65,0x7D,0x09,0x60, +0x3D,0xF3,0xBD,0xCA,0xDA,0x07,0x65,0x96,0x40,0x12,0xB4,0xFB,0x38,0x17,0x2C,0x46,0xDE,0x55,0xA6,0xC0, +0x33,0x64,0xA9,0x6C,0xB2,0x8B,0xD0,0xA3,0xF3,0x7A,0x48,0x52,0x22,0x7A,0xCA,0xEB,0x74,0x77,0x09,0x50, +0x94,0x35,0x5B,0x4B,0x73,0x55,0xED,0xFE,0xC9,0x01,0x05,0xD5,0x8B,0x32,0x72,0x1E,0x89,0x29,0x6A,0x45, +0x53,0xD6,0x17,0xD0,0x00,0x59,0xCD,0xE1,0x80,0x38,0x03,0x1E,0xA3,0xFC,0x5E,0x37,0x70,0x31,0xEE,0x02, +0x0A,0xCE,0x86,0x7D,0xB0,0xC7,0x5E,0xBC,0xA4,0x57,0x3F,0x73,0xC1,0xA6,0x50,0x03,0x39,0xB2,0x0D,0xCC, +0xD8,0x5F,0xEB,0x46,0x25,0x34,0xDE,0x83,0x71,0x15,0x78,0x78,0x62,0x02,0x07,0x94,0x3E,0x7A,0x12,0xDE, +0xF2,0x1B,0x29,0xAF,0x0E,0x14,0xBD,0xC6,0xC2,0xFE,0x3B,0x77,0x58,0x5D,0x61,0x5B,0xF1,0x36,0xB7,0x7F, +0x2D,0xBD,0x77,0x0E,0xD6,0x1A,0x9C,0xC9,0x9D,0x7D,0xAB,0x6C,0x01,0x23,0x61,0xC8,0x7C,0x8C,0x36,0x5A, +0x2E,0x5D,0x62,0x5E,0x3A,0x28,0x0E,0x12,0x90,0xF6,0xFE,0x16,0x7D,0x8D,0xCF,0xCC,0xC9,0xEE,0x2B,0x4D, +0x46,0x1E,0x11,0x18,0x55,0x8E,0xE6,0x6D,0xFA,0x3E,0x77,0x89,0xAF,0x10,0xF7,0x2E,0x97,0x9B,0xA2,0x61, +0x80,0x20,0xCA,0xFF,0x54,0x11,0xC4,0xF1,0xC2,0x0B,0xDE,0xE4,0xB8,0x9D,0x48,0x7D,0x94,0xCF,0x8E,0x2F, +0x17,0x12,0x76,0x81,0x15,0x0C,0xD6,0xF4,0xA0,0x77,0x40,0x00,0x31,0x1E,0xA0,0x37,0x01,0x1D,0x25,0x84, +0x6F,0x64,0x45,0x23,0x29,0x54,0x03,0x0B,0x11,0x76,0x4A,0x55,0x5A,0x87,0x57,0x81,0x58,0xFE,0x21,0xF5, +0x2C,0x15,0xA9,0x60,0x66,0xDC,0xF3,0x75,0xBD,0xEE,0x56,0x40,0x6D,0x01,0x67,0x34,0x38,0x5B,0x30,0x5D, +0x4E,0xA8,0x74,0xA1,0xD6,0xC4,0x4B,0x52,0x6C,0x31,0x78,0xF6,0x0F,0xE4,0xDF,0x8D,0x2C,0xBA,0x14,0xF6, +0xAB,0xC5,0x63,0x05,0x14,0x2D,0x89,0x85,0x10,0x53,0x59,0xA1,0x12,0x19,0x5D,0xA7,0x75,0xA7,0x6D,0xA2, +0x1B,0x15,0xB9,0x4B,0x81,0x12,0x2C,0xD3,0x30,0xA7,0x55,0x35,0x54,0x4A,0x8D,0xF9,0xDA,0x7C,0x2A,0xEC, +0xAD,0x3E,0x86,0x48,0x7C,0xC7,0xAA,0x04,0x5D,0xFF,0x54,0x80,0x66,0x4C,0xBC,0x18,0xF6,0xED,0x9A,0xAB, +0xC9,0xC2,0x80,0xB9,0xF1,0xF6,0xC4,0xFA,0x56,0x9A,0xAD,0xED,0xB8,0x2F,0x1D,0xC9,0x7F,0x67,0x89,0xA8, +0x70,0xB5,0x84,0xEA,0x61,0x86,0x95,0xFD,0xF7,0xCF,0xBB,0xAA,0x41,0xC6,0x81,0xB8,0x71,0xF7,0x8A,0xC0, +0x2C,0x5A,0x2F,0x71,0x59,0xEE,0x2C,0x85,0x0E,0x67,0xE2,0x8E,0x16,0xEC,0xDE,0x7D,0xAE,0x52,0xA8,0x2F, +0x58,0xA6,0x3C,0x8B,0xF0,0x5D,0x92,0xBC,0xD9,0x18,0x1C,0xC9,0x53,0x83,0x65,0xF3,0x77,0xD6,0x8E,0xEF, +0xA5,0xB1,0xAD,0x78,0xD6,0xEE,0xDF,0x39,0x70,0x81,0xAF,0x2C,0x80,0xC3,0x2B,0x91,0x34,0x64,0x6B,0xB8, +0xDD,0x1A,0x1C,0x73,0xCC,0x94,0x10,0xC6,0x38,0x7F,0x71,0x86,0xFC,0x94,0x13,0x31,0x1F,0x56,0x4D,0x63, +0xF5,0x91,0x43,0x64,0xB5,0x80,0x42,0x50,0x06,0xF1,0x9F,0x28,0xAD,0x07,0x7B,0xB1,0xE4,0xDE,0x85,0x86, +0x13,0xA2,0x94,0xA4,0x05,0xB4,0xB4,0xD5,0x1F,0x74,0x73,0x88,0xAD,0x38,0x97,0x10,0x19,0xAC,0xD9,0x97, +0x5B,0xF3,0xE3,0x2C,0xE5,0x5C,0x5C,0x12,0xD1,0x9B,0x8B,0xF6,0xFE,0x6A,0xF0,0x13,0xD9,0xD7,0xB4,0xD9, +0x7E,0x98,0xEB,0x30,0xA5,0xDD,0x0C,0xE9,0xCB,0x74,0x87,0xCD,0x98,0xDB,0x1C,0xC9,0x53,0xF3,0x05,0x87, +0xEA,0x1D,0xF3,0xD4,0x69,0x77,0x25,0x09,0x1D,0x03,0xDD,0x25,0x75,0xF8,0xEF,0xB1,0xE6,0xD7,0x5E,0xE6, +0x4F,0x36,0x15,0x75,0x1B,0x96,0xF5,0x28,0x16,0xF8,0x83,0x12,0xAB,0x8E,0xEC,0x9B,0x5C,0x28,0x76,0xD9, +0xE8,0xE9,0xD5,0x5F,0x98,0x04,0x81,0xF8,0x81,0xFC,0xE4,0x83,0x7C,0xB8,0xEF,0x49,0xE1,0xD4,0x88,0xBC, +0x16,0x7C,0x77,0x15,0x57,0x9C,0x8E,0xC8,0x92,0x36,0x49,0xAD,0x05,0xBE,0xE9,0x98,0x5D,0x51,0x17,0x65, +0x01,0x96,0x86,0x98,0xBC,0x3B,0x41,0x59,0x41,0xD6,0xBD,0xF9,0x6F,0x54,0x1E,0xA8,0x6D,0x43,0xD5,0xEB, +0x1A,0xD2,0x9A,0x6A,0x92,0xFC,0x66,0xEF,0x5E,0xFC,0x76,0xEA,0x0C,0xDC,0xC6,0x1C,0xBD,0xB5,0x3E,0xE5, +0x65,0x9F,0xFE,0xFE,0x7F,0xFD,0x1F,0x4F,0xF2,0xD0,0xA7,0xF0,0xB6,0xD2,0xDB,0xA9,0x6D,0x0A,0xF7,0xEF, +0xFE,0xFE,0xAF,0xC6,0xEC,0x64,0x00,0x2F,0xE7,0xB0,0xF8,0x1E,0x12,0xD6,0xFF,0xFF,0x1C,0x41,0x80,0x00, +0x0C,0x4C,0x04,0x00,0x18,0x2E,0x6F,0xD8,0xC1,0xBF,0x43,0xCC,0x56,0xBD,0x51,0xEF,0xE0,0xCE,0x90,0x11, +0x15,0x01,0x47,0x32,0x32,0x41,0x45,0x36,0x2A,0x61,0xB6,0x85,0xC0,0xB8,0x35,0x67,0xF1,0x38,0xEA,0xA5, +0xC4,0x54,0x6B,0x2D,0x2D,0xAD,0x60,0xEA,0xEA,0x06,0xE1,0x97,0x90,0x5B,0xC6,0x31,0xB6,0x4F,0xC2,0xB7, +0xAE,0x63,0x38,0xC2,0x01,0xE2,0x00,0x44,0x62,0xD1,0x22,0x80,0x06,0xCF,0xA8,0xE6,0x57,0x5D,0x31,0xB8, +0x09,0xCE,0xEE,0x59,0x97,0x81,0x5A,0x5E,0xB5,0x30,0x50,0xB1,0xF2,0xEF,0x79,0x31,0x9A,0x0F,0xC4,0xC1, +0x92,0xB7,0x7A,0x8F,0x7D,0x42,0xA9,0x42,0x71,0x60,0x4D,0xB9,0x89,0xCA,0x48,0x52,0xEC,0x23,0xAE,0x2E, +0x7E,0xBB,0x22,0x97,0x72,0xED,0xA9,0xE0,0x08,0xF3,0xD8,0x09,0xBB,0x53,0xD2,0x2C,0x3E,0x53,0x49,0x6C, +0x5E,0x28,0xE5,0xE2,0x62,0x99,0xEA,0xE1,0x19,0xF2,0xA5,0xCE,0xCB,0x43,0x9A,0xC1,0x59,0xB2,0x03,0x7B, +0x2F,0x1A,0xC3,0xF4,0x98,0xB1,0xD3,0x57,0x2F,0x5A,0xF2,0xD4,0x58,0xF1,0x24,0xE8,0xD1,0x0E,0xEA,0x99, +0x9D,0x3D,0xFD,0xC9,0x8D,0x44,0xFB,0xB9,0xDD,0xB8,0x1A,0xA7,0x0C,0x0C,0x19,0x44,0x9D,0x2B,0xF9,0x06, +0x9F,0x42,0xAD,0x8E,0x87,0xB1,0x58,0xDC,0x4B,0xA5,0xBA,0x82,0xF4,0x6F,0xF9,0x70,0x97,0x7D,0xBA,0x3C, +0x75,0xE6,0x16,0x29,0xEE,0x05,0x73,0xFF,0xB4,0x62,0x3B,0xEF,0x36,0x0F,0x7C,0xE9,0xD6,0x98,0x71,0xB6, +0x70,0x90,0xCB,0xE4,0x44,0x20,0x78,0x75,0x13,0x3F,0xDF,0x9F,0xFF,0xD3,0x04,0x80,0x78,0xF8,0x84,0x7C, +0xB2,0xCB,0xAB,0x94,0x87,0x42,0xEC,0x83,0x13,0x58,0xDE,0xB0,0x26,0xE9,0x0C,0x1E,0x4A,0x38,0xA6,0x38, +0x24,0x58,0xE4,0x93,0x12,0x69,0x4F,0x28,0x82,0x11,0x85,0x79,0x10,0x70,0xAE,0x15,0x07,0x42,0xED,0x82, +0x93,0x18,0x02,0x1D,0xDA,0x02,0xD6,0x95,0xCE,0x33,0x1C,0x33,0xE8,0xBE,0xE5,0x92,0x10,0x7C,0xF3,0xC1, +0xAF,0x18,0xC4,0xFC,0xCE,0x64,0xBB,0x0E,0xE7,0xF3,0x60,0x9B,0xD1,0xC9,0xAA,0x21,0xE9,0x55,0x49,0x50, +0x33,0xA4,0xDD,0xF7,0x14,0x51,0xBC,0xB0,0x4E,0x7A,0x2D,0xDF,0x64,0xE2,0x05,0xC5,0xC2,0xC3,0x73,0xEC, +0x66,0xF2,0x11,0x60,0xB1,0x85,0x13,0x43,0xA7,0x9A,0xEB,0xDC,0x37,0x93,0x82,0xE1,0x64,0x50,0x4D,0xEB, +0xE3,0x83,0xD9,0x89,0x2E,0x78,0x5D,0x0E,0x3E,0x78,0x4C,0x47,0xCB,0x5C,0xF6,0xE8,0x0C,0xF5,0x6E,0x58, +0xE7,0x92,0x74,0x94,0xC4,0xF6,0x26,0xC8,0x24,0x50,0xE6,0x3E,0x7A,0x9F,0x19,0xFB,0x43,0x18,0x54,0x65, +0xBE,0xE7,0xEC,0x2B,0x68,0x9B,0xEF,0x2F,0xF9,0x22,0x0D,0x7B,0x2B,0x33,0x04,0xFD,0xA9,0x3D,0x9B,0xBD, +0xE1,0x55,0xA7,0xCD,0xB5,0x72,0x38,0x56,0xC1,0xEA,0xC7,0xCB,0x9B,0x59,0xE6,0x5A,0x44,0x19,0xD3,0x2A, +0x90,0x30,0x2D,0x2B,0xCF,0xB2,0x23,0x36,0xBE,0x3A,0xB1,0x0A,0x6D,0x5D,0x76,0x5F,0x04,0x7C,0x19,0x52, +0xBA,0xB1,0x38,0x49,0xBA,0xAF,0xA1,0x4C,0x6F,0x59,0x27,0x69,0xBA,0xD6,0xF9,0x28,0x43,0x4F,0x27,0x7E, +0xBD,0x5F,0x08,0x27,0x12,0x21,0x1F,0xFD,0x8B,0xF2,0x7E,0x1F,0x54,0x2B,0xFF,0x86,0x67,0xA0,0x50,0x62, +0x59,0x4B,0xE9,0xA3,0xA9,0x21,0xD7,0x16,0x05,0x59,0x68,0x12,0x63,0xBA,0x67,0x32,0x36,0xCD,0x42,0x3E, +0xB0,0xF3,0x04,0x03,0xEF,0xA6,0x7E,0x07,0xE3,0xA4,0x35,0xC1,0xFB,0xC6,0x4B,0xAF,0x21,0x21,0x96,0xEE, +0x95,0xE0,0x69,0x69,0x72,0xB3,0xE6,0x33,0xB2,0xCB,0x33,0x57,0xC5,0xE5,0x9F,0xBC,0x00,0xC4,0x0D,0x3C, +0x93,0xA3,0x98,0xD1,0xC3,0x83,0x4F,0x3D,0xAF,0x6E,0x13,0xAD,0xF0,0xC7,0xE9,0x49,0x0F,0x31,0xB8,0x72, +0x37,0x30,0xCA,0x89,0xD5,0xAD,0xDB,0x31,0x39,0x39,0x09,0xE4,0xB2,0x72,0xD9,0xC0,0xB9,0xB5,0x75,0x96, +0x75,0xE4,0xED,0x66,0x66,0x78,0x68,0x4C,0x8B,0xE9,0x39,0xF7,0xC7,0x56,0xD9,0x15,0x60,0x82,0xC2,0xBC, +0x8B,0x8F,0x1D,0xF8,0x49,0xA1,0xF2,0x2E,0xDE,0x73,0xBE,0x59,0x3F,0x97,0xBA,0x1E,0x10,0x0B,0xF0,0xF1, +0xBE,0xAD,0x3A,0xC6,0xCC,0x8B,0x9A,0x0A,0x3E,0x21,0x8B,0xA9,0x53,0x65,0xA2,0x8D,0x95,0x47,0x13,0xD3, +0xCC,0x31,0xCB,0x2D,0x2B,0xEC,0xBB,0xF9,0x21,0xCA,0x50,0xF2,0xBC,0x10,0xBB,0x87,0xFE,0xA9,0xC3,0x18, +0xBE,0x73,0x99,0xCE,0x02,0x30,0x94,0x08,0xB8,0xEE,0xC5,0x62,0x48,0xCC,0xCA,0xBE,0x83,0x93,0x68,0x63, +0x09,0x8D,0x35,0x5A,0x19,0xAD,0x7A,0x42,0x30,0xDD,0x47,0x23,0xA0,0xEB,0xA3,0x5B,0xCC,0xCC,0xE1,0x1E, +0x1B,0x89,0x60,0x54,0xD6,0x8C,0x4A,0x3E,0x7D,0x31,0x3C,0x7F,0x00,0x8D,0xF8,0x2D,0x60,0xED,0x93,0xD9, +0x4A,0xC8,0x73,0x7D,0x2A,0xE0,0x80,0xE0,0x65,0x10,0xA8,0xF1,0x57,0xCF,0x80,0xC0,0x05,0x28,0xCD,0x24, +0x7D,0x96,0x76,0x93,0x86,0x97,0xEC,0x97,0x0A,0xB5,0x54,0x95,0xC4,0x58,0xDC,0xF7,0xB9,0x7A,0x5D,0x01, +0xA1,0x63,0xDD,0x85,0x43,0x19,0x2D,0xA6,0xE0,0xF2,0x8D,0xF7,0xF0,0xFD,0xA5,0xAF,0x06,0x95,0xF2,0x97, +0xC6,0xB5,0xB2,0xD3,0xE9,0x93,0xB9,0x55,0x77,0xF9,0x1A,0xF0,0xA3,0x82,0x99,0x42,0x76,0x9E,0x49,0xA4, +0xC4,0x9A,0x0B,0x62,0x76,0x65,0x35,0xC6,0xAA,0xF6,0x53,0x46,0x16,0x85,0xDB,0xFB,0xB7,0x85,0xEF,0xC9, +0x6F,0xB7,0x5A,0x9D,0x57,0x4A,0x75,0x99,0x4F,0x6A,0x01,0xC7,0x32,0xC6,0x42,0xEF,0xF0,0xF6,0xC6,0x76, +0x72,0x89,0xEF,0x37,0xCB,0xB1,0x5A,0xFE,0x60,0x70,0xFD,0xCF,0x72,0xF0,0x6E,0x1D,0x4F,0x38,0x9C,0x71, +0xCB,0xFA,0x32,0x68,0xC0,0xD5,0x50,0xCC,0x1D,0xE8,0x74,0x9B,0x8E,0xFC,0xF5,0x9E,0x42,0xB9,0xBE,0xBB, +0xEE,0xBC,0x1A,0xDC,0x3E,0x86,0x5F,0x09,0xAD,0xC2,0x27,0x05,0xC7,0xBE,0x2D,0xFB,0xCD,0xBA,0xAF,0x45, +0x7E,0xD2,0x15,0x79,0x92,0x9F,0x74,0x1D,0xBB,0xFB,0x07,0xCB,0xF4,0xD2,0xC7,0xDD,0xBC,0xEB,0x1B,0x39, +0xF6,0x48,0xEE,0x6B,0xDF,0xB3,0xDE,0x4C,0xEB,0xFB,0x1E,0x4D,0x78,0x9C,0x86,0x50,0x0D,0x4B,0xD6,0x0E, +0xE0,0xB2,0x6D,0x88,0x90,0x9F,0x6E,0xB8,0xD5,0x06,0x44,0x3A,0x32,0xDE,0x77,0x4D,0xBB,0xD4,0xA8,0xEE, +0xE8,0xDE,0x8A,0x6B,0xBE,0xD4,0x10,0xA8,0x45,0x37,0x8F,0x9B,0xCE,0x32,0x7F,0xC3,0x13,0xCF,0xF9,0x7B, +0xFF,0x6E,0xDF,0x15,0x87,0x07,0x80,0x04,0x10,0x20,0x10,0x20,0x40,0x40,0x90,0x24,0x50,0x60,0xE0,0xB2, +0xA5,0x86,0x88,0x14,0x11,0x21,0x18,0x30,0x41,0x41,0x98,0x34,0x51,0x61,0xA9,0xA3,0x5F,0x5D,0x81,0x05, +0x90,0x22,0x11,0x21,0xC0,0x42,0x91,0x25,0xD0,0x62,0xE9,0x11,0x04,0x04,0x89,0x15,0x91,0x23,0x19,0x31, +0xC1,0x43,0x99,0x35,0xD1,0x63,0x40,0x40,0x02,0x04,0xC0,0x44,0x12,0x24,0x50,0x60,0x42,0x44,0xD0,0x64, +0x52,0x64,0x48,0x50,0x03,0x05,0xC8,0x54,0x13,0x25,0x58,0x70,0x43,0x45,0xD8,0x74,0x53,0x65,0x41,0x41, +0x82,0x06,0xC1,0x45,0x92,0x26,0x51,0x61,0xC2,0x46,0xD1,0x65,0xD2,0x66,0x49,0x51,0x83,0x07,0xC9,0x55, +0x93,0x27,0x59,0x71,0xC3,0x47,0xD9,0x75,0xD3,0x67,0x12,0x08,0xED,0x49,0x82,0x0C,0x18,0x28,0x12,0x28, +0x48,0x48,0x92,0x2C,0x58,0x68,0xCA,0x08,0x40,0x45,0x8A,0x1C,0x19,0x29,0x1A,0x38,0x49,0x49,0x9A,0x3C, +0x59,0x69,0xEB,0xBA,0x0D,0x4D,0x83,0x0D,0x98,0x2A,0x13,0x29,0xC8,0x4A,0x93,0x2D,0xD8,0x6A,0x7F,0xE4, +0xA8,0x49,0x8B,0x1D,0x99,0x2B,0x1B,0x39,0xC9,0x4B,0x9B,0x3D,0xD9,0x6B,0x42,0x48,0x0A,0x0C,0xC2,0x4C, +0x1A,0x2C,0x52,0x68,0x4A,0x4C,0xD2,0x6C,0x5A,0x6C,0x4A,0x58,0x0B,0x0D,0xCA,0x5C,0x1B,0x2D,0x5A,0x78, +0x4B,0x4D,0xDA,0x7C,0x5B,0x6D,0x43,0x49,0x8A,0x0E,0xC3,0x4D,0x9A,0x2E,0x53,0x69,0xCA,0x4E,0xD3,0x6D, +0xDA,0x6E,0x4B,0x59,0x8B,0x0F,0xCB,0x5D,0x9B,0x2F,0x5B,0x79,0xCB,0x4F,0xDB,0x7D,0xDB,0x6F,0x74,0x46, +0x8A,0xEF,0x84,0x84,0x30,0x30,0x14,0xA0,0x60,0x50,0x94,0xA4,0x70,0x70,0x8E,0x14,0x21,0x80,0x8C,0x94, +0x31,0x31,0x1C,0xB0,0x61,0x51,0x9C,0xB4,0x71,0x71,0x95,0xC7,0x0A,0xE9,0x85,0x85,0xB0,0x32,0x15,0xA1, +0xE0,0x52,0x95,0xA5,0xF0,0x72,0xA5,0x33,0x26,0x34,0x8D,0x95,0xB1,0x33,0x1D,0xB1,0xE1,0x53,0x9D,0xB5, +0xF1,0x73,0x44,0xC0,0x22,0x14,0xC4,0xC4,0x32,0x34,0x54,0xE0,0x62,0x54,0xD4,0xE4,0x72,0x74,0x4C,0xD0, +0x23,0x15,0xCC,0xD4,0x33,0x35,0x5C,0xF0,0x63,0x55,0xDC,0xF4,0x73,0x75,0x45,0xC1,0xA2,0x16,0xC5,0xC5, +0xB2,0x36,0x55,0xE1,0xE2,0x56,0xD5,0xE5,0xF2,0x76,0x4D,0xD1,0xA3,0x17,0xCD,0xD5,0xB3,0x37,0x5D,0xF1, +0xE3,0x57,0xDD,0xF5,0xF3,0x77,0x96,0xCE,0x82,0xE3,0x86,0x8C,0x38,0x38,0x16,0xA8,0x68,0x58,0x96,0xAC, +0x78,0x78,0xA6,0x3A,0xAE,0x3E,0x8E,0x9C,0x39,0x39,0x1E,0xB8,0x69,0x59,0x9E,0xBC,0x79,0x79,0x05,0x0D, +0xA8,0x8B,0x87,0x8D,0xB8,0x3A,0x17,0xA9,0xE8,0x5A,0x97,0xAD,0xF8,0x7A,0x9F,0xBD,0xA9,0x1B,0x8F,0x9D, +0xB9,0x3B,0x1F,0xB9,0xE9,0x5B,0x9F,0xBD,0xF9,0x7B,0x46,0xC8,0x2A,0x1C,0xC6,0xCC,0x3A,0x3C,0x56,0xE8, +0x6A,0x5C,0xD6,0xEC,0x7A,0x7C,0x4E,0xD8,0x2B,0x1D,0xCE,0xDC,0x3B,0x3D,0x5E,0xF8,0x6B,0x5D,0xDE,0xFC, +0x7B,0x7D,0x47,0xC9,0xAA,0x1E,0xC7,0xCD,0xBA,0x3E,0x57,0xE9,0xEA,0x5E,0xD7,0xED,0xFA,0x7E,0x4F,0xD9, +0xAB,0x1F,0xCF,0xDD,0xBB,0x3F,0x5F,0xF9,0xEB,0x5F,0xDF,0xFD,0xFB,0x7F,0x20,0x3A,0x81,0x87,0xA0,0x06, +0x14,0xA0,0x30,0x22,0x44,0xC0,0xB0,0x26,0x54,0xE0,0x55,0x96,0x45,0xAB,0xA8,0x16,0x15,0xA1,0x38,0x32, +0x45,0xC1,0xB8,0x36,0x55,0xE1,0xC9,0xA0,0x82,0xE2,0xA1,0x07,0x94,0xA2,0x31,0x23,0xC4,0xC2,0xB1,0x27, +0xD4,0xE2,0xB9,0x55,0x2F,0x78,0xA9,0x17,0x95,0xA3,0x39,0x33,0xC5,0xC3,0xB9,0x37,0xD5,0xE3,0x60,0x42, +0x06,0x84,0xE0,0x46,0x16,0xA4,0x70,0x62,0x46,0xC4,0xF0,0x66,0x56,0xE4,0x68,0x52,0x07,0x85,0xE8,0x56, +0x17,0xA5,0x78,0x72,0x47,0xC5,0xF8,0x76,0x57,0xE5,0x61,0x43,0x86,0x86,0xE1,0x47,0x96,0xA6,0x71,0x63, +0xC6,0xC6,0xF1,0x67,0xD6,0xE6,0x69,0x53,0x87,0x87,0xE9,0x57,0x97,0xA7,0x79,0x73,0xC7,0xC7,0xF9,0x77, +0xD7,0xE7,0x24,0x8E,0x0C,0x19,0xA2,0x0E,0x1C,0xA8,0x32,0x2A,0x4C,0xC8,0xB2,0x2E,0x5C,0xE8,0x9A,0xA8, +0x23,0xC5,0xAA,0x1E,0x1D,0xA9,0x3A,0x3A,0x4D,0xC9,0xBA,0x3E,0x5D,0xE9,0xFC,0x03,0x0B,0x8D,0xA3,0x0F, +0x9C,0xAA,0x33,0x2B,0xCC,0xCA,0xB3,0x2F,0xDC,0xEA,0x5B,0xC4,0x62,0xC7,0xAB,0x1F,0x9D,0xAB,0x3B,0x3B, +0xCD,0xCB,0xBB,0x3F,0xDD,0xEB,0x62,0x4A,0x0E,0x8C,0xE2,0x4E,0x1E,0xAC,0x72,0x6A,0x4E,0xCC,0xF2,0x6E, +0x5E,0xEC,0x6A,0x5A,0x0F,0x8D,0xEA,0x5E,0x1F,0xAD,0x7A,0x7A,0x4F,0xCD,0xFA,0x7E,0x5F,0xED,0x63,0x4B, +0x8E,0x8E,0xE3,0x4F,0x9E,0xAE,0x73,0x6B,0xCE,0xCE,0xF3,0x6F,0xDE,0xEE,0x6B,0x5B,0x8F,0x8F,0xEB,0x5F, +0x9F,0xAF,0x7B,0x7B,0xCF,0xCF,0xFB,0x7F,0xDF,0xEF,0x24,0x82,0x24,0x90,0xA4,0x86,0x34,0xB0,0x34,0xA2, +0x64,0xD0,0xB4,0xA6,0x74,0xF0,0x2C,0x92,0x25,0x91,0xAC,0x96,0x35,0xB1,0x3C,0xB2,0x65,0xD1,0xBC,0xB6, +0x75,0xF1,0x25,0x83,0xA4,0x92,0xA5,0x87,0xB4,0xB2,0x35,0xA3,0xE4,0xD2,0xB5,0xA7,0xF4,0xF2,0x2D,0x93, +0xA5,0x93,0xAD,0x97,0xB5,0xB3,0x3D,0xB3,0xE5,0xD3,0xBD,0xB7,0xF5,0xF3,0x64,0xC2,0x26,0x94,0xE4,0xC6, +0x36,0xB4,0x74,0xE2,0x66,0xD4,0xF4,0xE6,0x76,0xF4,0x6C,0xD2,0x27,0x95,0xEC,0xD6,0x37,0xB5,0x7C,0xF2, +0x67,0xD5,0xFC,0xF6,0x77,0xF5,0x65,0xC3,0xA6,0x96,0xE5,0xC7,0xB6,0xB6,0x75,0xE3,0xE6,0xD6,0xF5,0xE7, +0xF6,0xF6,0x6D,0xD3,0xA7,0x97,0xED,0xD7,0xB7,0xB7,0x7D,0xF3,0xE7,0xD7,0xFD,0xF7,0xF7,0xF7,0x26,0x8A, +0x2C,0x98,0xA6,0x8E,0x3C,0xB8,0x36,0xAA,0x6C,0xD8,0xB6,0xAE,0x7C,0xF8,0x2E,0x9A,0x2D,0x99,0xAE,0x9E, +0x3D,0xB9,0x3E,0xBA,0x6D,0xD9,0xBE,0xBE,0x7D,0xF9,0x27,0x8B,0xAC,0x9A,0xA7,0x8F,0xBC,0xBA,0x37,0xAB, +0xEC,0xDA,0xB7,0xAF,0xFC,0xFA,0x2F,0x9B,0xAD,0x9B,0xAF,0x9F,0xBD,0xBB,0x3F,0xBB,0xED,0xDB,0xBF,0xBF, +0xFD,0xFB,0x66,0xCA,0x2E,0x9C,0xE6,0xCE,0x3E,0xBC,0x76,0xEA,0x6E,0xDC,0xF6,0xEE,0x7E,0xFC,0x6E,0xDA, +0x2F,0x9D,0xEE,0xDE,0x3F,0xBD,0x7E,0xFA,0x6F,0xDD,0xFE,0xFE,0x7F,0xFD,0x67,0xCB,0xAE,0x9E,0xE7,0xCF, +0xBE,0xBE,0x77,0xEB,0xEE,0xDE,0xF7,0xEF,0xFE,0xFE,0x6F,0xDB,0xAF,0x9F,0xEF,0xDF,0xBF,0xBF,0x7F,0xFB, +0xEF,0xDF,0xFF,0xFF,0x8F,0x95,0x80,0x00,0x0C,0x4C,0x8C,0x73,0x73,0x5F,0x62,0x04,0x64,0xCD,0xAA,0xD7, +0x86,0xCF,0x51,0xEF,0xE0,0xCE,0xC0,0x83,0x72,0xCE,0x67,0xC8,0xC0,0xBE,0xE6,0xAE,0xBA,0xA4,0xB6,0x85, +0x8C,0xD6,0xF9,0x07,0x67,0x24,0x6F,0xA1,0xFF,0x4B,0x76,0xD4,0x0A,0x72,0x60,0xEA,0xEA,0x06,0xF1,0x97, +0x94,0xF2,0xC2,0x13,0xC7,0x63,0xE7,0x02,0xBA,0xC6,0x30,0x66,0xE0,0x67,0x67,0x4D,0x95,0x83,0x76,0x68, +0xCE,0x49,0xA4,0x40,0xD7,0x43,0x38,0x8F,0xE0,0x47,0x12,0x12,0xB9,0xDE,0x4B,0xBF,0xF0,0x09,0xCB,0x32, +0xF1,0x2B,0xF1,0xF6,0xAC,0x4A,0x69,0xE3,0x94,0x46,0xE5,0x9E,0xC4,0x46,0x0E,0x75,0xD4,0x66,0x49,0xE8, +0x54,0xBA,0xD9,0xD1,0x93,0xB6,0x29,0xB7,0x69,0x05,0xAD,0x51,0xF7,0x67,0xA9,0xE0,0x08,0xF3,0xB8,0xEE, +0x9A,0x20,0x3F,0xD1,0x69,0xD3,0x13,0xDF,0xB8,0x24,0xE5,0xE2,0x62,0x99,0x6E,0x7E,0x58,0x69,0x32,0xBC, +0x41,0xB0,0x31,0xD4,0x1D,0x05,0x03,0x7B,0x2F,0x1A,0x0A,0xEF,0x1A,0x02,0x13,0xD4,0xC8,0x91,0xF2,0x56, +0x0D,0xF7,0x24,0xE8,0xD1,0x0E,0xF3,0x9F,0x90,0xCF,0x42,0xBD,0x3C,0x84,0x4F,0x63,0xF7,0xB7,0xAF,0x23, +0x8F,0x0B,0xF8,0xB3,0x1C,0x2C,0xD6,0x44,0x4C,0x2C,0xD2,0x6C,0x5A,0x6C,0x4B,0x47,0x13,0x99,0xCA,0x64, +0xE7,0x1D,0xF1,0x07,0x09,0x44,0xDA,0x7C,0x5B,0x6D,0xAB,0xEA,0xAE,0xDA,0xD0,0x72,0x8A,0x6C,0xF3,0x4D, +0x1F,0xF3,0xD3,0x6D,0xDA,0x6E,0xCA,0x42,0x97,0x41,0x0B,0x5D,0xEB,0x63,0x5E,0x69,0xE8,0xBE,0xDB,0x7D, +0xDB,0x6F,0x04,0x80,0x78,0xF8,0x3E,0x64,0x8F,0x72,0x3C,0x24,0x68,0xA9,0x3B,0xFA,0xC5,0xAC,0xDE,0xB0, +0x26,0xE9,0xD4,0xA4,0x37,0x51,0x1D,0xCF,0x86,0x57,0x0C,0xAA,0x61,0x85,0x4F,0x28,0x82,0x11,0x85,0x2C, +0x91,0xF3,0x4C,0x25,0x15,0x9D,0xFD,0x67,0x76,0x87,0x02,0x1D,0xDA,0x02,0x57,0xE7,0x0E,0x8C,0x55,0x26, +0x82,0x9C,0x98,0xAF,0xE5,0xC7,0x64,0x3C,0x32,0x5A,0xB4,0xE4,0x32,0xF9,0x1E,0x1B,0xC1,0xA8,0xD4,0xE4, +0x72,0x74,0xE4,0x72,0xF4,0xFA,0x3C,0x50,0x3F,0xFE,0x34,0x72,0x62,0x36,0xDC,0xF4,0x73,0x75,0x35,0xE7, +0x40,0x75,0x55,0x03,0x58,0x7A,0xEE,0xBE,0xE4,0x16,0xD5,0xE5,0xF2,0x76,0x8D,0xD1,0xD9,0xE9,0x65,0x76, +0xCC,0x3E,0x07,0xF0,0x40,0x16,0xDD,0xF5,0xF3,0x77,0xD9,0x89,0x2E,0x58,0xFD,0x73,0xCF,0x7A,0x6E,0x2A, +0x69,0x20,0x13,0x6A,0x92,0x34,0x36,0x70,0x6B,0xD6,0xF1,0x66,0xC6,0xE6,0x3E,0x41,0x69,0xC2,0x4B,0x38, +0x79,0xE8,0xE5,0x0B,0xAB,0xFC,0x07,0x18,0x59,0x45,0x4D,0xA8,0x4B,0x21,0x67,0xEB,0x52,0x81,0x55,0x6B, +0x0A,0x1D,0x4F,0x99,0xAA,0xB6,0x37,0x44,0xE9,0x80,0x28,0x3D,0xFF,0x7B,0x3E,0x07,0xDB,0x50,0x06,0xCC, +0x4A,0x70,0x79,0x97,0xB3,0xE1,0xD6,0xEC,0x7A,0x7C,0xED,0xD0,0xF7,0x2D,0x4A,0xF0,0x3D,0x5D,0x1E,0xCA, +0x94,0x5B,0xDE,0xFC,0x7B,0x7D,0x37,0x0F,0x00,0x5F,0xB7,0x0B,0x10,0x7C,0x1D,0xEC,0x81,0x51,0xD7,0xED, +0xFA,0x7E,0x6C,0xD5,0x73,0x6F,0x6F,0xF9,0x3E,0x18,0xD7,0xFB,0x4A,0x00,0xDF,0xFD,0xFB,0x7F,0x7E,0x1F, +0x54,0x2B,0xFA,0x07,0xB7,0xA6,0x31,0x5D,0xA3,0xC4,0xD9,0xCD,0xBF,0x54,0xD7,0x16,0x05,0x59,0xD0,0x94, +0x1C,0xC5,0x22,0x3A,0x66,0x59,0x38,0xF0,0xC7,0xE2,0x04,0x03,0xEF,0xA6,0xE9,0x90,0xF7,0xBD,0xFD,0xCB, +0x86,0x0F,0x12,0x3D,0xBF,0x96,0x96,0xEE,0x95,0xE0,0x91,0xC7,0x2A,0xAC,0x67,0xB3,0xCD,0xB8,0x5A,0xCC, +0x3C,0x44,0x16,0x04,0xA0,0xC8,0x90,0x80,0xBC,0xE6,0x10,0x22,0x68,0x49,0xF0,0x66,0x56,0xE4,0x68,0x6A, +0xE6,0x7A,0x48,0x72,0x92,0x82,0xB4,0x10,0x04,0x3B,0xF8,0x76,0x57,0xE5,0x15,0xBE,0x8A,0xC4,0x65,0x6B, +0x90,0xC6,0x09,0x47,0x44,0x8E,0xF1,0x67,0xD6,0xE6,0xA9,0x53,0xF7,0x72,0x36,0x46,0x91,0xA7,0x01,0xF1, +0xC2,0x5E,0xF9,0x77,0xD7,0xE7,0xC2,0xBC,0x8B,0x8F,0x9A,0x5E,0x0C,0xA7,0x12,0xD1,0x3F,0xC4,0xBC,0x9C, +0x7F,0x28,0xBA,0x1E,0x10,0x0B,0xD7,0xFC,0x2E,0x8B,0x17,0xC3,0xCD,0x52,0x9A,0x2E,0xE9,0x3E,0x8B,0xA9, +0x53,0x65,0xC3,0xCF,0x52,0x21,0xCC,0xD5,0xCA,0xEA,0xE9,0x75,0x6B,0x95,0xBB,0xF9,0x21,0xCA,0x71,0x1E, +0xAE,0x89,0x3B,0xC6,0xCD,0x10,0x0E,0x80,0x00,0x96,0x63,0xCE,0x0E,0x1D,0xF1,0xB3,0x52,0xE2,0x48,0x88, +0xCC,0x84,0xF2,0x6E,0x5E,0xEC,0x79,0x49,0x13,0xC9,0x13,0x98,0xBD,0xE8,0x1A,0x3E,0x40,0xC0,0xFA,0x7E, +0x5F,0xED,0xD4,0x42,0x88,0x8E,0x93,0x09,0x3C,0x50,0x6E,0x89,0x62,0xC1,0xF3,0x6F,0xDE,0xEE,0x4D,0x57, +0x03,0x74,0x99,0xD9,0x9F,0xE3,0x31,0x85,0x6C,0xC2,0xFB,0x7F,0xDF,0xEF,0x28,0x85,0x85,0x18,0x5B,0x78, +0x32,0xF0,0x3C,0x26,0x6C,0xEC,0xA7,0x99,0x64,0xB2,0xBB,0x62,0x2D,0x9E,0x6C,0x93,0x62,0xF3,0xE3,0xB2, +0x12,0xDD,0x7C,0xB6,0x05,0x0A,0x27,0x61,0x26,0xDA,0x5E,0x03,0xB8,0x1A,0x6A,0xA1,0x97,0xD2,0xB5,0x9F, +0x08,0xC2,0x4D,0xD7,0xD1,0x9C,0xAD,0x2E,0x91,0xDD,0xFD,0xB2,0x98,0xC8,0xBC,0x71,0x57,0xBF,0x8C,0x71, +0xA3,0xD3,0x3B,0xD7,0x30,0xB4,0xC0,0x80,0x25,0x28,0xF4,0xE6,0x76,0xF4,0x18,0x2F,0x23,0xD7,0x9C,0xF0, +0xD5,0xD6,0x87,0x9D,0x3A,0x2A,0xFC,0xF6,0x77,0xF5,0xA5,0xC6,0xC1,0xDA,0xF6,0x3A,0xA6,0xF8,0x88,0x8D, +0xAF,0xD9,0xF5,0xE7,0xF6,0xF6,0x6D,0xEB,0x46,0x68,0x45,0x75,0x68,0x58,0x1D,0xB7,0x67,0x0A,0xFD,0xF7, +0xF7,0xF7,0x46,0x4A,0xE2,0x13,0xE6,0xB1,0x34,0xD4,0xF2,0xD5,0x08,0x17,0xC6,0x71,0xCB,0xB4,0xA7,0x6A, +0x25,0x96,0x09,0x09,0x56,0x1F,0x67,0x3F,0x88,0xCB,0x98,0xB2,0xF1,0x22,0x59,0x69,0x2E,0x92,0x8F,0x4D, +0x68,0x7C,0x76,0xD5,0x8A,0x15,0xC1,0xBC,0xE0,0xBE,0x9B,0xE9,0x0E,0x56,0x2F,0x6E,0x7F,0xFB,0xB5,0xDB, +0xFD,0xDD,0x9F,0x42,0xBD,0xB5,0xA6,0xCA,0x5E,0x69,0x4E,0x6C,0xB9,0x9B,0x0E,0xCD,0x93,0xD3,0xF6,0xEE, +0x7E,0xFC,0xD9,0xD7,0x29,0x9D,0x31,0xCA,0x39,0xBD,0xA9,0x78,0x6A,0xA4,0xFE,0xFE,0x7F,0xFD,0xE6,0x4F, +0xAE,0x0F,0x18,0xEB,0x3B,0x99,0x48,0x6E,0xE0,0x54,0xF7,0xEF,0xFE,0xFE,0x7C,0xC8,0xB7,0xDB,0xFC,0x99, +0x1D,0xF1,0x07,0xDF,0x3B,0xCF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x80,0x04,0x10,0x20,0x10,0x20, +0x40,0x40,0x90,0x24,0x50,0x60,0x08,0x10,0x01,0x01,0x88,0x14,0x11,0x21,0x18,0x30,0x41,0x41,0x98,0x34, +0x51,0x61,0x01,0x01,0x80,0x02,0x81,0x05,0x90,0x22,0x11,0x21,0xC0,0x42,0x91,0x25,0xD0,0x62,0x09,0x11, +0x81,0x03,0x89,0x15,0x91,0x23,0x19,0x31,0xC1,0x43,0x99,0x35,0xD1,0x63,0x40,0x40,0x02,0x04,0xC0,0x44, +0x12,0x24,0x50,0x60,0x42,0x44,0xD0,0x64,0x52,0x64,0x48,0x50,0x03,0x05,0xC8,0x54,0x13,0x25,0x58,0x70, +0x43,0x45,0xD8,0x74,0x53,0x65,0x41,0x41,0x82,0x06,0xC1,0x45,0x92,0x26,0x51,0x61,0xC2,0x46,0xD1,0x65, +0xD2,0x66,0x49,0x51,0x83,0x07,0xC9,0x55,0x93,0x27,0x59,0x71,0xC3,0x47,0xD9,0x75,0xD3,0x67,0x02,0x08, +0x08,0x08,0x82,0x0C,0x18,0x28,0x12,0x28,0x48,0x48,0x92,0x2C,0x58,0x68,0x0A,0x18,0x09,0x09,0x8A,0x1C, +0x19,0x29,0x1A,0x38,0x49,0x49,0x9A,0x3C,0x59,0x69,0x03,0x09,0x88,0x0A,0x83,0x0D,0x98,0x2A,0x13,0x29, +0xC8,0x4A,0x93,0x2D,0xD8,0x6A,0x0B,0x19,0x89,0x0B,0x8B,0x1D,0x99,0x2B,0x1B,0x39,0xC9,0x4B,0x9B,0x3D, +0xD9,0x6B,0x42,0x48,0x0A,0x0C,0xC2,0x4C,0x1A,0x2C,0x52,0x68,0x4A,0x4C,0xD2,0x6C,0x5A,0x6C,0x4A,0x58, +0x0B,0x0D,0xCA,0x5C,0x1B,0x2D,0x5A,0x78,0x4B,0x4D,0xDA,0x7C,0x5B,0x6D,0x43,0x49,0x8A,0x0E,0xC3,0x4D, +0x9A,0x2E,0x53,0x69,0xCA,0x4E,0xD3,0x6D,0xDA,0x6E,0x4B,0x59,0x8B,0x0F,0xCB,0x5D,0x9B,0x2F,0x5B,0x79, +0xCB,0x4F,0xDB,0x7D,0xDB,0x6F,0x04,0x80,0x20,0x10,0x84,0x84,0x30,0x30,0x14,0xA0,0x60,0x50,0x94,0xA4, +0x70,0x70,0x0C,0x90,0x21,0x11,0x8C,0x94,0x31,0x31,0x1C,0xB0,0x61,0x51,0x9C,0xB4,0x71,0x71,0x05,0x81, +0xA0,0x12,0x85,0x85,0xB0,0x32,0x15,0xA1,0xE0,0x52,0x95,0xA5,0xF0,0x72,0x0D,0x91,0xA1,0x13,0x8D,0x95, +0xB1,0x33,0x1D,0xB1,0xE1,0x53,0x9D,0xB5,0xF1,0x73,0x44,0xC0,0x22,0x14,0xC4,0xC4,0x32,0x34,0x54,0xE0, +0x62,0x54,0xD4,0xE4,0x72,0x74,0x4C,0xD0,0x23,0x15,0xCC,0xD4,0x33,0x35,0x5C,0xF0,0x63,0x55,0xDC,0xF4, +0x73,0x75,0x45,0xC1,0xA2,0x16,0xC5,0xC5,0xB2,0x36,0x55,0xE1,0xE2,0x56,0xD5,0xE5,0xF2,0x76,0x4D,0xD1, +0xA3,0x17,0xCD,0xD5,0xB3,0x37,0x5D,0xF1,0xE3,0x57,0xDD,0xF5,0xF3,0x77,0x06,0x88,0x28,0x18,0x86,0x8C, +0x38,0x38,0x16,0xA8,0x68,0x58,0x96,0xAC,0x78,0x78,0x0E,0x98,0x29,0x19,0x8E,0x9C,0x39,0x39,0x1E,0xB8, +0x69,0x59,0x9E,0xBC,0x79,0x79,0x07,0x89,0xA8,0x1A,0x87,0x8D,0xB8,0x3A,0x17,0xA9,0xE8,0x5A,0x97,0xAD, +0xF8,0x7A,0x0F,0x99,0xA9,0x1B,0x8F,0x9D,0xB9,0x3B,0x1F,0xB9,0xE9,0x5B,0x9F,0xBD,0xF9,0x7B,0x46,0xC8, +0x2A,0x1C,0xC6,0xCC,0x3A,0x3C,0x56,0xE8,0x6A,0x5C,0xD6,0xEC,0x7A,0x7C,0x4E,0xD8,0x2B,0x1D,0xCE,0xDC, +0x3B,0x3D,0x5E,0xF8,0x6B,0x5D,0xDE,0xFC,0x7B,0x7D,0x47,0xC9,0xAA,0x1E,0xC7,0xCD,0xBA,0x3E,0x57,0xE9, +0xEA,0x5E,0xD7,0xED,0xFA,0x7E,0x4F,0xD9,0xAB,0x1F,0xCF,0xDD,0xBB,0x3F,0x5F,0xF9,0xEB,0x5F,0xDF,0xFD, +0xFB,0x7F,0x20,0x02,0x04,0x80,0xA0,0x06,0x14,0xA0,0x30,0x22,0x44,0xC0,0xB0,0x26,0x54,0xE0,0x28,0x12, +0x05,0x81,0xA8,0x16,0x15,0xA1,0x38,0x32,0x45,0xC1,0xB8,0x36,0x55,0xE1,0x21,0x03,0x84,0x82,0xA1,0x07, +0x94,0xA2,0x31,0x23,0xC4,0xC2,0xB1,0x27,0xD4,0xE2,0x29,0x13,0x85,0x83,0xA9,0x17,0x95,0xA3,0x39,0x33, +0xC5,0xC3,0xB9,0x37,0xD5,0xE3,0x60,0x42,0x06,0x84,0xE0,0x46,0x16,0xA4,0x70,0x62,0x46,0xC4,0xF0,0x66, +0x56,0xE4,0x68,0x52,0x07,0x85,0xE8,0x56,0x17,0xA5,0x78,0x72,0x47,0xC5,0xF8,0x76,0x57,0xE5,0x61,0x43, +0x86,0x86,0xE1,0x47,0x96,0xA6,0x71,0x63,0xC6,0xC6,0xF1,0x67,0xD6,0xE6,0x69,0x53,0x87,0x87,0xE9,0x57, +0x97,0xA7,0x79,0x73,0xC7,0xC7,0xF9,0x77,0xD7,0xE7,0x22,0x0A,0x0C,0x88,0xA2,0x0E,0x1C,0xA8,0x32,0x2A, +0x4C,0xC8,0xB2,0x2E,0x5C,0xE8,0x2A,0x1A,0x0D,0x89,0xAA,0x1E,0x1D,0xA9,0x3A,0x3A,0x4D,0xC9,0xBA,0x3E, +0x5D,0xE9,0x23,0x0B,0x8C,0x8A,0xA3,0x0F,0x9C,0xAA,0x33,0x2B,0xCC,0xCA,0xB3,0x2F,0xDC,0xEA,0x2B,0x1B, +0x8D,0x8B,0xAB,0x1F,0x9D,0xAB,0x3B,0x3B,0xCD,0xCB,0xBB,0x3F,0xDD,0xEB,0x62,0x4A,0x0E,0x8C,0xE2,0x4E, +0x1E,0xAC,0x72,0x6A,0x4E,0xCC,0xF2,0x6E,0x5E,0xEC,0x6A,0x5A,0x0F,0x8D,0xEA,0x5E,0x1F,0xAD,0x7A,0x7A, +0x4F,0xCD,0xFA,0x7E,0x5F,0xED,0x63,0x4B,0x8E,0x8E,0xE3,0x4F,0x9E,0xAE,0x73,0x6B,0xCE,0xCE,0xF3,0x6F, +0xDE,0xEE,0x6B,0x5B,0x8F,0x8F,0xEB,0x5F,0x9F,0xAF,0x7B,0x7B,0xCF,0xCF,0xFB,0x7F,0xDF,0xEF,0x24,0x82, +0x24,0x90,0xA4,0x86,0x34,0xB0,0x34,0xA2,0x64,0xD0,0xB4,0xA6,0x74,0xF0,0x2C,0x92,0x25,0x91,0xAC,0x96, +0x35,0xB1,0x3C,0xB2,0x65,0xD1,0xBC,0xB6,0x75,0xF1,0x25,0x83,0xA4,0x92,0xA5,0x87,0xB4,0xB2,0x35,0xA3, +0xE4,0xD2,0xB5,0xA7,0xF4,0xF2,0x2D,0x93,0xA5,0x93,0xAD,0x97,0xB5,0xB3,0x3D,0xB3,0xE5,0xD3,0xBD,0xB7, +0xF5,0xF3,0x64,0xC2,0x26,0x94,0xE4,0xC6,0x36,0xB4,0x74,0xE2,0x66,0xD4,0xF4,0xE6,0x76,0xF4,0x6C,0xD2, +0x27,0x95,0xEC,0xD6,0x37,0xB5,0x7C,0xF2,0x67,0xD5,0xFC,0xF6,0x77,0xF5,0x65,0xC3,0xA6,0x96,0xE5,0xC7, +0xB6,0xB6,0x75,0xE3,0xE6,0xD6,0xF5,0xE7,0xF6,0xF6,0x6D,0xD3,0xA7,0x97,0xED,0xD7,0xB7,0xB7,0x7D,0xF3, +0xE7,0xD7,0xFD,0xF7,0xF7,0xF7,0x26,0x8A,0x2C,0x98,0xA6,0x8E,0x3C,0xB8,0x36,0xAA,0x6C,0xD8,0xB6,0xAE, +0x7C,0xF8,0x2E,0x9A,0x2D,0x99,0xAE,0x9E,0x3D,0xB9,0x3E,0xBA,0x6D,0xD9,0xBE,0xBE,0x7D,0xF9,0x27,0x8B, +0xAC,0x9A,0xA7,0x8F,0xBC,0xBA,0x37,0xAB,0xEC,0xDA,0xB7,0xAF,0xFC,0xFA,0x2F,0x9B,0xAD,0x9B,0xAF,0x9F, +0xBD,0xBB,0x3F,0xBB,0xED,0xDB,0xBF,0xBF,0xFD,0xFB,0x66,0xCA,0x2E,0x9C,0xE6,0xCE,0x3E,0xBC,0x76,0xEA, +0x6E,0xDC,0xF6,0xEE,0x7E,0xFC,0x6E,0xDA,0x2F,0x9D,0xEE,0xDE,0x3F,0xBD,0x7E,0xFA,0x6F,0xDD,0xFE,0xFE, +0x7F,0xFD,0x67,0xCB,0xAE,0x9E,0xE7,0xCF,0xBE,0xBE,0x77,0xEB,0xEE,0xDE,0xF7,0xEF,0xFE,0xFE,0x6F,0xDB, +0xAF,0x9F,0xEF,0xDF,0xBF,0xBF,0x7F,0xFB,0xEF,0xDF,0xFF,0xFF,0x9C,0x67,0x80,0x00,0x55,0x40,0xE0,0x44, +0x0D,0xAB,0x69,0xF0,0x0C,0xC1,0xE8,0xA6,0x59,0xE0,0x4C,0xB4,0x25,0x41,0x01,0x84,0xB2,0x27,0x32,0xE0, +0x1D,0xC9,0xC0,0x30,0x58,0x2B,0x01,0x85,0x86,0x02,0x01,0xE7,0x12,0x2A,0x12,0x6B,0x4D,0x21,0xE9,0xA1, +0x9A,0xEF,0x09,0x05,0x22,0x66,0x01,0x28,0x32,0x25,0x09,0x7B,0x4D,0x4B,0x81,0x31,0xD8,0x29,0x57,0xAF, +0xB5,0xBB,0x00,0xD0,0x82,0xF0,0x8B,0x62,0x3D,0xC4,0x5C,0x2C,0x9A,0xEC,0x0D,0x9C,0xE2,0x7A,0x4F,0x50, +0x3A,0x53,0x8C,0x56,0xAD,0x26,0xF8,0xF5,0xDC,0xC8,0x3A,0xBE,0x75,0x44,0x4D,0x5A,0xD3,0x27,0xB9,0xC3, +0x66,0xC1,0xDC,0x76,0xD7,0xAE,0xB0,0xAA,0x7C,0xD8,0xF7,0x11,0xB1,0x2A,0xF1,0xD3,0x1C,0xC8,0xD3,0xE6, +0xCE,0xCA,0x92,0x2C,0x2E,0x48,0x0A,0x30,0xF9,0x27,0x10,0xDA,0x0F,0x4C,0x6D,0xD2,0x5E,0x69,0x0A,0x18, +0x09,0x49,0xA2,0xE3,0x6E,0x2D,0x20,0x3A,0x55,0x69,0x5A,0xA1,0x29,0xE4,0xC4,0x41,0xAE,0x49,0x5E,0x2D, +0x63,0xB1,0x17,0x7D,0x2F,0xB4,0x3A,0x5F,0x27,0xB5,0x4F,0x82,0x89,0x0B,0x4B,0x19,0x96,0x90,0x9B,0x29, +0xD9,0x49,0xE5,0x05,0x32,0xDA,0x82,0xD1,0x47,0x81,0xC3,0xC8,0x14,0xB4,0x92,0x68,0x1E,0x92,0x5E,0xFF, +0x4F,0x64,0xB5,0xA6,0x0D,0x1F,0xCC,0x2F,0x1E,0x6F,0x2A,0xBE,0xE1,0x0C,0xFC,0x2C,0x46,0xCD,0xBE,0xA7, +0x71,0x91,0x89,0xAF,0x5B,0x2A,0x6C,0xA6,0x73,0x02,0x51,0x7E,0xD7,0x36,0x6C,0x2B,0x60,0x7E,0x0F,0x05, +0xD8,0xDF,0x9B,0x7D,0x63,0xC2,0x53,0x0E,0xDE,0x03,0x04,0x80,0x78,0xF8,0xE4,0x44,0xFE,0xBB,0x2C,0xC0, +0xD0,0x58,0xFF,0xD6,0x8B,0xEF,0xDE,0xB0,0x26,0xE9,0x4C,0x8C,0x5E,0x7D,0xE5,0xC2,0xEF,0x34,0x6C,0xC6, +0xCE,0x2E,0x4F,0x28,0x82,0x11,0x34,0x67,0x37,0x23,0x64,0xD3,0x6E,0x37,0x6A,0x5B,0xF6,0x00,0x02,0x1D, +0x24,0xE6,0x3A,0x11,0x91,0x30,0x64,0xC3,0x6F,0x36,0xE2,0x4F,0x0E,0xAC,0x84,0x4D,0x67,0x99,0x48,0x37, +0x3F,0x9F,0x04,0xFD,0x60,0xF9,0x8D,0xE1,0xA7,0x18,0x0C,0xA2,0x9C,0xAA,0xFE,0xE4,0x41,0x77,0x54,0xF4, +0x4A,0x90,0xA1,0x1B,0xE6,0xA8,0xBA,0x3F,0xA4,0xE4,0xBD,0xC1,0x5B,0x7E,0xDD,0xA6,0x20,0x96,0x11,0xBB, +0xFC,0x68,0x36,0x2E,0x54,0x55,0x09,0xD4,0x5A,0x5F,0xF1,0x01,0xAB,0xF1,0x74,0x8E,0x9B,0x7A,0xC6,0xA8, +0x0A,0xB3,0xE6,0xC8,0x0E,0xB5,0x3F,0xFB,0xEC,0x44,0x56,0x20,0x63,0xF5,0x21,0x69,0x40,0x1C,0x4E,0xB8, +0x31,0xC2,0x66,0x9F,0xF8,0xF5,0x65,0x38,0x6F,0xF7,0x37,0xD7,0xC3,0x93,0xFF,0xAA,0xF8,0x35,0xBE,0xFA, +0x64,0x06,0x6A,0x43,0x03,0x85,0x51,0xF8,0xC8,0xB0,0x5A,0x19,0x9D,0x7F,0xBF,0xF3,0x7C,0xF7,0xA5,0x52, +0x4E,0xC4,0x05,0xCE,0x0E,0xC8,0xBE,0xEB,0xD3,0xB4,0xDE,0x1B,0x23,0x5F,0x29,0x96,0x7C,0x1E,0x9D,0xC3, +0x55,0x53,0xF6,0x22,0x97,0x30,0x48,0xA9,0x80,0xF5,0x63,0x1E,0xF9,0xB1,0x14,0xD6,0xD0,0x8A,0xBF,0x49, +0xBC,0x01,0x95,0xFD,0x89,0x56,0x9A,0x83,0x59,0x1B,0x39,0x9F,0x0D,0x53,0x63,0x4E,0xFA,0xE2,0x61,0xA8, +0x83,0x52,0xC4,0x9F,0xBB,0x70,0x20,0x02,0x04,0xC0,0xB0,0xFE,0x14,0x5B,0x20,0x62,0xC4,0xC6,0x4D,0xC8, +0xAF,0x7F,0x28,0x12,0x05,0xC1,0xEE,0xB2,0xE8,0x79,0x3C,0xB5,0x64,0x56,0x36,0x44,0xBE,0x70,0x35,0x7F, +0x84,0x82,0xA1,0xFB,0x15,0xE0,0x25,0x37,0x25,0x19,0x4E,0xD9,0xD2,0xF0,0x29,0x87,0x85,0x83,0xB1,0x1F, +0x17,0x8B,0x8D,0xCC,0x86,0x30,0xC7,0x0E,0x6A,0xBC,0x9D,0xB9,0xF5,0x7B,0x9E,0x13,0xEA,0x4C,0x8F,0x1D, +0x39,0xD4,0x92,0x7B,0x55,0xA4,0x52,0xA1,0x3F,0xFA,0xDF,0x06,0x11,0x65,0x08,0x34,0xE5,0x3B,0x78,0x55, +0xCE,0xE3,0x9A,0xC7,0x90,0xF4,0x3A,0x47,0x66,0xCE,0xA5,0xE5,0x20,0x88,0xFD,0xDC,0xF6,0x16,0x16,0xAC, +0x81,0xA6,0xC1,0x29,0x56,0xB8,0x87,0x57,0x26,0x68,0x4E,0x68,0x76,0x6E,0x22,0x0A,0x0C,0xC8,0x1C,0xFE, +0xEF,0xA7,0x62,0x59,0x54,0x42,0xCD,0xD4,0xA3,0x37,0x2A,0x1A,0x0D,0xC9,0xFA,0x9C,0x14,0xCD,0x8E,0x5A, +0x45,0x19,0x47,0xD0,0xA6,0x76,0x23,0x9E,0x8C,0x8A,0x83,0xF1,0x9A,0xAB,0xF4,0xD5,0x2D,0xAC,0x73,0xA6, +0x0E,0x67,0x6C,0x2C,0x8D,0x8B,0x93,0xCF,0x72,0xA4,0x94,0xEB,0x4C,0x6A,0x44,0xC1,0xDB,0xD9,0x5C,0x0C, +0x36,0xC0,0xA8,0xAC,0x8F,0xB5,0x7B,0x99,0x57,0x63,0xD2,0x8E,0x5A,0xC8,0x14,0x73,0xE4,0xDC,0x6D,0x16, +0x77,0x25,0xE7,0x8E,0xB0,0x62,0xC2,0x84,0xF3,0xE0,0xF2,0x39,0x65,0x9F,0x18,0x30,0x5F,0x24,0xFA,0x98, +0xD3,0xD5,0x25,0xED,0x1B,0x97,0x15,0x76,0x74,0x70,0x95,0x0F,0x6A,0x0C,0xF3,0x68,0xCA,0x67,0x84,0x21, +0x2E,0x33,0x01,0x82,0x4F,0xB4,0xFA,0x2C,0x64,0xFE,0x90,0xEC,0xBB,0xED,0x4B,0x58,0x72,0x42,0xAC,0x92, +0x94,0x1C,0xF6,0x97,0x96,0xFD,0x94,0x9A,0x1E,0xC9,0xC2,0x8E,0xCA,0x4E,0xDA,0x87,0xA4,0xF7,0x94,0x05, +0xB5,0xFD,0xDE,0xD4,0x64,0x05,0x77,0xD5,0x1F,0x83,0xC9,0xB4,0x16,0x1E,0x1E,0x51,0x09,0xFD,0xE2,0xB2, +0xE3,0xA1,0xC6,0x48,0x02,0xB1,0x10,0x3F,0x18,0xD6,0x82,0x83,0x35,0xE4,0x66,0xC2,0x8D,0x90,0xAC,0xF2, +0xF4,0x38,0xAC,0xD6,0x8F,0x60,0x60,0x34,0x9B,0x18,0xD8,0x90,0x90,0xB0,0xC6,0x05,0x3A,0x5E,0xE5,0x59, +0x5A,0x05,0x25,0x43,0x0D,0x1B,0x4F,0x53,0x5E,0x79,0x68,0x85,0xB6,0xF9,0x3A,0x57,0xA3,0xB2,0xE7,0x35, +0x38,0x1A,0x45,0x0C,0x0E,0x7F,0x85,0xF3,0x1E,0x1F,0xC2,0xAD,0x2D,0xF8,0x95,0x0C,0x35,0x58,0xB1,0x28, +0x6F,0x3E,0xF4,0xC3,0x9D,0x87,0x2F,0x45,0xCE,0x9D,0xA2,0x8A,0x9E,0xBF,0xB1,0x38,0x64,0xBD,0x45,0x3A, +0x25,0x3C,0xDD,0x89,0xA4,0xD5,0xFD,0x9B,0x1F,0xBC,0x0F,0xDB,0x58,0xD3,0x4E,0x54,0x0F,0x05,0x3A,0xE9, +0x23,0xFE,0xA3,0x8E,0xDE,0x4B,0x07,0xEB,0xFD,0xD4,0x85,0x4C,0x8D,0x54,0xB9,0xC2,0xA9,0x9B,0xEC,0x5D, +0x27,0x11,0x60,0x88,0x0E,0xD4,0xC4,0xDE,0x0C,0xBE,0xC6,0x69,0xE7,0x6E,0xAA,0xCD,0x2E,0xE5,0x4B,0x09, +0xE3,0xD0,0x4A,0x9C,0x84,0xFB,0xCF,0x69,0x71,0xC1,0x6B,0x5C,0xAF,0xB6,0x09,0xED,0x0F,0x5D,0x33,0xEE, +0x5F,0x61,0xCF,0xC8,0xD9,0xFB,0xC9,0x96,0xA2,0x1B,0x04,0xDC,0x4E,0x60,0x55,0x92,0x1E,0x54,0x78,0x01, +0x06,0xC0,0xEE,0x76,0x23,0xB9,0x68,0x04,0xA9,0x88,0x69,0xC9,0x58,0x7B,0x1E,0x72,0xFE,0xDC,0xEA,0x10, +0x10,0x61,0x5C,0x10,0x41,0x91,0x9C,0xC8,0x51,0x9A,0x38,0xFF,0x69,0x0D,0x7B,0x76,0xD9,0x4E,0xBD,0xB3, +0x84,0x48,0x88,0xDD,0x15,0xD9,0xC9,0x94,0x9A,0x9E,0xBD,0x3B,0x70,0x8C,0xD9,0xB4,0xD5,0x95,0x1D,0xB1, +0x95,0x35,0x60,0x30,0x9A,0x40,0xB8,0x76,0xC3,0x50,0x7E,0x66,0xD3,0xD8,0x56,0x73,0x54,0x84,0xB2,0x58, +0xDC,0x5A,0xF5,0x4A,0xB0,0xA0,0xE1,0xAE,0xF2,0x41,0x3C,0x53,0x9A,0x01,0xE0,0x46,0x23,0x63,0xB9,0x77, +0xE2,0xB9,0x7F,0x66,0x13,0xB8,0x77,0x17,0xFD,0xEB,0x69,0x99,0x1B,0x43,0xDA,0xAF,0x07,0x28,0xB4,0x7A, +0x47,0x13,0xF7,0x97,0x1A,0x03,0x7A,0x2F,0xF1,0x07,0x0A,0xAC,0x04,0xA8,0x5A,0x20,0xA9,0xE7,0xAC,0x68, +0x79,0x38,0x78,0x0D,0x8A,0x67,0x4A,0x98,0xA0,0x24,0x90,0xC7,0x6B,0x49,0x18,0xCD,0x1C,0x96,0x05,0x5C, +0x61,0xE2,0xBD,0x5C,0xB9,0x88,0x1A,0xDA,0xD1,0xE1,0x7B,0x20,0xEB,0xF3,0x6B,0x4F,0xF8,0x06,0x67,0x8F, +0xDD,0x21,0x9D,0x4A,0x8C,0x27,0xBB,0x25,0xDF,0x29,0xE3,0x4F,0xAB,0x69,0xFD,0x7E,0x6A,0xB3,0xF6,0x1A, +0xC4,0x29,0xFB,0x3F,0xDE,0x70,0x6A,0x00,0x8B,0x43,0xE5,0x76,0xB8,0x59,0x7A,0x22,0xDB,0x42,0xF4,0x9E, +0x92,0x09,0xBB,0x41,0x55,0x51,0x7A,0x53,0x39,0xAB,0xAB,0x61,0x15,0x71,0xAB,0x4A,0x13,0x0A,0x6B,0xB7, +0x0B,0xC3,0xB3,0x6F,0xE3,0xB3,0xE4,0x19,0xC3,0x9F,0xF2,0x2E,0x5F,0x73,0xC0,0x12,0x20,0x18,0x1F,0x64, +0x70,0x9F,0xB8,0x32,0x64,0x5A,0x4B,0xA1,0x76,0xB0,0xEF,0x50,0x2D,0xBA,0x26,0xFC,0x90,0xEE,0x12,0xB4, +0xE3,0x55,0x16,0x90,0x9C,0x41,0x87,0x05,0xAE,0x42,0x8B,0x87,0xC0,0x34,0x95,0x82,0x54,0xF9,0x74,0x4D, +0xCD,0xB7,0x87,0x6E,0x92,0x6A,0xED,0xC3,0xD8,0x3E,0xA8,0xD3,0x8A,0x3B,0x67,0xBD,0x2E,0x2C,0x7E,0x47, +0x8E,0x08,0x97,0x3E,0x87,0xB1,0xEB,0xFB,0xC1,0xD1,0xCC,0x9B,0xDE,0x11,0x62,0xD7,0xF2,0x1A,0xB3,0xA6, +0x41,0xAA,0x24,0xC2,0x53,0x89,0xA4,0xFC,0x18,0x31,0x6B,0xC7,0x33,0x8A,0xD2,0x9B,0xD8,0x39,0x64,0x03, +0x3F,0xC2,0x61,0xE7,0x2D,0xDD,0xF9,0x9B,0x6A,0x53,0x5D,0xBF,0x92,0xC7,0x7A,0x13,0x03,0x86,0xDD,0x8A, +0x8F,0x88,0xB4,0xDC,0x0A,0x78,0x1D,0x6C,0x18,0x3B,0x16,0x5B,0x29,0xD5,0xB6,0xF8,0x95,0x48,0x3A,0xD3, +0x3B,0xD4,0x8A,0x9E,0x2B,0x92,0xDE,0x3C,0xD4,0x54,0xBE,0x00,0xE9,0x3D,0x10,0xA9,0xE0,0x5A,0x02,0x9C, +0xD3,0x92,0x69,0xED,0x01,0x12,0x6F,0xA5,0x27,0x25,0x15,0x98,0x88,0x39,0x07,0x9C,0x39,0x59,0xB3,0x2B, +0xAD,0x51,0xBC,0xBA,0x14,0x4B,0x6F,0x92,0xE3,0x78,0xFD,0x8B,0x34,0xA3,0xAD,0xCC,0xA3,0x53,0x6D,0x49, +0x8D,0xC0,0xF0,0xDA,0x73,0x29,0x0A,0x22,0xC6,0x5F,0x26,0xAB,0xC8,0x42,0xF5,0xAF,0xFF,0x1E,0x6C,0x16, +0x13,0xC0,0xF8,0x48,0x41,0xE3,0x2E,0xCE,0x4B,0x4F,0x03,0xB6,0x2B,0x1D,0xEF,0xD7,0x27,0x92,0x30,0x17, +0x10,0x7E,0x61,0xFF,0xA1,0x1B,0xF1,0xFB,0x65,0xC2,0x42,0x40,0x86,0x4C,0xA3,0x84,0xD1,0xE9,0x52,0x36, +0x47,0xD0,0x8D,0x44,0xBF,0x28,0x20,0x0B,0x87,0x74,0xB1,0x74,0x68,0xA8,0x38,0x36,0xC0,0xC1,0x58,0x3B, +0x66,0x78,0xBC,0x61,0x46,0xE2,0x99,0xF8,0x16,0x6E,0x68,0x5B,0x80,0xC1,0x8F,0x76,0xB4,0x1D,0x8E,0xE3, +0x05,0x8C,0x7D,0x95,0x50,0x0A,0x59,0x65,0xE0,0x6E,0x03,0xF0,0x17,0xE3,0x40,0x90,0x86,0xBD,0xB1,0x77, +0xB5,0x1B,0xFB,0x02,0xCB,0xD0,0x60,0xA4,0xDA,0xEA,0x48,0xD2,0x87,0x40,0xFB,0x0D,0x7D,0xAA,0x0A,0x62, +0x47,0xCF,0xA0,0xF2,0x34,0xC5,0x41,0xA5,0x06,0xE5,0xDC,0x58,0x35,0x23,0x09,0x18,0xA6,0x86,0x51,0x8D, +0x37,0x80,0x49,0x3D,0x07,0xD1,0x92,0x38,0x43,0xA8,0x0C,0x80,0x43,0xBA,0x1D,0x97,0x8F,0x82,0x18,0x88, +0xC9,0xF1,0x9A,0xF0,0x9E,0x64,0xB8,0xC8,0xE0,0x65,0xBA,0xAB,0x6F,0x41,0x0A,0x35,0xAC,0x26,0x29,0x3E, +0x01,0xD9,0x37,0xD8,0x26,0x01,0x67,0x3F,0x6A,0x25,0x5B,0x2C,0x2F,0x8C,0x3B,0x6D,0xE9,0xA1,0x3A,0xC9, +0x60,0x67,0xE8,0x79,0xA7,0xCA,0xA5,0xE4,0x8B,0xE9,0xCB,0x49,0xAC,0xA6,0xC4,0xD3,0xBC,0x06,0xE6,0x5B, +0xAA,0xEB,0x42,0x60,0x8E,0xD2,0xD0,0xB0,0xA6,0xA3,0x60,0x6E,0xAC,0x4C,0x46,0xE9,0xED,0x67,0x4A,0xFF, +0x97,0xC9,0x45,0x0D,0xBC,0x7C,0xEE,0x2B,0xCB,0xAC,0xDB,0x79,0xBE,0x86,0x43,0x2D,0x0E,0xD2,0x5E,0x50, +0x3D,0x2B,0x73,0xAB,0x32,0xAF,0xF7,0xE8,0x35,0xAA,0xCA,0x5C,0x7E,0xD0,0xC4,0xF6,0x68,0x22,0x1B,0x6F, +0xD9,0xA4,0xA1,0x7B,0x51,0xF6,0x88,0x00,0xE1,0x49,0xB4,0x8B,0x36,0x1D,0x71,0xD1,0x61,0x92,0xCC,0x81, +0xAB,0xAF,0x86,0xEB,0x84,0x37,0xA4,0x9F,0xB7,0x7D,0x88,0xD0,0x9A,0xBF,0x46,0xBE,0xAA,0xAE,0x1D,0x10, +0xBD,0x94,0xAB,0x40,0x76,0xB2,0xF1,0x12,0x45,0x0D,0x95,0x03,0x59,0xC2,0x24,0xD3,0xA1,0xB6,0xB3,0xF5, +0xC8,0xB8,0x5B,0xE3,0x10,0x75,0x9D,0x5F,0x58,0xC3,0x80,0xE5,0xC1,0x84,0xDE,0x41,0xC5,0x3F,0x2C,0xE6, +0x2C,0xB0,0x15,0x9C,0xEC,0x59,0x59,0x30,0xDE,0xEA,0x6C,0x51,0xC0,0x3E,0xC8,0x18,0xC6,0x79,0x82,0xF0, +0x82,0x83,0x8A,0x28,0x57,0xC9,0xE1,0x40,0x4D,0x3D,0x4D,0x4B,0x45,0x97,0x55,0x6D,0xF7,0x66,0xFD,0xD8, +0x23,0xC3,0x69,0x50,0x48,0xF6,0x05,0xC2,0x44,0xD8,0x06,0x8C,0x61,0x48,0x0B,0x08,0xE9,0x61,0x26,0x7D, +0x75,0x15,0xBA,0xEA,0x20,0x0C,0x4E,0xA6,0xA3,0xA7,0x84,0xE3,0xC4,0x81,0x9C,0xAE,0x18,0x86,0xB6,0xEB, +0x25,0x91,0x9D,0xB9,0xD0,0xC9,0x19,0xDF,0x0F,0x9C,0x2F,0x7E,0x1F,0xDA,0xBB,0xB4,0xAD,0x7E,0x97,0x4F, +0x6C,0xBE,0x57,0xBC,0x44,0xA3,0xF5,0xC9,0xD7,0xB4,0x01,0xFF,0x0F,0x9B,0xC7,0x98,0x22,0xA4,0xC2,0xB0, +0x99,0x91,0xD7,0xC8,0xF6,0xD8,0x48,0xEC,0x24,0x98,0xCD,0x65,0x8D,0x0C,0x47,0x80,0xE6,0xF9,0x4E,0x5A, +0x73,0x59,0x46,0xB0,0x5D,0xD2,0x55,0x11,0x9E,0x41,0xD3,0x81,0x67,0xDA,0x9F,0x0D,0x32,0xB0,0x2F,0xEF, +0xA4,0xBA,0x99,0x0D,0x39,0x73,0x44,0x39,0x03,0x83,0x2F,0xCA,0x73,0xFD,0x46,0xDF,0x5E,0x2B,0x06,0x8D, +0x2E,0xC0,0x31,0x06,0x24,0x17,0xF3,0xFB,0x08,0x62,0x6F,0x5A,0xD6,0xDF,0x96,0x64,0x40,0xFD,0x45,0xBE, +0x01,0xB0,0x94,0x2C,0x38,0xC0,0x76,0xD2,0xD6,0xCC,0x18,0x55,0x3D,0xCC,0x01,0x42,0x3A,0x02,0x45,0x31, +0x93,0x62,0x28,0xAA,0x73,0xB2,0x7D,0xB7,0x94,0x6A,0x32,0x1E,0x22,0x87,0xB3,0xE6,0xC2,0x62,0x36,0xDE, +0x20,0xDF,0x52,0xF2,0x13,0xE3,0xEC,0xD2,0x12,0x0E,0x5B,0x32,0x14,0x46,0x90,0xE5,0x26,0x4E,0x19,0x8C, +0x56,0x08,0x03,0xE2,0x13,0x55,0x77,0xB6,0xFA,0xDF,0x17,0x6C,0x67,0xC8,0xB1,0x9F,0xB8,0x1F,0xC1,0x20, +0xF2,0xAB,0x82,0x3B,0x31,0x43,0xD1,0x00,0xB2,0xED,0x05,0x3B,0xFC,0xBA,0x19,0x45,0x87,0x2E,0x99,0x33, +0x9B,0xE5,0x00,0x08,0x24,0x0B,0x7A,0xB9,0x53,0xED,0xAD,0x56,0xD1,0x97,0xF1,0x0D,0x52,0x6A,0xEB,0x5A, +0xD9,0x77,0xDA,0x38,0xA9,0xE7,0x53,0x90,0xF4,0xF8,0xC2,0x18,0x30,0xB8,0x69,0xC7,0x43,0x52,0x45,0x2C, +0x5F,0x1B,0x3D,0xEB,0x15,0x35,0x47,0x48,0x5A,0x6A,0x83,0x73,0x35,0xD6,0xCB,0x29,0xF1,0xFB,0xF4,0x67, +0xA7,0xD4,0x54,0x19,0x9F,0x59,0x85,0x2D,0x2C,0x25,0xC0,0x7B,0xDD,0xF6,0x51,0xE8,0x0E,0x4C,0xA2,0x63, +0x10,0xA7,0xD3,0x99,0x11,0x48,0xEC,0xB5,0x3A,0xD3,0x59,0xDC,0x05,0xDC,0x70,0xDE,0xEF,0x0F,0x49,0xFA, +0x8E,0x64,0x98,0x1C,0x1C,0xEC,0x5F,0x71,0x08,0x7B,0x47,0xAF,0xA9,0xF7,0x43,0x6D,0xCE,0x67,0x8B,0x69, +0x52,0x76,0x5B,0x4D,0x87,0x0C,0xB3,0x9B,0x99,0x29,0x63,0x3E,0x09,0x0F,0xD9,0x1D,0xDF,0x4B,0xFF,0xFB, +0x0E,0xAF,0xE6,0x90,0x31,0x70,0x90,0xA9,0xDE,0xD0,0x14,0xE5,0x17,0xED,0xD8,0xDB,0x23,0xFF,0xEE,0x85, +0x30,0x71,0x76,0xAD,0x75,0x25,0x1C,0xF5,0x16,0x77,0x3E,0x24,0x53,0x2E,0x99,0xBD,0x41,0x5C,0x94,0x8B, +0xB4,0x02,0x79,0x37,0xB8,0x7A,0x0B,0x1E,0x18,0x45,0x91,0xA0,0x40,0x5F,0x5D,0xBD,0x51,0x77,0x28,0x34, +0x92,0x33,0xDF,0xB6,0xDD,0xB9,0x40,0xA4,0x3E,0x37,0x90,0x94,0x61,0x3D,0xEE,0x17,0x21,0x70,0x8B,0x54, +0x35,0xF3,0x94,0xD8,0x58,0xAF,0xC2,0x06,0x8A,0xEF,0xBE,0xE5,0x70,0xD5,0x8A,0x61,0x07,0x36,0x47,0xD9, +0x5B,0x7F,0xBD,0xED,0x03,0x4D,0x12,0x96,0xD7,0x1A,0xA5,0xC1,0x21,0xDB,0xC9,0xF5,0xF7,0xE4,0x47,0xED, +0xC0,0xCD,0x83,0x2D,0xFB,0x73,0x0E,0x9D,0xD9,0x6E,0xE4,0x88,0x3B,0x78,0x97,0xCA,0xB4,0x58,0xEE,0xDE, +0x93,0xA2,0x89,0x52,0x88,0x94,0x02,0x0E,0x3D,0x33,0x18,0xBC,0x40,0xC8,0xA0,0x64,0xBB,0x69,0x7C,0xE2, +0x3E,0x25,0x9B,0xB8,0xBE,0x58,0x17,0xA4,0x98,0x5B,0x91,0x75,0xAA,0xE8,0x22,0x77,0x48,0x87,0x0D,0x1F, +0x7C,0xC2,0x24,0x59,0xFB,0x19,0xD7,0x9D,0x10,0x01,0x1E,0xBB,0x3D,0x13,0xB8,0x14,0x13,0xB1,0x08,0x31, +0x36,0x1D,0x12,0x9F,0x5F,0x10,0xE6,0xC1,0xA9,0xD1,0x4E,0x4C,0xD2,0x54,0x3C,0xFD,0x6A,0x57,0xE0,0x21, +0x38,0xED,0xF3,0xBA,0xB5,0x11,0xD7,0xD9,0xB6,0x3D,0x0E,0x9C,0x0F,0x32,0xB5,0xF8,0xF9,0xEE,0x80,0xBB, +0xC2,0x45,0x8D,0x22,0x52,0x76,0x01,0x20,0x37,0x1E,0x1B,0x78,0xB8,0x8C,0x1F,0xA7,0xFF,0x1D,0xFB,0x74, +0x27,0x79,0x52,0xB2,0x45,0x50,0xE8,0x3F,0x76,0x00,0xD5,0x92,0xCA,0xE1,0x93,0x76,0x5D,0x2E,0xFD,0xCA, +0xC5,0x41,0xF3,0xC5,0x0E,0xA0,0xF5,0xF9,0x39,0xE1,0x5B,0x41,0xD4,0xE3,0x0B,0xD5,0x3B,0x80,0x37,0xD4, +0x83,0x42,0x4C,0x53,0xC5,0xFE,0xB1,0x13,0xBC,0x42,0x03,0xDB,0xA8,0x0C,0x51,0x33,0xF1,0x74,0xE0,0x4B, +0xEF,0x7E,0x53,0xC6,0xB7,0x2C,0x78,0x66,0x6F,0x55,0x6D,0xA3,0x09,0x7B,0xE8,0x50,0x4E,0x84,0x17,0xD2, +0x09,0x3E,0x26,0xAB,0xC7,0xC4,0x07,0xF3,0x59,0x6F,0x2B,0x46,0xF7,0x8F,0xC1,0xA5,0xB2,0x2B,0x2F,0xBA, +0xC4,0x87,0xCF,0xBA,0x95,0x76,0x6B,0x47,0x81,0xF5,0x79,0x77,0x9B,0xE7,0xF9,0xF2,0xE7,0x07,0x2E,0x33, +0x88,0x4A,0x47,0xE5,0x50,0x96,0x62,0x8B,0x78,0xA2,0x0C,0xF3,0x4A,0x28,0xB6,0x27,0xDE,0x9D,0xBA,0xF2, +0x1F,0x74,0x3C,0x9A,0x13,0x68,0x3F,0xBA,0x45,0xF9,0x52,0x2A,0x79,0x74,0x1D,0x79,0x37,0xD5,0x23,0x6E, +0xEC,0x83,0x07,0x23,0x03,0xCA,0x21,0xAB,0xD2,0x3B,0xBC,0xE4,0x78,0xE8,0xE3,0x17,0x6C,0xC7,0x6E,0x3F, +0xD5,0x90,0x17,0xAD,0xD9,0xE1,0x5B,0x0F,0x51,0x8E,0xC6,0xBA,0xF7,0x16,0xF1,0x4A,0x0E,0xBC,0x6A,0x29, +0x94,0x85,0x12,0xFA,0x0B,0x9E,0x46,0xCD,0x32,0xA7,0xFE,0xFE,0x51,0xD0,0x6F,0x0D,0x7A,0x81,0x59,0xC9, +0x4B,0xA7,0xFB,0x83,0x77,0xE7,0x4D,0xB6,0xEC,0x43,0xBB,0xC6,0xFC,0x4E,0x7B,0x4B,0xD7,0x94,0x27,0x2C, +0xC4,0x26,0xB7,0xA6,0x32,0x8D,0x99,0x7A,0xDC,0x4F,0xD9,0xA6,0x4F,0x9F,0x9F,0x64,0x10,0xB6,0xF0,0xF2, +0xA6,0xB0,0x07,0x6A,0x47,0xB0,0x97,0x37,0xD2,0x2C,0xB4,0x92,0x1C,0x50,0x06,0x41,0x36,0x5A,0x17,0x7C, +0xCE,0x5E,0x65,0xFC,0xD8,0x6D,0x0F,0xFA,0x15,0x2B,0x7D,0xA7,0xCD,0x43,0x19,0x02,0x21,0x91,0xF9,0x68, +0x74,0xF0,0xEE,0x0F,0x65,0x49,0xC2,0x31,0x20,0x29,0x70,0xA9,0xE2,0x6E,0x3C,0xD2,0x8A,0x99,0x48,0x59, +0x37,0xE4,0x64,0xF7,0x22,0xD5,0xE6,0xE2,0x9D,0x6E,0x84,0xCB,0xA5,0xE0,0xFE,0xD2,0xDC,0x2F,0xF9,0x80, +0x8C,0x0F,0xDD,0x71,0xF5,0xF6,0x7B,0x0E,0x87,0x06,0xDB,0x1A,0xF5,0xD6,0xF4,0xE6,0xC6,0x96,0xCB,0x3F, +0x74,0xB7,0x29,0x23,0xE7,0x98,0xCD,0x23,0x5E,0xED,0x03,0x2B,0x8C,0x6D,0xF8,0x15,0xD3,0xBB,0x0D,0xC0, +0x02,0x84,0x9D,0x0A,0x32,0x61,0x4E,0x8D,0xCF,0x73,0xA0,0x63,0x97,0x82,0x15,0x14,0x9C,0xAF,0xA2,0xAC, +0x75,0x63,0x75,0x7D,0xAF,0xD9,0x77,0xC4,0x3E,0x99,0x67,0x5C,0xE0,0xEC,0xC7,0xD9,0x95,0xB5,0x78,0xAA, +0xC8,0x77,0x8D,0x1E,0xEB,0x55,0x27,0x97,0x54,0xED,0x91,0x43,0x30,0x3D,0x77,0xBF,0xC4,0x4A,0x27,0x62, +0x14,0x61,0x38,0x13,0xA6,0xDD,0xCC,0x4B,0x30,0x36,0xF2,0xEE,0x38,0x12,0x74,0xCE,0x2E,0x2E,0x76,0xCE, +0xDE,0xF1,0x21,0xCF,0x6C,0x1D,0xD4,0x1A,0xCE,0x02,0x26,0x38,0x3B,0xFB,0x47,0xF7,0x47,0x04,0x63,0x3C, +0xED,0xF7,0x67,0xF2,0xCC,0xD8,0x37,0x6A,0x9B,0xF4,0x0D,0xDF,0xAE,0x7F,0xA4,0xAC,0xA0,0x6A,0xCB,0x99, +0x10,0xC4,0x4A,0xCF,0xF9,0x9D,0x93,0x73,0x5B,0x09,0x8A,0x44,0xB3,0x2D,0xD3,0x6B,0xC2,0x08,0xDA,0x25, +0x72,0x6D,0x68,0x3F,0x31,0x8C,0x00,0x03,0x72,0x01,0x60,0xB2,0x63,0x34,0x58,0xA8,0xD0,0x67,0x85,0x85, +0xA0,0xEA,0xCB,0xEA,0x33,0x24,0x35,0x43,0x83,0xFD,0x13,0xA7,0xD5,0xC2,0x57,0xF3,0x89,0x43,0xF1,0x97, +0xB3,0x83,0x21,0xE1,0x3F,0x4C,0x11,0xA1,0x70,0x9C,0xE7,0x77,0x69,0xA1,0x06,0xDC,0xFB,0xD5,0xB3,0x9B, +0xAB,0x35,0x53,0xE0,0x14,0x5A,0xE0,0xDA,0x97,0x91,0x08,0xC1,0x41,0xD0,0x66,0x5C,0x29,0x92,0x7C,0x0B, +0xF0,0xC5,0xC1,0xB0,0x62,0x46,0xD7,0x20,0xF2,0x66,0x47,0xDE,0x29,0x37,0x11,0xF1,0x37,0xC9,0xEC,0x4A, +0xE8,0x73,0x5A,0x6B,0xEB,0x92,0x27,0x5D,0x2A,0x76,0x4E,0x77,0x62,0x26,0x80,0xCE,0x8D,0xC8,0xB8,0xEE, +0x9A,0x2B,0x72,0x6C,0x69,0xC3,0xC2,0x4E,0x1C,0x6E,0x08,0xF0,0x7C,0xC9,0xCD,0xFE,0x9B,0x2A,0x9E,0xDA, +0xCB,0x01,0xB2,0x43,0xD4,0x0B,0x3D,0xD0,0x6A,0x8A,0xD6,0xEF,0x1A,0x29,0x1B,0xCB,0x64,0xC1,0x1B,0x24, +0xDE,0xB8,0x89,0x9B,0x35,0x1A,0x0E,0xFF,0x1B,0x28,0xD2,0x4B,0x6A,0x4D,0xCB,0x5F,0x9D,0x6D,0x84,0x8E, +0x98,0x0F,0xD1,0x76,0x26,0x37,0x04,0xD3,0xA1,0x7D,0x82,0x71,0x3B,0x6D,0xA8,0xAB,0xC5,0xA6,0x6D,0x60, +0xCF,0x9C,0x24,0x50,0xB7,0x3C,0x25,0x0F,0x00,0x01,0xA0,0xB2,0x6B,0xA1,0xC7,0xC9,0xD6,0x96,0x6D,0x41, +0xA0,0xD9,0x57,0xF5,0xB1,0xAF,0x2D,0x51,0x60,0x89,0xEC,0x65,0x4B,0x5E,0xE8,0x55,0x33,0x7E,0xB9,0xFD, +0xD8,0x1F,0xAB,0xFA,0xFD,0x52,0xBC,0x54,0xCB,0x3F,0x5E,0x7F,0xC3,0x56,0x77,0xBB,0xAE,0xDF,0x5C,0x88, +0x35,0x17,0xC6,0x6F,0x92,0x37,0xE7,0x52,0xCD,0x5C,0x2B,0xB2,0x85,0x15,0xC4,0x16,0x20,0x50,0xE5,0xC1, +0xE4,0x3F,0x1D,0x25,0x41,0xD8,0xF2,0x54,0x22,0x32,0xB8,0x11,0xC2,0x73,0x05,0x94,0xB7,0xE1,0x57,0x5E, +0x42,0x5E,0x3E,0x83,0x2D,0x96,0x25,0x60,0xF4,0xAB,0x68,0x5B,0x31,0x4C,0x56,0x20,0x26,0xF9,0x9B,0xD4, +0x81,0x7D,0xBF,0xFC,0xEB,0xA2,0x60,0x46,0x79,0x3F,0x5D,0x83,0x4E,0xD4,0xCE,0xE5,0x50,0x37,0x63,0x7E, +0x9E,0xB2,0x05,0x51,0x29,0xC9,0xC9,0xD1,0x19,0x52,0xD6,0x75,0xD3,0xA6,0x58,0xC2,0x51,0x06,0x4F,0xAA, +0xB5,0xF5,0x22,0x0E,0x6E,0x35,0x83,0x2C,0xB3,0x73,0x7E,0x4E,0x50,0x1C,0x70,0x0E,0x3D,0x98,0x5C,0x53, +0xCB,0x5E,0xC8,0x9F,0x7C,0xD3,0x46,0x19,0x42,0xA3,0x06,0x95,0x3F,0xEB,0xAA,0x5A,0xEB,0x51,0x3F,0xA6, +0xE5,0xCD,0xC4,0x0D,0xA6,0xD3,0x47,0x11,0x56,0x3C,0x9F,0x99,0x09,0x55,0xA5,0xA9,0x7D,0x6C,0x09,0x5C, +0xF6,0x84,0x79,0x1F,0xBC,0x8B,0xAB,0xA9,0x4A,0x5D,0xC1,0xB2,0xF3,0x35,0x60,0xFC,0xEC,0xB8,0x7C,0xCE, +0x20,0x7E,0x54,0xD9,0xCB,0xFD,0xD6,0x1D,0x1E,0x6C,0x28,0x29,0xE9,0x5D,0xAC,0xF1,0x38,0xBF,0xFE,0x8A, +0x09,0x3F,0x80,0x25,0x77,0xD6,0xD1,0x5E,0x4B,0xB1,0x05,0x06,0x45,0x52,0x6F,0xD9,0x3D,0xF1,0xF7,0xE5, +0x7D,0x3E,0xF8,0xDF,0x5F,0x7B,0x70,0xAD,0xB7,0xC0,0x21,0xFE,0xED,0xBF,0x4D,0xF1,0x33,0xBE,0xE0,0x87, +0x70,0x0D,0x36,0xE4,0x96,0x88,0xB8,0xF6,0xE7,0xC6,0x38,0x3F,0x52,0x32,0x31,0x64,0xF6,0x9A,0xD0,0x94, +0x1C,0x9C,0xE7,0xD0,0xE9,0xCC,0x0F,0x37,0xD8,0xED,0x78,0x7A,0x63,0x99,0x18,0x65,0xD7,0x1D,0xB9,0x21, +0x65,0x48,0x99,0x03,0x5B,0xE0,0xB2,0x65,0x08,0x15,0x69,0x8B,0x4C,0xA5,0x73,0xCD,0x66,0xC5,0xD1,0x29, +0xB1,0x17,0xD7,0x44,0xF2,0xE0,0xE6,0x7B,0x96,0xB8,0x0B,0xA0,0xC5,0x82,0xA0,0x67,0x46,0xA6,0x16,0xC9, +0x6C,0x13,0xBC,0xAA,0xDE,0x5E,0x3D,0x94,0x65,0xF7,0x42,0x85,0x33,0x10,0xC2,0xDD,0x5A,0x70,0xDB,0xB4, +0xB4,0x09,0xC6,0x47,0x27,0xDD,0x71,0x59,0xE5,0x9F,0xE9,0x4D,0x63,0x73,0x45,0xBA,0xE7,0x1C,0x7A,0xF1, +0x02,0x64,0x6B,0xF3,0xC7,0x41,0x6A,0x16,0x0A,0x89,0x2A,0x0A,0xBD,0x22,0x3A,0xAE,0xED,0x42,0x24,0x35, +0xD8,0x7C,0xEA,0x96,0xC3,0x7C,0x28,0x7C,0x5E,0x16,0x45,0xD8,0xE1,0xC4,0xC4,0xA9,0x36,0x4F,0xAD,0x78, +0x9B,0x75,0xDC,0xED,0x1E,0xE2,0xCE,0xC9,0x6D,0x40,0x17,0x5D,0x37,0x2C,0xE6,0x1F,0x9B,0x6D,0xD3,0x9D, +0x98,0xFB,0x71,0x84,0x6E,0xC6,0xBA,0xCC,0x1F,0x3F,0xD4,0xB9,0xE6,0x27,0x1D,0xCA,0x36,0xC3,0x4A,0x2D, +0x8C,0x6E,0xD2,0x53,0xBF,0xF7,0xCB,0x40,0x93,0x39,0x94,0x63,0x2C,0x8F,0x82,0xDA,0x11,0xD4,0x78,0x0D, +0x04,0xE4,0x51,0x4F,0x0B,0x98,0xB3,0xC6,0xE4,0x23,0x7B,0x6E,0xAD,0xEE,0x63,0x89,0xFC,0x2E,0x35,0x54, +0x83,0xC1,0x53,0xA0,0x76,0x5E,0x45,0x1E,0x40,0x49,0xE9,0x7D,0x8D,0x42,0x44,0xD4,0x7B,0x9D,0x64,0x1A, +0xDA,0x4B,0xBC,0xCE,0x85,0xDF,0xD5,0x06,0xA2,0x4F,0x52,0x5F,0x01,0x97,0xCC,0xD2,0x7B,0xBC,0x36,0xB6, +0xC6,0xD7,0x2A,0x21,0x94,0x5E,0x5B,0x4F,0x08,0x9F,0xBF,0x03,0x94,0x39,0x55,0xE2,0x60,0xDF,0x93,0x93, +0x32,0x56,0x98,0x13,0xC6,0x33,0x52,0xC5,0xBB,0xD1,0x35,0x16,0x86,0xF3,0xDB,0x46,0x37,0xB3,0xC7,0x5C, +0xFA,0x62,0x57,0x67,0x7E,0x97,0x6C,0xFD,0x12,0x00,0x68,0x62,0x34,0xBA,0x0F,0xD6,0xF3,0x50,0x4C,0xA4, +0x55,0x19,0xE9,0x80,0x8C,0x24,0x7F,0x84,0x88,0xB7,0x3B,0x58,0xA2,0x3D,0xBF,0x0C,0xC2,0x19,0x62,0xF8, +0x96,0x42,0xCB,0x3E,0x14,0x09,0xCA,0xE4,0xCC,0x32,0x93,0xD0,0x4A,0xB8,0x43,0xCE,0x6A,0x71,0x38,0x0F, +0x72,0x97,0x5E,0xCC,0x54,0xDA,0xEC,0x8B,0x1E,0xB5,0x4E,0x28,0x65,0x9C,0x01,0xA8,0x88,0x9C,0xA6,0xE2, +0xCC,0x96,0x6E,0x02,0xBC,0x44,0x5E,0x1A,0xD1,0xD4,0xE0,0x25,0x79,0x52,0x33,0xD3,0x88,0x9C,0x25,0x0D, +0xB9,0x9A,0x0F,0x7B,0x17,0xD5,0x14,0x31,0x20,0x0C,0x4F,0xDF,0x94,0xD9,0x85,0x1A,0xB3,0xD9,0x35,0xAB, +0x4E,0xD6,0xDC,0xBB,0x29,0x3E,0xE6,0x3B,0xCE,0xDC,0xE0,0xF3,0xBE,0x70,0xEA,0x2A,0x44,0x71,0x5E,0xE7, +0x4D,0xBD,0xCB,0xC1,0x44,0xE9,0xAA,0xB8,0xC0,0x10,0xC1,0xEA,0xD0,0x56,0xEA,0x27,0x4C,0x5F,0xCF,0x41, +0x3A,0x0A,0xDD,0x3C,0xC2,0xA5,0xE4,0x3B,0xE6,0x21,0xAD,0xEE,0x59,0xBE,0xAD,0x1D,0x3D,0x9C,0x78,0x98, +0x61,0xB5,0xFF,0xCA,0x93,0x9D,0x47,0xEF,0x58,0xBE,0x60,0x40,0x0E,0x0D,0x3E,0x42,0x16,0x61,0x28,0xF0, +0xF3,0x4F,0x50,0xB8,0x9E,0xCD,0x42,0xFF,0xA2,0x07,0xE8,0xB4,0x1D,0x61,0x52,0xEF,0xE2,0x47,0x7C,0xB6, +0x73,0x51,0x4B,0xFA,0x23,0x0F,0x91,0x18,0x94,0x03,0x71,0x94,0xEE,0x4F,0xDA,0xA7,0xF4,0x76,0x59,0x3E, +0x20,0x8B,0x9D,0x97,0x97,0x62,0x91,0x51,0x20,0x4C,0xE1,0xB1,0xF9,0xD8,0x50,0x9C,0x7D,0x14,0x90,0xB7, +0x96,0x89,0x30,0x20,0xFC,0xC9,0xD0,0x64,0x52,0x44,0x0B,0x23,0xA5,0xC7,0x6C,0x70,0xFA,0x5D,0x08,0x75, +0xE0,0xBE,0x27,0x74,0xAC,0x9A,0x81,0x61,0xE1,0x44,0xB9,0xF5,0x2E,0x89,0x29,0x27,0x76,0x40,0x2E,0x9A, +0xD2,0x66,0x89,0x55,0x77,0x3C,0xDF,0x37,0x6C,0x8A,0x43,0x8F,0xC5,0xB5,0x22,0x8A,0xDB,0x67,0x00,0xEA, +0xA9,0x82,0x5F,0xFC,0x79,0x27,0xA6,0xCA,0xCA,0x00,0x02,0x6A,0x50,0x2A,0x4A,0xE8,0x55,0x06,0xCA,0xDC, +0x1F,0x28,0x22,0x68,0x4D,0x46,0xEB,0x4E,0xFA,0x0C,0xFE,0xEB,0x0A,0x09,0xBD,0xD4,0x15,0xAC,0xD8,0x39, +0x6B,0x2F,0x83,0x2D,0x5A,0x62,0x6B,0xB9,0x3D,0x06,0x8E,0x08,0x9F,0x09,0x7B,0x7D,0xFE,0xC0,0x0B,0x7F, +0x78,0x67,0xDB,0x3F,0x39,0x35,0x4B,0xE9,0xED,0x40,0xF9,0xEC,0x6A,0x33,0x2D,0x93,0x5A,0x4C,0x5A,0x87, +0x30,0x54,0xC3,0x78,0xFE,0xED,0xA2,0x70,0xA2,0x5C,0xDA,0x83,0xA4,0x6D,0xD9,0xA9,0x86,0x4C,0xFD,0x04, +0x44,0x83,0x0A,0x65,0x23,0xAF,0xD3,0x92,0x25,0x91,0xF5,0xB1,0xB2,0xC6,0xD9,0xD9,0x70,0x6B,0xA3,0x86, +0x3F,0xAE,0x24,0x7D,0xDB,0x90,0xB1,0xE2,0x61,0x18,0xFC,0x75,0x6B,0xC4,0x10,0x42,0xC1,0xD8,0x08,0xE4, +0x1F,0xFD,0x34,0xC0,0x31,0x1E,0x94,0x80,0xD8,0x8B,0xDC,0x90,0x02,0x13,0xC2,0xD0,0x71,0x72,0x7D,0x03, +0x82,0xB2,0xBB,0x5C,0xD1,0x30,0x95,0x43,0x9F,0x0D,0x6A,0x21,0xD4,0xC2,0xB9,0x61,0xFD,0x1C,0x97,0x96, +0x92,0x3B,0x8D,0xE5,0xE7,0x12,0x1A,0xCD,0x74,0xE3,0x2C,0x22,0xA1,0x19,0xBA,0xC3,0x16,0xB9,0x17,0x78, +0x64,0xB6,0xD4,0xE4,0x72,0x8B,0x15,0x2D,0x84,0x57,0xF2,0x0C,0xBE,0x74,0x66,0x03,0x17,0x20,0x23,0xF4, +0x8C,0x8A,0x95,0x07,0xE8,0x9B,0xBB,0x19,0xFA,0xAC,0x09,0xC1,0xF8,0x26,0x2A,0xE5,0xF2,0x76,0x8F,0x64, +0xA5,0x36,0x61,0x50,0xD3,0x82,0x13,0x0A,0x1F,0x3E,0x19,0x1D,0xFD,0x0C,0x66,0x28,0x34,0x15,0x46,0xA8, +0x07,0xB3,0x42,0x2A,0x4A,0x19,0xCF,0xC0,0x1F,0x78,0x5E,0x19,0x4A,0xAB,0x94,0x1C,0x1A,0xBA,0x17,0xA8, +0xCA,0xD4,0xCE,0xB8,0x39,0xB2,0x4D,0x6B,0x0B,0x1C,0x6F,0x6F,0x51,0x80,0x2D,0x4B,0x6A,0x52,0xCE,0xC4, +0x9F,0x3A,0x77,0x1B,0xAC,0x71,0x4F,0x05,0xE4,0x96,0xE0,0x3D,0xCD,0xEB,0x99,0xFB,0xFD,0x80,0xF7,0x8E, +0xD6,0x50,0xB8,0xCA,0xDB,0xBF,0x96,0xC9,0xBA,0x5A,0x12,0x11,0x74,0xF8,0xB6,0x5C,0x61,0x89,0x5E,0x79, +0xCC,0xB6,0x26,0x7C,0x43,0x2E,0x1A,0x63,0x75,0xE8,0x57,0xBB,0x99,0xBC,0xE7,0x3E,0x36,0x33,0x07,0xEC, +0x89,0x7E,0x13,0xE2,0xF4,0xF8,0x94,0x8F,0xD4,0xBC,0xAF,0xE0,0x50,0x7B,0x65,0x06,0xED,0x1E,0x1B,0x52, +0xFB,0x7F,0x6A,0xE0,0x45,0x60,0xC4,0xF6,0xC4,0xAF,0x34,0xC0,0xC6,0x88,0xC8,0x64,0xD8,0xEC,0x72,0x13, +0xA6,0x87,0x58,0x82,0x13,0x33,0xE7,0x40,0xE6,0xC7,0xD0,0xB6,0x66,0xA0,0x59,0x81,0xA6,0x20,0x31,0x83, +0xB4,0x78,0x6C,0xC1,0x46,0x8A,0x11,0x65,0x57,0x49,0x79,0x96,0xE6,0x63,0x97,0xD1,0x9D,0xED,0xB1,0xCF, +0x85,0xCC,0x01,0xD7,0xDC,0xE0,0x38,0xCA,0x81,0xD6,0xDA,0xF6,0xE2,0x0B,0xB0,0xFE,0x88,0xC2,0x0F,0x99, +0xA9,0xE4,0x60,0xFD,0xE6,0x8A,0xD6,0x8A,0x98,0x23,0x00,0xF0,0x65,0x75,0xF8,0x89,0x57,0xE5,0xA1,0x67, +0x85,0x80,0x45,0x63,0xDE,0x7C,0x21,0x6A,0x2F,0xF7,0xF1,0x98,0xD6,0xE6,0x09,0x13,0x35,0x88,0x69,0x73, +0x76,0x0C,0x23,0x72,0x64,0xDC,0x06,0x88,0xD7,0xE7,0x5A,0x88,0x2E,0x18,0x63,0xC8,0x1A,0x05,0x52,0x6E, +0xCC,0xC5,0x35,0x22,0xB5,0xA1,0xA2,0xC7,0xAC,0x01,0x90,0xED,0x38,0xEB,0xEC,0x9F,0xEC,0x43,0xBC,0x5A, +0xDA,0xAB,0x79,0x0E,0x2F,0x8C,0xEC,0xBD,0x1C,0x3A,0x79,0xF4,0x6F,0xCC,0xAD,0x4A,0xFF,0xAA,0x2F,0xF9, +0x0F,0x88,0xEF,0x9C,0xFE,0x3F,0xC6,0xD9,0x6C,0x43,0x85,0x5B,0x52,0x4D,0xD6,0xBA,0x28,0x83,0x9A,0x4F, +0x1A,0x6C,0xB2,0x19,0x76,0x83,0xF2,0x91,0x5E,0xEC,0x6E,0xB8,0x8C,0x83,0xD8,0x6E,0x32,0x02,0x82,0xFE, +0x5D,0xCD,0xFA,0x81,0xA0,0xED,0x03,0x0B,0x30,0x05,0x0B,0xBE,0x3D,0xCE,0x2A,0xEE,0x27,0x9F,0x0C,0x90, +0xDE,0x11,0x03,0x5D,0x0C,0xEB,0x4B,0x2D,0xFD,0x63,0xBB,0x67,0x2B,0x8D,0x04,0x80,0xDF,0x10,0x1C,0x52, +0xD3,0x9F,0x6B,0x56,0x38,0x1F,0x0E,0x5D,0x60,0x91,0x2F,0x22,0x54,0x7B,0x4C,0xD6,0x62,0x1C,0x94,0x86, +0x96,0xBC,0x28,0x30,0x47,0x83,0x44,0x32,0x55,0xF1,0x1D,0x53,0x5F,0x9D,0xEE,0x05,0x71,0x9B,0x70,0x83, +0xE2,0x92,0xEC,0x83,0x97,0xD2,0x55,0x11,0xA0,0xC9,0x01,0x05,0xB1,0xB9,0xBD,0x92,0x67,0xC8,0x15,0x33, +0x75,0xAB,0x3F,0xC0,0x5D,0x3A,0xBE,0xF9,0x40,0x1B,0x73,0x66,0x46,0xD1,0xF4,0xF7,0x76,0xF4,0x7E,0x2E, +0xF2,0x6E,0x6E,0xA0,0xB8,0x33,0xEC,0x81,0x2E,0x7E,0xFC,0x67,0x77,0xF5,0xB8,0xEF,0xA0,0x44,0x41,0xE3, +0x85,0x0F,0xDD,0x67,0x61,0x23,0xF5,0xF2,0xF6,0xF6,0xFB,0x2B,0x27,0x2C,0x69,0xF3,0xDF,0xBA,0x05,0xF6, +0x07,0x56,0xFD,0xCF,0xF7,0xF7,0x5E,0x08,0x29,0x73,0xA0,0x0A,0x66,0x96,0xA6,0xCC,0x4F,0xDA,0xE6,0xAB, +0x31,0xE3,0x36,0xA7,0x8C,0x13,0x73,0x6E,0xAC,0xB6,0xFE,0x22,0x30,0x9B,0x00,0xF9,0x4E,0xC0,0x7D,0xA6, +0x0F,0x9C,0x87,0x9B,0xBA,0xFB,0x09,0xCF,0xCF,0x1A,0x2E,0xBB,0xC7,0xA3,0x81,0xCB,0xBD,0x94,0x70,0xF3, +0xCA,0xA9,0xFC,0x5C,0xEB,0x29,0x5D,0x7F,0xE1,0xB9,0x90,0x27,0x78,0xDE,0xF0,0xAC,0x7D,0x3C,0xEE,0x19, +0xEA,0x51,0xF2,0x86,0x7E,0xFC,0xF5,0xB8,0x21,0xFF,0xEA,0xDE,0x37,0x9D,0xEE,0x0B,0xCC,0x9D,0x3F,0x5C, +0x7F,0xFD,0xA4,0xFB,0x2C,0x9A,0x6F,0x12,0x5F,0xFF,0x25,0xBD,0x05,0xBA,0x75,0x6C,0xFE,0xFE,0x25,0x46, +0x44,0xF6,0xEB,0xDE,0x40,0x9F,0x41,0xBF,0x0F,0x5E,0xBD,0x25,0xFF,0xFF,0x4B,0x6A,0x22,0xF0,0x98,0x80, +0xCC,0xC1,0x06,0x15,0xBF,0xED,0x67,0x7B,0xED,0x9C,0x58,0x01,0x7D,0x07,0x73,0x90,0x31,0xAA,0xFA,0x2F, +0x8F,0xCC,0xF0,0xB2,0xAD,0x20,0x1F,0x21,0x8C,0x4B,0x41,0x24,0x24,0xD9,0x69,0x90,0xA4,0xED,0x3A,0x4B, +0x05,0x6C,0x3E,0x92,0x20,0x8A,0x49,0x34,0x00,0xD8,0x67,0xA2,0xAA,0xC5,0x89,0x15,0x92,0x2D,0x38,0x67, +0x61,0x6E,0xE3,0x43,0xEF,0x2B,0x67,0x5C,0x3D,0x64,0xAF,0x23,0x5C,0xE4,0x30,0x77,0x60,0x07,0xB6,0x52, +0xF2,0xB6,0xB4,0xF0,0xBF,0x65,0xCA,0x2E,0xB8,0x21,0x39,0x66,0xE1,0xA4,0x42,0x61,0x6B,0xD7,0x91,0xEC, +0x9E,0x07,0x2E,0x1A,0xBA,0x6B,0x31,0xD3,0x8A,0xBA,0xB7,0x52,0x72,0x41,0xF5,0x33,0x40,0x93,0xE3,0xC5, +0xDD,0xC8,0xB3,0xE8,0x64,0x0E,0x79,0x88,0x38,0xA3,0x92,0x3B,0x2C,0x9E,0x82,0xC4,0x37,0xA5,0x13,0xEE, +0xF6,0x0F,0xE8,0xF2,0x1A,0x89,0x7D,0xC9,0x9B,0x09,0x5F,0x21,0x26,0x77,0x30,0x8B,0x29,0x11,0xDA,0x9C, +0x3D,0x44,0x35,0x1C,0x16,0xE5,0xEC,0xD0,0xD0,0x28,0x3C,0x9A,0x68,0x04,0x4B,0x39,0xEB,0x2F,0x65,0x0F, +0x22,0xAE,0x40,0x34,0xDF,0x99,0x7A,0x98,0xF1,0x03,0x39,0x68,0xF1,0x68,0xA9,0x77,0xB5,0xE7,0x76,0x1E, +0xD4,0xB3,0x5E,0x81,0x2B,0x5F,0x6E,0x22,0xB8,0x6C,0xDE,0x89,0xF4,0xCD,0xF1,0x02,0x8A,0xE0,0x83,0xDC, +0xEE,0x4C,0xF9,0xFD,0x2E,0x81,0xAE,0xC0,0xE8,0x91,0x89,0x6C,0x54,0xD1,0xCE,0xDD,0xA3,0x5E,0xB5,0x5B, +0x7A,0xAC,0x05,0x96,0xCD,0xE4,0x24,0x02,0x56,0xC9,0x04,0xC0,0x4C,0xBB,0xDA,0x16,0x34,0xBD,0x66,0xA8, +0x84,0xF7,0xAC,0x74,0x0F,0x7F,0x9B,0x63,0xA5,0x9C,0xD2,0x0F,0x21,0x9E,0x1D,0x86,0x99,0xAA,0xE4,0x36, +0x70,0x13,0x99,0x94,0xC3,0x34,0xFB,0x1B,0x5B,0xC4,0x24,0x8C,0x04,0xC7,0x21,0xC7,0xB3,0xAD,0x5F,0xAB, +0x4A,0x77,0xEE,0x66,0x55,0x9C,0x1D,0x73,0x62,0x15,0xA5,0x65,0x0F,0x7C,0x9B,0xC0,0x55,0x1A,0x1B,0x44, +0x49,0x03,0xD7,0x40,0xD1,0xEB,0x38,0x76,0x2C,0x7C,0x99,0x20,0x21,0xB4,0xD4,0x40,0x13,0x97,0xA1,0xF5, +0x08,0x2A,0x94,0xFD,0xF1,0x71,0x85,0xC5,0xAD,0xB4,0x05,0xE5,0x58,0xCB,0x0B,0x0E,0xB0,0xFD,0x56,0x9A, +0x30,0x75,0x98,0x22,0x27,0x9A,0x59,0x51,0x97,0xA4,0x0D,0x51,0x50,0xE8,0x57,0x97,0x04,0x8A,0x3C,0x6A, +0x1B,0xC1,0x30,0x7D,0xD0,0x68,0xA1,0x8C,0x03,0xB9,0xAE,0x7C,0xA7,0x77,0x55,0x70,0x18,0xD4,0xB1,0xC2, +0xC8,0xE5,0x26,0x3A,0xD5,0x1B,0xA6,0x6C,0x82,0x76,0xFD,0x76,0xAE,0x68,0xF9,0xBF,0x3D,0x2C,0xE8,0x2B, +0x54,0x58,0xAF,0x7D,0x47,0x75,0xCF,0x1C,0xDC,0x00,0xD6,0x89,0x34,0x58,0x67,0x3B,0x55,0x79,0xFF,0xFC, +0x75,0x76,0x14,0xE7,0xC1,0x78,0xF8,0xF8,0xB7,0xBA,0xE5,0x16,0x96,0xA3,0x4D,0x0C,0x0A,0xF1,0x58,0x75, +0x98,0xD1,0x5C,0xDE,0xF8,0x7F,0xCE,0x08,0x01,0xFC,0x61,0xCC,0xBC,0x74,0x7F,0x36,0xC9,0x6F,0x47,0x0D, +0xFA,0x9E,0x3F,0x2B,0x6C,0xAB,0xB7,0xEF,0xBF,0x71,0xF0,0x8F,0x42,0x6C,0xDF,0xD3,0x3B,0x62,0xC8,0x0A, +0x6F,0xD2,0xCF,0xCD,0xEB,0x74,0x9F,0x32,0x00,0x3F,0xCC,0x40,0x16,0x2D,0x6E,0x11,0x54,0x6F,0x6B,0xA4, +0x55,0x07,0xE8,0x32,0xEF,0x7C,0xF8,0x13,0x19,0x0A,0x06,0x1B,0x8F,0x50,0x30,0xF3,0xF4,0x6B,0xFE,0x81, +0xF3,0x17,0x5E,0x83,0x8A,0x39,0x03,0x65,0x56,0xAE,0xEB,0x26,0x77,0xE4,0x31,0x0B,0x64,0x98,0xE6,0xE8, +0x93,0x82,0x47,0x28,0x2C,0xD2,0x42,0xD5,0x57,0xAB,0x39,0xD3,0xA3,0xE8,0x4A,0xB5,0x9A,0xD9,0x8D,0xF3, +0x2D,0xBB,0x6C,0xA6,0x18,0xA6,0x52,0xBA,0x4D,0xCA,0x7A,0xD4,0x97,0xAD,0x26,0x9D,0x51,0x51,0x6F,0xF2, +0x19,0xA7,0x03,0x4F,0x87,0xC9,0x99,0x63,0x77,0x09,0x72,0xC3,0x75,0x79,0x37,0x73,0xB5,0xE7,0xA9,0x77, +0xF5,0xC5,0xB3,0xA8,0x34,0x3C,0x82,0x68,0x38,0x6C,0x39,0xE2,0x93,0x4A,0x3B,0xFC,0x8E,0xFD,0xD7,0x2A, +0x93,0xAA,0x50,0x2A,0xA7,0x5C,0xAA,0x5C,0xFF,0x8D,0xC2,0x9A,0x3E,0x90,0xC2,0x00,0xDB,0x5D,0x5B,0x9A, +0x9B,0x76,0xC2,0xBC,0x58,0x23,0x63,0xFB,0xCC,0x85,0x14,0x0E,0x11,0xA6,0x6D,0x24,0xC0,0x84,0xCB,0xAD, +0xD9,0xB0,0x91,0xE4,0x02,0x0D,0x4D,0xEE,0x57,0xEB,0x12,0x54,0x5C,0x0E,0xC3,0xBD,0xD8,0xEF,0x76,0x9D, +0x08,0xCD,0x57,0xB7,0x1C,0xD7,0x8F,0xC3,0x6C,0x13,0x6E,0x53,0x3E,0xED,0xBF,0xDA,0x7C,0xF8,0xD2,0xDA, +0x1B,0xC7,0x24,0x95,0x49,0x66,0xDA,0x19,0x7B,0xEB,0xAA,0x49,0x23,0x25,0x63,0xB2,0x9E,0x75,0xF7,0x9A, +0x71,0x4E,0x33,0xFA,0xD8,0x1E,0x34,0xDB,0xB0,0xAF,0x43,0xCE,0xE8,0xDA,0x86,0xEA,0xA4,0xB0,0xDB,0x3F, +0x7E,0x10,0xB4,0x64,0xA6,0xE5,0x0F,0x23,0xE1,0xAE,0x0C,0x20,0xD8,0xB2,0xFE,0xD9,0xD7,0xB1,0xC4,0x97, +0x01,0xFF,0x8F,0x67,0xA9,0xF1,0xC4,0x12,0x67,0x79,0x7C,0x2B,0x58,0xF7,0x65,0x73,0xA0,0x9D,0xD8,0x74, +0x6C,0x66,0x4D,0xD1,0xD7,0x70,0x6A,0xA7,0x83,0x72,0x6D,0xAC,0xAD,0xFF,0x45,0x1D,0x97,0x65,0x5D,0x9C, +0xBB,0x58,0xB5,0x10,0x96,0xD3,0x3C,0xB1,0x15,0x7F,0x3F,0xC4,0x49,0x5C,0x26,0xB4,0x8D,0xB0,0x37,0xC6, +0x3E,0x86,0x1E,0x86,0x75,0x3C,0x31,0x7D,0x31,0x67,0x83,0xCC,0x45,0x75,0xAC,0x94,0x37,0xBB,0xBF,0x8B, +0x4F,0xE7,0xBE,0xE8,0xCD,0xB4,0x4D,0xC7,0x87,0xB6,0x95,0xE5,0x1A,0xFB,0x7A,0xA2,0xDB,0x9C,0xFF,0x53, +0xB1,0x1F,0x2D,0x03,0x6A,0x06,0xFB,0x31,0xA3,0xF1,0x0E,0x48,0xF8,0x59,0xD9,0xFD,0xD6,0x10,0x87,0x48, +0xEE,0xAD,0xCE,0xE8,0x6A,0xFE,0x09,0xB3,0xC4,0x08,0x85,0x70,0x82,0xBD,0x66,0x8F,0x5E,0x7B,0xC6,0x99, +0x1E,0xDA,0x80,0xBE,0x7C,0x8B,0xD5,0x6F,0xF8,0x31,0xF0,0xC9,0x8D,0x8F,0x93,0xEF,0x9F,0xC9,0x71,0x79, +0xA9,0x1E,0xAD,0xB1,0x4B,0xCE,0x87,0x44,0x84,0x3A,0xC7,0x98,0x9E,0x58,0xA4,0xB9,0x5E,0x1B,0x76,0xBD, +0x13,0xD2,0x08,0xEC,0x8F,0x5F,0x41,0xF1,0x9F,0xF3,0x70,0x7A,0x0C,0xED,0xA6,0xCF,0x5F,0x02,0x2C,0x5E, +0x9C,0x60,0x4A,0x1C,0xFA,0x9D,0xEB,0x4A,0xC7,0x4F,0x85,0xDF,0x57,0xD7,0x59,0xCF,0x15,0x53,0x97,0xB9, +0xC3,0xF1,0x36,0x2E,0x4B,0x4E,0x10,0xDD,0xFB,0x3E,0x65,0xFE,0x04,0x9B,0x6F,0x39,0xEF,0xBE,0xDB,0x02, +0x7F,0x79,0xA0,0x17,0xB1,0xDF,0x94,0xE6,0xD2,0x43,0xA6,0x26,0x3B,0xE5,0xAF,0x16,0xD5,0x65,0x0A,0x6B, +0x9E,0xA7,0x70,0xF2,0xC7,0xB4,0x8B,0x2E,0x99,0xD0,0x5A,0x03,0xFB,0x9B,0x2D,0x97,0x88,0x2A,0xF2,0xDA, +0xBF,0x42,0x93,0x63,0x42,0xC6,0x31,0xFE,0x8F,0x61,0xF0,0x55,0xD5,0x25,0x89,0xF6,0xC3,0xB6,0xBE,0xC4, +0x4D,0xA3,0x1E,0x73,0x0E,0xAF,0x9E,0x4B,0x00,0x6A,0x62,0x64,0xC7,0x52,0x1B,0x97,0x45,0xCB,0xE9,0x4A, +0x9F,0xB1,0x17,0x54,0x90,0x2B,0x06,0x7F,0x47,0x0B,0x17,0x8E,0x8F,0xDF,0x73,0x40,0x07,0x10,0xA0,0xE5, +0x44,0x99,0xF0,0x7B,0x5E,0xF2,0x1C,0x23,0x96,0x0C,0x17,0x5E,0x87,0x49,0x29,0x6A,0xB7,0xFB,0x38,0xD1, +0x15,0xF8,0x66,0x95,0xF7,0x61,0xC6,0xD8,0x04,0x0E,0x0A,0x61,0xB9,0xD9,0x16,0x6F,0xC9,0x46,0x7A,0xA6, +0x7A,0xBE,0x40,0x0D,0x8B,0x0A,0xB3,0xBC,0xF4,0xD9,0xFC,0x4A,0x3F,0xE6,0xF2,0xBA,0xA5,0x28,0x8B,0xC4, +0x2B,0x77,0xFB,0x29,0x1D,0x84,0xAC,0x19,0xCC,0xE5,0xEC,0xD0,0xD8,0x64,0x48,0xFB,0x0B,0x43,0x7B,0xCE, +0x78,0x47,0xF9,0xC8,0x03,0x0B,0x77,0xBD,0x25,0x4B,0x23,0xE8,0xDC,0xB3,0xFD,0x12,0xE7,0xAE,0x8D,0x68, +0xC9,0x42,0x67,0xED,0x1A,0x63,0xAA,0x67,0x2F,0x63,0xD9,0xDE,0x1A,0x4E,0xE5,0x23,0xC9,0x81,0x80,0x83, +0xD9,0xA1,0x9C,0x49,0x09,0x00,0xDB,0x44,0xDA,0x25,0xB3,0x56,0xEE,0xF2,0xB3,0x42,0xD8,0x61,0x0B,0x66, +0x83,0x63,0xF1,0xBF,0xBF,0x29,0x94,0x1B,0x3C,0x2A,0x14,0x9F,0x77,0x60,0x4E,0x95,0xA2,0x58,0xF9,0xF6, +0xA2,0x2F,0x37,0xAF,0xB8,0xFB,0xEA,0x97,0x1B,0xF5,0x4C,0xAF,0x29,0x7D,0x08,0x34,0xFA,0x81,0x4C,0x2E, +0x9A,0xAA,0x8F,0xAE,0xB9,0xC0,0x9D,0x63,0x84,0x7C,0xA5,0x80,0xB6,0x22,0xB0,0xA5,0x67,0x44,0x15,0xE3, +0x62,0xD6,0x25,0x53,0x75,0xD5,0xB7,0xD2,0x6F,0xCC,0x1D,0x73,0x62,0x15,0xBA,0x44,0x6D,0x13,0x14,0x5E, +0xD9,0x08,0xCC,0x61,0x51,0x14,0x4E,0xC1,0xBF,0x88,0x8A,0x76,0x76,0xF9,0x4D,0xE6,0xC9,0x00,0xB4,0x24, +0x3B,0x3A,0xA9,0xF8,0xF8,0x53,0x82,0xC7,0x67,0xDA,0xF8,0x8B,0x46,0x91,0xBD,0xE1,0x30,0xCA,0x4F,0x61, +0x37,0x26,0xAB,0xD3,0x19,0x93,0xD8,0xE7,0x53,0x07,0xAD,0x8A,0x50,0xBC,0xF7,0x2C,0x16,0x58,0xEF,0xB3, +0x61,0xE3,0xA1,0x1F,0xC9,0xB7,0xBC,0x12,0xCF,0xB5,0xA1,0x8C,0xB1,0xA5,0x7E,0x26,0x5A,0xAE,0xA5,0xE2, +0xFC,0xE5,0xF5,0xB8,0xB6,0x3B,0x40,0x5A,0x6B,0xDC,0xF6,0x3A,0x85,0x38,0x61,0x78,0x6A,0x5A,0xE0,0x76, +0x59,0xAC,0x38,0xD2,0xAB,0x3A,0xE8,0x50,0xF8,0x74,0x30,0xC6,0x7D,0xCD,0x38,0x9C,0x34,0x37,0xE0,0x3B, +0xEC,0x5F,0x73,0x3D,0x05,0x5B,0xF4,0xF3,0x55,0x1C,0xAD,0x2E,0xB8,0xC0,0xE2,0x97,0xC9,0x1D,0xF5,0xF7, +0xA2,0xD7,0xDE,0x1F,0x29,0xE8,0x7A,0xAF,0x07,0x32,0xF2,0xBA,0xE8,0xA9,0x8E,0x62,0x80,0x88,0x2F,0x0B, +0x2C,0xEB,0x3D,0xBE,0x8E,0x31,0xBB,0x69,0x16,0x7E,0x72,0x65,0x7D,0x68,0x4B,0x9E,0x2A,0x11,0x7F,0xF4, +0x5A,0x5C,0xFF,0xE7,0x67,0xFB,0x28,0xC3,0x0D,0xCA,0x6C,0xF2,0x08,0x8F,0x45,0xE9,0xF5,0xF6,0x6E,0xB0, +0x04,0x4D,0x1C,0x64,0xD7,0x34,0x10,0xED,0xC4,0xE3,0x92,0x9C,0xA6,0x3C,0x66,0xA9,0x55,0x6E,0xC6,0xA5, +0x3E,0x67,0x06,0x05,0x54,0xE6,0x58,0x75,0x0E,0x9D,0x4F,0xBD,0x2F,0x34,0x53,0x38,0x1A,0x6F,0xED,0x96, +0xC6,0xA3,0xF9,0x60,0xDB,0xE4,0x5A,0x6D,0x34,0x1F,0x39,0x2D,0x03,0x57,0x48,0x80,0xD2,0x42,0x68,0x83, +0xB7,0x2E,0x48,0x9D,0xA7,0xBB,0x58,0x62,0xD3,0x64,0x0E,0xA3,0xC5,0xC5,0x34,0xA6,0x1F,0xAA,0xC3,0xD7, +0xC1,0x14,0xE7,0x80,0xD2,0xB5,0xC6,0xD4,0x67,0x29,0x0E,0xA5,0x14,0xEE,0x4E,0xC6,0x40,0x77,0xCB,0x94, +0x89,0xFD,0x17,0x65,0x6C,0x62,0x89,0x13,0xE6,0x2A,0x46,0x42,0x66,0x78,0x11,0x62,0xD1,0x35,0x42,0x4E, +0x5F,0x87,0xCC,0x8A,0x06,0x30,0x9D,0x51,0x91,0x1C,0x55,0xDF,0x86,0xF8,0xAE,0x3D,0xAE,0x3D,0x06,0x91, +0xA2,0x24,0x0C,0x3E,0x26,0x4C,0x11,0x61,0xE0,0x15,0x9C,0x59,0x82,0x00,0x63,0x07,0x90,0x27,0x81,0x34, +0x20,0x61,0xCD,0xB5,0x09,0xB7,0x8B,0x01,0x01,0x86,0x4A,0xF1,0x7C,0x9D,0xBB,0x7D,0x5F,0x9F,0x18,0x09, +0x01,0x0E,0x3C,0x79,0x1E,0x23,0x9A,0xCC,0x1B,0x95,0xCD,0x5B,0xEF,0x33,0x18,0x4A,0xD1,0xEE,0x49,0x41, +0xD7,0x26,0xC7,0x01,0xEA,0x51,0x6D,0xDA,0x3B,0xED,0x92,0x60,0x99,0x19,0x51,0x0D,0x1C,0x1A,0x9B,0x68, +0x98,0x7C,0xC8,0xCE,0x39,0x8B,0x44,0x6E,0x53,0xE2,0xCE,0xD3,0x08,0x99,0x2B,0xD7,0x18,0xA9,0x8F,0xBB, +0xDF,0x33,0x1D,0x8E,0x15,0xAF,0x83,0x1D,0xCF,0x26,0xCC,0x98,0xF2,0x44,0x0C,0x4C,0xC8,0xDD,0x18,0xE4, +0xF7,0x24,0x95,0xCC,0xF8,0xEC,0xF2,0x04,0x31,0x25,0x32,0x50,0x92,0xAC,0xC2,0x25,0x1E,0x77,0x7B,0x19, +0xA0,0x4E,0x43,0x76,0x7E,0xF2,0x7F,0xFC,0x5B,0x8F,0x57,0xB8,0x3A,0x7F,0x82,0x8D,0x41,0x67,0x4E,0x8C, +0x6B,0x18,0xB2,0x4C,0x67,0x9B,0x3D,0x44,0x23,0x5C,0xC7,0x54,0xFA,0x72,0xCE,0x63,0x18,0x3E,0xD0,0x74, +0xAE,0x90,0x83,0xDC,0x84,0xFA,0x0E,0xD6,0xCC,0x43,0x7D,0xA4,0x19,0x39,0x04,0xA2,0x63,0x7A,0xEC,0xE3, +0x17,0xF4,0x5F,0x30,0x6C,0x3D,0xCD,0x9E,0x41,0xF3,0x93,0x98,0x27,0x5C,0x9D,0x61,0x0A,0xB7,0x13,0x4C, +0xCC,0x21,0x39,0x07,0x16,0x6F,0x1B,0x02,0x25,0x97,0x7F,0xD6,0x75,0x3B,0x90,0x79,0xC4,0x33,0xC1,0x82, +0xDD,0x17,0x16,0xD4,0xCF,0xBD,0x51,0x5F,0xA6,0xE8,0x08,0xA2,0xFD,0x3D,0x01,0xF1,0xE0,0x6D,0xFA,0x6A, +0x13,0xDF,0x15,0xE1,0x84,0x05,0x15,0x8F,0x29,0x8C,0xC4,0xD1,0x09,0x66,0x88,0x49,0x15,0xB8,0xC9,0x35, +0x29,0x67,0x38,0x80,0xC6,0xEF,0x1D,0x80,0x51,0x10,0xB7,0xD6,0x4E,0xDD,0x1C,0x89,0x21,0x1E,0x67,0x39, +0xFC,0x40,0x99,0xDD,0x06,0xFF,0xD5,0xDC,0xB2,0x39,0xE9,0x8C,0x95,0x1D,0xC1,0xC4,0xCB,0x69,0x63,0x23, +0x3F,0xFC,0x4C,0xFE,0xEA,0xCB,0xC0,0xCB,0x80,0xE6,0x5C,0x95,0x73,0x23,0x52,0xE7,0xB8,0x6C,0x29,0xD8, +0xEA,0x75,0x43,0x8D,0x15,0xEF,0xD9,0x28,0x47,0x34,0xD5,0x2C,0xEC,0x10,0xDE,0xE1,0x73,0x6B,0x64,0x7B, +0xF1,0xAD,0xBF,0xE2,0x06,0x52,0xF8,0x86,0x34,0x34,0x5E,0x04,0x94,0x81,0xC9,0x00,0x33,0x40,0xCC,0x9C, +0xFC,0x0E,0x4C,0x96,0x33,0xD1,0x3F,0x19,0x47,0x60,0x9E,0xAC,0xD6,0x91,0xE7,0x3E,0xB0,0x40,0xBB,0x82, +0x6F,0x4E,0xB6,0x14,0x10,0x53,0x69,0x63,0xDC,0x61,0xC9,0x9D,0x4F,0x05,0xF1,0x97,0x94,0x6A,0x09,0xCC, +0xC5,0x01,0x46,0x9A,0xD7,0x22,0xC0,0xA2,0x80,0x07,0xC0,0xC6,0x17,0x40,0x11,0x91,0x4F,0x1D,0x26,0x16, +0xF1,0x62,0x28,0xF0,0x5D,0x08,0x4F,0x45,0x94,0xF4,0xF3,0x4F,0x4E,0x90,0x23,0x96,0xF2,0xEF,0x06,0xB1, +0x8A,0x09,0x9B,0x55,0x31,0x25,0x8A,0x61,0xC4,0xB4,0xD9,0xD3,0x73,0xEC,0x43,0x50,0x20,0x01,0x09,0xC9, +0xB8,0x66,0xD1,0xF5,0x95,0xA1,0x5E,0x25,0xD2,0x68,0xA8,0x71,0xE1,0x52,0xD8,0x19,0xBB,0x68,0x92,0xB2, +0xB4,0x59,0x4E,0x0C,0x54,0x38,0x72,0x5E,0x45,0x48,0x3D,0x1D,0x94,0x25,0x0F,0xBC,0x4D,0x6C,0x46,0xD4, +0x7D,0xE2,0x7B,0x2E,0x61,0x70,0x97,0xF4,0x17,0x28,0xD3,0x2D,0x60,0xBF,0x4C,0x03,0xDE,0x2B,0x52,0x2C, +0x2C,0x67,0xE3,0xEC,0x5F,0x2B,0x3D,0x0C,0x4D,0xEF,0x9F,0xDB,0xFB,0xBB,0x12,0xD4,0xEB,0x03,0x61,0x78, +0xC6,0xCD,0x32,0x28,0xF4,0xC7,0xB2,0x2C,0xB8,0xB1,0xCE,0xBA,0xEA,0xF2,0xDA,0xD8,0x1F,0xBB,0x21,0x83, +0x74,0x4F,0x4A,0x3A,0xF1,0x96,0x23,0x0D,0xCD,0x85,0x03,0x6C,0xBA,0xD5,0x57,0x8B,0xEE,0xC3,0xAB,0x4A, +0x27,0x61,0x8B,0x7D,0xD3,0x82,0x7C,0x69,0x9D,0x6F,0x82,0x4C,0x70,0x50,0xDD,0xF9,0xDF,0x4A,0x5E,0xBD, +0xCB,0x54,0x5B,0x84,0xB3,0x3E,0x23,0x23,0x03,0xAF,0x98,0xA3,0xD1,0xF8,0xA8,0xEB,0x82,0xE1,0xCC,0xAB, +0x39,0x5D,0x26,0x52,0x52,0x48,0xF4,0xB2,0xF2,0x15,0x3F,0x31,0x14,0xBD,0x65,0xBA,0x94,0x5C,0x6D,0x23, +0x10,0x54,0x91,0x47,0x73,0x7C,0x2D,0x5A,0x85,0x5F,0xA5,0x57,0x48,0xBF,0xE7,0x33,0x15,0x51,0xF5,0x57, +0x72,0x7E,0xE4,0xB2,0x48,0x65,0x8E,0x3E,0xEF,0x3A,0x6C,0x30,0x99,0x5B,0x04,0xA0,0xD1,0x11,0x6C,0xB6, +0x07,0x13,0xE4,0xB6,0xB2,0x3A,0xCC,0x12,0xE1,0x1D,0x84,0x65,0x38,0xDF,0x3B,0xC6,0x5F,0x19,0xAD,0x43, +0x4E,0x77,0x6D,0xB1,0xEA,0x59,0xAD,0xC2,0xF4,0x96,0xE2,0x3E,0x5E,0x18,0xE5,0xD2,0x32,0x73,0x91,0x93, +0xA0,0x88,0x93,0xD1,0x71,0x7F,0x03,0x0A,0x0A,0xEA,0xCC,0x6E,0x79,0x28,0x6E,0x57,0x6E,0x2A,0x46,0x2E, +0x5A,0xC8,0x6E,0xDC,0x6E,0x94,0x8F,0x82,0xDD,0xCD,0xC4,0x44,0x6D,0x1B,0xCE,0x24,0x98,0x76,0x3F,0x59, +0x5F,0x15,0xF9,0x1E,0xD3,0x8C,0x4C,0xEF,0xF0,0xA1,0xCD,0xAC,0x5B,0x7C,0x77,0x1B,0x8B,0xE9,0x39,0x6C, +0x51,0x7F,0xD8,0x45,0x6B,0x53,0x40,0xB9,0xFF,0x3A,0x26,0x97,0x9D,0xA1,0xEE,0x0E,0x51,0x32,0x2E,0x8A, +0x29,0xE3,0x23,0x9E,0xD9,0x7A,0xF3,0x3A,0xA9,0xE1,0xA6,0x1E,0xB8,0x79,0xB6,0xF5,0x8A,0x46,0x25,0x1E, +0xDA,0xF7,0x3F,0x4B,0x77,0x21,0x87,0x49,0xB8,0x93,0x2F,0xCD,0x6D,0x5E,0xDF,0x43,0x5B,0xF4,0x36,0xAA, +0x8D,0x10,0xA7,0xDA,0x38,0x30,0x44,0x0F,0x14,0xA2,0x58,0x1F,0x79,0x77,0xE4,0x80,0xB0,0x0B,0x87,0x91, +0x7F,0x06,0xA2,0x25,0xE5,0xA5,0xB6,0xA2,0x06,0x67,0x84,0x81,0x4E,0x8B,0x0B,0x20,0xC9,0x44,0xD5,0xD8, +0xC0,0xC6,0x80,0x74,0xF6,0xED,0x59,0xFE,0x8C,0x7F,0x24,0x75,0x7F,0x24,0xCE,0xA7,0xC0,0xE7,0x19,0x3B, +0xF0,0xEE,0x3D,0xE3,0xE1,0x72,0xF7,0x24,0x99,0x08,0xD1,0x90,0xC3,0x31,0x1D,0x75,0x51,0xEF,0x9F,0x46, +0x22,0xB6,0xD4,0x79,0x7A,0xE6,0xB0,0x76,0xB1,0xBF,0x2F,0x73,0xD1,0xE3,0x4B,0x6B,0xDF,0x54,0x8D,0x52, +0x33,0xDC,0x79,0x9A,0x47,0x87,0x10,0xD4,0xF3,0x62,0xC2,0x6E,0x5A,0x17,0xF5,0xCF,0x90,0x54,0x66,0x8F, +0x78,0xFD,0x59,0xC5,0x09,0xB9,0xD4,0x33,0x99,0xF5,0x05,0xD7,0x6B,0x87,0x3C,0xE7,0x45,0xC4,0x19,0x5E, +0x52,0xE0,0x5B,0x6C,0xFB,0x03,0x90,0x0F,0x99,0xBE,0x57,0x2E,0x68,0xB1,0xDA,0xDF,0xDF,0xFA,0x86,0x84, +0xFA,0xCC,0xF4,0x11,0x0F,0xE7,0xE5,0xBA,0x3A,0xBC,0x2A,0x86,0xDF,0xE1,0xB5,0x36,0x3F,0xC7,0x02,0x15, +0x00,0x1E,0xEE,0x29,0x2D,0x75,0x73,0x2F,0xC8,0xA8,0x95,0x9E,0x76,0x00,0xCA,0xBF,0x4B,0x14,0xFB,0x1A, +0x62,0xCD,0x4F,0x4D,0x7E,0xED,0x5C,0x76,0x32,0x23,0x4E,0x0C,0x9D,0x51,0xB0,0x18,0xED,0xA9,0xE2,0x47, +0xBB,0xAD,0x14,0x5D,0xAE,0x72,0xB0,0x5B,0x63,0x52,0x30,0x84,0xEC,0xC0,0x7A,0x9C,0xDD,0xA5,0xC3,0x39, +0xE4,0x3F,0xA9,0x4A,0xBF,0xDE,0xCC,0x89,0xEA,0xC3,0x93,0x2B,0xA5,0x65,0x55,0x63,0xB3,0x20,0xD1,0xE3, +0x68,0x53,0x71,0x7F,0x6C,0x8E,0x5B,0x0D,0x7C,0xE9,0x1C,0x52,0xDF,0x9F,0xFA,0xB4,0x74,0xFC,0xC2,0x52, +0x6C,0xDF,0xB3,0x24,0x71,0x4B,0x54,0x10,0xA5,0x28,0x8B,0x67,0xA9,0x23,0x66,0xA2,0xC6,0xD7,0x6C,0xF2, +0x94,0xFE,0x45,0x23,0xFE,0x1F,0xC4,0x89,0x64,0xC6,0xA5,0x21,0xC6,0xC2,0xEF,0xA2,0x57,0xF4,0x15,0x11, +0x87,0xE1,0x45,0x1D,0x97,0x65,0x6D,0xAF,0x46,0x28,0x09,0x55,0x59,0xB1,0x04,0x82,0x9B,0x1F,0x8C,0xA4, +0x10,0xB2,0xB4,0x67,0x0C,0x59,0x85,0x98,0xD5,0x91,0x13,0x50,0x26,0x6A,0x8C,0x96,0x91,0xB8,0xBC,0x76, +0xDA,0x5E,0x64,0xB1,0xBD,0x9C,0x61,0x21,0x84,0x69,0xED,0x60,0x57,0xB9,0x0D,0xC4,0x45,0x2B,0x4A,0x05, +0xD2,0x5B,0x55,0xF3,0x06,0xA8,0xE7,0xD6,0x14,0xBA,0x82,0x11,0xBB,0x20,0xB5,0xEB,0xF1,0xF6,0x5E,0x08, +0x29,0x23,0xD9,0x73,0x3C,0xB6,0x5C,0x56,0x4E,0x9A,0x30,0x4E,0x7C,0xF8,0xFE,0xCA,0x2B,0x79,0xFE,0x96, +0x6D,0xBA,0x19,0xC8,0xE3,0xB5,0x3E,0x9A,0x67,0xFF,0x7D,0x8F,0x0F,0x9C,0xCF,0x09,0x40,0xFB,0xF4,0x3C, +0x6E,0x9B,0xB7,0xAF,0x83,0xBA,0x77,0x0A,0xE6,0x31,0xAE,0x9B,0x38,0xAB,0xFB,0x39,0xCF,0xEB,0xEF,0x22, +0x5C,0x73,0xF6,0x37,0x4F,0x37,0xAC,0xD3,0x7F,0xB9,0xF2,0x91,0x4A,0x92,0x3D,0x6A,0x20,0x7B,0x04,0x7A, +0x5B,0x8D,0x55,0x3C,0x93,0x40,0x24,0xFF,0xCC,0x9F,0xEA,0x07,0xD9,0x3F,0xEF,0x6B,0xC5,0xF6,0x9F,0x4D, +0xBF,0xB9,0xB1,0x69,0xEB,0x24,0x37,0xCB,0xFD,0xBC,0xB0,0x91,0xC4,0xD7,0x97,0xFB,0x3D,0xB7,0x6F,0x14, +0xE9,0xCD,0xF9,0x9B,0xDB,0xFF,0xC0,0x20,0x57,0x47,0x07,0x86,0x32,0x52,0xF7,0x60,0x4C,0x2E,0xAA,0xC6, +0x72,0x9F,0x8B,0xE1,0x24,0xFE,0xA4,0x85,0x99,0xF1,0x60,0x14,0xC3,0x45,0xC2,0x35,0xF2,0x20,0xC3,0x72, +0xA5,0x09,0xF9,0x21,0x19,0xE0,0x31,0x20,0x4D,0x48,0xEE,0xA7,0xF2,0x02,0xC9,0x88,0x3E,0x41,0x89,0x56, +0x97,0x07,0x11,0x53,0x22,0x4A,0xF9,0x6A,0x32,0xE8,0xD0,0x86,0x4C,0x46,0xC0,0x44,0x12,0x24,0xE4,0x44, +0xC0,0x4C,0xD0,0x64,0x52,0x64,0x93,0x54,0x07,0xF7,0xC8,0x54,0x13,0x25,0x51,0x30,0x71,0x46,0xD8,0x74, +0x53,0x65,0x01,0x41,0xFD,0xCD,0xC1,0x45,0x92,0x26,0xED,0x1E,0x61,0x07,0xD1,0x65,0xD2,0x66,0xE2,0x23, +0x74,0xDA,0xC9,0x55,0x93,0x27,0x48,0x51,0xC3,0x47,0xD9,0x75,0xD3,0x67,0xC5,0xBA,0x0E,0x9A,0x19,0x0C, +0x90,0xB0,0x91,0xAC,0x06,0x3F,0x96,0xCE,0x90,0xB9,0x6A,0x59,0xF0,0x04,0x4A,0x18,0xB1,0x65,0x00,0x16, +0x68,0x29,0x45,0x3C,0x7D,0x6F,0x3D,0xCF,0x90,0x4B,0x83,0x4E,0xBC,0x2A,0x73,0x2B,0xC9,0x47,0x43,0xA9, +0x8E,0x12,0x41,0xE7,0x2A,0x6E,0xFB,0xDB,0x33,0x6A,0x41,0xC6,0x6A,0x0A,0x97,0x43,0x78,0xE1,0x50,0x48, +0x0C,0xCE,0xC2,0x4C,0x1A,0x2C,0x52,0x68,0x4A,0x4C,0xD2,0x6C,0x5A,0x6C,0xDA,0x2A,0xFC,0xD0,0xCA,0x5C, +0x1B,0x2D,0x5A,0x78,0x4B,0x4D,0xDA,0x7C,0x5B,0x6D,0xB9,0xF7,0xB6,0xE1,0xC3,0x4D,0x9A,0x2E,0x53,0x69, +0xCA,0x4E,0xD3,0x6D,0xDA,0x6E,0x59,0x61,0x8D,0xCD,0xCB,0x5D,0x9B,0x2F,0x5B,0x79,0xCB,0x4F,0xDB,0x7D, +0xDB,0x6F,0x3E,0x62,0xA3,0x1E,0xDD,0x64,0xD7,0x36,0x2C,0x98,0x93,0xED,0xD5,0x1B,0x78,0x10,0xC3,0x6A, +0x12,0xC8,0xF4,0x52,0x85,0x70,0xB3,0x94,0xEE,0x53,0x5C,0x94,0xDE,0x78,0xE5,0xBE,0x84,0x78,0x8D,0x2A, +0x13,0xB2,0x4D,0x42,0x3D,0xCF,0x55,0x84,0x6E,0x33,0xB7,0xA1,0x2B,0xBC,0xDD,0xAC,0xF5,0x7D,0xAA,0xB0, +0x6C,0x5F,0x19,0x0A,0xFD,0x13,0xBB,0xB2,0x81,0xE9,0xC4,0xC4,0x32,0x34,0x54,0xE0,0x62,0x54,0xD4,0xE4, +0x72,0x74,0x5E,0xA2,0x80,0x70,0xCC,0xD4,0x33,0x35,0x5C,0xF0,0x63,0x55,0xDC,0xF4,0x73,0x75,0x3D,0xE5, +0x20,0xF5,0xC5,0xC5,0xB2,0x36,0x55,0xE1,0xE2,0x56,0xD5,0xE5,0xF2,0x76,0x17,0x2E,0x00,0x56,0xCD,0xD5, +0xB3,0x37,0x5D,0xF1,0xE3,0x57,0xDD,0xF5,0xF3,0x77,0xA6,0xFA,0x4A,0x8D,0xC6,0xFE,0x0B,0x21,0x7E,0xD7, +0x4A,0x55,0x16,0x8D,0xE6,0x3A,0xC7,0xBF,0x88,0xB6,0x26,0xA0,0x3D,0xEB,0x1A,0xA4,0xEA,0x57,0x8E,0xB2, +0xFB,0x7D,0x79,0x8E,0x09,0xB5,0x7D,0x7C,0xE3,0xC5,0x11,0xB4,0x16,0x5A,0x87,0x25,0xDC,0x38,0xC2,0xBD, +0x2B,0x18,0xD3,0xEF,0x52,0x72,0xFF,0x86,0xCD,0x58,0x97,0xDF,0x1B,0x2E,0x16,0xD5,0x6E,0x5E,0xC6,0xCC, +0x3A,0x3C,0x56,0xE8,0x6A,0x5C,0xD6,0xEC,0x7A,0x7C,0x58,0xFC,0x09,0x4F,0xCE,0xDC,0x3B,0x3D,0x5E,0xF8, +0x6B,0x5D,0xDE,0xFC,0x7B,0x7D,0xC2,0xF0,0xAC,0x5F,0xC7,0xCD,0xBA,0x3E,0x57,0xE9,0xEA,0x5E,0xD7,0xED, +0xFA,0x7E,0x49,0x5D,0xF7,0x19,0xCF,0xDD,0xBB,0x3F,0x5F,0xF9,0xEB,0x5F,0xDF,0xFD,0xFB,0x7F,0x18,0xD2, +0xF3,0x8F,0x48,0xB5,0x91,0xE7,0xD8,0x33,0xC3,0x30,0xCF,0xC4,0xD6,0xC8,0x48,0x53,0xF0,0x8C,0xDC,0x32, +0x9A,0xA3,0xC7,0xB6,0x5B,0x5A,0xC0,0x12,0x53,0xE0,0x95,0xF3,0xD8,0x8D,0x61,0x23,0xB9,0xEE,0x0B,0xCB, +0xA9,0x0D,0x8E,0x45,0x95,0xC2,0x23,0x17,0x26,0xC2,0x1E,0x16,0x18,0xAF,0x03,0xDB,0xF4,0x0C,0x45,0x57, +0xD9,0x14,0x9A,0xFC,0x04,0x6B,0xE0,0x46,0x16,0xA4,0x70,0x62,0x46,0xC4,0xF0,0x66,0x56,0xE4,0x30,0x46, +0x25,0xE5,0xE8,0x56,0x17,0xA5,0x78,0x72,0x47,0xC5,0xF8,0x76,0x57,0xE5,0xF1,0xAB,0xA2,0xCB,0xE1,0x47, +0x96,0xA6,0x71,0x63,0xC6,0xC6,0xF1,0x67,0xD6,0xE6,0xED,0xD7,0xDD,0xA9,0xE9,0x57,0x97,0xA7,0x79,0x73, +0xC7,0xC7,0xF9,0x77,0xD7,0xE7,0xCE,0x8A,0xF0,0xA8,0xCA,0x0E,0x77,0x4C,0x9A,0x2F,0x48,0x5A,0x36,0x2B, +0x58,0xE9,0x22,0x57,0x6E,0xE9,0x4A,0x21,0x39,0xE7,0x85,0x03,0xA6,0x8D,0x2A,0xBA,0x7D,0x86,0x8F,0x49, +0x0F,0x8C,0xA7,0x0F,0x1F,0xA4,0x41,0x59,0x3F,0x78,0xF2,0xAB,0xF4,0x9C,0x53,0x99,0x8C,0xD3,0xE8,0x6D, +0x76,0xE2,0x01,0x87,0x26,0xAF,0xE3,0x3A,0xD9,0xEA,0xF2,0xC8,0x60,0x4D,0xE2,0x4E,0x1E,0xAC,0x72,0x6A, +0x4E,0xCC,0xF2,0x6E,0x5E,0xEC,0x30,0xA5,0xAC,0xCC,0xEA,0x5E,0x1F,0xAD,0x7A,0x7A,0x4F,0xCD,0xFA,0x7E, +0x5F,0xED,0x39,0x5E,0x2D,0xEB,0xE3,0x4F,0x9E,0xAE,0x73,0x6B,0xCE,0xCE,0xF3,0x6F,0xDE,0xEE,0x0B,0x1B, +0x21,0x82,0xEB,0x5F,0x9F,0xAF,0x7B,0x7B,0xCF,0xCF,0xFB,0x7F,0xDF,0xEF,0x65,0x22,0x62,0x80,0x64,0x1F, +0x07,0xF2,0x32,0x22,0xE1,0x40,0x30,0x56,0x8B,0xFF,0x76,0xB0,0x86,0xD0,0x2C,0xD0,0x73,0xFF,0xC3,0x30, +0xA0,0x28,0x86,0x54,0xBD,0xC0,0x7F,0xA8,0x07,0xF7,0xE7,0x83,0x94,0x42,0x0B,0x7E,0xA7,0xB2,0x25,0x25, +0x29,0x7D,0x77,0xB8,0x06,0xF6,0x6D,0xB3,0x34,0xBE,0x05,0xCE,0xC6,0x93,0x6D,0x33,0xA3,0x8B,0xCC,0x4E, +0x02,0xD8,0xE4,0xC6,0x36,0xB4,0x74,0xE2,0x66,0xD4,0xF4,0xE6,0x76,0xF4,0x78,0x5A,0x03,0xD9,0xEC,0xD6, +0x37,0xB5,0x7C,0xF2,0x67,0xD5,0xFC,0xF6,0x77,0xF5,0x11,0x3E,0xE2,0xD4,0xE5,0xC7,0xB6,0xB6,0x75,0xE3, +0xE6,0xD6,0xF5,0xE7,0xF6,0xF6,0x19,0x2E,0xE7,0xD5,0xED,0xD7,0xB7,0xB7,0x7D,0xF3,0xE7,0xD7,0xFD,0xF7, +0xF7,0xF7,0x7C,0xAA,0x8F,0xD9,0x8E,0x4C,0x57,0xB6,0xDE,0xB2,0x48,0xDE,0x69,0xAE,0x58,0x0C,0xD5,0x18, +0x2C,0x7C,0xC6,0x5C,0xBE,0xB4,0xBA,0x45,0x49,0xDF,0xA6,0xAA,0x63,0x44,0x47,0xCB,0x40,0x97,0xA6,0x0B, +0xE0,0xE5,0x17,0xF2,0x4D,0x50,0x17,0xB1,0x70,0x87,0x17,0xDC,0x7B,0xF7,0x7F,0x1D,0x9F,0xDB,0x1F,0xC2, +0x4C,0x51,0xC7,0x98,0x7D,0x14,0x72,0x42,0x0A,0x9A,0xE6,0xCE,0x3E,0xBC,0x76,0xEA,0x6E,0xDC,0xF6,0xEE, +0x7E,0xFC,0xDA,0x38,0x0B,0x9B,0xEE,0xDE,0x3F,0xBD,0x7E,0xFA,0x6F,0xDD,0xFE,0xFE,0x7F,0xFD,0x43,0x69, +0x53,0x91,0xE7,0xCF,0xBE,0xBE,0x77,0xEB,0xEE,0xDE,0xF7,0xEF,0xFE,0xFE,0x67,0x71,0x4E,0x90,0xEF,0xDF, +0xBF,0xBF,0x7F,0xFB,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x80,0x04,0x10,0x20,0x10,0x20, +0x40,0x40,0x90,0x24,0x50,0x60,0x08,0x10,0x01,0x01,0x88,0x14,0x11,0x21,0x18,0x30,0x41,0x41,0x98,0x34, +0x51,0x61,0x01,0x01,0x80,0x02,0x81,0x05,0x90,0x22,0x11,0x21,0xC0,0x42,0x91,0x25,0xD0,0x62,0x09,0x11, +0x81,0x03,0x89,0x15,0x91,0x23,0x19,0x31,0xC1,0x43,0x99,0x35,0xD1,0x63,0x40,0x40,0x02,0x04,0xC0,0x44, +0x12,0x24,0x50,0x60,0x42,0x44,0xD0,0x64,0x52,0x64,0x48,0x50,0x03,0x05,0xC8,0x54,0x13,0x25,0x58,0x70, +0x43,0x45,0xD8,0x74,0x53,0x65,0x41,0x41,0x82,0x06,0xC1,0x45,0x92,0x26,0x51,0x61,0xC2,0x46,0xD1,0x65, +0xD2,0x66,0x49,0x51,0x83,0x07,0xC9,0x55,0x93,0x27,0x59,0x71,0xC3,0x47,0xD9,0x75,0xD3,0x67,0x02,0x08, +0x08,0x08,0x82,0x0C,0x18,0x28,0x12,0x28,0x48,0x48,0x92,0x2C,0x58,0x68,0x0A,0x18,0x09,0x09,0x8A,0x1C, +0x19,0x29,0x1A,0x38,0x49,0x49,0x9A,0x3C,0x59,0x69,0x03,0x09,0x88,0x0A,0x83,0x0D,0x98,0x2A,0x13,0x29, +0xC8,0x4A,0x93,0x2D,0xD8,0x6A,0x0B,0x19,0x89,0x0B,0x8B,0x1D,0x99,0x2B,0x1B,0x39,0xC9,0x4B,0x9B,0x3D, +0xD9,0x6B,0x42,0x48,0x0A,0x0C,0xC2,0x4C,0x1A,0x2C,0x52,0x68,0x4A,0x4C,0xD2,0x6C,0x5A,0x6C,0x4A,0x58, +0x0B,0x0D,0xCA,0x5C,0x1B,0x2D,0x5A,0x78,0x4B,0x4D,0xDA,0x7C,0x5B,0x6D,0x43,0x49,0x8A,0x0E,0xC3,0x4D, +0x9A,0x2E,0x53,0x69,0xCA,0x4E,0xD3,0x6D,0xDA,0x6E,0x4B,0x59,0x8B,0x0F,0xCB,0x5D,0x9B,0x2F,0x5B,0x79, +0xCB,0x4F,0xDB,0x7D,0xDB,0x6F,0x04,0x80,0x20,0x10,0x84,0x84,0x30,0x30,0x14,0xA0,0x60,0x50,0x94,0xA4, +0x70,0x70,0x0C,0x90,0x21,0x11,0x8C,0x94,0x31,0x31,0x1C,0xB0,0x61,0x51,0x9C,0xB4,0x71,0x71,0x05,0x81, +0xA0,0x12,0x85,0x85,0xB0,0x32,0x15,0xA1,0xE0,0x52,0x95,0xA5,0xF0,0x72,0x0D,0x91,0xA1,0x13,0x8D,0x95, +0xB1,0x33,0x1D,0xB1,0xE1,0x53,0x9D,0xB5,0xF1,0x73,0x44,0xC0,0x22,0x14,0xC4,0xC4,0x32,0x34,0x54,0xE0, +0x62,0x54,0xD4,0xE4,0x72,0x74,0x4C,0xD0,0x23,0x15,0xCC,0xD4,0x33,0x35,0x5C,0xF0,0x63,0x55,0xDC,0xF4, +0x73,0x75,0x45,0xC1,0xA2,0x16,0xC5,0xC5,0xB2,0x36,0x55,0xE1,0xE2,0x56,0xD5,0xE5,0xF2,0x76,0x4D,0xD1, +0xA3,0x17,0xCD,0xD5,0xB3,0x37,0x5D,0xF1,0xE3,0x57,0xDD,0xF5,0xF3,0x77,0x06,0x88,0x28,0x18,0x86,0x8C, +0x38,0x38,0x16,0xA8,0x68,0x58,0x96,0xAC,0x78,0x78,0x0E,0x98,0x29,0x19,0x8E,0x9C,0x39,0x39,0x1E,0xB8, +0x69,0x59,0x9E,0xBC,0x79,0x79,0x07,0x89,0xA8,0x1A,0x87,0x8D,0xB8,0x3A,0x17,0xA9,0xE8,0x5A,0x97,0xAD, +0xF8,0x7A,0x0F,0x99,0xA9,0x1B,0x8F,0x9D,0xB9,0x3B,0x1F,0xB9,0xE9,0x5B,0x9F,0xBD,0xF9,0x7B,0x46,0xC8, +0x2A,0x1C,0xC6,0xCC,0x3A,0x3C,0x56,0xE8,0x6A,0x5C,0xD6,0xEC,0x7A,0x7C,0x4E,0xD8,0x2B,0x1D,0xCE,0xDC, +0x3B,0x3D,0x5E,0xF8,0x6B,0x5D,0xDE,0xFC,0x7B,0x7D,0x47,0xC9,0xAA,0x1E,0xC7,0xCD,0xBA,0x3E,0x57,0xE9, +0xEA,0x5E,0xD7,0xED,0xFA,0x7E,0x4F,0xD9,0xAB,0x1F,0xCF,0xDD,0xBB,0x3F,0x5F,0xF9,0xEB,0x5F,0xDF,0xFD, +0xFB,0x7F,0x20,0x02,0x04,0x80,0xA0,0x06,0x14,0xA0,0x30,0x22,0x44,0xC0,0xB0,0x26,0x54,0xE0,0x28,0x12, +0x05,0x81,0xA8,0x16,0x15,0xA1,0x38,0x32,0x45,0xC1,0xB8,0x36,0x55,0xE1,0x21,0x03,0x84,0x82,0xA1,0x07, +0x94,0xA2,0x31,0x23,0xC4,0xC2,0xB1,0x27,0xD4,0xE2,0x29,0x13,0x85,0x83,0xA9,0x17,0x95,0xA3,0x39,0x33, +0xC5,0xC3,0xB9,0x37,0xD5,0xE3,0x60,0x42,0x06,0x84,0xE0,0x46,0x16,0xA4,0x70,0x62,0x46,0xC4,0xF0,0x66, +0x56,0xE4,0x68,0x52,0x07,0x85,0xE8,0x56,0x17,0xA5,0x78,0x72,0x47,0xC5,0xF8,0x76,0x57,0xE5,0x61,0x43, +0x86,0x86,0xE1,0x47,0x96,0xA6,0x71,0x63,0xC6,0xC6,0xF1,0x67,0xD6,0xE6,0x69,0x53,0x87,0x87,0xE9,0x57, +0x97,0xA7,0x79,0x73,0xC7,0xC7,0xF9,0x77,0xD7,0xE7,0x22,0x0A,0x0C,0x88,0xA2,0x0E,0x1C,0xA8,0x32,0x2A, +0x4C,0xC8,0xB2,0x2E,0x5C,0xE8,0x2A,0x1A,0x0D,0x89,0xAA,0x1E,0x1D,0xA9,0x3A,0x3A,0x4D,0xC9,0xBA,0x3E, +0x5D,0xE9,0x23,0x0B,0x8C,0x8A,0xA3,0x0F,0x9C,0xAA,0x33,0x2B,0xCC,0xCA,0xB3,0x2F,0xDC,0xEA,0x2B,0x1B, +0x8D,0x8B,0xAB,0x1F,0x9D,0xAB,0x3B,0x3B,0xCD,0xCB,0xBB,0x3F,0xDD,0xEB,0x62,0x4A,0x0E,0x8C,0xE2,0x4E, +0x1E,0xAC,0x72,0x6A,0x4E,0xCC,0xF2,0x6E,0x5E,0xEC,0x6A,0x5A,0x0F,0x8D,0xEA,0x5E,0x1F,0xAD,0x7A,0x7A, +0x4F,0xCD,0xFA,0x7E,0x5F,0xED,0x63,0x4B,0x8E,0x8E,0xE3,0x4F,0x9E,0xAE,0x73,0x6B,0xCE,0xCE,0xF3,0x6F, +0xDE,0xEE,0x6B,0x5B,0x8F,0x8F,0xEB,0x5F,0x9F,0xAF,0x7B,0x7B,0xCF,0xCF,0xFB,0x7F,0xDF,0xEF,0x24,0x82, +0x24,0x90,0xA4,0x86,0x34,0xB0,0x34,0xA2,0x64,0xD0,0xB4,0xA6,0x74,0xF0,0x2C,0x92,0x25,0x91,0xAC,0x96, +0x35,0xB1,0x3C,0xB2,0x65,0xD1,0xBC,0xB6,0x75,0xF1,0x25,0x83,0xA4,0x92,0xA5,0x87,0xB4,0xB2,0x35,0xA3, +0xE4,0xD2,0xB5,0xA7,0xF4,0xF2,0x2D,0x93,0xA5,0x93,0xAD,0x97,0xB5,0xB3,0x3D,0xB3,0xE5,0xD3,0xBD,0xB7, +0xF5,0xF3,0x64,0xC2,0x26,0x94,0xE4,0xC6,0x36,0xB4,0x74,0xE2,0x66,0xD4,0xF4,0xE6,0x76,0xF4,0x6C,0xD2, +0x27,0x95,0xEC,0xD6,0x37,0xB5,0x7C,0xF2,0x67,0xD5,0xFC,0xF6,0x77,0xF5,0x65,0xC3,0xA6,0x96,0xE5,0xC7, +0xB6,0xB6,0x75,0xE3,0xE6,0xD6,0xF5,0xE7,0xF6,0xF6,0x6D,0xD3,0xA7,0x97,0xED,0xD7,0xB7,0xB7,0x7D,0xF3, +0xE7,0xD7,0xFD,0xF7,0xF7,0xF7,0x26,0x8A,0x2C,0x98,0xA6,0x8E,0x3C,0xB8,0x36,0xAA,0x6C,0xD8,0xB6,0xAE, +0x7C,0xF8,0x2E,0x9A,0x2D,0x99,0xAE,0x9E,0x3D,0xB9,0x3E,0xBA,0x6D,0xD9,0xBE,0xBE,0x7D,0xF9,0x27,0x8B, +0xAC,0x9A,0xA7,0x8F,0xBC,0xBA,0x37,0xAB,0xEC,0xDA,0xB7,0xAF,0xFC,0xFA,0x2F,0x9B,0xAD,0x9B,0xAF,0x9F, +0xBD,0xBB,0x3F,0xBB,0xED,0xDB,0xBF,0xBF,0xFD,0xFB,0x66,0xCA,0x2E,0x9C,0xE6,0xCE,0x3E,0xBC,0x76,0xEA, +0x6E,0xDC,0xF6,0xEE,0x7E,0xFC,0x6E,0xDA,0x2F,0x9D,0xEE,0xDE,0x3F,0xBD,0x7E,0xFA,0x6F,0xDD,0xFE,0xFE, +0x7F,0xFD,0x67,0xCB,0xAE,0x9E,0xE7,0xCF,0xBE,0xBE,0x77,0xEB,0xEE,0xDE,0xF7,0xEF,0xFE,0xFE,0x6F,0xDB, +0xAF,0x9F,0xEF,0xDF,0xBF,0xBF,0x7F,0xFB,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x80,0x04, +0x10,0x20,0x10,0x20,0x40,0x40,0x90,0x24,0x50,0x60,0x08,0x10,0x01,0x01,0x88,0x14,0x11,0x21,0x18,0x30, +0x41,0x41,0x98,0x34,0x51,0x61,0x01,0x01,0x80,0x02,0x81,0x05,0x90,0x22,0x11,0x21,0xC0,0x42,0x91,0x25, +0xD0,0x62,0x09,0x11,0x81,0x03,0x89,0x15,0x91,0x23,0x19,0x31,0xC1,0x43,0x99,0x35,0xD1,0x63,0x40,0x40, +0x02,0x04,0xC0,0x44,0x12,0x24,0x50,0x60,0x42,0x44,0xD0,0x64,0x52,0x64,0x48,0x50,0x03,0x05,0xC8,0x54, +0x13,0x25,0x58,0x70,0x43,0x45,0xD8,0x74,0x53,0x65,0x41,0x41,0x82,0x06,0xC1,0x45,0x92,0x26,0x51,0x61, +0xC2,0x46,0xD1,0x65,0xD2,0x66,0x49,0x51,0x83,0x07,0xC9,0x55,0x93,0x27,0x59,0x71,0xC3,0x47,0xD9,0x75, +0xD3,0x67,0x02,0x08,0x08,0x08,0x82,0x0C,0x18,0x28,0x12,0x28,0x48,0x48,0x92,0x2C,0x58,0x68,0x0A,0x18, +0x09,0x09,0x8A,0x1C,0x19,0x29,0x1A,0x38,0x49,0x49,0x9A,0x3C,0x59,0x69,0x03,0x09,0x88,0x0A,0x83,0x0D, +0x98,0x2A,0x13,0x29,0xC8,0x4A,0x93,0x2D,0xD8,0x6A,0x0B,0x19,0x89,0x0B,0x8B,0x1D,0x99,0x2B,0x1B,0x39, +0xC9,0x4B,0x9B,0x3D,0xD9,0x6B,0x42,0x48,0x0A,0x0C,0xC2,0x4C,0x1A,0x2C,0x52,0x68,0x4A,0x4C,0xD2,0x6C, +0x5A,0x6C,0x4A,0x58,0x0B,0x0D,0xCA,0x5C,0x1B,0x2D,0x5A,0x78,0x4B,0x4D,0xDA,0x7C,0x5B,0x6D,0x43,0x49, +0x8A,0x0E,0xC3,0x4D,0x9A,0x2E,0x53,0x69,0xCA,0x4E,0xD3,0x6D,0xDA,0x6E,0x4B,0x59,0x8B,0x0F,0xCB,0x5D, +0x9B,0x2F,0x5B,0x79,0xCB,0x4F,0xDB,0x7D,0xDB,0x6F,0x04,0x80,0x20,0x10,0x84,0x84,0x30,0x30,0x14,0xA0, +0x60,0x50,0x94,0xA4,0x70,0x70,0x0C,0x90,0x21,0x11,0x8C,0x94,0x31,0x31,0x1C,0xB0,0x61,0x51,0x9C,0xB4, +0x71,0x71,0x05,0x81,0xA0,0x12,0x85,0x85,0xB0,0x32,0x15,0xA1,0xE0,0x52,0x95,0xA5,0xF0,0x72,0x0D,0x91, +0xA1,0x13,0x8D,0x95,0xB1,0x33,0x1D,0xB1,0xE1,0x53,0x9D,0xB5,0xF1,0x73,0x44,0xC0,0x22,0x14,0xC4,0xC4, +0x32,0x34,0x54,0xE0,0x62,0x54,0xD4,0xE4,0x72,0x74,0x4C,0xD0,0x23,0x15,0xCC,0xD4,0x33,0x35,0x5C,0xF0, +0x63,0x55,0xDC,0xF4,0x73,0x75,0x45,0xC1,0xA2,0x16,0xC5,0xC5,0xB2,0x36,0x55,0xE1,0xE2,0x56,0xD5,0xE5, +0xF2,0x76,0x4D,0xD1,0xA3,0x17,0xCD,0xD5,0xB3,0x37,0x5D,0xF1,0xE3,0x57,0xDD,0xF5,0xF3,0x77,0x06,0x88, +0x28,0x18,0x86,0x8C,0x38,0x38,0x16,0xA8,0x68,0x58,0x96,0xAC,0x78,0x78,0x0E,0x98,0x29,0x19,0x8E,0x9C, +0x39,0x39,0x1E,0xB8,0x69,0x59,0x9E,0xBC,0x79,0x79,0x07,0x89,0xA8,0x1A,0x87,0x8D,0xB8,0x3A,0x17,0xA9, +0xE8,0x5A,0x97,0xAD,0xF8,0x7A,0x0F,0x99,0xA9,0x1B,0x8F,0x9D,0xB9,0x3B,0x1F,0xB9,0xE9,0x5B,0x9F,0xBD, +0xF9,0x7B,0x46,0xC8,0x2A,0x1C,0xC6,0xCC,0x3A,0x3C,0x56,0xE8,0x6A,0x5C,0xD6,0xEC,0x7A,0x7C,0x4E,0xD8, +0x2B,0x1D,0xCE,0xDC,0x3B,0x3D,0x5E,0xF8,0x6B,0x5D,0xDE,0xFC,0x7B,0x7D,0x47,0xC9,0xAA,0x1E,0xC7,0xCD, +0xBA,0x3E,0x57,0xE9,0xEA,0x5E,0xD7,0xED,0xFA,0x7E,0x4F,0xD9,0xAB,0x1F,0xCF,0xDD,0xBB,0x3F,0x5F,0xF9, +0xEB,0x5F,0xDF,0xFD,0xFB,0x7F,0x20,0x02,0x04,0x80,0xA0,0x06,0x14,0xA0,0x30,0x22,0x44,0xC0,0xB0,0x26, +0x54,0xE0,0x28,0x12,0x05,0x81,0xA8,0x16,0x15,0xA1,0x38,0x32,0x45,0xC1,0xB8,0x36,0x55,0xE1,0x21,0x03, +0x84,0x82,0xA1,0x07,0x94,0xA2,0x31,0x23,0xC4,0xC2,0xB1,0x27,0xD4,0xE2,0x29,0x13,0x85,0x83,0xA9,0x17, +0x95,0xA3,0x39,0x33,0xC5,0xC3,0xB9,0x37,0xD5,0xE3,0x60,0x42,0x06,0x84,0xE0,0x46,0x16,0xA4,0x70,0x62, +0x46,0xC4,0xF0,0x66,0x56,0xE4,0x68,0x52,0x07,0x85,0xE8,0x56,0x17,0xA5,0x78,0x72,0x47,0xC5,0xF8,0x76, +0x57,0xE5,0x61,0x43,0x86,0x86,0xE1,0x47,0x96,0xA6,0x71,0x63,0xC6,0xC6,0xF1,0x67,0xD6,0xE6,0x69,0x53, +0x87,0x87,0xE9,0x57,0x97,0xA7,0x79,0x73,0xC7,0xC7,0xF9,0x77,0xD7,0xE7,0x22,0x0A,0x0C,0x88,0xA2,0x0E, +0x1C,0xA8,0x32,0x2A,0x4C,0xC8,0xB2,0x2E,0x5C,0xE8,0x2A,0x1A,0x0D,0x89,0xAA,0x1E,0x1D,0xA9,0x3A,0x3A, +0x4D,0xC9,0xBA,0x3E,0x5D,0xE9,0x23,0x0B,0x8C,0x8A,0xA3,0x0F,0x9C,0xAA,0x33,0x2B,0xCC,0xCA,0xB3,0x2F, +0xDC,0xEA,0x2B,0x1B,0x8D,0x8B,0xAB,0x1F,0x9D,0xAB,0x3B,0x3B,0xCD,0xCB,0xBB,0x3F,0xDD,0xEB,0x62,0x4A, +0x0E,0x8C,0xE2,0x4E,0x1E,0xAC,0x72,0x6A,0x4E,0xCC,0xF2,0x6E,0x5E,0xEC,0x6A,0x5A,0x0F,0x8D,0xEA,0x5E, +0x1F,0xAD,0x7A,0x7A,0x4F,0xCD,0xFA,0x7E,0x5F,0xED,0x63,0x4B,0x8E,0x8E,0xE3,0x4F,0x9E,0xAE,0x73,0x6B, +0xCE,0xCE,0xF3,0x6F,0xDE,0xEE,0x6B,0x5B,0x8F,0x8F,0xEB,0x5F,0x9F,0xAF,0x7B,0x7B,0xCF,0xCF,0xFB,0x7F, +0xDF,0xEF,0x24,0x82,0x24,0x90,0xA4,0x86,0x34,0xB0,0x34,0xA2,0x64,0xD0,0xB4,0xA6,0x74,0xF0,0x2C,0x92, +0x25,0x91,0xAC,0x96,0x35,0xB1,0x3C,0xB2,0x65,0xD1,0xBC,0xB6,0x75,0xF1,0x25,0x83,0xA4,0x92,0xA5,0x87, +0xB4,0xB2,0x35,0xA3,0xE4,0xD2,0xB5,0xA7,0xF4,0xF2,0x2D,0x93,0xA5,0x93,0xAD,0x97,0xB5,0xB3,0x3D,0xB3, +0xE5,0xD3,0xBD,0xB7,0xF5,0xF3,0x64,0xC2,0x26,0x94,0xE4,0xC6,0x36,0xB4,0x74,0xE2,0x66,0xD4,0xF4,0xE6, +0x76,0xF4,0x6C,0xD2,0x27,0x95,0xEC,0xD6,0x37,0xB5,0x7C,0xF2,0x67,0xD5,0xFC,0xF6,0x77,0xF5,0x65,0xC3, +0xA6,0x96,0xE5,0xC7,0xB6,0xB6,0x75,0xE3,0xE6,0xD6,0xF5,0xE7,0xF6,0xF6,0x6D,0xD3,0xA7,0x97,0xED,0xD7, +0xB7,0xB7,0x7D,0xF3,0xE7,0xD7,0xFD,0xF7,0xF7,0xF7,0x26,0x8A,0x2C,0x98,0xA6,0x8E,0x3C,0xB8,0x36,0xAA, +0x6C,0xD8,0xB6,0xAE,0x7C,0xF8,0x2E,0x9A,0x2D,0x99,0xAE,0x9E,0x3D,0xB9,0x3E,0xBA,0x6D,0xD9,0xBE,0xBE, +0x7D,0xF9,0x27,0x8B,0xAC,0x9A,0xA7,0x8F,0xBC,0xBA,0x37,0xAB,0xEC,0xDA,0xB7,0xAF,0xFC,0xFA,0x2F,0x9B, +0xAD,0x9B,0xAF,0x9F,0xBD,0xBB,0x3F,0xBB,0xED,0xDB,0xBF,0xBF,0xFD,0xFB,0x66,0xCA,0x2E,0x9C,0xE6,0xCE, +0x3E,0xBC,0x76,0xEA,0x6E,0xDC,0xF6,0xEE,0x7E,0xFC,0x6E,0xDA,0x2F,0x9D,0xEE,0xDE,0x3F,0xBD,0x7E,0xFA, +0x6F,0xDD,0xFE,0xFE,0x7F,0xFD,0x67,0xCB,0xAE,0x9E,0xE7,0xCF,0xBE,0xBE,0x77,0xEB,0xEE,0xDE,0xF7,0xEF, +0xFE,0xFE,0x6F,0xDB,0xAF,0x9F,0xEF,0xDF,0xBF,0xBF,0x7F,0xFB,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,0x00,0x00, +0x00,0x00,0x80,0x04,0x10,0x20,0x10,0x20,0x40,0x40,0x90,0x24,0x50,0x60,0x08,0x10,0x01,0x01,0x88,0x14, +0x11,0x21,0x18,0x30,0x41,0x41,0x98,0x34,0x51,0x61,0x01,0x01,0x80,0x02,0x81,0x05,0x90,0x22,0x11,0x21, +0xC0,0x42,0x91,0x25,0xD0,0x62,0x09,0x11,0x81,0x03,0x89,0x15,0x91,0x23,0x19,0x31,0xC1,0x43,0x99,0x35, +0xD1,0x63,0x40,0x40,0x02,0x04,0xC0,0x44,0x12,0x24,0x50,0x60,0x42,0x44,0xD0,0x64,0x52,0x64,0x48,0x50, +0x03,0x05,0xC8,0x54,0x13,0x25,0x58,0x70,0x43,0x45,0xD8,0x74,0x53,0x65,0x41,0x41,0x82,0x06,0xC1,0x45, +0x92,0x26,0x51,0x61,0xC2,0x46,0xD1,0x65,0xD2,0x66,0x49,0x51,0x83,0x07,0xC9,0x55,0x93,0x27,0x59,0x71, +0xC3,0x47,0xD9,0x75,0xD3,0x67,0x02,0x08,0x08,0x08,0x82,0x0C,0x18,0x28,0x12,0x28,0x48,0x48,0x92,0x2C, +0x58,0x68,0x0A,0x18,0x09,0x09,0x8A,0x1C,0x19,0x29,0x1A,0x38,0x49,0x49,0x9A,0x3C,0x59,0x69,0x03,0x09, +0x88,0x0A,0x83,0x0D,0x98,0x2A,0x13,0x29,0xC8,0x4A,0x93,0x2D,0xD8,0x6A,0x0B,0x19,0x89,0x0B,0x8B,0x1D, +0x99,0x2B,0x1B,0x39,0xC9,0x4B,0x9B,0x3D,0xD9,0x6B,0x42,0x48,0x0A,0x0C,0xC2,0x4C,0x1A,0x2C,0x52,0x68, +0x4A,0x4C,0xD2,0x6C,0x5A,0x6C,0x4A,0x58,0x0B,0x0D,0xCA,0x5C,0x1B,0x2D,0x5A,0x78,0x4B,0x4D,0xDA,0x7C, +0x5B,0x6D,0x43,0x49,0x8A,0x0E,0xC3,0x4D,0x9A,0x2E,0x53,0x69,0xCA,0x4E,0xD3,0x6D,0xDA,0x6E,0x4B,0x59, +0x8B,0x0F,0xCB,0x5D,0x9B,0x2F,0x5B,0x79,0xCB,0x4F,0xDB,0x7D,0xDB,0x6F,0x04,0x80,0x20,0x10,0x84,0x84, +0x30,0x30,0x14,0xA0,0x60,0x50,0x94,0xA4,0x70,0x70,0x0C,0x90,0x21,0x11,0x8C,0x94,0x31,0x31,0x1C,0xB0, +0x61,0x51,0x9C,0xB4,0x71,0x71,0x05,0x81,0xA0,0x12,0x85,0x85,0xB0,0x32,0x15,0xA1,0xE0,0x52,0x95,0xA5, +0xF0,0x72,0x0D,0x91,0xA1,0x13,0x8D,0x95,0xB1,0x33,0x1D,0xB1,0xE1,0x53,0x9D,0xB5,0xF1,0x73,0x44,0xC0, +0x22,0x14,0xC4,0xC4,0x32,0x34,0x54,0xE0,0x62,0x54,0xD4,0xE4,0x72,0x74,0x4C,0xD0,0x23,0x15,0xCC,0xD4, +0x33,0x35,0x5C,0xF0,0x63,0x55,0xDC,0xF4,0x73,0x75,0x45,0xC1,0xA2,0x16,0xC5,0xC5,0xB2,0x36,0x55,0xE1, +0xE2,0x56,0xD5,0xE5,0xF2,0x76,0x4D,0xD1,0xA3,0x17,0xCD,0xD5,0xB3,0x37,0x5D,0xF1,0xE3,0x57,0xDD,0xF5, +0xF3,0x77,0x06,0x88,0x28,0x18,0x86,0x8C,0x38,0x38,0x16,0xA8,0x68,0x58,0x96,0xAC,0x78,0x78,0x0E,0x98, +0x29,0x19,0x8E,0x9C,0x39,0x39,0x1E,0xB8,0x69,0x59,0x9E,0xBC,0x79,0x79,0x07,0x89,0xA8,0x1A,0x87,0x8D, +0xB8,0x3A,0x17,0xA9,0xE8,0x5A,0x97,0xAD,0xF8,0x7A,0x0F,0x99,0xA9,0x1B,0x8F,0x9D,0xB9,0x3B,0x1F,0xB9, +0xE9,0x5B,0x9F,0xBD,0xF9,0x7B,0x46,0xC8,0x2A,0x1C,0xC6,0xCC,0x3A,0x3C,0x56,0xE8,0x6A,0x5C,0xD6,0xEC, +0x7A,0x7C,0x4E,0xD8,0x2B,0x1D,0xCE,0xDC,0x3B,0x3D,0x5E,0xF8,0x6B,0x5D,0xDE,0xFC,0x7B,0x7D,0x47,0xC9, +0xAA,0x1E,0xC7,0xCD,0xBA,0x3E,0x57,0xE9,0xEA,0x5E,0xD7,0xED,0xFA,0x7E,0x4F,0xD9,0xAB,0x1F,0xCF,0xDD, +0xBB,0x3F,0x5F,0xF9,0xEB,0x5F,0xDF,0xFD,0xFB,0x7F,0x20,0x02,0x04,0x80,0xA0,0x06,0x14,0xA0,0x30,0x22, +0x44,0xC0,0xB0,0x26,0x54,0xE0,0x28,0x12,0x05,0x81,0xA8,0x16,0x15,0xA1,0x38,0x32,0x45,0xC1,0xB8,0x36, +0x55,0xE1,0x21,0x03,0x84,0x82,0xA1,0x07,0x94,0xA2,0x31,0x23,0xC4,0xC2,0xB1,0x27,0xD4,0xE2,0x29,0x13, +0x85,0x83,0xA9,0x17,0x95,0xA3,0x39,0x33,0xC5,0xC3,0xB9,0x37,0xD5,0xE3,0x60,0x42,0x06,0x84,0xE0,0x46, +0x16,0xA4,0x70,0x62,0x46,0xC4,0xF0,0x66,0x56,0xE4,0x68,0x52,0x07,0x85,0xE8,0x56,0x17,0xA5,0x78,0x72, +0x47,0xC5,0xF8,0x76,0x57,0xE5,0x61,0x43,0x86,0x86,0xE1,0x47,0x96,0xA6,0x71,0x63,0xC6,0xC6,0xF1,0x67, +0xD6,0xE6,0x69,0x53,0x87,0x87,0xE9,0x57,0x97,0xA7,0x79,0x73,0xC7,0xC7,0xF9,0x77,0xD7,0xE7,0x22,0x0A, +0x0C,0x88,0xA2,0x0E,0x1C,0xA8,0x32,0x2A,0x4C,0xC8,0xB2,0x2E,0x5C,0xE8,0x2A,0x1A,0x0D,0x89,0xAA,0x1E, +0x1D,0xA9,0x3A,0x3A,0x4D,0xC9,0xBA,0x3E,0x5D,0xE9,0x23,0x0B,0x8C,0x8A,0xA3,0x0F,0x9C,0xAA,0x33,0x2B, +0xCC,0xCA,0xB3,0x2F,0xDC,0xEA,0x2B,0x1B,0x8D,0x8B,0xAB,0x1F,0x9D,0xAB,0x3B,0x3B,0xCD,0xCB,0xBB,0x3F, +0xDD,0xEB,0x62,0x4A,0x0E,0x8C,0xE2,0x4E,0x1E,0xAC,0x72,0x6A,0x4E,0xCC,0xF2,0x6E,0x5E,0xEC,0x6A,0x5A, +0x0F,0x8D,0xEA,0x5E,0x1F,0xAD,0x7A,0x7A,0x4F,0xCD,0xFA,0x7E,0x5F,0xED,0x63,0x4B,0x8E,0x8E,0xE3,0x4F, +0x9E,0xAE,0x73,0x6B,0xCE,0xCE,0xF3,0x6F,0xDE,0xEE,0x6B,0x5B,0x8F,0x8F,0xEB,0x5F,0x9F,0xAF,0x7B,0x7B, +0xCF,0xCF,0xFB,0x7F,0xDF,0xEF,0x24,0x82,0x24,0x90,0xA4,0x86,0x34,0xB0,0x34,0xA2,0x64,0xD0,0xB4,0xA6, +0x74,0xF0,0x2C,0x92,0x25,0x91,0xAC,0x96,0x35,0xB1,0x3C,0xB2,0x65,0xD1,0xBC,0xB6,0x75,0xF1,0x25,0x83, +0xA4,0x92,0xA5,0x87,0xB4,0xB2,0x35,0xA3,0xE4,0xD2,0xB5,0xA7,0xF4,0xF2,0x2D,0x93,0xA5,0x93,0xAD,0x97, +0xB5,0xB3,0x3D,0xB3,0xE5,0xD3,0xBD,0xB7,0xF5,0xF3,0x64,0xC2,0x26,0x94,0xE4,0xC6,0x36,0xB4,0x74,0xE2, +0x66,0xD4,0xF4,0xE6,0x76,0xF4,0x6C,0xD2,0x27,0x95,0xEC,0xD6,0x37,0xB5,0x7C,0xF2,0x67,0xD5,0xFC,0xF6, +0x77,0xF5,0x65,0xC3,0xA6,0x96,0xE5,0xC7,0xB6,0xB6,0x75,0xE3,0xE6,0xD6,0xF5,0xE7,0xF6,0xF6,0x6D,0xD3, +0xA7,0x97,0xED,0xD7,0xB7,0xB7,0x7D,0xF3,0xE7,0xD7,0xFD,0xF7,0xF7,0xF7,0x26,0x8A,0x2C,0x98,0xA6,0x8E, +0x3C,0xB8,0x36,0xAA,0x6C,0xD8,0xB6,0xAE,0x7C,0xF8,0x2E,0x9A,0x2D,0x99,0xAE,0x9E,0x3D,0xB9,0x3E,0xBA, +0x6D,0xD9,0xBE,0xBE,0x7D,0xF9,0x27,0x8B,0xAC,0x9A,0xA7,0x8F,0xBC,0xBA,0x37,0xAB,0xEC,0xDA,0xB7,0xAF, +0xFC,0xFA,0x2F,0x9B,0xAD,0x9B,0xAF,0x9F,0xBD,0xBB,0x3F,0xBB,0xED,0xDB,0xBF,0xBF,0xFD,0xFB,0x66,0xCA, +0x2E,0x9C,0xE6,0xCE,0x3E,0xBC,0x76,0xEA,0x6E,0xDC,0xF6,0xEE,0x7E,0xFC,0x6E,0xDA,0x2F,0x9D,0xEE,0xDE, +0x3F,0xBD,0x7E,0xFA,0x6F,0xDD,0xFE,0xFE,0x7F,0xFD,0x67,0xCB,0xAE,0x9E,0xE7,0xCF,0xBE,0xBE,0x77,0xEB, +0xEE,0xDE,0xF7,0xEF,0xFE,0xFE,0x6F,0xDB,0xAF,0x9F,0xEF,0xDF,0xBF,0xBF,0x7F,0xFB,0xEF,0xDF,0xFF,0xFF, +0x7B,0xA9,0x80,0x00,0x55,0x40,0xA9,0x57,0x94,0x3C,0x8D,0x02,0x2B,0x50,0x78,0xA9,0xB1,0x7B,0x88,0xB8, +0x01,0x41,0x67,0x7F,0xC6,0xCC,0x46,0x33,0xBE,0x01,0xB3,0x72,0xAD,0x23,0x01,0x8D,0x05,0x22,0x28,0x56, +0x1C,0x7E,0x88,0xD0,0x58,0x42,0x96,0xC3,0xD6,0xA2,0x09,0x0D,0x87,0x03,0xA9,0xAB,0x14,0x51,0x19,0x7A, +0xC5,0x63,0x46,0xE1,0x53,0x2B,0xF7,0xE9,0x04,0x44,0xEB,0x9B,0xA7,0xFA,0x68,0x47,0xA5,0x54,0x6F,0x7F, +0xF1,0xE1,0xC8,0xE5,0x7C,0x15,0x68,0x5A,0x9F,0xA8,0x7D,0x76,0xD7,0x21,0xA0,0x46,0x63,0xB9,0x97,0x7E, +0xB4,0x44,0xF8,0x47,0x0D,0x12,0xBE,0x8F,0x42,0x5C,0xE0,0x87,0x0F,0xF2,0xA1,0xF3,0x06,0x00,0x2D,0x72, +0x34,0x37,0x61,0x56,0x64,0x57,0xFE,0x97,0x33,0xB6,0x47,0xAC,0x2C,0x48,0xDD,0x44,0x67,0x08,0x91,0x5A, +0xC6,0x2D,0x1E,0x4E,0x1B,0xB7,0x9A,0x3C,0x2F,0x49,0x86,0x62,0xB8,0xA3,0x12,0x3D,0xAE,0x4D,0xA2,0x6C, +0x5D,0x66,0x58,0xE0,0x2B,0x6F,0x43,0xF9,0xB9,0x2C,0x6A,0x5B,0x46,0x2F,0xEB,0xAF,0xD1,0x07,0x87,0x59, +0xAF,0x48,0x70,0xFF,0x35,0xA0,0x1F,0xDF,0xD9,0xB5,0xFB,0x79,0xEF,0xE6,0xAD,0xA6,0x8F,0xAB,0x2D,0xA7, +0x9A,0xB0,0xBD,0x86,0xCA,0xD4,0x29,0x48,0xA8,0x6C,0x9F,0x5F,0x7C,0x09,0xCE,0x40,0x4E,0x24,0x7A,0x2E, +0xCB,0xC3,0x65,0x67,0xF8,0xE9,0x65,0xF1,0x0E,0xAA,0xE2,0xAF,0x67,0x27,0x73,0xAF,0x4A,0x11,0x56,0xD3, +0xDA,0x5F,0x94,0x49,0x0C,0x08,0x67,0x57,0x38,0x92,0x7B,0x10,0x4B,0x00,0x24,0x46,0x78,0x2E,0x04,0x80, +0x78,0xF8,0x0D,0x14,0x93,0x36,0x91,0xA1,0x64,0xD0,0xCE,0xB0,0xD3,0x76,0xDE,0xB0,0x26,0xE9,0x04,0xA8, +0xD0,0x3E,0x3C,0x32,0x5E,0x0D,0x90,0xA5,0x12,0x81,0x4F,0x28,0x82,0x11,0x0D,0xB8,0x13,0x34,0x14,0x21, +0xC0,0x5A,0x99,0xB1,0x53,0x74,0x02,0x1D,0x24,0xE6,0xD3,0x2C,0x91,0x4C,0x27,0x4D,0xE9,0x35,0xE5,0x37, +0xF8,0xF3,0x34,0x1F,0xCD,0x55,0x60,0xA6,0x16,0x3E,0x7D,0xBA,0xAB,0x30,0x44,0x9F,0xC1,0xDB,0xA3,0x3E, +0xA3,0xDD,0x37,0xD0,0x9E,0x74,0x72,0xF6,0xF2,0xC9,0x34,0x6C,0x84,0xC0,0xFB,0xC8,0x45,0x06,0x45,0xB2, +0x96,0x41,0x7E,0x03,0x4E,0x4A,0xAD,0x9B,0x32,0x77,0xF3,0xD8,0x04,0x07,0xE8,0xD3,0x27,0x53,0x73,0xF6, +0x32,0xA9,0xA5,0x04,0x50,0x67,0xC6,0x75,0x6F,0x1E,0x5F,0xCE,0xC3,0xA3,0x0E,0x12,0xC4,0xA7,0xEE,0x28, +0x49,0x55,0x8E,0x12,0x08,0xAB,0xB4,0x65,0x19,0xA2,0x1B,0x68,0x37,0x86,0x61,0x42,0x7F,0xC2,0xAC,0x90, +0x09,0x01,0xA7,0x72,0xBE,0x1A,0x5D,0x14,0xCA,0xF7,0x8F,0xB4,0xDB,0x0A,0x56,0x66,0x48,0xD4,0x8F,0x60, +0xB9,0xE0,0x25,0x3E,0x45,0x52,0xB2,0xCF,0x06,0xA4,0xA9,0x26,0xAA,0xCF,0xFC,0x4B,0x1E,0x4B,0x6B,0x36, +0x87,0x58,0x69,0xD1,0x85,0xC1,0xF0,0xD1,0x88,0x78,0xDB,0x2F,0xBF,0x90,0xFA,0x8A,0xE5,0x38,0xBF,0x3C, +0x3F,0xD3,0x66,0xCF,0x7A,0x7A,0xC3,0xD5,0x53,0x7A,0x50,0xE2,0x6E,0x0A,0x03,0x16,0xFB,0x9E,0xA0,0x37, +0x2B,0x5C,0x6B,0x71,0x50,0x5B,0xA5,0xF1,0x34,0x60,0xA7,0x1B,0xDF,0x13,0x20,0x02,0x04,0xC0,0x27,0xE4, +0x96,0x88,0x4A,0x20,0x7C,0x4D,0xC8,0x01,0x14,0xEF,0x28,0x12,0x05,0xC1,0xD0,0x94,0x16,0x47,0xBE,0x02, +0x15,0xDD,0x6D,0xB2,0x2A,0x3F,0xFA,0x24,0x84,0x82,0x1A,0x65,0xD5,0xE2,0xD5,0x04,0x77,0x48,0x71,0xDA, +0x0E,0x19,0x29,0x8F,0x85,0x83,0x91,0x67,0x21,0xAA,0x95,0x96,0x04,0x49,0xE7,0x9D,0x85,0xAD,0xD0,0xF0, +0x28,0xC1,0xF2,0x42,0xF4,0x24,0x50,0xC7,0xC6,0xC6,0xCA,0x3C,0xE5,0x4F,0x87,0xA0,0x01,0x85,0x48,0x39, +0x77,0xE5,0x58,0xFC,0xC7,0xD0,0x07,0x08,0x79,0x3A,0x97,0xE6,0x03,0x81,0xE1,0x87,0x2C,0x09,0x51,0x55, +0x46,0x9B,0x89,0x6F,0x2B,0x17,0xAB,0x8D,0x7E,0x29,0x9B,0x47,0x97,0xAD,0x59,0xBD,0x47,0x8A,0xC2,0xD2, +0x24,0x3A,0x22,0x0A,0x0C,0xC8,0xEC,0x8C,0x15,0xCC,0xB5,0x7A,0x6C,0xD4,0x83,0xAC,0x5D,0xA7,0x2A,0x1A, +0x0D,0xC9,0xCA,0x5E,0x00,0x22,0xF0,0x38,0x45,0x01,0x09,0xF8,0xE1,0xA7,0x23,0x96,0x8C,0x8A,0x9B,0x5F, +0x8C,0xA5,0x97,0x6B,0x8C,0x45,0xE9,0x2E,0x7F,0xA6,0xF2,0xBB,0x8D,0x8B,0x2B,0xFD,0x1F,0xA3,0xC1,0xE4, +0x2C,0xCF,0x88,0xBD,0xD4,0x0B,0x35,0x20,0x8B,0x8B,0x55,0x6B,0x32,0x04,0x52,0x24,0xCE,0xAF,0x95,0x14, +0xCC,0xE4,0xB5,0x52,0x21,0xCB,0x88,0xBB,0xA1,0x8D,0x41,0x94,0xAE,0xAB,0x01,0x63,0x94,0xE2,0x8B,0xE8, +0xAA,0x73,0x43,0x6A,0x1C,0xEE,0x56,0x6D,0x5A,0xAA,0xF5,0x95,0x2B,0x58,0x99,0x9D,0x2D,0xC3,0x69,0x54, +0x1B,0xFB,0xCF,0x31,0x06,0x8B,0xC6,0x0D,0x0A,0x50,0x4D,0x79,0xA6,0x94,0x8C,0x02,0x45,0xC9,0x30,0xBE, +0xB9,0x5A,0x74,0x5E,0x2F,0xB1,0xA3,0xE0,0x86,0xF4,0xCC,0xD7,0xD8,0x3A,0x0D,0xF2,0xD7,0x5C,0x1D,0x1B, +0xE9,0x62,0x2D,0x7E,0x25,0x49,0x1A,0xDB,0x95,0xA2,0x1D,0x92,0x45,0xDB,0x96,0x0E,0x2C,0xA1,0xC2,0x69, +0x72,0xCC,0xD6,0x75,0x35,0x6C,0xD9,0x94,0x52,0x5E,0x16,0xC8,0x20,0xBD,0xD8,0xCB,0xC1,0x84,0xDC,0xE2, +0x35,0x74,0x4F,0x0C,0xDE,0xDB,0x95,0x1D,0x2A,0x5A,0xD0,0xDB,0x80,0x85,0x56,0xF2,0x89,0x6A,0xDC,0xFC, +0xEB,0x48,0x92,0x8C,0x55,0x18,0x8A,0x2D,0x26,0x8D,0xD8,0xF6,0x32,0xA9,0x4A,0x0C,0xC2,0xE2,0x8D,0x89, +0xD2,0xBA,0x82,0x3D,0x27,0x9C,0x6F,0xBC,0xDF,0xF3,0x84,0x91,0x4B,0xCB,0xF8,0x51,0x3C,0x7A,0x7F,0x8A, +0x53,0x98,0x66,0x73,0x7B,0xBE,0xD2,0x8D,0xDF,0x55,0xC0,0xE8,0xDA,0xB4,0x55,0x6B,0x8D,0x45,0x50,0x7C, +0xBF,0xB3,0x9E,0xF0,0xF8,0x75,0x3E,0x0B,0xA0,0x24,0x1D,0x6D,0xBC,0x64,0xAB,0x88,0x1D,0x30,0xD3,0x8C, +0x7D,0x76,0xC3,0x52,0xC2,0xB8,0x71,0xF7,0x74,0x30,0x49,0x6F,0x09,0xB4,0x9B,0xF5,0x4E,0xBE,0x10,0x3B, +0xF9,0x18,0x47,0xCC,0xFE,0xF8,0x9F,0xA8,0x1A,0x11,0x58,0xEC,0xFF,0x40,0x5A,0x75,0x85,0x71,0x81,0x34, +0xAF,0x14,0xD0,0xD9,0x09,0x12,0xCA,0xB0,0xA6,0x99,0x40,0x6F,0xD9,0x53,0xDB,0xC2,0x0D,0xFB,0x47,0xE6, +0x55,0xFA,0x59,0xEC,0x3F,0xD1,0x94,0x15,0x0B,0xFD,0x4A,0xDD,0x3B,0xFB,0x4B,0xAD,0x31,0xFE,0x56,0xA1, +0x26,0xBB,0xC5,0xB8,0x21,0x00,0x3A,0x9E,0xF7,0x42,0x61,0x7E,0x8A,0x8D,0x58,0x29,0xF9,0xE1,0x6D,0x00, +0x3B,0x6F,0x6F,0xEB,0xE0,0x97,0xF6,0x12,0xE4,0x57,0xAA,0xD2,0x65,0x36,0x23,0x91,0xA6,0xDC,0x85,0x87, +0x0D,0x8F,0x21,0x8F,0x91,0xB2,0xB1,0x6B,0x27,0x52,0xD1,0x5A,0xAC,0x9D,0x72,0x13,0x8D,0x41,0x72,0x6E, +0x07,0x9C,0xE2,0x38,0x78,0xE2,0x4D,0xCE,0x00,0x00,0xFF,0x07,0x2C,0xFB,0xF8,0x94,0xE5,0x2B,0xC0,0xA2, +0xCE,0x4A,0x9A,0x9F,0xF1,0x62,0x9C,0xAB,0xF2,0x66,0x82,0xBB,0xB0,0x28,0x59,0x80,0x4B,0x23,0xA7,0x96, +0xD1,0x2D,0xFA,0xE4,0x75,0xBB,0xA1,0x05,0x94,0x2B,0xF1,0x13,0x4C,0x09,0x59,0x71,0x73,0xEC,0x32,0x9B, +0x28,0x46,0x83,0xAE,0x30,0x42,0xA1,0x79,0xA0,0x07,0x58,0x17,0x90,0xD8,0x86,0x8E,0x2A,0xA6,0xB9,0x87, +0xEB,0xD8,0xB2,0x62,0xEF,0xE5,0xB9,0x66,0x76,0x74,0xF5,0x6A,0xDF,0xD6,0x21,0xF3,0xF8,0x95,0x23,0x27, +0xEA,0xCC,0xA1,0xB2,0xE8,0x5F,0x85,0x4E,0x69,0xFC,0xED,0xEF,0x5F,0xA7,0x6B,0x21,0x6F,0x0B,0xD3,0xFA, +0x94,0x1C,0x9B,0x4A,0x2A,0x14,0x72,0x6F,0x48,0x14,0x30,0x36,0x6A,0xCE,0x93,0x31,0x20,0x1D,0xF8,0xB2, +0x1A,0xC1,0xFA,0x9C,0xE4,0x23,0xB6,0x8E,0x5A,0xC7,0xAA,0xEE,0x5F,0xBC,0x4B,0x2E,0xF4,0x4C,0xAA,0x1C, +0x1D,0x20,0x58,0x9D,0xAB,0xEC,0xBA,0x38,0x53,0x2F,0x3C,0x41,0x6F,0xD1,0xFB,0x9D,0x45,0x21,0xD7,0xEE, +0x6D,0xC5,0xEB,0xBD,0x21,0x61,0x71,0xDE,0x78,0x84,0x81,0xA3,0x38,0x4A,0xFB,0x8A,0x4F,0xE2,0x86,0xB3, +0x59,0x27,0x3C,0x73,0x83,0x75,0xBB,0x21,0xCB,0xAD,0x6C,0x92,0x10,0xEC,0xF7,0x5E,0x54,0x0D,0x31,0xA1, +0xA5,0x0E,0x71,0x14,0xFE,0x51,0xBF,0x52,0x81,0x8E,0x7F,0xF0,0xD2,0x4C,0x3D,0xA5,0xA3,0x22,0x51,0x7F, +0x0D,0x51,0x43,0x43,0x13,0x2F,0x72,0x56,0x53,0x2F,0xAF,0x73,0xB1,0xDE,0xE8,0xD5,0xF1,0x4E,0x28,0x53, +0x5C,0xA7,0xFA,0xF1,0x52,0xEE,0xF0,0xBF,0x81,0x55,0x9E,0xC5,0x34,0x0F,0x88,0x10,0x66,0x32,0xEC,0xF0, +0xF0,0x3C,0xB4,0xD8,0xD6,0x5A,0xF4,0x84,0x73,0x3A,0xE8,0xD7,0xE3,0xAB,0x63,0xA6,0x7D,0x17,0x7E,0x27, +0xB2,0xAB,0xB8,0x47,0x90,0x43,0x4C,0x81,0x1F,0x33,0xD1,0x61,0xC9,0x1B,0x4C,0xAE,0x04,0x56,0xF5,0x85, +0xB2,0x38,0x3D,0xB5,0x92,0xDA,0x19,0x25,0xFB,0x74,0x96,0x27,0xDF,0x48,0xE3,0x63,0x64,0x26,0x6E,0x9A, +0xB5,0xF4,0x8C,0xAE,0xE9,0xF1,0xB6,0x6B,0x8A,0x09,0x1E,0x74,0x2B,0xC4,0xE5,0xCA,0x1B,0xC6,0x0E,0xD3, +0xA7,0xD6,0x3A,0xB8,0x2C,0x05,0xB9,0xFF,0x03,0x65,0x6F,0x95,0x31,0x69,0xB7,0x27,0xB1,0x75,0xB7,0xBD, +0x40,0x7F,0x18,0x62,0x4C,0x58,0xA6,0x8B,0x91,0x87,0xE7,0xD3,0x2F,0x33,0x77,0xCE,0xE2,0x78,0xFE,0x1C, +0x85,0x33,0x2E,0x6A,0x6F,0x65,0xEE,0xF8,0xF8,0x34,0xEE,0x5C,0x6F,0xF4,0xCA,0x3E,0xB9,0x3E,0xD6,0xFB, +0xCA,0xD7,0xBE,0xB8,0x3D,0x70,0x3F,0x0B,0x26,0x10,0xA7,0x89,0x76,0xB5,0x97,0x00,0x1B,0x58,0xD1,0x69, +0xC1,0x13,0x8F,0xCD,0xC6,0x5D,0xC9,0xAF,0x18,0x39,0x20,0x1B,0x69,0x5C,0x20,0x5D,0x5A,0xBF,0x94,0x60, +0x34,0x8F,0x91,0x00,0x30,0xB7,0x23,0xD8,0xFD,0x14,0xCF,0x5C,0xC2,0x7F,0x88,0x83,0x81,0x8A,0xE5,0xB8, +0x15,0x10,0x99,0xD0,0xBC,0x44,0xD6,0xD4,0xC2,0x6C,0x0F,0xE1,0x37,0x2F,0xA1,0x44,0x2E,0xA2,0x49,0x11, +0xB4,0x5D,0x88,0xAC,0x67,0x12,0xA9,0x82,0x09,0x8E,0x92,0x18,0x36,0x27,0x2A,0xC9,0x70,0x17,0x96,0xD8, +0x34,0x7F,0x64,0xC5,0xFD,0x0F,0xD8,0x96,0xA9,0xAB,0x08,0xD3,0xCA,0x6B,0xF6,0xE2,0x6D,0xBA,0xEC,0xD5, +0xF8,0xC4,0x88,0x12,0x77,0x28,0x10,0x74,0xF4,0x48,0xA5,0xB8,0xD5,0xAD,0xE1,0xC4,0x71,0x0D,0xD9,0x97, +0x6D,0xA9,0xD5,0x47,0x45,0xA2,0x91,0x23,0xCE,0xA4,0x52,0xA5,0x97,0x3A,0x91,0x70,0x34,0xA1,0x9D,0x93, +0xC1,0x4C,0xFE,0xF3,0xEC,0xB9,0x73,0xE8,0x28,0xFF,0x0D,0x50,0xC5,0x37,0x4A,0x18,0x95,0xDD,0x4B,0x5C, +0xCD,0xD7,0x3F,0xE9,0x89,0x24,0xF3,0x96,0xE0,0x58,0x2D,0x60,0x7F,0x68,0x45,0x4C,0x8B,0x36,0x27,0x8B, +0x65,0xCE,0x9D,0xED,0x01,0x95,0x4B,0x24,0x6F,0x4F,0x23,0x68,0x3D,0x1C,0x8F,0xB7,0x66,0xEF,0x54,0x61, +0xB3,0x74,0x43,0xC0,0x74,0x3F,0x81,0xA4,0x26,0x66,0x98,0x42,0xFB,0x43,0xEA,0x69,0x5E,0xA3,0x76,0xED, +0x6D,0x7C,0x2D,0x1E,0x58,0x57,0x51,0xB8,0xA3,0x30,0x92,0xDC,0x16,0xE9,0x20,0x7B,0xC1,0x62,0xC2,0x81, +0x9E,0x8F,0x62,0x34,0x69,0xCF,0x83,0x0B,0xAB,0x23,0xC7,0x4C,0x40,0xD1,0x38,0xED,0xDB,0x0C,0x13,0x7C, +0x7A,0x80,0xD3,0x0F,0x9B,0xA0,0xDB,0x71,0x43,0x42,0x3F,0xAF,0xD3,0xEC,0xB5,0x71,0xA8,0xAD,0x5F,0xFD, +0x1A,0x0F,0x62,0x40,0x9F,0x5D,0xCC,0xCD,0xAE,0xB8,0x11,0x15,0x01,0x8E,0x78,0xDD,0x37,0x5F,0x44,0xBA, +0x0E,0x95,0xC4,0x92,0xC4,0xF8,0xC1,0x70,0x07,0xF7,0x9E,0x22,0x47,0x8E,0x66,0x59,0xC0,0x79,0xCD,0xCD, +0x26,0x5A,0xD8,0x92,0xAF,0x3E,0xAB,0x18,0x0C,0xE5,0x3D,0xCC,0x99,0x2C,0x3A,0xCD,0x78,0x91,0xE6,0xB7, +0x20,0x54,0xB4,0x6F,0x95,0xB2,0xC1,0x80,0x25,0x23,0x94,0xA2,0x6E,0xB6,0x88,0xF5,0xEE,0xF1,0xBC,0xDB, +0x94,0xB3,0x26,0xB2,0xC4,0xB0,0x38,0x56,0xD6,0x35,0xFB,0xB1,0x89,0x1B,0xB5,0x5E,0x15,0xB0,0x0D,0x61, +0xE3,0xDF,0xA8,0x80,0x0B,0x9A,0x43,0x31,0x6E,0xF3,0xBD,0xE2,0x14,0xB1,0x27,0xF6,0x44,0xD1,0x9D,0xB3, +0xAF,0xB5,0x86,0xA3,0xC7,0xDC,0xAE,0x9B,0xCD,0xCE,0x8D,0x0F,0x9B,0x64,0xCD,0xD5,0x72,0x47,0x8A,0xF0, +0x8E,0x34,0x29,0x54,0x9C,0x34,0x15,0xE9,0xE9,0xBA,0x7A,0x41,0xEE,0xD6,0x19,0x8C,0x9A,0x35,0xDC,0xE4, +0x2A,0x85,0xE3,0xF0,0x3D,0xB9,0x0C,0x2A,0x0B,0x07,0x57,0xBC,0x0E,0xDA,0x82,0x71,0x5C,0x27,0x11,0xBD, +0x73,0x66,0x2F,0xD5,0xDC,0x0B,0x4F,0x99,0xAA,0x80,0xEA,0xA0,0x9F,0x36,0xFE,0x26,0x8F,0xD3,0xAB,0x89, +0x5A,0xE7,0x40,0x38,0xE6,0xF9,0xD3,0x5A,0x04,0xB2,0x1E,0xBE,0xEF,0xD0,0x21,0xE3,0xDE,0x22,0x1F,0xEC, +0x67,0xFA,0x98,0x2D,0x3C,0x96,0x17,0xAF,0xA9,0xD1,0x97,0x7B,0x1B,0xBC,0x46,0x88,0x2B,0x83,0x8F,0x9B, +0xBB,0xB2,0x35,0x06,0x4C,0xBA,0x4B,0x9D,0x00,0xBE,0x59,0x1D,0xE5,0xDF,0xDE,0xE6,0x14,0x5D,0xB4,0x42, +0xB7,0x25,0x68,0xA6,0x95,0xF4,0x9C,0x92,0xC4,0x27,0x28,0x67,0xB2,0xA2,0x0E,0x52,0x21,0x47,0x18,0x55, +0x57,0x7A,0xAD,0x93,0x84,0x08,0xB3,0x35,0x44,0x8D,0x29,0xDE,0x29,0x13,0xA9,0x55,0xD8,0x6B,0x53,0x14, +0x22,0x05,0xA4,0xE6,0x1D,0xFE,0x67,0x37,0x20,0xC0,0xCF,0x53,0x26,0x73,0xFB,0x02,0xA3,0xF9,0x3F,0xC0, +0x69,0xAF,0x78,0x02,0xBF,0x48,0xC6,0x06,0x32,0x62,0xF0,0xAE,0x13,0x48,0x73,0xC7,0x23,0x2D,0xA3,0x78, +0xE6,0xBA,0xF5,0x87,0xDF,0x68,0x69,0x23,0xB1,0xA5,0x2D,0x3A,0x58,0x17,0x69,0x89,0xA6,0x0B,0xAF,0x63, +0x33,0xE5,0xB6,0x23,0x70,0xB8,0xCF,0x27,0x11,0xEB,0x63,0x8B,0x38,0x3C,0x22,0x52,0x72,0x98,0xA8,0x12, +0xAB,0x13,0xFA,0x2B,0xE5,0x27,0x3B,0xDB,0xC4,0x95,0x2A,0xD3,0x6B,0xA9,0x5E,0xFA,0xE8,0x0F,0x8B,0x7A, +0xE6,0x45,0x24,0x14,0x21,0x44,0xE5,0xFB,0x87,0xF4,0x94,0xEF,0x0A,0xC6,0xDA,0x28,0x3D,0xF5,0x6B,0x0E, +0x35,0x45,0x2B,0xD7,0xC8,0x27,0xA1,0x9E,0x2A,0x0D,0xD2,0x39,0x3C,0xDD,0x0D,0x5B,0xA9,0x4D,0x78,0x7D, +0xC9,0xB7,0x9F,0x58,0xBD,0x33,0xB2,0xAE,0xFB,0x2A,0x50,0x86,0xF1,0x53,0xEC,0x50,0x26,0xC3,0x63,0x22, +0x9A,0x31,0x60,0x63,0xB8,0x36,0x61,0x32,0xD2,0xF0,0xA4,0x45,0xA2,0xCE,0x3A,0xCD,0xCA,0x18,0x69,0xCB, +0x39,0x28,0x93,0x79,0x58,0x52,0x40,0x1E,0xA2,0xBD,0x74,0x12,0x1E,0xD2,0xDD,0xAD,0x64,0x60,0x76,0x37, +0x3E,0x13,0xC8,0x8E,0xAB,0xF2,0xAC,0xFE,0xAF,0x96,0x7B,0xF4,0x7C,0x39,0x34,0xBA,0x89,0x61,0x20,0xC6, +0x8F,0x1C,0xA0,0x15,0xC6,0x9C,0x94,0x91,0xCC,0x3A,0x0D,0x15,0x96,0xDA,0x7B,0x4B,0xF3,0xBD,0x25,0x41, +0x9F,0xDF,0x84,0xFA,0xD1,0x12,0x03,0xC3,0x1F,0xFF,0xF5,0xF3,0xFD,0x7F,0x73,0xBD,0x48,0x42,0x8C,0x17, +0x74,0x15,0x7D,0x8C,0x0A,0x17,0x15,0xD7,0x27,0xAC,0x7C,0x3F,0xAF,0x12,0x7C,0x3B,0xD3,0xC0,0xD4,0xD2, +0x02,0x80,0x79,0x0A,0x93,0x4B,0xB3,0x52,0xE6,0x56,0xDF,0x27,0x0F,0x9A,0x0E,0xBA,0x88,0x31,0xB4,0x96, +0x84,0x37,0xEF,0x64,0x03,0xE0,0x56,0xDB,0xCA,0x99,0x2B,0xE7,0x0B,0x59,0xAC,0x27,0x53,0x89,0x75,0x4F, +0x54,0x79,0x5C,0xA6,0x87,0x5B,0x65,0x0B,0x4F,0x5A,0xDB,0xD0,0x2F,0x34,0xAA,0x60,0x74,0xDE,0xDC,0x8D, +0x9B,0x3C,0x4C,0xE2,0x1E,0xF7,0x7A,0x44,0x14,0x35,0x18,0xFA,0x49,0xB7,0xEA,0x7E,0x0A,0xC9,0x26,0x43, +0x5A,0xA9,0xD6,0xDC,0xFB,0xB5,0x4F,0xF1,0x41,0x4B,0x81,0xFF,0x3A,0xF6,0xB3,0xCB,0x1B,0x3F,0x70,0x25, +0x5D,0xAC,0x71,0x9F,0x48,0x98,0x35,0xAD,0x7A,0x94,0xA5,0x56,0x82,0x54,0xA8,0xDF,0x0E,0x1E,0x1F,0x7C, +0x8F,0xEA,0x9F,0xD1,0xFC,0x36,0x29,0x00,0x5A,0x11,0x75,0x4D,0xA2,0x7F,0xD6,0x5A,0xEE,0xE9,0xF6,0xEC, +0xB9,0x92,0x9E,0x01,0x08,0x33,0x6D,0xC5,0x83,0xEC,0x06,0xAF,0x7C,0x14,0x0B,0xBE,0x8E,0x9F,0xAC,0xE1, +0x4F,0xA1,0xF4,0xD0,0x06,0xAF,0x77,0x27,0x07,0x12,0x6F,0xAF,0xD9,0x23,0xE0,0x6A,0xD3,0x82,0xEC,0xD0, +0x0E,0x73,0x8A,0x18,0x67,0xE0,0xFD,0x33,0xBB,0xB2,0x4E,0x24,0xA5,0x43,0x8B,0x78,0x89,0x5D,0x58,0xF0, +0xFA,0xC0,0xF1,0x2F,0xB0,0x7E,0xC3,0x15,0xE4,0x3E,0xA9,0x29,0x6D,0x4C,0x59,0x71,0x06,0x4E,0x19,0x99, +0x8E,0xCD,0x1C,0xD0,0x48,0xCF,0x1E,0x25,0xD4,0x36,0x70,0x0E,0x60,0x7C,0xA8,0x71,0x6A,0xCF,0x07,0x1F, +0xAD,0xCE,0xA8,0x70,0xDB,0x4C,0xC9,0x0D,0xFB,0xF8,0xB9,0xE2,0xB1,0xBF,0xDD,0x1D,0xDB,0xCA,0xA6,0x4B, +0xBD,0x95,0x50,0xAC,0x84,0x88,0x10,0xD2,0x7D,0x73,0x83,0xB0,0xE6,0x7A,0x4F,0xD2,0xA3,0xC6,0x09,0x21, +0x79,0x88,0xF1,0xA1,0xA5,0x37,0x49,0x9C,0x45,0xCB,0xF7,0x4B,0x56,0x43,0x16,0x91,0x26,0x18,0xB0,0x7F, +0x32,0x78,0x11,0x11,0x34,0xAB,0xCE,0xD7,0x27,0x16,0x30,0xF5,0xE7,0xB9,0xFB,0xBE,0xB9,0x5E,0x20,0xA8, +0xA7,0x8C,0xA3,0x5D,0x64,0x8A,0x3B,0x65,0x82,0x0F,0x12,0x80,0x07,0xC6,0x9E,0x44,0xEE,0xAC,0x10,0x9C, +0xFE,0xEF,0x19,0xBB,0x73,0x25,0xFE,0xBB,0x33,0xB8,0x09,0x9B,0x55,0x65,0xCD,0x06,0x3D,0xEC,0x23,0xDB, +0x89,0xAB,0xCB,0x48,0x56,0xA6,0x84,0xD9,0x85,0x9A,0x11,0x20,0x7C,0x34,0xCE,0xCE,0x46,0xB2,0xE3,0x28, +0xE1,0x21,0xB2,0x7B,0xD5,0xC6,0x49,0x2C,0xFF,0x11,0x4A,0xB7,0x8D,0x41,0x94,0xFE,0xF4,0x5C,0x20,0x7B, +0xEC,0xD6,0x40,0x4E,0x57,0x12,0x6B,0x4F,0x87,0xF9,0x44,0xEB,0x4A,0x8D,0xF1,0xE9,0x0B,0xC9,0xDB,0x0D, +0xED,0x1E,0x5C,0x39,0x78,0xEA,0xEA,0x39,0x68,0xBF,0xFC,0x0D,0xA4,0xC0,0xC1,0xDA,0x42,0x12,0x8A,0x71, +0xA8,0x9D,0x04,0xF4,0x56,0x5C,0xB4,0x90,0x04,0x04,0x8C,0x59,0xF9,0xF6,0xBD,0x61,0xA1,0x1C,0x40,0xE6, +0xB5,0x37,0x6E,0xF8,0x8E,0xB5,0x43,0x34,0xB0,0xB2,0xDA,0x73,0x6F,0x33,0xDB,0x80,0x15,0x4D,0x4B,0xA5, +0x0D,0xDD,0x1F,0x02,0x55,0x04,0x7F,0xC4,0x4E,0xF7,0x0D,0xD7,0xED,0x4E,0x06,0x51,0x49,0x6E,0x85,0x29, +0x02,0x7E,0x9B,0x85,0xA4,0x58,0x9A,0xC1,0x97,0x6B,0x12,0xCA,0x65,0xE5,0xCC,0x99,0xF7,0xF9,0x0C,0x84, +0x22,0x98,0x97,0x2D,0xDE,0xF6,0x04,0xF6,0x87,0x54,0xF8,0x09,0x96,0x96,0xE9,0xA1,0x78,0x69,0x51,0xA5, +0x49,0x3B,0x2C,0xFE,0x03,0x7D,0xAC,0xFA,0x13,0x77,0x8E,0x2D,0x46,0x08,0x7A,0x24,0x91,0x1A,0xDE,0x00, +0x63,0x7A,0x50,0x88,0x6A,0xA8,0x99,0x68,0xC5,0xC9,0xBC,0x8C,0xFE,0x7C,0x4E,0x5A,0xEE,0x29,0xCD,0x55, +0x43,0x58,0x3C,0x18,0xC6,0xDD,0x39,0x78,0xBD,0x19,0xED,0x49,0xE1,0xD4,0xBC,0x34,0x8C,0xF5,0x31,0xE9, +0xC4,0x97,0xEF,0x9B,0x5D,0xA1,0x49,0xAD,0x8F,0xE6,0x4E,0x44,0x4F,0xB8,0x15,0x2B,0x3C,0x34,0xF6,0xA2, +0xDE,0x9B,0xC4,0x9C,0x4C,0x24,0x87,0xC4,0x7C,0xF6,0x19,0x27,0x66,0xC3,0xB2,0x72,0xD5,0x9F,0x0E,0x5A, +0xF7,0x73,0xCC,0x05,0xCD,0xF2,0x0F,0xA0,0xAE,0x90,0xBE,0xA4,0x55,0x4C,0x46,0x01,0x5C,0x8C,0x05,0x7A, +0x37,0x9C,0x1A,0x21,0xA8,0x1E,0xD8,0x7E,0x9C,0x11,0xD3,0x89,0x1D,0xBB,0xCF,0x10,0x7D,0xF3,0x50,0x99, +0x0E,0x42,0x91,0xE2,0x56,0xEE,0xC7,0x05,0xFF,0x92,0x58,0xC3,0x2B,0x4E,0x27,0x38,0xD0,0x71,0xE9,0x76, +0xFB,0x71,0x7B,0x5F,0xCD,0xC6,0x82,0xC1,0xBB,0x24,0x70,0x37,0xFC,0x0E,0xB6,0x38,0x9C,0xD7,0x66,0x1C, +0x72,0xB1,0xE6,0x33,0xA4,0x6E,0x61,0x57,0x81,0xDF,0xD8,0x18,0x75,0xDD,0x10,0x61,0xF7,0xCF,0xAF,0xC7, +0xB2,0xE5,0x69,0x47,0xBB,0xAE,0x81,0x11,0x39,0xFF,0xA3,0xCE,0x28,0x12,0xC3,0xE6,0xB9,0x32,0x3E,0x47, +0xA3,0xFB,0x99,0x78,0xB7,0xD5,0x51,0x06,0xEE,0xB8,0x8F,0x94,0x8E,0x20,0x36,0x56,0xE2,0x86,0x64,0xD1, +0xE4,0xD8,0x01,0x6D,0xA6,0xBA,0xA7,0x99,0x1B,0x3A,0x1B,0xA1,0xEA,0x57,0x3E,0xCD,0x37,0xF5,0x29,0x46, +0x3F,0x49,0x72,0x62,0x33,0xF9,0x3B,0xA2,0x0F,0xFA,0x0D,0xAA,0x3F,0xFA,0x07,0x93,0xC7,0xC2,0xA4,0x9F, +0xD5,0xE7,0x56,0xEA,0xA4,0xA5,0xD8,0xDF,0x70,0x79,0xBE,0xB7,0x4B,0x61,0xEC,0x2A,0xB9,0xEB,0xB0,0xE9, +0xAA,0x49,0x24,0xEF,0x95,0x24,0x64,0x3E,0xA8,0xCA,0x61,0xCD,0xFA,0xA9,0xD3,0xEB,0xBB,0xFA,0xFD,0x0B, +0x79,0xA9,0x49,0xFA,0xA0,0x1B,0x3D,0xDE,0x54,0x67,0x39,0x29,0x5D,0xA4,0x70,0xEC,0x3A,0xEB,0xB5,0xCA, +0x45,0x46,0xA5,0x11,0x39,0xEA,0x3A,0x59,0x3E,0x08,0xBA,0x6B,0xE7,0x23,0x40,0x76,0xA1,0x08,0xB3,0x16, +0xDB,0x61,0x38,0xB1,0x28,0x4F,0x1C,0xAC,0xE4,0x62,0x24,0x7F,0xEA,0xF2,0xF2,0x1E,0xA6,0x61,0x2A,0xA4, +0x82,0x55,0x74,0x78,0xBE,0x35,0x6D,0x8B,0xA8,0x52,0xEC,0x2F,0x7B,0xB3,0x1B,0x59,0x57,0xEE,0x34,0x79, +0x47,0xDC,0xEF,0x1B,0x49,0x53,0xE3,0x43,0xD2,0x9A,0x5E,0x81,0x83,0x14,0x15,0xB6,0x50,0x1B,0x4A,0x42, +0x6C,0xFD,0xEA,0xA2,0x99,0x7F,0x58,0x72,0x12,0x40,0xDE,0x26,0xDA,0x55,0x62,0xB6,0x88,0x5E,0x27,0x56, +0x39,0x20,0x03,0xF3,0x22,0xDE,0xFB,0x83,0x59,0x3D,0x84,0x93,0x80,0x79,0xC7,0x17,0x1B,0x16,0xB5,0x6F, +0xB1,0x5E,0x36,0x77,0xD2,0x9D,0x4F,0x03,0x0A,0x37,0xA9,0xA5,0xCE,0x53,0xEE,0xDA,0x41,0x74,0xFC,0x3B, +0xDB,0x3C,0x2C,0x64,0x35,0xCB,0xAB,0x26,0xD3,0xEB,0x3C,0x32,0xCA,0xF4,0xB2,0xD2,0xD2,0xB6,0x5D,0x96, +0xE1,0x49,0x94,0xE1,0x9A,0x86,0x3D,0xB3,0x20,0xDA,0xD3,0xA7,0xD2,0x70,0x0C,0xD5,0x47,0xA9,0x79,0x61, +0xBA,0x48,0xE1,0x43,0xA3,0x1D,0xE4,0x26,0x3F,0x3A,0x04,0xAE,0x40,0x32,0x85,0xF0,0x8C,0x57,0xF9,0xFA, +0xDB,0xA7,0x90,0xA0,0xD3,0x7C,0xAD,0x4A,0x0B,0xF6,0x4F,0x1E,0x43,0x73,0x3B,0xA0,0x99,0x68,0x2A,0xFE, +0xCE,0x92,0x24,0x08,0xA4,0xF6,0xAC,0x47,0xF9,0x8A,0xB2,0xB5,0x1C,0xAB,0xBD,0x3D,0x75,0x95,0x01,0x85, +0x03,0x1E,0x28,0x5C,0x5B,0xBA,0xE3,0x1D,0xE1,0x25,0xF7,0x89,0x50,0x6A,0xBB,0xDB,0x1E,0xF0,0xC6,0xA0, +0x1C,0x84,0xC6,0xAB,0x64,0xB1,0xBD,0xEB,0x9B,0x83,0xE9,0x0A,0x59,0xFF,0x46,0xD2,0x73,0x89,0xCE,0xBB, +0x65,0x06,0xC2,0xC3,0x3E,0x90,0xEA,0xA7,0xC8,0x38,0x03,0xF8,0xCC,0x42,0xD1,0x5B,0xCA,0x16,0x07,0x34, +0xD9,0xEA,0xEF,0x16,0xFA,0x13,0x5F,0x9F,0x09,0xC1,0x99,0xAA,0xC7,0x50,0xC7,0xEC,0x1A,0xBE,0xE0,0x1B, +0xD8,0x7E,0xA6,0x79,0xBB,0x69,0x80,0x71,0xA7,0x03,0x9E,0x2A,0xF4,0x21,0xCB,0xD3,0xE7,0xA0,0xEA,0xD5, +0xD0,0x4D,0xD3,0x35,0xA4,0x7E,0xD0,0xA6,0xF7,0x0E,0x60,0xC1,0xC1,0x6C,0x1C,0x48,0xF6,0x6A,0x0C,0xF0, +0x08,0x8F,0xF9,0xF4,0x10,0x0F,0x0F,0x0F,0x24,0x43,0xC9,0x97,0x36,0x4D,0x13,0xE9,0x7E,0xF6,0x0D,0x69, +0x36,0x28,0x41,0x83,0x27,0x6C,0xD7,0x06,0xE1,0x4C,0x40,0x57,0x35,0x67,0xDA,0xB5,0x17,0xBF,0x2A,0x39, +0xE5,0xA1,0x78,0x14,0xA5,0x5B,0xFE,0xD0,0xC2,0xA3,0xD6,0x16,0x9A,0x53,0xF8,0x0D,0xA7,0x44,0x81,0xF2, +0x17,0xF3,0x3B,0xBC,0x21,0x29,0x66,0x31,0xD4,0x59,0x4E,0x81,0xAD,0xC9,0x2C,0x62,0x61,0xD9,0x33,0x56, +0x24,0x81,0xE1,0x53,0x3E,0x98,0xDA,0x80,0x43,0x6A,0xD0,0x0D,0x46,0xDB,0xB1,0x24,0x74,0xBD,0xCC,0x3F, +0x28,0x07,0x96,0x54,0xEF,0x43,0x12,0x5C,0x3E,0x04,0xEA,0x0B,0x96,0x83,0xD4,0x19,0xBC,0x76,0x9A,0x48, +0x2F,0x25,0xE4,0xDC,0x19,0x44,0x30,0x21,0xB0,0xE4,0x03,0x7D,0xFE,0x46,0x5D,0x1A,0xF8,0x65,0xCD,0x28, +0x7D,0x35,0x2A,0x99,0x48,0xA8,0xF5,0xFD,0xD9,0x06,0x45,0x3C,0x6C,0x14,0x2A,0x0D,0xBD,0x40,0xC8,0x50, +0xAD,0x97,0xDC,0x0E,0x76,0xA1,0x0A,0xDA,0xD7,0x63,0xCD,0x25,0xCB,0x31,0x3E,0xB8,0xEE,0x8B,0xD0,0xEE, +0x8E,0x02,0x42,0xF8,0xDE,0x06,0x92,0x1C,0xA0,0xE3,0xF4,0xAD,0x0C,0x42,0xF1,0xCD,0x75,0xEA,0xD7,0x09, +0x31,0xAB,0x5A,0x20,0x23,0x92,0xC1,0xDC,0x2C,0x89,0x4F,0x3D,0x68,0xCA,0xD4,0x99,0x63,0x32,0xC3,0x81, +0x5C,0xE2,0x6C,0x8A,0xA6,0x5C,0x96,0xB6,0x13,0x1F,0x4C,0xA7,0x8D,0x81,0x18,0x34,0x76,0xF8,0x0C,0x83, +0xC4,0x97,0xDE,0x65,0xB9,0x6C,0x9C,0xC1,0xC6,0x52,0xF4,0x1E,0x94,0x5E,0x75,0x73,0xAC,0x9D,0x05,0xF4, +0x17,0x31,0x07,0x93,0xC3,0x7D,0xE2,0xD8,0x36,0xFA,0x87,0x33,0x06,0x88,0xD5,0x67,0x7E,0x12,0x4F,0x40, +0x69,0x0E,0x2C,0x5F,0xA9,0x3E,0xDC,0x40,0x50,0x5B,0x84,0x35,0xB2,0x39,0xCC,0x1C,0x76,0x99,0x41,0xE0, +0xC2,0x90,0x14,0xF5,0xC6,0x9A,0xD4,0x28,0x9B,0xB8,0xEB,0x0D,0x75,0x98,0x3C,0xE7,0xEC,0xFF,0x81,0x41, +0x37,0x4F,0xB7,0x8C,0x5D,0xD2,0x8A,0x0B,0x86,0x9B,0xCF,0x0C,0x45,0x9A,0xAD,0x93,0xA7,0x8C,0x12,0xA4, +0xB6,0x16,0xAE,0xB4,0xE9,0x08,0xFC,0x84,0x89,0x70,0xA1,0xFC,0xD3,0xF4,0x37,0x7D,0xB8,0x35,0x4E,0xBB, +0x58,0xDC,0xC9,0xDD,0x48,0x94,0x1A,0x40,0xD0,0x1F,0x96,0x60,0x56,0xB6,0x4C,0x53,0x4E,0x24,0xD0,0x8F, +0x49,0x56,0x45,0x8F,0xAF,0xDA,0xF5,0xD8,0x57,0xDE,0x51,0x46,0xE4,0x81,0xD0,0x6F,0xAA,0x71,0x6F,0xDB, +0xA9,0xBE,0x2D,0xEC,0x89,0x3E,0x61,0x59,0xE1,0xFE,0x1F,0xCD,0x9F,0x17,0x77,0xAC,0xD1,0x8C,0xDE,0xFE, +0xB8,0x13,0xC9,0x6F,0x91,0xB9,0xF2,0xEB,0x01,0xDC,0xC1,0x38,0x83,0x60,0x90,0xD9,0x9E,0x22,0x06,0x12, +0x41,0x90,0x6A,0x03,0x7F,0xBC,0xDF,0x49,0x3F,0x95,0x47,0xBD,0xDC,0x82,0xCC,0x09,0x42,0x23,0x67,0xFE, +0xFF,0xD3,0x17,0xD3,0x0A,0x60,0x5B,0xBD,0x44,0xFD,0x84,0xF3,0x4A,0x20,0xFF,0xFF,0xFF,0xFF,0x3A,0xF3, +0x76,0xAF,0x38,0xC3,0xCE,0x28,0x73,0xE0,0x4C,0xEB,0xCE,0x98,0x58,0x22,0xBA,0x94,0x61,0xD2,0xD1,0xA5, +0xB4,0xFE,0xA0,0xCE,0x51,0x0C,0x1C,0xC5,0x27,0x41,0xD6,0x7E,0x86,0xC2,0x05,0xF4,0xE6,0x02,0xC2,0x20, +0xF3,0x83,0x8A,0xA5,0x2E,0x42,0xC9,0x8F,0xD6,0x01,0x88,0x73,0x6E,0xB8,0xE6,0x43,0x32,0xFC,0xA3,0xC6, +0xAB,0x78,0xEC,0xDB,0xE3,0x92,0x88,0x41,0x79,0xF7,0xD4,0x91,0x34,0x64,0xF9,0x97,0xDE,0x69,0x76,0xE9, +0x62,0x25,0x37,0xD0,0x0A,0xFC,0xD8,0x6C,0xC1,0x89,0x34,0x9C,0x6B,0x28,0x09,0x45,0x0B,0xD1,0xC5,0xAD, +0xFA,0x6B,0x08,0xC0,0x67,0xC1,0xAA,0x42,0x73,0xD9,0x51,0x55,0x0A,0xD0,0x65,0xA5,0x9B,0xD1,0x8C,0x13, +0x3C,0x05,0xBE,0xFD,0x76,0xF1,0xD4,0x6D,0x02,0x20,0x82,0xF5,0x5C,0x6A,0xCF,0x38,0xFF,0x77,0xC2,0x4A, +0xA7,0xC5,0x4E,0x79,0x74,0x6B,0x32,0x21,0xE6,0x3B,0xA1,0x7A,0xE8,0xB4,0xDC,0xCC,0x3B,0xC8,0x1D,0x88, +0x83,0xB3,0x07,0x8B,0xAB,0x5B,0x6A,0xAD,0x88,0x5C,0xC4,0x6A,0x06,0x60,0x95,0xFC,0x87,0x89,0x33,0xA1, +0x6E,0x80,0x33,0x5B,0xFA,0xE8,0xCC,0xCE,0x5D,0xE6,0x3C,0xF4,0x83,0xDB,0x4A,0xF0,0x93,0xFB,0xDC,0x53, +0xB4,0x6C,0xDA,0xF0,0x31,0x63,0x5A,0x2A,0x0F,0x21,0xDA,0x3A,0x1F,0x01,0x3A,0x2E,0x29,0x40,0x79,0x8F, +0xDF,0xC0,0x23,0x03,0xD9,0x03,0xA3,0x07,0x85,0x23,0xD7,0x98,0xBC,0x6E,0x53,0x12,0x3A,0xEF,0x39,0xDD, +0xCA,0xE3,0xB9,0xB5,0xB9,0x62,0x7B,0x15,0x49,0x53,0xA3,0xCD,0x42,0xC0,0x5D,0xA1,0x85,0xCF,0x4F,0x06, +0xA1,0xAA,0x94,0x92,0x00,0x84,0x3E,0x57,0xFC,0x7D,0x1D,0xF6,0xD2,0x01,0xA0,0x26,0x37,0x50,0x4E,0xFA, +0x8A,0x35,0x6B,0xB5,0x39,0xDA,0x04,0xE7,0x5F,0x09,0xBD,0xA5,0x19,0x72,0x6B,0xA7,0x09,0x5D,0x6A,0x21, +0xE5,0xDC,0xB5,0x6A,0xA7,0xA8,0xA3,0x8A,0xC7,0x1F,0x25,0x4F,0x4D,0x5E,0x4E,0xB4,0x71,0x43,0x1D,0x61, +0x87,0x92,0x7C,0x24,0x3E,0x9F,0xD0,0x11,0x14,0x74,0x54,0xE7,0x21,0xFF,0x9F,0xD1,0x10,0x16,0x99,0xB6, +0xC4,0x50,0xDA,0xF8,0xC6,0x5E,0x7C,0x86,0x11,0x99,0xC5,0x81,0xAE,0xBD,0x16,0xC4,0x30,0xFA,0x0C,0x41, +0x47,0x5D,0xBB,0xD4,0x88,0xD9,0xF5,0xA1,0xAB,0x1E,0xF5,0x2A,0x3C,0x2C,0xD9,0x00,0x95,0x77,0xA3,0xF2, +0x52,0xFE,0x5C,0xF7,0x1B,0x58,0x75,0x0E,0xA9,0xA2,0xE9,0x2A,0xAD,0x6B,0x90,0x15,0x91,0xCB,0xCA,0x52, +0x92,0xA6,0xA2,0x2E,0x3F,0x6A,0x61,0xFF,0x94,0xEF,0x6C,0x38,0x5F,0xF7,0xAC,0xCE,0xA6,0xC6,0xBF,0xAD, +0x1D,0x7A,0x2F,0x53,0x44,0x57,0x3B,0x3F,0xB0,0x72,0x24,0xE7,0x78,0x86,0x27,0x82,0xCF,0x17,0xA4,0x23, +0xEA,0x3B,0x38,0x04,0x10,0xC8,0xC2,0x39,0x5C,0x3C,0xD3,0xAA,0xE4,0x2E,0x0F,0xF5,0x8F,0xF7,0x50,0x8C, +0x7E,0x58,0xB5,0xFF,0x8A,0xE2,0x90,0x60,0x33,0x26,0xFD,0x0B,0xEF,0xF0,0xE0,0x45,0x9B,0xFC,0x27,0x9F, +0x90,0x13,0x7F,0x53,0xBB,0x5E,0x2F,0xED,0x0A,0xDF,0x9E,0x1C,0x59,0x3E,0xA3,0x31,0x93,0x52,0xDF,0xBB, +0x44,0x7D,0x27,0x49,0x7A,0xF0,0x7C,0x0E,0x7F,0xD2,0xFA,0x86,0x46,0x6B,0xD8,0x02,0xA9,0x25,0x88,0xDC, +0x54,0x8D,0xE2,0x70,0xBF,0x84,0x99,0x3C,0x47,0x75,0x96,0xF4,0x77,0x9D,0x02,0xD9,0xF6,0xCF,0xD6,0x89, +0x5D,0xA1,0xE3,0x38,0xB3,0x20,0xB3,0x19,0x7F,0xE6,0xCC,0x6D,0x31,0x9E,0x89,0xD8,0xD2,0xBA,0x9C,0x82, +0xC8,0xD4,0xD7,0x10,0x34,0x3C,0x01,0xCC,0x46,0xCE,0x99,0xAE,0xE6,0xC0,0xC7,0xFE,0x8F,0x53,0x1F,0xF4, +0x12,0x64,0xBD,0x00,0x66,0x49,0x54,0x04,0xA1,0x81,0x78,0x35,0x03,0xA9,0xF0,0x4F,0xEA,0xCB,0x28,0x14, +0xB8,0x42,0x6D,0x10,0x89,0xF7,0x01,0x09,0x99,0x8B,0xE0,0x21,0xF7,0xE6,0xF1,0x20,0x24,0xDD,0xC9,0x98, +0x5B,0xFD,0x1B,0xBB,0xA5,0xCA,0x8B,0x53,0x94,0x47,0xF9,0x67,0xD7,0x8A,0x41,0xE9,0xD6,0x87,0xE0,0x32, +0xB2,0x88,0x16,0x6C,0x91,0x5E,0xC9,0xED,0x4A,0x68,0x0A,0xD1,0xB5,0x5B,0x03,0xC2,0xAC,0x88,0xF4,0xA2, +0x15,0xAF,0xE9,0x3B,0x7E,0x39,0xE0,0x93,0x35,0x5A,0x23,0x9F,0x7A,0x8C,0x98,0x91,0x9F,0xCA,0x5E,0x6B, +0xC0,0x61,0x1F,0xB0,0xDF,0xF8,0x13,0x1F,0x04,0x0C,0x01,0xAF,0x3C,0x82,0x81,0xD4,0xA6,0xC4,0xC5,0x39, +0x3C,0x68,0x9D,0xF8,0x0A,0x4C,0xBB,0xEF,0xBB,0x2A,0x68,0x6E,0x6F,0x7C,0xAC,0xD2,0x56,0x61,0x72,0x43, +0xF2,0xE3,0x39,0x5F,0x2C,0xAE,0x32,0x6F,0x7C,0xEE,0x40,0xEE,0xA0,0x40,0x62,0x2D,0xEF,0xCE,0x63,0x0F, +0x92,0x05,0xCC,0xAC,0x0C,0x8E,0x8D,0xD6,0xED,0x1E,0x09,0x5F,0x8C,0x6F,0x53,0xBF,0xD3,0xBF,0xC3,0xE9, +0xCB,0xC7,0xAC,0x38,0x01,0xE7,0x0C,0xE0,0xDD,0x9C,0x57,0x04,0xA5,0x2A,0x6A,0x1E,0x6C,0xCB,0x18,0x34, +0x7C,0xFA,0xD7,0x9A,0x80,0x6E,0x80,0x24,0x06,0x92,0x38,0x72,0x21,0xC1,0x6F,0xC6,0x7D,0xFA,0x1D,0x6B, +0x94,0xDF,0x9D,0xA7,0x19,0xF2,0x65,0xC5,0x6B,0x54,0x35,0xE4,0x02,0x5F,0x74,0xB6,0x00,0x0C,0x15,0x68, +0xA7,0xFE,0x85,0x21,0xE1,0xDB,0x3D,0xF4,0x03,0x58,0x83,0x4A,0x83,0x42,0xE9,0xBA,0xCB,0xFC,0xD0,0x80, +0x91,0xB1,0x8C,0x56,0xEF,0x5B,0xD6,0x23,0x84,0xD5,0xC5,0x1B,0x96,0xD0,0x29,0x90,0x94,0xB0,0xC4,0x09, +0x9E,0x46,0x2D,0x4E,0x95,0x66,0x36,0x84,0x40,0xB0,0x4D,0x1C,0x64,0x1A,0x51,0x85,0x01,0x93,0x5F,0xE3, +0x73,0x38,0xFD,0xA4,0xB3,0x9B,0x45,0x08,0x6A,0x2A,0xEB,0x95,0x97,0xF1,0x27,0xEC,0xD7,0xDA,0x31,0x71, +0xDD,0xDB,0xB2,0x5B,0x1A,0xF8,0x65,0xAF,0x95,0x31,0x51,0x58,0x8C,0x06,0x2A,0xE0,0x5C,0xBD,0xBE,0xA6, +0x5E,0xD8,0x84,0x1B,0x8E,0xC2,0x78,0x7B,0x2F,0x97,0x5C,0xC8,0x41,0x3C,0x6E,0x0A,0x49,0x5D,0x73,0x9F, +0xF4,0x45,0x83,0xE4,0x77,0x46,0xCD,0x9D,0xBE,0xDB,0x87,0x44,0xDE,0x7A,0xE9,0xD8,0x70,0x99,0xC6,0xB9, +0x8D,0x1F,0x94,0x26,0x62,0x71,0x11,0x94,0xBC,0xD4,0x88,0xE8,0x9F,0x7F,0x15,0xFD,0x8E,0xF3,0xDC,0xEE, +0xEB,0x12,0x05,0xF2,0xCA,0x62,0x85,0xD9,0xDE,0x91,0x4E,0x38,0x22,0x93,0x18,0x3E,0x1D,0xFE,0x70,0x03, +0xDE,0x93,0xDA,0x1C,0x72,0xF3,0x88,0xA1,0x79,0x97,0x4F,0xAC,0x1C,0x3C,0xC0,0x60,0x1A,0x49,0x18,0x00, +0x0E,0x29,0xFB,0x84,0x77,0x93,0xBA,0xB4,0x81,0x8F,0x6B,0x07,0xE1,0xFF,0x90,0xDD,0x18,0x22,0xB3,0xB5, +0xF2,0x9C,0xB0,0xEB,0x93,0xED,0x7B,0xF0,0x45,0x6D,0xB3,0x6F,0xAC,0xDD,0xBE,0x30,0x21,0xBD,0x25,0x67, +0x67,0x47,0xFD,0x5E,0x1A,0x9F,0x15,0xA3,0x01,0xBF,0x21,0x73,0x78,0x0F,0xDF,0x77,0xF9,0x2E,0xEA,0x72, +0x23,0x45,0xC4,0x01,0x7C,0x0F,0x78,0x3F,0x83,0x09,0xBE,0x68,0x14,0xC5,0xC4,0x1E,0xC3,0x49,0xE8,0x97, +0x6A,0x01,0x49,0x36,0xBC,0x59,0xF6,0x7D,0x15,0xC4,0x0E,0x16,0xB4,0x55,0xA7,0x4B,0x67,0xB0,0x18,0xF0, +0x27,0xD9,0x00,0x36,0xA6,0x29,0xEE,0x23,0x63,0x5D,0xE9,0x96,0xE6,0xEB,0xF2,0x1F,0x62,0x38,0x8C,0x2A, +0x30,0x87,0xE1,0x9E,0x56,0x9A,0xCC,0xF1,0xC4,0xE3,0x3A,0xF9,0xAB,0x48,0x90,0x8E,0xF3,0x6C,0x3B,0xE5, +0xE9,0x49,0x56,0xD2,0x40,0x05,0xA9,0xEB,0x8D,0xA4,0x2E,0x7E,0xEA,0x4C,0x44,0x81,0x41,0x52,0xF9,0x7C, +0x55,0xC2,0x3D,0xB0,0x68,0x8B,0xB9,0xBD,0x09,0x85,0x2B,0x2D,0x41,0xCD,0x57,0x6A,0x02,0xB7,0x73,0xA9, +0x18,0xA4,0xB3,0xE6,0x9F,0x90,0x9C,0x4F,0x8B,0xB4,0x48,0x3C,0xEA,0x48,0x3B,0x8A,0xAB,0xF3,0x54,0x3F, +0x76,0x40,0xFB,0x1A,0xF1,0x53,0x71,0x45,0x86,0x3D,0x8A,0x49,0x90,0x05,0x93,0x74,0xBE,0xD2,0x62,0x86, +0xC6,0x0F,0xC8,0x7C,0xA4,0xE0,0x2B,0x2B,0x7D,0x62,0xA1,0xCD,0x9B,0xD9,0x3B,0x0B,0x35,0x40,0x6C,0x97, +0x33,0x5F,0xCF,0xA8,0xFD,0x2F,0xCA,0x3B,0x19,0xA9,0x5D,0xB2,0xCA,0x2F,0x88,0x83,0xDD,0x8E,0x6C,0xE2, +0xDB,0x1E,0x84,0x44,0x34,0x1C,0x1C,0xA5,0x0B,0x83,0x04,0x54,0xBB,0xD1,0xEB,0xEE,0x40,0x15,0xA5,0x4C, +0x90,0x30,0xF4,0x58,0x0B,0x1C,0xCE,0xE3,0x9A,0x15,0x3D,0x7B,0x2D,0xAF,0x76,0xC6,0x52,0x34,0x11,0xB0, +0x9A,0x56,0xC2,0x56,0x74,0xFF,0x74,0xEB,0xC0,0x17,0x37,0x91,0x38,0xB4,0xE6,0xB9,0x44,0xAC,0xA5,0x4A, +0x7E,0xFA,0xA3,0x00,0x0E,0x9F,0x57,0xB7,0x5E,0x76,0xC4,0x11,0x52,0x24,0xFB,0x9B,0xC5,0xE9,0xEC,0xA2, +0x41,0xF9,0x83,0x50,0x5F,0x83,0xCA,0x78,0x9E,0x5A,0x0D,0x0A,0x75,0x94,0x2B,0xF0,0xD8,0xB9,0x53,0xA6, +0xB4,0xD7,0x35,0xAB,0x97,0x14,0xC7,0xE5,0x0D,0xFB,0x33,0xD6,0x02,0xE8,0xDF,0xE5,0xB5,0xD6,0x3D,0xBB, +0x9E,0x15,0xBA,0xC5,0xD7,0x35,0x67,0xC8,0x60,0xB3,0xD8,0x35,0x30,0x23,0x4D,0xA8,0x13,0xF8,0xB6,0x3E, +0xF0,0x70,0x08,0x21,0x00,0xDE,0xB0,0x25,0xB4,0xCF,0xA5,0xE2,0xB0,0xA4,0xFC,0xAB,0x7A,0x19,0xD4,0x88, +0x28,0x9A,0x00,0xFB,0xFA,0xC5,0xD7,0xAC,0x6E,0xC6,0x16,0xD2,0x99,0x7E,0x56,0x39,0x0C,0x92,0xC7,0x11, +0xDA,0x95,0x30,0x50,0x8D,0x36,0xC1,0x01,0xF1,0xDB,0xAA,0xB8,0xAA,0x9A,0x92,0xB2,0x99,0x59,0xC0,0x60, +0x97,0x53,0x40,0x4D,0x8F,0x73,0xF1,0xA8,0xAB,0x9B,0x0E,0xE9,0x86,0x7F,0xC8,0xD8,0xCA,0x3F,0x48,0x9F, +0x5C,0x66,0x61,0x09,0xBA,0x72,0x78,0x2F,0x53,0xDF,0x6D,0x1A,0x86,0xF3,0x63,0x92,0x59,0xDE,0xEF,0x19, +0xA7,0xB4,0x59,0x04,0xBD,0xDE,0x9F,0xCC,0xA8,0xD2,0x09,0x0D,0x04,0x30,0x84,0x60,0xF3,0xE5,0xFA,0x5C, +0xE1,0x3C,0x0E,0x9B,0xC9,0x36,0x08,0xE1,0x96,0xE0,0x3E,0x70,0x65,0x87,0x3A,0x71,0x98,0xC3,0x2E,0x8B, +0xAE,0x85,0x94,0x84,0xD7,0xFD,0x19,0xFC,0x6D,0x31,0x8E,0x78,0x4D,0x99,0x79,0x06,0xA7,0x6C,0xF9,0x23, +0x5D,0x35,0x57,0x15,0x64,0x00,0x52,0x1E,0x38,0xC1,0x03,0x83,0x08,0x6C,0xF2,0x55,0xF5,0x4E,0x39,0xE2, +0xA3,0xEA,0xF0,0x19,0xB5,0xC1,0x2E,0xDE,0x4E,0xDF,0xE5,0x18,0xF5,0x81,0x44,0xEC,0x8E,0x02,0x50,0xA9, +0x07,0xE8,0x78,0x32,0x49,0xC1,0x9F,0x46,0x73,0xA7,0x03,0x43,0x85,0xC6,0x5E,0xA5,0xA5,0xF7,0x21,0x05, +0x49,0x40,0x4E,0x85,0xD0,0x07,0x09,0x19,0xD4,0x8A,0x5D,0x08,0x34,0xC2,0xFF,0xF1,0x56,0xBD,0x6F,0xD6, +0x76,0x38,0x0B,0xF9,0x80,0x85,0x5D,0xC9,0xE5,0x5E,0x96,0x48,0xB3,0xA4,0x32,0x6D,0xBE,0x43,0xCD,0xE5, +0xFC,0x5F,0xF4,0xA2,0x15,0xB2,0x32,0x32,0xC2,0x34,0x00,0xAE,0xA2,0x44,0x58,0x2C,0x2D,0xE6,0x98,0x91, +0x9D,0xCA,0x29,0x29,0x0E,0xEE,0xE4,0x2E,0xEF,0x1A,0xD0,0x9F,0xFA,0x18,0xFF,0x79,0x12,0x2D,0x21,0x39, +0x0F,0xAF,0xEC,0x78,0x03,0xE1,0x72,0x3D,0x0A,0x88,0x5D,0xAC,0xFF,0x03,0x4A,0x4A,0xAB,0x6C,0x46,0x0C, +0x8F,0x31,0x33,0x47,0xEA,0x0F,0xD2,0xCE,0xE0,0x00,0x7C,0xFE,0x46,0x48,0x3A,0xB2,0x9F,0x71,0xBC,0xBA, +0xF4,0xAE,0x75,0xCD,0x53,0xC0,0x2D,0xD7,0xC6,0xCA,0xD8,0x90,0xA5,0xCE,0x94,0x28,0xF5,0xE3,0x7D,0x18, +0x41,0xA5,0xDC,0xC7,0x33,0x1C,0x40,0x25,0x06,0x12,0xA4,0xE2,0x28,0x3B,0xB2,0x3F,0xDF,0xF4,0x98,0x27, +0x93,0xE0,0xE3,0xA4,0xFB,0xEB,0x96,0x63,0x86,0xD1,0x08,0xF4,0xB8,0x38,0x87,0x28,0x64,0xB1,0x04,0x49, +0x94,0x6E,0xF6,0x82,0x97,0x62,0x9F,0x37,0x79,0x1D,0x89,0x26,0x69,0x64,0x27,0xC1,0x03,0xE2,0x1F,0xA3, +0x71,0x3C,0x8D,0x05,0x7D,0xB9,0x63,0x0F,0xED,0xC8,0xC2,0x5A,0xF1,0xAC,0xB7,0xC3,0x6E,0x27,0x83,0xF6, +0x52,0xF6,0x0B,0x66,0x28,0x7B,0xCE,0x15,0x5F,0xB6,0xD4,0x2C,0x37,0xD8,0x58,0xA9,0x94,0x15,0x22,0xDB, +0x67,0x7A,0xFE,0x0B,0x09,0xF1,0x45,0x05,0x95,0x57,0x73,0x66,0x43,0xB9,0x4B,0x82,0xC7,0x84,0x2A,0x44, +0xD4,0xD7,0x92,0xA1,0x54,0x28,0x7B,0xD5,0x72,0x3A,0xEC,0xF1,0xE9,0x7A,0x7D,0x0A,0x40,0xB5,0x86,0xF9, +0x8F,0x1B,0x22,0x7F,0x4A,0x98,0x66,0xCC,0x0D,0x98,0xCB,0x44,0x7A,0x78,0xD5,0xBD,0x8C,0x66,0xF7,0x2F, +0x98,0x66,0x6C,0xD8,0x05,0xD4,0x47,0x55,0xCE,0xBB,0x0E,0x78,0x20,0x97,0xA1,0x36,0x3C,0xC4,0x6F,0xFA, +0x6E,0x16,0xD6,0xDD,0xC3,0x5A,0x4F,0xCD,0x97,0x96,0xAE,0xF9,0x42,0x20,0x2D,0x39,0x06,0x9F,0xB9,0x9A, +0x08,0xF7,0xBB,0xCE,0x99,0xA3,0x98,0xFB,0xBC,0x50,0xE0,0x6E,0x02,0x56,0xA9,0x32,0x7A,0x07,0x54,0x37, +0x67,0xC2,0x78,0x99,0xE1,0xB7,0x00,0x89,0x46,0xD4,0x5D,0xD7,0xA3,0xAC,0x1E,0x4F,0xEE,0x88,0x0B,0xAD, +0x41,0x13,0x28,0xEA,0xE8,0x3C,0xF7,0x6B,0xE9,0x7A,0x12,0x31,0xA9,0x3F,0x24,0x5B,0xD3,0x8E,0x79,0x89, +0x04,0xEE,0x6F,0xFF,0xFF,0xFF,0xA8,0x98,0x85,0x41,0xCA,0x19,0x31,0x50,0xD0,0xDD,0x51,0x9B,0x98,0x21, +0x3B,0x30,0x14,0x56,0x21,0x4D,0xD5,0x7D,0xBE,0x8C,0x9C,0x42,0xBA,0x03,0xFE,0x2D,0x50,0xC1,0xA9,0x24, +0x61,0xAD,0xB9,0x81,0xFC,0x35,0x38,0xDC,0xFD,0x39,0x14,0x56,0x80,0x0E,0x1D,0x93,0x10,0x5A,0xF1,0x9C, +0x3E,0xF8,0xC6,0x79,0xB6,0x9F,0xBF,0x2D,0xA5,0x67,0xBB,0xC2,0x82,0x5C,0x81,0x22,0x31,0x14,0x52,0xE4, +0x21,0x6C,0x0B,0xA3,0x61,0xD4,0x38,0xD4,0x68,0x16,0x30,0x5C,0x70,0x4E,0x88,0x12,0xA8,0xF4,0x58,0x77, +0x56,0x64,0x18,0x88,0x84,0xE7,0x98,0x48,0xF1,0x44,0x19,0xD4,0x40,0x42,0x69,0x15,0xD6,0x6D,0x73,0xA2, +0x9F,0x1C,0x31,0xD1,0xFF,0x77,0xED,0x13,0x3C,0x41,0xDC,0x71,0x5B,0x2F,0x7A,0xCE,0x40,0x13,0x28,0xF1, +0xB2,0xB3,0xCD,0xF5,0x77,0x28,0x16,0x3F,0x00,0xB9,0xF2,0xEB,0x28,0x12,0x1B,0x98,0x2E,0x0D,0x13,0xBA, +0xC9,0xB1,0xD8,0xCF,0x2D,0xCD,0xDC,0xEF,0xBB,0x90,0xA3,0xF4,0x53,0x51,0x29,0xD2,0xCE,0xB1,0xAD,0x11, +0xB0,0x3A,0x54,0xFF,0xBA,0xE8,0x50,0x43,0xE6,0x38,0x23,0xE9,0x95,0xE4,0x1A,0xDF,0x19,0x70,0x44,0xAE, +0x39,0x28,0x75,0x75,0x1C,0xCD,0x72,0x84,0xEB,0x57,0xC2,0x6C,0x5E,0x48,0x72,0xDD,0x05,0x6F,0xE2,0x3E, +0x1D,0xCC,0x03,0x81,0xAC,0x56,0xE2,0x2E,0x55,0x0F,0xBB,0xCB,0x0A,0x35,0x1A,0x0F,0x3B,0xD3,0x97,0x8F, +0x66,0x43,0x5B,0xEF,0x5A,0xF5,0x01,0xC4,0x09,0xE3,0x97,0xB2,0x9D,0xCE,0x9F,0x1F,0x3C,0xE2,0x91,0x78, +0xE8,0xCD,0x3C,0x60,0x34,0x16,0x30,0xE6,0x73,0xC0,0x3E,0x70,0x3C,0xD0,0xEA,0xCD,0x39,0x69,0x74,0xB7, +0x42,0xEE,0x56,0x96,0xD8,0xA1,0xE7,0xC0,0x69,0x58,0x81,0x26,0x80,0xDC,0x2C,0x4C,0xC3,0x72,0xFB,0xF0, +0x83,0x86,0x4C,0x5D,0x47,0x1F,0x8D,0xA8,0x7F,0xDF,0x75,0x79,0xF9,0x5E,0x9B,0x8C,0x5A,0xFA,0x1A,0xC2, +0x95,0xD2,0x84,0x27,0xB1,0x7B,0xD2,0x56,0xA7,0xE1,0xB4,0x40,0x5D,0x91,0x54,0x62,0xE2,0x8C,0xB6,0xF5, +0x71,0x14,0x34,0x96,0x97,0x13,0x4B,0xA6,0x1D,0x2E,0x64,0xE0,0xC7,0x65,0xFC,0x08,0xD2,0xFF,0x25,0x81, +0x1C,0x9B,0x05,0x31,0x67,0x73,0x6D,0xA6,0xEC,0x57,0x8F,0xF4,0x55,0x70,0x1D,0xD4,0x00,0x0C,0xEA,0x81, +0x4C,0x2C,0xBD,0xF1,0x9C,0xDE,0x5A,0xC4,0x52,0xD6,0x1C,0x8C,0x0B,0x58,0xDF,0x0D,0x9F,0x39,0x12,0x53, +0x89,0x3B,0x14,0x2E,0xF0,0x78,0xA6,0x88,0x5E,0x3D,0xB4,0x6F,0x61,0x22,0x16,0xA8,0x5A,0x82,0x00,0x56, +0x98,0x42,0x13,0xF6,0x2D,0xCA,0x84,0x85,0x53,0xAA,0xFB,0x2D,0x84,0xF3,0xAF,0xCD,0x4F,0xD7,0xD0,0xCD, +0xDA,0x1F,0xA8,0x6B,0x3B,0x3F,0xA0,0x5F,0x6B,0x5F,0x80,0x5A,0x48,0xDA,0x41,0xAE,0x4B,0x5C,0x83,0xAA, +0xCD,0xB0,0x8D,0xE8,0x6C,0xC7,0xEE,0x04,0x2C,0x33,0x11,0xBA,0x05,0x5B,0x41,0x8C,0x19,0x42,0x44,0xFC, +0x4A,0xA7,0xBE,0xAF,0xCD,0x72,0x5F,0x21,0x28,0x1A,0x13,0x68,0xF9,0x32,0xAC,0x01,0xB2,0x13,0xB7,0xEF, +0x7A,0x73,0x4A,0x5B,0x2B,0xB6,0xF8,0xA8,0x47,0x6F,0x3F,0xFB,0xDA,0x52,0xE7,0xBA,0x39,0x2F,0x7A,0xFD, +0xA3,0xCC,0xFB,0x04,0x6F,0x47,0xA3,0xC2,0x0C,0x6B,0xEA,0xD0,0x52,0xFA,0x10,0xEC,0x87,0x85,0x8C,0x94, +0x95,0xE8,0x06,0x0E,0xCA,0x47,0xA2,0x32,0x74,0x91,0xA4,0x81,0x04,0x47,0x7C,0x9B,0x92,0xF9,0xA2,0x22, +0x44,0x92,0xDC,0xCF,0x8C,0xAF,0x1F,0x71,0x7E,0x3E,0x91,0xC7,0xCB,0x0C,0xBB,0x73,0xC9,0x68,0x83,0xDF, +0xD5,0xAC,0x0C,0xA0,0xA7,0x8F,0xA4,0x84,0xB7,0x5B,0x67,0x25,0x90,0xCC,0x08,0x04,0x15,0x17,0x08,0x50, +0xA5,0x88,0xEE,0x73,0x24,0xE7,0xFB,0x9A,0x3C,0x08,0xA6,0x94,0x5B,0x60,0xE5,0xB3,0xDA,0x89,0x89,0x25, +0x61,0xE4,0xB1,0x1C,0x10,0xCE,0xA8,0xFA,0x71,0xAB,0x7B,0x42,0xB4,0x65,0x56,0xB1,0x15,0xA3,0x82,0x00, +0xBF,0xA9,0xA7,0x95,0x9F,0x63,0xDD,0x88,0x9D,0xF2,0xA1,0x6C,0x32,0xEE,0xA1,0x3E,0xA5,0x19,0xEB,0xA6, +0xFB,0x17,0x52,0x98,0x9C,0xF3,0x6D,0xED,0x45,0xA4,0x42,0xD2,0x52,0x86,0x20,0x2D,0x30,0xE6,0x98,0xE9, +0x20,0x77,0x24,0x28,0x3D,0x20,0x31,0xD4,0x0D,0x40,0x73,0xD7,0x98,0x47,0x13,0xFB,0x89,0xEE,0x1B,0x6C, +0x1B,0x3B,0x5B,0x39,0x90,0xC6,0x89,0x2C,0x7E,0xF2,0x9A,0x2C,0x3D,0xAC,0xFC,0x2C,0xE9,0xC9,0x91,0xAA, +0x0E,0x31,0x92,0x3D,0xF5,0xE3,0x58,0xA5,0xFB,0x82,0xB3,0xCE,0xB8,0xEF,0x5A,0x0B,0xEE,0x62,0xD0,0xAE, +0x03,0xF6,0x9B,0xBA,0x2D,0x7D,0xDB,0x08,0x48,0x5F,0x90,0x2B,0x8A,0xC8,0x93,0x6D,0xA9,0xE3,0xAB,0xA3, +0x73,0xCD,0x72,0x7F,0x99,0x95,0x6C,0x5D,0x9B,0x89,0xBB,0x99,0x7A,0x83,0x7B,0xCA,0x1B,0x10,0x3F,0xE4, +0xCB,0xD2,0xF8,0xC0,0x57,0x44,0x8C,0x2F,0xDB,0x5D,0x08,0x6F,0x74,0xEA,0x2D,0xB6,0x69,0x41,0x04,0xD2, +0x61,0xDC,0x23,0x51,0xC4,0x50,0xE5,0x6F,0x2C,0x49,0x61,0x57,0xEA,0x1D,0xCF,0x21,0x64,0xF5,0x2F,0x4D, +0x15,0xC9,0x77,0xE1,0x5E,0xD1,0x8B,0x8E,0xA1,0x1E,0xC7,0x5B,0x35,0x1E,0x85,0x3E,0x5A,0xF5,0x5C,0x31, +0x5E,0x97,0x24,0x3B,0x13,0x39,0x8F,0x60,0xE6,0x3D,0xBC,0xE3,0x15,0x0B,0xFB,0xB0,0xC4,0x6A,0x22,0xF9, +0x5A,0x0A,0xE9,0x89,0x8C,0x44,0x3C,0xC3,0x3B,0xB7,0x60,0x16,0x24,0x92,0xF5,0xDF,0xFA,0x19,0x4D,0x18, +0x13,0x79,0x8D,0x65,0x76,0xAD,0x0D,0xD1,0xD3,0x9A,0xCD,0xC3,0x5C,0x5D,0x1D,0xF1,0xD2,0xDA,0x6B,0x1F, +0x76,0xFA,0xF9,0xC2,0x2A,0x7B,0xA5,0x49,0xF6,0x08,0x6F,0x29,0x8B,0xC3,0x96,0xE7,0xDD,0x27,0xF5,0xD0, +0x52,0x23,0x2F,0x9C,0x29,0x14,0x64,0xFA,0xCA,0xDF,0x74,0x3A,0x11,0xFE,0x53,0x0F,0xD3,0x9A,0xAF,0x92, +0x74,0x2A,0x2E,0xD9,0x4B,0xCA,0xD7,0xAD,0xED,0xE1,0xF2,0x83,0xD6,0x64,0x2E,0x58,0x7F,0xCB,0x1F,0x25, +0x4C,0x57,0xDF,0xBD,0xE0,0xF6,0xF9,0x2A,0x7A,0x91,0x53,0xBB,0xC6,0xEC,0x8D,0x68,0xEE,0xE5,0x49,0xAC, +0xDF,0xBE,0xED,0xCF,0x8E,0x62,0x75,0x5C,0x1D,0xDD,0xFB,0x1C,0x96,0xCD,0x68,0x7F,0xFC,0xF0,0xA3,0x4D, +0xFA,0x9D,0x50,0xC3,0xB8,0x45,0x4F,0x10,0x1B,0xC5,0x61,0x0E,0x41,0xBC,0xC3,0x5E,0xA1,0xD9,0xB5,0xDE, +0x1C,0xFD,0x87,0x9D,0xCC,0x9F,0x00,0x3D,0x5E,0x20,0xC0,0x11,0x2C,0x1B,0x3F,0xE2,0x23,0x01,0xA4,0x53, +0x34,0x4F,0x91,0x42,0xAF,0x0C,0x28,0xFD,0x07,0xE0,0x77,0xD3,0xDB,0x90,0x41,0x15,0xA8,0xD0,0x67,0xBC, +0xF4,0xB7,0xC5,0x7E,0x27,0x04,0x39,0xFB,0x80,0x6F,0xA5,0x52,0xBC,0x4D,0xC8,0x01,0x75,0x94,0x8F,0x95, +0xED,0x18,0x32,0x86,0xE1,0x2B,0xE1,0x39,0x28,0xF2,0x62,0x4A,0xE2,0x23,0xBF,0x2E,0xD4,0xDB,0xC8,0x58, +0x9D,0x89,0x7B,0x27,0xAB,0xA5,0xB2,0x66,0x51,0x04,0xF3,0xC2,0x03,0x0D,0xE8,0x14,0x5B,0x8E,0xF4,0x0A, +0x81,0x05,0xE6,0x5D,0x32,0x61,0xAD,0x3E,0x40,0x56,0x50,0x35,0x12,0xA0,0x33,0x65,0xC1,0x56,0x8F,0x48, +0x9E,0x0A,0xC6,0xA1,0x8B,0x08,0x5C,0x54,0x13,0xCC,0x11,0x75,0x43,0x57,0xBB,0x77,0xD2,0x87,0x2A,0x6A, +0xF5,0x04,0x02,0x0E,0x58,0xFD,0xEA,0xC0,0x60,0xE5,0x39,0x6B,0x56,0xB4,0xF7,0x9C,0x65,0x2B,0x9E,0x62, +0xBE,0x39,0x0D,0xDE,0x7A,0xF8,0x76,0x4F,0x69,0x9F,0x3B,0x8D,0xE4,0x21,0x90,0x32,0xE0,0x31,0x00,0xCF, +0xD8,0xE7,0x57,0xE7,0x63,0x95,0x63,0x7B,0x76,0x05,0x34,0xFB,0xAA,0x9A,0x25,0x05,0x6E,0x5B,0xA5,0x08, +0x0F,0x63,0x7F,0x78,0x02,0xD3,0xFC,0x65,0x39,0xFC,0x0B,0x75,0xAF,0x20,0x8B,0x51,0x39,0x4C,0xFE,0x06, +0xA8,0x16,0xEA,0xCE,0x9B,0x25,0x60,0x86,0xB4,0x0C,0x83,0x41,0xFC,0x76,0x79,0xEC,0x26,0x01,0x2F,0x3E, +0xAE,0xA7,0x31,0x6B,0xCB,0xCE,0x2B,0x6F,0x9A,0xE3,0xDF,0x3F,0x74,0x1F,0xCD,0xAC,0xA7,0x6F,0x3B,0x2F, +0x73,0x42,0x5C,0x0B,0x24,0xEE,0xC1,0x66,0xC1,0x0B,0x7B,0x43,0xFA,0xC1,0x1D,0x50,0x9F,0x56,0xAB,0x3B, +0x81,0xA6,0xA4,0x89,0x27,0xCA,0x0C,0x96,0x71,0xE4,0x64,0x4C,0xF8,0xAA,0xFC,0xE2,0xA1,0x7C,0xDE,0x77, +0x4B,0x22,0x3E,0x16,0xC4,0x3A,0x38,0xBF,0x43,0x37,0x9D,0xA1,0x79,0xCA,0x71,0x57,0x5D,0x52,0x1E,0xAA, +0xCD,0x28,0x7D,0x5E,0x1A,0x11,0x87,0xB4,0xD0,0xC8,0xF0,0xBF,0x81,0x12,0xC1,0xB7,0x06,0x3F,0x41,0x1F, +0xE0,0x98,0xEC,0xD4,0xF0,0xDB,0xF8,0xBF,0x80,0x11,0xEC,0x6D,0xBE,0x98,0x64,0x0F,0xEE,0xF3,0xA2,0xF3, +0x9A,0xA4,0xEF,0x65,0x17,0x19,0xC3,0x34,0x8E,0xB6,0xE0,0x83,0x15,0x33,0x75,0x97,0x90,0x4A,0xCA,0x53, +0x66,0x83,0xD8,0xA5,0x33,0xB1,0xCA,0x8F,0x29,0x86,0xA5,0xD2,0x1A,0x86,0x3C,0x7B,0x14,0xCC,0x52,0xF2, +0x9F,0x28,0xC9,0xE0,0x0B,0xA7,0xCF,0xB1,0x9D,0x47,0x9D,0x83,0x55,0x1F,0x36,0x66,0x29,0x74,0xAA,0x5A, +0x1E,0xB5,0xC7,0x99,0xDC,0xA6,0x14,0x96,0xD0,0x8E,0x38,0x6B,0x8B,0x2B,0x77,0xE7,0x3C,0x55,0xF5,0xA8, +0xF9,0xD1,0xA5,0x1E,0x08,0x92,0xF0,0xA2,0xC1,0xEE,0xC0,0x6A,0xD6,0x5F,0x9E,0xDB,0x06,0x60,0x7E,0x7A, +0x26,0x0C,0xE6,0x0C,0x6E,0x50,0x1E,0xF9,0x01,0x0D,0xAE,0x6E,0xBF,0x49,0xFA,0x28,0xD4,0x12,0xAC,0xDE, +0x38,0x9D,0x40,0xC5,0x48,0x3D,0xE0,0xC5,0xD8,0x18,0x7D,0x2B,0x06,0x11,0xF9,0xE1,0xDB,0x3A,0x53,0xEB, +0xE0,0xA3,0xE9,0xD5,0x59,0x1B,0x2F,0x8F,0x13,0x12,0x91,0xF0,0xF3,0x3B,0xE4,0x88,0x9F,0x54,0xE1,0xC1, +0x58,0x1A,0x18,0xFC,0x02,0x20,0x18,0xF8,0x04,0xED,0x0E,0x1F,0xE3,0xDB,0x30,0x65,0x0D,0xFB,0xD2,0x96, +0x32,0x21,0x13,0x85,0x61,0xAB,0x39,0x41,0x39,0x8E,0x00,0xC9,0xD8,0xFA,0xB5,0xEB,0xFF,0x7F,0x5E,0x40, +0x5E,0x53,0xE5,0x50,0xB0,0x8D,0xA6,0x41,0x23,0xF2,0xE9,0x2A,0x32,0xC1,0x29,0x15,0xD5,0x76,0x59,0x65, +0x4B,0x48,0xEB,0x51,0x0B,0x1C,0xD8,0x65,0xDB,0x8B,0xC0,0x37,0x9B,0x09,0x8B,0x45,0xE7,0x3B,0x9E,0x95, +0xD2,0x69,0x7C,0x34,0xF8,0x95,0xC8,0x96,0x4F,0x08,0x1E,0x4A,0x44,0x65,0xC6,0x5B,0xF4,0x18,0xD5,0x3C, +0x25,0x9D,0xF4,0x37,0x16,0x20,0xDD,0xF0,0xBE,0x1B,0xA3,0x30,0x3D,0x82,0xD1,0xD1,0x42,0xCF,0x78,0x27, +0x17,0x21,0x27,0x5A,0xCF,0xC3,0xEF,0x15,0xB7,0xE1,0xFD,0x8C,0x0A,0xF2,0x31,0x31,0x60,0xB3,0x36,0xC8, +0xAD,0xD3,0xF3,0x48,0x8A,0x37,0xD5,0x98,0xC4,0x74,0x15,0xF8,0x2E,0xCA,0xE5,0xB8,0x72,0x36,0x16,0xBB, +0x88,0x8B,0xEF,0xE3,0x82,0xC7,0xB4,0x71,0x3B,0xBA,0xB4,0xDD,0xBB,0xD6,0x0C,0xC7,0xD8,0x36,0x13,0x5C, +0x53,0x90,0x13,0xE1,0x8D,0xE6,0x64,0xC4,0xCB,0x30,0xD2,0xD4,0x22,0x85,0xCD,0xA8,0xA2,0x71,0xC2,0x0E, +0x56,0x07,0x36,0x15,0x27,0x7D,0x8C,0x68,0xBF,0x6F,0x95,0x52,0xAA,0x8B,0x46,0x2D,0x27,0x24,0x69,0x9A, +0x0F,0x62,0xE9,0x9C,0xF3,0x40,0x1B,0xA3,0xF6,0xC3,0x76,0x4A,0x1E,0x56,0x2B,0x6E,0x3B,0x67,0xDA,0x9C, +0x52,0x43,0xC1,0x60,0x52,0x80,0xCB,0xCD,0x1F,0xA5,0x6E,0x79,0xC3,0x64,0xEC,0x9D,0x22,0x4E,0x20,0x62, +0x20,0xB4,0xB7,0x02,0x4F,0x3B,0x4B,0x26,0x1B,0xC8,0x24,0xC0,0xAA,0x0F,0x3F,0x74,0x35,0x3C,0xF5,0xBA, +0x90,0x2E,0x84,0x4C,0x75,0x9C,0x50,0xC9,0xB7,0xA1,0x9F,0x6B,0x94,0x3F,0x06,0xB2,0x68,0xA3,0x19,0x29, +0xD7,0xB3,0xF4,0xC1,0x22,0x2D,0x3A,0x75,0xB5,0x3E,0xAC,0xF1,0x4E,0x46,0xC2,0xF4,0x2F,0x62,0x06,0x25, +0xF5,0xFB,0x1F,0xE5,0x87,0x2B,0x76,0xB5,0x0E,0xBF,0x76,0x11,0x52,0xD0,0xCA,0xDB,0xD5,0x34,0xAC,0x2B, +0x44,0x41,0xF6,0xD4,0xF5,0xB1,0x90,0x81,0x5F,0x5C,0x6C,0x1E,0xEB,0x35,0xD2,0xFA,0x52,0x07,0x66,0x80, +0x5F,0xE7,0xF1,0x12,0xD2,0x29,0x2E,0xE7,0x89,0xD6,0xFB,0xCC,0x97,0x91,0xA5,0xC6,0xDC,0xC6,0x5D,0x61, +0x67,0xDF,0x3D,0x0B,0x71,0xEC,0xB5,0x6C,0x3C,0x35,0x31,0xB0,0x48,0xFA,0x8D,0x39,0x1C,0xD2,0x2B,0x46, +0x04,0xB5,0x1B,0xE9,0x5D,0x96,0x81,0xC4,0xC8,0x25,0x2D,0x85,0x15,0xC2,0xE7,0x1B,0xD8,0xA6,0xB0,0x6D, +0x2E,0x56,0xF8,0x7F,0x65,0x47,0xB7,0xA9,0xAC,0x0F,0x4C,0xA7,0x59,0x05,0x9B,0xE8,0xD5,0x94,0xF6,0xBA, +0x18,0x64,0xAB,0xC5,0x4A,0xCB,0xBE,0xD9,0x42,0x0D,0xCC,0xE5,0x8F,0x03,0x64,0xCC,0x7C,0xD2,0x77,0x99, +0x5A,0xD7,0x53,0x98,0xF1,0x7A,0xF9,0xE4,0x5B,0xDF,0x8C,0xDC,0x3E,0xCD,0xD8,0x3D,0x86,0xEC,0xB7,0xFE, +0x79,0x86,0xD3,0xA9,0x55,0x6B,0xD9,0xE6,0xDF,0xBA,0x75,0x18,0xD2,0xF3,0xF5,0xAF,0xEE,0xBC,0x30,0x2B, +0x7E,0x42,0xD1,0xF3,0xDE,0xBB,0x65,0xF9,0x2D,0xDB,0x3A,0x39,0xF9,0xBE,0xA5,0xB9,0x94,0xD3,0xE0,0x52, +0xDE,0x2D,0x42,0x76,0xAB,0x24,0xEF,0x56,0xAF,0x22,0x32,0xEB,0xF2,0xBC,0xC0,0x19,0x93,0xED,0x26,0x7D, +0xA3,0x11,0xA0,0xCB,0xA4,0x02,0x24,0xBC,0x58,0x0A,0x7E,0xC2,0x52,0x02,0xAE,0xC3,0x88,0x3A,0x4A,0x34, +0x2D,0xC3,0x1F,0x73,0x7E,0x9E,0xDD,0x77,0x66,0xDE,0xED,0x1E,0xC8,0x16,0x62,0xC5,0xD3,0x92,0x00,0x7D, +0xE9,0x40,0xBE,0x15,0xA7,0xF7,0x5B,0xF3,0x17,0xBB,0x10,0x98,0x1A,0x99,0xEC,0x32,0xF4,0x60,0x8A,0xAF, +0xEF,0xBD,0x26,0x29,0xAA,0x9D,0x0C,0x8A,0x30,0x67,0x1B,0x6E,0xF4,0xA9,0xBF,0x15,0x7B,0x5E,0x6F,0x39, +0xAA,0x9E,0xC7,0x07,0x2D,0xBB,0x71,0xAE,0x76,0x0B,0x09,0xA9,0xDB,0xDA,0x4B,0x70,0x38,0xCA,0x4E,0x86, +0x57,0xEC,0xD6,0xF6,0x6B,0x0A,0x19,0x6C,0x1C,0x2C,0x9A,0x03,0x45,0x4E,0xEC,0x2A,0x3B,0x1D,0xBF,0xA4, +0xE2,0x6D,0xB2,0xE3,0x96,0xAF,0xD6,0xBA,0x8C,0x5C,0x61,0x1B,0xF8,0x96,0x94,0xFA,0x0C,0x81,0x47,0x8F, +0x5D,0x3C,0x13,0x25,0xCE,0x2A,0x40,0xDE,0x54,0x67,0x31,0xFB,0x25,0x04,0x8F,0xDD,0xC1,0x2D,0x63,0xBB, +0x0C,0xED,0x20,0x7F,0x78,0x96,0x7A,0x37,0x8B,0x01,0xD4,0x2E,0xE5,0xF1,0x86,0x92,0xA3,0xD4,0x67,0xD0, +0xB1,0x08,0x7F,0xE5,0xC3,0x75,0x5D,0xAF,0x9F,0xA6,0x7A,0x92,0x28,0x49,0xE4,0x29,0xF8,0xCD,0xF6,0xF0, +0x3E,0xDD,0x17,0xB3,0xF9,0x2C,0xFF,0xF2,0x3B,0xC7,0xED,0x39,0x79,0x0B,0xEB,0xA8,0x07,0x0F,0x7E,0xE1, +0x70,0x4B,0x3A,0xB9,0xCF,0xB4,0x56,0x3C,0x27,0xCF,0xB1,0xC1,0x94,0x58,0xCC,0x82,0xF8,0xC8,0xEF,0xDF, +0x15,0x59,0xBC,0xC6,0x88,0x08,0xAC,0x61,0xAD,0x11,0x54,0x50,0xCC,0x52,0x24,0x4F,0x00,0x11,0x9A,0xCB, +0x19,0x7C,0x30,0xC4,0x68,0x6A,0x21,0xE7,0x4B,0x70,0x55,0x23,0x2D,0xFC,0xAF,0x5A,0xF6,0xA9,0xCD,0x94, +0xAE,0xB8,0xEB,0xF7,0x46,0xCE,0x05,0xA4,0x1C,0xDA,0x62,0xCB,0xDF,0xAC,0xFF,0x82,0x83,0x99,0xBA,0xC2, +0x51,0x41,0xF4,0x11,0xEE,0x54,0x2F,0xC3,0xD3,0x8B,0x97,0xC1,0xDE,0xB4,0x37,0xF3,0x92,0x94,0x84,0xA0, +0x9E,0x36,0xE4,0x0B,0x90,0x7C,0x3A,0xFE,0xBF,0x54,0x16,0x36,0x3E,0x3B,0x95,0xE4,0xED,0x14,0x45,0x67, +0x37,0xF5,0x75,0x2E,0x56,0x74,0xC0,0x2A,0x5A,0x2F,0x3B,0x93,0x08,0x4F,0xDC,0x71,0xEA,0xAE,0x0F,0x88, +0xC3,0x20,0xAE,0xEE,0xCD,0x34,0x94,0xC8,0x6C,0x5C,0xCC,0x2C,0x04,0xD7,0xA5,0xBE,0xC4,0x7B,0x4E,0x60, +0x71,0xC4,0x26,0x47,0xE6,0xDF,0xE0,0xBB,0xFA,0x74,0xB4,0xC1,0x9B,0x9A,0xBF,0xFF,0x43,0xC5,0xDB,0x2B, +0x2D,0x9C,0x37,0x5D,0x44,0xA9,0xA4,0x1C,0x3A,0x04,0x99,0xFF,0x46,0xE6,0x1B,0x79,0xC1,0x40,0xE7,0x9A, +0x7A,0x76,0xBD,0x38,0x28,0xED,0x15,0x32,0xB7,0x91,0xF1,0xA1,0x83,0xC4,0x69,0x9C,0x72,0x75,0x9D,0x2B, +0xA7,0x13,0xC4,0xAC,0xBB,0x22,0x1C,0x03,0x6D,0x86,0xE6,0x03,0x7D,0x45,0x39,0xCF,0xC9,0x6B,0x49,0x5E, +0xF3,0x93,0x15,0x16,0x03,0x26,0x52,0x6F,0x3F,0xDD,0x77,0x3B,0x07,0x11,0xF1,0x89,0xDA,0x3B,0x59,0x86, +0x83,0x52,0x44,0x42,0xF3,0x1F,0x27,0xB9,0x04,0xA0,0x0A,0xA6,0xB5,0x7F,0x08,0xDD,0xCB,0x46,0x98,0x44, +0xE8,0x53,0x13,0x62,0x45,0x8A,0x92,0xE8,0xEA,0xE0,0x92,0x28,0xE4,0x1E,0x78,0x33,0x63,0xA3,0x22,0x78, +0xA7,0xE2,0x1E,0x7B,0xB5,0x22,0x35,0xE3,0xD8,0xC4,0x00,0x9B,0x6C,0x11,0xC2,0x61,0x7E,0x18,0xF7,0x4A, +0x50,0x08,0x86,0x4F,0xE4,0x83,0x61,0x67,0x28,0x5C,0xA0,0x47,0x09,0x7B,0xD8,0xB8,0xBA,0xA9,0x74,0x11, +0x1F,0xA8,0xFB,0x27,0x3D,0x49,0xE7,0x55,0xA6,0x3A,0xD6,0x1E,0x61,0x0A,0x46,0x3E,0x05,0x6A,0x71,0xE6, +0xAC,0xA7,0x47,0x83,0x02,0x22,0xF7,0x0E,0x7D,0x4E,0x17,0x2F,0xC7,0x66,0xF9,0xF7,0x29,0x4B,0xA9,0xB7, +0x80,0x7A,0x63,0x24,0xC6,0x25,0x76,0x6C,0xDA,0x6A,0x22,0x66,0x2A,0x46,0x64,0x88,0xC9,0x0E,0xEA,0x80, +0x77,0xF0,0x12,0xDE,0xCE,0x04,0x66,0xBD,0xFD,0x77,0x51,0xE2,0x0D,0x32,0x79,0x35,0x63,0xEB,0x58,0x3B, +0x4E,0xFB,0xD2,0x5C,0x2F,0x36,0x19,0xE9,0x20,0x14,0x24,0x20,0xE6,0xFF,0x51,0x49,0x33,0xA4,0xDB,0x4D, +0xA4,0x15,0x6D,0x69,0x66,0xF3,0x2F,0xB3,0x62,0x0F,0x5B,0x6D,0x47,0xC6,0x04,0x7D,0x7C,0x36,0x1D,0xEF, +0xC4,0x81,0x1D,0x75,0x03,0xEE,0xFF,0xAD,0x84,0x74,0xCA,0x91,0xAB,0x8F,0x95,0x98,0xAE,0x1E,0xD2,0xA1, +0xEA,0xCE,0xCF,0xC3,0xFB,0x1E,0x84,0x78,0x3C,0x98,0x18,0x89,0x2F,0x3F,0x38,0x5E,0x63,0x0F,0x7B,0x6F, +0xE7,0x38,0x08,0x9F,0xDC,0x1F,0x90,0x24,0x0E,0x82,0x10,0xAF,0x9D,0x5E,0x4E,0xC6,0x07,0x57,0x28,0x8C, +0x53,0xE2,0x6E,0x9F,0xDB,0x3D,0x70,0x78,0x57,0xB2,0xA3,0xC4,0x93,0x2D,0xCC,0xB7,0x69,0xF4,0x4E,0x61, +0xA1,0x1C,0x19,0x2A,0xDE,0xD5,0xBB,0xC4,0x05,0x5F,0x82,0xFB,0xF8,0x57,0xA8,0xB2,0x05,0x13,0x32,0x74, +0x30,0x39,0xAE,0xC3,0xFE,0xC9,0xD1,0x56,0xE9,0xD2,0x7F,0xC5,0x4E,0xF7,0xC5,0xF5,0x16,0xD6,0x43,0xB5, +0x04,0x50,0xB5,0x77,0x9A,0x5E,0x5C,0x20,0x6E,0xEC,0x85,0x06,0x72,0x10,0x8B,0x9C,0x48,0x0B,0x2B,0xE7, +0x52,0xEF,0xDB,0x92,0x21,0x6E,0x62,0x11,0xCA,0x13,0xDC,0x02,0xDB,0x06,0x44,0x09,0xF8,0xEE,0x45,0xC5, +0x5E,0xCE,0xEF,0x93,0x7E,0x1E,0x2F,0x63,0x9A,0x79,0x61,0x81,0x01,0xE6,0xBC,0xAC,0xC7,0xD7,0x63,0xA4, +0xF2,0x3E,0x03,0xF4,0x46,0x88,0xE8,0x91,0x29,0xE5,0x99,0x68,0xC5,0xA0,0xCE,0xEC,0x9F,0x13,0x98,0x59, +0xE0,0xD5,0x3B,0x3E,0x83,0x75,0xA3,0xAB,0x8C,0x18,0x02,0x0D,0x28,0xB3,0xB8,0xC5,0x0C,0x19,0x01,0x8F, +0xDC,0x06,0x6D,0x96,0x53,0x37,0x2A,0x8E,0x55,0xC2,0xC8,0xDB,0xE8,0xD3,0xC8,0x2B,0x8B,0x5A,0x49,0x68, +0x29,0x16,0xB6,0xEC,0xA0,0x39,0x27,0xBF,0x6D,0xCA,0x04,0x1A,0x0A,0x70,0x18,0x96,0x45,0x04,0xC6,0x24, +0xCB,0x35,0xC2,0x88,0xD1,0x09,0x4E,0x70,0x7F,0xAF,0x08,0x9A,0x2E,0xDD,0x4D,0x8A,0xE3,0x55,0x7E,0x03, +0x63,0x9F,0x81,0x16,0x5B,0xB0,0x63,0xB8,0xFF,0xF2,0xC7,0x45,0xBF,0x3E,0x7E,0xD4,0xF7,0x45,0x4F,0x15, +0xEE,0xB3,0x73,0xFC,0x22,0x32,0xD8,0x92,0x43,0x27,0xFB,0xF9,0x52,0x2E,0x98,0x10,0xED,0xB2,0x63,0xEE, +0x3B,0xC1,0xDE,0xE6,0x14,0xA5,0x42,0x6B,0xAB,0x24,0x2B,0xBE,0x53,0x20,0x51,0x14,0xD4,0x6D,0xB6,0xF6, +0x73,0x3D,0xE7,0xD8,0x75,0x0C,0x22,0xC5,0xF2,0x21,0xBD,0xFF,0x98,0x6F,0x93,0x1B,0x7B,0x66,0x29,0xDF, +0x6C,0x4F,0xBD,0x6D,0xE3,0x92,0xCD,0x4F,0x8F,0x1D,0xF7,0x12,0x30,0xFC,0x62,0x39,0x64,0xFC,0xAB,0x05, +0x05,0xCC,0x78,0x71,0xA3,0x85,0x44,0xB9,0x1A,0x65,0x2E,0x66,0xA3,0xC7,0x6B,0x40,0xD0,0x78,0x1A,0x1B, +0xE8,0x61,0xB6,0x68,0xE7,0x54,0x23,0x57,0xE2,0x29,0x48,0x96,0xFF,0xEE,0x21,0xB2,0x06,0x8B,0x1E,0x45, +0xB6,0x2B,0x78,0x92,0x4E,0x4B,0x1C,0x07,0x91,0x22,0x71,0xAF,0x2F,0x0A,0x7E,0x6D,0x0E,0xDA,0xBC,0x8A, +0x32,0x11,0x5E,0x97,0x51,0x4F,0x7F,0x25,0xF7,0x55,0x36,0x6E,0xE7,0x2E,0xD2,0xD1,0x2B,0xD4,0x32,0x5F, +0xFB,0xEB,0xB2,0xF6,0x19,0x44,0x3E,0x7E,0xE2,0x45,0x35,0xD1,0x23,0x24,0xE1,0x1B,0xF8,0xD6,0xD0,0xF7, +0xBB,0x6B,0x29,0xA4,0x39,0xB5,0xA8,0x73,0x11,0xB7,0xBE,0xDE,0x54,0x67,0xF6,0x5E,0x70,0x7D,0x34,0x86, +0x6C,0xBD,0xE0,0x30,0x64,0x50,0x37,0x42,0x03,0xB6,0xBD,0x0F,0xB7,0xFA,0x6F,0x02,0xEF,0x70,0x29,0xAF, +0xB3,0xBA,0x69,0x0E,0x1B,0x2C,0x2A,0x0E,0x79,0x00,0xF2,0xA3,0xEF,0x3C,0x85,0x79,0x6F,0x4B,0x2C,0x8C, +0x53,0x62,0xFA,0xD7,0x8B,0xBF,0xF9,0xA6,0x29,0x6F,0x68,0xF7,0xCB,0x2E,0xAB,0x49,0x58,0x66,0x5D,0x3B, +0xEB,0x09,0xCD,0x75,0xF8,0x27,0xF1,0xC8,0x6A,0xEE,0x4B,0x8C,0x78,0xEF,0xBF,0xC2,0x81,0xED,0xDD,0xA8, +0x95,0xEF,0x6C,0x10,0xF1,0xFF,0xAC,0x5A,0xDC,0x7D,0xB4,0x6E,0x31,0x5C,0xB3,0x0B,0xC0,0xE7,0x24,0x4B, +0xEE,0x4A,0xA4,0x85,0xD0,0xF0,0x2D,0xE3,0x93,0xD3,0x84,0xE3,0x4F,0x5E,0xB1,0xC3,0x13,0x37,0x6A,0x27, +0x35,0xE1,0xF0,0xDF,0x54,0x4F,0xC5,0x0D,0x33,0xFF,0x08,0xD7,0x3B,0x41,0xFD,0x46,0x75,0xFE,0xA3,0xBA, +0xF4,0x1E,0x96,0x92,0xD9,0x50,0xAD,0xC7,0xC3,0x38,0xB4,0xE6,0x0B,0x79,0x2C,0x86,0x49,0x18,0xF6,0x64, +0x15,0xAA,0x89,0x8B,0x0B,0x58,0x8C,0x79,0x57,0x38,0xC1,0x3C,0xAA,0x57,0xFD,0xF5,0xB2,0x89,0xB2,0x8F, +0x34,0x5C,0xFF,0x35,0xAE,0x70,0x5B,0xB3,0xC3,0x11,0xF2,0xA5,0xBF,0x98,0x4F,0x73,0x08,0x13,0xA6,0xFD, +0x56,0xC8,0x3C,0x63,0x9B,0x16,0x53,0xEE,0x50,0x35,0xAE,0x32,0x69,0x38,0xC4,0xE7,0x93,0x1C,0xF5,0x5F, +0x2F,0xB9,0xB4,0x2C,0xA0,0x96,0x4E,0xDE,0x8B,0x19,0xE1,0x7B,0xA7,0xE4,0x3F,0x76,0x2B,0x17,0x95,0x0F, +0x53,0x7E,0xC8,0xA8,0xCC,0x41,0xAF,0x57,0x54,0x77,0x62,0xD9,0xA5,0xE0,0x2B,0xFF,0x0E,0x5E,0x9C,0xB1, +0x4C,0xA4,0x7C,0x7D,0xE7,0x7D,0x38,0xCE,0xCB,0x9F,0x66,0xD6,0xB6,0x7D,0x6C,0x58,0xF3,0xF3,0x69,0xDD, +0xDB,0xDD,0xB5,0xFF,0x8A,0xE2,0xB0,0xDA,0xDA,0xBE,0x66,0x03,0x58,0x0C,0x94,0x41,0x1B,0x5D,0x6E,0x3A, +0x26,0x13,0xD1,0xAF,0xDA,0x35,0xF3,0x8B,0x19,0x3B,0xEF,0xC9,0xF4,0x1C,0x16,0xF1,0x0E,0x40,0xE6,0x2E, +0x37,0x32,0xE7,0x07,0xFB,0x12,0xA0,0x8F,0xD5,0xE0,0x5F,0x78,0x92,0x1F,0xE8,0x03,0x6B,0x80,0xB0,0x7C, +0xC9,0xA2,0xD3,0xE6,0x50,0xCC,0xCB,0x52,0x09,0x7A,0xB2,0x12,0x36,0x3A,0xC7,0xF5,0xBC,0x37,0xE1,0x97, +0xF0,0x68,0xCD,0x78,0x5A,0x1F,0x31,0xEF,0xBE,0xEF,0x9A,0xA6,0x57,0xFD,0xB8,0xDA,0xDC,0xA3,0x2D,0x37, +0xB6,0x20,0xC9,0x41,0xE7,0xAE,0x02,0xAD,0xC4,0xA3,0x3D,0x57,0xD1,0xCF,0x1E,0x44,0xE7,0x07,0x73,0xB5, +0x92,0x29,0x48,0x52,0xC4,0x6B,0xCE,0x53,0xB6,0xA5,0x93,0x75,0xA6,0x7A,0x78,0xA7,0xB4,0x25,0x06,0x75, +0xE6,0x1A,0x07,0xF4,0xC6,0xDC,0x4C,0xB0,0x0A,0x8B,0xB3,0x44,0x7D,0xC2,0xD1,0x11,0xA4,0xDA,0x91,0x30, +0x5D,0xEB,0x09,0x05,0xFD,0x8A,0xD7,0x62,0x77,0x26,0xCD,0x11,0x38,0xC1,0xC1,0xB0,0x09,0xA6,0x9A,0xF4, +0x1C,0xC5,0xB4,0x6C,0x7C,0xAE,0xED,0x2B,0x68,0xD3,0xBB,0xAC,0x99,0x9B,0xF7,0x1F,0xBA,0xB6,0x87,0xED, +0x91,0xA4,0x42,0x3E,0xAD,0x48,0xDA,0xCD,0xD9,0x64,0xDC,0x79,0x7F,0x35,0xDD,0x09,0x7D,0x29,0xB4,0x5D, +0x3B,0x61,0x8B,0x1E,0x7D,0x6B,0x52,0x9F,0xCD,0x9D,0xD0,0x38,0x3C,0x14,0x98,0xC8,0x49,0x66,0xE9,0x74, +0x36,0x8F,0x74,0x28,0x6E,0x8A,0xF2,0xBD,0x9A,0x01,0xD8,0xC7,0xEF,0x73,0xCA,0x95,0xAB,0xA3,0x47,0xA9, +0x83,0x80,0x4E,0x7A,0x7C,0x8A,0x04,0x7C,0xAE,0x4E,0xD0,0xAE,0x03,0x46,0x1D,0x4D,0x6F,0x0D,0x9B,0xFF, +0x5C,0x01,0x65,0x09,0xAE,0xC8,0xCC,0x67,0x79,0xAF,0x10,0x7C,0x2E,0xE3,0x78,0xAC,0x1B,0x22,0x52,0x88, +0x43,0xC2,0x83,0x5F,0x3F,0xAE,0x20,0xA6,0xA6,0x5C,0x9C,0xC1,0xEA,0xED,0xD8,0x30,0x68,0xDA,0x1E,0x1F, +0xD5,0x51,0x28,0xD2,0x29,0x6A,0xA8,0xB2,0xB7,0x7D,0x38,0x72,0x69,0x2A,0x1C,0xC4,0x17,0xCD,0x92,0xE1, +0x2B,0x14,0x46,0x47,0xB8,0x49,0xB7,0xDC,0x69,0x54,0x8D,0x97,0x76,0x5D,0x29,0xB7,0x27,0x5F,0x78,0xF5, +0xDD,0xBE,0x39,0x97,0x86,0x5D,0xC3,0xB0,0x54,0xAC,0x65,0xA4,0x99,0xFA,0x1F,0xE1,0x97,0x4B,0x8B,0x66, +0x1D,0x5F,0x64,0xD7,0xD7,0x75,0x64,0x73,0x14,0x54,0xD7,0xA6,0xB7,0xAA,0xC3,0xA9,0x54,0x76,0xAE,0xBC, +0x53,0x54,0xDA,0x4C,0x53,0xC0,0x75,0x3D,0x43,0x00,0x5E,0x9D,0x37,0x6A,0x95,0x14,0x72,0x7B,0xD5,0x2D, +0xB7,0xDA,0xB7,0xD5,0x25,0xF6,0xC5,0x0D,0xF7,0x9A,0xC5,0xC7,0x75,0x58,0xC6,0xE8,0x4D,0xD8,0xB4,0x0C, +0xD7,0xFC,0xA5,0x59,0xE8,0x55,0x02,0xCC,0xC3,0x96,0x96,0xAB,0x8C,0x18,0x0A,0xFC,0xCA,0xDC,0x06,0xCA, +0x21,0xD0,0xB6,0xBB,0x02,0xD9,0x7F,0x32,0x9F,0x9B,0x9D,0x3F,0x25,0x15,0x65,0xFC,0x07,0xBE,0x88,0x20, +0x0D,0xAC,0x4F,0x68,0x29,0x16,0x97,0x60,0x32,0x0D,0x2E,0x53,0xB1,0x16,0x2F,0x3D,0x38,0x88,0x99,0x32, +0x2E,0x27,0x9E,0x26,0x22,0xF1,0x2F,0xEE,0xBB,0xB0,0x56,0x9C,0x1C,0xC0,0x0E,0x8C,0x45,0x90,0x59,0xE2, +0xCC,0x02,0x03,0x05,0xE0,0x60,0x01,0x8D,0x12,0x09,0xE3,0x4F,0xA2,0xD8,0x1C,0xC7,0x1B,0xFF,0xB3,0xB5, +0xE0,0xC0,0x67,0x07,0xF4,0xB3,0x79,0xB9,0xCF,0x99,0x14,0x5B,0xFF,0xA9,0x98,0x81,0x39,0xD7,0x87,0xCD, +0xDB,0xFF,0x3A,0xF3,0x7C,0xFF,0x38,0xFF,0x9F,0xD6,0x6F,0x5E,0xCF,0xF6,0x7C,0xB7,0x2C,0x68,0xA4,0x95, +0xEA,0x02,0xB3,0x64,0x91,0x37,0xA2,0x40,0x49,0x48,0x62,0x36,0x11,0xEC,0x58,0x82,0x65,0xDD,0x3A,0x75, +0x10,0x3D,0x19,0xA9,0xF3,0x26,0x13,0x5A,0x1A,0x93,0x50,0x12,0x24,0x0A,0x81,0x01,0x44,0xBE,0x1C,0xC5, +0xC5,0x51,0xC0,0x26,0x36,0x78,0x50,0xD0,0x06,0x2D,0x3A,0x60,0x21,0x22,0x70,0xA0,0xCD,0xB9,0xF2,0x55, +0xF3,0x0F,0xB7,0x97,0xC9,0xF4,0x73,0xD0,0x5F,0x4A,0x21,0x0C,0xD1,0x4D,0xC4,0x16,0xDB,0xE5,0x45,0xA9, +0x4A,0xCB,0x7B,0xA5,0x96,0x03,0x37,0xC1,0xA1,0x42,0xCD,0xF7,0xFB,0x71,0x41,0x45,0x7E,0xA1,0x6A,0xF8, +0x4F,0xB4,0xDE,0x99,0xA6,0x0A,0xFD,0x51,0x5B,0x9E,0x04,0xF9,0x74,0x28,0x29,0x53,0xE1,0xD4,0x2C,0x15, +0x2C,0x87,0xB4,0x5A,0x7B,0x28,0x44,0x7A,0xEB,0x29,0x90,0xDC,0x1F,0xF4,0xBE,0xCE,0x5B,0x86,0x80,0xB8, +0x00,0x97,0xDC,0x0D,0x0A,0x16,0xDA,0x92,0x9E,0x92,0x33,0xA0,0x29,0x51,0x7B,0xA1,0xFA,0x38,0x8C,0x6B, +0xBA,0x4F,0x73,0x15,0x64,0x64,0x3B,0xB8,0xFA,0x0F,0xC2,0xA7,0x7C,0xF4,0xD5,0xBE,0x8A,0x8C,0x02,0x28, +0x55,0x83,0xAD,0x60,0xEF,0x57,0xF6,0xF7,0xD2,0x9B,0xA6,0xDC,0x52,0x22,0x1B,0x2F,0x76,0x52,0xE5,0x9E, +0xCB,0x0E,0x40,0xEC,0xA0,0xC0,0x79,0xA1,0x42,0xC1,0x96,0x6A,0x3B,0x81,0x30,0x36,0x6D,0x5E,0x13,0x09, +0x44,0xC3,0x8B,0x00,0xBE,0x05,0x12,0x5D,0x6F,0x5C,0x02,0xE3,0x6E,0x90,0x8A,0x3A,0x01,0x65,0x5D,0x06, +0x85,0x00,0x8C,0x04,0xD1,0xFF,0x2A,0x9D,0x04,0x9F,0xC4,0x5F,0x91,0xF6,0xCE,0x94,0xA6,0xB3,0x44,0x85, +0x32,0xF1,0x26,0x46,0x52,0x15,0xFB,0xCE,0x10,0x75,0x55,0xF6,0xA2,0x11,0xD5,0x04,0xAC,0x70,0x2B,0xC1, +0xC1,0x12,0x95,0x5F,0x7D,0x8F,0xE5,0x05,0x92,0x55,0xD4,0xBF,0xD2,0xB3,0xA7,0x76,0x23,0x43,0xE4,0xCB, +0x90,0x77,0xAC,0x4C,0x02,0x46,0x7A,0xDA,0x46,0xC0,0x2D,0x9E,0x03,0x50,0x14,0x80,0xA6,0x36,0x54,0x30, +0x7E,0x0E,0x54,0x1A,0x48,0x25,0x3F,0x8A,0xC4,0x45,0xE2,0x81,0x13,0xAA,0xC5,0x80,0x79,0xBB,0x52,0x3C, +0xFA,0x74,0x34,0x21,0xFE,0x4D,0x4D,0xAE,0xF1,0xB4,0x02,0xB7,0x80,0x4F,0x0D,0xD0,0x5E,0xE3,0x62,0x17, +0xD0,0xF3,0x22,0x86,0x9D,0x1B,0x5C,0x89,0x8F,0x08,0x7E,0xA8,0x18,0x1A,0x1E,0xBD,0x89,0x97,0xF7,0x6C, +0x7A,0x14,0x4F,0x49,0x1A,0x03,0xCC,0x98,0x11,0x86,0x8E,0x98,0x2B,0x99,0xCE,0x5A,0x6B,0x34,0x5D,0xB1, +0x0F,0x1B,0x07,0xAC,0x43,0x39,0x4E,0x83,0xA8,0x15,0xCE,0x36,0x5D,0xDC,0xB7,0x67,0xC2,0x14,0x4F,0xC4, +0x4B,0x33,0x0F,0x30,0xE5,0x5A,0xFD,0xBD,0x5E,0x60,0x86,0x91,0xD8,0x14,0x96,0xD3,0x10,0x91,0x8C,0xE4, +0x59,0xF8,0x31,0xAC,0x7E,0x58,0x2D,0xBE,0xDC,0x0D,0x4E,0x82,0x9F,0xD0,0x6F,0x08,0x6F,0x12,0x88,0x51, +0x90,0xCE,0xC7,0xCB,0xC5,0x05,0x50,0xF3,0xCE,0x25,0xED,0x09,0xAE,0x45,0xE8,0x69,0xDF,0x30,0xF7,0x26, +0x26,0xA2,0x0B,0x83,0xB5,0x21,0xCF,0xBE,0xED,0xE7,0xFB,0x86,0xB3,0xFC,0xDA,0xEA,0xCC,0x4B,0xF0,0x87, +0x00,0xE2,0x8A,0xDC,0xCB,0x36,0xB1,0x40,0xAF,0x8C,0xBF,0x84,0x7A,0x47,0x68,0x4A,0x12,0xA5,0xC2,0x30, +0x05,0x4C,0xDB,0xC8,0xAD,0xE2,0xF1,0x0B,0x63,0x29,0x69,0x16,0x97,0x02,0x39,0x32,0x31,0x34,0x0E,0xBC, +0x2B,0x3F,0x79,0x87,0x89,0x80,0x6E,0xFF,0x01,0x68,0x60,0x35,0x22,0xD8,0xE2,0x37,0xD3,0x3B,0x66,0xC6, +0x5F,0xDE,0x57,0xFE,0xED,0x3F,0x71,0x04,0xB9,0xDF,0xB6,0x15,0x33,0x65,0xD2,0xAD,0x26,0x75,0x4F,0xFE, +0xE3,0xD6,0xC0,0x89,0xCA,0x33,0x54,0xED,0x56,0xA5,0x29,0xD2,0xB5,0x22,0xE1,0xC3,0x9A,0x4B,0xEB,0x05, +0x35,0xD6,0x0A,0x9C,0x3F,0xF5,0x85,0xC0,0xFB,0x8F,0x5E,0xEF,0x4E,0xDA,0x86,0x09,0x11,0x18,0xDD,0x0C, +0x3E,0x74,0xE6,0x16,0xE5,0x79,0x22,0x0C,0x42,0xEA,0x92,0x5C,0xC3,0x4E,0x75,0x6E,0x48,0xF3,0x92,0x81, +0xAA,0x9B,0x94,0x23,0x79,0x66,0x7B,0x48,0xAA,0xCA,0xFB,0x58,0x2F,0xED,0x5C,0x4C,0xBF,0xEC,0x28,0xCB, +0xAF,0xFE,0xB2,0x6B,0x8C,0x84,0xD4,0x49,0xA4,0xA5,0x93,0x89,0x8D,0xC4,0x11,0xD8,0x5F,0x8B,0x7A,0xB6, +0xFE,0x8F,0xAF,0x78,0x3C,0x4D,0xE0,0x35,0xC4,0x7D,0xCD,0xB6,0x1E,0xEE,0x4F,0x85,0xC3,0x41,0x65,0x9D, +0x28,0x31,0x33,0x49,0xE8,0x96,0xB5,0x4B,0x19,0xE4,0x7A,0x94,0xC2,0x30,0xC4,0x0B,0x3F,0x12,0x99,0x49, +0xCE,0x03,0x67,0x38,0x46,0x4D,0x96,0x84,0x2F,0x48,0xD3,0x4B,0x96,0x6D,0x4D,0x2D,0xAC,0xCF,0x02,0x46, +0x99,0xCF,0x9E,0x15,0xAE,0xCB,0x04,0x0D,0xBD,0x10,0x22,0xB0,0x44,0x30,0x24,0xA7,0x81,0xAB,0x70,0x42, +0x62,0x19,0x92,0x52,0x60,0xEB,0x57,0x55,0xFF,0x99,0xE6,0x2B,0xCA,0xCE,0xB5,0x5A,0x04,0x9C,0xB0,0x61, +0x73,0x49,0x5A,0x6B,0xF3,0xDF,0x80,0xF1,0xBA,0xD0,0x30,0xD0,0xC5,0xD9,0x93,0xD1,0xD7,0x50,0x2E,0x7B, +0x29,0x5E,0x41,0xEC,0x2B,0xF1,0xC6,0xBB,0x40,0x2C,0x52,0x5F,0x6D,0x3E,0x83,0x3D,0xD7,0x42,0x9D,0x35, +0x18,0x60,0x08,0x66,0x3F,0x8D,0xCA,0x93,0x16,0xD4,0x11,0x29,0x21,0x4D,0xD2,0x66,0xBA,0x33,0xB5,0x32, +0x61,0xCE,0xDB,0x85,0x45,0xFC,0x9E,0x2B,0x2C,0x5B,0x35,0xB5,0x5D,0x35,0x3D,0x76,0xE0,0x6E,0x0A,0x95, +0xF0,0xBF,0xAA,0x93,0xA9,0x8C,0xEC,0x17,0x39,0x3C,0xDF,0x80,0x9B,0x16,0xBB,0x30,0x35,0xD7,0xCA,0x18, +0x24,0x92,0xA9,0xC5,0x3F,0xA8,0x8D,0x0A,0x81,0x38,0x1A,0x2B,0x87,0x94,0xEC,0xE0,0x46,0x96,0x2A,0xBE, +0x73,0x60,0x04,0x24,0x9A,0xC2,0xBC,0x56,0xB5,0x32,0x33,0x7F,0xA4,0x9E,0x67,0xD6,0xAB,0xB2,0x9B,0xD9, +0x32,0x25,0x77,0xF3,0xDC,0xF0,0x29,0xA9,0xCD,0x3B,0xF6,0x8C,0x58,0x44,0xA5,0xDD,0x1E,0xCB,0x6F,0x1F, +0xF7,0x5B,0xFC,0xAC,0xD5,0x8C,0x19,0x3D,0x44,0x13,0x8C,0x9C,0xE3,0x5A,0xBE,0xEA,0xF6,0x41,0x96,0xD2, +0xD6,0xD2,0xEF,0xDE,0x3E,0xFD,0x4F,0x0A,0x63,0x92,0x80,0x42,0x96,0x8E,0xDF,0x23,0x7C,0x22,0x34,0xBC, +0xDC,0x39,0x71,0xAB,0xFA,0xC5,0xC9,0x57,0x34,0x17,0x36,0xC8,0xC8,0xDC,0xCB,0xA4,0x3D,0xCE,0xEF,0x89, +0xDC,0x1B,0x9D,0xFF,0x14,0x4C,0x24,0x7B,0x48,0x83,0x18,0xB3,0x13,0xC0,0x8A,0xB0,0xBF,0xED,0x2B,0x54, +0xD0,0x7F,0xF7,0x62,0x63,0xFE,0xB6,0xA0,0xB6,0x04,0xD8,0xB4,0x64,0x14,0xF9,0x74,0x0E,0xBC,0x3F,0x74, +0xE0,0xFD,0xBF,0xB4,0x37,0x32,0x40,0x66,0x1E,0x48,0xAF,0x8C,0xB1,0x66,0xF2,0x95,0xA4,0xF5,0x25,0xD2, +0x78,0xE0,0xB5,0x42,0xB3,0xE5,0x29,0x42,0xDF,0xFC,0xF8,0xBF,0x8F,0x1F,0xD8,0x40,0x5A,0x07,0xAF,0xF0, +0xB5,0x5F,0x10,0x70,0x60,0xC4,0xDF,0xB8,0x7C,0x47,0x8A,0x47,0x39,0x2A,0x50,0x60,0xBE,0xC4,0xAC,0x65, +0x2F,0x48,0x1E,0x37,0x5C,0xA9,0xFF,0x30,0xFA,0x05,0x88,0x17,0x4F,0x90,0x01,0x74,0xF0,0x62,0xD7,0x1D, +0x4B,0x08,0xEB,0xBD,0x85,0x68,0xA2,0x87,0xF0,0x1C,0x9F,0x9D,0xDD,0x2A,0x3C,0xBD,0x29,0x98,0xE4,0xA9, +0xF1,0x6B,0x8C,0xDB,0x49,0xE5,0x2D,0xA9,0xA3,0xC5,0x8A,0x1B,0xF0,0x4B,0x0A,0x3F,0xAC,0x84,0xCD,0x1B, +0x44,0xE9,0x61,0x4F,0x21,0x0B,0xEF,0x9B,0x80,0x00,0x43,0x69,0xF7,0x20,0xC6,0xBB,0xC8,0xE5,0x80,0x0B, +0x35,0x08,0x93,0x37,0x01,0xB6,0x58,0xEF,0xBA,0x4B,0x49,0x4A,0xA4,0xF4,0x8C,0xCE,0xBF,0xB6,0x16,0xA0, +0x21,0xC7,0xF8,0xBF,0x3C,0x83,0xE8,0x97,0x79,0x0E,0xB2,0x3A,0xBF,0x63,0x48,0xAE,0x38,0xF6,0x35,0x2F, +0x67,0x41,0xCD,0x90,0x09,0x02,0xA2,0x95,0x47,0x00,0xC4,0x3A,0xA0,0x07,0x54,0xA5,0x8C,0x63,0xAB,0x81, +0x98,0x03,0x8A,0x94,0x3F,0x0B,0xC9,0xB1,0xF4,0xC2,0x2C,0x9D,0xEE,0x6D,0x0B,0x7C,0xDF,0x02,0x6F,0x9F, +0xE8,0xFF,0xE3,0x73,0x5C,0xBD,0x3D,0xA7,0xD1,0x72,0xEF,0x91,0x12,0xFF,0xAA,0x10,0xD7,0x76,0xCC,0xF4, +0xBF,0xBC,0x88,0x74,0x35,0x14,0xC9,0x43,0x5F,0xFC,0xE4,0x30,0x54,0x75,0x96,0x1F,0x4B,0xC3,0x1D,0x87, +0x11,0xBB,0x46,0x51,0x1F,0xF1,0x3B,0x63,0x51,0xF2,0xDB,0xF1,0xF7,0xBE,0x34,0xE6,0xC7,0x92,0xCB,0x51, +0xE5,0x76,0x5D,0x8C,0x0C,0x86,0x07,0x26,0x11,0x7F,0xCD,0x40,0x5F,0xF6,0x2A,0xDD,0x51,0x2F,0xAC,0xF9, +0x92,0x6F,0x1C,0xC8,0x3D,0x13,0xF4,0x3E,0x9F,0x38,0x01,0x83,0xC0,0x9A,0xA2,0xDD,0x51,0xE5,0xBF,0x29, +0xE4,0x59,0xED,0xC2,0x33,0x72,0x95,0x94,0xF7,0x4D,0x89,0xD1,0x92,0x79,0x1D,0xCC,0x02,0x7B,0xB0,0xF2, +0x12,0x68,0x9D,0x18,0x6B,0x4C,0x5C,0x1D,0xA1,0x3A,0x9C,0x18,0xD3,0xB5,0xBE,0x73,0xD1,0x8B,0xAF,0xDB, +0x5A,0x53,0xC5,0x92,0x46,0x3A,0x4C,0x1C,0x0C,0x57,0x9D,0xBB,0x98,0x96,0x86,0x7E,0x03,0x2A,0x72,0xCF, +0x1F,0xDF,0x56,0xCE,0x72,0x10,0x47,0xE9,0xEF,0x95,0x97,0x8A,0x5D,0x18,0xC8,0x32,0x78,0x38,0x59,0x34, +0x42,0xA8,0x98,0xEE,0xB8,0x9A,0x61,0x00,0x9E,0x5B,0x4B,0xCE,0xDF,0x39,0x1F,0x24,0xEC,0x27,0x72,0xAE, +0x85,0x21,0x88,0x97,0x8D,0xD1,0x29,0xAB,0x93,0x4D,0xF6,0x27,0x09,0xF0,0xF6,0xAE,0x44,0x1D,0x7E,0xFE, +0xCA,0x46,0xDA,0x97,0xF6,0xDB,0x04,0x2E,0x99,0x8C,0xEF,0xAF,0x03,0x32,0x0E,0x11,0x0D,0x58,0x30,0x1E, +0xC2,0x45,0x4A,0x2B,0xEB,0x50,0x34,0x26,0x48,0xB4,0x9E,0x1F,0x4E,0x54,0xCA,0x3D,0xE9,0x83,0x26,0xB2, +0xED,0x51,0x9E,0xBF,0xF7,0xA9,0x6B,0x22,0x2C,0xCD,0xE3,0xD5,0x3E,0x8E,0xF8,0x61,0x79,0xE3,0x7B,0xE5, +0x91,0x2A,0x1F,0x41,0x77,0xC8,0x86,0x96,0x53,0xA8,0x91,0x74,0x8A,0x2D,0xE2,0xF7,0x96,0x03,0xCE,0x59, +0xC2,0x8B,0x8F,0x93,0x1E,0xC1,0x57,0xB6,0x6C,0x72,0x5C,0xA6,0xEF,0x0C,0x79,0xB7,0xE0,0xFF,0x67,0x77, +0xEB,0xA1,0x8C,0xD0,0x12,0x8C,0x7E,0xD2,0x10,0x64,0x29,0xE6,0xE1,0xDF,0x48,0x41,0xF5,0x81,0x34,0xA6, +0x5B,0x83,0xE8,0x11,0xFE,0x4C,0x80,0x9A,0x41,0x88,0x66,0x7F,0xF6,0xFE,0xE3,0xB7,0x92,0x9D,0xA9,0x47, +0x96,0xA6,0xA8,0x15,0xF5,0x44,0xAB,0x66,0x75,0xA4,0x39,0x5B,0xE4,0xA7,0x8F,0xF6,0x68,0x0A,0x19,0xD3, +0xDF,0xC8,0xA4,0x43,0x55,0x2B,0x91,0x36,0x3F,0xE8,0x06,0x6C,0xE3,0xC6,0x7A,0x27,0x4A,0x81,0x2A,0xFB, +0x5A,0xA1,0x81,0x9F,0x9E,0x96,0x8A,0xF4,0x74,0x0A,0x44,0x7A,0xBC,0xCD,0x22,0x89,0x5E,0x09,0x88,0x2D, +0x61,0xE8,0x9D,0xBB,0x42,0x21,0x82,0x58,0xBE,0x7B,0xA8,0x6F,0xF4,0xA8,0xD4,0x5C,0x64,0x7A,0xCA,0xDF, +0x99,0x8E,0xAA,0x2A,0xAF,0x40,0x85,0x8E,0x7A,0xFB,0x1A,0xC8,0x2C,0x5C,0x32,0x89,0xC0,0xA4,0x2B,0xFA, +0xEB,0xCA,0x4F,0x8C,0x7A,0x47,0x52,0xB2,0x38,0x42,0x94,0xFE,0xF6,0xAE,0xBE,0x1C,0xB0,0xA1,0x84,0x53, +0xB4,0x7C,0x1B,0xC9,0xAC,0xBE,0x63,0x50,0xB8,0x23,0x23,0x76,0x6D,0xD5,0x62,0x6E,0xBD,0x11,0xC3,0x5E, +0x6E,0x94,0x47,0xCC,0xB5,0xA5,0x22,0x97,0x2A,0x39,0xA2,0x82,0x3A,0x44,0x88,0xF1,0x56,0x66,0x9C,0x79, +0xDD,0x43,0x0A,0x1A,0x0C,0x39,0x2C,0x53,0x75,0x30,0xCF,0x61,0x5B,0xB4,0x18,0xF4,0xCA,0xDF,0xE9,0x41, +0x1B,0xF4,0xAB,0xC9,0x3D,0x72,0x5B,0xC3,0x4D,0xE1,0x65,0xE3,0xE3,0x6D,0x4B,0xE3,0x11,0x71,0x75,0xC3, +0x74,0xB0,0xA1,0x82,0xC7,0x18,0x93,0x3B,0x7F,0x02,0xB1,0x37,0xC0,0xD7,0xA1,0xDF,0xD1,0x78,0x5C,0x2A, +0x11,0x5B,0xB5,0xF7,0x10,0xAB,0xF4,0xF2,0xC1,0xCF,0xC9,0xB9,0x70,0xEF,0x80,0x3A,0x29,0xD8,0xEA,0x2D, +0xB4,0xB8,0xFB,0xB2,0x6B,0x5E,0xEF,0x88,0xBD,0x84,0x8D,0xC6,0xA0,0x4D,0x5D,0x2C,0x05,0xF4,0xB4,0x85, +0x69,0x50,0x0F,0xA0,0x0B,0x50,0x92,0x3B,0x90,0x5A,0x90,0x15,0x16,0xA8,0xFA,0x15,0xD4,0x85,0xB5,0xE3, +0x23,0x86,0xA6,0xBB,0x5E,0x37,0x98,0xB6,0x5D,0xBC,0x0E,0xDA,0x64,0xD3,0xB2,0x4C,0x80,0x6B,0x50,0x37, +0x2B,0xD0,0x8E,0x14,0x3C,0x60,0xA6,0x6F,0x6B,0x90,0x4D,0x9A,0x9C,0xE2,0x74,0xF9,0xC6,0xE9,0xDE,0xFC, +0x86,0x33,0xB7,0x88,0x59,0x98,0x04,0x02,0xFA,0xD1,0x02,0x5B,0xFF,0x36,0x43,0xEC,0x8B,0x4D,0x24,0xFB, +0xB9,0x99,0xF8,0x59,0xCE,0x99,0x8A,0x55,0x2D,0xFC,0x5B,0x93,0xC1,0xE1,0xCE,0x15,0x87,0x35,0x51,0xD6, +0xE6,0xAD,0x2D,0xBC,0xD0,0xF1,0x91,0xB4,0x6E,0x22,0x2A,0x89,0x02,0x29,0x6F,0x04,0x96,0x8C,0xD8,0xDB, +0x49,0x85,0x6C,0x31,0x07,0x06,0xD0,0x09,0x2E,0x71,0xF2,0xED,0x5B,0x53,0x36,0x22,0x4A,0x69,0x87,0xD9, +0x3C,0xDB,0x07,0xE9,0x06,0xD0,0x00,0x85,0x08,0xBE,0xA5,0xA5,0x94,0x83,0xA0,0x8E,0x13,0xC0,0x94,0x22, +0x23,0x19,0xA8,0xD7,0x22,0xC4,0x32,0xE3,0x3F,0xAE,0xAE,0xBC,0x2B,0x81,0xCB,0xC1,0x48,0xBE,0xA6,0x9C, +0x72,0x21,0x24,0xB0,0x58,0xC1,0x22,0xA8,0x4C,0xB1,0x86,0xCA,0xA3,0xF1,0xC0,0x89,0x98,0x71,0x5A,0xE0, +0xBB,0xFC,0xD8,0x66,0xA3,0x28,0x67,0x75,0x59,0x2B,0x9F,0x80,0xB0,0xE2,0x7E,0xEC,0x8C,0xDB,0x78,0xDA, +0xF9,0x1C,0x6E,0xC9,0x2A,0x49,0x50,0x17,0x53,0xE1,0x76,0xFC,0x6B,0x08,0x90,0xDD,0x9C,0x88,0x62,0xC0, +0x86,0xEA,0xE6,0x96,0x31,0x79,0xFE,0x3D,0xA3,0x55,0xFF,0x0D,0xDB,0xCE,0x43,0x31,0x29,0x02,0xC3,0x7B, +0x39,0x22,0x5B,0x01,0x68,0x43,0x40,0xC7,0x93,0x8A,0xFD,0x13,0x30,0x22,0xA7,0x72,0x72,0xF8,0x7C,0xBD, +0xE3,0x1B,0x02,0x1D,0x76,0x44,0xA7,0x8D,0xFC,0xCB,0x9C,0x99,0x7B,0xAE,0xF5,0x6B,0x67,0x6A,0xE8,0x1C, +0x1A,0x69,0xDA,0x18,0x49,0xD5,0x88,0x6C,0xB2,0x2D,0x3D,0xA1,0xE0,0x07,0xE1,0x3D,0x71,0xC9,0x26,0x98, +0x30,0x89,0xAD,0x84,0xB0,0x67,0xF0,0xE9,0xC8,0xFA,0x8F,0xA1,0x51,0x18,0xA0,0x63,0x10,0xB6,0xA1,0x8D, +0x1C,0xC4,0x78,0xF8,0xCF,0xA3,0xCF,0x3C,0x9A,0xAA,0x6A,0x2F,0x94,0x91,0x66,0x0E,0xD7,0x9A,0x72,0xA7, +0x78,0x0D,0x5C,0xA1,0x19,0x29,0x40,0x7A,0xD9,0x47,0xA4,0x29,0xB2,0x65,0xE7,0x2B,0x7D,0x6B,0xE3,0x0D, +0xDE,0xF5,0x49,0x6B,0x79,0xD3,0xAD,0x25,0x2B,0xB8,0x14,0x5C,0x8D,0x6F,0x8A,0xA1,0x08,0xD4,0xDA,0x42, +0xFD,0xBA,0xCD,0x1F,0xBB,0x69,0x74,0xE2,0xDB,0x97,0xBC,0x7B,0xBF,0x96,0xD4,0x20,0x60,0xA7,0x08,0xB1, +0x99,0x23,0x6C,0x2C,0xC6,0x77,0xAC,0x7E,0xC4,0xB8,0x0A,0xD2,0x9E,0xFC,0x9B,0xCB,0x93,0xBA,0x01,0x99, +0x49,0x01,0xD6,0xF6,0x8E,0xBB,0x11,0x34,0x09,0x41,0x71,0xD5,0x97,0x7B,0x17,0xEC,0x80,0x53,0xAD,0x1F, +0xB0,0xF0,0xCB,0x14,0x16,0xD8,0x5C,0xC6,0xC7,0x75,0x4C,0x50,0x9F,0x9D,0xDE,0xC6,0xF0,0xD1,0xB0,0x1E, +0x1F,0x5F,0x78,0x7B,0x99,0x2C,0x56,0xFF,0x02,0x3F,0x5A,0x25,0x72,0x37,0x44,0xE0,0x96,0xD2,0xE2,0xBC, +0x3A,0x9D,0xB4,0xA1,0xE5,0x6B,0xCD,0xD1,0xD9,0x5E,0xD6,0x9F,0x83,0xEF,0xEE,0x7B,0x19,0x4E,0xF0,0xA1, +0x17,0x1E,0x61,0xA6,0xF2,0xB1,0xC2,0xE0,0x1F,0x64,0x85,0x7C,0x7C,0xDA,0x26,0x90,0xD1,0x13,0xB8,0x25, +0x51,0x2B,0x1C,0x95,0x83,0x1C,0x45,0x5A,0xF6,0xFF,0xDD,0x6E,0xA7,0x9E,0x96,0xA4,0xBB,0xF5,0xBA,0xCA, +0xCA,0x3C,0x88,0xDE,0x19,0xF1,0x97,0xFA,0x9A,0x1C,0xDF,0x89,0x51,0xD9,0x4D,0xFF,0x9E,0xF5,0x0B,0x2C, +0x11,0x29,0x90,0x10,0x40,0x08,0x1C,0xFF,0x4A,0x5E,0x67,0xCA,0xDB,0xFA,0xE1,0xBB,0x18,0xF8,0x4D,0x67, +0x94,0x5C,0xBE,0xBF,0x37,0xB5,0xC6,0x15,0x95,0x1D,0x5F,0x7E,0x7A,0xD1,0x2E,0x64,0xCC,0x7B,0x4C,0x2D, +0x36,0x23,0xD6,0x09,0x76,0xA2,0xFE,0xBC,0x3F,0xA6,0x67,0x9C,0x43,0x4D,0xE7,0x5F,0xA9,0x34,0x6D,0x1A, +0xE3,0xF1,0xDA,0x9D,0x7A,0xF8,0xB0,0xAA,0x91,0x79,0x91,0x8D,0x18,0x94,0x3F,0xB3,0x69,0x52,0x49,0x00, +0xF9,0x7B,0x5E,0x04,0x67,0x4C,0x71,0x74,0xFF,0xD3,0x1F,0x51,0x76,0x61,0x14,0x44,0xBF,0x93,0x50,0x35, +0xA6,0x21,0xD6,0xBE,0xFC,0xB2,0xEC,0xCC,0x26,0x49,0x86,0x9F,0xD8,0x67,0xF2,0xF0,0x08,0x0F,0xDF,0xBF, +0x7F,0x41,0x09,0xDC,0x2D,0x21,0x05,0x45,0x3F,0x71,0x78,0x60,0xB7,0x88,0xBF,0x75,0x6A,0x0E,0xAE,0xC0, +0x41,0x48,0xAB,0x77,0xCD,0x4E,0x40,0xDB,0x00,0xE4,0x98,0x44,0x10,0x71,0x25,0xE6,0x17,0x45,0x8E,0x60, +0xB7,0x67,0x50,0x62,0x46,0x2A,0xE8,0xAF,0x03,0xE7,0x2D,0x56,0xC8,0x68,0x03,0x51,0xF6,0x1A,0xDF,0x30, +0xBC,0x27,0xEC,0x78,0x83,0x3D,0xD6,0xCA,0xE2,0x33,0xDC,0x94,0x5A,0xEB,0xC9,0x21,0xE5,0x4B,0x6D,0x55, +0x67,0x4F,0x2A,0xE1,0x17,0x6A,0xA7,0x95,0xD3,0x4A,0xA2,0x1B,0x62,0x01,0x74,0xAB,0xEB,0x23,0x98,0x96, +0xA7,0xAC,0xE7,0xBC,0x5C,0xE2,0xC7,0x68,0xE6,0x6A,0xF0,0x48,0x6B,0x06,0x42,0x49,0x7F,0xCF,0x84,0x97, +0xDF,0x3A,0x31,0x5A,0xE2,0x81,0xA9,0x32,0x77,0xEE,0x08,0xC9,0x60,0x77,0x37,0xD2,0x23,0xAB,0x55,0xB3, +0x0F,0x47,0x0F,0x7D,0x6A,0xCE,0xE8,0xCD,0x43,0x34,0x41,0xB8,0x22,0x6C,0x1C,0x4D,0xAF,0x13,0xD5,0x06, +0x18,0xCC,0xA7,0x1A,0xCE,0x4A,0xFA,0x5C,0x3E,0x38,0xD1,0x2A,0x8F,0x92,0xE0,0x99,0xF6,0x25,0xAB,0xF8, +0x39,0x02,0xA8,0x35,0xB4,0x89,0xD7,0x29,0x03,0x78,0x5D,0x51,0x93,0x5A,0x53,0x2B,0xD8,0x63,0x8D,0x69, +0x37,0xE1,0x50,0x2B,0x0F,0x99,0x89,0xDF,0x76,0xC7,0x9F,0x84,0x26,0xFC,0xC3,0x85,0x73,0xE2,0x32,0xE0, +0xDB,0x3D,0x9C,0x7D,0xBB,0x4D,0x0C,0x5D,0x8D,0x33,0x1E,0x55,0xF8,0x7D,0x26,0xAF,0xCE,0xD5,0xEB,0xE5, +0x07,0x10,0xAB,0x41,0xE1,0x5A,0xDC,0xE0,0x09,0xFC,0xF3,0x26,0x53,0x19,0xC2,0xF9,0x66,0xBA,0xE1,0x5D, +0x87,0x5A,0xCD,0x80,0x57,0x9E,0x77,0xC5,0xD3,0x3C,0x95,0x68,0x5C,0x50,0x97,0x0F,0x0E,0xB7,0xDB,0x0F, +0x77,0x3F,0xFB,0xA2,0x67,0x39,0xEC,0xC7,0xDF,0xBC,0x8F,0xC5,0xC7,0x2B,0xB5,0x1A,0xE5,0x0F,0x66,0x21, +0xA3,0x18,0xE4,0xD2,0x9F,0xC3,0x9B,0x01,0x76,0xC7,0xF1,0xC9,0x62,0x6E,0xB4,0xF2,0x07,0x17,0x49,0x2F, +0xEA,0x70,0xD9,0x0B,0xDE,0x9B,0x8D,0xE5,0xF0,0x23,0x3F,0x85,0x4C,0xF3,0xD3,0x97,0xDF,0xBA,0xC5,0x6D, +0x0C,0x3F,0xFD,0x0E,0xE3,0xB5,0x82,0xF8,0x8F,0xFD,0x72,0x70,0x5F,0x30,0x0E,0x54,0xC0,0xD5,0x25,0xCC, +0xB6,0x8B,0xF8,0xA5,0x1F,0x02,0x04,0x22,0xD6,0xDD,0xD9,0xC4,0x0C,0xDD,0x80,0x17,0xFF,0x2A,0x5F,0x89, +0xA9,0x4F,0x30,0x7C,0x38,0x31,0xC8,0xEC,0x05,0x49,0xBF,0xAB,0xF5,0xAF,0x2F,0x62,0xB1,0xD9,0x97,0x6C, +0x83,0xDE,0x46,0xC8,0xD3,0x52,0x45,0x38,0x02,0x84,0x5E,0x34,0x82,0x91,0xF4,0x4C,0xD5,0xF8,0x16,0xA1, +0xEC,0xD1,0x72,0xEC,0x8E,0x14,0xEA,0x5E,0x23,0x99,0x4A,0xBC,0xC8,0xD8,0xD2,0x12,0x53,0x90,0x40,0xE0, +0x36,0x09,0x98,0x33,0xAE,0x25,0xDD,0x7F,0x2F,0x11,0x8C,0xCC,0x4F,0x21,0xC0,0xA7,0xF8,0x9E,0x28,0x5F, +0xA3,0x72,0xD7,0x20,0xD4,0xB0,0x98,0x08,0xFA,0xCD,0x75,0x38,0x16,0x37,0x62,0x80,0xE9,0xA8,0xFB,0x23, +0xB1,0x4C,0xBD,0x5F,0xDD,0x95,0x96,0x60,0xB9,0x48,0x00,0x04,0x6A,0xA9,0x6B,0xE7,0x5C,0x8C,0xCC,0xA3, +0xE0,0xFE,0x18,0x25,0x54,0xEC,0x1B,0x03,0x42,0xE7,0x66,0xF6,0x81,0xBF,0x1F,0x1E,0x85,0x9F,0x7D,0xB7, +0xD4,0x6A,0x9F,0xE0,0xC4,0x01,0x81,0x24,0x30,0xA2,0x62,0x76,0xC7,0xE3,0xE7,0x74,0x19,0x6B,0x48,0x44, +0xAB,0xB2,0x2C,0xDB,0xE3,0xF2,0x6B,0xFE,0x43,0xC4,0x28,0x17,0x7C,0x08,0x5A,0xD6,0xE8,0x41,0xE8,0x50, +0x6C,0x25,0x87,0x70,0xDE,0xB8,0x6F,0xD1,0x1B,0x06,0x7F,0xF1,0xEA,0x0B,0xC9,0x55,0xED,0x06,0x8E,0x60, +0x42,0x06,0xB3,0x74,0xD1,0x44,0x73,0xE1,0x12,0xA8,0x64,0x2A,0x0E,0x8A,0xF4,0x02,0xA1,0xE6,0x83,0xD8, +0xAF,0xC8,0xAE,0x7B,0x4D,0x8E,0xE2,0xFF,0x9C,0xA5,0xBE,0x68,0x08,0xE8,0x1F,0x3F,0x11,0x00,0x2A,0x8A, +0x1A,0x03,0xB2,0xE2,0xB5,0x24,0x16,0x7F,0x8B,0x69,0x92,0x5D,0x7C,0x9C,0x7B,0x7A,0xC1,0x83,0xD1,0x46, +0x73,0x4E,0x1F,0x0A,0x06,0xE7,0xB5,0x79,0x99,0xCA,0x89,0xE8,0xC0,0x15,0x74,0x6E,0x84,0x8A,0x53,0x3D, +0x61,0x3F,0x13,0x19,0x38,0x70,0xE6,0x2A,0xFD,0x69,0x90,0x7D,0xBB,0xAD,0x6A,0x58,0xC8,0xE3,0x72,0x1E, +0x38,0xA0,0x5C,0x3A,0x6B,0x0B,0x98,0x17,0xF0,0x49,0x24,0x7F,0xEA,0x92,0xA2,0x6D,0x39,0x48,0x7B,0xB6, +0x63,0x8D,0xA3,0xBE,0x1E,0xA3,0xF3,0x1B,0xA8,0x52,0xAD,0x6A,0x33,0xED,0x35,0x5F,0x6A,0x8C,0xF3,0xA3, +0x37,0x22,0xEF,0x1B,0xB2,0x44,0x25,0x95,0xF9,0x22,0x3F,0xCA,0xB9,0xAD,0x2D,0xFA,0xA5,0x4C,0xF7,0x53, +0x2D,0xFD,0xCD,0x88,0xD5,0xAF,0xA1,0xEF,0xBC,0xC4,0x34,0x6A,0x21,0x7C,0x7C,0x43,0xE5,0xDC,0xFC,0xFF, +0xFB,0x7C,0x28,0xCF,0x55,0x4E,0x3A,0xCA,0x83,0xF3,0x1D,0x90,0x41,0xD3,0x94,0xC3,0x0F,0x1C,0x03,0xAE, +0xE4,0xCE,0x72,0x6D,0xB1,0x88,0x4F,0xFA,0x0A,0x37,0x7A,0x37,0x68,0x75,0xBB,0xB3,0x40,0xB5,0xCC,0x11, +0xDB,0xF7,0xF1,0x51,0x51,0x57,0xEE,0x0C,0xF2,0xBF,0xEC,0xA2,0x41,0x29,0x7B,0xB6,0x73,0x3A,0x14,0xE9, +0x00,0xD6,0xE4,0x0B,0x12,0xBD,0x7D,0xF1,0x20,0xB9,0x9D,0x50,0x30,0xFA,0xED,0x1E,0x20,0xF6,0xDC,0x67, +0x4E,0x74,0x33,0xD6,0x02,0x88,0xF5,0x2A,0x51,0x17,0xCA,0x02,0x67,0xDA,0x85,0x55,0x71,0x02,0xD2,0x1B, +0x89,0xA7,0x02,0x08,0x34,0x7E,0x2E,0x56,0xC4,0x55,0xAE,0x32,0x79,0xF8,0xA2,0x58,0x5B,0xCC,0x6D,0x5C, +0x51,0x8C,0xA6,0x27,0x82,0x01,0x41,0xBC,0xA5,0xBA,0x7C,0x4E,0xAE,0xBA,0x6B,0xE2,0x66,0x67,0xE8,0xEE, +0xDB,0x2B,0x48,0xAC,0x78,0x3A,0x83,0xA6,0xE8,0xC6,0x06,0xA7,0xA0,0xB6,0x5E,0xDF,0x69,0x31,0x44,0xEB, +0x86,0x08,0xF2,0xAA,0xD1,0x5E,0xC4,0x24,0x52,0x38,0x04,0xBE,0x81,0x38,0x16,0x8E,0x8D,0x81,0xE9,0x74, +0xC2,0x9E,0xDA,0x34,0x1D,0x39,0x0E,0x9E,0x2B,0x12,0x9C,0x9E,0x06,0x76,0x18,0x39,0x7E,0x2D,0x57,0xB2, +0x58,0x7E,0x69,0x59,0x49,0x45,0x4C,0x12,0x78,0x0B,0x59,0xBB,0xCB,0x19,0x0E,0xAE,0xDD,0xB8,0x61,0x49, +0x83,0x52,0xCB,0x7F,0x47,0x5D,0x7E,0x56,0xA7,0x55,0x98,0x36,0x96,0x0F,0x0E,0x6F,0xA7,0xCB,0xE0,0xC0, +0x44,0xAF,0xFC,0x81,0xA4,0x3E,0xD6,0x11,0xB4,0x3E,0x00,0x02,0xC7,0x6E,0xB9,0x50,0xAA,0x8F,0xAD,0x3C, +0xC5,0x5F,0x01,0x75,0xF6,0x9E,0xE4,0x50,0xC5,0x63,0xE8,0x0F,0x71,0x3D,0x52,0x61,0xBA,0x63,0x1D,0x75, +0x18,0x55,0x99,0x41,0xA7,0xDF,0xD9,0x7D,0x5F,0xEE,0x49,0xB1,0x8A,0x89,0xFF,0xA6,0x12,0x39,0xF0,0x18, +0x33,0xCF,0x1C,0xF4,0x5A,0xEE,0xA8,0xAB,0x64,0x51,0x3A,0x25,0x71,0xDC,0x2E,0x1F,0x66,0xC6,0x7C,0x36, +0x1F,0x68,0x1A,0x64,0x27,0x39,0x7A,0xA7,0x92,0xD3,0xF1,0x4C,0xAC,0x6B,0x73,0x6F,0x73,0x60,0xBF,0x4C, +0xB5,0x2A,0xF1,0x3A,0x63,0x94,0xCA,0xC6,0x3B,0xD4,0x99,0x21,0x75,0xE8,0xDB,0xE1,0xBF,0xCA,0xDC,0x42, +0xED,0x7E,0x4C,0x2D,0xED,0x17,0x55,0xAC,0xCD,0xEE,0x2B,0xF4,0xB6,0x96,0x99,0x4B,0xFC,0x56,0x63,0x13, +0xE8,0x3F,0x65,0x3F,0xDD,0xA9,0x21,0x81,0x6D,0xF1,0xDD,0x46,0x64,0xB2,0x87,0x49,0x33,0xA6,0x8B,0xB1, +0xDD,0x6A,0xEB,0xFA,0xE3,0x97,0x50,0x9B,0xE6,0x20,0x45,0x73,0xDF,0x86,0x64,0x3F,0x01,0x48,0x30,0x7B, +0xAF,0x0D,0x55,0xE2,0x6D,0xAC,0x29,0x6A,0x35,0x9C,0x62,0x82,0xE2,0x97,0x38,0x11,0xE4,0xE9,0xCA,0x99, +0xE2,0x0B,0xC5,0xE9,0x79,0x10,0xA5,0x7E,0x2C,0xE3,0x83,0xB8,0x0A,0x03,0xBC,0x43,0x98,0xCE,0xB3,0x6E, +0x4E,0xA0,0xB3,0x9E,0xA4,0xCE,0x53,0xA5,0x23,0x82,0xBA,0x21,0x55,0x4C,0x1D,0xD2,0xCE,0x5D,0xC1,0x80, +0xD9,0xCF,0xF0,0x11,0x85,0x2F,0x5B,0x78,0x32,0x0B,0x0A,0xE2,0x0C,0xDD,0x69,0xB7,0x0F,0x0F,0xD5,0x79, +0x96,0xD3,0x01,0xE9,0xA8,0xAA,0x06,0x02,0xF4,0x7E,0x16,0x4B,0x17,0x8A,0x5E,0xF1,0x9B,0xA2,0xFF,0xC9, +0x41,0xEE,0x27,0x21,0x0F,0x96,0x75,0x5A,0xE5,0x29,0x2F,0x19,0x44,0xE8,0xFB,0xF1,0x42,0xA3,0x99,0xD1, +0x12,0xB6,0xBB,0x4E,0x0A,0xB1,0x1A,0xC4,0xC7,0x17,0xE0,0x4E,0xB4,0x78,0x66,0x60,0x8D,0x90,0xCC,0x19, +0x94,0x9C,0x97,0xF5,0x86,0x6A,0xD4,0x29,0xD5,0x95,0xD8,0x90,0x90,0xB0,0xC4,0x08,0x8A,0x2C,0x4C,0x30, +0x2A,0x9B,0x05,0xA5,0xF6,0xB9,0x4F,0x53,0x7F,0x79,0xB0,0x65,0x4A,0x94,0x53,0x63,0xCF,0x9A,0xEF,0x3F, +0x97,0xB3,0x45,0x0C,0x0E,0x54,0x02,0x75,0x4B,0x55,0x27,0x64,0x97,0x87,0x1E,0x71,0x4F,0xB8,0x0E,0x55, +0x85,0xA0,0x69,0xE6,0x9D,0x57,0x15,0xD0,0xB4,0x24,0x4E,0x59,0x80,0x4F,0x40,0xBC,0x8C,0x5A,0x39,0xC8, +0x3F,0x06,0xE7,0x6A,0xC2,0x86,0xF8,0x8A,0xBA,0xDA,0x21,0xC9,0x8C,0xDC,0x63,0x5C,0x9E,0xE1,0x02,0xD5, +0x58,0xC7,0x16,0x01,0xBC,0xCB,0x16,0x48,0x61,0xD6,0x81,0x0F,0x70,0x0D,0x74,0x4C,0xC5,0xD8,0x64,0xB1, +0xDC,0xFC,0x60,0x88,0x0E,0x9A,0xCE,0x93,0x5D,0xAC,0xCA,0xB8,0xDC,0xF8,0xBC,0x38,0xA3,0x7E,0x53,0x09, +0xE3,0xD0,0x81,0x03,0x77,0xBF,0x5D,0x7B,0x3F,0x31,0xE1,0x27,0xCE,0x13,0x09,0xED,0x0F,0x5D,0xAE,0xED, +0x0B,0x31,0x57,0x20,0x20,0x69,0xB6,0x7E,0x1A,0x3F,0x04,0xDC,0x4E,0x60,0x25,0x9F,0xDB,0xFF,0x59,0x03, +0xA5,0xFF,0xE0,0x52,0x9E,0x2F,0xCC,0x36,0x46,0xEB,0x17,0xCC,0x3E,0xEB,0xF0,0x92,0xCC,0x2F,0x70,0x1C, +0xB6,0x3A,0x78,0x67,0x82,0x4C,0x03,0xD6,0xFD,0xEC,0x58,0xF0,0x25,0xF3,0xDB,0xFA,0xA3,0x33,0x4F,0x81, +0xEC,0x50,0xBA,0xC3,0x52,0x7E,0x31,0xEE,0x24,0x6D,0x18,0xF3,0x81,0x6C,0x01,0xB5,0x20,0x58,0xE1,0xDD, +0xAA,0x2C,0x41,0xC4,0x6E,0x78,0x5F,0xA4,0x69,0x3F,0x28,0xE2,0xD3,0xBD,0xB0,0x32,0x38,0x69,0x72,0xE0, +0x92,0xAA,0xDA,0xD6,0xF8,0x61,0xB4,0x12,0xBC,0x43,0x81,0x54,0xF6,0xBA,0x53,0xBD,0x69,0x42,0xD7,0x23, +0xFA,0x2B,0x6B,0x83,0x40,0xAA,0x2E,0x97,0xF3,0x24,0xED,0x2B,0x20,0x62,0xF3,0xE5,0x0A,0x88,0x70,0x0D, +0x62,0x48,0x66,0x32,0x05,0x6D,0xE5,0x48,0x48,0x85,0x8E,0x32,0x9A,0x34,0x32,0xCE,0xCD,0x29,0x3A,0x09, +0x51,0xEE,0xF5,0x9C,0x7C,0xA0,0xB2,0xE3,0xB5,0x24,0x64,0x59,0x7A,0xB9,0x1A,0x5C,0x5D,0x41,0x5A,0xF0, +0x2F,0x87,0x4D,0x6F,0x6F,0x4F,0x73,0x7F,0x46,0x45,0xCA,0xD4,0x7D,0xE3,0xD4,0x18,0x8F,0x90,0xF0,0x3A, +0x38,0x94,0xE1,0xD1,0xB2,0x04,0xF9,0xB9,0xB5,0x2F,0x7D,0xAA,0x88,0xE0,0x66,0x2E,0xE9,0x49,0xE6,0x0A, +0x17,0x43,0xD7,0x84,0x32,0x21,0x6A,0x13,0x38,0xEE,0x72,0xA2,0x0B,0x60,0x6F,0x9A,0xE7,0x42,0xDE,0x58, +0x68,0x6E,0xAF,0x2B,0xCA,0x01,0xFB,0xB6,0xA9,0x7F,0x09,0x96,0x48,0x82,0x30,0x2D,0xD6,0x95,0x11,0x03, +0x2C,0x82,0x34,0xD9,0xE0,0xA4,0x3B,0x2F,0x77,0x40,0x63,0x1D,0x88,0xEE,0xC4,0x7C,0xAD,0x13,0x3B,0x43, +0xF2,0x34,0x6C,0x48,0x1D,0x1D,0x20,0xDE,0xD3,0x15,0x0C,0x6C,0xDF,0xEA,0xEC,0xC2,0xBF,0x3C,0xA4,0x00, +0x65,0x34,0xE4,0x93,0x8C,0x7E,0x97,0x84,0xA6,0x1B,0x8D,0x81,0xB9,0x67,0x07,0xA1,0x17,0x40,0xAA,0x47, +0x5C,0xAF,0x76,0xBE,0x98,0x46,0xD5,0x91,0xB8,0x66,0x65,0x96,0x34,0x5C,0x29,0xCF,0x52,0x16,0x4C,0x77, +0xC3,0x1B,0xFE,0x74,0xAB,0x9B,0x8A,0x2A,0xE0,0x98,0x2F,0xC3,0xD3,0x8B,0xB7,0xF7,0x82,0x79,0xF4,0x2B, +0x00,0x94,0x4A,0x96,0x1E,0x5E,0xA4,0xF0,0x93,0xF4,0x25,0x81,0x40,0x1B,0x61,0xA7,0x45,0x53,0x80,0x83, +0x1D,0x4D,0x8C,0xF8,0x17,0xDD,0x2B,0xE5,0x5C,0xCA,0x75,0xE4,0x12,0xB6,0xC8,0x19,0xD7,0x1A,0x7E,0x06, +0x77,0xDA,0x1F,0xFA,0xD3,0x5A,0x46,0x54,0xE7,0xC5,0xD6,0x40,0x46,0x1A,0xA9,0x4E,0xD4,0xF5,0x59,0x74, +0x97,0x62,0x82,0xAD,0x1B,0x58,0x47,0xBB,0xCC,0xA6,0x2A,0xCE,0xDA,0x1C,0x5E,0xF9,0xAE,0xD2,0x9D,0x8C, +0x99,0x7A,0x81,0x9B,0xEB,0xBA,0xEF,0x8A,0xB8,0x75,0x4F,0xC6,0x14,0xE7,0x59,0x75,0xC2,0x76,0x27,0x84, +0x4A,0xF6,0x9D,0x5F,0x18,0x7D,0x20,0xF9,0xDD,0xE1,0xA6,0x3F,0xBE,0xB1,0xAD,0xE0,0xCF,0xA3,0xAE,0x5C, +0xEB,0xD3,0x8A,0x86,0x25,0x03,0xF6,0x26,0x97,0x30,0x5F,0x9E,0x90,0x1F,0xE6,0x07,0x7D,0xC6,0x1E,0xCD, +0x7F,0x72,0x95,0x86,0x51,0x5A,0x0E,0xD0,0x4F,0xC1,0x73,0x8F,0x09,0x1B,0x32,0x26,0x29,0x17,0xB0,0x59, +0xC0,0xB4,0x00,0x09,0x3A,0x82,0x85,0xB3,0x0E,0x23,0xA2,0x86,0x68,0x2F,0x60,0x9E,0x17,0x88,0x50,0x75, +0x87,0xCD,0xE8,0x22,0x5D,0x66,0xA4,0xEE,0x8D,0x7A,0x00,0x32,0xF4,0xBA,0x80,0xCD,0x64,0x40,0x93,0xD4, +0xF9,0x6C,0x07,0xE1,0x81,0x2D,0x12,0xA7,0xB0,0x12,0x69,0x0F,0xF7,0xC6,0xD1,0x6D,0xA1,0x69,0x01,0xFF, +0x3B,0xF8,0x2E,0xE1,0xA6,0x18,0xD1,0x16,0x2E,0xEA,0xC1,0xDF,0xE6,0xAE,0x39,0xBB,0xA1,0x80,0xCB,0x38, +0xC7,0x18,0xC4,0x80,0xC4,0x28,0x24,0x95,0xD2,0x69,0x60,0xE5,0xE6,0x8A,0x54,0x11,0x19,0x7A,0x7A,0x90, +0xA6,0xDE,0xC0,0x89,0x64,0xA6,0xFE,0x85,0xA6,0x80,0x5E,0x1C,0xAD,0x05,0x9D,0x01,0xE5,0x86,0xA3,0x31, +0x3D,0x82,0xA9,0x5B,0x87,0xC5,0xEC,0x30,0x99,0x58,0xFE,0x85,0xC1,0xBC,0x41,0x89,0x2A,0x89,0x62,0xF3, +0x9E,0x13,0x5A,0x8C,0x8D,0xF1,0xE9,0x2A,0x3F,0xA8,0x49,0x26,0xF9,0x17,0xEA,0xF2,0x0D,0x72,0x55,0x59, +0xDF,0xA9,0x1A,0xB8,0xDC,0x23,0x05,0xDC,0x4D,0xA4,0x86,0x8F,0xF1,0x54,0xDB,0xE7,0xC0,0x67,0x6C,0x0B, +0xCA,0xAA,0x07,0x51,0x7F,0x8F,0xAB,0x9F,0xFE,0x4B,0xE3,0x1B,0x94,0xFE,0x80,0xD9,0x61,0x36,0xC0,0x37, +0x78,0x54,0xF4,0xDC,0x2C,0xAD,0x0E,0x35,0xC0,0x31,0x53,0xE8,0xDF,0x06,0x11,0x2E,0x4F,0x11,0x52,0xA9, +0x67,0xE8,0xFA,0x38,0x77,0xA0,0x5A,0x1C,0x6E,0xAD,0x84,0x78,0xBE,0x6E,0xB2,0xC9,0x8F,0x82,0x00,0x8F, +0xDB,0xB5,0x4D,0x0B,0x6D,0xD5,0xE5,0x0D,0xBE,0xE8,0x53,0xA8,0xEB,0x89,0xF9,0xDD,0x74,0xEB,0x43,0x6B, +0x6C,0x8F,0xD2,0x8C,0x53,0xE2,0x8F,0xEC,0xF1,0x96,0xDB,0x34,0x3C,0x32,0x2C,0x42,0x2C,0xCB,0x1A,0x61, +0xD7,0xF6,0x77,0x92,0xED,0x88,0x96,0x76,0x39,0x6C,0x06,0x5A,0x0E,0x9E,0x10,0x24,0x3D,0xFB,0x05,0x47, +0x05,0x2D,0x65,0xB2,0x30,0x6D,0x15,0xC5,0xC5,0x61,0x1B,0x60,0x55,0x0D,0x3A,0x80,0x9C,0x42,0xB7,0x95, +0x96,0xA3,0x5D,0xF9,0xA2,0xDE,0xAA,0x5F,0xC6,0xB1,0x16,0xBC,0x85,0xF1,0xCF,0xB8,0xE7,0x08,0x5F,0xB9, +0x9B,0x68,0x59,0x99,0xEB,0xEF,0x8E,0xA0,0xDC,0x6A,0x50,0x28,0x2F,0xD8,0xB8,0x0C,0x7F,0xB8,0x44,0x09, +0x04,0xF5,0xDA,0x21,0xA0,0x77,0x5A,0x9C,0x8D,0x15,0x28,0x52,0x4B,0xBA,0x67,0x81,0x01,0xE6,0xAD,0x27, +0x86,0xDB,0xB4,0xD3,0x62,0xDB,0xB9,0x0C,0x6A,0x6A,0xA2,0xF2,0xF1,0x97,0xE6,0x6F,0x60,0x43,0x98,0xEF, +0x5C,0xB4,0x6E,0xBF,0x5F,0x28,0x20,0xE1,0x1C,0x63,0x33,0xB4,0x1C,0x22,0x91,0x2C,0x39,0x3B,0x46,0x1A, +0x49,0x1B,0x97,0x4D,0xF1,0x64,0xD2,0x76,0xAE,0xEF,0xFE,0x3A,0x3C,0x0A,0xCD,0x29,0x29,0xBC,0xC9,0xA9, +0x1D,0x79,0x6F,0x63,0x13,0xD9,0x6F,0xAA,0x39,0xB2,0x05,0x53,0xB1,0x14,0xC7,0x98,0x04,0xF4,0x76,0x22, +0x72,0x51,0x22,0x90,0x30,0xA2,0x91,0x90,0xB8,0xD6,0x16,0x29,0xC3,0x0A,0x16,0x1D,0xED,0x95,0x09,0xA4, +0xE9,0xB7,0x1E,0xAC,0x51,0xD0,0x21,0xFF,0x5B,0xFB,0x65,0x49,0x63,0xF0,0x9A,0x30,0x33,0x03,0xF3,0x16, +0xE6,0x9F,0x4E,0x71,0xFF,0x9E,0x67,0xDE,0xCC,0x97,0x6B,0x22,0xB7,0xFE,0x80,0x13,0xCF,0x92,0x55,0xC0, +0x5E,0x76,0x80,0x60,0x0C,0xFB,0xD2,0x4E,0xFB,0x44,0xA8,0xDA,0x50,0x0D,0x90,0xA1,0x5C,0xCA,0xC8,0x64, +0xC1,0xF6,0x64,0x8F,0xA4,0xB7,0xFB,0xF0,0x69,0x5A,0x9C,0xA1,0x1D,0x43,0x05,0x25,0x61,0xFD,0xB9,0xEB, +0x3C,0x2F,0x6E,0xE6,0x1E,0xDF,0x1D,0x80,0xF4,0x40,0x0D,0x14,0xFE,0x23,0xC1,0x10,0xEE,0x03,0x4D,0x57, +0x23,0x23,0x5D,0x90,0xD1,0xC3,0x96,0xB5,0x08,0x24,0xDF,0x3D,0x6B,0x9D,0x1E,0x25,0x6C,0x65,0x2F,0x9A, +0xAF,0xC5,0x96,0xF5,0x2D,0xE6,0x57,0xFA,0xA5,0x72,0x58,0xD1,0x4F,0xEE,0x23,0x07,0x63,0x94,0x95,0xE0, +0x8C,0xED,0xDE,0x38,0xEF,0xDF,0x15,0xC4,0xA8,0xE6,0xE9,0x9A,0x27,0x05,0x97,0xF4,0x8F,0x24,0x7C,0x7A, +0x2F,0x4C,0xD5,0xD4,0xC9,0xAC,0xA7,0x73,0x3A,0x86,0x92,0xE0,0x62,0x45,0x12,0x8E,0xDD,0x5B,0xD1,0xAA, +0x8D,0xDB,0x5E,0x89,0x70,0x4A,0x30,0xE2,0xF2,0x72,0x3E,0x1E,0x15,0x2F,0x7A,0xCB,0xCD,0xC4,0x4E,0xC9, +0x36,0xC3,0xF8,0x01,0x2D,0xF5,0xBB,0x71,0xBB,0x4A,0x2B,0x18,0x69,0xCB,0xD7,0x2D,0xD2,0x08,0x89,0xF7, +0x32,0x14,0x21,0xA4,0x38,0x84,0x49,0x73,0x22,0x2F,0x4F,0x1C,0xD3,0x89,0x96,0xED,0x24,0x6F,0x1E,0x62, +0xA4,0x5B,0x96,0xCD,0x02,0x2F,0x01,0x9F,0xD6,0x61,0x04,0x49,0x21,0x6E,0x13,0xB0,0x1B,0x2D,0x5A,0x78, +0x4B,0x4D,0xFC,0x54,0xDF,0xC9,0x17,0xC8,0xE5,0xE5,0x19,0xF1,0xCD,0x75,0x87,0xCC,0xCA,0x4E,0x28,0x4A, +0x7B,0x91,0x9F,0xD8,0x81,0x6C,0xCB,0x5D,0x4F,0xCE,0x5B,0x79,0xE5,0x2C,0x4D,0x7A,0x7A,0xF0,0x0C,0x85, +0x5F,0x30,0x20,0xE6,0xC3,0x55,0xEF,0xDF,0x6E,0xAF,0x4A,0xB0,0x52,0x73,0xF3,0x14,0x6E,0xE7,0xD6,0xDA, +0xC4,0x6D,0x64,0xB4,0x81,0xD0,0x42,0x35,0x3F,0xBA,0x95,0x69,0xC8,0x5F,0xBD,0x7E,0xB6,0x89,0x4C,0xBC, +0x05,0xF9,0x11,0x01,0xD8,0x90,0xB2,0xE1,0xA9,0x1A,0x20,0xEA,0x2C,0x28,0xBE,0x42,0x65,0xFE,0x99,0x15, +0xD3,0x13,0x9E,0xB1,0x6D,0xDD,0x5D,0xD3,0xDB,0x05,0xD0,0x45,0x62,0x76,0x33,0x1B,0x93,0xF2,0x98,0x25, +0x46,0xFC,0xF6,0x47,0x07,0x9A,0x88,0xE0,0x41,0x76,0x4D,0x6B,0x86,0xFC,0xDF,0xD5,0x8C,0x75,0x95,0xB2, +0x96,0x5A,0x11,0x60,0xCC,0x35,0xD5,0x1B,0x7F,0xDB,0x13,0x05,0xCE,0xDE,0x5C,0xA7,0x79,0x06,0x19,0x04, +0x8C,0xBC,0xFD,0x1F,0x1A,0x46,0x87,0x60,0x0E,0x55,0xD0,0xEA,0xCF,0x28,0x6E,0x18,0xF9,0xF7,0xD2,0x29, +0x17,0x53,0xF9,0x99,0x25,0xE2,0xD1,0x88,0x3F,0x59,0x26,0xFF,0xB7,0xC4,0xCE,0x1D,0x7D,0x3B,0xF8,0x0D, +0xE7,0xEC,0x3F,0x72,0xCB,0x3A,0xB3,0xCB,0x1B,0x3F,0xD3,0x38,0x97,0x9A,0x0B,0xBD,0x9A,0x18,0x6F,0xDA, +0x04,0xCD,0xFC,0x79,0xE5,0xA0,0x0D,0x5D,0xFF,0x9A,0xC0,0x6D,0x04,0x7F,0xB8,0xE5,0xB5,0x91,0x88,0x4C, +0x4E,0x1F,0xCC,0xEE,0xE8,0x76,0x84,0x2D,0x4E,0xBD,0x5B,0xAC,0xBB,0x22,0x1A,0x7D,0x45,0x3E,0xDC,0x1A, +0x92,0xCC,0x09,0x1D,0xCF,0xB7,0x56,0x5E,0xCA,0x93,0x53,0x69,0xE4,0x3D,0xD1,0x05,0xE9,0x33,0x1F,0x78, +0xA7,0x5E,0xF1,0xF4,0xDA,0x3B,0x8B,0x79,0xEB,0xBF,0x1F,0x11,0x4B,0xD2,0xE0,0x12,0x96,0x5D,0xA8,0x75, +0x15,0x01,0x08,0xDC,0xE8,0xCD,0x36,0xA3,0x5A,0x83,0x10,0xFA,0x61,0xCC,0x08,0x64,0x77,0x9D,0x03,0xAC, +0x44,0xA1,0xAC,0xB7,0x1B,0x01,0x09,0x61,0x79,0x8E,0x99,0x37,0x16,0x0D,0xCE,0xE4,0x3D,0x34,0xF5,0xD2, +0x9F,0x88,0xD2,0x1B,0x20,0xFC,0xD7,0x10,0x34,0x7C,0xE6,0x32,0xE1,0xD8,0xE9,0x97,0xD9,0xC1,0xB4,0x93, +0x4D,0x6F,0x47,0x6E,0xF7,0x0B,0xA4,0xC7,0x07,0x4C,0x44,0x04,0x2A,0x4B,0xB6,0xA7,0x4C,0x2F,0x8E,0x22, +0x16,0xE5,0x7A,0xD7,0x69,0xA6,0xED,0x9E,0xDD,0x28,0x65,0xE2,0xA8,0xE5,0xF6,0x34,0xEE,0xCA,0x7B,0x33, +0x87,0x4E,0x60,0x1D,0xA0,0x49,0xBD,0xF6,0x8D,0x67,0xD5,0xB8,0x7E,0x4E,0x37,0x23,0x86,0x4F,0x06,0x8C, +0x58,0x4A,0x8B,0x74,0x99,0x05,0x16,0x6C,0xE3,0xB3,0x26,0x4C,0xBB,0xD8,0x72,0xDB,0x33,0xCA,0xD5,0xD8, +0xAC,0x56,0xB8,0x9C,0xF6,0xED,0x82,0x07,0xB2,0xDB,0xEA,0x3B,0x7B,0xCB,0x5E,0xE1,0x0F,0x87,0xB5,0x69, +0xF4,0xA7,0x8B,0xD4,0xFF,0x4B,0x75,0xDA,0xD4,0xE9,0xC7,0x9F,0xC5,0xB5,0x91,0xAF,0x04,0x04,0x83,0x87, +0x40,0xA9,0x65,0xDF,0xFB,0x09,0x36,0xEF,0x20,0x26,0x9D,0xB6,0x1E,0xD7,0x78,0x3A,0x0F,0x4C,0x63,0xF5, +0x3D,0xE8,0x2E,0xFF,0x47,0xEE,0xB4,0xF3,0x1B,0x58,0xAA,0x5B,0x20,0x26,0xF2,0x6E,0x6C,0x37,0x2D,0xBE, +0xE1,0xAC,0x76,0xBE,0xA8,0x9F,0x23,0xCB,0xCE,0x8F,0x8A,0x1E,0xE6,0xF8,0xBF,0xFE,0xEA,0x66,0xFA,0x61, +0xF3,0xED,0xE1,0x0F,0x83,0xCD,0xDB,0xF6,0x52,0x62,0x9C,0x45,0xE6,0x50,0x1D,0x18,0x37,0xD0,0x30,0x86, +0x57,0x71,0xEC,0x22,0x70,0x93,0xD3,0x00,0x6D,0x9B,0xAC,0xB2,0x35,0xD3,0x2E,0x30,0x8E,0x95,0xE4,0x32, +0x19,0xFA,0x6D,0x9A,0xB4,0xDF,0x7A,0x86,0x90,0x49,0x8D,0x5D,0x8C,0xDF,0xE1,0xA3,0xFE,0x38,0xAF,0xEC, +0x28,0x15,0x29,0xD2,0x9B,0xF0,0x07,0x03,0x74,0x7C,0x7D,0xB3,0xDB,0xD0,0xF4,0xE6,0x02,0xD5,0x85,0x86, +0x72,0x10,0x34,0x67,0x48,0xD4,0x61,0x04,0xDA,0x59,0x38,0xD7,0x09,0xF6,0xFF,0x3E,0xE7,0x78,0x3C,0xF2, +0x2B,0xD7,0xA2,0x14,0x73,0x70,0xF5,0xE7,0xA2,0x95,0xF0,0xEA,0x7E,0xE7,0xAB,0xE6,0xC8,0xB5,0xE6,0x05, +0x1F,0x1F,0xB9,0x76,0x89,0xF4,0x12,0x90,0x5E,0x26,0xB9,0x56,0x88,0x3C,0x4E,0x15,0x9F,0xE6,0xA2,0x4A, +0x20,0x63,0xB2,0x0F,0x70,0x53,0x92,0xC8,0x9F,0xBD,0x32,0x2B,0x3B,0xF3,0x7B,0xF8,0xDA,0xFC,0xA4,0x3B, +0x13,0xDA,0x86,0x8B,0xCC,0x58,0x38,0x1B,0x57,0x9B,0x23,0xAF,0x2E,0x56,0x25,0x8F,0xB2,0xDA,0x0F,0x50, +0xDF,0x99,0x77,0x9A,0xDF,0xB8,0x17,0x64,0x9E,0x8A,0xFB,0x1E,0xB7,0x9B,0x5F,0x48,0x69,0x56,0x61,0x4A, +0xF7,0xD9,0xB2,0xCF,0x0C,0xBF,0x01,0x3E,0xBE,0xA3,0xAA,0x4F,0x40,0xDE,0x88,0xC6,0x8B,0x5F,0x2A,0x5B, +0x25,0xBF,0xF2,0xAD,0x52,0x3C,0xE2,0x8B,0x06,0x74,0xE9,0x9D,0x17,0xBC,0xE3,0x4A,0xA4,0xBC,0xF9,0xE2, +0x2C,0xB4,0x77,0xFE,0xC3,0xB7,0x61,0x1C,0x92,0x5E,0x6B,0xDB,0x85,0x9F,0x10,0x20,0x5E,0x3C,0xA1,0x0E, +0x80,0x34,0xFF,0xFF,0xFF,0xFF,0x59,0xA8,0x73,0x00,0x2B,0x76,0xFB,0x43,0x41,0xE7,0xFD,0xE6,0xA8,0xDA, +0xFC,0x6D,0xD1,0xAD,0x3A,0x53,0xF1,0x62,0xEE,0x2A,0x10,0x39,0xD5,0x82,0xA0,0x05,0xF0,0xE0,0x5E,0x01, +0xBF,0xFD,0xDB,0xAD,0xF8,0x41,0xC7,0x4F,0x0A,0x81,0x6E,0x56,0xFE,0xC3,0xD2,0x11,0xFE,0x83,0x5F,0xFD, +0xA1,0x6E,0xBC,0x84,0x28,0x20,0x39,0xC6,0x55,0xEE,0x1A,0x0E,0xF7,0x58,0x3B,0x63,0xB3,0xDB,0x54,0x44, +0xC0,0x88,0x13,0x8C,0x12,0x99,0x1E,0x36,0xF4,0x15,0x2F,0xDC,0xB6,0xF3,0x4A,0xF2,0xA8,0x01,0x03,0xA9, +0x60,0xA5,0xEC,0x3E,0x1F,0x1D,0x2D,0xAD,0xAE,0x6B,0x03,0x03,0xAA,0x4B,0x29,0x5A,0x8A,0x24,0xF1,0xAE, +0xF0,0x07,0x81,0x68,0xA0,0xD7,0x63,0xC1,0x52,0xE8,0x66,0x93,0x53,0x25,0xC2,0x0D,0x4A,0x13,0xF9,0x04, +0xBD,0x97,0x10,0xDB,0x72,0xE5,0xC0,0x66,0xB3,0x0C,0xB2,0x06,0x6B,0xA6,0x9C,0x7E,0x79,0x2D,0x7A,0xCB, +0xCD,0xC4,0xE2,0x2D,0x77,0xC4,0x12,0x6F,0x7F,0x1A,0xBD,0xA8,0xF0,0x27,0xC7,0x18,0x69,0xCB,0x28,0xCF, +0x74,0x97,0x5D,0x07,0xEF,0xA4,0xF5,0x1B,0x78,0xA8,0x49,0x72,0x22,0x2F,0x4F,0x4D,0x99,0x62,0x1D,0x4D, +0x0C,0x6C,0x78,0xBD,0xB9,0x6C,0xF6,0x0A,0xBD,0x29,0x65,0x75,0x5C,0x97,0xF3,0xC6,0x0A,0x6D,0x6A,0x2F, +0xB8,0xAE,0xE2,0x82,0x5B,0x00,0x22,0x43,0x0B,0x2F,0xA3,0x8E,0x37,0xF8,0xF1,0x7D,0x4E,0x81,0x6B,0x96, +0xF9,0x5F,0x10,0x85,0x9E,0x93,0x94,0x58,0xAF,0x14,0xE6,0xAE,0x17,0x22,0x24,0x3E,0x36,0xF9,0x00,0xA0, +0xE8,0xEF,0x06,0xEF,0xC2,0x47,0xBB,0x66,0xB0,0x9A,0xBB,0xCF,0xBD,0xFD,0xF4,0xF2,0x71,0x7D,0x72,0x39, +0x12,0xE1,0xF5,0x65,0x92,0x71,0x1A,0x15,0xE1,0x05,0x70,0xCB,0xAB,0xAC,0x86,0xF3,0x4B,0x01,0xDF,0x2D, +0xD8,0x51,0xC1,0xB1,0x0B,0x21,0xEE,0x82,0x51,0xCD,0xB7,0x62,0x97,0xBC,0x32,0xA7,0xD1,0xE7,0x27,0x42, +0xCF,0xA6,0xFE,0x75,0xE5,0x68,0xED,0xB2,0x99,0x0B,0xEC,0xA6,0xB3,0x3B,0xF7,0x13,0xE6,0xF9,0x4C,0x0C, +0x32,0x39,0x74,0x2E,0xAC,0x57,0xE4,0x16,0x58,0x3B,0xF8,0x92,0xD4,0x30,0xA3,0x05,0x3C,0x75,0x2D,0xA3, +0x5D,0x18,0xED,0xC2,0x33,0x72,0x2D,0x51,0x73,0xF9,0x2A,0x0D,0xB6,0x3B,0x4B,0x1A,0xA2,0x77,0x8D,0x75, +0xAF,0x25,0x65,0xB6,0x39,0xE8,0x68,0x80,0xF5,0x8C,0xD3,0xA9,0x20,0x95,0xF8,0x8A,0xD1,0x37,0xC2,0xD7, +0xE5,0xDE,0x86,0xCA,0x87,0x3A,0xA2,0x70,0x75,0xDF,0xB6,0x62,0x95,0x34,0x4F,0x85,0xDA,0x94,0x1A,0x41, +0x71,0x38,0x79,0x2C,0x41,0x79,0xD5,0xC7,0x53,0x5E,0x15,0x69,0xC4,0xD1,0x19,0x96,0x06,0x5A,0x47,0xE5, +0x40,0x78,0x70,0xEE,0x97,0x9A,0xE4,0x49,0xDB,0xFA,0xFF,0xEB,0x05,0x76,0x99,0xC9,0x0E,0x07,0x98,0x19, +0x3A,0x97,0xEF,0x72,0x99,0x1E,0x4D,0x04,0x5D,0xB1,0xC8,0xD0,0x8E,0x73,0xCE,0x2D,0x2C,0x3D,0x75,0xA3, +0x96,0xE1,0xA6,0xCE,0xB3,0x94,0x17,0xAF,0x48,0x5E,0x8E,0xCD,0xD1,0x04,0x08,0x19,0x3B,0x83,0x2A,0x9E, +0xEE,0x0A,0x2D,0xC9,0xAA,0x7F,0x91,0x10,0xBB,0xB2,0x02,0xCD,0x46,0x33,0xA7,0xCF,0x04,0x64,0xF6,0x0A, +0xA1,0x5F,0x89,0xF5,0x98,0x3D,0x08,0xCC,0xE8,0xCD,0x30,0x07,0x14,0xA1,0x03,0x6C,0xD4,0x9A,0xA9,0x70, +0xE6,0xB1,0x5B,0xF2,0x59,0x5D,0x54,0xA4,0x5D,0xE9,0x20,0x65,0x7B,0x3D,0xD9,0x20,0x6D,0xAD,0xCC,0x64, +0x1E,0x9F,0xD1,0x71,0x52,0xEF,0xFF,0x75,0x07,0x50,0x11,0xEC,0x7C,0xC0,0x80,0x69,0x1C,0xBE,0x2E,0xDF, +0xBD,0xAE,0xF2,0x24,0xF1,0x94,0x1B,0x61,0xB7,0x5B,0x8F,0x1C,0x94,0x1B,0x4F,0x80,0x50,0x0F,0x17,0xBF, +0x47,0xDA,0xFE,0x34,0x77,0xA3,0x6E,0x10,0x27,0xC3,0x2C,0x9E,0x8F,0x2D,0xD9,0xBC,0x67,0x19,0x81,0x11, +0xF4,0xAB,0x11,0x35,0xAC,0xCB,0xC7,0x41,0x8A,0x6B,0x14,0xB9,0x81,0x07,0x97,0x51,0x76,0x24,0x07,0x75, +0x26,0x44,0x06,0x9F,0xCD,0xAA,0xD8,0x8D,0xB3,0x01,0xB4,0x6C,0x74,0xA5,0x1D,0x59,0x62,0x48,0xA4,0x4C, +0x3C,0xEE,0x30,0xB5,0x2C,0xB9,0x90,0xAE,0x8C,0x06,0xDD,0x54,0x9B,0xC1,0x97,0xCD,0xD1,0xE4,0x92,0x6B, +0xD8,0xF7,0xB1,0x09,0x77,0xEE,0x4D,0x87,0x43,0xB7,0xCD,0x29,0x3D,0x69,0x96,0x6B,0x31,0x82,0x0F,0x65, +0x3E,0xCE,0xBE,0x65,0x78,0x17,0x40,0x18,0x7C,0x14,0x03,0x34,0x8F,0x81,0xCF,0xBD,0x92,0xA1,0x5B,0x99, +0xC2,0xC1,0x09,0x3C,0x70,0x8F,0x3C,0x3C,0xF8,0x9D,0x0D,0x24,0xC9,0xA5,0x23,0x67,0xAA,0x66,0xAA,0x91, +0xA7,0x04,0xDC,0x09,0x2F,0x95,0x98,0x68,0x3F,0xC0,0x08,0x4C,0x6F,0x71,0xB9,0x2D,0x83,0x66,0xD3,0xB4, +0x1A,0x52,0x6B,0xA2,0x97,0xEE,0x03,0x7F,0x2F,0x4E,0x4C,0x73,0xD9,0x14,0x32,0xE0,0x44,0x96,0x9C,0xB7, +0x95,0x31,0xE0,0x48,0x81,0x6F,0x58,0x34,0x7C,0xF8,0x05,0x61,0xA9,0x9C,0xFE,0xDC,0xDE,0xD5,0x66,0x1A, +0x19,0xCE,0xAA,0xD4,0x15,0xF7,0x5B,0x85,0x45,0x11,0x85,0x74,0x30,0x3F,0xD9,0x3D,0xE5,0x22,0x64,0x4F, +0xD2,0xBF,0xD4,0xB4,0x04,0xEC,0x16,0x75,0x19,0x4E,0x97,0xC8,0x20,0x58,0xC3,0xB1,0x14,0x70,0xBB,0xC3, +0x02,0x92,0x19,0x3D,0xC9,0xF6,0xB0,0x1C,0x7E,0xB9,0x72,0x95,0xD5,0xBB,0x16,0xB2,0x63,0xD7,0xB5,0x4F, +0x92,0xBC,0x9B,0x88,0xB1,0xDD,0xFB,0x1E,0x6D,0xB8,0xCF,0x73,0x07,0x69,0xB8,0xF3,0x3E,0x21,0xB1,0x1C, +0x69,0x6B,0xF4,0x98,0x51,0xA3,0x60,0xAF,0x5A,0x9E,0x6D,0xD4,0x7D,0x1A,0xF9,0x0E,0xEF,0x96,0xA5,0xF3, +0x43,0x67,0x8A,0x19,0x46,0xC5,0xDE,0xF8,0x57,0xB7,0x67,0x9B,0x42,0xC7,0x9B,0x5D,0xF0,0xF5,0x8F,0x2A, +0xB1,0x3A,0xD0,0x98,0xD4,0xB6,0x1E,0x6D,0x25,0xBA,0xBF,0xD8,0x8E,0xE9,0x41,0x3B,0xAF,0xAA,0x27,0xBD, +0xDC,0x6E,0x9D,0xD5,0x29,0x2A,0x4C,0x88,0x5D,0x05,0x11,0x3E,0xED,0x34,0xFD,0xD4,0x56,0xDF,0x01,0x1E, +0x0F,0x5B,0x07,0x44,0xFB,0x40,0xE5,0x48,0xEB,0x3F,0xE3,0xBE,0x36,0xB5,0x16,0xBC,0x04,0xD1,0xAF,0x1E, +0x9B,0x7D,0x6B,0x5E,0x36,0x44,0xAB,0xB8,0x1C,0x3F,0x00,0xFC,0x8E,0x5E,0x01,0x00,0x87,0xAD,0x5F,0x34, +0x4D,0x97,0x67,0xCC,0x8A,0xA5,0x61,0x89,0x8E,0xD8,0x08,0x10,0x1F,0x7D,0x98,0xDA,0xA3,0x64,0x58,0xC7, +0xB9,0x44,0x52,0x08,0x63,0xD2,0xA4,0xFF,0xF9,0x9F,0x20,0x7F,0x34,0xBF,0x79,0xEF,0xA3,0x62,0x49,0xDC, +0x04,0x43,0xA8,0xDA,0xD3,0x6D,0x1E,0x72,0xC9,0x51,0xB0,0x6B,0x90,0x2C,0xCC,0xD8,0x1B,0xCA,0x34,0xB0, +0x19,0x5F,0x3A,0xBD,0x73,0x7F,0x83,0x8F,0x65,0x2E,0x14,0x95,0xE2,0x42,0xEE,0xE7,0x71,0xFD,0x71,0x23, +0x7E,0x6F,0xD0,0x21,0x34,0xFC,0x1D,0xD7,0x44,0x03,0xD1,0x30,0xBA,0x6B,0x56,0x26,0x6A,0x09,0x00,0x19, +0xF7,0xAF,0xB1,0x13,0x7E,0xE5,0xEA,0xD4,0xC3,0xCB,0x72,0xE0,0x9A,0xAA,0x50,0x47,0x23,0x4C,0x98,0x2D, +0x8F,0xDA,0x82,0x64,0x3B,0x54,0x53,0xC3,0x69,0x42,0xC5,0xA7,0x5A,0x37,0x69,0x9E,0x2B,0x17,0x75,0xE1, +0x96,0x75,0xED,0x33,0x74,0x62,0xEF,0x60,0xF2,0x83,0xED,0x13,0x38,0x5C,0xA7,0x5C,0x51,0x8B,0x3D,0x97, +0xF7,0x95,0x83,0x6A,0xA7,0x74,0xD2,0xD1,0xEF,0x4C,0x96,0xC4,0x78,0x25,0x94,0xE0,0x09,0x4B,0xF3,0xDE, +0xB8,0xD6,0x43,0xA9,0xEC,0xB6,0xFA,0xCF,0xDD,0xE4,0x65,0xEB,0x7F,0xBF,0x38,0x43,0x79,0x15,0x85,0xAD, +0xB3,0x05,0x6C,0x1C,0x79,0xEB,0x8F,0x1B,0xBA,0x3B,0xE3,0x7F,0x6E,0x45,0x42,0xA0,0x6C,0x27,0xC9,0x76, +0x32,0x0F,0x7A,0xB7,0x39,0x6F,0x54,0x3D,0x98,0xC0,0x36,0x1E,0xF5,0x20,0xB8,0x0E,0x1A,0x63,0x35,0xDC, +0x70,0x86,0xF1,0xBA,0x0B,0x90,0x23,0x02,0x2A,0x49,0x92,0xF8,0x13,0x7C,0xFB,0xB3,0x9A,0x43,0x2B,0xAF, +0xA9,0x77,0x6C,0xE6,0xA9,0x4A,0xEB,0x2A,0x18,0x0E,0xE2,0x27,0x1E,0x73,0x33,0x2F,0xA8,0x29,0x3A,0xB9, +0xCF,0x62,0xDD,0x50,0x32,0x1E,0xD0,0x6F,0x4B,0xFA,0x3C,0x7E,0x20,0x7D,0x7C,0xA7,0xE3,0x5F,0x2C,0xD4, +0x7C,0x79,0x72,0x58,0x31,0x5C,0xB6,0x6E,0xCA,0xAC,0x62,0xF0,0xE3,0x9D,0xC5,0x8C,0xD4,0xD0,0x05,0x69, +0xEC,0x5F,0xFA,0x01,0xCB,0xB9,0x7D,0xC3,0xC6,0xDF,0x11,0x54,0xF1,0x52,0x73,0x58,0x92,0x23,0xA5,0xF7, +0x48,0x3F,0xFD,0xD3,0x03,0x13,0xA5,0x85,0x73,0xDC,0x24,0x97,0xE1,0x1B,0x28,0x56,0x72,0x3E,0xCA,0x1F, +0x97,0xF7,0x8D,0xCC,0xD7,0xAB,0xDA,0xA3,0x4F,0x79,0xAA,0xB0,0xBC,0xB3,0x9C,0xAD,0xA9,0x5D,0x83,0x04, +0x86,0x79,0x1C,0x18,0x05,0xB9,0x8B,0x82,0x5B,0x5F,0xC4,0x65,0xBF,0x72,0xD4,0x83,0x0D,0x34,0x2B,0xA5, +0xA2,0x57,0xCF,0x95,0xF7,0x9A,0xDD,0x92,0x75,0xFA,0xE5,0x8A,0x72,0x7A,0xBE,0x7B,0x3F,0x08,0xBE,0xF2, +0xB9,0x35,0x06,0x40,0x34,0x95,0x36,0xDE,0x1A,0x64,0xC2,0x1C,0x12,0xD8,0xD8,0xFA,0xCE,0x29,0x0C,0xA6, +0x82,0x1D,0x2A,0xDE,0x82,0x84,0xBF,0x7A,0xB7,0xAF,0x38,0xCF,0x19,0x21,0x49,0x4B,0xEC,0xDF,0xE9,0xAA, +0x59,0xE5,0xCF,0x60,0xB8,0xB6,0x37,0x62,0x58,0x40,0x21,0x5B,0x8B,0x47,0x89,0xDF,0x99,0x7D,0x7A,0xF2, +0x49,0x5A,0xD8,0xBD,0x5B,0x35,0x47,0x88,0x20,0xF1,0xE8,0xAC,0x12,0x71,0x74,0x68,0x9F,0xB2,0xF6,0x27, +0x5B,0x36,0x60,0xD4,0x45,0x82,0xE4,0x4C,0xE2,0xD2,0x51,0xFC,0x41,0x5A,0xC9,0x4F,0x77,0xB0,0xC2,0xD8, +0x4B,0xA1,0xC5,0x6F,0x11,0x3A,0xEB,0xBB,0x88,0x5F,0xB6,0x2D,0x44,0x70,0x05,0xE5,0xED,0xA7,0x7B,0x9F, +0x0C,0x1A,0x9B,0xE4,0x14,0x7D,0x60,0x17,0x8F,0xA8,0xD7,0xE2,0x1C,0x82,0x88,0xDC,0xF8,0xED,0x08,0x0E, +0xEC,0xB1,0xF1,0x0B,0xF0,0x0A,0x64,0xDA,0x1F,0x8C,0x80,0xD8,0xF9,0xEC,0xD9,0xF2,0x8B,0x82,0x25,0xF6, +0x95,0x82,0xEE,0x1B,0xC2,0xDB,0xCE,0xA5,0x11,0xEA,0x37,0x1F,0xA6,0x23,0xD1,0x13,0x75,0x22,0x3B,0xD5, +0x45,0xF3,0x44,0x70,0x2C,0x95,0xDF,0x0D,0x35,0x27,0x1A,0x79,0x2A,0x71,0x91,0x11,0x2B,0x46,0xE8,0x62, +0xDF,0xEF,0x97,0xAA,0x07,0x3E,0x28,0x7B,0x13,0xBE,0x22,0xF6,0x41,0x3D,0xFE,0x43,0xDE,0xDD,0xD9,0xBD, +0x96,0xCB,0x70,0xC3,0xED,0x50,0x6F,0x4B,0xE7,0x56,0xF7,0x4B,0x5F,0xED,0xEB,0xD7,0x8B,0xC1,0x70,0x31, +0x60,0xB7,0xDC,0xF7,0x9A,0x61,0x69,0x68,0xD6,0x1A,0x7C,0xCF,0x00,0x8C,0x01,0xFD,0x98,0x05,0x6B,0xB3, +0xAD,0x87,0x89,0xA0,0x5F,0x88,0x14,0x13,0x4F,0x76,0x0E,0x7C,0xEA,0xCC,0xF3,0xBE,0x60,0x30,0xEA,0x58, +0xD2,0x6F,0xA7,0xFA,0x83,0xAA,0xDB,0xBF,0x05,0x05,0xDB,0x2F,0xCA,0x91,0xED,0x6F,0xD4,0xF1,0x9B,0x0F, +0x23,0x06,0x93,0xE0,0xAE,0xFA,0x53,0xF9,0x4E,0x8F,0xB9,0xFF,0x99,0xFB,0xCE,0x25,0xD0,0xD1,0x5A,0xB1, +0x4B,0xA5,0x7A,0x6E,0xE7,0x9A,0xE4,0x0C,0x3E,0xEA,0x62,0x5B,0xF3,0x85,0x72,0xBE,0x0B,0xC1,0xEC,0x1A, +0x0D,0x16,0xD3,0x8D,0xD3,0xE0,0x80,0x8B,0x82,0x25,0xFD,0x3C,0xB3,0x07,0x4D,0x1F,0x8C,0x67,0x8D,0x69, +0x3F,0x6D,0xFB,0x29,0x64,0xBE,0xD5,0x2E,0x55,0x26,0x7B,0x08,0xF3,0x6E,0x80,0x58,0x7E,0x50,0x21,0x45, +0xEE,0xC0,0x24,0x68,0x8F,0xAF,0x4A,0xA5,0xC5,0x0F,0xCA,0xA0,0x95,0x73,0x50,0x63,0x3D,0x91,0x71,0x93, +0x82,0x8E,0x65,0x9B,0xC0,0x27,0x47,0x91,0xD4,0x9D,0x2D,0x57,0xA2,0x49,0x65,0x97,0x26,0x3F,0x81,0xC1, +0x1B,0xBC,0x9C,0x54,0x78,0xFF,0xC5,0x8A,0x22,0xD3,0xD4,0x13,0xFD,0xD2,0x7C,0xD5,0x33,0xDB,0xDA,0xC9, +0x27,0xFB,0x58,0xE8,0xCF,0x75,0x48,0xB9,0xF4,0x4B,0xD1,0x66,0x3B,0x72,0xCC,0x19,0x45,0xA5,0x4A,0x30, +0x13,0x3A,0xCC,0x16,0x23,0xAE,0x42,0xC7,0x46,0x57,0x83,0x72,0x0C,0x7E,0x43,0xB6,0x05,0x13,0x5E,0xB7, +0x36,0x30,0x7D,0xE7,0x4F,0x80,0x4D,0x1D,0xE6,0xBB,0xF8,0xA1,0x4C,0x86,0x70,0xB1,0x48,0x3C,0xD1,0x80, +0xDB,0x71,0x95,0x95,0x0C,0xF9,0x7F,0x6E,0x68,0xA3,0x8F,0xF4,0xAD,0x84,0xB2,0x5B,0x6D,0xF8,0x32,0x5F, +0x7D,0xD8,0x74,0x0C,0x2C,0x91,0x07,0xD1,0xC0,0xC5,0x3F,0xDC,0x92,0x54,0x9C,0xC1,0x5C,0x99,0xFF,0xFC, +0x21,0x81,0x98,0xC4,0x29,0x67,0x6E,0x1A,0x49,0x05,0x68,0xAE,0xFA,0x33,0x76,0x7F,0xCA,0x9B,0xC7,0xFD, +0x42,0xB5,0x44,0x40,0xD2,0x1B,0xE1,0xFF,0xF5,0xE0,0x58,0xE2,0xA3,0x3A,0xBE,0xF7,0x8D,0x41,0xE8,0x15, +0x87,0x8D,0xCE,0x14,0xF1,0x01,0x5F,0x5E,0x72,0x50,0x6C,0x5E,0x5C,0x07,0x5A,0x7E,0x32,0x7B,0x7A,0x03, +0x77,0xBC,0xF9,0x8B,0xAA,0xB3,0x1F,0x27,0x9B,0xFC,0x15,0xEB,0xE8,0x26,0x90,0x91,0x2C,0xF6,0x57,0xBB, +0xAB,0xB2,0xF9,0xF6,0x54,0xFB,0x77,0xFF,0x46,0x89,0x20,0xFF,0xDB,0xFF,0x5E,0x35,0xFF,0x1B,0x2C,0x96, +0x50,0x28,0xCC,0xD6,0x73,0xB2,0xB9,0xD7,0xDC,0x6D,0x9E,0xE9,0x0B,0x43,0xB0,0xC4,0x33,0xDE,0xA0,0x20, +0xE6,0x2F,0x27,0x05,0xF0,0xE0,0xDF,0x77,0x7F,0x79,0x91,0x87,0x10,0x99,0xA9,0xDE,0xF3,0x80,0xEA,0x02, +0x71,0xDD,0xC5,0xF7,0x5D,0xC2,0x7E,0x95,0x89,0x8E,0xFE,0xF1,0xC5,0x62,0xF9,0xC6,0x55,0xEE,0xF4,0x22, +0xF9,0x14,0xA7,0xB7,0x1B,0x79,0x52,0xEA,0xB3,0x48,0x6F,0x55,0xF3,0xE5,0xB5,0x17,0xFA,0x73,0xDE,0x36, +0x73,0x23,0xE3,0x32,0xE2,0xB8,0x8A,0x3E,0xB8,0x01,0xF9,0xAF,0x92,0x4B,0xA2,0xB6,0x93,0xDB,0x69,0x1A, +0x43,0x4B,0x31,0x96,0x56,0xEB,0x37,0x04,0x72,0x51,0xB7,0x53,0x72,0xA4,0x71,0x13,0x37,0xCF,0xE1,0x9B, +0x7F,0x6A,0x5B,0xE5,0xED,0xF7,0x9A,0x6C,0x50,0x65,0xC6,0x5A,0xEF,0x0A,0xC0,0x66,0xB3,0x0C,0xCA,0xDD, +0xAE,0xFD,0xB0,0xF4,0x4D,0x66,0xB9,0x0C,0xA8,0xB6,0x36,0xA7,0xB2,0xC1,0xDE,0x3C,0x69,0xB5,0xC1,0xEB, +0x18,0x9A,0x84,0x8E,0x14,0xAB,0xAB,0xC3,0x74,0x67,0x1D,0x6A,0xE1,0x84,0xD2,0x98,0x3C,0x8A,0x42,0x25, +0x6C,0x42,0x22,0xA7,0x32,0xE3,0x3C,0x1C,0xF7,0xAD,0xEF,0xBF,0x96,0x21,0xE5,0x39,0xBF,0x2F,0x7E,0xF7, +0xB1,0xC4,0xEA,0x2A,0x69,0x11,0x94,0xBE,0x1F,0xD0,0x73,0x02,0xDA,0x71,0x65,0x4D,0xFA,0xEC,0x7B,0x79, +0x08,0xA1,0xB8,0x6A,0x3B,0x91,0x35,0x0B,0x31,0xD1,0x6A,0xF7,0x31,0xE6,0x35,0x5E,0x2A,0x90,0xF9,0x6D, +0x4F,0x80,0x64,0x32,0x5E,0x92,0xBB,0x8E,0x5F,0xE2,0xA3,0xB5,0xC9,0x01,0x23,0xB5,0x03,0xDB,0x36,0x53, +0x08,0x4B,0xAC,0x4A,0xDC,0x7D,0xA0,0x03,0x4D,0x19,0x0E,0xA2,0x59,0xBC,0x22,0x81,0x52,0xBA,0x25,0x2E, +0x9A,0xB9,0xC1,0x04,0xE3,0xE1,0x3F,0xF4,0xD8,0x3B,0xC8,0xD5,0xC1,0xD0,0x39,0x3E,0x1B,0x9A,0x59,0x79, +0xAF,0x5E,0xD4,0x91,0x16,0x9E,0x87,0xD1,0xB9,0x48,0xBD,0xE5,0x0C,0x78,0x3A,0xC6,0xC3,0x97,0x60,0xA6, +0xC1,0x51,0x3C,0x82,0x95,0x5A,0x79,0x0A,0x5C,0xD2,0x37,0xF7,0x82,0xAA,0xD9,0xB2,0xE9,0x9A,0x27,0x37, +0x65,0xF5,0x54,0xCB,0x7E,0xA8,0x68,0x32,0x2E,0x1B,0xFD,0x3E,0x3F,0x2D,0x6D,0x1A,0x61,0x5B,0xED,0x0E, +0x41,0xA3,0xF2,0xE0,0x02,0x96,0xC1,0x5D,0x16,0xA1,0xF1,0xB1,0xEF,0xAC,0x09,0x66,0x52,0xC8,0xF9,0x60, +0x53,0xD5,0x9E,0xEC,0x20,0x23,0x95,0x58,0x60,0x17,0x9A,0xD3,0x10,0x75,0xB6,0x63,0xA4,0xC4,0x0E,0xFA, +0x45,0x76,0x24,0x50,0x6D,0x16,0xA4,0x0C,0xE8,0xD6,0xE0,0x77,0x9B,0x88,0xA3,0xEB,0x47,0x21,0x4E,0x5C, +0x0C,0xFB,0x85,0x2F,0x13,0x3E,0x68,0x6A,0xC1,0xB6,0xEF,0xCE,0x12,0x36,0x46,0x25,0x4C,0xFA,0x3B,0xDF, +0x0A,0x1E,0xA6,0x3B,0xAE,0x91,0xB8,0x8C,0xC7,0x9D,0x52,0xCC,0x15,0x5C,0xAD,0x68,0x3A,0x6A,0x76,0x26, +0x87,0x10,0x6E,0xAE,0x59,0x01,0x5E,0xB8,0x24,0xA0,0xF6,0x9E,0x82,0x71,0x15,0x82,0x41,0x7A,0xFF,0xFD, +0x38,0x91,0xC7,0x96,0x65,0xD8,0x17,0xFC,0x10,0xE3,0xE3,0x42,0x54,0xC2,0xB1,0xDA,0x1A,0xA0,0x49,0x9B, +0x8B,0x59,0xE7,0x83,0x7A,0x72,0x38,0x07,0xCC,0x21,0x32,0xF9,0x12,0x19,0xB6,0x65,0x77,0xDB,0xEE,0xC4, +0x50,0x1D,0x76,0xF0,0x59,0x04,0x90,0xE9,0xFC,0x40,0x87,0xF5,0x87,0x81,0x18,0x45,0xF6,0x62,0xB3,0xEB, +0xBB,0x4F,0x09,0x85,0x5D,0xF5,0x8B,0xB0,0xA0,0x3D,0x83,0x17,0x00,0x4D,0x70,0xFA,0xE1,0x7C,0x45,0x88, +0x94,0xC3,0x31,0x3A,0x38,0x45,0x94,0xC4,0x59,0xEE,0xD4,0x20,0xFD,0x79,0x40,0x35,0xB5,0x27,0xD9,0x2D, +0xBB,0xB8,0xA2,0x2D,0xBD,0x80,0x16,0x54,0xE6,0x06,0x11,0x71,0xB6,0xC9,0xC3,0xD7,0x8D,0xC8,0x87,0x09, +0x3F,0xE8,0x77,0x21,0xE6,0xC0,0xCC,0xB4,0x1A,0xAB,0xC2,0x64,0x3A,0x82,0xC9,0x9D,0x7A,0xEB,0x40,0xA0, +0x0B,0x8A,0x8E,0xA4,0x9A,0xFA,0x06,0x89,0xC1,0x47,0xEB,0xF1,0x3C,0xA3,0xE2,0xE2,0xEB,0x55,0x62,0xE2, +0xF7,0xB3,0xC9,0xEA,0x0C,0x45,0xC9,0x09,0xFD,0x57,0x92,0xE5,0xE4,0x68,0xF3,0x02,0xB8,0xA2,0x63,0x0C, +0x29,0x64,0xDA,0xCD,0xD9,0x64,0x5D,0x23,0xBF,0x88,0x7F,0x79,0xBF,0x48,0x6A,0x37,0x6B,0xD1,0x0C,0x1E, +0x7D,0x6B,0x87,0x84,0x8E,0xCB,0x6B,0x9B,0xA6,0x8F,0xA9,0xCA,0x6E,0x3B,0xE9,0x74,0x36,0x8F,0x9B,0x6D, +0xAF,0xE0,0xC2,0xE2,0xE3,0xA7,0x13,0x20,0xBF,0xD0,0xC8,0xDE,0xC7,0x43,0x09,0xA9,0x1E,0x70,0xF8,0xDC, +0xF4,0xE9,0xC1,0x34,0xD2,0x30,0xC2,0x39,0x85,0x12,0x04,0xB8,0x97,0xD3,0x32,0x30,0xF6,0xA3,0x5E,0x10, +0x57,0x92,0x57,0x0D,0x29,0x8B,0x7D,0x39,0xEF,0x89,0xD1,0xEF,0x0E,0x00,0xD6,0xB9,0x6E,0x30,0x40,0xE5, +0x42,0x12,0xB6,0xC5,0xEE,0x31,0x5B,0x6E,0x30,0xFD,0xA2,0x5D,0xE9,0x76,0x8C,0x5D,0x47,0xE1,0xAE,0xE4, +0xE7,0xB1,0x96,0x70,0x33,0x0A,0xC3,0xC1,0x55,0xBF,0x41,0xF1,0x8C,0x87,0x6D,0x1B,0x97,0xF9,0x09,0x18, +0xB5,0x12,0xA3,0x63,0xE0,0x29,0x0D,0x49,0xE4,0xBF,0x25,0x03,0x4C,0x52,0x46,0xB3,0x48,0xDD,0xDA,0xF3, +0x83,0xC8,0xC3,0xE6,0x04,0xA5,0x07,0xDD,0xA2,0x3B,0x50,0xA4,0xCD,0xD8,0x0A,0xE4,0x87,0x57,0x4B,0xA4, +0xD7,0x21,0x61,0x9D,0xDA,0xE9,0x92,0x93,0x25,0xF8,0x07,0xD5,0xC6,0x6A,0x43,0xB9,0xE2,0x28,0xC1,0xFD, +0xB7,0x63,0xBC,0xEA,0x13,0x00,0x5C,0x10,0x6A,0xDB,0xFD,0xD8,0xFF,0x8A,0xC4,0xAD,0x32,0xCA,0x8E,0x24, +0xB2,0x4A,0x23,0x11,0xE3,0x2A,0x54,0x99,0xD9,0x51,0xB1,0x75,0x2A,0x21,0xC4,0x8E,0x3D,0xE2,0xB5,0xCC, +0x4F,0x38,0xC8,0xFE,0x81,0x59,0x14,0x72,0x6B,0xD6,0x9C,0xAE,0xE9,0x16,0x67,0xBE,0xCA,0xC2,0x1E,0xCC, +0x1F,0xC5,0x8F,0x0F,0xD7,0x44,0xF9,0x6D,0xB8,0x47,0x8F,0xBB,0x4B,0x57,0x8F,0x9F,0x7E,0x55,0x0F,0x8B, +0x4C,0x80,0x0F,0xEC,0x1E,0x38,0xBC,0xDD,0xAD,0x94,0xC1,0xB8,0x5C,0x64,0xB2,0x59,0x8F,0xA3,0xF0,0xAC, +0x5E,0xBA,0x44,0xDA,0xBA,0x73,0xCE,0x05,0xCD,0x29,0xE0,0xA4,0x01,0x3B,0xC7,0x2D,0xB3,0xB0,0x57,0x09, +0xE3,0xD0,0x2A,0x6D,0xDE,0x42,0x1E,0xF5,0xEB,0x6B,0x99,0xC9,0x5F,0x3D,0xD7,0x98,0x4D,0x5D,0xFD,0xD0, +0xB7,0x23,0x57,0x20,0x5C,0xDD,0x94,0xF8,0x1E,0x00,0x86,0xDC,0x4E,0xB3,0x84,0x7B,0xBF,0xE9,0x29,0x7A, +0x91,0x3C,0xFD,0xEE,0x16,0xA0,0x6D,0xCA,0x46,0xE0,0x91,0x42,0xAF,0x21,0xA1,0x5F,0xFC,0x7D,0xA5,0x6F, +0x88,0x7D,0xA7,0x72,0xE0,0x5A,0xE7,0x13,0xF0,0xBE,0x3E,0x4A,0x15,0xDF,0xE0,0x4F,0x61,0x3E,0x85,0x5F, +0x41,0x4F,0xA9,0xDF,0x7C,0x6F,0x61,0x73,0x7E,0x0D,0x32,0x5B,0x0C,0xDE,0x4F,0x57,0x36,0x53,0x2D,0x57, +0x2E,0x2E,0xBF,0x33,0x6F,0xF0,0x98,0xA9,0x1A,0xA9,0x6C,0xE4,0x06,0x4E,0x40,0x9A,0xAF,0xC5,0xD6,0xA1, +0xA0,0x45,0xD7,0x28,0x5B,0xDC,0x62,0xF2,0x86,0x3B,0x23,0x84,0x51,0x94,0x39,0x73,0xA6,0xAB,0xBE,0xB8, +0x9A,0x64,0x51,0x61,0xC2,0x46,0xE9,0x9A,0x27,0x05,0x7B,0x6F,0x20,0x46,0xE5,0xD3,0x11,0xEB,0x21,0x56, +0x60,0xE3,0xA7,0x73,0xB0,0x10,0x3A,0xF6,0x8B,0x05,0x2F,0xCE,0xB9,0xD7,0xAA,0xC7,0xDD,0x95,0x6F,0x24, +0xFD,0x57,0xA6,0x9C,0x41,0x65,0xB2,0xE7,0x9A,0x24,0x72,0x5A,0xB6,0x47,0x22,0x73,0xEA,0x28,0x7C,0xCB, +0x29,0x95,0xEB,0x6F,0x6F,0x24,0xBA,0x5B,0x73,0x55,0x92,0x4B,0x6F,0x7A,0x03,0x1C,0xF6,0x2B,0xF0,0x5A, +0x9F,0x8B,0x23,0xC7,0x46,0x09,0x4F,0xC3,0xBA,0x69,0x22,0x06,0x98,0x01,0xAD,0xC8,0x47,0xE9,0x48,0x15, +0xA3,0xB5,0x01,0x9F,0xD6,0x61,0xFE,0x3A,0xBC,0x68,0xB5,0xDE,0xDE,0x93,0x04,0x6B,0x6E,0x46,0x36,0xE7, +0xAA,0xE4,0x3A,0x6E,0x2B,0x31,0x9A,0x44,0x9C,0x8E,0xBF,0xFA,0xA3,0x44,0x43,0x93,0x76,0x63,0x73,0xB6, +0xAF,0x61,0x0B,0x00,0x3D,0x4A,0x65,0x99,0x44,0xE9,0xFB,0x97,0x2E,0xE6,0x3A,0x3C,0xC2,0x45,0x1A,0x75, +0x93,0x50,0x49,0x11,0xCD,0x3C,0xCD,0xD0,0xD5,0xEF,0x49,0xEE,0x40,0x46,0xEB,0xE6,0xF3,0x31,0x7E,0xB0, +0x60,0x31,0x7B,0x44,0xF1,0x6E,0x07,0x9E,0xDA,0x16,0xA7,0x7E,0x3F,0xCF,0xD1,0x66,0x3A,0xDF,0x94,0xC3, +0x0B,0x1E,0x15,0x88,0x54,0x9A,0x85,0x90,0x4D,0x80,0xAA,0x08,0xC5,0xA8,0xA6,0xC5,0x71,0x65,0xBB,0x87, +0x11,0x31,0x70,0x40,0x7A,0x55,0xAB,0x92,0xDD,0xEF,0xEE,0x0F,0xC1,0x35,0x15,0xDA,0xC6,0x93,0x34,0xAA, +0x51,0x15,0x62,0x84,0x21,0xAA,0xEB,0x81,0x00,0x75,0xFD,0x5E,0x86,0x7A,0xFF,0xF8,0x81,0x10,0xAA,0x65, +0x9B,0x8F,0x62,0x98,0x85,0x76,0x4B,0x59,0x46,0x91,0x8C,0x33,0x31,0xFB,0x63,0x80,0x6E,0xA1,0x1D,0xF0, +0x73,0x8A,0xB3,0xE8,0x38,0xC5,0x16,0x71,0xC7,0x79,0xE9,0x8C,0x17,0xA7,0x06,0x2E,0xED,0x6E,0xFD,0xB6, +0x69,0xAD,0x71,0xB8,0xB4,0xB4,0xE5,0xB0,0xCC,0xA6,0xE1,0x9B,0xD8,0xA6,0x1D,0x26,0x89,0x7A,0x58,0x72, +0x9C,0xC1,0x87,0x41,0x82,0x17,0xAF,0x57,0x54,0x77,0x58,0x9B,0xA5,0xE0,0x68,0x62,0x58,0xBD,0x25,0x43, +0x12,0x20,0x2B,0xDF,0xDD,0x60,0x46,0xEC,0xCB,0x07,0x2B,0xAE,0xFB,0x23,0x1E,0xF0,0xA2,0xF5,0xC0,0x0C, +0x85,0xE1,0xDE,0x5A,0xBE,0x0B,0x35,0xFB,0x9A,0xB1,0x5A,0xC7,0x06,0x1F,0x49,0x03,0xCE,0xAE,0xA4,0x2F, +0xBA,0x51,0x8D,0x2F,0x2B,0x27,0xC8,0x9B,0x55,0xE5,0x04,0xC9,0x49,0x03,0x8F,0xCD,0x99,0x19,0x85,0xC0, +0xAA,0xC0,0x40,0x85,0x23,0xF6,0x24,0x96,0x81,0xC0,0xB0,0xFF,0x04,0xC1,0xCD,0x46,0x76,0x2D,0x36,0xE9, +0x45,0xE3,0x27,0xD5,0xD0,0x6B,0xCC,0xE1,0x73,0x3C,0x5F,0x17,0x19,0x5A,0x20,0x26,0xAC,0x12,0x28,0xB9, +0xAA,0x3C,0x9E,0x81,0xF2,0x4D,0x5E,0x83,0xC8,0x70,0x0F,0x9F,0xA5,0x95,0x04,0x9B,0x3F,0x86,0xCD,0xED, +0x6C,0x50,0x56,0x33,0x7C,0x70,0x23,0x1C,0xE6,0x82,0x58,0xDA,0xA5,0xB8,0xDF,0xD9,0x65,0x80,0x20,0x1B, +0xF2,0xE6,0xEC,0xA2,0x43,0x86,0xD0,0xEC,0x72,0xE2,0xC4,0xBA,0xCB,0x48,0xB1,0x49,0xB0,0x78,0x5C,0x8C, +0xEB,0xC8,0x4C,0x14,0xAC,0x80,0x18,0x3F,0x14,0xC7,0xE7,0x62,0x77,0x57,0xFE,0x31,0xC0,0x3E,0x5B,0x04, +0x77,0x79,0x0B,0x52,0xA3,0x26,0xBB,0x56,0x85,0xE8,0x86,0xF7,0xE2,0xAA,0xC1,0x89,0x7B,0xEA,0x38,0xA4, +0x2D,0xAA,0xB8,0x20,0x3D,0x08,0xED,0x2B,0x4A,0x38,0xB6,0xD0,0xA5,0xDE,0x32,0x17,0xE4,0x5A,0x6F,0xF7, +0x79,0xC4,0xE5,0xC5,0x69,0x64,0x80,0xD5,0xEE,0xA8,0x1D,0xB7,0xED,0xFF,0x9D,0xB3,0x7E,0xDD,0xF0,0x94, +0xC4,0xAA,0xCC,0x55,0x4E,0x75,0x31,0xB4,0xAC,0x2B,0x07,0x9A,0x62,0x06,0xA1,0x7C,0xC3,0x74,0xE2,0x25, +0x38,0x14,0x5A,0x7A,0xFC,0x23,0x22,0x13,0xB2,0xB7,0x4C,0x17,0x27,0x65,0x0D,0x4A,0x58,0x2C,0x14,0x5D, +0x2B,0x70,0x8A,0x08,0xB6,0xEF,0x62,0x66,0xA4,0x34,0xC2,0x80,0xF3,0xE0,0xC3,0x39,0xEC,0xDB,0xE6,0xCB, +0xD6,0x11,0x2B,0x46,0x27,0x47,0xA2,0xED,0x1B,0x90,0xAF,0xDE,0xCC,0x7C,0x64,0xF9,0x99,0x57,0x45,0x0E, +0x2C,0x4F,0x06,0x31,0x2A,0xB3,0xDB,0xA6,0xCD,0x23,0xA4,0x78,0x07,0x19,0x32,0x4C,0xDF,0xCF,0xAE,0xC0, +0x83,0xE0,0x52,0x2E,0x16,0x50,0xB6,0x94,0xDE,0xBE,0x14,0xD0,0x9C,0xDD,0x22,0xD0,0xAB,0x0E,0x45,0x3F, +0x43,0xF4,0x09,0xE1,0x6A,0x6F,0xF5,0xB3,0x76,0x4F,0x0D,0x58,0x79,0xE9,0x95,0x6D,0xB5,0xDE,0xEC,0xF1, +0xD4,0xB7,0x05,0xCD,0x64,0xDE,0xFC,0xD1,0x23,0x2C,0xCD,0x58,0x02,0xE8,0x84,0x90,0xA9,0x69,0xEB,0xF3, +0x45,0xD0,0xCD,0x5E,0x85,0xB4,0xC5,0xF6,0x29,0x2A,0x40,0x44,0xC0,0x68,0xF9,0x01,0x44,0xAE,0xEA,0xDB, +0x9C,0xB1,0xDA,0x8C,0x33,0x4B,0x9D,0xE0,0x4B,0xB9,0x83,0x90,0xC3,0xDF,0x77,0x4F,0x95,0x69,0xC1,0x3B, +0x4B,0xDA,0x8F,0xD7,0xB6,0x77,0x82,0x81,0x1C,0x2C,0xA7,0x48,0x9D,0xA6,0xD9,0xF8,0xDF,0x27,0xC0,0x6C, +0x18,0xFA,0x89,0xE8,0xCD,0xC3,0x26,0x46,0xF6,0x35,0x57,0x1E,0x6D,0x8F,0x16,0x64,0x2D,0xF4,0x86,0x45, +0x8C,0x46,0x06,0x25,0x1E,0xFD,0xFA,0x9A,0x1B,0xA5,0x25,0xDF,0x8F,0xAC,0xA5,0xCD,0x1B,0xCA,0x48,0x54, +0xCF,0x13,0x15,0x76,0xA9,0xC4,0xD0,0x97,0x18,0x64,0x40,0x56,0xE9,0x84,0x2F,0x57,0xF7,0xB6,0x01,0x3A, +0xAE,0xDD,0xBF,0xD5,0x5D,0x43,0x89,0x6E,0x17,0x05,0x88,0xE9,0x5A,0xF1,0xEC,0x1A,0x2F,0x9D,0x85,0xBC, +0x0C,0x09,0x40,0x9F,0xE2,0x2B,0x4A,0x9C,0xC8,0x98,0x07,0x9D,0x75,0xDC,0x1F,0xEB,0x3C,0x72,0x49,0x9E, +0xAC,0x21,0x8E,0xC8,0x5F,0xC1,0x6F,0xDB,0x2D,0x53,0x17,0xB9,0xFF,0xF0,0x37,0xE3,0x27,0xB6,0xC7,0x10, +0x4E,0xBE,0x59,0x06,0xA5,0xDF,0x13,0x80,0x58,0x41,0x18,0x25,0x3F,0x9F,0x30,0x1A,0xDC,0xB4,0xB0,0x8B, +0x62,0x05,0x8C,0x53,0x90,0x2F,0x22,0xC3,0x75,0xEE,0xFF,0xC5,0x83,0x21,0x7E,0x46,0xB3,0xE9,0x11,0xC2, +0x92,0xD7,0x81,0xAD,0x40,0xFF,0x72,0x3A,0x0E,0xCD,0x77,0xF3,0x93,0x4E,0x2A,0xB8,0x4D,0xB0,0x8C,0xC2, +0xBD,0xEC,0x3A,0x03,0x0D,0x86,0x28,0x82,0x84,0xF1,0x50,0x03,0x36,0x66,0x28,0xD0,0xFE,0xEB,0xAE,0xCC, +0xB9,0x57,0x13,0x36,0xE8,0x26,0x8A,0xA7,0x35,0x88,0x60,0x9F,0xCE,0xB8,0xFC,0x74,0x53,0x65,0xD1,0x07, +0xD8,0x1D,0x4A,0x20,0x7B,0xCF,0xF5,0x03,0x75,0x23,0x88,0xEF,0xD4,0xA6,0x13,0xAE,0x24,0xAA,0x53,0xC5, +0x78,0x44,0xBC,0x82,0xA9,0x9A,0xD9,0x07,0x38,0x44,0x18,0x0A,0xC2,0x07,0xA5,0x0A,0xC8,0x4C,0x81,0xDB, +0x30,0xE7,0xEC,0x1F,0x33,0xED,0x9A,0x38,0x69,0x5B,0x6C,0xED,0xD3,0x39,0xF6,0xB7,0x4A,0xBA,0xB9,0x33, +0x81,0xC2,0x4B,0x0C,0xF7,0xF5,0xB9,0xFE,0x5E,0x85,0x00,0x07,0xA4,0x17,0x13,0x6B,0x4A,0x3E,0xB0,0xE6, +0x04,0x10,0xF5,0x8F,0x4D,0xFD,0xDB,0x40,0xDF,0x16,0x3E,0x38,0x5E,0x7D,0x16,0x0F,0xC0,0xC5,0xFC,0x39, +0x71,0x23,0xB3,0x9B,0x28,0x4F,0xEC,0xCD,0xD7,0xCA,0x34,0xFC,0xE0,0x6E,0xF4,0xBE,0x2D,0xB2,0x3C,0xC9, +0xA0,0xEE,0xBB,0xF8,0x02,0x99,0x4B,0x48,0xAE,0x83,0x43,0x7F,0xA6,0x91,0xED,0x64,0x47,0xC3,0x03,0xAD, +0xCD,0x75,0x15,0xED,0x7B,0xA4,0xF5,0xF8,0x53,0xC6,0x61,0xEA,0xA9,0xE0,0xE2,0x3F,0x7A,0x52,0x8B,0x9F, +0x4C,0x0B,0xD4,0x1A,0xCB,0x94,0x34,0xD2,0x93,0xEF,0x77,0xBB,0xAE,0xDB,0x08,0x69,0x79,0x53,0x6A,0xE6, +0xDA,0x97,0x8B,0xC3,0x15,0x82,0x1C,0xAA,0x95,0x85,0x23,0xE7,0x5F,0x69,0x50,0x13,0x78,0xA1,0x2B,0x9C, +0x9C,0xFD,0xF2,0xA1,0x9B,0xE4,0xC6,0xCC,0x3C,0xEE,0xD3,0x07,0xB5,0xC6,0x63,0x8D,0x18,0xF0,0x2B,0x44, +0x19,0x33,0x7B,0xF0,0x26,0xEB,0xE2,0x61,0x18,0x99,0xAB,0xA7,0x8B,0x37,0x8F,0x56,0x74,0x5E,0x5A,0xB2, +0xDC,0xC8,0x1A,0xE4,0x37,0x8A,0x14,0xF4,0xE4,0xE7,0xB4,0x96,0xC4,0x7B,0x7F,0x64,0x55,0xEB,0x91,0xA5, +0x80,0x9B,0xB2,0x92,0xC4,0x80,0xD3,0x27,0x53,0x09,0x99,0x2F,0x4A,0xF4,0xF7,0x64,0xD5,0xA8,0xF1,0x8A, +0x29,0x34,0xE5,0x1E,0x70,0x7A,0xAB,0xCF,0x95,0xBE,0x26,0xB2,0xB4,0xEC,0x01,0x5B,0x10,0xC5,0xC8,0x9E, +0x7C,0x34,0x06,0x9D,0x56,0xC6,0xE9,0x98,0x52,0xAF,0x9F,0xBA,0x9B,0xAC,0xB9,0x4D,0xE5,0xBB,0x91,0x4E, +0x6A,0x7A,0x64,0x92,0x66,0x91,0x41,0x91,0x03,0xCB,0xF6,0xA3,0x28,0x0E,0x9F,0xEB,0x1E,0x46,0x0F,0x83, +0x5D,0xCF,0x88,0x87,0x9D,0xEE,0x77,0x37,0xDB,0xAD,0xD1,0x3B,0xAE,0xB1,0x98,0x88,0x3A,0x98,0x28,0x59, +0x9B,0xFA,0xAF,0x83,0x06,0x83,0x76,0x26,0x87,0x10,0x7F,0x6C,0xC7,0xDE,0x3A,0x8E,0x94,0x33,0x89,0x07, +0xCA,0xEE,0x95,0x75,0x41,0x7A,0x17,0x88,0x06,0x9D,0x87,0x1A,0x88,0x45,0x6E,0x51,0x0D,0x43,0xB0,0xCA, +0xC5,0x5B,0x7C,0x69,0xBD,0xC6,0x61,0x48,0x35,0xD4,0xA4,0x15,0x69,0x3D,0xBC,0x64,0xDA,0x92,0x07,0x99, +0xFF,0x16,0xF0,0x36,0xD2,0xCD,0xE0,0xB8,0xAF,0x44,0xAC,0xEF,0xF2,0xC0,0x08,0x28,0x99,0x75,0x46,0x1B, +0x2D,0xB0,0x6F,0x25,0xAF,0x32,0x99,0x91,0x84,0x8A,0xFF,0x9D,0x90,0x57,0x4F,0x0B,0x68,0xCF,0x46,0x67, +0x1C,0x35,0x70,0x00,0x20,0x03,0x1B,0x08,0x79,0x08,0x47,0x1E,0x2C,0xD2,0x9F,0x8D,0xAF,0x47,0xB6,0xC2, +0x7D,0x86,0x98,0x74,0xDE,0xAB,0x22,0x11,0x2C,0x65,0xD8,0x04,0xE3,0xE8,0xA8,0xBF,0x6E,0x30,0x55,0x09, +0xC2,0xF8,0x2A,0xC3,0x61,0x6A,0xC6,0xDF,0x3F,0xE8,0x3A,0x6C,0x7A,0xA5,0x69,0xB4,0x9B,0x5A,0xA5,0x90, +0xE8,0x6B,0xC9,0x08,0x57,0xEB,0x3D,0x6C,0xE9,0x52,0x42,0xBA,0x95,0xFC,0xA9,0x6A,0x47,0x03,0x06,0x04, +0xE5,0x84,0x7C,0xE8,0x1C,0x0D,0x94,0x0A,0x77,0x2D,0x64,0x06,0xA7,0x99,0x67,0xB8,0x94,0x7B,0x92,0xE5, +0x32,0x76,0x89,0x11,0xC5,0x02,0xE1,0x3A,0xBD,0xD8,0xE4,0xAC,0x59,0x1C,0xDC,0x2F,0xBF,0x2E,0x23,0x49, +0x0E,0xFE,0x8A,0x3B,0x77,0x35,0x55,0x5D,0x37,0x4C,0x11,0xE0,0x8B,0x51,0x0E,0x9E,0x1A,0xBD,0x0C,0x12, +0xCB,0xAB,0x1B,0x01,0x51,0x3F,0xB0,0xCE,0x61,0x0C,0x57,0xCA,0x63,0x72,0x4C,0xCB,0x48,0x14,0x09,0x11, +0x3E,0xEE,0x78,0xA4,0xF0,0x30,0xBC,0xDE,0x74,0x6E,0x42,0x81,0xBE,0xA1,0x01,0x0D,0x71,0x92,0x59,0xB0, +0x67,0x67,0xBD,0xFF,0x22,0x05,0xE4,0x09,0x3D,0xAB,0x0C,0x11,0xBC,0x9B,0xC7,0xC4,0x8C,0x84,0x5E,0xAE, +0xF1,0xAD,0xBF,0x85,0x36,0xAD,0x22,0x7F,0xA4,0xF2,0x88,0x11,0x48,0x9A,0x12,0x77,0xDC,0xF0,0x23,0x98, +0x14,0xCB,0xCB,0xD5,0x75,0x51,0xEC,0xEB,0x45,0x99,0xCD,0x98,0xE5,0xC5,0x9B,0x8F,0xB1,0x00,0x6B,0x07, +0x83,0x5E,0xA6,0x07,0xDD,0xC0,0xFB,0xB5,0xB0,0xFE,0xB1,0x27,0xAC,0x6D,0x42,0x54,0xF5,0x5F,0xA9,0x6E, +0x52,0xD2,0x8A,0x66,0x29,0x51,0x1A,0x8A,0x35,0x42,0x6A,0xC4,0x83,0x50,0x42,0x76,0xAA,0x3F,0x0F,0xB5, +0x10,0xF6,0x54,0x08,0x0F,0x57,0x76,0xB6,0x9F,0x97,0xEE,0x5C,0x86,0xCA,0x92,0x67,0xC2,0x16,0x3B,0x52, +0x3D,0x77,0xC6,0x47,0x45,0x5A,0x1D,0xC7,0x5F,0xD4,0x6E,0xCE,0xDE,0x15,0x14,0xA3,0xE2,0x98,0xE3,0x4E, +0x1D,0xC5,0xD9,0xB1,0x18,0xFB,0xBF,0x24,0xD5,0xF5,0x6D,0x66,0xE5,0xCC,0xAC,0xE6,0xDD,0xF3,0xA7,0x88, +0xDD,0xC3,0x4E,0x04,0x1E,0x6E,0x85,0x86,0x90,0xA9,0xC1,0x5D,0x0A,0x55,0x26,0x86,0x2B,0x20,0xD0,0x09, +0x56,0x1F,0x85,0xF4,0x8C,0xE6,0xE9,0x81,0x7C,0x2C,0x20,0xE5,0x23,0xEC,0xD8,0xFD,0x57,0x7C,0x9A,0xD4, +0x71,0x86,0xE0,0x1E,0x0E,0x55,0xEE,0x1F,0xD4,0x1A,0xAE,0x6C,0x7F,0x4E,0x46,0x84,0x91,0x0E,0x68,0x84, +0x8B,0x64,0xD9,0x45,0xD1,0x41,0x6D,0xDB,0x56,0x5F,0x14,0x6E,0x37,0xC7,0x11,0xCA,0xA2,0xCD,0xEE,0xA1, +0xCF,0x1C,0x3C,0x2D,0x59,0x1F,0x92,0x7E,0x27,0xE3,0xA4,0x5C,0x03,0xBF,0x86,0x35,0xC5,0x91,0x99,0x7A, +0x4B,0x1D,0x76,0x6F,0xB7,0x2A,0xD0,0xC3,0x62,0x8F,0x2F,0x28,0x2B,0x32,0xBB,0xDD,0x7E,0x32,0x77,0xFA, +0xCB,0xB1,0x61,0xE3,0x5E,0x50,0x54,0xE8,0x0E,0x4D,0xF8,0x66,0x51,0x00,0xAD,0xC2,0xAB,0x43,0x56,0x34, +0xF3,0x66,0xEF,0xE3,0x79,0xAA,0xB2,0xF6,0x93,0x29,0x48,0xCF,0x47,0xA8,0x9C,0xD6,0xD3,0x29,0xFE,0x46, +0x69,0x21,0xF9,0x87,0x91,0xE0,0xAA,0x41,0xCC,0xE9,0x19,0x26,0x71,0xEA,0x9A,0x0C,0xB2,0xF8,0xFB,0x6B, +0x32,0x46,0xC9,0x53,0x3E,0xEE,0xB9,0x57,0x90,0x67,0x1A,0x45,0xA1,0x02,0x48,0x88,0xB1,0x22,0x1A,0xBF, +0xE1,0x42,0x64,0x1B,0xF1,0x62,0x4C,0xB2,0x81,0x06,0xB0,0x73,0x70,0xDA,0xA5,0x92,0xE2,0xCD,0xA0,0x06, +0xA8,0x9A,0xC9,0x9C,0x23,0x8E,0x49,0x25,0xF1,0xDD,0x87,0xC4,0x63,0xCC,0xD9,0xD2,0xB1,0x46,0xFC,0x33, +0xC2,0x0F,0xB1,0xD7,0x96,0x4D,0x5D,0x93,0x62,0xCF,0x19,0x81,0xF2,0x2B,0xB8,0x98,0x61,0x39,0x3D,0xEE, +0x9A,0x00,0x42,0xEF,0x96,0x40,0xEA,0xAE,0x5D,0xA2,0xB0,0xEB,0x7D,0x65,0xF2,0x6E,0x1F,0x12,0x24,0x98, +0xEA,0xE4,0x12,0xF0,0xFA,0x6F,0x5B,0x18,0xBB,0x21,0x23,0x6F,0xD9,0x6A,0x91,0xAD,0xA5,0x09,0xC9,0x28, +0x7B,0x6C,0x52,0xE0,0x6C,0xFD,0xF6,0x9F,0x9C,0x72,0x0C,0x59,0xDB,0x27,0x13,0x5D,0xBA,0x90,0x3A,0xCA, +0x28,0xAC,0xFA,0x1C,0x12,0x23,0xD2,0x8A,0x35,0x13,0x92,0x48,0xB3,0x5C,0xFE,0xA8,0x57,0x02,0xC0,0xDC, +0xB8,0x2B,0x8C,0x48,0xAA,0x42,0x2E,0xF8,0x20,0x75,0x7B,0x19,0x9A,0x01,0xA3,0x0C,0x16,0x23,0x93,0x90, +0x9D,0x48,0x8B,0x68,0xDC,0xB5,0x2B,0xF9,0x97,0x02,0xC3,0xD8,0x3A,0xA7,0xEF,0x89,0x34,0x40,0x73,0x79, +0xFF,0xE2,0x3C,0x7E,0x8C,0x1D,0x44,0xE6,0x73,0x8F,0x2C,0x5F,0x89,0x13,0xEC,0x26,0x79,0x96,0x55,0x1D, +0x84,0xEE,0xF4,0x16,0x34,0xB0,0xDC,0xC5,0x05,0xFC,0x09,0x24,0xD2,0x30,0xF8,0xCF,0x55,0x4E,0xFD,0xE7, +0xF1,0xB2,0xF9,0x3E,0xE1,0x92,0x97,0x47,0x72,0x3A,0x33,0xA8,0x2C,0xE5,0xD7,0x94,0x12,0x35,0xCD,0x53, +0x51,0x22,0xFD,0xF5,0xFF,0x7E,0x1E,0xED,0x81,0x12,0x4F,0x46,0x33,0x38,0x4C,0xE4,0xCB,0x82,0xF9,0x17, +0xFE,0x79,0xE2,0x80,0x33,0x1A,0x33,0x56,0x32,0xB2,0xF3,0x12,0xC2,0xD2,0xBB,0x9A,0xA1,0x7F,0x5D,0xFC, +0x03,0x9C,0xFD,0x3B,0x1E,0x3B,0x05,0xF8,0xE8,0x50,0x2C,0xC2,0x53,0x1A,0x75,0x01,0x10,0x18,0xF5,0x2F, +0x1F,0x3A,0xD9,0xF4,0x6C,0x53,0x4C,0x8B,0x9B,0x7A,0x0E,0x85,0x08,0xC8,0x8E,0xEB,0x9B,0x3E,0xAC,0x57, +0x81,0x1B,0xDC,0x57,0xDB,0x75,0x9B,0x77,0xC8,0x4A,0x86,0x3B,0xD8,0x36,0xC1,0x47,0x4D,0x9C,0xCE,0x93, +0xD8,0xF1,0x06,0x61,0xFE,0x57,0x8F,0xAA,0x1B,0x3C,0xFB,0x36,0xE9,0x3A,0xDD,0x42,0x5B,0x7C,0xF6,0xA6, +0x83,0xBB,0xEF,0xDD,0x56,0x36,0xCF,0x86,0x95,0x1A,0x9D,0x5F,0x58,0xF1,0x26,0x7D,0x04,0x11,0x6A,0x53, +0xC1,0xA1,0x52,0xAF,0x6B,0x1C,0xC4,0x6E,0x91,0x38,0xC6,0xB8,0xCA,0x12,0xAC,0xD4,0xCA,0xBB,0x07,0x04, +0x8E,0x56,0x7A,0x9E,0x88,0x18,0x0D,0x16,0x09,0x18,0x24,0x37,0x35,0x83,0x6B,0x77,0x6F,0xEE,0xED,0x5D, +0x6B,0xD1,0xFB,0x3B,0x29,0x57,0xCF,0x9D,0x8F,0x39,0xDF,0x9A,0x6D,0x5C,0xE7,0x06,0x06,0xDE,0xDF,0xEA, +0x56,0xCD,0xFA,0x07,0xB7,0xA6,0x56,0x87,0x47,0xA2,0xC8,0x01,0x37,0x1F,0x6A,0xE1,0x2B,0x2A,0x28,0xF4, +0xB4,0x29,0xC2,0x4C,0xAE,0xC2,0x80,0xE6,0xAB,0xEE,0xDA,0x44,0x79,0x54,0xA9,0x82,0x35,0x2A,0x86,0x1A, +0xC2,0xD9,0xC9,0xA5,0xF6,0x97,0xF9,0xEC,0xEE,0x72,0xAB,0xF5,0x17,0xAB,0x95,0xA0,0xE3,0xC9,0xD9,0x73, +0xDA,0xEE,0x2A,0xA0,0xA5,0x82,0x60,0xA4,0xB7,0x2C,0xC4,0x92,0x0A,0xCB,0x0B,0x18,0xDB,0x12,0x10,0xD0, +0x02,0xEF,0xF8,0xB4,0xB6,0x2D,0x18,0xD2,0x63,0x48,0xC0,0x46,0xD5,0x4A,0x31,0xC2,0xE5,0x34,0xE3,0xA5, +0x37,0x2E,0xC5,0x93,0x39,0xC9,0xB9,0xB7,0x23,0x47,0x51,0x83,0x70,0x88,0xE1,0xB5,0x15,0xEF,0x01,0xF1, +0xC6,0xDF,0x59,0x05,0xB5,0xDB,0xDD,0x78,0xE7,0x19,0x62,0x6C,0x5D,0x88,0xB0,0x39,0x6E,0x8B,0xB8,0x2A, +0xFF,0xE5,0xB9,0x5A,0x09,0xAD,0xBA,0xFC,0xBC,0x21,0x29,0x2B,0x35,0xED,0x32,0x57,0x3E,0xC9,0x1D,0x33, +0x01,0x2C,0xDB,0x28,0x3D,0x22,0x15,0x12,0xB0,0x6A,0xB9,0x2E,0x7F,0xEC,0x5C,0x9F,0xE8,0xB4,0xA3,0xFD, +0x1F,0xA3,0x69,0xBF,0xA0,0x0A,0xC3,0xBD,0xD8,0x72,0x5A,0x9A,0xF5,0x83,0xC6,0x2C,0x5F,0x8C,0x70,0x88, +0x48,0x17,0x8C,0x69,0xFF,0x73,0x12,0xD8,0x0A,0xD7,0xD2,0x0E,0x9F,0xA2,0x6A,0x7E,0x4B,0xE0,0xEC,0x1C, +0x3F,0xEB,0x03,0x0F,0xC9,0x03,0x9B,0xCD,0x9B,0xAA,0x0F,0x6F,0xB5,0xCD,0x47,0x0D,0x25,0x13,0x13,0xD9, +0x8A,0x64,0x03,0x7E,0xBF,0xAE,0x98,0x93,0x95,0x82,0x85,0x79,0x3E,0x6C,0x70,0x06,0x1B,0xC5,0xAE,0x87, +0x97,0xB6,0x54,0xE6,0xA8,0x5D,0x49,0x44,0xF6,0xF3,0x55,0x68,0xDE,0x4E,0x2B,0xC6,0x14,0xBE,0x44,0x30, +0x6C,0x11,0xDC,0x16,0xC1,0xFC,0x82,0x23,0x45,0xAD,0xAD,0x31,0x15,0x38,0x4D,0x21,0xE1,0xA1,0xF5,0x57, +0xA8,0xFD,0xED,0x83,0x37,0x88,0xCD,0xD7,0x13,0xBE,0x67,0xB7,0x46,0xD5,0xF7,0x55,0xB4,0x13,0xAF,0xD2, +0x85,0xF1,0xEC,0x71,0xD7,0xBB,0x71,0x67,0x44,0xD4,0xCC,0xD6,0xF4,0x5B,0x0C,0x96,0x10,0x1E,0x97,0xF1, +0x96,0x43,0xBC,0x94,0xE5,0xD6,0x82,0xF1,0xD6,0xAA,0x5D,0x93,0xA2,0x99,0x85,0x87,0x54,0xBB,0x35,0x25, +0xF2,0xCD,0x55,0x95,0x94,0xEA,0x69,0x31,0x25,0xDF,0x12,0xAD,0x61,0x68,0x78,0x11,0xD4,0x55,0x49,0x95, +0x78,0x41,0xA0,0x0E,0x64,0xC5,0xEC,0x93,0x7D,0xBA,0x3A,0xBA,0x2C,0xD7,0xCE,0x2C,0x5E,0x5A,0x91,0xD5, +0x2B,0x50,0xF4,0x83,0x9E,0xDC,0x38,0x58,0xEF,0xF1,0xEE,0x3B,0x1E,0x19,0x8E,0xF5,0x39,0xE6,0xDF,0x0D, +0xBD,0xBD,0x57,0xEA,0x11,0x51,0xED,0xAE,0x5F,0xFC,0x52,0xF5,0x0E,0xFE,0x95,0x7D,0x3F,0xB3,0x84,0xD9, +0xAC,0x9B,0xC7,0x3D,0xDF,0x6B,0x3B,0x28,0xAC,0xD4,0x59,0x26,0x3A,0x60,0xCE,0x68,0x4C,0x2C,0x4F,0x74, +0x7D,0x9C,0xE6,0x26,0x6F,0x92,0x87,0x35,0xC0,0xBB,0xFE,0x78,0x6A,0x17,0xDE,0xC9,0x00,0xFD,0xB8,0xB9, +0x0D,0x98,0x4B,0x4A,0x6B,0xDC,0x0F,0x2D,0xE6,0x92,0x28,0xEE,0xDA,0x2E,0x0F,0x9F,0x2F,0x92,0xE7,0x6D, +0x4A,0xB0,0x25,0xFE,0x4C,0xD9,0x6F,0xFF,0xFF,0xFF,0xA8,0x81,0x85,0x82,0x46,0x62,0xEF,0xFB,0x1F,0x4C, +0x41,0x00,0x50,0x5D,0x53,0xCD,0xC8,0x79,0xE7,0x43,0x88,0x90,0x1D,0x25,0xA2,0x77,0x83,0x01,0x9A,0xE3, +0x71,0xE0,0xA9,0x84,0x05,0x30,0x81,0x67,0x6B,0xB9,0x31,0x81,0xF3,0x66,0x06,0xC7,0x8C,0x95,0x12,0x42, +0x87,0x99,0xE9,0x17,0x9E,0x2E,0x51,0x09,0xA6,0x03,0x9B,0x47,0xE2,0x07,0xC1,0x70,0xF1,0x46,0x94,0x03, +0xFB,0x67,0x84,0x62,0xF3,0x05,0xF4,0x6C,0x9A,0xE7,0xFF,0xF4,0xF7,0x26,0xAE,0x6D,0x10,0xE5,0x67,0x10, +0x17,0x5E,0x6C,0x16,0xAC,0xEE,0x9B,0x1D,0x3F,0x09,0xA7,0x79,0x7B,0x05,0xF2,0x4C,0x1E,0xD7,0x71,0x76, +0xFC,0x02,0x7E,0xF1,0x73,0xF6,0xEF,0x6C,0xB9,0x83,0x14,0x17,0x28,0xE4,0x4F,0x44,0xAF,0xC8,0xC7,0xE0, +0xB8,0x45,0xFD,0x88,0x14,0x6E,0x32,0x00,0x7B,0x7C,0x6A,0xBD,0x3D,0x9D,0x09,0xB8,0x43,0x39,0xEA,0x1E, +0xD7,0x24,0x91,0x54,0x4F,0xF1,0x04,0xC4,0x59,0x2B,0xAF,0x9B,0x84,0x00,0xDA,0x0B,0x65,0x65,0xA9,0xD6, +0x45,0x08,0x09,0xD1,0xD8,0xDF,0x1B,0x8C,0xCD,0x0A,0xC1,0x00,0xAA,0x4F,0x82,0xF9,0xD7,0x09,0x1F,0x3F, +0x24,0xCA,0x1B,0x49,0x0C,0xAC,0x51,0xE8,0x97,0x81,0x53,0x0E,0xA1,0x8F,0x72,0x1E,0x38,0xA0,0x1E,0x43, +0x29,0x99,0x1A,0x2F,0x31,0x8B,0x59,0x90,0x0C,0x00,0xFC,0xCC,0xDF,0xC9,0xFA,0x56,0xAC,0xDA,0x13,0xDE, +0xEE,0x81,0x33,0x6B,0xD5,0x4A,0xAD,0x6A,0x27,0x61,0xDC,0x48,0xA5,0x0B,0xDC,0xAE,0xB1,0x43,0x25,0xC8, +0xDB,0x02,0x0F,0x7A,0x77,0x0A,0x63,0x70,0xA0,0x0F,0xBC,0x54,0x6C,0xB0,0x30,0xD6,0x41,0x10,0xCE,0xA5, +0xD7,0x73,0x04,0x85,0x03,0x33,0xEC,0x96,0xAF,0x3C,0x63,0x41,0xC2,0x11,0xDD,0xCB,0x19,0x7C,0xBC,0xF1, +0x20,0x04,0xE5,0xCB,0x3A,0x3D,0xFD,0x24,0xE6,0xEA,0x12,0x68,0xF6,0xA9,0xCF,0x57,0xE3,0x17,0xA7,0x45, +0xED,0xB3,0x2F,0x5E,0x55,0x5C,0x8B,0xD7,0x91,0xA4,0xCC,0x44,0x45,0xF5,0xEC,0xA6,0xC6,0x57,0x50,0x99, +0x43,0x04,0x8D,0xE9,0xD7,0xAB,0x4A,0x54,0x44,0xB6,0x4F,0x16,0x92,0xCA,0x4F,0x54,0x50,0x8C,0x67,0xBA, +0x92,0x4A,0xE9,0x53,0xE8,0x1C,0x72,0x75,0xB4,0xD7,0x73,0xCC,0xC8,0xF2,0xD4,0x83,0x4D,0x2A,0x6D,0x55, +0x5E,0x7B,0xA5,0xB7,0x44,0x75,0x7D,0xF9,0x2B,0x26,0xA4,0x37,0x52,0x88,0xC6,0xF7,0xA5,0x7A,0xE6,0xC2, +0xBE,0x37,0xCD,0x07,0x17,0x5A,0xE8,0xAA,0x99,0xFB,0x54,0x9A,0x9A,0x40,0xC4,0x81,0x79,0x3F,0x04,0x44, +0xBC,0xA2,0x1C,0x24,0xA5,0x3A,0xF8,0x4E,0x15,0xEC,0xE7,0x8F,0x26,0x37,0x2D,0x52,0xEC,0x41,0x4D,0x5E, +0x74,0x38,0x6E,0xD9,0xAD,0x55,0x26,0x1A,0x1A,0xB6,0x39,0x54,0xF9,0xD6,0x3C,0x1C,0x21,0x78,0x24,0xE5, +0x29,0x1E,0xC0,0xE9,0x1E,0x3A,0x02,0xFB,0x1A,0x1F,0xBE,0x8E,0x8D,0x3E,0x14,0x1E,0x5F,0xB2,0xAE,0xDE, +0x56,0x30,0x8A,0xF0,0xCE,0xF2,0x0D,0x83,0xD8,0x3F,0xF4,0x78,0xE2,0xBD,0xE7,0xA5,0x1B,0xE1,0x0E,0x91, +0x4F,0xF1,0xD1,0xC8,0xFC,0x97,0xEF,0xAB,0xC9,0xB3,0xB0,0xA3,0x50,0x1C,0x0D,0xBE,0x02,0xDC,0x41,0x41, +0x7A,0x1B,0x22,0x07,0x02,0xA9,0x58,0x84,0x94,0x36,0xBB,0x8F,0x42,0x78,0x88,0xD9,0xA1,0x83,0x92,0x80, +0x0D,0x93,0x57,0xC6,0xB6,0xAA,0xB3,0x1A,0x44,0x11,0xC6,0x4A,0xA0,0x62,0x08,0xC4,0xB7,0x96,0x99,0x0F, +0x33,0xEF,0x2A,0xE3,0xCA,0x80,0x4A,0x58,0xB4,0xE0,0x93,0x81,0x85,0x89,0xAB,0x68,0xD4,0xAA,0xD1,0xB2, +0x42,0x21,0x4C,0xC4,0xAC,0xA2,0x4A,0x30,0xED,0x07,0xDE,0xF6,0xDC,0x75,0x0E,0xD6,0xC4,0xC0,0xC8,0x95, +0x74,0x9B,0xB7,0xE8,0x38,0x14,0x8E,0x6F,0xFC,0xC6,0xEE,0xD8,0x8F,0xCA,0x4B,0xD7,0xAB,0xA6,0x1F,0xF2, +0xF1,0x2A,0x9F,0xF7,0x7F,0xC5,0x3A,0x01,0x35,0x84,0xCB,0x89,0x6D,0xF9,0x36,0xAC,0x81,0x7C,0x5A,0xF6, +0x6B,0xE4,0x6E,0x80,0xB3,0x5A,0x82,0x8C,0xD1,0x67,0xA2,0x0B,0xBA,0x93,0x5A,0x8C,0x9C,0xFE,0x08,0xC2, +0xC4,0x07,0x88,0xC6,0x46,0xA7,0x73,0x2C,0xA8,0xD6,0xA8,0x9C,0x88,0xAF,0xE0,0x3B,0x4B,0x11,0x10,0x9D, +0xFC,0x85,0x06,0x7D,0x73,0x35,0x9B,0x5D,0xDF,0x5A,0x13,0x3B,0xFF,0xEE,0xE3,0x37,0x8C,0xEC,0x2A,0x7D, +0x32,0xE5,0xD3,0x9D,0x1D,0xFD,0x2A,0x7B,0x85,0xD0,0xD9,0xAE,0xDC,0x8B,0x6B,0xEA,0x5E,0x0F,0x22,0x7B, +0x4A,0x79,0xB2,0x5F,0xF4,0x68,0x93,0x1C,0x61,0xAC,0x2E,0x3C,0xF0,0x20,0x95,0xDA,0x5F,0xBB,0x1A,0x78, +0x16,0xC0,0xF8,0xF4,0xAA,0xE1,0x59,0xB8,0xA0,0x95,0xB5,0x70,0xF8,0x31,0x0B,0x56,0x25,0xCD,0x0A,0x84, +0x6D,0xAC,0xBF,0x1C,0x51,0x85,0x50,0x1D,0x3E,0x52,0xBF,0xFE,0xC1,0x45,0xC3,0x00,0x5E,0xE2,0x61,0x44, +0x2E,0xD2,0x5B,0xF9,0x47,0xB0,0x4B,0x26,0x1B,0xC8,0x97,0x9B,0x95,0x5F,0x3C,0x07,0x78,0x92,0xD1,0xEC, +0x57,0xB5,0x5C,0xB0,0x30,0xDC,0xDA,0xBA,0x76,0x52,0xAE,0xD6,0xA5,0x4A,0x78,0x86,0xD4,0xD4,0x9D,0x92, +0x61,0x53,0x61,0xD4,0xDA,0x9E,0xEF,0xA3,0x96,0xA7,0x54,0x13,0xB9,0xE0,0xF9,0x35,0x81,0xD2,0x83,0x13, +0xB6,0xD3,0x1A,0xC5,0xDB,0x9B,0xDB,0x35,0x10,0x1F,0x12,0x42,0x8D,0x57,0xDC,0xE0,0xD7,0x0B,0x56,0x21, +0x09,0x8E,0x4C,0x54,0xF2,0x54,0x02,0x57,0xEA,0x78,0x82,0xF0,0x96,0x76,0x63,0x66,0x26,0x6A,0x31,0xC5, +0xDD,0x35,0x4B,0x46,0x2C,0x27,0xAF,0x8C,0x9E,0x07,0x29,0xB5,0x58,0x3A,0xB7,0xD5,0x14,0xAC,0xAD,0x60, +0x85,0x7A,0xD3,0x04,0x7B,0xFA,0x9C,0x7B,0x8F,0xF8,0xD8,0xB3,0x7F,0x58,0xA4,0xAE,0x44,0x2D,0x49,0xD1, +0x3C,0x87,0xC2,0x72,0xC1,0xD4,0xD4,0xFE,0x39,0xF7,0x67,0xBC,0xCA,0xDF,0x7E,0x4A,0x28,0x84,0x15,0xCC, +0xA2,0x65,0xBF,0x9A,0x55,0x4B,0x57,0xA9,0x7E,0xD7,0xED,0x55,0x94,0x99,0xC8,0x6B,0x2D,0xD9,0xBD,0x6F, +0x7F,0x4A,0x1F,0x18,0x4C,0xD2,0xC7,0xCC,0xD3,0x5A,0xB2,0x8D,0xF0,0x96,0x22,0xA8,0xBC,0x10,0x22,0x79, +0x40,0xD4,0x0D,0xA9,0x83,0x2A,0xAE,0x2E,0x45,0x32,0xEA,0xAD,0x43,0xD1,0x81,0x09,0x49,0x70,0x86,0xEF, +0x03,0x76,0xE4,0x4F,0xC9,0x7F,0x5E,0x2D,0xD5,0x4F,0x74,0x98,0x8C,0x5F,0x9F,0xE9,0x7D,0x9A,0xCB,0xA4, +0x0C,0x3F,0x8D,0xCA,0xBE,0xFF,0xAB,0x4B,0x10,0x70,0x7B,0xCE,0x9D,0x50,0x52,0x72,0x6A,0x63,0xF8,0xFB, +0x34,0x62,0x40,0xDB,0x33,0x40,0x94,0x00,0xF1,0xBF,0x51,0xE9,0xE4,0x07,0xBC,0xF4,0x22,0x9A,0x4D,0xCD, +0xC0,0x9A,0xE3,0x3C,0xF4,0xDE,0x7F,0xA4,0xA9,0x39,0x17,0x37,0x91,0x62,0xCC,0x84,0xAB,0x4A,0x25,0x47, +0x2F,0x2F,0x27,0xF3,0x22,0x18,0x31,0xF5,0x95,0x27,0xEA,0xB5,0xA2,0xB8,0x59,0xCC,0xB2,0x0F,0x60,0xD3, +0xA1,0x0E,0x13,0xB2,0x9C,0xAD,0x84,0x93,0x6C,0xE9,0xC5,0x97,0xD6,0xE9,0xB7,0xB8,0x6C,0x48,0x7A,0xBC, +0x33,0x68,0x88,0x03,0x6D,0x90,0xE0,0x45,0xF2,0xE4,0x01,0xA9,0x06,0x4B,0xDE,0x25,0x96,0x0B,0x01,0xF2, +0xE4,0xE9,0x83,0x33,0x39,0x02,0xAE,0xD9,0x26,0x8E,0x36,0xD7,0x56,0x54,0x89,0x99,0xC7,0x9B,0xB9,0x86, +0x57,0xEA,0xDB,0x7E,0xF7,0x4A,0x41,0xE4,0x28,0x65,0xBE,0xC0,0xA4,0x05,0x29,0xBE,0x54,0x29,0xB5,0xEE, +0x2D,0x84,0xD3,0x98,0x42,0xAF,0xDA,0x61,0x78,0x43,0x22,0xC7,0x5F,0xD2,0xDE,0x27,0xBB,0xA1,0x78,0x05, +0x3D,0x31,0x75,0x99,0x21,0x29,0x6C,0x4B,0x2B,0x7A,0x75,0xB8,0x62,0x48,0xC3,0x04,0xAA,0x7A,0x9D,0x4A, +0xE7,0x04,0xC1,0x7A,0x2C,0xED,0x62,0xDB,0xA9,0x04,0xFA,0x31,0x39,0x0F,0xFE,0xED,0x9F,0x2E,0x80,0x26, +0xB1,0x08,0xB2,0xA7,0x8B,0xAC,0xD8,0xDE,0xF0,0x69,0xF9,0xC8,0x4D,0xF4,0xBA,0x36,0x38,0xD1,0xC5,0x3B, +0xB9,0x0E,0xFB,0xB2,0xF2,0x23,0x3A,0x82,0x21,0xED,0xEB,0x96,0x76,0x63,0x12,0x44,0x2E,0x04,0xF1,0xED, +0x0A,0x80,0x12,0xFD,0xB2,0xDC,0xA3,0x5A,0x22,0x60,0xB1,0x7D,0x91,0xCB,0x85,0xE2,0x03,0x6B,0xB7,0x15, +0xB8,0x93,0x2C,0x63,0xB2,0xF9,0x32,0xE5,0x41,0xCE,0x74,0xE6,0xDA,0xD0,0xAB,0xD9,0x67,0x89,0xFF,0x52, +0x42,0x55,0x77,0x05,0xDD,0xCC,0x2A,0x63,0xA0,0xCF,0x36,0x10,0x14,0x4B,0x9D,0x2C,0x55,0xF3,0x73,0x31, +0x40,0xBC,0xB3,0xA0,0x3C,0x28,0x81,0xC3,0x5A,0x4C,0xC7,0xB4,0x56,0x68,0xC4,0x44,0x1F,0x3E,0x6B,0x26, +0x9E,0xC9,0x45,0x64,0x1B,0xDD,0x6F,0x02,0x11,0x7F,0x49,0xC0,0xC2,0x0E,0xB1,0xE4,0x05,0x9A,0x15,0x0E, +0xDE,0xFA,0x63,0xC5,0xD2,0xD4,0x15,0xDD,0xEE,0x15,0xBD,0x2D,0x98,0x7B,0x5D,0x45,0xE4,0xEF,0xC2,0x0F, +0x13,0x39,0x4D,0x37,0x87,0x2B,0x6D,0xA7,0xD1,0xFB,0xFD,0x54,0x29,0x5A,0xE5,0x0A,0x0A,0xD6,0x91,0xFB, +0x54,0x74,0x01,0x1A,0x3B,0xF9,0xA1,0x00,0x9C,0xBB,0x96,0xCA,0x38,0x37,0x30,0x3C,0x41,0x14,0xB2,0x6F, +0xB5,0x22,0x2E,0xC6,0xCE,0x49,0x96,0xB5,0x1A,0x65,0x61,0xFD,0xAB,0x60,0xB9,0xB8,0xBE,0xDB,0xD7,0xB8, +0xC4,0x41,0x2F,0x6A,0x3A,0x66,0xF0,0xEA,0x83,0x78,0xD6,0x19,0xE2,0x7F,0xA0,0x5F,0xCD,0x19,0x67,0xBF, +0xB9,0xF6,0x79,0x83,0x97,0x7F,0xB8,0xCB,0x9B,0x9D,0x28,0xEF,0x97,0xFD,0xEE,0xDD,0xDB,0xC3,0x61,0xA3, +0x12,0x16,0x6E,0xAE,0x59,0x01,0xFA,0x7C,0x12,0xCE,0xC9,0x78,0x10,0x5C,0xA7,0x51,0x73,0xE3,0xFF,0xFD, +0x38,0x91,0xF7,0x16,0x1F,0xFD,0x0C,0xFD,0x99,0xC4,0xCF,0x9A,0x18,0x5D,0xB1,0xDA,0x1A,0xE0,0xA4,0xDE, +0x4A,0x33,0xE7,0x07,0xFD,0xD4,0x79,0x34,0xA3,0x90,0x18,0xF8,0x04,0xED,0x31,0x51,0x26,0x8F,0x34,0x02, +0xBD,0x90,0x5B,0xFF,0x46,0xDE,0xCA,0x56,0x43,0x2C,0x46,0x96,0xA4,0x62,0x33,0x34,0xBA,0xFA,0xD9,0xFF, +0x30,0x79,0xF8,0xEB,0x92,0x18,0x0F,0x83,0xAC,0x81,0xE9,0x36,0xD2,0x39,0x56,0x97,0xB6,0x0A,0xF0,0xEE, +0x32,0xB8,0x6D,0xC0,0xEF,0x63,0x7F,0x51,0x2A,0x4E,0xF4,0xC0,0xCB,0xAA,0x44,0x24,0xED,0xC1,0x0E,0xC2, +0xEA,0xC9,0x44,0x18,0xF5,0x81,0x52,0xF7,0xF0,0x9E,0xC7,0xB4,0xBB,0x18,0xAC,0x01,0x65,0x63,0x52,0x05, +0xF6,0x67,0x59,0x73,0x8E,0x79,0xD9,0xC5,0x07,0xAD,0x0F,0xC2,0x4B,0x60,0x4E,0x85,0xF2,0xE0,0x69,0x35, +0x08,0x71,0x91,0x28,0xFF,0xAA,0xA9,0xB3,0x86,0xC4,0x81,0x87,0xF4,0x56,0x7B,0x24,0xA9,0x27,0xB3,0x68, +0xE3,0xB8,0xA5,0x28,0x9A,0x13,0x37,0x31,0xFF,0x6D,0xA6,0xF7,0xBC,0xD2,0x52,0x16,0xE0,0xE6,0xA0,0xC2, +0x4D,0x8B,0xE3,0x2F,0xF8,0x18,0xAB,0x03,0x29,0x25,0x1B,0xE7,0xAF,0x56,0x82,0xD6,0x3E,0x7F,0x4C,0xC7, +0xD4,0xA5,0x59,0xE2,0x8F,0x10,0xF2,0x33,0x38,0x54,0xE5,0x97,0x11,0xD8,0x43,0x4D,0x36,0x9B,0xD9,0x3A, +0x8E,0x93,0xF0,0xCC,0xF5,0xE8,0x31,0x7E,0xB7,0xA0,0x8B,0x08,0xA9,0x67,0xEF,0xD8,0x87,0xF5,0x4E,0x3C, +0xE0,0xC8,0x6A,0xE2,0x3B,0x70,0x56,0xE0,0x5C,0x2D,0x39,0x49,0x1C,0x86,0xD9,0xFF,0x07,0x01,0x11,0x6F, +0xCD,0xFE,0xAB,0x52,0x6D,0xA3,0x53,0xBB,0xC7,0x74,0xD3,0xDD,0x0E,0xE4,0x97,0xE9,0xD3,0xC5,0xA1,0x9F, +0xA3,0xF0,0xDF,0xFD,0x44,0x8D,0xEC,0x9A,0xDD,0x51,0xA2,0xA4,0x47,0x90,0xED,0xA5,0xD3,0xEB,0xD7,0xE1, +0x07,0xEE,0x08,0x7E,0x02,0xF3,0xD8,0xD0,0x04,0xF1,0x3A,0xC4,0x46,0x01,0xDA,0xFD,0xC6,0x15,0x65,0xB2, +0x09,0x1D,0xCA,0x87,0x66,0x1E,0xB2,0xC1,0x16,0xB2,0xF4,0x93,0xDE,0x9F,0xE2,0x91,0xB4,0x73,0x25,0xB6, +0x9A,0xD3,0x45,0x5F,0xAD,0xBC,0x7B,0x4E,0xDF,0xD6,0x50,0xA4,0xC9,0xAF,0x12,0x43,0x93,0x72,0x37,0x84, +0xF9,0x62,0x3C,0xF5,0x86,0x3A,0x6C,0xE4,0x57,0x61,0x7A,0x76,0x1E,0x5C,0xDC,0xF2,0x48,0xF5,0xE7,0x4D, +0x07,0x39,0x62,0xB1,0xDD,0xB9,0x25,0x23,0xEC,0xD2,0xFD,0xF7,0xC9,0xD6,0x39,0xED,0x85,0x8C,0x93,0xD1, +0x5E,0xB8,0x75,0xFF,0x5A,0x66,0x46,0x27,0xFF,0x8E,0x7D,0x34,0x2A,0xB2,0x9C,0x66,0x47,0xF7,0xA6,0xD8, +0xEE,0x14,0xEF,0x2D,0x99,0x07,0xA5,0xA7,0xD8,0x96,0x8E,0x58,0x0E,0x02,0xA7,0xD8,0x4C,0x39,0x59,0x4E, +0xFD,0x56,0x21,0xF8,0xD0,0xD8,0x58,0xAB,0xF4,0x5B,0xD3,0x49,0x6E,0xC6,0x5B,0x47,0x91,0xB7,0x9B,0xE4, +0x0E,0x36,0x17,0x8F,0x1A,0x40,0x05,0x53,0x96,0x94,0xC7,0x37,0x58,0x72,0xE2,0x94,0xA3,0xFE,0xB4,0x85, +0xD5,0xD8,0x09,0xE8,0x26,0xA1,0xEE,0xFF,0x78,0x57,0x10,0x7F,0xFB,0xDE,0x42,0x41,0xCE,0x6B,0xD1,0x81, +0xB2,0x9C,0xF9,0x20,0xE0,0xBC,0xCC,0x4E,0x3D,0xA1,0xDF,0x35,0x12,0xB3,0x60,0x10,0x67,0xE4,0x34,0x95, +0x5D,0x0E,0xC3,0xA8,0x85,0x39,0xA7,0xF7,0xDC,0xEC,0x26,0x4E,0x4A,0xD9,0xFF,0xFF,0xFF,0xFF,0x3A,0xF3, +0x38,0xAF,0xC0,0xF5,0x72,0x2F,0x01,0xC2,0x5C,0x3D,0x1D,0x64,0x00,0xED,0x1B,0xFF,0xDC,0x7C,0xDC,0x74, +0x7D,0xAC,0x41,0xC4,0xA8,0x70,0x47,0x7E,0x26,0x47,0x90,0xF2,0xBC,0xAD,0xDF,0xB4,0x90,0x8F,0x0B,0x3D, +0xE3,0x06,0xE9,0xC8,0xD1,0xDD,0xA6,0x95,0xA6,0xCF,0x74,0x2E,0xFB,0xB6,0xE1,0x39,0x28,0x12,0x59,0xC8, +0xC0,0x65,0xF0,0x37,0x0C,0x5B,0xFD,0x06,0xB3,0x79,0x0A,0x9A,0x2A,0xD7,0xC6,0x06,0x32,0x65,0x77,0x61, +0xA2,0xFA,0xF0,0x6A,0x63,0xD0,0x0E,0xDD,0xA8,0x21,0xED,0xF0,0x3E,0xAF,0xF5,0x23,0x8C,0x79,0xE9,0x27, +0x2F,0x2A,0x2F,0x67,0xA1,0xB1,0xAF,0x63,0x33,0xE5,0x72,0xD5,0xDA,0x91,0xDE,0x1A,0x6E,0x5B,0xC9,0xD4, +0x34,0x2B,0xCB,0x35,0x38,0x23,0xBD,0xCF,0xCA,0x68,0xD0,0x33,0x36,0xFD,0xEA,0xC0,0x67,0xE5,0xBC,0x47, +0xF9,0xE8,0x9C,0xEB,0x39,0x0D,0xB0,0x2D,0x37,0x86,0x09,0xDE,0x6D,0x52,0xB4,0x56,0xF8,0xE9,0x0B,0x1C, +0x69,0xA5,0x53,0x89,0xB7,0x86,0x86,0xCF,0xD8,0xE7,0xEB,0xCD,0x9C,0x6C,0xC5,0x9D,0xF0,0x59,0x5F,0xED, +0x91,0x88,0xAA,0x5F,0x22,0x88,0xE3,0xBF,0x10,0x76,0xFB,0x47,0xA9,0x4E,0x02,0x11,0xE0,0xD9,0x6C,0xD0, +0x94,0xE3,0xE8,0xDC,0xE2,0x2E,0x12,0x07,0x0D,0xD5,0x0A,0x4C,0x89,0x23,0x24,0xD5,0x6F,0xB8,0x1A,0x08, +0xA0,0x60,0x41,0xD0,0x73,0x96,0x9B,0xB7,0x61,0xF1,0x00,0x1A,0xF4,0x98,0x4F,0x12,0x33,0xE4,0xC5,0x19, +0xE1,0x14,0xF3,0xB2,0x18,0x22,0xC5,0x85,0xCB,0xB2,0xA0,0x5A,0x7A,0x03,0x3A,0xB5,0x02,0xFD,0x06,0xE6, +0x5B,0x01,0x2B,0x42,0x89,0xB3,0xAD,0x46,0xDC,0x7F,0x72,0xB8,0xAE,0xBC,0x91,0xCC,0xD0,0x9E,0x4A,0x04, +0x92,0xAA,0xC2,0x89,0x93,0xDA,0x03,0xF3,0x4B,0xF3,0x85,0x76,0x84,0x70,0x07,0xA0,0x1B,0xDF,0x55,0x2D, +0xF0,0x33,0x1C,0x03,0x5E,0xBE,0x9B,0x66,0xD5,0x9C,0x5D,0x4D,0x5D,0x11,0xCD,0xDF,0x74,0xD1,0xAC,0x55, +0xC3,0x0F,0xD3,0x8B,0xCF,0x48,0x2A,0x02,0x70,0x19,0x74,0x96,0x10,0x41,0x5D,0x10,0x3B,0x05,0x53,0x2E, +0xC8,0xEA,0xCC,0x83,0x0E,0xD7,0xD8,0x18,0xBA,0x4E,0x61,0x37,0xA4,0xCE,0x05,0x98,0x48,0xC3,0x4F,0xE3, +0x28,0x59,0x15,0x80,0x0F,0x0D,0x77,0xE5,0x44,0x05,0x0D,0xC5,0x21,0x39,0xA2,0x82,0x8D,0x3B,0x7E,0x71, +0x9E,0x3E,0x90,0xF8,0xA8,0x9E,0x10,0x7F,0x08,0xC3,0xC8,0x04,0xE5,0xD5,0xCF,0xA6,0x9D,0x6A,0x98,0x85, +0x42,0x08,0x13,0x3B,0xB4,0x94,0x65,0xCB,0x07,0xF8,0x85,0xEF,0x7F,0xA2,0xA0,0xC9,0xEC,0xB1,0x91,0x74, +0xD4,0x78,0xF0,0x52,0x09,0x8C,0x1D,0x4D,0xE8,0x38,0xF0,0x5E,0x40,0x0A,0x1D,0x0E,0x8D,0x96,0x27,0x46, +0x00,0x98,0x0E,0xFC,0xBA,0x60,0x1C,0xC9,0x4C,0xD3,0xFE,0x23,0xB9,0x31,0xB1,0xCC,0x83,0xCF,0x16,0xFC, +0x54,0xC3,0x1D,0xE9,0x8A,0xE2,0xA6,0xBE,0xB9,0xF1,0x64,0xDC,0x9F,0x6E,0xB8,0x1E,0x7A,0x4D,0xC7,0xA9, +0x34,0xB3,0x3E,0x0F,0x1B,0x01,0x45,0xE8,0x01,0x8D,0x3B,0x92,0x20,0xA3,0x71,0x74,0x85,0xC0,0xF3,0x59, +0xE6,0xF1,0xE8,0x55,0x98,0x5F,0x1F,0x88,0xDE,0xA2,0x9D,0x86,0x40,0xD6,0x70,0xF5,0x32,0x2D,0x31,0x44, +0xAF,0x23,0x88,0x94,0x5C,0x50,0x10,0xE1,0x35,0xED,0xF2,0x17,0x7F,0x22,0x79,0xD2,0x4D,0x01,0xB9,0xB4, +0xC4,0x4B,0x19,0xF0,0xE8,0xE7,0xB7,0xB6,0x7F,0x01,0x68,0x29,0x80,0x0F,0x05,0x45,0x36,0x09,0x4F,0x2B, +0x6C,0xF2,0xD7,0xA7,0xDF,0x80,0x60,0x24,0x20,0x5C,0xE3,0x36,0x76,0xE7,0x45,0x34,0xF9,0xC6,0x19,0x84, +0xB7,0x9B,0x66,0xDA,0xAD,0x57,0x17,0x1C,0x80,0xEE,0xF1,0x92,0x3F,0xC7,0x87,0xD2,0x4A,0x6B,0xAD,0x56, +0xAE,0x56,0x62,0x8D,0xA2,0xEA,0xEA,0x2F,0x80,0x3E,0x89,0x25,0x14,0x6A,0xCA,0xD2,0xF8,0x69,0x70,0x14, +0x95,0xA4,0xE2,0xFE,0x81,0x3F,0x89,0x01,0x3E,0xE5,0x6B,0x8C,0x2C,0x14,0x4D,0x08,0x74,0x4A,0x38,0x08, +0xBF,0x25,0x82,0xDD,0x38,0xB3,0x33,0x5C,0xB7,0x65,0xB1,0xD3,0x5C,0x33,0x62,0x0E,0xC5,0x68,0xAA,0xED, +0x29,0xAF,0x04,0x8E,0x4B,0x71,0x80,0xBC,0xCC,0x43,0xB5,0x7B,0x0C,0x9C,0xC7,0x79,0xF7,0x9B,0xE5,0x1A, +0x6D,0x35,0x73,0x2B,0x9F,0xE7,0xBE,0x08,0xBD,0x1A,0x8B,0xA9,0x3C,0xA2,0x58,0x41,0x6E,0xAE,0xC3,0x4D, +0x5F,0x47,0x79,0x8A,0x26,0x97,0x6D,0xA9,0x9F,0xA1,0x4C,0xC7,0x2C,0x33,0xBC,0x5F,0xFF,0x6D,0xEE,0x9A, +0x03,0x4D,0xC2,0x3C,0xA2,0xA1,0xE7,0x1C,0x85,0x0E,0xA8,0x55,0x59,0x04,0x47,0x3D,0x03,0x08,0xDE,0x0D, +0x3F,0xF3,0x0D,0xD2,0xEA,0xD5,0xEB,0x9C,0x5A,0x63,0x4B,0xCF,0x08,0xAD,0xD3,0x61,0xEF,0x5A,0x45,0xCA, +0xAE,0xCB,0x31,0x4F,0x5F,0x40,0x42,0xAE,0xCD,0xA1,0xB2,0x15,0x0C,0xBA,0xE0,0x5C,0x07,0x92,0x05,0xC0, +0x83,0xE0,0xBA,0xE2,0xA5,0x87,0xBD,0x69,0xD4,0x17,0x44,0x95,0x9C,0xDE,0x97,0xCD,0x2F,0xFA,0x3F,0x81, +0x17,0x3F,0x69,0xC0,0x55,0x14,0xF5,0xFA,0x44,0x4F,0x0D,0x5C,0x25,0x2F,0x25,0x87,0x6D,0x72,0x3B,0x69, +0x38,0x4E,0x82,0x83,0xE9,0x0E,0xB9,0x2F,0x0C,0x52,0x3E,0x42,0x5A,0x3B,0x84,0x90,0xE5,0xB9,0xF4,0xE7, +0xE6,0x00,0x53,0x04,0x70,0x74,0x12,0xD5,0x86,0xD4,0x46,0x19,0x96,0x16,0x42,0xCB,0xA5,0xD5,0xB6,0xB1, +0xB5,0x05,0xC5,0x33,0x18,0x45,0xF3,0xFE,0x15,0xB0,0x66,0xFC,0x9E,0xB8,0x68,0xF6,0xB5,0x5B,0x13,0x62, +0x0B,0x9A,0xFE,0x35,0x93,0x3A,0x43,0xCB,0x25,0x47,0xF5,0xE5,0xD3,0x58,0x33,0x99,0x1C,0xC9,0xC0,0xA2, +0xC9,0x1E,0x64,0xAB,0x87,0xFB,0x8E,0x51,0x8D,0x9B,0xEE,0x8E,0xBB,0x34,0x28,0x5C,0xBF,0x15,0xFE,0x53, +0x99,0x72,0xC0,0xB8,0x94,0x08,0xE7,0xF2,0xBA,0xE7,0xB2,0x4F,0xB5,0xBB,0xE8,0xAB,0x9B,0xD5,0x4C,0xDC, +0xDE,0x0B,0xB9,0x79,0x01,0x36,0x5A,0xFD,0x32,0x3D,0xEF,0x94,0x86,0xB8,0x6C,0x4C,0x71,0xF6,0x18,0x7E, +0xA1,0x3A,0x98,0x1E,0xF6,0x36,0x7E,0xFE,0x05,0x4D,0x52,0x8C,0x8D,0x99,0x4E,0x30,0xC6,0x3E,0xB4,0x9E, +0x57,0x17,0x1E,0xAC,0xB4,0x9F,0xBC,0xDA,0xAB,0x4C,0xF0,0xB8,0xDA,0x17,0xA9,0x6F,0xFA,0x7E,0x74,0x1A, +0x96,0xDE,0xCF,0x14,0xF8,0x27,0x75,0xD9,0x3D,0xDE,0x91,0x0E,0x56,0x15,0xF0,0x1C,0x6E,0xD2,0x58,0xC3, +0x2F,0x0E,0x27,0xA0,0x94,0x23,0xBA,0x86,0x81,0x19,0x4A,0x9B,0xC2,0x5C,0xEE,0x23,0x33,0x40,0x9A,0x72, +0x22,0xAB,0x57,0x92,0xF8,0xE8,0x5E,0xD8,0x12,0x0C,0x08,0x46,0xBA,0xD0,0xA4,0xA5,0x02,0xCE,0xF9,0x21, +0xE7,0x77,0x8C,0x43,0x37,0x4B,0xE9,0x38,0x78,0xA0,0x77,0x55,0x49,0xEA,0x74,0xF9,0x91,0xAE,0x41,0xB1, +0xF2,0xB9,0xE7,0x09,0x3A,0x82,0x35,0x80,0x4A,0x1F,0xDB,0xB7,0x96,0xA9,0x09,0x4B,0xE5,0x05,0x8A,0xF6, +0x2A,0x26,0xD8,0xAD,0x01,0xDE,0x58,0xBC,0x2C,0xE8,0x2A,0x71,0x5B,0x5E,0xC0,0xF8,0xDE,0x98,0x1A,0x32, +0xB2,0x49,0x93,0x16,0x79,0x42,0xF6,0x20,0x2B,0x6E,0xCE,0xA5,0x73,0xF9,0xFC,0xD5,0xF0,0x2F,0xDB,0xF7, +0x78,0x63,0x49,0x17,0x28,0x0F,0xBA,0x9A,0x22,0x09,0x8E,0x27,0x2A,0x5D,0xFD,0x88,0x2B,0xA1,0xAA,0xD7, +0x6B,0x88,0xAC,0x19,0xD5,0xCE,0xAF,0x9C,0x74,0xD7,0xEC,0x68,0x1A,0xB0,0x95,0x67,0x7A,0xB3,0x09,0x0D, +0xF8,0x96,0x94,0xF0,0x1A,0x91,0xB9,0xF2,0x65,0x46,0x4A,0xD5,0x6D,0xB6,0x09,0xED,0x8B,0xC7,0x31,0xE6, +0x74,0x67,0x34,0x99,0xAE,0x3E,0xA4,0xDF,0xFA,0xD1,0xA5,0x04,0xF7,0xB4,0x9D,0xC8,0x7D,0x79,0xF8,0xFC, +0xD3,0x83,0x0B,0x50,0xCA,0xAC,0x35,0x2C,0x56,0xF1,0x68,0x2E,0x86,0x8B,0xDC,0x3E,0x73,0x20,0xD2,0x90, +0x6D,0x00,0x62,0x86,0xE6,0x03,0x83,0x8C,0x86,0x15,0x67,0x69,0x73,0xDF,0x0A,0x58,0x6F,0xE1,0x34,0x82, +0xE9,0x0A,0x0B,0x99,0x95,0xCF,0xD9,0xFD,0x70,0x6B,0x25,0x3C,0x22,0x07,0xB8,0xBD,0x93,0xD2,0xC4,0x94, +0xB6,0x8D,0x80,0x66,0xCD,0x39,0x2C,0x5B,0xA2,0x50,0xCD,0xD1,0xD5,0xD6,0x4B,0x8D,0xA1,0x5F,0xBE,0xA4, +0x65,0x73,0x9A,0x58,0x1C,0x13,0x45,0x03,0x72,0xE1,0x22,0x63,0xA6,0x92,0x40,0x74,0x13,0x72,0x2E,0x33, +0xE4,0x5A,0x04,0xD6,0xC8,0x30,0xBE,0x30,0x5D,0x50,0x54,0xAB,0xB7,0x68,0x43,0x98,0xE0,0x93,0xA3,0x9C, +0x56,0x63,0xBB,0x28,0x62,0x56,0xD2,0xF9,0xD9,0x70,0x6C,0x1B,0x64,0xEF,0xD5,0xE6,0x76,0x18,0x01,0x54, +0x67,0x1F,0x68,0xF0,0x58,0x3A,0x73,0x8F,0xBA,0x6E,0xFC,0x12,0x40,0x21,0x43,0xAF,0xA4,0xCE,0xFF,0x75, +0x7B,0x99,0x0F,0xBB,0x17,0xCA,0x01,0x2F,0x01,0x6D,0x4D,0xD1,0xA3,0x17,0x4A,0xC7,0x54,0x9A,0x0B,0x96, +0x6E,0x35,0x65,0x15,0xF1,0x6C,0x31,0xFD,0x5B,0x18,0x2E,0xCC,0x60,0xB3,0x76,0xE2,0x5D,0xD3,0xA8,0x80, +0xDF,0x63,0xDB,0x99,0x95,0x7A,0xB4,0x2C,0x8D,0x96,0x5F,0x50,0x36,0x14,0x72,0x54,0x10,0x34,0x21,0x39, +0x9E,0xB1,0xE3,0xB0,0x53,0x7E,0x13,0x4B,0x1D,0x53,0xCC,0xDE,0x94,0x35,0xCF,0xF5,0x65,0x1F,0x2B,0x6D, +0xB1,0x34,0xE0,0x69,0xB5,0x52,0xF9,0x85,0x10,0x0A,0x7C,0x20,0xEA,0xD3,0x51,0x3D,0x99,0xCC,0xAD,0xE1, +0xC7,0x3E,0xF6,0x8A,0x49,0x28,0xFE,0x5C,0x72,0x99,0xF6,0x22,0x97,0x30,0x65,0x66,0x6A,0x3D,0xC3,0x1E, +0x5F,0xF0,0x27,0x87,0x38,0x05,0xE5,0xE9,0x51,0x5A,0xA8,0x2E,0x13,0xA8,0x2F,0x9F,0x78,0x62,0xA3,0x5D, +0xE3,0x21,0x30,0xAE,0xF0,0x9E,0x80,0xF8,0xCF,0xAA,0x86,0xF3,0x5C,0x3E,0x46,0x77,0x07,0x91,0x98,0xFC, +0xB8,0xAD,0x88,0x42,0x61,0xC6,0x0F,0x16,0x56,0x1F,0xBF,0x15,0x6E,0x8E,0x55,0xD1,0xEC,0xD7,0x8C,0x50, +0xBE,0xAF,0x8F,0x43,0x26,0xE1,0x07,0xA3,0x00,0x26,0xDE,0xEF,0x1E,0x6F,0x84,0x12,0x65,0x5D,0x0A,0x97, +0x6A,0x3D,0xA9,0x6C,0x83,0x43,0xF3,0x15,0x26,0x3E,0x5B,0x33,0x34,0x45,0x64,0x1E,0xBE,0xEB,0x00,0x0C, +0xD4,0x9F,0xDA,0xF6,0xDF,0x0B,0x66,0x00,0x26,0xC2,0xF2,0x98,0xD6,0x64,0xD7,0x7F,0xF8,0x58,0xFE,0x7F, +0xFC,0xE1,0x55,0x81,0xCB,0xC8,0x43,0xB1,0x95,0x65,0x00,0xC7,0xDF,0x02,0x45,0x63,0xF5,0xE9,0x0F,0x65, +0x27,0x45,0xF6,0xDC,0x96,0xF8,0xB8,0xAD,0x7E,0xB4,0xD3,0xE7,0x5E,0x08,0x82,0x54,0x66,0x38,0xF1,0x7F, +0x50,0xA6,0xC3,0x68,0xFF,0xED,0xB8,0x0C,0x8E,0xA0,0xB2,0x6A,0x16,0xD3,0x27,0xAA,0x3F,0x13,0x8A,0x09, +0x27,0xED,0xD4,0x18,0xFC,0x2A,0x72,0xAE,0xCF,0xBC,0xC4,0x02,0xBC,0x4A,0x1B,0xF0,0x44,0xC9,0xEB,0xFF, +0x1A,0x5B,0x2C,0xAF,0xA7,0xFB,0x8D,0x5A,0xB4,0x3B,0x75,0xF9,0x89,0x76,0x1A,0xEC,0x11,0x20,0xAE,0x59, +0x3E,0xAE,0xAC,0xCC,0xA5,0x87,0x1D,0x30,0x3C,0x13,0x46,0x6A,0x7D,0x31,0x4C,0x2F,0x26,0xC1,0xAB,0x6C, +0x3D,0xCC,0xE8,0xF2,0x8D,0xD1,0xD0,0xEE,0xDA,0x02,0x40,0xCA,0xD6,0x62,0x6A,0xEE,0xA0,0x66,0x03,0x05, +0x5C,0xCE,0xF5,0x76,0x75,0xEA,0x61,0xE9,0x25,0x8A,0x0B,0x4B,0x2B,0xE7,0x08,0xDF,0xD6,0x01,0x4F,0x7B, +0xFC,0xF2,0xDF,0x19,0x3C,0xAA,0xFF,0x35,0x22,0xF3,0x60,0x6F,0x25,0x1D,0x9A,0xF2,0x76,0x6F,0x36,0xFD, +0x27,0xDF,0x74,0x4A,0x9A,0xF8,0x78,0x16,0x5A,0x89,0xEF,0x67,0x96,0xF1,0x5C,0xF8,0x58,0xDE,0xBD,0xC5, +0x05,0xBE,0x5A,0xBC,0x82,0x47,0x1A,0xC0,0x62,0xB8,0x9A,0x4B,0xC7,0x9F,0x34,0xD4,0xC8,0xBD,0x4D,0xC5, +0xC1,0x9E,0x12,0xA5,0xD5,0xF1,0x64,0x6E,0x18,0x9C,0x9B,0x82,0xC5,0x53,0x6C,0xCB,0x20,0x2C,0xDC,0xE2, +0x5D,0xBB,0xFC,0x66,0x7F,0x0D,0xCE,0x1C,0x8D,0x8F,0xAC,0xC6,0x66,0xD7,0x92,0xD0,0xFF,0xBA,0xFD,0xCD, +0x6A,0x97,0x85,0x72,0x37,0xE3,0x09,0x3C,0x95,0xD3,0x65,0xB4,0xF5,0x33,0xCA,0x92,0xEF,0xDF,0xB5,0x0B, +0x9A,0xC9,0x74,0xD3,0xA4,0x67,0x49,0xF3,0x49,0x48,0x70,0x8F,0x1A,0x7E,0x20,0xCE,0xC0,0x80,0x64,0x68, +0xC5,0x71,0x66,0x62,0xC8,0xFA,0xA6,0x42,0x4F,0x95,0x20,0xAC,0xA6,0xE3,0xBD,0xA0,0x55,0x62,0xF4,0x19, +0x41,0x16,0xDC,0xFA,0x79,0xDF,0xE7,0xCB,0xD8,0x0F,0xDA,0x67,0xAC,0x2F,0x7E,0xC9,0xBD,0x0A,0xCC,0x6C, +0xDF,0x4E,0xD3,0xD9,0x03,0x96,0x4E,0x67,0x31,0xDB,0x0F,0xED,0xDF,0xEE,0x16,0xD6,0x18,0xD4,0xE5,0xBD, +0xFB,0xA0,0x3F,0xE1,0x8B,0x1C,0xE4,0xBC,0xC9,0xB8,0x7A,0x0A,0x62,0x27,0xAB,0xE6,0x4D,0xFC,0x66,0xD3, +0x3D,0x16,0x35,0xCF,0xBF,0x2C,0xEE,0x89,0x5B,0x7C,0xAE,0x6A,0x9E,0xF2,0x9F,0xAD,0x6C,0xBE,0x33,0x70, +0x49,0x3E,0x73,0xCF,0x91,0xDE,0x37,0x0E,0x90,0xF8,0xED,0x3D,0x8B,0x12,0x34,0xCB,0x5E,0x00,0x6C,0xCA, +0x4E,0x5E,0x4B,0x80,0x5C,0xBE,0x59,0x92,0x06,0xB8,0xF8,0x23,0x50,0x2F,0x40,0x3D,0xE3,0x46,0x4F,0x25, +0x56,0x9B,0xA4,0x94,0x49,0x3F,0x3C,0xE4,0x13,0x2E,0x52,0x2D,0xBE,0x2F,0xE0,0xDC,0x57,0x2C,0x58,0x85, +0xD5,0x00,0x35,0xF5,0xB2,0x2D,0x31,0x58,0x61,0xCE,0x0A,0xA1,0xBC,0x6E,0x41,0x24,0x03,0x5F,0xE9,0x51, +0x9C,0x2E,0x7B,0x34,0xC0,0x03,0xF9,0x95,0xC9,0x21,0x7A,0xF1,0x7E,0x9B,0xFB,0xC0,0x71,0x5B,0x1A,0x75, +0xC0,0x0C,0x0B,0x38,0xBB,0x14,0x88,0xA5,0x35,0xF8,0x0C,0x9E,0xA8,0x9A,0x18,0x4F,0x4B,0x29,0xA0,0x9C, +0x41,0x28,0x9E,0xC1,0xF5,0x73,0x6A,0x02,0x9C,0xFA,0xC9,0x83,0xE6,0x28,0x3D,0xF7,0xC6,0x6E,0xC2,0xB1, +0x93,0x45,0x66,0x3B,0x4E,0x65,0x71,0xB3,0x17,0xE4,0x81,0xFC,0x76,0xE7,0x63,0x6A,0xBB,0x6D,0xC8,0xF2, +0xBB,0x2E,0xCD,0x2D,0x14,0xB8,0x04,0xCC,0xA7,0x2A,0x32,0xF0,0xCB,0x4B,0xF5,0xFE,0x1F,0xD0,0x62,0xD0, +0x3A,0x89,0xFA,0x9C,0x01,0xE2,0xB7,0x2E,0x39,0x06,0x8F,0x76,0x39,0xA0,0x73,0x89,0xD6,0xB7,0x0D,0x4F, +0x5D,0x3F,0x04,0xF1,0x0A,0x06,0x6D,0x1F,0x81,0x30,0x42,0xCD,0x2C,0x94,0x9F,0xDF,0xDF,0x90,0xC9,0x60, +0x0B,0x7C,0x1D,0xE0,0x83,0xD1,0xF5,0xDC,0x9A,0xAF,0x2A,0xE8,0x63,0xF4,0x13,0x4F,0xEC,0x1D,0x77,0xDE, +0xA7,0x5C,0x04,0x9A,0x4F,0xC8,0x48,0x8F,0x37,0xC2,0xAB,0xC8,0xAE,0x83,0xEE,0xBC,0x39,0x6E,0x74,0xC1, +0x23,0x3D,0xE9,0x9E,0xB2,0xC1,0xB1,0x1F,0x81,0x4E,0x0B,0xAC,0x93,0xF3,0x4D,0xCD,0x34,0xE2,0xCA,0x80, +0xB3,0xD4,0x6C,0xE2,0x93,0x7C,0x00,0x00,0x4F,0x9C,0xAC,0x5F,0x53,0xCB,0xAC,0x5B,0x99,0x81,0xE0,0x14, +0x69,0x2F,0xC3,0xB2,0xB1,0x7C,0x22,0x52,0x67,0xB8,0x38,0x4B,0x90,0xA2,0xBA,0x05,0xF9,0x27,0x45,0x85, +0xF4,0x70,0xAF,0xBE,0x43,0xD6,0x41,0x5B,0x0D,0xF3,0x45,0x15,0x92,0x56,0xD4,0x97,0x54,0x8C,0x5C,0xD3, +0x12,0x36,0x66,0xCA,0xC2,0x93,0x3C,0xC2,0x32,0xE9,0xBA,0x26,0xD2,0x8B,0x66,0xA6,0xF0,0x38,0x14,0x18, +0x27,0x72,0x16,0xD1,0x80,0x13,0xB4,0xE6,0x4B,0xCA,0x22,0xEB,0x8A,0xB6,0x58,0xF1,0xFC,0x71,0xBD,0x43, +0x80,0xA6,0xF6,0x27,0x0B,0x99,0x6B,0x49,0x28,0x25,0x7A,0x07,0x53,0xF1,0x6D,0xBC,0x02,0xE8,0xF3,0x37, +0xC1,0xE8,0x3F,0xF1,0x08,0xC3,0xD9,0xB2,0xF2,0x27,0xC6,0xD1,0xF4,0x5A,0x59,0x8D,0x3E,0xF3,0x2E,0x53, +0xC4,0x55,0x3D,0xEB,0x76,0xA4,0x01,0xB3,0xA6,0x5B,0xD7,0x09,0x9C,0x92,0x7E,0x1C,0x28,0x1B,0xC9,0x51, +0x7B,0x22,0x08,0x4A,0x25,0x58,0x9F,0x09,0xD3,0x29,0xEC,0x8E,0x49,0xA5,0x53,0x67,0x43,0xD5,0x09,0x52, +0xA8,0xEB,0xF7,0x20,0x59,0xC4,0x9D,0x11,0xED,0x80,0x2A,0x44,0xF9,0xE0,0x82,0x4D,0x24,0x96,0x56,0x24, +0x66,0x71,0x08,0xE7,0x66,0x12,0x16,0x11,0x96,0xD1,0x36,0xA7,0x68,0xFD,0x96,0xD4,0x08,0xCD,0x77,0x97, +0xFA,0x98,0xD6,0x97,0x04,0x5D,0xC3,0x4B,0xAF,0x64,0x58,0xAD,0xA5,0xC3,0x36,0x49,0x3C,0xE1,0x52,0x2A, +0x38,0x2E,0x2F,0x79,0xF9,0x10,0x70,0x3B,0x88,0x8F,0x2D,0xF1,0x0F,0xF8,0x1F,0x81,0x92,0x7E,0x59,0x45, +0xF9,0xF6,0xA7,0x60,0xF6,0xE0,0x4A,0x42,0x5A,0xDB,0xA3,0xA4,0x76,0xF2,0x61,0xFE,0x01,0xC3,0x40,0x96, +0x90,0xF1,0xA6,0x29,0xE6,0x45,0xE2,0x16,0xF6,0xE7,0xDE,0x7D,0x12,0xF9,0x25,0x83,0xBD,0xC1,0xF0,0x45, +0x3F,0x6F,0xEB,0x0C,0x77,0x87,0x26,0xB0,0x08,0xC1,0x01,0x16,0xB5,0x83,0xC6,0x40,0xA8,0x77,0xE9,0x32, +0xB6,0xC3,0xA0,0x77,0x87,0xC6,0x4C,0xC3,0xC3,0xC6,0x08,0xD3,0x2C,0x6B,0x66,0xE2,0x6B,0x83,0xF6,0x30, +0x34,0xC7,0x90,0x52,0xE6,0xA3,0x06,0xE1,0x2C,0x43,0x98,0x25,0xE9,0xEA,0xF7,0xA3,0x79,0xC4,0x88,0xAC, +0x29,0x0D,0x93,0x7C,0x08,0x4B,0xE1,0x72,0x2F,0x6B,0xD1,0xAC,0x05,0x84,0x5C,0x7A,0x91,0x0C,0xF9,0x60, +0xAD,0x11,0x06,0x8B,0xD1,0xA5,0x24,0xC1,0x0F,0xA8,0x23,0x8A,0x6B,0x70,0x4A,0x38,0xA5,0xC7,0xCA,0xE8, +0x40,0xA6,0x13,0x58,0xAC,0x92,0x2B,0x5E,0xB2,0xEB,0x9D,0xD8,0x8D,0xD2,0x02,0xCD,0x21,0xF9,0xB3,0x8F, +0xD9,0x88,0x9D,0x02,0x11,0x2C,0x2B,0x2A,0x90,0x17,0x04,0x0B,0xEF,0xBF,0x9B,0x9F,0xD4,0x90,0x74,0x28, +0xBF,0xAB,0x60,0xCD,0xFE,0x99,0x03,0xCC,0xFF,0x4A,0x67,0xA8,0x3D,0x0E,0xE6,0x10,0x93,0xCE,0x54,0xDE, +0x90,0x63,0xB8,0x0C,0x7A,0x18,0x0A,0xFA,0x53,0x82,0x95,0x01,0xA2,0x51,0x04,0x4C,0xA4,0x28,0x61,0xD9, +0xBE,0x42,0x33,0x53,0xDE,0xC3,0x48,0xCA,0x0D,0x91,0x14,0x9A,0x1C,0x8E,0x66,0x74,0xAE,0xAC,0x0B,0xFB, +0xD7,0x02,0x2B,0xA2,0xA9,0x52,0x25,0x48,0xDF,0x60,0x7E,0xFB,0xA8,0xA2,0x1A,0xE2,0xAB,0x16,0x17,0x64, +0x32,0x2B,0x8C,0x5F,0x64,0x0B,0xCC,0x5B,0x7C,0xB2,0x63,0xF4,0xC7,0xB1,0xF5,0x1F,0x90,0x3D,0x5C,0xF2, +0xCB,0x5A,0xAA,0xD4,0x8A,0x5C,0x21,0x43,0xE0,0x89,0x12,0x03,0xD8,0x74,0x37,0x27,0x97,0x54,0xB1,0xD5, +0x1D,0xF1,0xAD,0x54,0x81,0xFF,0x79,0x32,0xF6,0xBF,0x39,0x51,0xD6,0x63,0x2A,0x33,0xAC,0x65,0x04,0x86, +0x2D,0x1F,0x1C,0xE2,0xCB,0x3D,0x45,0x4E,0x82,0x41,0x72,0x62,0xBE,0x85,0x77,0xB0,0xD8,0x19,0x6A,0x3E, +0x6B,0x48,0x7C,0x30,0xE4,0x93,0x21,0xBC,0x0C,0xEC,0xE1,0x21,0x24,0x92,0x65,0x27,0xAB,0xFA,0x74,0xD5, +0x1E,0x2D,0x21,0xF4,0x86,0x75,0xA9,0x56,0xA9,0x1D,0x15,0x3F,0xEF,0xF8,0xCA,0xD7,0x36,0x6A,0x22,0xBF, +0xF1,0x6E,0xB6,0x0E,0x41,0xA8,0xAC,0x2E,0x83,0x0D,0x8E,0x4A,0x1C,0xDE,0x8E,0x51,0xD0,0xF5,0x56,0x72, +0x42,0xDB,0x71,0xFA,0xDC,0x16,0x46,0x9D,0x0E,0x71,0xBF,0xC1,0x9A,0x54,0x1F,0x09,0x8E,0xAA,0x39,0x72, +0xB4,0xF8,0x13,0xEB,0x8F,0x32,0xEE,0xB8,0x21,0x35,0xB1,0x96,0x0C,0x9D,0x61,0xB0,0xD0,0x04,0x47,0x9C, +0x8E,0xB1,0xEF,0x8F,0xF9,0x44,0x62,0x48,0x2B,0x06,0xDC,0x3D,0x22,0xBA,0x5D,0xA5,0x93,0xA0,0x74,0x28, +0x32,0xBD,0x24,0xDF,0x83,0x92,0x96,0xFE,0x37,0x0D,0xD5,0xBD,0x61,0x01,0xED,0x4E,0x40,0xE0,0x1F,0xB4, +0x6F,0xFC,0x4D,0xFB,0xDD,0xFE,0xCA,0x6F,0x8D,0xA1,0xD1,0xC2,0xD0,0x5A,0x0F,0xD9,0x94,0x92,0x2F,0x22, +0x53,0xFD,0xBB,0x31,0x54,0x80,0xA0,0xD5,0x80,0xEB,0xC0,0x78,0x44,0x4C,0x96,0xB4,0xFB,0xA3,0xF7,0xD1, +0x9A,0x50,0xAB,0xA0,0x0D,0x84,0x53,0x93,0x76,0x27,0x5C,0x90,0x44,0xC1,0x66,0x07,0x2A,0xE4,0x2C,0x56, +0x5F,0x1E,0x87,0x25,0xB7,0x24,0x3A,0xB4,0xBE,0x8D,0x6F,0xBB,0x2B,0x87,0x21,0x52,0xDE,0xBD,0xC9,0x74, +0x36,0x42,0x9F,0xB1,0x7A,0x60,0x98,0xC2,0x21,0x0F,0x30,0x4B,0x44,0x96,0x32,0x80,0x06,0x48,0x50,0x02, +0x14,0x68,0x47,0x60,0x8A,0xAD,0x28,0x66,0x0E,0x08,0x70,0x70,0xEA,0xA5,0x0A,0x12,0x59,0x69,0x18,0x63, +0x3B,0xC6,0x99,0x12,0x81,0x6F,0x87,0xC3,0x02,0xBD,0x80,0x03,0xDC,0x6A,0xC2,0x8D,0x7E,0x3D,0x88,0x00, +0x77,0xD0,0x96,0x55,0x85,0xFC,0x08,0xD1,0xC6,0x6D,0x7F,0x4D,0xA9,0xBC,0xDF,0x0F,0x74,0x77,0x38,0xFB, +0x01,0xA7,0x39,0xBD,0x32,0x87,0x73,0x53,0x9D,0xD5,0x03,0x53,0x76,0xCE,0x02,0xEB,0x8D,0x84,0xA6,0x38, +0xD1,0xF0,0xCE,0x66,0x67,0x95,0xE5,0x42,0x2B,0xF6,0x0B,0xF9,0xEA,0xAB,0xD7,0x1C,0xF2,0x2E,0xB8,0xC1, +0x8C,0x26,0xAB,0xD3,0x25,0xDB,0x59,0x4F,0x62,0x6F,0x2B,0x0E,0xE0,0x4F,0x72,0xD2,0x22,0xFF,0xA4,0x0C, +0x78,0x94,0xAC,0x4C,0x75,0x4A,0x9B,0x4A,0xFD,0x3C,0x33,0x94,0xD6,0x0E,0xED,0x8A,0x06,0x9B,0xE6,0x1A, +0x88,0xD9,0xCB,0xBA,0x28,0x38,0x85,0xF8,0xF7,0x9C,0xA4,0x4D,0xD9,0x49,0xAF,0xC9,0x76,0x2E,0x39,0xA5, +0x48,0x61,0x0B,0x59,0xBD,0x3B,0x50,0x3B,0xFE,0xE3,0xB0,0x46,0x74,0xA4,0x33,0xB5,0x5F,0xE0,0xEA,0x40, +0xB0,0xAF,0xDB,0x9F,0xEC,0x1A,0xBB,0xB1,0x29,0xBF,0x7B,0xFA,0x1E,0xEF,0x7C,0x62,0xE6,0xA5,0x0C,0xC3, +0xA1,0x8D,0x04,0xD7,0xE3,0xB1,0x2C,0xE7,0x48,0xE2,0x42,0x14,0xE0,0xFA,0xC5,0x45,0x8C,0xBE,0x09,0x90, +0xA1,0xBF,0xBB,0xF9,0xCC,0x9D,0x85,0x50,0xCA,0x76,0xBE,0x21,0xCF,0x27,0x05,0xC6,0x48,0x3B,0xF3,0x92, +0x10,0x72,0xC9,0x03,0x8A,0xD0,0x32,0xCF,0x2C,0x70,0xC0,0x31,0x9D,0x94,0x5E,0xDB,0x91,0xB1,0xD3,0x9F, +0x22,0x38,0x0B,0xD3,0x9B,0xD5,0xB1,0x41,0x48,0x6A,0xB4,0x32,0x23,0xC8,0x66,0x55,0xEE,0x17,0x20,0xE5, +0x1B,0x71,0x1B,0x2E,0xA4,0xBD,0x3A,0x2D,0x06,0x9B,0x91,0xD1,0xEA,0xE9,0x79,0x77,0xF6,0x7C,0xCE,0x71, +0x10,0xA8,0x35,0xF1,0x52,0x2C,0xCB,0x80,0xE2,0xA5,0xB1,0x09,0x73,0x8C,0x1E,0x0D,0x1B,0x3B,0xF8,0x8A, +0xD9,0xBB,0x2F,0xDB,0x05,0xD9,0x95,0xB1,0x4B,0xEA,0x99,0x67,0xC8,0x7A,0x33,0x63,0x17,0x9F,0x60,0x09, +0x80,0xFA,0x1A,0xA9,0xAC,0xE4,0xBF,0x76,0xBA,0x57,0x2E,0x7E,0x34,0x7B,0xEC,0x5A,0x8E,0xD7,0x2F,0x95, +0x07,0x79,0xF4,0xEA,0xA0,0xE2,0xB7,0x63,0x40,0xCA,0xB3,0x2A,0x8C,0x51,0x34,0x47,0x24,0xA6,0x18,0x27, +0x78,0xB7,0xE0,0x2A,0xD1,0xDD,0x06,0xFD,0x0A,0xA1,0x58,0x14,0xC6,0xC7,0x1E,0x78,0x98,0xA2,0x36,0xD4, +0x9C,0xC2,0xE5,0x17,0xE4,0x1F,0x07,0xFF,0x7D,0x6F,0xBA,0xCC,0xC1,0x61,0xB9,0xE5,0x89,0x77,0x55,0x6D, +0x86,0x90,0x97,0x00,0x40,0x3C,0xFC,0x27,0x57,0xE0,0x0F,0xA4,0xAD,0xC2,0xC9,0x8C,0xEA,0xAF,0xDF,0xD9, +0x74,0x7D,0x18,0xFD,0xE7,0x89,0xFE,0xE4,0x10,0xE1,0x93,0x38,0x2F,0xB4,0x8B,0xA2,0x09,0x04,0x97,0x23, +0x0C,0x2E,0x90,0xE8,0xB9,0xAC,0xDB,0xC9,0xAC,0x66,0x54,0xB9,0xA0,0xB7,0x20,0x87,0x9D,0x5B,0x18,0x83, +0xD0,0xF4,0xB1,0xE5,0x56,0xC1,0x4A,0x00,0x75,0x1D,0x25,0xE3,0xBB,0x22,0x56,0xFF,0x11,0xEE,0x37,0x81, +0xE6,0x03,0xB1,0x23,0x00,0xBE,0x9D,0xEB,0x24,0x5B,0xB9,0x49,0xF1,0xBF,0xB0,0x8A,0x8C,0x1F,0x2D,0xE6, +0x3D,0x57,0x36,0xBD,0x01,0x2E,0xE9,0xA6,0x04,0xEA,0xEB,0x5C,0x3F,0x7E,0xC0,0x04,0xA8,0xA7,0xE5,0xB2, +0x39,0x06,0x01,0xB7,0x92,0xE9,0xC4,0x9E,0xC4,0xB3,0x71,0x9E,0xD6,0x7D,0x94,0xC2,0xEC,0xF8,0xD3,0xBF, +0x1F,0x68,0x18,0x8B,0x5B,0x85,0xFD,0x05,0x52,0x47,0x2A,0xF9,0x88,0x05,0xDD,0x49,0xE1,0x1E,0x68,0x70, +0xFB,0xB7,0x19,0x71,0xE1,0x14,0x12,0xE5,0xEE,0x80,0xB0,0x1C,0x8F,0xE8,0x8F,0x85,0x90,0xB4,0xC4,0x43, +0xE4,0x48,0x71,0x5D,0x67,0xEE,0xF9,0x0D,0x2F,0x77,0x13,0x3B,0x78,0x1D,0x8D,0x02,0xB4,0x13,0x2A,0x9F, +0x94,0x52,0x50,0x60,0xF5,0xA6,0x94,0x65,0x78,0x17,0xE3,0xCC,0xFE,0xAB,0x61,0xEA,0xBD,0x33,0xBB,0x5D, +0x79,0xEF,0x2A,0x06,0x6A,0xD7,0x29,0x41,0x21,0xEE,0x91,0x41,0xF0,0x26,0xCF,0xA8,0xF6,0x44,0x81,0x04, +0xC2,0x3B,0x5B,0x01,0x7E,0xCF,0x3D,0xA4,0x98,0x1A,0xBA,0xCC,0x7B,0xB5,0x37,0x0D,0x31,0x43,0xAC,0xC4, +0xD8,0x55,0x96,0xF2,0xAD,0x50,0xF9,0xA1,0x60,0x02,0x33,0x3F,0xEF,0x2F,0xEB,0x6E,0x89,0xAD,0x7C,0x83, +0xD1,0x9B,0x5B,0xF4,0x42,0xF1,0x65,0xD1,0x42,0x51,0x1B,0x4E,0x72,0x6D,0xF3,0x93,0x01,0xFF,0xFA,0xE5, +0x17,0x17,0x68,0x4C,0x0E,0x99,0xC4,0x5E,0x37,0x0C,0xA1,0x7E,0xA4,0xD3,0x49,0xF4,0x9E,0x14,0x37,0x5C, +0x05,0x71,0x4D,0x25,0xD6,0xC2,0x6D,0xAC,0xAD,0xFF,0xFF,0xB3,0x69,0xE2,0x3D,0xA0,0x83,0xBB,0x45,0x35, +0xD7,0x03,0x0C,0x00,0xA0,0x61,0x24,0xD2,0xA0,0xB9,0xCB,0x13,0xC5,0xB4,0x43,0xE7,0xFB,0xF8,0x3C,0xDB, +0x6A,0x96,0x00,0x45,0x07,0x28,0xD0,0x9D,0x61,0x34,0x1A,0x84,0x9C,0x53,0xF5,0x99,0x5B,0x0A,0x9E,0xE0, +0x17,0x09,0x47,0x67,0x8A,0x18,0x9D,0xF9,0x30,0x02,0x6D,0x83,0x94,0x3C,0x8B,0xE2,0xB6,0xD5,0xE3,0xB3, +0xF7,0x95,0xA3,0x65,0xF3,0x2B,0x0E,0x48,0xF8,0x5E,0x81,0xA3,0xA5,0xC5,0x83,0x1A,0xD8,0xBB,0xCE,0x46, +0x60,0xB5,0xAE,0x6B,0xEF,0xD9,0x81,0xE1,0xE4,0x26,0xFE,0xC7,0xBA,0x74,0x7E,0xCB,0xDC,0xBB,0x80,0x1C, +0xC7,0x3C,0x8A,0x0B,0xE1,0x36,0x00,0x0F,0x1C,0xF9,0x4C,0xA7,0x59,0x05,0x15,0x68,0x7B,0x34,0x90,0xAE, +0x1C,0x44,0xED,0x3F,0xB8,0xEB,0xA8,0x51,0xFB,0x40,0xDC,0x31,0x0F,0x4F,0xBF,0xAA,0xD7,0x5D,0xE0,0x46, +0x0D,0x9C,0xCD,0xB0,0xA3,0x41,0x16,0xE3,0xC4,0x4C,0x16,0xC4,0x53,0x09,0xE8,0x56,0x0C,0xFD,0x19,0x0D, +0xA5,0x56,0xA7,0xFE,0x45,0x3A,0x1F,0xC7,0x57,0xAF,0x0F,0xE9,0xAA,0x9C,0x58,0xF1,0x28,0x0A,0x54,0xBB, +0xEB,0x34,0xFE,0x37,0x77,0x42,0x07,0xE7,0x66,0xE8,0x9C,0xFB,0x2A,0xA2,0xAB,0x5F,0xBD,0xFC,0x47,0x80, +0x3B,0x5B,0x2A,0xD3,0x96,0xEF,0x57,0x35,0x63,0x2B,0x76,0x23,0x6A,0x84,0xA6,0xE9,0x96,0x3A,0x66,0xAA, +0x94,0xDC,0xC5,0xC4,0xBC,0x7A,0xA2,0x37,0x5C,0xE7,0xD1,0x1D,0xEC,0xF9,0xF6,0xD0,0x1A,0x52,0x2B,0x27, +0xC0,0x0E,0x89,0x57,0x13,0xA7,0xCC,0x73,0xF0,0x03,0xB2,0x6E,0x38,0xBF,0x41,0xA3,0x93,0xC7,0xD0,0xA8, +0xB2,0x49,0x33,0x54,0xDB,0xD8,0x2B,0x3F,0xB3,0xB8,0xD0,0xA6,0xD1,0x22,0xCE,0x10,0x43,0x48,0x88,0x6B, +0x1B,0x49,0xD3,0x80,0x70,0x91,0x6F,0x75,0xDE,0x69,0x59,0xF8,0x0D,0x80,0x7A,0x1A,0xB6,0x48,0xC1,0x7E, +0xFA,0x04,0x66,0x41,0x5D,0x64,0x0B,0xB7,0xA7,0xDC,0xE1,0x97,0x47,0xE1,0x39,0x5E,0xAB,0x05,0xB1,0x6B, +0x15,0x93,0x8A,0x12,0xC0,0x60,0x90,0xF3,0x9E,0xDA,0xB1,0x1E,0x94,0xAD,0x13,0xCE,0xB8,0xF7,0xE2,0x92, +0x2B,0xDF,0x8F,0x5B,0xD3,0xB9,0x28,0x3C,0xCC,0x5F,0xA7,0x5C,0x7D,0xC4,0x24,0xF8,0x14,0x6A,0x03,0xEC, +0xA7,0x87,0x4D,0x1A,0xCC,0xE1,0x20,0x24,0x60,0x3A,0x74,0xE4,0x89,0x05,0xC3,0x08,0xEE,0x87,0xBA,0x23, +0x55,0xFF,0xD5,0x05,0x32,0x2F,0x66,0xB5,0x8B,0x4E,0x65,0xDB,0xFB,0x83,0x0C,0x65,0x79,0x4A,0x34,0x1E, +0xB1,0xCA,0x95,0x1A,0x0D,0x67,0xE9,0xC2,0xC3,0xDB,0x04,0x75,0x78,0xF9,0x39,0x8F,0x85,0xC6,0x18,0x08, +0xFD,0x2A,0xA5,0xBC,0x58,0x6E,0x33,0x46,0xF6,0x0C,0x8D,0xFF,0xDE,0xC1,0xCF,0xDD,0xD2,0xC4,0x95,0xC6, +0x8B,0x80,0xE3,0x82,0xA8,0x6C,0xBC,0x75,0x30,0xF9,0x3E,0x73,0xF2,0xCC,0x28,0x0B,0x8F,0xBD,0x2C,0x70, +0xBD,0x2F,0x39,0xEA,0x85,0x2C,0xA3,0x8E,0xC5,0xE5,0xF1,0xE6,0xA3,0x2E,0xA1,0xED,0x9E,0x57,0x9C,0x30, +0x7D,0x37,0xBC,0xDF,0x7D,0x6F,0x64,0x6B,0x51,0x04,0xAC,0xF0,0x43,0x8D,0xAB,0xD0,0x0B,0xE9,0xBB,0x60, +0x49,0x17,0xB6,0x35,0x5C,0xD1,0x95,0xB3,0x14,0x5C,0x22,0x72,0x3B,0xDA,0x1D,0x48,0x85,0x55,0x1B,0xC4, +0xB1,0x3A,0xEF,0x02,0xCE,0xA9,0xBC,0x26,0xF4,0x81,0xC1,0x23,0xA7,0x98,0x8C,0xEB,0x3B,0x59,0x06,0x62, +0x17,0x17,0x89,0xEE,0x45,0xC1,0xBA,0xB2,0xA1,0xB7,0x25,0xFA,0x96,0x58,0x2D,0xC5,0x03,0x89,0x45,0xFB, +0xC0,0x82,0x1B,0x8C,0x48,0x73,0xE5,0x17,0x67,0xF1,0x42,0x31,0x42,0xE8,0x08,0x33,0x19,0x3B,0x58,0xBA, +0x68,0x54,0x76,0x5F,0x3E,0x13,0xA2,0xD7,0xCB,0xE5,0x9E,0xBC,0xA4,0xD1,0x28,0x29,0xF1,0xB2,0xB4,0xDB, +0xA7,0x46,0x7E,0xFC,0x54,0x56,0xF8,0xCC,0x7A,0x39,0x66,0x9A,0xCA,0x8E,0x98,0x09,0xF0,0x5B,0xD3,0x2C, +0xAB,0xA9,0xB7,0xA5,0x05,0x16,0xAA,0x8D,0x2E,0x0D,0xB5,0x13,0x0E,0xB6,0x7F,0xBB,0x21,0x56,0x38,0xCD, +0x10,0x92,0x7E,0x33,0xA5,0xA1,0x61,0x5B,0xDB,0x93,0x4E,0xD1,0xE7,0xDA,0x26,0x68,0x05,0x27,0x54,0xDA, +0xB9,0x15,0xB0,0x42,0xD0,0xCB,0x5E,0xFA,0x2B,0xE0,0x1E,0xF8,0x15,0x86,0x5D,0xCB,0x19,0xE3,0xA1,0x3C, +0x78,0x7E,0x55,0x29,0xAA,0xC5,0x7F,0x4E,0x85,0x3E,0x49,0xA6,0x71,0xC0,0x91,0x46,0xAB,0x90,0x4D,0x03, +0x18,0xC2,0xDB,0x79,0xFF,0x9C,0x48,0x84,0xF8,0xC1,0x7F,0xBC,0x12,0xBB,0x6E,0x2D,0x40,0x8E,0x8A,0x97, +0x17,0x4F,0x84,0x50,0x86,0x55,0x96,0x1F,0x98,0x07,0xE7,0x32,0xC6,0xCF,0xA0,0xB3,0x88,0x9C,0xCD,0x83, +0x78,0xA2,0x0B,0xA7,0xC4,0x72,0x50,0x83,0x12,0x7D,0x15,0x45,0x6B,0x6D,0xCB,0x0C,0x4B,0x28,0xAE,0xD7, +0xD9,0x78,0xD9,0x0C,0xE1,0x7F,0x16,0xC7,0x26,0x32,0x39,0xD0,0x00,0x44,0x83,0x18,0xA3,0x78,0x66,0x4B, +0xAD,0x80,0x5B,0x1C,0x83,0x18,0x52,0xBA,0xB7,0xCA,0x5A,0x49,0xFB,0x0A,0xDC,0x09,0xE4,0x68,0x5F,0x41, +0x3C,0x40,0x6B,0xC7,0x95,0x86,0x4E,0x28,0x4B,0x72,0x4B,0xD3,0x7A,0x69,0xCE,0x38,0x02,0x23,0x30,0x55, +0x60,0xCB,0xDF,0xA6,0x77,0xE7,0x6C,0x93,0x81,0xDC,0x79,0x86,0x37,0xA7,0x44,0x0E,0x67,0x0E,0x8C,0xF3, +0x9B,0xEA,0x8D,0x71,0xB5,0x42,0x72,0xDA,0x09,0xE5,0x74,0x84,0x0D,0x7D,0xC4,0x74,0x3F,0x44,0x08,0xC5, +0xCF,0x81,0xFF,0x26,0x09,0xED,0xA3,0x54,0x75,0x76,0xFA,0x59,0xB8,0xE6,0xB7,0xDA,0x6F,0xC8,0xCC,0xAB, +0xAB,0xCE,0xCC,0xEA,0x57,0xFB,0x2C,0xB9,0x56,0x26,0x1B,0x59,0x7A,0xAE,0x56,0x1B,0x40,0x16,0x23,0x42, +0xE9,0x97,0x4A,0xC4,0xD6,0x1D,0xD1,0x0C,0xB5,0xDC,0x5A,0xE4,0xCA,0x78,0x33,0x4C,0xE8,0xC1,0xB4,0x51, +0x13,0xE3,0x55,0x98,0xE3,0x70,0x7A,0xB8,0xCD,0xEE,0x00,0xAD,0x9E,0xC1,0xC0,0x5C,0xEA,0x1A,0xCB,0xE9, +0x5F,0x24,0x56,0x74,0xB5,0x9A,0xAA,0xD3,0xE8,0xCC,0x8A,0xFF,0x49,0x10,0x03,0xF9,0x5E,0xF5,0x18,0x84, +0xA0,0xEF,0x74,0x1C,0xDF,0x6B,0xC1,0x6D,0xD5,0xA6,0xCB,0xE5,0xA6,0xE0,0xCB,0x5E,0x74,0x2C,0x9B,0xB6, +0xAA,0x93,0xAA,0xB3,0x17,0x1F,0x5E,0x58,0x64,0x11,0x13,0x32,0x79,0xB7,0x25,0x41,0x27,0xD4,0xDC,0x85, +0xB8,0xF0,0x3D,0xB7,0x19,0xBC,0x0C,0xF9,0x29,0x8F,0x9A,0x92,0x28,0x9F,0xAA,0xE5,0x38,0x45,0x5D,0xF7, +0xD8,0xDE,0x12,0xCC,0x28,0x0E,0x44,0xD2,0xAB,0x29,0x87,0x98,0xC7,0x68,0xB0,0x67,0x68,0x5E,0x43,0x4A, +0x70,0xB4,0x6E,0x2A,0x33,0x91,0x5E,0xC9,0xDB,0x1E,0xBC,0xE2,0x94,0x68,0x7C,0x43,0xBF,0xC6,0x82,0x3D, +0x53,0x9D,0x4A,0xBC,0x6B,0x62,0xB2,0x18,0xC4,0x57,0x23,0xD8,0xC8,0xB4,0x2F,0xAD,0xC6,0xB7,0xDB,0xD2, +0xDC,0x32,0x65,0xF2,0xBD,0x2A,0x5D,0xE4,0xC5,0x93,0x4E,0xF5,0x4C,0xD8,0x59,0xFC,0xEA,0x67,0xA1,0x48, +0x48,0xDB,0x5A,0x3D,0x51,0xF0,0x50,0x0C,0x46,0x3F,0xCD,0x64,0x19,0x6D,0xE1,0x00,0x5E,0xEB,0x01,0xF9, +0xB7,0xB0,0x59,0x1C,0x4D,0x49,0x9D,0x14,0x47,0x37,0xB0,0x8A,0x9B,0x76,0x33,0xB0,0xD1,0xBB,0xAF,0x6A, +0x6F,0x1B,0xE5,0x80,0xF6,0xBA,0x87,0x8B,0x12,0x9D,0xF7,0xBB,0x21,0xB2,0x7E,0xCF,0xD8,0x7C,0xE2,0x88, +0xAC,0xE8,0xDA,0x71,0x6F,0xAC,0xCE,0xC9,0x81,0xBE,0x6F,0xA4,0x44,0x92,0x4B,0xDA,0xB8,0xAB,0xFC,0xF8, +0x7F,0x20,0x56,0x5C,0xF8,0xDA,0x65,0x33,0xEA,0x9A,0xC4,0xC0,0x66,0x15,0xC8,0x2C,0x3C,0xD4,0x77,0x5A, +0x61,0xE1,0xEE,0xE9,0x4C,0x1F,0xBF,0x41,0x44,0x44,0x60,0x9B,0xAF,0x0F,0x3F,0x07,0x6A,0xBD,0xDF,0x16, +0x24,0x1B,0x96,0x80,0x54,0x76,0x50,0x1F,0x48,0x2C,0xA8,0xC4,0x10,0xCD,0x32,0xE3,0x6D,0x1A,0xD1,0x01, +0x35,0x6C,0xBF,0xA7,0xA0,0xEE,0xC1,0x22,0xF6,0x7A,0x59,0x67,0xA1,0x11,0xB9,0xFB,0x3C,0x2F,0x39,0xE3, +0x14,0x84,0x89,0x45,0x90,0xEF,0x42,0x77,0x7E,0xAE,0x72,0x1D,0x34,0xDC,0x7F,0xC0,0x03,0x03,0xBB,0x53, +0x10,0xE9,0x38,0x10,0x06,0xAB,0xC7,0x46,0xBF,0x65,0x6A,0x82,0xC0,0x0C,0x14,0x9F,0xFE,0x69,0xEB,0x66, +0xDF,0xE0,0xF6,0x21,0xCB,0x2A,0x05,0x0A,0x9E,0x98,0xA3,0x6B,0xD7,0xB1,0x27,0xB0,0x40,0x46,0x62,0xED, +0x4E,0x15,0x4C,0x83,0x6E,0x04,0xC6,0x9E,0x33,0x05,0x17,0x62,0x87,0xAC,0xFB,0x64,0x32,0xD8,0xF6,0xF5, +0xE0,0xB2,0x7D,0x52,0x7F,0x6A,0x94,0x4F,0xD6,0x02,0xDC,0xEE,0x1C,0x85,0x6C,0x1E,0xA3,0xAD,0x15,0xD3, +0x6B,0xAC,0x9E,0x28,0x2A,0x16,0x31,0xFE,0xB5,0xD4,0x28,0x7E,0xDB,0xDD,0x1B,0xD4,0xD1,0x24,0x96,0x7A, +0xE4,0x03,0x96,0x89,0xDC,0x7C,0x4D,0x1A,0xD8,0xE5,0x2B,0x6A,0x06,0x60,0xB3,0x79,0xD3,0xBE,0xF3,0x39, +0xFA,0x91,0x38,0x22,0x11,0xE0,0x64,0xD5,0x1D,0x26,0x70,0x4C,0x8F,0x1A,0xFC,0xAE,0x34,0xF3,0x32,0x28, +0x64,0xC7,0x7E,0xE9,0x2D,0x6C,0x14,0x57,0x19,0x43,0x1F,0x22,0x79,0x5A,0x5E,0x79,0xB4,0xB2,0x76,0xF9, +0xAC,0x90,0xE2,0x53,0x16,0xBA,0x7C,0x7D,0x98,0x81,0x57,0x8B,0xEE,0x6E,0xC4,0x92,0x2F,0xFD,0x2A,0xF9, +0x5D,0xB0,0xB5,0xF1,0xF8,0x23,0xA4,0x79,0xCB,0xB0,0x1F,0x82,0x2E,0x66,0x94,0x02,0xA0,0x93,0x0C,0xE4, +0xD1,0x3F,0x10,0xE7,0xE1,0x5E,0x3A,0x76,0xD1,0x8F,0x8C,0xD7,0x05,0xEA,0x45,0x76,0xB3,0x79,0x26,0x43, +0xAB,0xFA,0xD4,0x35,0x12,0x7A,0x3D,0xF1,0x14,0x1B,0x31,0x67,0x32,0x7A,0xB6,0x37,0x3C,0xB4,0xAB,0x90, +0x7D,0x84,0x0C,0x0C,0xC2,0x00,0x47,0x77,0x33,0x7B,0x7F,0xB5,0x0A,0x85,0x8B,0x80,0x42,0x3E,0x6A,0xE4, +0xDF,0xA5,0xAC,0xDA,0xF4,0xC0,0x54,0xF5,0x62,0x54,0x6C,0xA3,0xA4,0xAB,0x32,0xD7,0xC2,0x73,0x92,0x46, +0x37,0xB8,0x58,0x98,0x63,0x55,0x86,0x04,0x0F,0xDA,0x3B,0xC7,0x43,0xC5,0x23,0x34,0x78,0x76,0x55,0xD9, +0xE2,0x56,0x65,0x92,0xFC,0xC9,0x36,0xF5,0x48,0x53,0xB3,0xE3,0x58,0xD2,0xDF,0x72,0xE5,0x8C,0x7D,0x87, +0x91,0x22,0x91,0x7B,0xAC,0x95,0xA6,0xEE,0x7B,0xC3,0x68,0x37,0x03,0xEE,0x8E,0xBD,0x84,0x99,0x36,0x66, +0x4A,0x1A,0x75,0x7E,0xBB,0x31,0x25,0xE6,0xB4,0xE4,0x08,0xBE,0x98,0x62,0x55,0x8B,0x43,0x7E,0xFF,0xAA, +0x19,0xB0,0x16,0x5A,0x3A,0x86,0x57,0x50,0x46,0xDA,0x98,0x6A,0x2D,0x96,0x4B,0xFF,0xFA,0xCC,0xB0,0xA7, +0x0D,0xAF,0x45,0x49,0x06,0x7D,0x7C,0x78,0xE3,0xB3,0x98,0xFF,0x2E,0x93,0x17,0x97,0x02,0x51,0xA8,0xEB, +0x83,0x73,0x74,0x68,0x9F,0xB2,0xED,0xC7,0xE3,0x96,0x64,0x48,0x0C,0xF2,0x05,0xFE,0x04,0x95,0xE3,0xED, +0x41,0x5A,0xF5,0x8B,0x28,0xAA,0x45,0x5F,0x01,0x1A,0x50,0xEF,0x61,0x3F,0xEB,0xA3,0x08,0x5E,0x6A,0x55, +0x3C,0x29,0xFB,0x8B,0x65,0x80,0x80,0x56,0xFD,0xC4,0xB6,0x70,0xFB,0xC2,0x37,0xF5,0x90,0x2D,0x95,0xAA, +0xC3,0xD6,0x27,0xC0,0x70,0x6D,0x35,0x74,0xDB,0x93,0x38,0x70,0x75,0xA1,0x85,0x78,0xA1,0x46,0x27,0x6A, +0x53,0xEB,0xB8,0x7D,0x0B,0x99,0xF3,0x4D,0x7F,0xC6,0x61,0xBD,0x3F,0xDE,0xE8,0x25,0x73,0xA0,0x91,0x8D, +0x84,0x13,0x54,0x9F,0x30,0x20,0x38,0x05,0x2F,0xD6,0xB9,0xB3,0xB8,0x3A,0xBF,0x42,0x85,0x8A,0x77,0xB5, +0x92,0x2F,0x70,0x9D,0xB9,0x1B,0x74,0x9B,0xA9,0xA5,0x1C,0x63,0x29,0x2A,0x13,0xA7,0x12,0xA5,0x87,0x72, +0x4F,0xC5,0x54,0xF3,0xD5,0xB0,0x81,0x7C,0xA2,0x0D,0xC5,0xFB,0x6A,0xE2,0x8E,0x62,0xC6,0x39,0x61,0x8F, +0xE4,0xAB,0xC9,0x21,0xE5,0x4B,0xCF,0x22,0x9A,0xD2,0x86,0x8C,0x38,0xC7,0xA3,0x95,0xA8,0xC7,0x15,0x3F, +0xED,0x77,0x59,0xE0,0x91,0x15,0x3A,0x1C,0xBC,0xD8,0x22,0xC3,0x50,0x65,0xD5,0x9E,0x72,0xFE,0xCA,0x5A, +0x12,0xA4,0x52,0xF8,0xCB,0x3C,0x0F,0xBA,0x22,0xF1,0xE3,0xD6,0x60,0x07,0x46,0x75,0x0A,0xEB,0x81,0x10, +0xB3,0xCA,0xCC,0xD2,0xF6,0x31,0x2D,0x2E,0x0D,0xF7,0xE1,0xE1,0x3E,0xAD,0xAB,0xFC,0xCF,0x3E,0x81,0xCC, +0xB1,0xED,0x1C,0x4D,0xAF,0x73,0xB7,0x60,0x2C,0x19,0x8D,0x95,0x4E,0x33,0x4D,0x29,0x94,0x05,0x38,0xAA, +0xFD,0x5C,0x75,0x80,0x90,0xAF,0xA0,0xF5,0x28,0x88,0x6D,0x94,0xFA,0x32,0xF3,0x75,0xEC,0x2E,0x36,0x75, +0xA8,0xEE,0x73,0x6B,0xA9,0x28,0xBB,0x4E,0xBD,0x0D,0x15,0x5D,0x6E,0x0C,0x5C,0x5E,0x12,0xA3,0xA1,0x54, +0xCF,0xCF,0xA1,0xD7,0xA3,0xF0,0x76,0x80,0xCF,0xF4,0xDC,0xE4,0x77,0x4E,0x82,0x51,0x8C,0x7B,0x1A,0x74, +0xD5,0xF9,0x80,0xB6,0xD8,0x9A,0xD4,0xF4,0x76,0x0E,0x9D,0xA8,0xF9,0x65,0x10,0x33,0x92,0xB0,0x1D,0xFF, +0x85,0xD2,0xDD,0xE5,0xF7,0xCD,0x07,0xA7,0x61,0xC4,0x37,0x4E,0x20,0x9F,0x15,0x6F,0x25,0x68,0xD5,0x15, +0xBC,0xD7,0x63,0xBC,0xE1,0x9D,0x51,0x37,0x09,0xD3,0xCF,0xB9,0xF3,0x69,0xB4,0x58,0xCD,0x41,0x2E,0xE3, +0xE8,0x2B,0x55,0x99,0x57,0x16,0x34,0xEA,0xA5,0x9D,0x9B,0xEC,0xC5,0xBB,0x1A,0xFE,0x64,0x37,0xA5,0x0B, +0xD2,0x04,0x27,0xA3,0xBE,0x16,0x12,0xF9,0x40,0x03,0x4F,0x18,0x1F,0xBA,0xAC,0xE4,0x53,0x09,0xB9,0xA1, +0x04,0xD6,0x85,0x51,0x4B,0xF6,0xBD,0x07,0xE2,0x5C,0x05,0x91,0x78,0x71,0x76,0x73,0x6C,0x07,0x9E,0x5E, +0xC1,0xB7,0x57,0x0A,0xBA,0x67,0x1A,0xEC,0xFF,0x0C,0xA5,0xFA,0x29,0xF5,0xF7,0x9C,0x98,0xB2,0xDE,0x85, +0x49,0x72,0x1A,0x28,0xB5,0xBD,0xE7,0x7E,0x9A,0x67,0x37,0x2F,0xD8,0xA9,0xE8,0xAB,0x6F,0xD4,0x17,0xB1, +0x70,0x5E,0xBF,0x5C,0x89,0xF5,0x3D,0x1D,0x70,0x35,0x47,0xBF,0x6F,0xAE,0x59,0xC4,0x3C,0x71,0x06,0x8E, +0x21,0x91,0x3D,0xCE,0x5D,0xC1,0x66,0xD3,0x68,0x17,0xB4,0xAE,0x2E,0xFA,0xE6,0x3F,0x4C,0xBD,0x44,0x20, +0xE3,0xF9,0x40,0xF6,0x17,0x5C,0xFA,0x1C,0x5B,0x70,0x2D,0x14,0x0D,0x98,0x70,0x30,0x4B,0x3D,0xBD,0x6F, +0x89,0x96,0xFB,0xE8,0x5F,0x76,0x17,0x59,0xAA,0x06,0x91,0xD8,0x1E,0xD3,0x6F,0x7F,0x88,0x15,0xA6,0x02, +0x58,0xBE,0xA8,0x21,0x33,0x04,0x5F,0x04,0xE7,0x23,0xB8,0xAA,0xD4,0xD4,0x99,0xD9,0xAF,0xED,0xC8,0xE4, +0x20,0x1A,0x30,0x39,0xEE,0x63,0x59,0xF6,0xD3,0x42,0x22,0xCE,0xA8,0x0D,0xBB,0xFA,0xFF,0x22,0x82,0x98, +0xA3,0xB0,0xB4,0x3A,0xAB,0x36,0x6A,0xDE,0xE3,0x99,0xCF,0x77,0xEA,0x0C,0x57,0xF5,0x48,0xDE,0xFA,0xCA, +0xBE,0x43,0xFA,0xF5,0xCF,0x78,0x78,0x90,0xF9,0x0B,0x46,0x76,0xE6,0x2B,0x08,0x7E,0x3E,0xB0,0x8E,0xDD, +0x5A,0x9F,0xB7,0x22,0xF4,0x8E,0x0C,0x0A,0x1D,0x3B,0x88,0x1F,0x62,0x37,0xB8,0x77,0x4E,0x68,0xD1,0xA9, +0x8C,0x4B,0x98,0x40,0x47,0x4A,0x01,0x7B,0xE8,0xF2,0xD5,0x61,0xDA,0xEB,0x39,0x6D,0x85,0xEE,0xB4,0xAA, +0xF0,0xBA,0x9C,0x02,0xE5,0x36,0xC1,0xF1,0xD5,0x9C,0xD5,0x3A,0xF7,0xDD,0xAD,0x77,0xEF,0x75,0x7A,0xEA, +0xCE,0xBD,0x4F,0x5A,0x21,0x61,0x6A,0x58,0xE7,0x82,0x8A,0x6F,0x9D,0xD6,0x1E,0x7F,0xC8,0x47,0x5A,0x49, +0x6D,0x64,0x7B,0x8D,0xFB,0xFF,0xFD,0x0B,0xF3,0x4E,0x83,0xEE,0xCA,0xBF,0x53,0xDD,0x7F,0xDB,0x0F,0xFB, +0x8F,0xA0,0x67,0x86,0x98,0x8B,0x24,0x6B,0x8A,0x44,0xE0,0x7A,0x07,0x61,0xC1,0x37,0xA9,0x87,0xD5,0xC8, +0x77,0xEF,0x2C,0x6E,0xAB,0xEF,0xA6,0xCC,0x72,0xEC,0xDB,0x2A,0xA8,0x86,0x28,0x87,0x3F,0xF6,0xA5,0x0B, +0x69,0x3C,0x05,0x92,0x5D,0xD6,0xBB,0x75,0x8C,0xE7,0x7C,0xAF,0xC2,0x99,0x07,0x9A,0x46,0x43,0x0C,0xD0, +0x5A,0x2E,0xCC,0x64,0x74,0xDF,0xEF,0xA0,0x1A,0x6D,0x25,0x7F,0x2A,0xEC,0x10,0x79,0xA4,0x6F,0x7A,0xE0, +0xDD,0x19,0xCE,0xC6,0x69,0xEF,0x14,0x62,0xE3,0x16,0x4B,0xA5,0x76,0x30,0xCC,0x60,0x2D,0x17,0xC6,0xF6, +0x64,0x8E,0xB1,0xFE,0x94,0x0D,0x1C,0x01,0x8D,0x42,0x44,0x05,0xCB,0x35,0xBB,0x50,0x71,0x51,0xA2,0x85, +0x7D,0xAF,0x43,0x9A,0xC2,0x30,0xA7,0xE2,0x00,0x7D,0xAB,0x5C,0xEE,0x46,0x23,0xB8,0xC0,0x91,0x5D,0xB1, +0x9F,0x3F,0x84,0x3D,0xCE,0x12,0x54,0xB7,0x26,0x4B,0x2C,0xC4,0xC3,0xCB,0xAA,0xE2,0x93,0xF7,0x2C,0x91, +0xAF,0x18,0x18,0x3A,0xCE,0x59,0x5D,0x8A,0x02,0x51,0x23,0xD0,0xFA,0xB5,0x4D,0x66,0x43,0x19,0xFA,0xE8, +0x0D,0xBB,0xE1,0x83,0x6D,0xD0,0x7F,0x16,0x7E,0x7B,0x47,0xD0,0x00,0x19,0x28,0xBB,0xD2,0x33,0x3F,0xF3, +0xC7,0x51,0xF1,0xE4,0x7A,0x33,0x64,0x89,0x29,0xD8,0xCF,0x88,0x0F,0xC4,0x04,0x57,0x97,0xD5,0xE6,0x6A, +0xD2,0x3A,0x8E,0xBC,0x42,0x10,0x84,0x98,0x9A,0x3F,0x89,0x4B,0xED,0x04,0x3C,0x98,0xD8,0xF3,0xEF,0xAD, +0xC3,0x13,0xE7,0x2D,0xE6,0x37,0x45,0x56,0x1F,0x27,0xCC,0xE3,0xFE,0x81,0x0B,0x1D,0xC8,0x5F,0xDF,0x04, +0xDA,0x1B,0xCC,0x4A,0x65,0x56,0x64,0x5F,0x58,0xF3,0x2E,0x0A,0xAE,0x12,0xBF,0x3C,0xBA,0x2A,0xF9,0x07, +0x97,0x53,0x5E,0xBA,0x0E,0x7C,0x76,0x7C,0xA9,0x1E,0x5E,0xA3,0xB6,0x8B,0x26,0x7A,0xB6,0x62,0xD2,0xAA, +0x51,0x1D,0xE3,0x0B,0x09,0x10,0xCF,0xC8,0x46,0x6E,0x37,0xB6,0x5D,0xE3,0xFE,0xEC,0xA6,0x7E,0x88,0xBB, +0xE8,0xC0,0xC7,0xCD,0x46,0x89,0xE2,0x1B,0x69,0xA3,0xD3,0xAB,0xD9,0x1F,0x71,0x70,0xEF,0xB0,0x9E,0x00, +0xE3,0x1D,0x3A,0x2A,0xAF,0x66,0x32,0x79,0xA5,0x1C,0xAA,0x54,0x5D,0x9A,0xD0,0xE6,0x1D,0xAE,0x8A,0x2D, +0xA9,0x6A,0x98,0xEC,0x88,0x3C,0x78,0xE7,0x63,0xCE,0x5E,0x23,0x16,0x5E,0x6F,0xB8,0xD4,0x16,0x1A,0x5C, +0x01,0x52,0xF2,0xE5,0x00,0xA3,0xC9,0x48,0x76,0x28,0x0F,0x35,0xAE,0x46,0x16,0x13,0x01,0xF0,0x93,0x4E, +0xB7,0x5F,0x2C,0x43,0x10,0x1C,0xE7,0x91,0xCA,0x39,0xA9,0xD3,0xF3,0x6B,0x8A,0xBE,0x07,0x08,0xE7,0xB3, +0x24,0x23,0x26,0x90,0x43,0x40,0xD4,0x52,0x20,0xC5,0xCB,0xBE,0x77,0xFD,0x3B,0xAF,0x32,0xE4,0x09,0x61, +0x63,0x87,0xE9,0x62,0xD0,0x24,0x16,0x57,0xB4,0x0E,0x29,0x0E,0xB8,0xE5,0x6B,0xF3,0x2C,0x83,0xA3,0x19, +0xA3,0xA5,0xCA,0x0E,0x28,0x8E,0xC9,0xEC,0x9E,0x54,0x30,0x6C,0xDE,0x9C,0x15,0x87,0xDB,0x4F,0x80,0x69, +0xAE,0x92,0x1E,0x6D,0x02,0xA6,0x9F,0xA2,0xCA,0xDF,0x63,0x78,0xF7,0x12,0x8D,0xD9,0x2D,0x8C,0x59,0x7C, +0x8B,0xA5,0x10,0x24,0x14,0x61,0x1B,0x89,0xDA,0x11,0x60,0xFD,0x72,0x06,0x16,0x4D,0xB3,0xC8,0x6B,0xA5, +0x36,0x30,0xAB,0xBB,0xD9,0x08,0x4A,0x28,0x8F,0x83,0x69,0x87,0x18,0x6C,0x4C,0x88,0x2C,0xB9,0x6C,0x2A, +0xFF,0x53,0x42,0x98,0x64,0x83,0xEA,0x2C,0x2C,0x29,0x5A,0x89,0xEC,0xDF,0xF8,0x62,0xA9,0x2D,0x4B,0x4C, +0x0F,0xCA,0xAB,0x4F,0x9E,0xAE,0x0D,0x6C,0xEA,0x47,0x4C,0x28,0x04,0xE6,0x2A,0xDF,0x8F,0xCD,0x11,0xB7, +0x27,0xE0,0xC3,0x0B,0x4F,0x69,0x44,0x8F,0xB3,0x3E,0xE4,0x7A,0x44,0xD1,0xDC,0x04,0x16,0x42,0xCB,0xD0, +0x9F,0x92,0x34,0x44,0x50,0xFD,0x80,0xD0,0xA6,0x3A,0xCC,0x36,0x63,0x3C,0x39,0x41,0xE1,0x5C,0xB6,0xB7, +0xD6,0xB0,0xC9,0x03,0x58,0xB2,0x9D,0xD7,0xBC,0xBD,0xEE,0xA0,0x59,0x73,0xFF,0x5C,0x57,0xFF,0xCF,0x93, +0x7D,0x75,0xD5,0x15,0xB0,0x79,0xEC,0x40,0x69,0xDE,0xC5,0x35,0xF0,0x99,0x1C,0x40,0x23,0x5E,0x1B,0xE2, +0x49,0xB4,0x0D,0x91,0x39,0xDB,0xF8,0xB0,0xF8,0xF4,0xAB,0xB0,0x64,0x2A,0x45,0xAC,0xA2,0x18,0x78,0x10, +0x45,0x2A,0x43,0xC7,0xD6,0x54,0x5F,0x21,0x24,0x95,0x75,0x88,0x4F,0xCA,0x15,0xA3,0x5B,0x5D,0xD1,0x3E, +0xF6,0xF6,0x15,0x51,0x85,0x25,0x73,0xE7,0x40,0x16,0x02,0x71,0xE6,0x28,0xC5,0xC7,0xAC,0x58,0x78,0x19, +0x30,0x15,0xFC,0x8B,0x9F,0xFA,0xC9,0x53,0x68,0x98,0x8E,0x7E,0x8B,0xF7,0x89,0xAD,0x46,0x3C,0x71,0xE6, +0x02,0x31,0x93,0x3E,0x02,0xD2,0x2E,0x3C,0x7C,0x9A,0x59,0x19,0x78,0x5F,0x7C,0x6C,0xCB,0x16,0xEC,0xA8, +0x71,0x27,0x8F,0x7F,0x07,0xF5,0xAB,0x6A,0x4D,0xBB,0x95,0x64,0xB9,0x40,0x96,0xC4,0x78,0x86,0xC7,0x3D, +0xF4,0xBF,0x5C,0x28,0xAC,0x98,0xDE,0x30,0xE2,0xB3,0x4E,0xCA,0xCF,0xE3,0x56,0x9C,0x1C,0xE0,0x24,0xC7, +0xAD,0x9E,0xD0,0x3C,0x5D,0xB2,0x45,0xC3,0x69,0x34,0x4A,0x9C,0x84,0x98,0x78,0xA9,0x51,0x12,0xD5,0xFF, +0xBE,0x41,0xE7,0x99,0x15,0x55,0x89,0xE8,0x5F,0x61,0xAA,0x39,0xAB,0x44,0xC0,0xA0,0x66,0x20,0xAD,0x99, +0x84,0xD0,0xC7,0x01,0x53,0xF2,0xFF,0xE8,0x25,0x40,0x75,0x76,0xB3,0x26,0xB0,0x62,0xC3,0xEB,0x6B,0x00, +0xDD,0xDD,0x10,0x1C,0x43,0x08,0x73,0xF6,0xB0,0xAB,0x69,0xF2,0xC2,0x4F,0x63,0x10,0xB0,0xFE,0x83,0x39, +0x7D,0x80,0x89,0xAB,0x31,0xA8,0x79,0xA1,0xC6,0x88,0x76,0xDA,0x21,0xB4,0x0E,0x21,0x85,0x08,0x0E,0xF7, +0x13,0x2B,0xB9,0xF3,0x4D,0x4D,0xDE,0x4A,0xA9,0xCC,0x53,0xC4,0x33,0x2F,0xA0,0x05,0xEB,0x29,0xC0,0x3F, +0x23,0x24,0x06,0x22,0xF0,0x2A,0x93,0x50,0x70,0x05,0xF0,0x84,0xE4,0x67,0x62,0xC0,0x65,0xB1,0x07,0x64, +0x55,0x25,0xD1,0x0E,0x7B,0x7A,0x8B,0xBB,0x31,0x43,0xFE,0x13,0xBE,0xB9,0xA5,0x41,0x57,0x41,0x16,0x4C, +0x85,0x67,0x5F,0x5E,0xB7,0x8C,0xF9,0x82,0x4F,0xFA,0x0F,0x33,0x71,0x29,0xC2,0x0C,0x75,0x28,0xF3,0x72, +0xBB,0x4D,0x6A,0xEA,0xE9,0x0B,0x32,0x5E,0x2E,0xC7,0xCD,0x73,0x2B,0x4B,0x10,0xEC,0x99,0x66,0x62,0xBA, +0x48,0x0E,0xA5,0xDC,0xF2,0x95,0x13,0x8D,0xD8,0x4A,0x3C,0xEF,0xBC,0x31,0x73,0x69,0x66,0xC7,0x37,0x4F, +0xA8,0xF5,0x89,0x9D,0xB9,0x0B,0x8A,0x6F,0x3E,0x30,0x23,0x69,0xC1,0x44,0xA0,0x62,0xFD,0x70,0x62,0x37, +0x36,0xF3,0xBA,0x48,0xFA,0xAD,0x2A,0x4C,0x4C,0xF4,0xA6,0x48,0xBB,0x77,0x74,0x54,0x86,0x8B,0xB2,0xEC, +0xAD,0x82,0x01,0x7B,0x30,0x41,0x20,0x94,0x1D,0x22,0x78,0xF5,0x7D,0x4F,0xD2,0xBE,0x1E,0x83,0x2C,0x86, +0x7E,0x41,0x50,0x8B,0xE9,0x05,0x4D,0x99,0x87,0x82,0x6F,0x79,0xA8,0x64,0x84,0xF3,0xBC,0x3B,0x4B,0xF9, +0x90,0xF3,0x94,0x04,0x75,0x79,0x20,0xF6,0x93,0xC0,0x6C,0x22,0x61,0xD7,0xB4,0x36,0xF8,0x78,0xDC,0xD2, +0x5A,0x13,0xB2,0x9D,0xBC,0x97,0x64,0x94,0xE4,0x76,0x0C,0x73,0x73,0x84,0x5B,0x20,0x28,0xB9,0x72,0x05, +0x0D,0x73,0xAE,0x43,0x4C,0xAF,0x15,0x62,0xD4,0x1E,0x56,0x3E,0xA7,0xAB,0x0C,0x55,0xE1,0x71,0xC2,0xA0, +0xE7,0x13,0x99,0xF2,0x70,0x7D,0x26,0xC2,0x23,0x54,0xA3,0x3B,0x16,0x58,0x56,0x02,0x46,0x16,0x63,0xCC, +0x76,0x3F,0xAB,0x2F,0xC2,0xC3,0x6B,0xD2,0xE7,0x51,0x87,0x5F,0x65,0xA6,0x74,0xF8,0x75,0x6D,0x65,0xD4, +0x2F,0x9B,0xFA,0x5A,0x4D,0x77,0x0A,0x74,0x9D,0x54,0xF3,0x45,0xE6,0xD6,0xB6,0xF5,0x2C,0x15,0x70,0xB5, +0xF7,0x45,0x9E,0x75,0x8A,0x97,0xDD,0xD1,0xBB,0x07,0x79,0x9B,0x8B,0x50,0xDD,0xFF,0x3E,0xC3,0xC0,0x55, +0x24,0x16,0x29,0x0C,0xD9,0xD8,0xBD,0x39,0x2D,0xE0,0x4E,0x60,0x9C,0x99,0xE7,0x7E,0xCB,0x1C,0x1D,0x7E, +0xFA,0x3F,0x79,0xCC,0x54,0x59,0x94,0x09,0x9B,0x55,0x67,0xEF,0x4A,0xA4,0x10,0x12,0xF8,0x5A,0xE4,0x5E, +0xAB,0xEE,0x8A,0xB9,0x3B,0x33,0x6D,0x3F,0xB3,0x17,0x28,0x99,0x18,0x84,0xF1,0xC9,0xA7,0x10,0xF9,0x2E, +0x96,0x38,0xD6,0x99,0xF2,0xD1,0xB6,0xBF,0xC4,0x71,0x4A,0xD8,0xA8,0x13,0x43,0x2C,0x37,0x32,0xA4,0x7A, +0x6A,0x2A,0xCC,0xE9,0x48,0x68,0x2F,0xC9,0xC1,0xFA,0x39,0xE9,0x38,0x36,0x29,0xE0,0xD9,0x15,0xD5,0x0F, +0xDE,0x83,0xAF,0xE6,0x8F,0x73,0xAF,0x9D,0xAE,0xB2,0x27,0xE9,0x48,0x11,0x27,0xD9,0x79,0x77,0xE0,0xE6, +0x0C,0xC1,0xBA,0xF6,0x6B,0xEF,0x08,0xF2,0x18,0x48,0xD0,0x50,0xD9,0x66,0x62,0x0F,0x24,0x83,0x92,0xFE, +0x42,0xEE,0x48,0x4C,0xE6,0xA4,0xD8,0x40,0x11,0xA3,0x78,0xDE,0x21,0x7D,0xA0,0xF7,0x6B,0xED,0x01,0xC1, +0x46,0xCA,0x72,0xE7,0x84,0xF9,0xEE,0x6C,0xC6,0x73,0xF0,0xDF,0x32,0xE2,0x86,0xD1,0xE1,0xC5,0x66,0x2A, +0x20,0xEC,0x40,0x56,0xEF,0xD4,0x5A,0xB8,0xFF,0xF4,0xF0,0x92,0xBC,0xC8,0x2F,0x92,0x21,0xA4,0x97,0x76, +0x34,0xD0,0x28,0xBB,0x1E,0xE4,0xD8,0xF6,0x38,0x19,0xF0,0xD1,0xF6,0x1A,0x73,0xAC,0x0B,0xE4,0x42,0xA5, +0x76,0x19,0x49,0x21,0x4A,0xCA,0x71,0x9F,0x21,0xE0,0xD1,0xBD,0x97,0xCA,0x89,0x13,0x13,0x2A,0x11,0x75, +0x44,0xA3,0xC3,0x95,0x2A,0xE8,0x3A,0x1B,0x67,0x81,0x98,0xF1,0xE1,0x29,0x3A,0x9D,0xAD,0xC7,0x06,0x51, +0xFF,0xA9,0x4A,0x50,0x30,0x86,0x7A,0xE4,0xE4,0x20,0x70,0xC4,0xEE,0xC4,0xE3,0xB9,0xF8,0x6F,0x27,0x09, +0xC4,0x07,0xB0,0xF4,0x7D,0x29,0x53,0x6B,0x2A,0xC7,0xA3,0xBB,0xDE,0x84,0x72,0xC6,0x70,0xC4,0x2F,0xEC, +0x19,0x3F,0x71,0x26,0x8C,0xC3,0xA8,0xB7,0x78,0x62,0x9F,0xB3,0x0C,0x17,0x9A,0xCC,0x38,0xE4,0x1A,0x08, +0x68,0xCA,0x62,0xEC,0x57,0x31,0x18,0x5E,0x6C,0x3A,0x31,0xBE,0xE2,0xC3,0x02,0xFE,0x7A,0xCC,0x6C,0x75, +0x7B,0x19,0xD6,0xB6,0x3F,0x55,0x9B,0x68,0x3D,0xEE,0xFB,0xB6,0xAD,0xAE,0xCB,0x3F,0xD6,0xAC,0xC7,0x25, +0xEE,0x8B,0x8C,0x1F,0xDF,0x52,0x1B,0x3F,0x43,0x44,0xEA,0xFB,0xE0,0xF2,0x20,0xC5,0xA5,0x9E,0x12,0xE4, +0xC3,0xB6,0x44,0x82,0x3E,0x1D,0xEE,0x40,0x08,0xB2,0xA9,0x62,0x29,0x60,0x4F,0xD1,0xEB,0xB9,0x6C,0xA6, +0x7D,0x5A,0x10,0x33,0xD6,0x01,0x9A,0x53,0xA8,0x9B,0xAD,0xB0,0x15,0xDE,0xA5,0x21,0xC6,0xC0,0x2B,0x8B, +0x55,0x2D,0xD2,0xE1,0xD3,0x4C,0x29,0x50,0x35,0x93,0x08,0x51,0x49,0x58,0x4A,0xBB,0x5E,0xB3,0x39,0x32, +0xCB,0x8F,0x9C,0xE2,0xB4,0x48,0xC5,0xC6,0xE4,0xD7,0x48,0x99,0xD5,0xB5,0xED,0x30,0xC7,0x2A,0x23,0x3B, +0x3F,0xF5,0x83,0x09,0xE5,0xD6,0x03,0x09,0x88,0x0A,0xBD,0x55,0xE4,0x32,0x9F,0xB5,0x15,0xC2,0xF1,0x91, +0x45,0xD5,0x0A,0x18,0x09,0x09,0xAD,0x3E,0xAE,0xD6,0x34,0x88,0x35,0x4B,0xF9,0x03,0xEF,0xD8,0x02,0x08, +0x08,0x08,0x89,0x5A,0xDF,0x64,0x0A,0x4E,0x9F,0xF9,0x06,0x48,0xEC,0x38,0x6F,0x5D,0x7A,0x63,0xBE,0xD8, +0x8C,0x95,0xCD,0xDE,0x71,0x44,0x64,0x9A,0xCE,0x9E,0x3B,0x2F,0x65,0xBB,0x4F,0x49,0x2A,0x6F,0x4B,0xF0, +0x66,0x67,0x6D,0x80,0x4F,0xBF,0x89,0xDC,0xE4,0xF1,0x57,0xD9,0x21,0x97,0xC8,0x60,0x48,0x2D,0xBD,0x9F, +0x6F,0xD3,0xE2,0x6F,0xFB,0x00,0x06,0x8E,0x55,0x17,0x9C,0x3E,0x36,0xB3,0xE6,0x98,0x99,0x20,0x09,0x11, +0x81,0x03,0x64,0x5E,0x6B,0x97,0x37,0x81,0xBA,0x9A,0xBE,0x06,0xE7,0x0D,0x01,0x01,0x80,0x02,0xE7,0x29, +0x2C,0xDD,0xC1,0x1A,0xE1,0xFE,0xCC,0xB4,0x0F,0x61,0x08,0x10,0x01,0x01,0x29,0x0A,0xE4,0x35,0x30,0xCB, +0xB9,0xFF,0x8C,0xD6,0x0C,0x9E,0x00,0x00,0xA7,0x33,0x80,0x05,0x76,0x8D,0xDE,0x85,0xB1,0x8B,0x52,0x92, +0x14,0x40,0xCE,0xA1,0x58,0xCB,0xAC,0x72,0x40,0x81,0x90,0xE5,0x5B,0x21,0x24,0xB2,0x41,0xA7,0xC6,0xB5, +0xD3,0xCA,0x7F,0x19,0x02,0x2A,0x41,0x05,0xFB,0xA0,0x19,0x24,0xC4,0x62,0x90,0x05,0x50,0x48,0x71,0xEC, +0xC1,0x41,0xD7,0x1D,0xB1,0x88,0x47,0xD3,0xCD,0xC6,0x59,0x35,0xBA,0xE1,0x7E,0x48,0xC0,0x06,0x3F,0xBA, +0x14,0xE4,0x46,0xF1,0xA9,0xE6,0xF9,0x23,0x7C,0xE8,0xFB,0xC0,0x05,0xA5,0x08,0x40,0x82,0xA8,0x1A,0x03, +0x5F,0x4C,0xF1,0x73,0x52,0xE5,0x49,0xC5,0x7E,0xA4,0xD4,0xC1,0xD6,0xBB,0xEA,0xD0,0x80,0xE9,0x9B,0x78, +0x93,0x67,0x05,0x23,0xEB,0xA5,0x36,0xD1,0xD7,0xD2,0x2F,0xF3,0xCA,0x3A,0xA3,0xA1,0x53,0x47,0x80,0x6A, +0x73,0xDA,0x87,0x0C,0x9A,0x20,0x3C,0x2F,0x20,0x47,0x82,0xDD,0x12,0x68,0x7A,0x5E,0xF5,0x4B,0xEA,0x5C, +0x0C,0x26,0x1A,0x7B,0x4D,0x49,0x9B,0x1C,0xD9,0xA8,0xDC,0x08,0x8E,0x8A,0x0E,0xFD,0x90,0x25,0x3D,0x2E, +0xE7,0x0A,0xCD,0xA8,0xD0,0xC1,0x89,0x63,0x0B,0x23,0x0B,0x1C,0x30,0x80,0xF1,0x3D,0xC9,0xE4,0xC5,0xBC, +0x5B,0xC0,0xBD,0x3B,0x48,0x8F,0x02,0x5D,0x8D,0x6E,0x08,0x75,0xE9,0x4A,0x58,0x9A,0x85,0xE1,0x74,0x54, +0x6A,0xED,0xB5,0xA6,0xE4,0xF2,0xDA,0x9A,0xEA,0xB2,0xD8,0x74,0x59,0x6C,0x03,0xB7,0x0A,0x5E,0x41,0xF7, +0x7B,0x51,0x5F,0x07,0x6B,0xC6,0xF3,0x60,0xD2,0x2E,0x53,0x4C,0x77,0xAD,0x0B,0x4D,0xB1,0xA2,0x11,0x78, +0x28,0xC5,0xD3,0x7F,0x59,0x8F,0xBF,0xE2,0x61,0x50,0x03,0x75,0x3A,0x36,0xBA,0x51,0x6A,0x5C,0x95,0x84, +0x1B,0x40,0x74,0xE3,0x71,0x18,0xCE,0x1E,0x5A,0x93,0x62,0x20,0x8A,0xF3,0xD8,0x36,0x1A,0x33,0x7D,0xE3, +0xE3,0xCD,0xDB,0x01,0xB0,0x99,0x4B,0x25,0xE0,0xDF,0x95,0xA7,0xB2,0xD9,0x4C,0x6C,0xC7,0x51,0x8D,0x64, +0xA1,0x23,0x43,0xB9,0xC1,0xFC,0x9D,0x44,0xB3,0x7D,0x3A,0xCD,0xAD,0xB9,0x04,0xD0,0xC3,0x2F,0x6C,0xB0, +0x66,0x5B,0xEE,0x63,0xDE,0x2B,0x4D,0x42,0x23,0x1D,0xB3,0x56,0xB3,0x35,0x26,0x20,0x6B,0x8A,0xE6,0x73, +0xDF,0x69,0x40,0x53,0x22,0xBB,0x3A,0xB7,0x55,0x28,0x6D,0x1E,0xA1,0x76,0xEF,0x62,0x5E,0x69,0x09,0x20, +0xB7,0x13,0x12,0xD5,0xC4,0x3D,0xE2,0x21,0x14,0x8F,0xF3,0xF3,0x62,0x2B,0x84,0x62,0x57,0x10,0xD8,0x85, +0x38,0x78,0x13,0x2A,0x69,0x20,0xC8,0x3D,0x78,0xF5,0x70,0x1A,0x28,0xFE,0xEE,0x6D,0x3F,0x39,0x26,0x49, +0x6F,0x59,0xDE,0x4F,0x61,0x7F,0xDC,0x8D,0xAE,0xBA,0x83,0xEE,0xD3,0x18,0x37,0x3D,0x83,0x78,0xE9,0x28, +0x93,0x6A,0x55,0x98,0x0A,0xB4,0xD1,0x0D,0x19,0x90,0x41,0x29,0xC9,0xF0,0x97,0xF0,0x9A,0x1B,0x1C,0xCA, +0x42,0x2C,0xFC,0x2E,0x96,0xC2,0x2E,0x19,0x3A,0x7C,0xF8,0xEB,0xEF,0x73,0x18,0xD0,0xC0,0x0D,0xFE,0x62, +0x50,0x09,0x26,0x8B,0x3B,0x56,0xF7,0xB2,0xB2,0x19,0x39,0xC0,0xC9,0xE1,0xBC,0x13,0x0D,0x95,0x37,0x29, +0x24,0xD3,0x63,0xA7,0x33,0x3A,0x6F,0xCD,0x63,0x2F,0xCF,0x2C,0x33,0xC0,0x24,0x99,0xBC,0x54,0x76,0x22, +0x42,0xA1,0x9D,0xF2,0x58,0x8F,0xE4,0x84,0x7F,0xE2,0xB0,0x23,0x44,0x80,0x70,0x26,0x3F,0x62,0x22,0x16, +0xA6,0x8C,0xF6,0x87,0x15,0x0A,0x68,0x36,0x4D,0xE9,0xE6,0xB3,0x5D,0x4A,0x41,0x42,0x31,0x8F,0xA1,0xF6, +0xD6,0xA6,0x35,0xBE,0xC0,0xE2,0xB9,0xD6,0x9E,0xE2,0xD6,0xC3,0x8D,0x0C,0xA8,0x97,0x15,0xA2,0xB9,0x32, +0x82,0x83,0xB8,0x17,0x55,0xA1,0xD3,0xD2,0x00,0x24,0x1D,0xBD,0xE5,0x5B,0x74,0x9C,0xBB,0x4E,0xF2,0x14, +0x21,0xC4,0x32,0x4F,0xA4,0x83,0xD2,0xB9,0xEC,0x3A,0xF0,0x4E,0xA6,0xCA,0x07,0xA6,0x29,0xE6,0x2D,0xC1, +0x8F,0xFB,0x1A,0xC3,0x9A,0xCB,0x8A,0x3F,0x65,0xC0,0x15,0x07,0x24,0x83,0x65,0x3D,0x26,0x0F,0x16,0xA9, +0x91,0x27,0x19,0x33,0xDA,0x4C,0xC7,0x7E,0x94,0x15,0x68,0x0B,0xFB,0x75,0xFC,0x8F,0x9E,0x03,0x36,0x5A, +0x48,0xE8,0xEC,0xAF,0xDE,0x43,0x4A,0x5B,0xF0,0x02,0xCA,0xEF,0x57,0xA9,0xBA,0x3B,0x9F,0x89,0xA2,0xCF, +0x17,0xE9,0x69,0xF5,0xD9,0x85,0x63,0x0F,0xF7,0x28,0x6D,0x2F,0xC4,0xDE,0x73,0x2F,0xB7,0x68,0xAC,0xF9, +0x0F,0xA3,0xF5,0x17,0x8D,0xAF,0x3F,0x99,0xC9,0xEB,0xE5,0xBA,0xD5,0x40,0xE2,0xA8,0xAF,0x73,0x3A,0x3C, +0xE1,0x73,0xF6,0x88,0xCC,0xC4,0x09,0x1C,0xD0,0x89,0x6E,0xA4,0xF2,0x07,0x68,0xDE,0x19,0x6D,0x76,0x05, +0x2C,0x3D,0xB0,0x3C,0x37,0xE0,0x29,0x4A,0x6D,0x04,0x23,0x5E,0x95,0xEC,0xFA,0x19,0x6D,0xC8,0xEB,0x6E, +0x8A,0x12,0x90,0x07,0x2C,0x02,0x63,0x7B,0x1A,0x5A,0x03,0xF9,0xC6,0x12,0xE3,0x55,0xDE,0xF8,0x55,0x44, +0xD4,0xDE,0xE2,0x86,0xB4,0xD3,0x72,0xA2,0x0F,0xC0,0xCC,0x24,0x7D,0x8D,0x76,0x93,0x86,0x97,0x6C,0x96, +0x5E,0x33,0x5C,0xF2,0x78,0x5C,0xB0,0xD8,0xD4,0x79,0x92,0x01,0xA1,0x63,0xFB,0x06,0x36,0x19,0x25,0x52, +0xFC,0xD2,0xEF,0xBA,0x57,0xF4,0xA5,0xAF,0x06,0x95,0x85,0x66,0xFF,0xB3,0x45,0x31,0xE4,0x8B,0x3D,0x55, +0x54,0x0C,0xE5,0x33,0x3A,0xB4,0x64,0xC3,0xE0,0xF4,0x3F,0x0D,0x9D,0x2B,0x4A,0xE4,0x80,0x20,0x5F,0x42, +0xDB,0xD7,0x58,0x3C,0xD6,0xD3,0xBC,0xE6,0x44,0x97,0x7B,0xED,0x75,0xBB,0xD0,0xCF,0x5E,0x34,0xE5,0xC2, +0x57,0xD0,0x8E,0x67,0xA2,0x58,0xF2,0xF8,0xA2,0x62,0xDE,0x52,0xA1,0x17,0x59,0x97,0xBB,0x78,0x7B,0x0A, +0x98,0x87,0x8B,0xB1,0x51,0xBB,0x6E,0x1D,0x8D,0x91,0xF8,0x86,0x3E,0xBC,0x34,0x48,0x68,0xF8,0xFC,0xAF, +0x9F,0x72,0x16,0x69,0x39,0x14,0xF0,0x1A,0x3D,0x34,0x60,0x3E,0x6D,0x72,0x45,0xE2,0xDE,0x97,0xDE,0x09, +0xAF,0x7C,0xA8,0x7E,0xB6,0xBC,0x0B,0x5A,0xE6,0xD6,0xB3,0x51,0x01,0x70,0x51,0x1E,0x44,0xCB,0xD1,0x0F, +0x56,0x19,0x7D,0xFB,0x6D,0xEB,0x81,0xB6,0x3F,0xFB,0xBE,0xF5,0x3A,0x47,0xC6,0xCF,0x99,0xAC,0xB6,0xFE, +0x79,0x9E,0x82,0x13,0x40,0xBE,0x10,0x5E,0xDA,0x3E,0xD4,0x59,0x93,0xA2,0x7E,0x7E,0x2B,0x79,0x3E,0xEA, +0x83,0x08,0x67,0xB4,0xC6,0xDC,0x08,0x3D,0x3E,0x8F,0xF5,0x65,0xE8,0xDE,0x75,0xD0,0x02,0x9C,0x2B,0x28, +0xA5,0x62,0xA5,0xCA,0xDF,0x2F,0xBF,0xEA,0x3D,0x52,0xF8,0x7B,0xBB,0x0A,0xB7,0x1C,0x06,0xC0,0x24,0x66, +0x33,0x40,0x63,0x66,0xEA,0xBB,0x94,0x63,0xD2,0x68,0x78,0x56,0xA3,0xFF,0x68,0x1C,0x33,0x31,0xAF,0xB5, +0x47,0x81,0xBE,0xEF,0x05,0xC5,0xB6,0xFC,0x90,0x4C,0x6D,0x07,0x98,0x4E,0x91,0xA5,0x84,0xB7,0xA0,0x47, +0x3B,0xD2,0xF0,0x57,0x6B,0xA7,0x8C,0x06,0xDF,0x67,0xAE,0x0E,0x9D,0x01,0x72,0x28,0x19,0x9D,0x38,0x22, +0x41,0xF4,0x2F,0x36,0xB1,0x65,0xE3,0x79,0xBE,0x94,0xD0,0x64,0x52,0x64,0x40,0xE2,0xF6,0x0A,0xB0,0x73, +0x37,0x25,0x5C,0x37,0xC1,0x4D,0xD8,0x74,0x53,0x65,0x4B,0x01,0x21,0x00,0xC5,0x65,0x92,0x26,0xC1,0xA6, +0xC0,0xB3,0xD1,0x65,0xD2,0x66,0xFD,0x2E,0x20,0x46,0xC9,0x55,0x93,0x27,0xEB,0x13,0x28,0xF7,0xD9,0x75, +0xD3,0x67,0x42,0x0E,0xC0,0xF8,0xA4,0x98,0x94,0xA3,0x90,0x17,0xB4,0x4A,0xD2,0xAA,0xA4,0x9D,0x08,0xDE, +0xAB,0x4C,0x71,0x3A,0x09,0xA4,0x99,0x3E,0x81,0xF9,0x19,0x06,0x01,0x28,0xA7,0xF5,0x08,0xF1,0x87,0xEF, +0x9E,0xEA,0xD3,0x3D,0x34,0xEE,0xD3,0x13,0x84,0xDF,0x79,0xBC,0x2D,0xEC,0x5F,0xE2,0x1A,0x25,0xBF,0x5B, +0x65,0xB4,0x77,0xBD,0x25,0x4B,0xAA,0xFB,0x8F,0x4B,0xC2,0x4C,0x1A,0x2C,0x74,0xB7,0x1E,0x0A,0xD2,0x6C, +0x5A,0x6C,0x3E,0xA5,0x2A,0x4F,0xCA,0x5C,0x1B,0x2D,0xD9,0x5C,0xC4,0x4F,0xDA,0x7C,0x5B,0x6D,0x83,0x5D, +0x78,0x42,0xC3,0x4D,0x9A,0x2E,0xE4,0x57,0x92,0xBB,0xD3,0x6D,0xDA,0x6E,0xC9,0x66,0x0E,0x08,0xCB,0x5D, +0x9B,0x2F,0xEC,0x78,0x46,0x49,0xDB,0x7D,0xDB,0x6F,0x80,0x04,0x64,0xE5,0x0C,0x86,0xC5,0x3F,0x74,0xE4, +0x6F,0x5D,0xBC,0x66,0xF2,0x78,0xBB,0xAF,0x79,0x53,0x48,0x11,0x72,0xC2,0x94,0xC8,0x80,0x5E,0xFC,0xF4, +0x8A,0x7C,0x3F,0x7E,0xA6,0xD2,0x31,0xFA,0x13,0x8F,0x5F,0x7E,0x43,0x54,0x7A,0x55,0xA8,0x7D,0x8F,0xAE, +0x5D,0xC3,0xED,0xD1,0x8C,0x3C,0x7D,0xF5,0xD8,0x5C,0xEF,0xAC,0xB1,0x88,0x3C,0xE4,0xA7,0x33,0xC4,0xC4, +0x32,0x34,0x94,0xF4,0x9E,0x18,0xD4,0xE4,0x72,0x74,0xFB,0x2D,0x33,0x5B,0xCC,0xD4,0x33,0x35,0xF4,0x53, +0x1C,0xD5,0xDC,0xF4,0x73,0x75,0x9A,0xD0,0xA4,0xD6,0xC5,0xC5,0xB2,0x36,0x25,0x27,0x48,0x17,0xD5,0xE5, +0xF2,0x76,0x3D,0xF7,0x41,0x74,0xCD,0xD5,0xB3,0x37,0x9D,0xE5,0x1F,0x1B,0xDD,0xF5,0xF3,0x77,0xC6,0x9C, +0xD4,0xBC,0x16,0x92,0x60,0xCC,0xA2,0x4A,0xEA,0x10,0x92,0xAE,0x7C,0x83,0xAA,0x65,0xA9,0xC2,0x7E,0x18, +0x7D,0xAE,0x66,0xDA,0x2A,0xE6,0x29,0x98,0xFC,0x5E,0x47,0x8F,0x60,0xEA,0x04,0x4B,0x52,0x76,0xDB,0xCB, +0xAB,0x85,0x97,0x6F,0x7B,0x3C,0x0E,0x5F,0x0B,0x5E,0x27,0x3E,0xC6,0x3A,0x67,0xE6,0x1C,0xA7,0x40,0xAC, +0xFF,0xBB,0xEE,0x6A,0xF5,0xF3,0xC6,0xCC,0x3A,0x3C,0x26,0x2E,0xC0,0x1D,0xD6,0xEC,0x7A,0x7C,0xB1,0xFC, +0xA9,0x15,0xCE,0xDC,0x3B,0x3D,0xF2,0xBA,0xE8,0x53,0xDE,0xFC,0x7B,0x7D,0xEF,0x6B,0x2D,0x39,0xC7,0xCD, +0xBA,0x3E,0xBB,0x69,0x16,0x7E,0xD7,0xED,0xFA,0x7E,0xF9,0xBB,0x5C,0x19,0xCF,0xDD,0xBB,0x3F,0x37,0x7F, +0x17,0x1E,0xDF,0xFD,0xFB,0x7F,0xF4,0x44,0xA6,0x7E,0x40,0x39,0x30,0x1C,0xF0,0x36,0xB8,0xBE,0x1C,0xA4, +0x55,0x65,0xC3,0x69,0x9A,0xBC,0x2C,0xE7,0xB6,0xA3,0x4C,0xB6,0x0D,0x9F,0xD7,0x2A,0x9D,0x3F,0x5B,0x87, +0xC8,0x92,0x1E,0x5C,0x6D,0x28,0x48,0x65,0x66,0x8C,0x89,0xD4,0x8C,0x46,0x81,0xB1,0x02,0xA4,0x9B,0xE8, +0x17,0xEB,0xF9,0x27,0x54,0x82,0x3E,0x24,0x0A,0xE1,0x88,0xE1,0x00,0x24,0xE0,0x46,0x16,0xA4,0x78,0x50, +0xE7,0x6B,0xF0,0x66,0x56,0xE4,0xF8,0xD0,0x06,0xF2,0xE8,0x56,0x17,0xA5,0x98,0x4D,0xB3,0x75,0xF8,0x76, +0x57,0xE5,0x88,0xC7,0xC2,0x9A,0xE1,0x47,0x96,0xA6,0x76,0x70,0x1D,0x16,0xF1,0x67,0xD6,0xE6,0x53,0xB1, +0x05,0x8F,0xE9,0x57,0x97,0xA7,0xCE,0x6F,0xE3,0x3A,0xF9,0x77,0xD7,0xE7,0xB2,0x14,0x54,0x7C,0x82,0x6C, +0xAB,0xCD,0x99,0x51,0x99,0x35,0x52,0x11,0xA0,0xEA,0x6A,0xDC,0xE7,0xC5,0x13,0x4F,0xBE,0x76,0x62,0x07, +0xCF,0xC1,0x89,0x27,0x79,0x87,0xA0,0x11,0xD0,0x3E,0x9B,0xDF,0x41,0xD5,0x71,0x4B,0xD4,0x4A,0x00,0x32, +0x24,0x3A,0xDB,0x5D,0x27,0x70,0x16,0x42,0x62,0xAD,0xEF,0x49,0x6E,0x8A,0xFB,0x00,0xD5,0x87,0x93,0x28, +0x4D,0x53,0xE2,0x4E,0x1E,0xAC,0xAD,0x62,0x60,0x8A,0xF2,0x6E,0x5E,0xEC,0x12,0xD8,0x0E,0x9A,0xEA,0x5E, +0x1F,0xAD,0x0A,0xA5,0xA0,0x8C,0xFA,0x7E,0x5F,0xED,0x1B,0x29,0xCD,0x7E,0xE3,0x4F,0x9E,0xAE,0x81,0xAD, +0x6C,0x82,0xF3,0x6F,0xDE,0xEE,0xD0,0xB9,0x23,0x72,0xEB,0x5F,0x9F,0xAF,0xD3,0xD8,0xB0,0x0F,0xFB,0x7F, +0xDF,0xEF,0x56,0x27,0xA1,0x97,0x64,0x92,0xC8,0x45,0xF4,0xB3,0x48,0xD6,0x03,0x5B,0x38,0xBE,0x2D,0x4D, +0x86,0xEF,0x1B,0x8F,0x33,0x71,0x44,0x96,0xEA,0xD3,0x45,0x70,0xD7,0xB4,0xCE,0x74,0xA2,0x72,0x61,0x03, +0xF0,0x47,0x3D,0x06,0x87,0xF2,0xC5,0xE1,0x56,0x0C,0x16,0xD5,0x07,0xDD,0x1A,0xA8,0xE1,0xF1,0x8A,0xB2, +0x68,0xDF,0xCF,0x31,0xED,0xBF,0x6C,0xF5,0x87,0xF8,0xE4,0xC6,0x36,0xB4,0x14,0xA2,0x6A,0x29,0xF4,0xE6, +0x76,0xF4,0xE8,0x15,0xA7,0xB5,0xEC,0xD6,0x37,0xB5,0x26,0xF3,0xC4,0x94,0xFC,0xF6,0x77,0xF5,0x86,0x84, +0x78,0x9E,0xE5,0xC7,0xB6,0xB6,0x0D,0x61,0xE7,0x96,0xF5,0xE7,0xF6,0xF6,0xC1,0x13,0x04,0xD6,0xED,0xD7, +0xB7,0xB7,0x1D,0xB3,0xFA,0x5C,0xFD,0xF7,0xF7,0xF7,0x52,0xAE,0xF8,0x28,0x24,0xB1,0xB9,0xBF,0x5E,0xB4, +0x2A,0x2C,0xC6,0x8E,0x64,0x35,0x09,0x1A,0xAA,0x3E,0x47,0x1A,0x79,0xA5,0x81,0xDA,0xDA,0x7D,0x84,0x5C, +0xFF,0xF1,0x80,0x97,0x7C,0x6A,0x4F,0x2C,0xBA,0x1A,0xF1,0x2F,0xA4,0xAD,0x27,0x2D,0xFD,0x1D,0x87,0x3D, +0xAB,0x5B,0x3F,0x58,0xBF,0x4E,0xF9,0xBD,0x25,0x19,0x4D,0xDD,0xBE,0x24,0x8A,0x4A,0xD2,0xBC,0xE6,0xCE, +0x3E,0xBC,0xF2,0x08,0xEC,0xD4,0xF6,0xEE,0x7E,0xFC,0x56,0x29,0x77,0x39,0xEE,0xDE,0x3F,0xBD,0x1E,0xBA, +0xC2,0x20,0xFE,0xFE,0x7F,0xFD,0xCB,0x49,0xAF,0xCB,0xE7,0xCF,0xBE,0xBE,0xFE,0x99,0x4D,0x9F,0xF7,0xEF, +0xFE,0xFE,0x80,0xC7,0x29,0x6A,0xEF,0xDF,0xBF,0xBF,0x07,0xDF,0x6D,0xD7,0xFF,0xFF,0xFF,0xFF,0x00,0x00, +0x00,0x00,0x80,0x04,0x10,0x20,0x10,0x20,0x40,0x40,0x90,0x24,0x50,0x60,0x08,0x10,0x01,0x01,0x88,0x14, +0x11,0x21,0x18,0x30,0x41,0x41,0x98,0x34,0x51,0x61,0x01,0x01,0x80,0x02,0x81,0x05,0x90,0x22,0x11,0x21, +0xC0,0x42,0x91,0x25,0xD0,0x62,0x09,0x11,0x81,0x03,0x89,0x15,0x91,0x23,0x19,0x31,0xC1,0x43,0x99,0x35, +0xD1,0x63,0x40,0x40,0x02,0x04,0xC0,0x44,0x12,0x24,0x50,0x60,0x42,0x44,0xD0,0x64,0x52,0x64,0x48,0x50, +0x03,0x05,0xC8,0x54,0x13,0x25,0x58,0x70,0x43,0x45,0xD8,0x74,0x53,0x65,0x41,0x41,0x82,0x06,0xC1,0x45, +0x92,0x26,0x51,0x61,0xC2,0x46,0xD1,0x65,0xD2,0x66,0x49,0x51,0x83,0x07,0xC9,0x55,0x93,0x27,0x59,0x71, +0xC3,0x47,0xD9,0x75,0xD3,0x67,0x02,0x08,0x08,0x08,0x82,0x0C,0x18,0x28,0x12,0x28,0x48,0x48,0x92,0x2C, +0x58,0x68,0x0A,0x18,0x09,0x09,0x8A,0x1C,0x19,0x29,0x1A,0x38,0x49,0x49,0x9A,0x3C,0x59,0x69,0x03,0x09, +0x88,0x0A,0x83,0x0D,0x98,0x2A,0x13,0x29,0xC8,0x4A,0x93,0x2D,0xD8,0x6A,0x0B,0x19,0x89,0x0B,0x8B,0x1D, +0x99,0x2B,0x1B,0x39,0xC9,0x4B,0x9B,0x3D,0xD9,0x6B,0x42,0x48,0x0A,0x0C,0xC2,0x4C,0x1A,0x2C,0x52,0x68, +0x4A,0x4C,0xD2,0x6C,0x5A,0x6C,0x4A,0x58,0x0B,0x0D,0xCA,0x5C,0x1B,0x2D,0x5A,0x78,0x4B,0x4D,0xDA,0x7C, +0x5B,0x6D,0x43,0x49,0x8A,0x0E,0xC3,0x4D,0x9A,0x2E,0x53,0x69,0xCA,0x4E,0xD3,0x6D,0xDA,0x6E,0x4B,0x59, +0x8B,0x0F,0xCB,0x5D,0x9B,0x2F,0x5B,0x79,0xCB,0x4F,0xDB,0x7D,0xDB,0x6F,0x04,0x80,0x20,0x10,0x84,0x84, +0x30,0x30,0x14,0xA0,0x60,0x50,0x94,0xA4,0x70,0x70,0x0C,0x90,0x21,0x11,0x8C,0x94,0x31,0x31,0x1C,0xB0, +0x61,0x51,0x9C,0xB4,0x71,0x71,0x05,0x81,0xA0,0x12,0x85,0x85,0xB0,0x32,0x15,0xA1,0xE0,0x52,0x95,0xA5, +0xF0,0x72,0x0D,0x91,0xA1,0x13,0x8D,0x95,0xB1,0x33,0x1D,0xB1,0xE1,0x53,0x9D,0xB5,0xF1,0x73,0x44,0xC0, +0x22,0x14,0xC4,0xC4,0x32,0x34,0x54,0xE0,0x62,0x54,0xD4,0xE4,0x72,0x74,0x4C,0xD0,0x23,0x15,0xCC,0xD4, +0x33,0x35,0x5C,0xF0,0x63,0x55,0xDC,0xF4,0x73,0x75,0x45,0xC1,0xA2,0x16,0xC5,0xC5,0xB2,0x36,0x55,0xE1, +0xE2,0x56,0xD5,0xE5,0xF2,0x76,0x4D,0xD1,0xA3,0x17,0xCD,0xD5,0xB3,0x37,0x5D,0xF1,0xE3,0x57,0xDD,0xF5, +0xF3,0x77,0x06,0x88,0x28,0x18,0x86,0x8C,0x38,0x38,0x16,0xA8,0x68,0x58,0x96,0xAC,0x78,0x78,0x0E,0x98, +0x29,0x19,0x8E,0x9C,0x39,0x39,0x1E,0xB8,0x69,0x59,0x9E,0xBC,0x79,0x79,0x07,0x89,0xA8,0x1A,0x87,0x8D, +0xB8,0x3A,0x17,0xA9,0xE8,0x5A,0x97,0xAD,0xF8,0x7A,0x0F,0x99,0xA9,0x1B,0x8F,0x9D,0xB9,0x3B,0x1F,0xB9, +0xE9,0x5B,0x9F,0xBD,0xF9,0x7B,0x46,0xC8,0x2A,0x1C,0xC6,0xCC,0x3A,0x3C,0x56,0xE8,0x6A,0x5C,0xD6,0xEC, +0x7A,0x7C,0x4E,0xD8,0x2B,0x1D,0xCE,0xDC,0x3B,0x3D,0x5E,0xF8,0x6B,0x5D,0xDE,0xFC,0x7B,0x7D,0x47,0xC9, +0xAA,0x1E,0xC7,0xCD,0xBA,0x3E,0x57,0xE9,0xEA,0x5E,0xD7,0xED,0xFA,0x7E,0x4F,0xD9,0xAB,0x1F,0xCF,0xDD, +0xBB,0x3F,0x5F,0xF9,0xEB,0x5F,0xDF,0xFD,0xFB,0x7F,0x20,0x02,0x04,0x80,0xA0,0x06,0x14,0xA0,0x30,0x22, +0x44,0xC0,0xB0,0x26,0x54,0xE0,0x28,0x12,0x05,0x81,0xA8,0x16,0x15,0xA1,0x38,0x32,0x45,0xC1,0xB8,0x36, +0x55,0xE1,0x21,0x03,0x84,0x82,0xA1,0x07,0x94,0xA2,0x31,0x23,0xC4,0xC2,0xB1,0x27,0xD4,0xE2,0x29,0x13, +0x85,0x83,0xA9,0x17,0x95,0xA3,0x39,0x33,0xC5,0xC3,0xB9,0x37,0xD5,0xE3,0x60,0x42,0x06,0x84,0xE0,0x46, +0x16,0xA4,0x70,0x62,0x46,0xC4,0xF0,0x66,0x56,0xE4,0x68,0x52,0x07,0x85,0xE8,0x56,0x17,0xA5,0x78,0x72, +0x47,0xC5,0xF8,0x76,0x57,0xE5,0x61,0x43,0x86,0x86,0xE1,0x47,0x96,0xA6,0x71,0x63,0xC6,0xC6,0xF1,0x67, +0xD6,0xE6,0x69,0x53,0x87,0x87,0xE9,0x57,0x97,0xA7,0x79,0x73,0xC7,0xC7,0xF9,0x77,0xD7,0xE7,0x22,0x0A, +0x0C,0x88,0xA2,0x0E,0x1C,0xA8,0x32,0x2A,0x4C,0xC8,0xB2,0x2E,0x5C,0xE8,0x2A,0x1A,0x0D,0x89,0xAA,0x1E, +0x1D,0xA9,0x3A,0x3A,0x4D,0xC9,0xBA,0x3E,0x5D,0xE9,0x23,0x0B,0x8C,0x8A,0xA3,0x0F,0x9C,0xAA,0x33,0x2B, +0xCC,0xCA,0xB3,0x2F,0xDC,0xEA,0x2B,0x1B,0x8D,0x8B,0xAB,0x1F,0x9D,0xAB,0x3B,0x3B,0xCD,0xCB,0xBB,0x3F, +0xDD,0xEB,0x62,0x4A,0x0E,0x8C,0xE2,0x4E,0x1E,0xAC,0x72,0x6A,0x4E,0xCC,0xF2,0x6E,0x5E,0xEC,0x6A,0x5A, +0x0F,0x8D,0xEA,0x5E,0x1F,0xAD,0x7A,0x7A,0x4F,0xCD,0xFA,0x7E,0x5F,0xED,0x63,0x4B,0x8E,0x8E,0xE3,0x4F, +0x9E,0xAE,0x73,0x6B,0xCE,0xCE,0xF3,0x6F,0xDE,0xEE,0x6B,0x5B,0x8F,0x8F,0xEB,0x5F,0x9F,0xAF,0x7B,0x7B, +0xCF,0xCF,0xFB,0x7F,0xDF,0xEF,0x24,0x82,0x24,0x90,0xA4,0x86,0x34,0xB0,0x34,0xA2,0x64,0xD0,0xB4,0xA6, +0x74,0xF0,0x2C,0x92,0x25,0x91,0xAC,0x96,0x35,0xB1,0x3C,0xB2,0x65,0xD1,0xBC,0xB6,0x75,0xF1,0x25,0x83, +0xA4,0x92,0xA5,0x87,0xB4,0xB2,0x35,0xA3,0xE4,0xD2,0xB5,0xA7,0xF4,0xF2,0x2D,0x93,0xA5,0x93,0xAD,0x97, +0xB5,0xB3,0x3D,0xB3,0xE5,0xD3,0xBD,0xB7,0xF5,0xF3,0x64,0xC2,0x26,0x94,0xE4,0xC6,0x36,0xB4,0x74,0xE2, +0x66,0xD4,0xF4,0xE6,0x76,0xF4,0x6C,0xD2,0x27,0x95,0xEC,0xD6,0x37,0xB5,0x7C,0xF2,0x67,0xD5,0xFC,0xF6, +0x77,0xF5,0x65,0xC3,0xA6,0x96,0xE5,0xC7,0xB6,0xB6,0x75,0xE3,0xE6,0xD6,0xF5,0xE7,0xF6,0xF6,0x6D,0xD3, +0xA7,0x97,0xED,0xD7,0xB7,0xB7,0x7D,0xF3,0xE7,0xD7,0xFD,0xF7,0xF7,0xF7,0x26,0x8A,0x2C,0x98,0xA6,0x8E, +0x3C,0xB8,0x36,0xAA,0x6C,0xD8,0xB6,0xAE,0x7C,0xF8,0x2E,0x9A,0x2D,0x99,0xAE,0x9E,0x3D,0xB9,0x3E,0xBA, +0x6D,0xD9,0xBE,0xBE,0x7D,0xF9,0x27,0x8B,0xAC,0x9A,0xA7,0x8F,0xBC,0xBA,0x37,0xAB,0xEC,0xDA,0xB7,0xAF, +0xFC,0xFA,0x2F,0x9B,0xAD,0x9B,0xAF,0x9F,0xBD,0xBB,0x3F,0xBB,0xED,0xDB,0xBF,0xBF,0xFD,0xFB,0x66,0xCA, +0x2E,0x9C,0xE6,0xCE,0x3E,0xBC,0x76,0xEA,0x6E,0xDC,0xF6,0xEE,0x7E,0xFC,0x6E,0xDA,0x2F,0x9D,0xEE,0xDE, +0x3F,0xBD,0x7E,0xFA,0x6F,0xDD,0xFE,0xFE,0x7F,0xFD,0x67,0xCB,0xAE,0x9E,0xE7,0xCF,0xBE,0xBE,0x77,0xEB, +0xEE,0xDE,0xF7,0xEF,0xFE,0xFE,0x6F,0xDB,0xAF,0x9F,0xEF,0xDF,0xBF,0xBF,0x7F,0xFB,0xEF,0xDF,0xFF,0xFF, +0xFF,0xFF,0x00,0x00,0x00,0x00,0x80,0x04,0x10,0x20,0x10,0x20,0x40,0x40,0x90,0x24,0x50,0x60,0x08,0x10, +0x01,0x01,0x88,0x14,0x11,0x21,0x18,0x30,0x41,0x41,0x98,0x34,0x51,0x61,0x01,0x01,0x80,0x02,0x81,0x05, +0x90,0x22,0x11,0x21,0xC0,0x42,0x91,0x25,0xD0,0x62,0x09,0x11,0x81,0x03,0x89,0x15,0x91,0x23,0x19,0x31, +0xC1,0x43,0x99,0x35,0xD1,0x63,0x40,0x40,0x02,0x04,0xC0,0x44,0x12,0x24,0x50,0x60,0x42,0x44,0xD0,0x64, +0x52,0x64,0x48,0x50,0x03,0x05,0xC8,0x54,0x13,0x25,0x58,0x70,0x43,0x45,0xD8,0x74,0x53,0x65,0x41,0x41, +0x82,0x06,0xC1,0x45,0x92,0x26,0x51,0x61,0xC2,0x46,0xD1,0x65,0xD2,0x66,0x49,0x51,0x83,0x07,0xC9,0x55, +0x93,0x27,0x59,0x71,0xC3,0x47,0xD9,0x75,0xD3,0x67,0x02,0x08,0x08,0x08,0x82,0x0C,0x18,0x28,0x12,0x28, +0x48,0x48,0x92,0x2C,0x58,0x68,0x0A,0x18,0x09,0x09,0x8A,0x1C,0x19,0x29,0x1A,0x38,0x49,0x49,0x9A,0x3C, +0x59,0x69,0x03,0x09,0x88,0x0A,0x83,0x0D,0x98,0x2A,0x13,0x29,0xC8,0x4A,0x93,0x2D,0xD8,0x6A,0x0B,0x19, +0x89,0x0B,0x8B,0x1D,0x99,0x2B,0x1B,0x39,0xC9,0x4B,0x9B,0x3D,0xD9,0x6B,0x42,0x48,0x0A,0x0C,0xC2,0x4C, +0x1A,0x2C,0x52,0x68,0x4A,0x4C,0xD2,0x6C,0x5A,0x6C,0x4A,0x58,0x0B,0x0D,0xCA,0x5C,0x1B,0x2D,0x5A,0x78, +0x4B,0x4D,0xDA,0x7C,0x5B,0x6D,0x43,0x49,0x8A,0x0E,0xC3,0x4D,0x9A,0x2E,0x53,0x69,0xCA,0x4E,0xD3,0x6D, +0xDA,0x6E,0x4B,0x59,0x8B,0x0F,0xCB,0x5D,0x9B,0x2F,0x5B,0x79,0xCB,0x4F,0xDB,0x7D,0xDB,0x6F,0x04,0x80, +0x20,0x10,0x84,0x84,0x30,0x30,0x14,0xA0,0x60,0x50,0x94,0xA4,0x70,0x70,0x0C,0x90,0x21,0x11,0x8C,0x94, +0x31,0x31,0x1C,0xB0,0x61,0x51,0x9C,0xB4,0x71,0x71,0x05,0x81,0xA0,0x12,0x85,0x85,0xB0,0x32,0x15,0xA1, +0xE0,0x52,0x95,0xA5,0xF0,0x72,0x0D,0x91,0xA1,0x13,0x8D,0x95,0xB1,0x33,0x1D,0xB1,0xE1,0x53,0x9D,0xB5, +0xF1,0x73,0x44,0xC0,0x22,0x14,0xC4,0xC4,0x32,0x34,0x54,0xE0,0x62,0x54,0xD4,0xE4,0x72,0x74,0x4C,0xD0, +0x23,0x15,0xCC,0xD4,0x33,0x35,0x5C,0xF0,0x63,0x55,0xDC,0xF4,0x73,0x75,0x45,0xC1,0xA2,0x16,0xC5,0xC5, +0xB2,0x36,0x55,0xE1,0xE2,0x56,0xD5,0xE5,0xF2,0x76,0x4D,0xD1,0xA3,0x17,0xCD,0xD5,0xB3,0x37,0x5D,0xF1, +0xE3,0x57,0xDD,0xF5,0xF3,0x77,0x06,0x88,0x28,0x18,0x86,0x8C,0x38,0x38,0x16,0xA8,0x68,0x58,0x96,0xAC, +0x78,0x78,0x0E,0x98,0x29,0x19,0x8E,0x9C,0x39,0x39,0x1E,0xB8,0x69,0x59,0x9E,0xBC,0x79,0x79,0x07,0x89, +0xA8,0x1A,0x87,0x8D,0xB8,0x3A,0x17,0xA9,0xE8,0x5A,0x97,0xAD,0xF8,0x7A,0x0F,0x99,0xA9,0x1B,0x8F,0x9D, +0xB9,0x3B,0x1F,0xB9,0xE9,0x5B,0x9F,0xBD,0xF9,0x7B,0x46,0xC8,0x2A,0x1C,0xC6,0xCC,0x3A,0x3C,0x56,0xE8, +0x6A,0x5C,0xD6,0xEC,0x7A,0x7C,0x4E,0xD8,0x2B,0x1D,0xCE,0xDC,0x3B,0x3D,0x5E,0xF8,0x6B,0x5D,0xDE,0xFC, +0x7B,0x7D,0x47,0xC9,0xAA,0x1E,0xC7,0xCD,0xBA,0x3E,0x57,0xE9,0xEA,0x5E,0xD7,0xED,0xFA,0x7E,0x4F,0xD9, +0xAB,0x1F,0xCF,0xDD,0xBB,0x3F,0x5F,0xF9,0xEB,0x5F,0xDF,0xFD,0xFB,0x7F,0x20,0x02,0x04,0x80,0xA0,0x06, +0x14,0xA0,0x30,0x22,0x44,0xC0,0xB0,0x26,0x54,0xE0,0x28,0x12,0x05,0x81,0xA8,0x16,0x15,0xA1,0x38,0x32, +0x45,0xC1,0xB8,0x36,0x55,0xE1,0x21,0x03,0x84,0x82,0xA1,0x07,0x94,0xA2,0x31,0x23,0xC4,0xC2,0xB1,0x27, +0xD4,0xE2,0x29,0x13,0x85,0x83,0xA9,0x17,0x95,0xA3,0x39,0x33,0xC5,0xC3,0xB9,0x37,0xD5,0xE3,0x60,0x42, +0x06,0x84,0xE0,0x46,0x16,0xA4,0x70,0x62,0x46,0xC4,0xF0,0x66,0x56,0xE4,0x68,0x52,0x07,0x85,0xE8,0x56, +0x17,0xA5,0x78,0x72,0x47,0xC5,0xF8,0x76,0x57,0xE5,0x61,0x43,0x86,0x86,0xE1,0x47,0x96,0xA6,0x71,0x63, +0xC6,0xC6,0xF1,0x67,0xD6,0xE6,0x69,0x53,0x87,0x87,0xE9,0x57,0x97,0xA7,0x79,0x73,0xC7,0xC7,0xF9,0x77, +0xD7,0xE7,0x22,0x0A,0x0C,0x88,0xA2,0x0E,0x1C,0xA8,0x32,0x2A,0x4C,0xC8,0xB2,0x2E,0x5C,0xE8,0x2A,0x1A, +0x0D,0x89,0xAA,0x1E,0x1D,0xA9,0x3A,0x3A,0x4D,0xC9,0xBA,0x3E,0x5D,0xE9,0x23,0x0B,0x8C,0x8A,0xA3,0x0F, +0x9C,0xAA,0x33,0x2B,0xCC,0xCA,0xB3,0x2F,0xDC,0xEA,0x2B,0x1B,0x8D,0x8B,0xAB,0x1F,0x9D,0xAB,0x3B,0x3B, +0xCD,0xCB,0xBB,0x3F,0xDD,0xEB,0x62,0x4A,0x0E,0x8C,0xE2,0x4E,0x1E,0xAC,0x72,0x6A,0x4E,0xCC,0xF2,0x6E, +0x5E,0xEC,0x6A,0x5A,0x0F,0x8D,0xEA,0x5E,0x1F,0xAD,0x7A,0x7A,0x4F,0xCD,0xFA,0x7E,0x5F,0xED,0x63,0x4B, +0x8E,0x8E,0xE3,0x4F,0x9E,0xAE,0x73,0x6B,0xCE,0xCE,0xF3,0x6F,0xDE,0xEE,0x6B,0x5B,0x8F,0x8F,0xEB,0x5F, +0x9F,0xAF,0x7B,0x7B,0xCF,0xCF,0xFB,0x7F,0xDF,0xEF,0x24,0x82,0x24,0x90,0xA4,0x86,0x34,0xB0,0x34,0xA2, +0x64,0xD0,0xB4,0xA6,0x74,0xF0,0x2C,0x92,0x25,0x91,0xAC,0x96,0x35,0xB1,0x3C,0xB2,0x65,0xD1,0xBC,0xB6, +0x75,0xF1,0x25,0x83,0xA4,0x92,0xA5,0x87,0xB4,0xB2,0x35,0xA3,0xE4,0xD2,0xB5,0xA7,0xF4,0xF2,0x2D,0x93, +0xA5,0x93,0xAD,0x97,0xB5,0xB3,0x3D,0xB3,0xE5,0xD3,0xBD,0xB7,0xF5,0xF3,0x64,0xC2,0x26,0x94,0xE4,0xC6, +0x36,0xB4,0x74,0xE2,0x66,0xD4,0xF4,0xE6,0x76,0xF4,0x6C,0xD2,0x27,0x95,0xEC,0xD6,0x37,0xB5,0x7C,0xF2, +0x67,0xD5,0xFC,0xF6,0x77,0xF5,0x65,0xC3,0xA6,0x96,0xE5,0xC7,0xB6,0xB6,0x75,0xE3,0xE6,0xD6,0xF5,0xE7, +0xF6,0xF6,0x6D,0xD3,0xA7,0x97,0xED,0xD7,0xB7,0xB7,0x7D,0xF3,0xE7,0xD7,0xFD,0xF7,0xF7,0xF7,0x26,0x8A, +0x2C,0x98,0xA6,0x8E,0x3C,0xB8,0x36,0xAA,0x6C,0xD8,0xB6,0xAE,0x7C,0xF8,0x2E,0x9A,0x2D,0x99,0xAE,0x9E, +0x3D,0xB9,0x3E,0xBA,0x6D,0xD9,0xBE,0xBE,0x7D,0xF9,0x27,0x8B,0xAC,0x9A,0xA7,0x8F,0xBC,0xBA,0x37,0xAB, +0xEC,0xDA,0xB7,0xAF,0xFC,0xFA,0x2F,0x9B,0xAD,0x9B,0xAF,0x9F,0xBD,0xBB,0x3F,0xBB,0xED,0xDB,0xBF,0xBF, +0xFD,0xFB,0x66,0xCA,0x2E,0x9C,0xE6,0xCE,0x3E,0xBC,0x76,0xEA,0x6E,0xDC,0xF6,0xEE,0x7E,0xFC,0x6E,0xDA, +0x2F,0x9D,0xEE,0xDE,0x3F,0xBD,0x7E,0xFA,0x6F,0xDD,0xFE,0xFE,0x7F,0xFD,0x67,0xCB,0xAE,0x9E,0xE7,0xCF, +0xBE,0xBE,0x77,0xEB,0xEE,0xDE,0xF7,0xEF,0xFE,0xFE,0x6F,0xDB,0xAF,0x9F,0xEF,0xDF,0xBF,0xBF,0x7F,0xFB, +0xEF,0xDF,0xFF,0xFF,0x90,0xAF}; +#endif + +/* +*[HW INFO]00900600 +*[PID]910 +*[VID]1010 +*[GENERATED]2013/08/27 20:59:13 +*/ +#if GTP_COMPATIBLE_MODE +unsigned char gtp_default_FW_fl[] = { +/* 0x00,0x90,0x06,0x00,0x39,0x31,0x30,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x80,0x00, + 0x55,0x40,0xf8,0x86,0x98,0x71,0x69,0xf0,0x0c,0xc1,0x78,0x1e,0xd2,0x48,0x88,0x58, + 0xa3,0x41,0xd2,0xeb,0xb2,0x63,0x32,0xe0,0x1d,0xc9,0xf8,0x75,0x15,0x6e,0x01,0x8d, + 0x05,0x02,0xf9,0x87,0x18,0x7a,0x12,0x6b,0x4d,0x21,0x17,0xd5,0x94,0x6d,0x09,0x0d, + 0x87,0x03,0x4f,0xc2,0x13,0x0b,0x09,0x7b,0x4d,0x4b,0xf9,0x74,0x99,0xe8,0x38,0xa8, + 0x3d,0xc9,0xa2,0x4d,0x13,0x74,0xab,0x47,0xe3,0xe5,0xee,0x49,0xdf,0xd2,0x00,0x54, + 0x8b,0xfb,0x48,0x94,0x1f,0x67,0x8b,0x8e,0xbe,0xe4,0xce,0x59,0x55,0x46,0xbe,0x86, + 0x40,0x06,0x98,0xb8,0x77,0xa0,0x85,0x9e,0x2b,0x05,0x99,0xfd,0xb1,0xd4,0xf6,0xb9, + 0x40,0x9c,0x50,0x1d,0x4e,0x1a,0x0d,0x82,0xe9,0x9a,0x5d,0x17,0xba,0x86,0x47,0xac, + 0x2c,0x48,0x26,0x6e,0x59,0x38,0x10,0xda,0x0f,0x4c,0x15,0xce,0xda,0x40,0x9a,0x3c, + 0x2f,0x49,0xd0,0x18,0xba,0x2f,0x20,0x3a,0x55,0x69,0xea,0x5c,0x4f,0x62,0x98,0xcc, + 0x0f,0x7a,0xfb,0x8f,0x99,0x52,0x17,0x7d,0x2f,0xb4,0x91,0xcf,0xde,0x32,0x48,0x6c, + 0xaf,0x48,0x83,0x51,0xdb,0x24,0x9b,0x29,0xd9,0x49,0xda,0xc2,0x2e,0x29,0xa5,0xcc, + 0x28,0x7a,0x6d,0x4e,0x1e,0xd7,0x04,0xc8,0xa1,0x4f,0x8a,0x74,0x39,0x55,0xf0,0xa7, + 0xb2,0x61,0xcf,0x1d,0x5d,0xa0,0x5c,0x41,0xa2,0xfc,0x2f,0x1e,0x1b,0x62,0x79,0xa2, + 0xb9,0xf5,0x44,0xc9,0xf3,0x59,0x55,0x44,0x82,0x7f,0xc5,0x40,0xdc,0x6d,0xac,0x19, + 0x8f,0x26,0xb6,0xb5,0xa4,0xe2,0x03,0xd6,0x83,0xde,0xfb,0x6d,0x93,0x1e,0x04,0x80, + 0x78,0xf8,0x88,0x83,0x91,0xba,0x2c,0xc0,0xd0,0x58,0x9c,0xb7,0x63,0x58,0xde,0xb0, + 0x26,0xe9,0x6a,0x64,0x85,0x3e,0xe5,0xc2,0xef,0x34,0x5c,0x69,0x02,0xaa,0x4f,0x28, + 0x82,0x11,0x7b,0x67,0x32,0x38,0x64,0xd3,0x6e,0x37,0x48,0x25,0xc7,0x77,0x02,0x1d, + 0x24,0xe6,0x65,0xb8,0xb7,0x22,0x64,0xc3,0x6f,0x36,0xa8,0x48,0xc1,0x06,0x22,0x10, + 0x21,0x5d,0x8e,0x84,0x36,0x1d,0x74,0xa0,0x61,0x4f,0xe4,0x60,0x50,0x10,0x34,0xe2, + 0xd7,0x1a,0x06,0x36,0xd3,0xca,0x5c,0xb0,0x79,0xf8,0x4f,0xe7,0x5d,0x84,0x7b,0xe9, + 0x6a,0xdc,0xfc,0xb6,0x82,0x92,0x8b,0x97,0x6d,0xd0,0xdd,0xf1,0x3a,0x35,0x16,0xd1, + 0xcb,0x3d,0x7e,0x37,0x5a,0x1d,0xca,0xc0,0x42,0xa8,0xe3,0x50,0x9b,0x54,0xc6,0x69, + 0x14,0xb3,0x86,0xca,0xc4,0x3e,0x3f,0xfb,0xec,0x44,0xdf,0x82,0x37,0xc3,0x79,0x69, + 0x44,0x1c,0x3a,0x8c,0x9a,0x7b,0x66,0x9f,0xf8,0xf5,0x43,0x0c,0x12,0xea,0x37,0x37, + 0xc3,0xd3,0x0f,0x21,0x59,0x35,0xbe,0xfa,0x64,0x06,0x68,0x29,0xc1,0x20,0x51,0xfc, + 0xcc,0xb0,0x14,0x4a,0x65,0x72,0xbf,0xf3,0x7c,0xf7,0x0c,0x86,0xea,0xee,0x38,0xf1, + 0xdb,0xcf,0x1f,0xcc,0x46,0x93,0x68,0xd4,0x44,0x83,0xa8,0x4d,0x93,0x3f,0x5b,0xab, + 0x13,0x73,0xdd,0xcf,0x30,0x0c,0xbc,0x70,0x8e,0xd4,0xd8,0xd5,0x33,0xcc,0x39,0xf1, + 0x62,0x34,0xd0,0xa3,0xcc,0x91,0xfb,0x96,0xd9,0xd5,0x81,0x4d,0x11,0x7d,0x29,0x1d, + 0xa8,0x57,0xf1,0xf4,0x34,0x99,0x7f,0x13,0x1e,0xd6,0xe1,0xc4,0xd8,0x3f,0x20,0x02, + 0x04,0xc0,0xff,0x26,0x67,0xa0,0x20,0x62,0xc4,0xc6,0x2f,0xd9,0xb5,0x1f,0x28,0x12, + 0x05,0xc1,0x68,0xdf,0xca,0x5c,0x3c,0xb5,0x64,0x56,0x82,0xc9,0xa2,0xa3,0x79,0xfa, + 0x84,0x82,0x7e,0x07,0xe3,0xae,0xac,0xd1,0x25,0x19,0x4a,0xa3,0xa1,0x01,0x29,0x8f, + 0x85,0x83,0x22,0x77,0xcd,0xa5,0x8d,0xcc,0x86,0x30,0xa7,0x31,0x34,0x5c,0xa5,0xb2, + 0x3d,0xb5,0x1f,0x2d,0x9b,0x52,0x50,0xd5,0x0e,0xd5,0xd0,0xb8,0xbf,0x95,0x10,0x39, + 0x6f,0x88,0xb6,0xb4,0x57,0x98,0xc2,0x8d,0xc8,0x68,0xbf,0x4f,0x51,0xc6,0xa1,0xe3, + 0x39,0x0b,0xe9,0x43,0x1e,0x58,0x7d,0xda,0xf5,0x1d,0xee,0x87,0xd4,0x6d,0x7f,0x31, + 0xe7,0x78,0xdb,0x67,0x54,0x08,0xee,0xec,0xa4,0xc3,0x7d,0x04,0xbb,0xe8,0x22,0x0a, + 0x0c,0xc8,0xae,0x79,0x7f,0x37,0x62,0x59,0x54,0x42,0x4d,0xd0,0x5a,0x01,0x2a,0x1a, + 0x0d,0xc9,0xe7,0x19,0x9d,0xe7,0x8e,0x5a,0x45,0x19,0x65,0x62,0x2e,0xee,0x23,0x96, + 0x8c,0x8a,0xdb,0xf2,0x90,0xe8,0xf4,0xd5,0x2d,0xac,0x02,0x0b,0xab,0x5f,0xb6,0xda, + 0x8d,0x8b,0x6b,0xfe,0xa1,0xad,0x94,0xeb,0x4c,0x6a,0xe4,0x0b,0x15,0x01,0x1c,0x4c, + 0xef,0x0f,0x42,0x3d,0xbd,0x2f,0x0b,0x1b,0x3a,0xda,0x32,0xce,0xec,0x67,0x14,0x77, + 0xc7,0xe7,0x95,0x4d,0x10,0xbc,0x2e,0xe8,0x4f,0x60,0xae,0xda,0x3c,0xef,0x93,0xcf, + 0xac,0x14,0x04,0xcb,0xbc,0x34,0x7b,0xb2,0x41,0x63,0xf7,0x8d,0x86,0xac,0x7a,0x28, + 0xbf,0xe1,0xd5,0x77,0x10,0x09,0x2b,0x0b,0x4f,0x49,0x6c,0x8c,0x5b,0x64,0x01,0x82, + 0x4f,0xb4,0xc4,0x84,0x6a,0x1d,0x90,0xec,0xbb,0xed,0x7a,0x5b,0x76,0x2b,0xac,0x92, + 0x94,0x1c,0x82,0x12,0x1e,0x43,0x94,0x9f,0x1e,0xc9,0xe5,0x57,0x90,0x0e,0xda,0x87, + 0xa4,0xf7,0x3d,0x65,0xb2,0x99,0xde,0xd4,0x64,0x05,0x85,0x23,0xd9,0xd7,0xc9,0xb4, + 0x16,0x1e,0x72,0x3a,0xb3,0x98,0xe2,0xb2,0xe3,0x9a,0x51,0xc4,0x9f,0x05,0xa4,0x63, + 0x00,0x1f,0x2c,0x86,0x32,0x9d,0x54,0x68,0x67,0x57,0xf2,0xde,0x5f,0x6e,0x36,0xe9, + 0x21,0x96,0xfb,0x25,0xb3,0x3e,0x26,0x64,0x75,0x18,0x10,0x85,0x0b,0x73,0xee,0xfe, + 0x4d,0xd2,0xdf,0x37,0x86,0x17,0x99,0x90,0x9a,0xcd,0xf3,0xcf,0xdf,0x65,0xc9,0x93, + 0xe3,0x33,0xd8,0x66,0xc7,0x18,0x67,0xf1,0x54,0x7a,0x02,0x84,0x83,0x7e,0xc2,0xad, + 0x2d,0xf8,0x4b,0x7f,0x8e,0x28,0x20,0xd8,0xee,0xdc,0xec,0xac,0xcf,0x51,0x2f,0x45, + 0xce,0x9d,0x56,0x6e,0x35,0xb6,0xb2,0x4a,0x92,0xd6,0xe7,0x47,0x1a,0xf8,0xdd,0x89, + 0xa4,0xd5,0x4f,0xa5,0x3e,0xb2,0x3b,0x49,0x6e,0xde,0xe5,0x25,0xfd,0x7a,0x3a,0xe9, + 0x23,0xfe,0x07,0xa1,0x3a,0xce,0x05,0x9c,0x4e,0xbe,0x85,0x3d,0x1f,0xe0,0xb6,0xf6, + 0xe6,0xff,0x42,0xac,0xd5,0x5d,0xe5,0x9a,0xee,0xca,0xd6,0x7c,0xfe,0xf4,0x10,0xdc, + 0x4c,0x98,0xd0,0xeb,0xdc,0xb4,0xcc,0xc6,0x7f,0x18,0xde,0xfb,0xb7,0x0c,0xf0,0x3b, + 0xac,0x6f,0xfd,0xd2,0x9f,0xb7,0x7f,0xfe,0xdd,0xb5,0xf1,0x1e,0xc6,0x01,0xbc,0x28, + 0x23,0x92,0x3e,0xad,0x54,0xce,0xe8,0x88,0xd3,0xb1,0xea,0x84,0x70,0x79,0x00,0x40, + 0x3f,0x8d,0xda,0x06,0xa3,0xb9,0xaa,0xdf,0xa9,0x71,0xa8,0x20,0xd5,0xb2,0x58,0xba, + 0xa0,0xfe,0x9a,0x15,0x17,0x22,0x08,0xbd,0x4a,0x5a,0xd9,0xd4,0x59,0xa3,0x7f,0x2c, + 0xda,0x40,0xe0,0x45,0xa2,0xdf,0xfd,0xbe,0xc3,0xc0,0xc8,0xcc,0x35,0xa0,0xe5,0x82, + 0xbd,0x0b,0x98,0xd5,0xdb,0x38,0x45,0x47,0xbd,0xbc,0xc0,0xdc,0x34,0x71,0xfa,0xbf, + 0x8d,0x82,0xd6,0x26,0xa9,0x99,0xe8,0x80,0x46,0x69,0x77,0xa5,0xbb,0x4e,0x11,0xbd, + 0x66,0x0c,0x08,0xf4,0x19,0xd8,0x85,0x06,0xbc,0xd8,0x5c,0x06,0xb8,0x4f,0x41,0x01, + 0xde,0xfb,0x6d,0xce,0x91,0x56,0x2c,0x13,0x31,0x5d,0x3d,0xf7,0x84,0x6e,0x4c,0xb9, + 0xa4,0xca,0xb1,0x4c,0x13,0x48,0xf5,0xee,0xc2,0x07,0x19,0xd5,0x92,0x25,0x00,0x17, + 0x34,0xbc,0x5f,0x7a,0x79,0x08,0x28,0x8d,0xbf,0x0a,0x18,0xcc,0x3e,0x6e,0x34,0x31, + 0x86,0x12,0x18,0x9e,0x99,0x22,0x4a,0x04,0x48,0x41,0x5e,0xb9,0x1a,0x9a,0x95,0x72, + 0xab,0xd7,0xdb,0x24,0xb8,0x98,0x43,0xc1,0x69,0x08,0xb3,0x74,0x79,0xb5,0xd0,0x8f, + 0x88,0x6b,0xb3,0x98,0x97,0xa1,0x21,0xd1,0xa2,0x84,0x5f,0xbb,0x97,0x96,0x20,0x4d, + 0x09,0x4c,0xc1,0x0f,0xd6,0x37,0x6e,0xed,0xbb,0xed,0x82,0x16,0xd5,0xc1,0x92,0xae, + 0x38,0xb6,0x4a,0x3f,0xa0,0x36,0x48,0x72,0x4d,0x4e,0xd2,0x6c,0xa7,0x27,0xc1,0x6d, + 0x6b,0x15,0x1e,0x3b,0xeb,0x25,0x6b,0x58,0x6b,0xf1,0x1b,0xe9,0xf8,0x9f,0xf1,0xa6, + 0x06,0x89,0x16,0xc9,0x7a,0xb0,0x4b,0x1b,0x34,0x0d,0xfb,0x6c,0xdd,0x6c,0x7a,0xa8, + 0xdd,0x19,0xdd,0x86,0xd7,0x31,0xd4,0x00,0x53,0x5d,0x1f,0x2e,0x71,0xd0,0x34,0x63, + 0x11,0x17,0xd7,0x26,0x06,0xc7,0x14,0xb4,0xbd,0x60,0xf6,0x36,0x93,0x6a,0x06,0x05, + 0x8a,0x62,0x40,0x04,0x83,0x26,0xea,0x66,0x2a,0x63,0xaf,0x5a,0xf6,0x59,0x7f,0x79, + 0x00,0x91,0xd0,0x47,0xc6,0x33,0x7d,0x03,0xd2,0x5e,0xa5,0x4a,0xd2,0xd3,0x34,0x39, + 0x46,0x61,0xf8,0x32,0x34,0x37,0x66,0x1f,0x51,0x9f,0xee,0x17,0x7d,0x36,0xd0,0x0f, + 0xc2,0x0e,0xf2,0x10,0xbe,0xc3,0xb9,0x00,0xe3,0x4a,0xe7,0x33,0x9a,0xff,0x0c,0xef, + 0xed,0x54,0x82,0xa7,0xf0,0xc9,0xed,0x0e,0x6f,0xab,0x85,0x4d,0xf4,0x75,0x12,0x27, + 0x90,0xbc,0x85,0xd1,0x1a,0xf8,0x43,0x13,0x71,0x5f,0x1d,0x55,0x8f,0x7f,0x7e,0x0c, + 0x0a,0x03,0x59,0x34,0x3e,0x1b,0xe9,0x98,0x3c,0x1a,0xcf,0x5d,0x3c,0x7c,0x1b,0xd8, + 0x2d,0xed,0x50,0xea,0xb6,0xbf,0x66,0x3c,0x10,0x34,0x64,0x54,0x52,0xb4,0x3f,0x76, + 0x27,0xbc,0x41,0xce,0xfe,0x21,0x47,0x44,0x01,0x6b,0x95,0xdf,0xcb,0xd1,0x1a,0x69, + 0xfd,0xba,0x8f,0xdd,0xb5,0xf9,0x1a,0xd8,0xb3,0x5d,0xe0,0x7a,0x10,0xd8,0xfc,0x0f, + 0xe8,0x95,0x06,0x6c,0x08,0x7e,0x81,0x6c,0x48,0xee,0xd4,0xd3,0x39,0x78,0xb1,0x5c, + 0x00,0x93,0x02,0x58,0x19,0xcc,0xb2,0x6a,0x3d,0x55,0xdc,0x03,0xa7,0xf7,0x4f,0xc4, + 0x4b,0xd1,0x97,0xb7,0x35,0x93,0x6f,0x79,0x01,0x74,0xd1,0x69,0xd8,0x6d,0x6f,0xdc, + 0x98,0xa4,0xc7,0xd9,0x12,0xf0,0xdb,0x8b,0x00,0x75,0x86,0x10,0xbd,0xb2,0x06,0x2b, + 0x38,0x0b,0x77,0x26,0xb5,0xd2,0x0e,0x0b,0x2f,0xcf,0x74,0xa0,0x02,0xe6,0x7c,0x17, + 0xa4,0x2e,0x44,0x84,0x19,0xa9,0x6e,0x41,0x27,0x48,0x43,0xd4,0xd0,0x93,0x66,0x32, + 0xe8,0xc0,0xf8,0x05,0xd0,0x6f,0xb1,0x11,0x49,0x64,0x91,0x76,0x75,0x68,0xbf,0x23, + 0xbe,0xc1,0x6b,0xff,0xa6,0x68,0x19,0xd9,0x2c,0xcc,0x11,0xbe,0x57,0x64,0x70,0x82, + 0x1e,0x79,0xb9,0xab,0xf3,0x5b,0x20,0x32,0xcb,0x32,0xfa,0x76,0xa9,0x10,0x3e,0xf2, + 0x1d,0xc6,0x68,0x15,0xdf,0x38,0x30,0x8d,0x41,0xc6,0xba,0x89,0xbe,0x8f,0xcd,0xd1, + 0x96,0x8e,0xda,0x00,0x48,0xae,0x73,0x88,0xc0,0xc5,0x39,0xe3,0xf4,0xec,0x09,0xe1, + 0xb4,0x8a,0xff,0x35,0xff,0xaa,0x28,0x34,0x19,0x47,0x55,0xe8,0xd4,0x07,0x72,0xe5, + 0xad,0x77,0x27,0x06,0x7b,0xbf,0x28,0x28,0xde,0xc2,0xeb,0x4c,0x7f,0x4a,0x62,0x1e, + 0x85,0x17,0xa4,0x7c,0x5c,0x89,0x63,0xdb,0x8b,0xc3,0x56,0x4d,0x00,0x1f,0x1d,0x26, + 0x03,0x7c,0x4b,0x82,0x1e,0xae,0xb6,0x58,0xf4,0xa6,0xea,0xd3,0x39,0x15,0x4b,0xa9, + 0xbe,0x86,0xd3,0x1d,0xdd,0x26,0xbf,0x1b,0xd3,0x59,0xe1,0x3d,0x6e,0x42,0x3b,0xb7, + 0xe9,0x41,0x9d,0x7e,0x86,0xee,0x8d,0x01,0xc3,0x4a,0x41,0xab,0x83,0x31,0xaa,0xfa, + 0x91,0x56,0xd1,0x2d,0x14,0xef,0xd6,0xe8,0x5f,0xc7,0x36,0x0d,0x50,0x83,0x3a,0xb4, + 0xfd,0xc9,0xb3,0x1a,0x98,0xad,0x72,0xab,0xd8,0x33,0x5c,0x6d,0xde,0x1a,0x5c,0xa6, + 0xda,0x14,0xbb,0x63,0x9e,0xef,0x39,0x10,0x13,0xc0,0x99,0x53,0xde,0x8f,0x35,0x06, + 0x06,0xeb,0x84,0x92,0xd5,0xab,0x46,0x4a,0xc5,0x2f,0xd3,0x56,0xf4,0xef,0x3d,0x16, + 0x5c,0xfc,0x96,0x7e,0x3a,0xfe,0xdb,0x41,0x51,0xca,0x3f,0xc9,0x15,0xb1,0x1b,0xaa, + 0x07,0x67,0x79,0x71,0xa4,0x7d,0x99,0x4b,0xdb,0x1f,0xab,0x17,0x66,0xfa,0x77,0x7a, + 0xcd,0x72,0xcd,0x95,0xe0,0xbe,0xe1,0xd5,0x16,0xc3,0x7d,0x17,0xc5,0xfb,0xe6,0x2a, + 0x55,0x59,0x24,0x66,0x35,0x36,0xb4,0x42,0x27,0x54,0xe2,0x84,0x1e,0xf9,0x68,0x46, + 0x03,0x8e,0x0b,0x16,0x33,0x98,0x34,0x62,0x8c,0xbf,0xb4,0xfe,0x71,0xf6,0x89,0x51, + 0xa6,0x9e,0x1a,0xb4,0xf5,0xda,0x0b,0x27,0xe0,0xd5,0x88,0x9c,0x7b,0xc0,0xcb,0xb5, + 0x28,0x11,0x17,0x53,0x95,0x05,0x91,0x61,0xd3,0xdf,0xb9,0x88,0x54,0x47,0xe6,0x2a, + 0x93,0x35,0x8c,0x5e,0x60,0xb9,0x8e,0x51,0xe1,0x55,0x34,0x68,0x66,0xe3,0xab,0xe9, + 0x1d,0x96,0xce,0x9c,0x1e,0xb4,0x45,0x52,0x1a,0x14,0xcc,0x56,0xdc,0xe2,0xb2,0x69, + 0xaa,0xb9,0x9f,0x8b,0x39,0x58,0x50,0x50,0x0d,0x4c,0x69,0x5b,0xbe,0xfc,0x0f,0x47, + 0x9e,0x40,0x50,0xd8,0xb3,0xba,0xc2,0x7c,0x14,0xad,0x62,0x49,0xce,0x30,0x66,0x8a, + 0x32,0xd1,0xde,0x5e,0xc1,0x11,0xf2,0x98,0x85,0xb6,0xd6,0x09,0x9f,0x63,0xd4,0x3a, + 0x23,0x86,0x68,0xe0,0x34,0x41,0x00,0x2a,0x5c,0xa6,0xee,0xda,0x4c,0xef,0x25,0x2d, + 0x9d,0xe5,0xab,0x88,0x60,0xb4,0xb7,0x4b,0xdc,0x5e,0xcb,0xcf,0xae,0xd3,0xc9,0x3d, + 0x9c,0xf5,0x54,0x80,0x3f,0xbf,0xc5,0x6b,0x87,0xd2,0x47,0xef,0x58,0xbe,0xa8,0x38, + 0xe1,0x1b,0xcd,0x44,0x92,0x24,0x5a,0xbd,0x4e,0x06,0xd6,0x03,0xf1,0x25,0xe0,0x0d, + 0x13,0x4e,0xa2,0x91,0x1f,0xab,0x20,0xe0,0x1d,0x5a,0x3e,0xc0,0x59,0x7a,0xa3,0xe7, + 0x05,0xb0,0xc9,0x67,0xd3,0x2e,0xd6,0xa3,0x40,0xda,0xaf,0xa3,0x88,0x79,0xa1,0x81, + 0x04,0xa3,0x0d,0xfd,0x15,0x6c,0x39,0xd7,0x64,0x2d,0x5a,0x53,0x2e,0x6a,0x02,0xa6, + 0x31,0xd6,0x98,0x5d,0xb3,0x46,0xa8,0xe2,0xc2,0x9e,0x2f,0x5a,0x3e,0x26,0x36,0x84, + 0x05,0xed,0x4a,0x36,0x9e,0x47,0x20,0xf2,0xc3,0xbf,0xdd,0x07,0x6b,0x6a,0xf9,0xa9, + 0x1a,0xc7,0x21,0xd5,0xb0,0xa4,0x69,0xe3,0x2c,0x0b,0xca,0x5e,0x50,0x65,0x5a,0x23, + 0x7c,0x45,0x0d,0xd3,0xd7,0x21,0x61,0xf3,0x2d,0x2a,0x89,0x6c,0x8b,0x61,0xaa,0x1c, + 0x8d,0x28,0xe2,0x0e,0x43,0x25,0x70,0x39,0x49,0x28,0x16,0xc4,0x94,0xa8,0xf5,0xf5, + 0x01,0x52,0x72,0x7a,0x94,0xaf,0x3a,0x65,0xe8,0xc3,0x8e,0x5a,0xae,0x72,0xf8,0xf4, + 0x9f,0xb1,0xc9,0x10,0xab,0x3e,0x49,0x38,0x6f,0x4c,0x83,0x34,0x80,0x71,0x79,0xf0, + 0x06,0x49,0x89,0xdd,0x95,0xa0,0x9c,0xd1,0xa6,0x04,0x8b,0x5b,0xad,0x24,0xdc,0xbc, + 0xe3,0xa6,0xe2,0xe8,0xbb,0x83,0x2a,0xea,0xca,0x45,0x82,0x71,0xb3,0x3d,0x6c,0xba, + 0x44,0xa2,0x5b,0xde,0x9b,0x76,0x22,0xfa,0xcb,0x64,0xe0,0x9e,0xdb,0x5d,0x65,0x9d, + 0x29,0x8b,0xd6,0x6a,0x3b,0x81,0x6b,0xeb,0x24,0xc3,0xab,0xef,0xf8,0xde,0x02,0x2a, + 0xc0,0xae,0xf3,0xb5,0x5b,0xe0,0x63,0xfb,0x25,0x60,0xfd,0x54,0xef,0x69,0x64,0x82, + 0x39,0x1d,0xa4,0x6d,0xfb,0xef,0xb0,0xd2,0xc3,0xdb,0xac,0x21,0x7e,0xfa,0x6c,0x92, + 0x34,0x1c,0x4a,0x7c,0x41,0xaa,0x26,0x00,0xcf,0xfe,0xda,0x25,0x42,0x50,0x65,0x82, + 0xed,0x1d,0x5a,0xcd,0xb6,0x11,0xfd,0x9d,0x0b,0x16,0x52,0x56,0x99,0x73,0x6d,0x92, + 0xb0,0x1c,0x7e,0x6c,0x46,0x48,0xb9,0x41,0x1e,0x5c,0x25,0x4a,0xc2,0x72,0x24,0xc2, + 0x63,0x19,0x23,0x84,0x7a,0x76,0x50,0x06,0x83,0x4f,0x92,0x96,0x5c,0xfc,0x86,0x3a, + 0xc2,0x2e,0x0c,0xb1,0x1e,0x3f,0x24,0x4d,0x83,0xaa,0x64,0xa6,0x5d,0x16,0x4f,0xc9, + 0x01,0xbb,0x9d,0x12,0x32,0xd6,0x95,0x07,0x1f,0xfd,0xf5,0x1a,0xc1,0xe4,0x94,0x36, + 0x12,0xb6,0x4d,0x13,0xc3,0x31,0xee,0x13,0xe5,0x8e,0x97,0xb7,0xae,0x88,0x66,0x8a, + 0x35,0x15,0x82,0x60,0xb8,0x03,0x4c,0xd8,0x14,0x47,0x2e,0x52,0xf7,0x8e,0xd5,0x98, + 0x56,0x92,0x9e,0x18,0x61,0xbd,0x1c,0x84,0x9e,0x5d,0x31,0xbe,0x79,0x8d,0x67,0x8a, + 0xb1,0x15,0x71,0x71,0xb8,0xc1,0x2d,0x4f,0xb4,0xd1,0x9f,0xbc,0x25,0xa7,0x50,0x99, + 0x96,0x3b,0xef,0x9f,0x9c,0x36,0xb2,0x51,0x61,0xd0,0x81,0xbf,0xed,0xd6,0x7e,0x41, + 0x85,0xb1,0xe6,0xa4,0x9b,0xe3,0x73,0x6a,0x6b,0xbb,0xe8,0x88,0x12,0x71,0x15,0x3f, + 0x9a,0xbc,0xb1,0xa2,0xd0,0xdc,0x56,0x57,0x8a,0x52,0xe4,0x59,0x8c,0xf1,0x09,0x23, + 0x4b,0x25,0xa7,0xcf,0xd7,0x33,0x0d,0xe8,0x49,0x58,0x58,0x12,0x5e,0x6e,0x77,0x50, + 0x04,0x19,0xf0,0x2e,0x8b,0x3e,0xf7,0xd7,0x69,0x5c,0x0b,0x2d,0x5a,0x87,0x60,0x38, + 0xe5,0x9b,0xa2,0xe0,0x96,0xa4,0x88,0xc2,0x40,0x40,0x8a,0xce,0x7c,0xaf,0x56,0x4b, + 0x36,0xb5,0x50,0x94,0x95,0x2b,0x87,0x75,0x87,0x31,0xe1,0x3d,0xb0,0x3e,0x85,0xe5, + 0x94,0xcd,0xed,0x65,0xa7,0x69,0xc9,0x51,0x3b,0x1d,0xe8,0x29,0xb3,0xc2,0xd1,0xfb, + 0xb2,0x4c,0x91,0xff,0xe2,0x6c,0x71,0x0e,0xa6,0xd7,0x55,0xa8,0xd4,0x43,0xaa,0xaa, + 0x71,0xcb,0x54,0x24,0x25,0x60,0x08,0x24,0xba,0x88,0xa0,0x7f,0x35,0xc4,0x56,0x9a, + 0x4e,0x6f,0x17,0x25,0x2f,0xc9,0x42,0x9a,0x55,0x8a,0xed,0x90,0x64,0x27,0x5b,0xe6, + 0x94,0xc9,0x1b,0xaf,0x56,0x6b,0xb3,0xe7,0xd5,0xda,0x89,0x8f,0x9c,0x4b,0x71,0x5e, + 0x08,0x2a,0x0e,0x17,0xd5,0x0a,0x20,0x63,0x60,0xdc,0xc7,0x5b,0x70,0xa5,0x7b,0x0a, + 0xab,0x93,0xc2,0x0c,0x13,0xa5,0xa1,0xae,0x6e,0xc9,0x1d,0x50,0x81,0xec,0x4a,0x18, + 0x1c,0x84,0xf3,0x09,0xba,0xb2,0x10,0x07,0xa6,0x8d,0x45,0xd6,0x0d,0x14,0x36,0xfb, + 0x80,0xc5,0xfa,0xee,0x7b,0x27,0x69,0xd4,0x6f,0x41,0xb1,0xc7,0x8a,0xa7,0x4b,0x18, + 0xc8,0x84,0x32,0xe7,0x73,0xf0,0x01,0x8b,0x2f,0x64,0x43,0xbd,0x5d,0x32,0x2b,0xd8, + 0x0e,0x21,0x73,0xd1,0x1f,0x5c,0xd3,0x8c,0xcc,0xc8,0x3c,0xc4,0x58,0xe4,0xec,0xa7, + 0x03,0xcf,0xd4,0x77,0x90,0x5b,0x68,0x6b,0x7c,0xbf,0x3a,0xa7,0x38,0xf6,0xad,0xd9, + 0x82,0x86,0xba,0x59,0x7b,0x51,0xb9,0x09,0x8d,0x3e,0xf3,0xeb,0xac,0x61,0x26,0x5c, + 0x87,0x9c,0xa3,0x4e,0x76,0xfe,0x83,0x1d,0x30,0xd4,0xf8,0x19,0x24,0xaa,0xfd,0x81, + 0x1f,0x08,0xee,0x1b,0x07,0xb1,0xb4,0x44,0x57,0x3b,0xaa,0x61,0xb6,0x80,0x74,0xbc, + 0xa7,0x95,0x6b,0x7e,0x1d,0xfe,0x44,0x5a,0x62,0x9e,0x39,0x5e,0x55,0xbc,0xe5,0x03, + 0x54,0xd0,0x5d,0xa0,0x15,0x38,0x8d,0xb3,0x25,0x58,0xbd,0xa2,0x9f,0x5b,0x22,0xf1, + 0xab,0xf1,0x19,0xf5,0xf6,0x43,0x5d,0xb1,0xe6,0xde,0x42,0x86,0x9c,0x71,0x44,0x8b, + 0x87,0x4b,0xf7,0xdf,0x30,0xbf,0xf0,0x00,0xe4,0xd0,0x8a,0xaa,0x49,0xd4,0x13,0xac, + 0x14,0x0d,0xd4,0x25,0x0f,0xd0,0xfc,0x34,0x2f,0xd3,0x26,0x1e,0xef,0x38,0x05,0xc1, + 0xb7,0x9b,0x0b,0x45,0x36,0x1f,0x2a,0x81,0xc4,0x1b,0x42,0x96,0xf0,0xaf,0x95,0xa8, + 0xb7,0xd8,0xd5,0x24,0x83,0x4c,0x5d,0x0a,0x46,0xb4,0x00,0x1f,0xa1,0xba,0x6c,0x37, + 0x22,0xde,0xff,0x85,0xdb,0xb5,0x7c,0x17,0x87,0xe2,0x90,0xdf,0xdf,0x7c,0x16,0x1f, + 0xab,0x4b,0x6d,0x78,0xbf,0xbd,0x40,0x73,0xe2,0x5f,0xaa,0xd8,0x8a,0x04,0xe1,0x09, + 0x2c,0x91,0x8d,0x5f,0xe0,0xa1,0x21,0xc9,0x84,0xd7,0xee,0xa9,0x1b,0xe1,0x17,0x1e, + 0xa3,0xf9,0x37,0xfd,0x93,0xfd,0x37,0xfb,0xe1,0x70,0x2c,0x4c,0xb6,0xe0,0x06,0xc8, + 0x33,0x91,0xfc,0x32,0x3e,0xfe,0x96,0xe3,0x4c,0xec,0xe6,0xf7,0x3a,0x53,0x56,0x21, + 0xda,0x86,0x01,0xad,0x53,0xf2,0x46,0x08,0x90,0xdb,0xfc,0x0d,0x6a,0x48,0x9c,0x49, + 0x2e,0xc6,0x7c,0x71,0xb8,0xbd,0xbe,0x69,0x6e,0x2f,0x7e,0x9d,0x05,0xfa,0x27,0x3d, + 0x56,0x8f,0xee,0xac,0x8f,0xf0,0x5f,0xc7,0x4e,0x26,0xe1,0xc0,0x96,0xbd,0x99,0x8c, + 0x82,0x03,0x6f,0xea,0x90,0xb8,0x70,0x96,0x15,0x4d,0x7f,0xcf,0xd0,0xfc,0xc8,0xf0, + 0x1e,0x02,0xa8,0x42,0x91,0xaf,0x45,0xad,0xee,0xcc,0x9c,0x28,0x04,0x68,0x85,0xf1, + 0x88,0x0d,0xa1,0xc3,0x10,0x7d,0xbd,0xc9,0x00,0x84,0xb0,0xc7,0x2d,0x6b,0x0c,0xe8, + 0x03,0x07,0xa9,0x7c,0x11,0x6c,0xe6,0xb5,0xea,0xa0,0x35,0x3f,0x72,0xde,0x7a,0x1e, + 0xf9,0x45,0xbf,0x2f,0xce,0x2b,0x81,0x93,0xce,0x49,0x6b,0xc1,0xa5,0xd9,0xf3,0x42, + 0x23,0x4b,0xb0,0xae,0xae,0xf1,0xc8,0xb0,0x5b,0x78,0xa3,0x1b,0x7d,0x1a,0x7e,0xab, + 0x69,0x09,0xf3,0x7d,0x4b,0x85,0x2f,0x83,0x6e,0x4b,0x05,0x9e,0x23,0x05,0x0a,0xaf, + 0x7b,0x08,0xb1,0x67,0x64,0x12,0x4f,0x77,0x70,0x83,0x99,0xa2,0xdf,0x51,0x59,0x6a, + 0xc9,0x6a,0xa2,0xa9,0x98,0x2a,0x28,0xc0,0x37,0x87,0x80,0x28,0xba,0xe8,0xcc,0xfe, + 0x3a,0xed,0xaa,0x92,0x99,0x3c,0xe0,0xd0,0x22,0x86,0x3a,0x53,0x39,0x29,0xc7,0xd9, + 0x84,0x11,0xa3,0x3b,0x18,0x77,0x4a,0xc1,0x2f,0x5a,0x93,0xed,0x62,0xc5,0xb1,0xde, + 0x4b,0x2b,0xab,0xd3,0x19,0x66,0x1a,0xcf,0xfa,0xf0,0xe9,0x2d,0xd9,0x61,0x1c,0xaa, + 0x1a,0xf1,0xba,0x23,0xc6,0x23,0x2a,0x60,0xaf,0x0d,0xda,0x7c,0xe7,0x5a,0x35,0x18, + 0x47,0x1b,0x59,0x07,0x21,0xf2,0x4c,0x7e,0xf8,0x00,0xe0,0x97,0xec,0x2c,0xd4,0xb6, + 0x73,0x6d,0xf1,0x12,0x53,0x21,0xa6,0x97,0xde,0x73,0x2e,0x70,0x49,0xc3,0x03,0x4d, + 0x40,0x00,0xf1,0xe5,0x68,0x72,0x25,0x9b,0xdb,0x02,0x82,0xf5,0x26,0x9e,0x24,0x79, + 0x81,0x9a,0xb9,0x5a,0xdd,0x34,0xfb,0x4e,0xe0,0x83,0xae,0x23,0x54,0x8d,0xb8,0xf2, + 0xde,0x9d,0x28,0xe6,0xbf,0x54,0xa2,0xb9,0xc2,0x34,0xe4,0xeb,0xa1,0x7e,0x82,0x69, + 0x90,0x5d,0x82,0x8e,0x34,0x66,0x34,0xa7,0x30,0x36,0xb2,0x47,0x10,0x67,0x47,0x8c, + 0x92,0x71,0x77,0x9d,0x6e,0x0c,0xf2,0x5f,0x61,0x10,0xaf,0x9d,0x24,0xc7,0xe8,0x5f, + 0xdd,0x99,0x64,0x4b,0xcb,0x62,0xe0,0x02,0x46,0x5e,0x2d,0x96,0xa3,0x0b,0x22,0x97, + 0xc2,0xa3,0xad,0x94,0x63,0x9a,0x75,0x06,0x73,0x90,0x63,0xc9,0x8c,0xa8,0xa6,0x3f, + 0xa4,0xa6,0xfe,0x4e,0x5b,0x72,0x50,0x8a,0x8a,0x12,0x45,0x14,0x51,0x74,0x32,0xa3, + 0x71,0x88,0x6d,0xab,0x2d,0xe8,0x25,0xd5,0x5d,0x88,0x09,0x0b,0x0a,0x14,0xfe,0xee, + 0xa5,0x9e,0xbd,0x62,0x80,0x37,0xaa,0xa1,0x8f,0x48,0xee,0x9e,0x0c,0xa7,0x08,0x7e, + 0xab,0x1d,0x2e,0x92,0xb5,0xa4,0xa2,0xb1,0xce,0x49,0x6d,0xbc,0x41,0x84,0x01,0x49, + 0xa4,0x91,0xb8,0x62,0x9c,0x0e,0xf8,0x47,0x68,0x41,0x07,0x17,0xf8,0x0a,0xd4,0xfb, + 0xea,0xeb,0x76,0xff,0x15,0x27,0xf0,0x57,0x69,0x50,0xb8,0x5f,0x39,0x84,0x66,0xcd, + 0x2c,0xac,0xf9,0x42,0xc1,0xa1,0x53,0x83,0x02,0x18,0xa9,0xb6,0x54,0xe0,0xe2,0xaa, + 0xf5,0xe2,0xb6,0x0a,0xda,0xe1,0x5f,0x1e,0x4f,0x40,0x30,0xe9,0xe5,0xe0,0x29,0x69, + 0x61,0xfe,0xa2,0x37,0xe6,0x90,0x7e,0x0f,0x03,0x51,0xfe,0x48,0x6b,0x7c,0x75,0x47, + 0x5c,0x5e,0x32,0xaf,0x62,0x60,0xf8,0x1b,0x0b,0xc3,0x3e,0x97,0x61,0x77,0x28,0x17, + 0x37,0x62,0x80,0x48,0x94,0xc3,0xca,0x64,0x5e,0x8c,0x07,0x03,0x78,0x48,0xd0,0x90, + 0x85,0x1a,0x93,0xf8,0xf4,0xc7,0x8f,0xb6,0x6e,0x28,0xba,0xd3,0xeb,0xc1,0x99,0xfc, + 0x21,0x73,0x84,0x01,0x00,0xc6,0xf4,0x65,0xc0,0x8c,0x11,0x02,0x56,0x52,0x11,0xc3, + 0xfb,0x98,0x1d,0x5d,0x5c,0xe7,0x60,0x2f,0x30,0x8c,0x3b,0x3c,0x51,0xb7,0x98,0x66, + 0x8b,0x92,0xd2,0x7f,0xc3,0x07,0xe0,0x11,0xca,0x95,0x0f,0x18,0x78,0x3b,0xd1,0x76, + 0x82,0x2b,0x93,0x72,0x7c,0xaa,0x06,0x90,0xeb,0xf8,0x2c,0x8c,0xce,0x86,0x1e,0x5e, + 0x4d,0x89,0x99,0xbc,0x77,0x35,0x0f,0x64,0x7f,0xa0,0xce,0xc2,0x2d,0x7b,0x52,0xf3, + 0x6a,0xb7,0xe8,0xa6,0x13,0xa7,0x9d,0x57,0x74,0xb0,0xd4,0xf7,0x18,0x47,0xb7,0xec, + 0xa9,0x23,0x8b,0x54,0xd5,0xcc,0x33,0x55,0xeb,0x89,0x16,0x4c,0x78,0xe2,0x52,0x0b, + 0xcd,0x8f,0x84,0x18,0x8c,0x35,0xd5,0xd4,0xcd,0x01,0x41,0x3a,0xf0,0xa8,0x5b,0x0e, + 0x6c,0x21,0x88,0xed,0x30,0xb6,0x8d,0x22,0x2b,0xda,0x33,0x58,0xf8,0x9d,0xd9,0xdb, + 0x2e,0x8d,0x85,0x18,0x4c,0x55,0x85,0x32,0x6a,0xdb,0x9e,0x39,0x49,0x8f,0x92,0x99, + 0xef,0xe0,0x5d,0x73,0xe1,0x71,0x76,0xeb,0xa7,0x88,0x17,0x05,0xc8,0xe4,0x11,0x24, + 0x2d,0x60,0xc5,0x04,0x31,0x31,0xde,0xd6,0xa4,0xa9,0xc7,0xf0,0xe4,0x1d,0x04,0xb0, + 0x6f,0x18,0x37,0xb1,0x47,0xcd,0x66,0x98,0x4a,0x63,0x75,0x15,0x40,0x71,0x2d,0xfd, + 0x44,0x02,0xc5,0x59,0xb1,0x03,0x42,0x99,0x26,0xc0,0x92,0x1d,0x3e,0xd3,0x32,0xe0, + 0x4c,0x9d,0x8a,0x80,0xa5,0x2c,0x15,0xa4,0xb4,0xb4,0x83,0x44,0x50,0x7d,0x14,0x7a, + 0x33,0xde,0x18,0xdc,0xfc,0xf5,0xd3,0x5c,0xe5,0x58,0xbd,0xc9,0x09,0x0e,0x7c,0xaf, + 0x03,0xf7,0x8b,0x80,0x65,0xbd,0x89,0xaa,0x47,0xb7,0x9e,0x4d,0x9f,0xfd,0xed,0xff, + 0x26,0xd1,0x84,0xcd,0x7c,0xd7,0x18,0xb5,0x71,0xb7,0x06,0x12,0x02,0x6e,0x4a,0x20, + 0x95,0xf1,0xde,0x9c,0x8d,0xa1,0xd1,0x00,0x86,0x45,0x75,0x9d,0xe8,0x4b,0x14,0x38, + 0xce,0xd1,0xc0,0x7d,0x37,0x8f,0x4e,0xca,0x94,0x81,0x99,0x1c,0x2b,0x5b,0x5d,0xeb, + 0x05,0x3a,0x45,0xe3,0x04,0xb6,0x0e,0x88,0x32,0xd9,0xce,0x69,0x05,0xeb,0x2b,0xd5, + 0x84,0xd7,0x1c,0xd7,0xcf,0x2a,0x05,0x88,0x07,0x46,0x85,0x39,0x16,0x4b,0xe4,0xa7, + 0x2a,0xb3,0x8d,0x51,0x89,0x66,0x0e,0x8d,0x8b,0xc8,0x62,0x54,0x89,0x4e,0x77,0x07, + 0x4e,0x66,0x0e,0x90,0xb1,0x34,0x1b,0xbc,0xf9,0xbd,0xc5,0xc0,0xa7,0x26,0xa8,0x0f, + 0xef,0xa6,0x9e,0x8d,0x23,0x8e,0xd8,0x45,0x6c,0xc0,0x8c,0x25,0xfd,0x5a,0xd7,0x3b, + 0xe5,0xeb,0x4b,0xb8,0x1a,0xab,0x07,0x9c,0x4a,0xcb,0x38,0x6c,0x5e,0xc6,0x20,0xcd, + 0x8f,0x8f,0x43,0x2c,0xfe,0x40,0x0d,0x84,0xba,0xd3,0x0b,0x9c,0xaf,0xa3,0x2e,0xa9, + 0xab,0xac,0x96,0x91,0x84,0xa6,0xdb,0x18,0x8f,0x6c,0x43,0x61,0x94,0xf2,0x1f,0xef, + 0x10,0xbe,0x4c,0x94,0x4d,0x13,0x45,0xb0,0x5e,0xd1,0xcd,0xa5,0x45,0xbf,0x11,0xdd, + 0x46,0xfb,0xae,0xa0,0xc3,0x40,0x54,0x53,0x87,0xd0,0x46,0x61,0xfa,0xf0,0x3d,0x9b, + 0x05,0x0f,0x27,0xa0,0xe4,0xa3,0xb2,0xa4,0x42,0x84,0x90,0x64,0x54,0x48,0x98,0x7a, + 0x20,0xf1,0xa7,0xec,0x11,0x63,0xac,0x63,0xcd,0xed,0x8e,0x56,0x7e,0x40,0x38,0x9b, + 0xc9,0x0d,0x36,0xb4,0x49,0x5f,0x2b,0xc4,0x21,0x24,0xea,0xa7,0xda,0x16,0x32,0x56, + 0x8f,0x9c,0x0a,0x39,0x49,0x00,0x61,0x62,0x4d,0x5f,0x7c,0x14,0x2f,0x42,0x4c,0xba, + 0xeb,0xa7,0xda,0x45,0x31,0x64,0xfc,0xff,0x41,0xd6,0x10,0xe1,0x84,0x91,0x76,0xe0, + 0xc1,0x05,0x8b,0x14,0x4f,0x3e,0x66,0xd4,0xce,0xb3,0xc3,0x0f,0xd3,0xd5,0x27,0x95, + 0x69,0xe5,0xdd,0xce,0x94,0xac,0x6f,0xb0,0x80,0xb9,0x87,0x5b,0xb0,0x24,0x37,0xe5, + 0x8a,0x98,0x90,0x33,0x6c,0x8a,0x11,0xf5,0xc5,0xcd,0xe7,0xd5,0x5c,0xc1,0x3d,0x8d, + 0xf3,0xd5,0xd2,0x85,0x0e,0x33,0x3c,0x2e,0xd9,0x47,0xaf,0x6d,0x5e,0x40,0xf5,0xd2, + 0xa2,0x48,0x0a,0xdc,0x1f,0x92,0x62,0x6b,0xc5,0x55,0x2a,0x7d,0xc8,0x2b,0xc7,0xf7, + 0x75,0x68,0x5c,0x7b,0x15,0xac,0xa7,0x7a,0x44,0xe6,0xc5,0x6c,0xff,0x42,0x32,0x79, + 0xd5,0xf6,0x09,0x99,0xda,0xf8,0x35,0x3f,0x58,0x0a,0xd1,0x3d,0x30,0xc1,0x44,0x75, + 0xe3,0xc6,0x92,0x8b,0xc4,0x24,0xd5,0x2f,0xa3,0xef,0x41,0x2c,0x1e,0x2e,0x18,0xa7, + 0xfc,0x4f,0xd6,0xb1,0xf2,0x2e,0x64,0xc8,0x89,0x4d,0x39,0x6d,0x27,0x4c,0x51,0xb6, + 0x75,0x83,0x47,0x3e,0xb8,0x61,0x35,0xbd,0x21,0x7d,0x1f,0x1e,0xdc,0x0c,0x01,0x49, + 0x62,0x2c,0x27,0xce,0xef,0x27,0x25,0xd1,0xe2,0x8c,0xc4,0x59,0xb8,0x4f,0xb0,0xe2, + 0xd7,0x75,0x84,0x00,0x68,0x5c,0xff,0x4e,0x44,0x64,0x5e,0x94,0x8f,0x8f,0xe8,0x6a, + 0x42,0x31,0x1d,0x8b,0x49,0x2a,0x19,0x6f,0x92,0x64,0x50,0x53,0x77,0xfb,0x3d,0x7e, + 0x84,0x9f,0xda,0x8d,0xb6,0xe2,0x6d,0x61,0xac,0xbd,0xaf,0x15,0x0f,0x30,0xe9,0x6a, + 0xc2,0x53,0x2b,0xf3,0x3e,0xb5,0x65,0x95,0x5f,0x8c,0xd1,0xf2,0x2f,0x79,0x0e,0x5d, + 0xdd,0x78,0x53,0x34,0x02,0x95,0x43,0x13,0x58,0xc9,0x46,0xe1,0x50,0x15,0x5f,0x54, + 0x60,0x15,0x7e,0x65,0x01,0x9a,0x06,0x0e,0x0b,0xf6,0x70,0x1c,0xd9,0x38,0x7b,0xf9, + 0x7c,0xb9,0x90,0x36,0x36,0xbd,0x75,0x41,0xaa,0xa7,0x56,0x96,0xce,0xc9,0x73,0x70, + 0x2c,0x91,0x69,0xb7,0x44,0x9a,0x23,0x40,0x80,0xa8,0xba,0x13,0xe1,0x3a,0xe2,0x76, + 0x4b,0x78,0x86,0x4c,0x20,0x23,0x6d,0x4f,0x70,0xa6,0x54,0xdf,0x3f,0xf9,0xf4,0x90, + 0xd0,0xd6,0xc6,0x03,0x38,0xf9,0x20,0x74,0xe6,0xdf,0x32,0x23,0x78,0x39,0xe3,0x76, + 0x8c,0x87,0x5d,0xeb,0x47,0x97,0x6c,0x82,0x4b,0x1b,0x6c,0x52,0x11,0x59,0x0e,0xe7, + 0x4e,0x0b,0xb1,0xa4,0x34,0x59,0x1f,0x79,0xed,0x72,0x93,0x47,0xff,0xf1,0x46,0x88, + 0x70,0xb1,0x12,0x0b,0xe4,0x34,0x00,0x58,0x81,0xdf,0xb4,0xec,0xdd,0x67,0x9e,0x43, + 0x28,0x9f,0x2d,0x9c,0x4d,0xe0,0x5e,0x38,0x6f,0x74,0x60,0x7c,0x59,0xbc,0x09,0x59, + 0x51,0xb3,0xcd,0xbe,0x94,0x50,0x69,0x48,0x65,0xd8,0xa7,0x8b,0xea,0x7d,0x8f,0x09, + 0xb2,0xbc,0x0b,0x23,0x46,0x53,0x3a,0x8a,0xcd,0x31,0x5f,0x3b,0x93,0x31,0x8c,0xa7, + 0xfb,0x5d,0xff,0x0e,0x12,0x70,0x02,0x13,0xc0,0x6f,0xf2,0xdd,0xbd,0xa3,0x57,0x68, + 0x2b,0x1e,0xa8,0xef,0x19,0xa5,0x9c,0xc1,0xc9,0x80,0x86,0xe7,0x35,0x3e,0xf5,0xfd, + 0x7d,0xe1,0x30,0x18,0xe4,0x39,0x91,0x50,0x67,0x61,0x1d,0xbc,0xd7,0x40,0x40,0xf0, + 0xa1,0x4e,0x2e,0xee,0xd9,0xe1,0x86,0x6f,0xe4,0x81,0xc6,0x44,0xf3,0x8f,0x8c,0xd0, + 0x06,0x8c,0xb9,0x35,0x78,0x2b,0x76,0x5f,0xaf,0x0e,0x88,0x59,0x3c,0x31,0x0a,0x53, + 0x04,0xc5,0x92,0x36,0x0f,0xe7,0x40,0x8d,0xb6,0x87,0x68,0x04,0xbc,0x94,0xe2,0x30, + 0xac,0xe8,0xb9,0x42,0x7f,0x65,0x0e,0x9b,0xc6,0x67,0xa3,0xe3,0xff,0x1c,0x65,0xa9, + 0x81,0x0d,0xa3,0x6a,0x7e,0xa4,0xb5,0x95,0x2e,0x84,0x06,0x9f,0xa0,0x2a,0x59,0x02, + 0xe9,0x37,0xe8,0xb2,0x44,0xea,0x8d,0x4a,0x44,0x18,0xd5,0x6e,0x58,0xc0,0x90,0xe5, + 0x29,0x84,0xf1,0x1e,0x66,0x09,0x1f,0x3c,0xd9,0xad,0xc4,0x8b,0xa8,0xed,0x22,0x7d, + 0x7b,0x9a,0x20,0x23,0x40,0x3b,0x0c,0x84,0xc4,0xba,0xc8,0x5c,0xb6,0x1b,0x50,0x3c, + 0x2c,0x34,0x04,0x70,0x40,0x70,0x43,0x1c,0x12,0x54,0xa9,0x2e,0xa1,0x46,0xe5,0x0b, + 0xfd,0x2c,0x0e,0xd1,0x1f,0x05,0x9e,0xf8,0x4e,0xc4,0x09,0x29,0x50,0x43,0xae,0xa9, + 0x7b,0x20,0xd4,0x3c,0x7e,0x8d,0x9d,0xba,0x53,0x8f,0xe2,0x6f,0x34,0x9c,0xf4,0x38, + 0xfe,0xe2,0xff,0xc8,0x98,0xc4,0x37,0xef,0x8d,0xe4,0xe0,0x87,0x4a,0xa3,0x78,0xde, + 0x81,0xed,0xf3,0x92,0x99,0x25,0x31,0x66,0x26,0x6c,0xff,0x82,0xdb,0xec,0x9b,0x74, + 0x00,0x0d,0xda,0xbf,0xdd,0x21,0x53,0x26,0x19,0xf1,0xb9,0x17,0x16,0x5f,0x98,0xec, + 0x86,0xf4,0xd2,0xaa,0xd4,0x1e,0x66,0x9a,0x19,0x7e,0x2b,0xc5,0x32,0x70,0x5d,0xa4, + 0x5d,0x9d,0x61,0x02,0xf7,0x41,0x96,0x13,0x38,0x71,0x67,0xe6,0x07,0x52,0x92,0x71, + 0x81,0x86,0x3a,0xe4,0xc9,0xdf,0x9d,0x43,0x01,0x00,0xb9,0x48,0x14,0xb1,0x36,0x31, + 0x40,0xf8,0x20,0xfa,0xdd,0xb7,0x16,0xe2,0x65,0x94,0x66,0x0e,0xd4,0x7f,0x39,0xa1, + 0x45,0x43,0xbc,0x52,0x74,0x27,0x71,0x43,0x05,0x7a,0xef,0x10,0x57,0xe4,0x5b,0x72, + 0x78,0x39,0x09,0x54,0xce,0xbe,0x69,0x68,0xe0,0x5c,0xf1,0x01,0xe6,0x7d,0x13,0x7b, + 0x8e,0x54,0xe5,0x4b,0x84,0xac,0xaf,0x0f,0xe7,0x7a,0x37,0x1f,0xa2,0xba,0x86,0x99, + 0xa0,0x97,0xc4,0x86,0x3d,0xf8,0x48,0xad,0xcd,0x77,0x7a,0x48,0x95,0xbb,0xee,0x1a, + 0xe9,0xdb,0xd0,0x2a,0xd6,0x5a,0xe7,0xba,0x96,0x42,0x78,0xcd,0x5b,0x97,0x4f,0x8c, + 0x2f,0xde,0xa3,0x45,0xdf,0x45,0xe3,0xd8,0xab,0xa5,0x5b,0x3d,0xfc,0xf2,0x6f,0x8d, + 0xab,0x99,0x91,0xa2,0x5f,0xab,0x3f,0x3f,0xb9,0x8a,0xdd,0xbe,0xfe,0xbb,0x60,0xf7, + 0x4d,0xdc,0x5e,0x31,0xd7,0xbf,0x20,0xdb,0x29,0x73,0x0d,0x1f,0xdd,0x5c,0x54,0x6b, + 0x4d,0x32,0xd0,0x7e,0x98,0x1d,0x00,0x52,0xef,0x8e,0xa7,0x2e,0xda,0x62,0x71,0x7a, + 0x45,0x3d,0x0b,0x50,0xbf,0xde,0x22,0x95,0x84,0x5d,0xc5,0xdf,0xb6,0x41,0x3d,0x5f, + 0xec,0xb5,0xa7,0x5b,0xb0,0x12,0xbf,0x3e,0x06,0xd2,0x13,0x64,0xfe,0x6f,0x59,0xb7, + 0xa5,0x6e,0x6b,0x44,0x1c,0x21,0xa8,0xde,0x50,0x0d,0xc9,0xd8,0xb5,0x9f,0x52,0x11, + 0x81,0xc3,0xab,0x62,0xdb,0x50,0x9e,0x77,0xa0,0xb7,0x58,0x88,0x4f,0x6b,0x63,0x00, + 0x83,0x43,0x17,0xd0,0x1d,0x39,0xee,0x5f,0xe2,0xaf,0xee,0xdd,0xd0,0x0c,0x32,0xe0, + 0x22,0xa3,0x73,0xf5,0x95,0x6d,0xe6,0x43,0x17,0x9c,0x9f,0xb1,0xab,0xbd,0xfa,0xa0, + 0x42,0x14,0x99,0xdd,0xb7,0xdb,0x28,0xe2,0x60,0x74,0x90,0xfc,0xd1,0x69,0x93,0x26, + 0x8e,0x47,0xea,0xa7,0x31,0x88,0xf0,0x60,0xa2,0x5e,0x65,0x29,0xac,0x38,0x9b,0x45, + 0xa6,0x1d,0xff,0x91,0x4e,0x29,0x69,0x89,0x4e,0x89,0xac,0xa7,0x73,0x79,0x9a,0xd8, + 0x80,0xc5,0x03,0x4a,0x30,0xa3,0x4f,0x97,0xe1,0xf7,0x52,0x8b,0x6a,0xdf,0x30,0x38, + 0x40,0xb7,0x13,0xac,0x2c,0x21,0xbe,0x57,0x82,0xb0,0xda,0x25,0x6b,0xfc,0x4f,0xf0, + 0xe7,0x44,0xfb,0x7a,0xea,0x39,0x5e,0xf8,0x09,0x9c,0xfc,0x11,0xbe,0x72,0xb8,0xce, + 0x52,0x02,0x43,0xb4,0x77,0x31,0x2d,0x75,0xce,0x99,0x29,0x4d,0x98,0x06,0x11,0x18, + 0xa8,0x5b,0x33,0xe6,0x14,0xd6,0x90,0x06,0x94,0x50,0xb8,0x4b,0xfa,0x2b,0x82,0xf1, + 0xdd,0x06,0xfc,0xae,0x3b,0x6c,0x46,0xea,0x68,0xbc,0xad,0x06,0x0b,0xf3,0x5c,0x75, + 0xac,0x40,0xdc,0xfc,0x59,0x89,0xb8,0x91,0x2f,0x22,0x1a,0xfc,0x76,0xcd,0x07,0xa1, + 0x3c,0x43,0xc5,0xed,0x73,0xe4,0x6b,0x2e,0xf9,0x2a,0xbb,0x6b,0x59,0x0a,0xe7,0xcb, + 0xc3,0x07,0x9b,0xbf,0x5b,0x34,0x02,0x4d,0x6e,0xb0,0x8f,0x6c,0xa7,0x6b,0x5d,0x36, + 0x87,0x0b,0x97,0x00,0x46,0x20,0xc7,0x92,0x53,0x3c,0x54,0x1d,0xcb,0x1e,0x8d,0xd0, + 0x61,0x5f,0xf9,0xf2,0xfb,0xa0,0xa4,0x77,0xa3,0x01,0x99,0x30,0x07,0x79,0xf7,0xe7, + 0x2f,0x94,0xcd,0x05,0x3d,0x29,0xad,0x90,0xdc,0x1d,0x55,0x19,0xa4,0x7a,0x1c,0xe3, + 0x06,0x10,0x75,0x1d,0x14,0xb5,0x15,0x30,0x00,0x1c,0xc4,0xaf,0x96,0xb5,0xd2,0x26, + 0xaf,0x2f,0x3b,0xb7,0x18,0x5a,0xea,0x08,0xa2,0x92,0xd5,0x86,0xf0,0xe1,0xae,0x23, + 0x57,0x13,0x98,0xa6,0xd8,0xc4,0x64,0x0e,0x9e,0x81,0x9a,0x96,0x8c,0x73,0xe7,0xb6, + 0x91,0x92,0x22,0x85,0xb6,0xc2,0xaa,0x63,0xc0,0x46,0x8f,0x07,0xf4,0x5c,0xbf,0xc7, + 0xa5,0x3d,0xf3,0xe8,0x3e,0x91,0x25,0xe3,0x08,0x86,0x2f,0x78,0x52,0xa8,0x17,0x14, + 0x1b,0xdf,0x86,0x6a,0x0b,0xac,0x46,0x89,0x38,0x1a,0xb6,0x94,0xf7,0x85,0x57,0x74, + 0xcc,0x10,0x34,0x7c,0x23,0x15,0x47,0xa3,0x0e,0xd9,0xe7,0xc0,0xeb,0x71,0xbf,0xb8, + 0x94,0x55,0x5d,0x11,0x8b,0xae,0xc7,0x74,0xeb,0xba,0xf1,0x95,0x9b,0x7e,0x0d,0xeb, + 0x9a,0xdc,0x0b,0x19,0xc3,0xd4,0xb7,0x09,0xcd,0x58,0x9a,0x39,0x8f,0x73,0x5e,0xdb, + 0x89,0x1f,0x96,0x0c,0x6f,0x7e,0x36,0x5e,0x38,0x1e,0x69,0xd0,0xf8,0xe9,0xc9,0x3a, + 0xc2,0x1e,0xe6,0xda,0x9a,0x22,0x9b,0x8b,0xc8,0x52,0xfa,0xbc,0x18,0x4e,0x27,0x7a, + 0x36,0x95,0x8b,0xe8,0x3b,0x5a,0x1b,0x89,0x68,0x99,0x89,0x0f,0xde,0x78,0x57,0xcc, + 0x08,0x19,0x7b,0xbf,0x00,0x5a,0x9f,0x90,0x56,0x59,0xa7,0xda,0x98,0x5c,0x7a,0x06, + 0xa3,0x92,0xc7,0xf9,0xe1,0x36,0x43,0xa6,0x3e,0xdd,0x58,0x0a,0x76,0xb1,0x08,0x9b, + 0xe4,0x9a,0xa8,0xd1,0xe8,0x17,0x39,0x4d,0xe2,0xc2,0xe0,0xb2,0x66,0x8b,0x99,0x32, + 0xb8,0xcd,0x5a,0x3c,0xe4,0x39,0x79,0xa7,0x31,0x8d,0x29,0xcf,0xe3,0x2f,0xdf,0xf5, + 0x97,0xcc,0xf3,0x15,0x26,0x7a,0x2d,0x3f,0xc3,0x80,0x01,0xd7,0x8d,0xf8,0x65,0xaa, + 0xde,0x4f,0xa7,0xa0,0xf7,0x0b,0x20,0x15,0x5e,0x4b,0x45,0x77,0x22,0xc9,0x99,0xb4, + 0x23,0x9e,0xaf,0x30,0xe8,0x08,0xdc,0x84,0xc0,0x45,0x98,0x4c,0x74,0xea,0xe5,0x67, + 0x67,0x9d,0xb5,0xb4,0xe2,0xbd,0x73,0x85,0x67,0xdd,0x67,0x8f,0x16,0x2b,0x99,0xab, + 0x69,0x3c,0x7a,0x10,0x49,0xad,0x20,0x47,0x62,0xdc,0xa0,0x61,0x32,0x82,0x02,0x8b, + 0x3f,0x4f,0xc3,0x4e,0x08,0xb3,0xfd,0xea,0x04,0x8a,0xee,0x58,0xa3,0x84,0x22,0x0b, + 0xf8,0x7f,0xeb,0x78,0x6f,0xad,0x63,0x7d,0x2e,0xb9,0x69,0xa2,0x5c,0xa9,0x9b,0xf5, + 0x03,0x7c,0xd6,0x69,0xe4,0xe5,0xe0,0x19,0x4c,0xcb,0x8d,0x72,0x02,0xa8,0xd3,0x19, + 0xcd,0x06,0xe9,0x58,0x7c,0x0d,0xc3,0x39,0xed,0x89,0x9b,0x87,0xee,0xfc,0x66,0xa7, + 0x06,0xd7,0xb8,0xca,0x15,0xcd,0x64,0x8c,0xaf,0xca,0x8a,0x86,0x4a,0xa1,0x6a,0xa7, + 0x2f,0xcf,0xea,0x5e,0x1f,0xc1,0x3f,0x9c,0x49,0xc6,0xc1,0x59,0xfc,0x88,0x43,0xa2, + 0x60,0x55,0x23,0xcf,0xe3,0xae,0x05,0x21,0x6d,0xd5,0x88,0x67,0x7b,0x51,0x6c,0x49, + 0x6e,0x94,0xd5,0x8b,0x55,0xac,0xb6,0x3c,0xf4,0xab,0xc4,0x9d,0x5d,0xec,0xdc,0x6a, + 0xc2,0xdd,0xfd,0x98,0xd1,0xdc,0x26,0xa6,0xcc,0x5b,0xed,0xbc,0x13,0x22,0xaa,0xe0, + 0x82,0x8a,0xcb,0x66,0xb5,0xae,0x90,0xc1,0x38,0x27,0x7c,0x0f,0xce,0xea,0xc9,0x11, + 0xb4,0x9a,0x61,0x7c,0x39,0x4f,0x6c,0x42,0x01,0x2d,0x95,0x2f,0xc7,0xe5,0x0a,0x67, + 0xad,0xd2,0x36,0x1d,0xb6,0x33,0xfd,0x0f,0xb3,0xd9,0x66,0xc1,0x0e,0x9f,0x96,0xd4, + 0x87,0x14,0xdc,0x28,0x9a,0xb9,0x86,0x6b,0x9b,0xdb,0x8c,0xc1,0x34,0xfb,0x54,0x15, + 0xe5,0xc5,0xd1,0x94,0x96,0x38,0x04,0x70,0xe7,0x91,0xa6,0x76,0xd4,0x90,0x1d,0x41, + 0x40,0x52,0x18,0xad,0x37,0xbb,0x4f,0x61,0x00,0xfc,0xcf,0xc0,0x55,0x93,0x65,0xda, + 0xc4,0xc7,0x32,0xd6,0x40,0x08,0x45,0x1b,0xbd,0x98,0x85,0x1f,0xf7,0x6c,0x36,0xba, + 0x20,0x9b,0xff,0x94,0x5b,0x7e,0x2d,0x42,0xb8,0x15,0x8c,0x35,0x7a,0x2b,0xd0,0x72, + 0x1a,0x54,0x3f,0xd9,0x0e,0x2d,0xd2,0x3e,0x1b,0xeb,0x6d,0xfe,0x4e,0x6d,0x32,0xe2, + 0xaa,0xe2,0xb7,0xbf,0xb8,0x96,0xf3,0x2e,0xaf,0x29,0xb6,0x6f,0xb0,0xb8,0x77,0xda, + 0x9e,0xf0,0x15,0x0c,0x81,0x74,0x77,0xb3,0xeb,0x68,0x65,0xb3,0xce,0x6f,0x1e,0x48, + 0xc4,0xe8,0x9d,0x3e,0x98,0x1d,0xce,0x0a,0x6a,0x5c,0xd6,0x17,0x76,0x87,0x3e,0xd2, + 0x4c,0xbd,0xbc,0x69,0xd4,0xd9,0x92,0x68,0x33,0xd5,0x86,0x02,0x7f,0x06,0x3d,0xd6, + 0x0d,0x98,0xb3,0x3c,0x3a,0x33,0x8f,0x03,0xb4,0x93,0x08,0x03,0x8b,0xc5,0x17,0x59, + 0x8d,0x4f,0xd7,0x34,0x0c,0xfd,0xfb,0x0b,0xb3,0x90,0xef,0xfb,0xa7,0x7b,0x5e,0xa5, + 0xe4,0xab,0xb1,0x28,0x00,0x24,0xcf,0xf2,0x37,0xb6,0x93,0x65,0x50,0xc4,0x9e,0x63, + 0x6d,0x6d,0x4c,0x4a,0x1f,0x3f,0x90,0xdc,0x41,0xcc,0x48,0x75,0x51,0xec,0x53,0x29, + 0x61,0xad,0x03,0x5b,0x34,0xcf,0xd1,0x44,0xa0,0x39,0x06,0x84,0x18,0x61,0x6f,0xc0, + 0x80,0x43,0xf0,0xea,0x1c,0xa5,0x66,0xcc,0xc3,0x98,0xe7,0x94,0x3a,0x20,0x80,0xf0, + 0x21,0xb1,0x3f,0xac,0x65,0xe9,0x0b,0x42,0x39,0x64,0xb0,0x46,0x91,0x69,0x89,0x95, + 0xea,0xcf,0x08,0xe4,0x9b,0x2d,0x05,0xa2,0x45,0xf5,0x74,0x0b,0x89,0x9a,0x91,0x7b, + 0xa8,0x44,0x6d,0xc0,0x69,0x48,0x8c,0x60,0xf5,0xb0,0xaa,0x42,0x73,0xd9,0x17,0xb3, + 0x87,0x82,0x49,0x44,0xeb,0x87,0x7b,0x99,0xb4,0x8a,0x62,0xef,0x24,0xca,0x0e,0x95, + 0xe1,0xc2,0x8a,0x4c,0x1c,0xd3,0x22,0xac,0x71,0x12,0xec,0x04,0xb1,0x79,0x9f,0xe9, + 0x7b,0xb8,0x1b,0xe3,0x45,0x94,0x0b,0x7f,0x83,0x83,0x1c,0xb8,0x77,0x9e,0x7c,0xf1, + 0x88,0x71,0x54,0x7f,0x6f,0x81,0x29,0xda,0xf8,0xe7,0x3f,0xbe,0x9f,0x60,0xbc,0xa9, + 0x7d,0x68,0x89,0xee,0xa9,0x86,0x53,0x25,0xcf,0xc8,0x9d,0x15,0x59,0x24,0xf1,0xaa, + 0x62,0x8f,0x54,0x0d,0xa2,0x37,0xad,0x93,0xc7,0xe1,0x9c,0x5c,0xad,0xd3,0x9e,0xab, + 0x25,0xad,0x96,0x2a,0xa4,0x76,0x23,0x09,0x1e,0x5b,0x1a,0x60,0x6f,0xe0,0x3d,0xf9, + 0x7f,0xad,0x18,0x3b,0x65,0x35,0xdc,0xf2,0xa9,0x4a,0xe9,0xdd,0x25,0xf1,0xdd,0x58, + 0x93,0x09,0xcb,0x60,0x70,0xbe,0x13,0x71,0x36,0x23,0xa5,0x50,0x30,0xfe,0x5f,0x80, + 0x5b,0x18,0xba,0xac,0x72,0x9f,0xef,0x87,0xc1,0xaf,0xf2,0x04,0xf2,0x97,0x0e,0x63, + 0x19,0x9c,0x66,0xe6,0xda,0x12,0x22,0x11,0x17,0xfe,0xd4,0x14,0x77,0xf2,0xc5,0x9d, + 0x94,0xef,0x14,0x94,0x80,0x36,0x03,0x05,0x0b,0xc3,0x6c,0xc7,0x3a,0x83,0x73,0xbd, + 0x69,0x22,0xf3,0x31,0x5a,0x02,0x88,0xf6,0x08,0x10,0x91,0x5d,0x86,0xbe,0xfb,0x45, + 0xdd,0x12,0x7b,0xe9,0xcd,0xe9,0x6c,0x1b,0x9f,0x16,0x14,0x54,0xee,0xc2,0xf8,0xaf, + 0x80,0x98,0xac,0x67,0xff,0x38,0xf9,0x6b,0x92,0xdc,0xa2,0xdd,0x75,0xf6,0xb3,0x3b, + 0x57,0x19,0x14,0x3b,0x53,0x89,0x81,0xf3,0xe4,0xd5,0xab,0xc9,0x47,0xe0,0x2d,0x66, + 0x14,0x18,0xb4,0xf2,0x12,0x08,0x7d,0x1b,0x56,0xde,0x93,0x71,0xdd,0x23,0x17,0xfb, + 0x18,0x76,0xf8,0xa4,0xd1,0x29,0xf1,0x5b,0x1c,0xf5,0x3a,0x29,0x83,0x14,0x30,0xb0, + 0x27,0xb6,0xcd,0x18,0x5b,0xd8,0x4e,0xcf,0x21,0xd4,0xe7,0xc0,0xeb,0x73,0x65,0x89, + 0xa9,0x2a,0x2b,0x1e,0xff,0x30,0x43,0x37,0x03,0xeb,0x28,0x36,0x9b,0x7e,0x1e,0x88, + 0x9d,0x1f,0x70,0xda,0x73,0x6a,0x61,0x80,0x02,0x8a,0xd8,0xce,0x85,0x74,0xf2,0x2a, + 0x0e,0x69,0x72,0x48,0x58,0x48,0x76,0x62,0x69,0x1d,0xee,0x16,0xd6,0x71,0x1c,0xe6, + 0x05,0x5f,0x8e,0x34,0x34,0x70,0x0c,0xa1,0x6d,0x3e,0xe5,0x72,0xcc,0x11,0x15,0xe7, + 0x84,0xeb,0x07,0xd0,0x09,0x34,0x97,0x4c,0x6e,0x1c,0xa8,0xaa,0x64,0x01,0xd7,0xea, + 0x8f,0x92,0x97,0xd0,0x39,0x98,0xff,0x97,0x48,0x3a,0xe1,0xd1,0x25,0xd2,0xe0,0x67, + 0xac,0x0b,0xb1,0xc1,0xca,0xaa,0xa6,0x12,0x4e,0x82,0x87,0xf2,0x52,0x63,0x88,0x60, + 0x67,0xb7,0x7c,0xd9,0xee,0x2a,0x3e,0x1a,0xc5,0xbc,0x9e,0x92,0x77,0x4c,0x79,0x32, + 0xe8,0x2d,0xb3,0xf7,0x96,0xe0,0xe5,0xf8,0x84,0xcd,0xb2,0x34,0xfe,0x13,0x57,0x14, + 0x24,0x88,0x2e,0x93,0xbb,0xdd,0x95,0x41,0x0f,0x12,0x2e,0x97,0x38,0x93,0x96,0xa9, + 0xa7,0xea,0x59,0xe3,0xfd,0xd5,0xb4,0x93,0x3f,0xc4,0xae,0x53,0x5e,0x49,0x52,0xb0, + 0x85,0x62,0xed,0xbe,0x18,0xe8,0xee,0x01,0x2b,0xa9,0x6e,0x31,0x8d,0xef,0x03,0x09, + 0x87,0xd7,0xb8,0xab,0x73,0xad,0x0f,0x1f,0x27,0x69,0xbf,0xf7,0x2d,0x4b,0x12,0x31, + 0x70,0xe2,0xb1,0x47,0x12,0x44,0x1f,0xa2,0xc4,0xae,0xb2,0x86,0x74,0xa7,0xa2,0x2b, + 0x90,0xca,0xb5,0xf5,0x7f,0x8a,0x4c,0x8e,0xad,0x6e,0x1e,0x5c,0x96,0xeb,0x19,0x23, + 0x0b,0xdb,0xd4,0x37,0x92,0x7f,0xad,0x29,0x6b,0xca,0x2d,0xcd,0x21,0x85,0x71,0xeb, + 0x74,0x5b,0x63,0xaa,0x03,0x1b,0x24,0xd8,0xe6,0x65,0xcd,0x8f,0x3d,0x4c,0xe7,0x9f, + 0xef,0xa3,0xa3,0x0a,0x69,0x9a,0x5b,0x8c,0x3e,0xc6,0xdb,0x88,0x62,0xe6,0x5a,0xb5, + 0x8c,0x6b,0xc2,0x76,0x3e,0x4f,0x4c,0x5f,0x0e,0x33,0xcc,0x5b,0xbe,0x6d,0x0a,0xed, + 0xb8,0x80,0xf9,0xa6,0x1f,0x16,0x32,0xc7,0x49,0xae,0xc2,0x84,0xf3,0xe0,0x9e,0x29, + 0xf2,0x71,0xb1,0x71,0xa2,0x5b,0xcc,0x2c,0x04,0x64,0x1b,0xeb,0xf0,0xba,0xb8,0x1c, + 0x81,0x50,0xed,0xdb,0xc7,0xc3,0xdb,0x19,0x3c,0xaa,0x84,0xfb,0xf1,0xab,0x5c,0x06, + 0x0a,0x5d,0xac,0x9b,0xdd,0xe1,0x0a,0x8f,0x46,0x3d,0x00,0xd5,0x56,0xff,0x9f,0x37, + 0x23,0xf8,0x40,0x08,0x36,0x11,0x42,0x8a,0x8c,0x00,0x84,0x25,0x57,0xf7,0x7e,0x1c, + 0x58,0x11,0xb7,0x83,0x43,0x4f,0x33,0xd1,0x0f,0xa3,0x19,0x25,0x1a,0x4d,0xc2,0xe0, + 0xe2,0xec,0x6d,0x32,0x4b,0x13,0x8e,0x8a,0x55,0x82,0x4b,0x4d,0x54,0x55,0x1a,0xea, + 0xcd,0x25,0x42,0x42,0x34,0x4d,0xc9,0x00,0x0d,0xdb,0xe1,0x78,0x75,0xd5,0xa6,0xa0, + 0xcc,0x4d,0x7c,0x54,0xdd,0x51,0xda,0x81,0x5b,0xda,0x1f,0xb6,0x61,0xb7,0x75,0x5f, + 0xa2,0xb2,0xe5,0xc7,0xb6,0xb6,0xf5,0x9c,0xe0,0xb5,0x59,0x88,0x28,0xab,0x13,0x8e, + 0xd8,0x86,0x2d,0x57,0xca,0xb7,0xc9,0x80,0x97,0xd8,0x29,0xf1,0xf1,0x74,0xff,0x8a, + 0xd4,0xc9,0xb3,0x9f,0x0c,0xbc,0x37,0xa8,0x28,0x04,0x21,0x6e,0x30,0x55,0xee,0xeb, + 0x75,0xdb,0xcc,0x9e,0x3c,0x59,0xfa,0x70,0xde,0x66,0xee,0x5c,0xff,0x1e,0xf8,0x59, + 0xdb,0x6c,0xc8,0xfc,0x84,0xd4,0x87,0xdc,0xe2,0x06,0x20,0x4d,0x50,0x57,0xfb,0xed, + 0xde,0x6d,0x98,0xb6,0xbb,0x38,0x01,0x83,0x19,0xaa,0xc2,0xdd,0xbd,0xf4,0xbd,0xfc, + 0x28,0xcf,0xe6,0xce,0x3e,0x11,0x48,0xdf,0x4d,0x9c,0xf9,0x06,0x09,0x31,0x16,0xde, + 0xcf,0x62,0x2e,0x7b,0xab,0xb0,0x0c,0x7e,0x41,0x99,0xb6,0xe3,0x79,0x7e,0x9c,0xb8, + 0xe5,0x35,0xa9,0x4b,0xdc,0x87,0xd0,0xc3,0xb2,0xf6,0x5b,0x6b,0x9c,0x24,0xdc,0x39, + 0x9c,0x11,0x14,0xf8,0x1e,0x40,0x47,0x05,0x43,0xd2,0xb1,0x7b,0xd1,0xab,0xc0,0xb0, + 0x59,0x04,0x19,0x88,0x23,0xf2,0x24,0xde,0xa9,0xc9,0xb0,0x21,0x3b,0xa8,0xbc,0xd7, + 0xe8,0x90,0x32,0xfb,0x6d,0x9e,0x2c,0x49,0x72,0xd3,0x67,0x12,0x1d,0x06,0x03,0x10, + 0xec,0x2b,0x39,0xfa,0xa3,0x16,0x0b,0x20,0xe1,0x02,0x95,0x56,0xb1,0xe0,0x6f,0x6d, + 0x68,0x72,0xb3,0xb0,0x62,0x38,0xa1,0xd1,0xd3,0x58,0x79,0x08,0x75,0x33,0x9b,0xa8, + 0x4c,0x49,0xd0,0xc4,0xb3,0xa6,0xe8,0x24,0x7a,0x40,0xc0,0x21,0xaf,0x6b,0xe4,0xcf, + 0x00,0xc4,0xd9,0xd0,0x33,0x27,0x62,0x8f,0xc3,0x27,0x18,0x54,0x51,0xee,0xbe,0xa9, + 0xee,0x4b,0xb9,0xb5,0x35,0x87,0x90,0x90,0xfa,0x66,0x8b,0x83,0xba,0x77,0x10,0x46, + 0x66,0x81,0xf1,0x45,0x30,0x92,0x67,0x58,0x80,0x48,0xdd,0x97,0xb8,0x68,0x64,0x71, + 0x09,0x2a,0xa6,0x7a,0xaf,0x85,0x02,0x4e,0xb7,0x0a,0x72,0x8c,0x6b,0xa8,0xf5,0x6b, + 0x35,0xaa,0x75,0x22,0xba,0x6b,0xa5,0xde,0x7a,0x68,0x22,0xcf,0x4c,0x72,0x3d,0x31, + 0xe0,0xd3,0x9d,0x03,0x3b,0xaf,0xd4,0x5b,0xfb,0x2a,0x2b,0xde,0xc1,0x7a,0x14,0x5e, + 0x87,0xa4,0x8c,0x5a,0xaa,0xeb,0xa3,0xc6,0xcf,0xf2,0x9a,0x5b,0x32,0x13,0x46,0x08, + 0x0e,0x4b,0x54,0x73,0x2a,0x6e,0x4a,0x71,0xab,0xe3,0x52,0x1f,0x36,0x2e,0x1a,0xd9, + 0x43,0x09,0xca,0xd8,0x3b,0x45,0x4c,0x4d,0x4d,0x4c,0xcb,0xf8,0x7b,0xcb,0xc2,0xe9, + 0x9e,0xae,0x59,0x3d,0x9c,0x2f,0x46,0x96,0xa9,0xc2,0xc3,0x49,0x25,0xc3,0x4a,0xf9, + 0x81,0xaf,0x74,0xbf,0xf8,0xa3,0x56,0x0b,0x68,0xc4,0x85,0x9f,0xdf,0xc2,0xe7,0x04, + 0x72,0xfa,0x84,0x00,0x68,0x5c,0x4d,0xb8,0xc5,0xef,0xb2,0xb0,0xf7,0x32,0x42,0x50, + 0x39,0xe4,0xb7,0x28,0xc2,0x6c,0x16,0xb2,0x9e,0x4a,0x22,0xf3,0x42,0x95,0x3b,0xb4, + 0x2d,0xb4,0x3a,0xb4,0xf9,0x8d,0xa5,0x30,0x01,0x31,0x7d,0xa1,0xcb,0xd6,0x9b,0x15, + 0x8b,0x80,0x9b,0xf7,0x79,0x9a,0x5e,0xd7,0x20,0x30,0x7f,0xf5,0x8c,0x3f,0x2c,0xc6, + 0xa1,0x70,0x6b,0x40,0x5f,0xea,0x94,0xc0,0x32,0x59,0xc2,0xcc,0xc1,0x69,0x9c,0xa2, + 0xc8,0xf4,0x5a,0x50,0x68,0xb9,0x9c,0xd0,0x1b,0x58,0x85,0x30,0xd6,0xaa,0x2d,0x23, + 0x21,0x1b,0xea,0xae,0x6b,0xc3,0x0d,0xe5,0x4b,0xa8,0xfd,0x87,0x57,0x89,0x17,0x83, + 0xcb,0xf6,0x0d,0xf5,0xe3,0x3a,0x20,0x03,0xc0,0x17,0x62,0xa9,0x0c,0x79,0x00,0xbd, + 0xa8,0x17,0xfe,0xbe,0xc7,0x54,0xc2,0x78,0xe9,0xa0,0x17,0x44,0xb0,0xb3,0xf5,0xbf, + 0x88,0xe6,0xe8,0x7e,0xce,0x22,0x26,0xe5,0x96,0x1c,0xc3,0xbf,0x94,0x62,0xef,0x3c, + 0x8c,0x17,0xb8,0x12,0x47,0xa7,0xe8,0xda,0xcd,0xfb,0x97,0x45,0x70,0xba,0x50,0x4b, + 0xda,0x3e,0x4c,0xfb,0x85,0x84,0x1e,0xcb,0xc7,0x84,0x3f,0x2b,0xf8,0xa1,0x86,0xe8, + 0x33,0x11,0x39,0x3c,0xfb,0x0d,0x6a,0x8c,0x09,0xd5,0xee,0x06,0x87,0x33,0x82,0x28, + 0x8c,0x5f,0xb6,0x2c,0x5a,0x0c,0x4b,0x10,0xeb,0x10,0xe0,0xd4,0xf6,0xfb,0xab,0x5b, + 0xaa,0x16,0x07,0xed,0xa3,0xc3,0x42,0x03,0x4f,0xf1,0xf7,0xe4,0xb2,0x6f,0x5f,0xc5, + 0x0a,0x14,0xb6,0xae,0x83,0x70,0xa0,0x92,0x66,0xa9,0x58,0xbd,0x35,0xdf,0x3f,0x7d, + 0x0a,0x2f,0x1b,0xe0,0x04,0x5d,0x27,0xca,0x0c,0x3d,0xb1,0x40,0xbf,0x78,0xe8,0xb7, + 0xd3,0xc3,0xf0,0x06,0x26,0xa0,0x2c,0x54,0xba,0x83,0x84,0xb2,0x68,0x44,0xba,0x87, + 0xaa,0x5f,0x59,0xef,0xc6,0xef,0xc9,0x21,0x82,0xd9,0x86,0x73,0xd2,0x98,0x6a,0xc6, + 0x6c,0x62,0x89,0x13,0xa6,0x82,0xfe,0x41,0xf6,0x63,0x87,0x47,0x5a,0x45,0xa0,0xa3, + 0x71,0x80,0xf5,0xc2,0x36,0x9c,0x6a,0x53,0x2a,0xdb,0x66,0xe4,0xf6,0x9e,0xa8,0x86, + 0x4d,0x9e,0x6a,0xd2,0x37,0x14,0x68,0x97,0xba,0xca,0xc6,0x5e,0x51,0xe4,0xe5,0xc7, + 0xad,0xed,0xdb,0xa5,0xa5,0xfd,0x4f,0x4a,0x61,0x84,0x31,0x47,0xbe,0x19,0xff,0x35, + 0xc7,0xc8,0xb3,0xa8,0x34,0x8a,0x7f,0x46,0x2e,0x26,0x8d,0xf3,0xf7,0xe2,0x3a,0x03, + 0x46,0x69,0x1a,0xfd,0x55,0xb3,0x8d,0xcc,0x7f,0xc9,0xac,0xee,0x58,0xc4,0x79,0x18, + 0xa2,0xcb,0x55,0x6c,0x7f,0x56,0x2d,0xd2,0x41,0x34,0xe6,0x8b,0x36,0x60,0x94,0x3e, + 0x8a,0xa9,0x03,0x79,0xfc,0x55,0x8b,0xd4,0xca,0x73,0x60,0x5d,0x23,0xa8,0xff,0x65, + 0x8b,0xe8,0x50,0x24,0xf4,0x30,0xc3,0xbf,0xbf,0x44,0xbb,0x99,0xc9,0xf0,0x42,0x43, + 0x3d,0x6d,0x0d,0x5f,0x2e,0x80,0x68,0x77,0x6d,0xda,0xa8,0x87,0x58,0xed,0xaa,0x32, + 0xc9,0xcf,0x6d,0x3e,0x13,0xc7,0xec,0x3d,0x85,0x75,0x5f,0x4f,0x6f,0xf2,0x59,0xad, + 0x09,0xce,0x5a,0x3c,0xa6,0x24,0x49,0x98,0xa2,0x63,0x64,0x0d,0x21,0x65,0xe4,0x2f, + 0x0c,0x81,0xfe,0xbd,0x42,0x92,0x73,0x7f,0x66,0xa2,0x44,0x99,0xbc,0x66,0xe4,0xe7, + 0xfb,0x34,0x9e,0x23,0xc7,0xf2,0x1e,0x07,0x27,0xdd,0xed,0xa5,0x13,0xf0,0x14,0xd0, + 0x86,0x9d,0x17,0x70,0x25,0x4c,0x38,0x8d,0x0c,0x93,0xb9,0x66,0x4e,0xe5,0x34,0xb6, + 0x80,0x9e,0xa2,0xc0,0x87,0xa2,0xba,0x50,0xf1,0xa9,0xec,0xad,0xb0,0xf1,0x89,0xd1, + 0x21,0x9f,0x55,0xe4,0xd4,0x34,0xa4,0x47,0xd6,0xb3,0x03,0x5f,0x61,0x35,0xe9,0x32, + 0x47,0x35,0xd8,0x19,0x30,0xb5,0x7c,0x27,0x8f,0xe5,0x62,0xa5,0x98,0xb5,0x79,0x56, + 0x07,0xfe,0x36,0x52,0x17,0x25,0x02,0xda,0x54,0xd1,0xc2,0x87,0xa3,0xfa,0xf3,0x29, + 0x03,0x39,0xf2,0xa5,0x55,0xbd,0x3f,0x01,0xc5,0x6e,0xac,0xe4,0x13,0x29,0x55,0x2c, + 0x4e,0xa6,0xd5,0x10,0x84,0x9c,0xc5,0x0c,0x0e,0xc6,0x3d,0xaa,0x0e,0xff,0x4e,0x7b, + 0xaf,0x9a,0xa2,0x9f,0x57,0x70,0x8e,0x55,0x5f,0x78,0xbe,0xf6,0x4f,0x19,0xaa,0xd9, + 0x5b,0x82,0xb4,0xef,0x54,0xb2,0x84,0x55,0x5e,0x0b,0x3e,0x3a,0x00,0x22,0x37,0x83, + 0xec,0xd4,0xa7,0x8d,0xe8,0x17,0x8f,0x50,0xdf,0xee,0xed,0xae,0x5b,0xb6,0xb9,0xfd, + 0x8c,0xdb,0xa9,0x6e,0xf8,0xdb,0x87,0x48,0xf8,0x99,0x9f,0xff,0xfb,0x02,0x3e,0x46, + 0x1d,0x18,0x04,0x8e,0x4f,0x31,0xda,0x75,0x6f,0x9c,0x72,0xd1,0x17,0xbd,0xd6,0xba, + 0x23,0x60,0xe0,0xbc,0x1c,0xe7,0x70,0x98,0x4c,0x7e,0xfc,0x81,0xa9,0x02,0xdf,0x2b, + 0xaa,0x8c,0x99,0xe7,0xb8,0xbf,0x4b,0x34,0xe8,0xdf,0x48,0xa8,0x28,0xf6,0x77,0xce, + 0x9c,0xbb,0x2f,0xff,0xbf,0xfd,0x25,0x1d,0xd7,0x9d,0x6f,0x02,0xff,0xbe,0x37,0x28, + 0xfc,0xe1,0xb0,0x66,0xeb,0x62,0x49,0x0d,0xab,0x04,0x64,0xd7,0xdc,0x21,0x19,0x94, + 0x6c,0xdf,0xf0,0x26,0x35,0x8c,0xbc,0x14,0x22,0xa5,0xa2,0x84,0xff,0xce,0xc1,0xd8, + 0x41,0xf7,0xdd,0x00,0x6d,0x8d,0x2b,0x91,0x6e,0xed,0x83,0xe9,0x3b,0x26,0x53,0x76, + 0xe9,0xe2,0x1a,0x25,0x95,0xdc,0x8c,0xc2,0x45,0xce,0x3d,0x11,0xba,0x52,0x20,0x42, + 0x79,0x09,0xc8,0x55,0xf3,0x6b,0xa8,0x1e,0x29,0x4b,0x5e,0xec,0xaa,0xb5,0xdc,0x58, + 0x05,0x2e,0x17,0x50,0x15,0x0e,0xaa,0xfd,0xe2,0xb4,0xf8,0xe1,0xea,0xc4,0x51,0x32, + 0x8e,0x44,0x01,0x34,0x71,0x67,0xd6,0x53,0x3d,0x40,0xe2,0x5c,0xa5,0x46,0xc6,0xd5, + 0xea,0x88,0xa3,0xa8,0x97,0x65,0xa6,0xf5,0xf2,0x47,0xe1,0x9e,0x1b,0x16,0x7c,0x0e, + 0xe9,0x8b,0x42,0x75,0xe7,0xd5,0x40,0x8f,0xa3,0x2c,0x6d,0xae,0xbe,0x5a,0x21,0x63, + 0xd8,0x75,0xb0,0xac,0xb7,0x86,0x28,0x08,0x82,0xe6,0xc5,0xbd,0x5f,0x71,0xe4,0xfa, + 0x04,0x4b,0x2f,0x29,0x73,0x6e,0x83,0xd8,0x6b,0x8a,0xab,0xd2,0xe7,0x5b,0xb4,0x56, + 0x34,0xa0,0x2f,0x39,0x72,0x6f,0xbb,0x4b,0xab,0xcc,0x9b,0x22,0xe9,0x6d,0x78,0xa0, + 0x10,0x43,0x9e,0xea,0x3e,0x37,0xe9,0x9b,0x26,0x57,0x44,0x7f,0x2a,0x7d,0x3c,0x12, + 0xa8,0x16,0xaa,0xeb,0x22,0x20,0xa5,0x0b,0x27,0x23,0x1a,0x29,0x49,0xf8,0x63,0x58, + 0x6b,0x08,0x1a,0x3b,0xbb,0x1e,0xc2,0x0f,0xa2,0x7f,0x6a,0xe9,0x9f,0x0a,0xde,0x3f, + 0x74,0x14,0xd9,0x51,0x38,0x2b,0xbc,0x39,0xff,0x54,0x4c,0x46,0xf9,0xe2,0x84,0x00, + 0x80,0x1d,0xfa,0x82,0xd1,0xb3,0x6a,0xa6,0x81,0xd3,0x73,0x64,0x74,0x84,0x1d,0x63, + 0xa5,0x9c,0x1c,0x64,0xa5,0xc0,0x62,0xb7,0x0a,0x5e,0xe4,0xa4,0x91,0x8e,0xfa,0x71, + 0x61,0xb3,0xf7,0x76,0x3c,0x3f,0xe3,0x52,0x6c,0x13,0x80,0xd6,0xc8,0xd9,0x5f,0x23, + 0x4a,0x77,0xf3,0x93,0x50,0xb0,0x9d,0xc2,0xd9,0x11,0x71,0xc6,0xcd,0x85,0x45,0x42, + 0xc4,0x46,0x86,0xa4,0x62,0xb5,0x44,0x93,0x6e,0x16,0xd4,0xe6,0x68,0x89,0xb3,0xaf, + 0xac,0x93,0x17,0xd6,0x6b,0xce,0xd3,0x72,0x89,0x49,0xcf,0x07,0xf7,0xd8,0x7d,0x86, + 0x68,0x07,0x45,0x25,0xe2,0xcd,0xc1,0xe9,0xe4,0x7d,0x8b,0xe2,0xf2,0xd7,0xcd,0x91, + 0xbb,0xea,0x04,0xd7,0xab,0xcc,0x65,0x11,0xf9,0x4c,0x79,0x44,0xcf,0x35,0x96,0xe7, + 0x43,0x17,0xf4,0x7f,0xb4,0x35,0x56,0x8a,0xc9,0xc7,0xa8,0x80,0xb2,0x77,0x9e,0x68, + 0xb9,0xe8,0xf0,0x9a,0xd8,0xba,0x08,0xda,0x4d,0xa6,0x24,0x43,0x4a,0xbd,0x87,0x0b, + 0x08,0x60,0x17,0x7d,0x24,0xcb,0xa3,0xcb,0x13,0xa7,0x9f,0xed,0xcb,0xfe,0x71,0x9f, + 0x48,0x98,0xfd,0x6e,0x35,0x36,0x46,0xbe,0x4c,0x83,0x25,0x22,0x0e,0x60,0x24,0x36, + 0x29,0x9c,0x14,0xce,0x72,0x91,0x16,0x8e,0x49,0xde,0x58,0xf0,0x79,0xac,0x2e,0x6e, + 0x3d,0xb0,0xae,0x6b,0x02,0x30,0xc8,0x7a,0x8d,0x6f,0xcd,0x8e,0x11,0x0c,0x7d,0x21, + 0xa8,0x51,0x8a,0x8a,0xb4,0xc1,0x97,0x80,0x57,0xaa,0x68,0xdc,0x8a,0xd1,0x5e,0x3b, + 0xc0,0x10,0x63,0x4f,0x88,0x35,0x67,0x88,0x87,0x56,0xa1,0xd0,0x62,0xf7,0x58,0x06, + 0x86,0x85,0x9a,0xb6,0xba,0x0f,0x4e,0x25,0xb1,0xcf,0x42,0xbe,0xf5,0x1f,0x10,0xec, + 0xa9,0x8c,0xd6,0xf4,0xf5,0x10,0x40,0x49,0x2e,0xce,0xb8,0x29,0x65,0xe7,0x76,0x87, + 0x86,0x87,0x05,0x23,0x64,0xad,0x85,0x5c,0x67,0x83,0x8b,0xdc,0xd2,0xfa,0xb9,0xe3, + 0xdb,0x22,0x56,0x64,0x36,0x30,0xb9,0xb1,0x65,0xb9,0x4b,0xba,0x74,0xa1,0x25,0x24, + 0x46,0xcb,0xe6,0x34,0x94,0x43,0x30,0x04,0x65,0xa4,0x0b,0x19,0x2e,0x4b,0x64,0x19, + 0xe6,0xca,0x29,0xa6,0x5c,0xf4,0x38,0x14,0x07,0x8a,0x5c,0xb1,0xbe,0x74,0x8d,0xdc, + 0x85,0xc6,0xfc,0xa5,0xa1,0x56,0xc9,0x73,0x61,0xdd,0x51,0x15,0xa4,0x49,0xa9,0x8b, + 0x4f,0x53,0x90,0x31,0xb4,0xe7,0xd5,0xe1,0x87,0xcf,0x9f,0x71,0x3e,0x96,0xb4,0xf9, + 0x88,0x05,0x59,0x2a,0x67,0x88,0xa2,0xdb,0xef,0x08,0xfe,0x27,0xfd,0x47,0xba,0x65, + 0x66,0x86,0x75,0x03,0x19,0x19,0x9a,0x48,0x2f,0x6e,0x2f,0xd6,0x53,0xa4,0x71,0x29, + 0x67,0xee,0x7e,0x0e,0xeb,0xaa,0x01,0x1b,0xb0,0x65,0x22,0x08,0x7d,0x45,0xab,0x99, + 0x2d,0xab,0x89,0xef,0x05,0x5a,0xab,0xcb,0x42,0xfa,0x44,0x4c,0xe5,0x87,0xf3,0x55, + 0x32,0x28,0xc6,0x51,0xe2,0x96,0x33,0x18,0xe9,0x61,0x94,0x69,0x5f,0x1c,0x14,0x72, + 0xee,0x72,0xb2,0x73,0x2c,0xe9,0x85,0xfe,0x48,0x56,0xe9,0xed,0xdb,0x42,0xf6,0x62, + 0x67,0xdf,0x23,0x1b,0x01,0xa3,0x62,0x83,0x0e,0x0f,0x4c,0x9c,0x5a,0x43,0x32,0xdb, + 0x2a,0x86,0x53,0xcf,0xbe,0xdf,0x1b,0x79,0xb4,0xc2,0xe8,0x0c,0xe3,0x69,0x56,0x71, + 0xa8,0xd1,0x34,0x02,0x23,0x5d,0xcc,0xaa,0xc1,0x28,0xa2,0xc0,0x8f,0x9c,0x71,0x74, + 0x52,0x91,0x17,0x04,0x35,0xf0,0x04,0x48,0xc9,0xdc,0x82,0x9e,0xf8,0x57,0x7a,0x83, + 0x93,0x64,0x09,0xf8,0x76,0xba,0xcd,0x87,0x0f,0xb6,0x0e,0x3c,0x1f,0x13,0xf2,0x8e, + 0x9a,0xb3,0x82,0xe8,0x6c,0x2f,0x42,0x37,0x9c,0x6f,0x2b,0x77,0x85,0xf5,0xe3,0xd0, + 0xcd,0x75,0xe6,0x36,0x47,0x45,0xf2,0x91,0x0a,0xdb,0xf0,0xad,0x83,0x7d,0x97,0xa3, + 0x4b,0x9c,0xd4,0x25,0x4f,0xd0,0x25,0x1e,0x82,0xdc,0x76,0x39,0xd6,0xcd,0x05,0x75, + 0xf4,0x9b,0x1a,0x43,0xf3,0xa3,0x4f,0x0b,0xe2,0x99,0xf1,0x87,0x5a,0xb4,0x2f,0x51, + 0x41,0xa5,0xd5,0x24,0xc3,0xf5,0x78,0x1b,0x73,0x9a,0x85,0xe4,0xcb,0xc6,0xa6,0x0a, + 0xdc,0x13,0x1d,0xd4,0x18,0x13,0xda,0xd5,0xae,0xd8,0xc0,0xe4,0xdd,0x78,0x8e,0xe8, + 0x4f,0xfe,0x63,0xba,0x5d,0x2a,0x60,0x58,0x69,0xdf,0x2e,0xcd,0x4d,0x08,0x8b,0xba, + 0xc0,0x35,0xdf,0x8b,0x3e,0xbf,0x8c,0x39,0xe8,0x9b,0xcf,0x3d,0xf4,0xf2,0x51,0x9c, + 0x89,0x10,0xd1,0x99,0x5c,0x38,0x0f,0x02,0xe9,0xd9,0x40,0x3b,0xfa,0x60,0x5e,0xbb, + 0x42,0x95,0x6c,0x7d,0x9f,0x13,0x89,0x02,0x6a,0x91,0xd0,0xd6,0x4a,0xc1,0x6a,0x3c, + 0xc6,0x7c,0xbe,0xac,0x84,0xe0,0x36,0x98,0x90,0xc6,0x68,0xed,0x0b,0xec,0x64,0x23, + 0xac,0x15,0x70,0xe8,0x1f,0x11,0xe0,0x0d,0x6c,0x19,0xaf,0xf3,0x36,0x4f,0x17,0xa9, + 0x9c,0xdf,0x2f,0x8b,0xd8,0xfd,0xff,0x9d,0x62,0x29,0xd9,0xc2,0xc7,0x5b,0x50,0x2c, + 0x80,0xd1,0xd6,0x28,0x16,0xaa,0xbc,0xa5,0xff,0x02,0xae,0xf4,0x9a,0x0a,0x51,0x1a, + 0xa4,0x7e,0x75,0x67,0x5a,0xa3,0x64,0xc0,0xdd,0x10,0x40,0x73,0xb8,0x2b,0x3c,0x21, + 0x21,0x60,0x60,0xc5,0x94,0x07,0x8b,0xf3,0xc6,0x8a,0x7d,0xb7,0x90,0x68,0x3e,0xb1, + 0x71,0xf2,0x97,0x20,0xb0,0x01,0x60,0x4e,0x66,0x1e,0xff,0xf4,0x2e,0x0d,0xd5,0x20, + 0x06,0x20,0x99,0x4f,0xb7,0xdb,0x6e,0x4d,0x2a,0x49,0x40,0x16,0xb9,0x85,0xe6,0x41, + 0x6f,0x21,0x80,0xa0,0x5b,0x94,0x98,0x51,0x1f,0xc3,0xd7,0xb4,0x30,0xee,0xef,0x50, + 0xb6,0x22,0xff,0x1c,0x1d,0xd0,0x47,0x03,0x29,0x97,0xef,0x50,0x5f,0xc0,0x79,0x75, + 0x5f,0x76,0xe5,0x88,0xdb,0xb6,0x5f,0xb1,0x8f,0x05,0x65,0x44,0xbf,0x25,0xb5,0x24, + 0xfc,0x39,0xbc,0xd8,0x6b,0x28,0x0a,0x2c,0x61,0x59,0xf0,0x3c,0x59,0xa8,0x1f,0x07, + 0x3d,0x34,0xdc,0x30,0x1f,0xa3,0x43,0xd5,0xae,0x52,0x82,0x5d,0xd4,0xc4,0xc3,0x7d, + 0x4b,0xde,0x95,0x20,0x63,0xb7,0x83,0x5b,0x23,0x7b,0xad,0xfd,0xb1,0x00,0x1b,0x7a, + 0x87,0x10,0xef,0xdd,0x9d,0x0e,0xd7,0xdf,0x22,0xaa,0xd1,0xae,0xd6,0xeb,0xaa,0x70, + 0x69,0x85,0xee,0x10,0x38,0xbd,0x46,0x65,0x88,0xec,0xc2,0xec,0xfb,0x65,0x32,0x9f, + 0xc9,0x0f,0x35,0x2f,0x67,0xa2,0x38,0x3a,0xba,0xcb,0x4c,0xf8,0x7b,0x4e,0xd4,0xa3, + 0x2f,0x84,0x03,0x3e,0xb8,0xa1,0x5b,0x70,0x47,0xf3,0x49,0x9d,0x84,0xcf,0x43,0x5d, + 0x22,0x0b,0x30,0xb5,0x17,0x62,0x5b,0xb9,0x97,0x03,0xe3,0x8f,0xf8,0x15,0xc4,0xd4, + 0xac,0xbf,0xe3,0x7f,0xd9,0x61,0x6c,0x8c,0x8b,0x21,0xcd,0x5c,0xb6,0x78,0xb8,0xe3, + 0x15,0x1e,0xe8,0x54,0x35,0x14,0x0d,0xf7,0xab,0x9b,0xc5,0xd2,0x8e,0x6a,0xa1,0xf2, + 0x98,0x1d,0xe7,0x85,0xb6,0xb8,0x2f,0x52,0xd0,0xff,0x15,0x93,0xf3,0x69,0xcd,0xc5, + 0x11,0xbe,0x70,0x11,0xf2,0xa4,0x15,0xb5,0x68,0x63,0x40,0xc3,0x91,0xa3,0x14,0x30, + 0x85,0xb5,0xd3,0x3f,0xce,0xe5,0x40,0xed,0xa0,0xd4,0x9c,0x55,0x8a,0x95,0x74,0x23, + 0x09,0x98,0x70,0xe5,0x4b,0x77,0x3e,0x21,0x92,0xd3,0x69,0x04,0xde,0xd4,0xd0,0x45, + 0x82,0x14,0x05,0x78,0x0e,0xbd,0x5d,0x61,0x6d,0xeb,0x62,0xcd,0xf4,0x85,0x33,0xe9, + 0x4a,0x34,0xdd,0x55,0x52,0x38,0x5d,0xb1,0xdd,0xfa,0x4b,0x71,0xd3,0x75,0x90,0x6a, + 0x84,0xb5,0xdc,0x8d,0x9b,0x9c,0xd6,0x78,0x9a,0x55,0xe8,0xaa,0x99,0xfb,0x78,0xeb, + 0x11,0x16,0x46,0x8f,0x55,0x53,0x44,0x90,0x01,0x28,0xe6,0x54,0x72,0x3b,0x16,0x6b, + 0xae,0xd2,0x96,0x4c,0x70,0x2b,0x0f,0xad,0x40,0x25,0xe5,0x5e,0x74,0x87,0xbb,0xea, + 0x9d,0x14,0xa9,0xa8,0xfa,0x94,0x61,0xbf,0x8a,0x9e,0xdf,0x80,0x9a,0x6f,0x04,0x37, + 0xc3,0x8d,0x9c,0x51,0x52,0x8d,0x06,0xb9,0x16,0x57,0xec,0x0e,0x86,0x6d,0x72,0x5c, + 0xc2,0x8c,0x31,0x3e,0x58,0x72,0x3c,0xb8,0x9a,0xdb,0x19,0xcd,0x4b,0x3f,0xeb,0x56, + 0xab,0x5e,0x07,0xed,0x90,0xb5,0x01,0xcd,0x65,0xe3,0x17,0x81,0x45,0xf5,0x4d,0x2a, + 0xd3,0xb2,0xd9,0xf0,0xbd,0x3e,0x5f,0xb9,0xd7,0xf2,0xcf,0x5c,0x5a,0x80,0x01,0x64, + 0xbb,0x35,0x5d,0x75,0x24,0xa9,0x0e,0x17,0xc9,0x66,0x4b,0x59,0x14,0x34,0x39,0x2c, + 0x69,0xc3,0x3d,0xe5,0x91,0x2a,0x3f,0xc2,0x66,0x60,0x62,0x50,0xae,0x8d,0xb2,0x39, + 0xfc,0x77,0xe5,0xf7,0xf8,0x03,0x7f,0x63,0xc0,0xee,0xc9,0x15,0x2b,0xf9,0xb3,0xc1, + 0x51,0x62,0x1b,0xa6,0xa1,0xe1,0xaf,0xc0,0x41,0x4e,0x06,0xac,0x34,0x65,0xd7,0x6f, + 0x00,0x5e,0x2b,0xa0,0x06,0xe9,0x63,0x60,0x5a,0xa8,0x8e,0x4e,0xbf,0xf5,0x68,0x78, + 0x3b,0x95,0x0f,0x84,0xb6,0x0a,0x1a,0x72,0x44,0x85,0x30,0x05,0x3b,0x4c,0x54,0xb3, + 0x8e,0x5d,0x2e,0xa1,0xb2,0xa0,0x4e,0xf1,0xe5,0x5b,0x5d,0xf4,0x8f,0xec,0x49,0x42, + 0x0a,0xe4,0x7a,0xa6,0xe7,0x87,0xd1,0x4b,0x2e,0xe4,0xe8,0x17,0xc6,0x6c,0x85,0x22, + 0xb9,0xca,0xe8,0x80,0x1f,0xe8,0x60,0xa1,0xa7,0xac,0xb2,0x6e,0x48,0xf3,0x14,0x2f, + 0xae,0xec,0xb2,0x9b,0xf4,0x63,0x3f,0x49,0x21,0x6d,0xe3,0x29,0x3e,0x6b,0xa9,0xff, + 0x67,0xee,0x97,0xe0,0x75,0x4b,0x0b,0xcb,0xc8,0xe6,0x7f,0xdf,0xd4,0xa5,0x15,0x33, + 0x2e,0xd6,0xd4,0x58,0x74,0xda,0xf1,0xd9,0x2d,0x6f,0x43,0x4c,0xde,0x85,0xc9,0xef, + 0xdb,0x92,0xdc,0x76,0x93,0x0a,0x68,0x6e,0x6d,0x8f,0x4e,0x5f,0x6e,0xae,0xd2,0x86, + 0xe4,0x7c,0x80,0x6f,0x6f,0xef,0x85,0x05,0xc2,0x4b,0x29,0x45,0x6f,0x18,0x1e,0xb4, + 0xbd,0xea,0xb7,0x8f,0xb4,0x25,0xc4,0x57,0xc8,0x77,0xe3,0xef,0x7f,0xe7,0x6a,0x3d, + 0xd0,0x20,0xfb,0xdf,0x3e,0x00,0x79,0x3b,0x81,0x8d,0x6d,0xfb,0xf7,0xc6,0x7e,0x8d, + 0x10,0x8f,0xec,0x6e,0x07,0x4d,0x62,0x8e,0x8f,0xb4,0xa2,0x8f,0x9f,0xb4,0x76,0x43, + 0x11,0x8e,0x1b,0xbb,0xc1,0xe0,0x86,0x4c,0x98,0xbd,0x18,0x32,0x77,0x98,0x9d,0xc4, + 0xaa,0x6d,0x5d,0xf5,0x5f,0xe8,0x0d,0x5c,0xd7,0x09,0x8f,0x17,0x16,0x5d,0x95,0xd4, + 0xab,0x62,0x6d,0xef,0x4c,0xf1,0xde,0x73,0xe1,0xf6,0xe7,0xa7,0x9d,0xc2,0x73,0x85, + 0xec,0xb7,0xa4,0xa4,0x74,0xbb,0x24,0xb3,0x1a,0xdf,0x8e,0x86,0x34,0x7f,0x36,0x00, + 0x4f,0x04,0x5b,0xea,0x31,0xec,0x1e,0xf0,0x96,0x53,0x43,0xbc,0x67,0xf1,0x6d,0xc7, + 0x0f,0x46,0xe3,0xff,0x36,0xaa,0x63,0xc7,0x69,0x6b,0xf1,0x1b,0xf6,0xea,0xad,0xf3, + 0xa5,0x9a,0x10,0x27,0xbf,0x6c,0x7d,0xb3,0xf7,0x7a,0xfb,0xb0,0xd9,0x2b,0xd9,0x0e, + 0x69,0xb7,0xe6,0x44,0x0f,0xa3,0xcb,0xd9,0x2b,0x5a,0xc8,0x87,0x4f,0x83,0xbf,0x70, + 0x88,0x26,0x53,0xed,0x3a,0x10,0x64,0x93,0x05,0xa8,0x39,0x7e,0x7b,0x59,0xfc,0x8b, + 0xcf,0xee,0x1f,0x6f,0xb8,0x9f,0x29,0x83,0xcd,0xf8,0x35,0xd9,0x71,0x7c,0x74,0x9b, + 0x44,0xa1,0xe3,0x7f,0xa9,0xd7,0x41,0xbd,0x8e,0x1e,0xae,0xae,0xc1,0x56,0x99,0x3a, + 0xed,0x3d,0xe6,0xe4,0x02,0xac,0x26,0xbb,0x12,0xd7,0x22,0xb0,0xed,0xc3,0x56,0x21, + 0x29,0xc7,0x45,0x7b,0xea,0xa3,0x41,0x68,0x6f,0x40,0xef,0xfc,0x93,0x5d,0x70,0x4f, + 0x8e,0x9c,0xc7,0xde,0x33,0xdd,0xf7,0x88,0x6e,0xb0,0x37,0xcf,0x61,0x5e,0xd1,0x5f, + 0x87,0x06,0x92,0x5b,0x9f,0xc1,0x1d,0xfa,0xee,0x8f,0x69,0x9c,0x3f,0xbe,0x60,0x44, + 0x71,0x8d,0x8a,0x00,0xb3,0x26,0x4a,0x21,0xe3,0x46,0x6f,0x24,0xaf,0x9f,0x70,0x92, + 0x04,0x6b,0x73,0xf6,0xb0,0xa9,0x67,0xd2,0xc3,0x42,0x67,0xcb,0x51,0x41,0x79,0x83, + 0x85,0x3b,0x09,0x1c,0x31,0xa8,0x1d,0x27,0x61,0xc8,0x6a,0xda,0xd8,0x62,0x31,0xc1, + 0x76,0x0c,0x09,0xf7,0xee,0xaa,0xac,0x53,0x80,0xc3,0x66,0xcb,0x2e,0x43,0x40,0xbf, + 0x02,0xfb,0x62,0x22,0x31,0x06,0x50,0x60,0x42,0x75,0xa8,0x94,0x19,0xc5,0x4c,0xaf, + 0xfc,0xfa,0x4c,0x50,0x30,0x70,0x06,0x59,0xcf,0x74,0xd8,0x0b,0xf0,0xc5,0xbe,0xbe, + 0x7d,0x26,0x98,0x6c,0x37,0x2d,0x4f,0x48,0xff,0x77,0x47,0x8f,0xd4,0x65,0xb6,0x50, + 0x7c,0x27,0x21,0xdd,0xa0,0x16,0x3f,0x58,0x7f,0x76,0xc8,0x64,0xe3,0x25,0x3a,0xd8, + 0xf3,0x07,0x42,0x71,0xda,0x2e,0x6a,0x4a,0x09,0x40,0x92,0xd3,0xa7,0x68,0x40,0xe3, + 0xaa,0x0f,0xa0,0x99,0x17,0xa3,0x62,0xba,0x4c,0xad,0x65,0x3c,0xa6,0x96,0x63,0x4d, + 0x00,0x07,0x0b,0x98,0x39,0xd5,0x6b,0x4b,0x8b,0x35,0x97,0x2d,0x27,0x95,0x5b,0x36, + 0x28,0x81,0x0f,0xbd,0x38,0x5b,0x41,0x38,0x6a,0x4d,0x9b,0xc2,0xd9,0x6b,0xbd,0x49, + 0x02,0x2c,0x7a,0xdc,0xbd,0x28,0x7c,0x41,0xe7,0x1d,0x82,0x2b,0xfb,0xf3,0xb5,0xa7, + 0x03,0x2d,0x4e,0xba,0x70,0x3c,0x14,0x78,0x4b,0x4d,0x4f,0x42,0x6f,0x2f,0x47,0xb6, + 0x75,0x2e,0xc5,0xa5,0xa2,0xa5,0x55,0x45,0xf6,0x1f,0x67,0x0f,0x21,0x9b,0xb4,0xa6, + 0x74,0xf0,0x4c,0x2f,0x70,0x1e,0x5d,0x79,0xcb,0x4f,0xc4,0x26,0x59,0x6b,0x7c,0x02, + 0x21,0x52,0xe4,0xc0,0x76,0x3d,0xef,0x42,0xc1,0xda,0x94,0xa4,0x8f,0x70,0x34,0x40, + 0xda,0x1e,0xec,0xd0,0x29,0x3c,0x9c,0xd2,0x22,0xee,0x9c,0xb4,0x8e,0x71,0x3d,0x51, + 0x1f,0x1d,0x7a,0x25,0x11,0x42,0x6a,0x43,0x62,0x1a,0x95,0x5a,0x0f,0x72,0xb9,0xf3, + 0xe2,0xe4,0xc7,0x6e,0x12,0x3e,0x65,0x33,0xe4,0x93,0x9d,0x4a,0x0e,0x73,0x44,0xc0, + 0x22,0x14,0x55,0xdb,0x0e,0x8f,0x1c,0xe0,0x55,0xc8,0x6b,0x7f,0x87,0xf2,0x4c,0xd1, + 0x23,0x15,0x9e,0x52,0xe7,0xa4,0x64,0x90,0x67,0x71,0x9d,0x70,0x51,0x19,0x41,0xc1, + 0xaa,0x16,0xc1,0xfa,0xde,0x74,0x65,0x63,0x6a,0x8e,0xd5,0xa5,0xb4,0x38,0x49,0xd0, + 0xa3,0x17,0x6a,0xec,0xd0,0x9d,0x5f,0x51,0xed,0xc7,0xe3,0xd9,0x50,0x12,0x7e,0xea, + 0x6b,0xe6,0x8c,0x8d,0x9b,0xc5,0x2e,0x78,0x93,0x57,0x69,0xac,0x87,0x87,0x36,0x48, + 0xde,0x16,0x0b,0x1e,0x3c,0x89,0x54,0x43,0xca,0x5f,0x9e,0x43,0x79,0x79,0x7f,0x0b, + 0xa9,0x58,0x2b,0x08,0x9a,0x37,0x77,0xed,0xfc,0x57,0x68,0x52,0xf8,0x7a,0xbb,0xfb, + 0xea,0x64,0xb7,0x4d,0x42,0x34,0x97,0xa5,0x48,0xd1,0x60,0x42,0xf9,0x84,0x42,0xc8, + 0x22,0x3c,0xd0,0xf9,0x89,0x71,0x36,0xea,0x67,0xd7,0xe8,0xc1,0xd9,0x3e,0xb1,0x27, + 0x2b,0xe2,0xc8,0xf5,0xc7,0x2c,0xb6,0x70,0xe3,0xdd,0xa6,0xdb,0x92,0xcc,0x47,0x36, + 0x55,0xe1,0x9f,0xc9,0x93,0x80,0xd7,0x0b,0x6f,0x3c,0x87,0x2e,0x13,0xef,0x4f,0x26, + 0x54,0x1f,0xc9,0xf5,0xd8,0x37,0xf7,0x71,0xd8,0x04,0xa7,0xec,0x97,0x56,0xd7,0xe0, + 0x86,0xc8,0xc0,0x42,0x1c,0xad,0x60,0x33,0xa5,0xcf,0xb0,0xd9,0xab,0x1f,0x9c,0xe2, + 0x09,0x8e,0xa2,0x17,0xb6,0x5c,0x58,0x92,0x1f,0xce,0x47,0x36,0x55,0x1e,0x39,0xf3, + 0x85,0x8d,0xeb,0xfc,0x37,0xaf,0x51,0x83,0xfe,0xcd,0xb1,0xd8,0x2b,0xe2,0x49,0x57, + 0x92,0x0e,0x83,0x92,0x9b,0xc1,0x59,0x93,0xd9,0xcc,0x46,0xc8,0x2a,0xe3,0x64,0xbd, + 0x0e,0x7b,0x9e,0x73,0x25,0xa0,0x36,0x62,0x46,0xc4,0x3e,0x04,0xad,0x88,0x97,0xad, + 0x0f,0x85,0x44,0xc9,0x16,0xe5,0x61,0x72,0x47,0x05,0xf8,0xb6,0x05,0xa7,0x65,0x42, + 0x8e,0xa6,0x59,0xb8,0x7f,0x47,0x62,0x63,0xc6,0xe6,0x4e,0xfc,0x23,0x60,0x69,0x53, + 0x87,0xa7,0xf5,0x34,0xf4,0x0d,0x1d,0x73,0xc7,0x95,0xa9,0xb4,0x76,0x78,0x5a,0x88, + 0x09,0x42,0xe8,0x0f,0x3e,0xa5,0x52,0x8a,0x20,0xc7,0xb2,0xd1,0x5c,0xe8,0x12,0xca, + 0x72,0x86,0x92,0xce,0xe6,0xa6,0x70,0xc1,0xee,0xcf,0x45,0xc1,0xa2,0x16,0x5b,0x89, + 0x89,0x8e,0x26,0x8d,0x99,0x0a,0x53,0x6a,0x79,0xc7,0xb3,0xd0,0xdc,0xea,0x9f,0x79, + 0xce,0x54,0x93,0x4f,0x95,0xa4,0x37,0x50,0x6c,0x41,0xbb,0x3f,0x22,0xeb,0x62,0x4b, + 0x0e,0x8c,0xf4,0x7b,0xad,0xe1,0x02,0x6a,0x4e,0x4e,0x46,0x0c,0xa5,0x19,0x6e,0x5a, + 0x0f,0xad,0xd0,0xa5,0xe3,0x4c,0x43,0x7a,0x0f,0x62,0xe5,0x25,0xdd,0xe9,0x67,0x4b, + 0x8e,0xae,0xbb,0x4b,0xb7,0x10,0x18,0x6b,0xce,0x54,0xe4,0x51,0xae,0xac,0x6b,0x5a, + 0x87,0x8f,0x2b,0xef,0x19,0x7b,0x78,0x7b,0x93,0xa4,0xb2,0x1d,0x24,0x83,0x5c,0xe0, + 0x67,0x2f,0x9c,0xd6,0x3c,0xbf,0x4b,0x40,0xe6,0x98,0xb4,0x59,0x8b,0xf0,0x16,0x70, + 0x89,0x9e,0xa8,0x96,0x3d,0x91,0x44,0xd0,0x24,0x91,0xbc,0xb6,0x75,0x0e,0x5d,0x01, + 0xa1,0x13,0x35,0x86,0xb4,0x92,0x31,0xc1,0xa7,0x0d,0x4a,0x58,0xf4,0x0d,0x4d,0xd3, + 0x09,0x13,0xad,0x97,0xb5,0x93,0x45,0x31,0xe0,0x73,0x42,0xb7,0xf5,0xf3,0x64,0x3d, + 0xd9,0x94,0x73,0x42,0x14,0x84,0xce,0x1d,0xe4,0x93,0x64,0x0e,0xb2,0xb6,0x6c,0xd2, + 0x27,0x6a,0xbc,0xd2,0xde,0xc4,0xfc,0xf0,0x7b,0xce,0xc2,0xdf,0x36,0xf1,0x65,0x3c, + 0xa6,0x69,0xdb,0xf2,0x15,0xf4,0x8e,0x81,0x9b,0xdf,0xa5,0xe7,0x0b,0xf9,0x92,0x2c, + 0x58,0x68,0x95,0xa4,0x83,0xf5,0xdf,0x95,0x18,0xd1,0x83,0xc2,0x0a,0xfe,0x5e,0x08, + 0x29,0xc1,0xa2,0x8e,0x3c,0xb8,0x0e,0x7a,0x9b,0xd7,0x49,0xae,0x83,0x07,0x8e,0xf8, + 0x6c,0xd9,0xae,0x61,0x3d,0x46,0x5e,0xfe,0x75,0xd4,0x41,0xbe,0x7d,0xf9,0x1d,0x69, + 0x2e,0xb2,0xa3,0x70,0x43,0xba,0x0f,0xfb,0xe8,0xd5,0xb7,0x50,0x03,0xfa,0x57,0x19, + 0xac,0xf8,0x50,0x60,0xbd,0xbb,0x75,0x45,0x4e,0xd6,0x40,0x40,0xfd,0xfb,0x66,0x35, + 0x2e,0x63,0xb6,0xcf,0xc3,0xb3,0x82,0x47,0xcf,0x25,0x72,0xab,0x12,0xfe,0x91,0xda, + 0x2f,0x62,0xf9,0x3c,0xd6,0x2c,0x96,0x72,0x5c,0x86,0xda,0xa2,0x96,0x1c,0x98,0xcb, + 0xae,0x61,0x27,0x6f,0xba,0x13,0x6f,0xfb,0x13,0xd1,0xa7,0x67,0xee,0xf8,0x6f,0x24, + 0xaf,0x9f,0x2f,0x7f,0xb7,0x42,0xc5,0x1b,0xa9,0xc4,0x87,0xfd,0xb7,0x72,0x60,0x03, + 0x55,0x0f,0x15,0x35,0x64,0x8f,0xcf,0xde,0x64,0x5b,0x0f,0x24,0x50,0x60,0x49,0x0d, + 0x32,0x5a,0xf6,0x2d,0xe0,0xa1,0xe0,0xb4,0x18,0x29,0x58,0xb4,0x2c,0x61,0x51,0x1c, + 0x8c,0x03,0x12,0x77,0xfa,0x93,0xf2,0x47,0xf3,0x27,0x91,0xa7,0x3e,0xdf,0xb3,0xf1, + 0xd9,0x18,0xf4,0x66,0xad,0x17,0xa0,0xd3,0x6d,0x3e,0x99,0x35,0xd1,0x65,0x0a,0x80, + 0x3a,0xa9,0xc0,0x84,0x16,0x09,0x1a,0x19,0xc0,0xe3,0xc3,0xa3,0x90,0xe5,0x03,0xbd, + 0xfc,0x88,0x52,0x6c,0x9c,0x88,0x62,0x8d,0xe2,0x9e,0xe6,0x4c,0xdc,0xe3,0x0d,0x21, + 0x9e,0xa9,0xf7,0x7a,0xaa,0x64,0xf7,0xe5,0xc0,0x2f,0xd9,0xf8,0x52,0x86,0x36,0xac, + 0x7c,0x45,0x5c,0xc7,0x30,0x8a,0xde,0x8a,0x30,0x05,0xb9,0x35,0x95,0xec,0xa0,0x6e, + 0x2b,0x18,0xfa,0x3e,0xec,0x27,0x6a,0xc0,0xac,0x05,0x64,0x5f,0x5e,0x6a,0x8e,0x9c, + 0x2a,0x15,0x31,0xad,0x65,0x86,0x28,0xc7,0x6d,0x52,0x9a,0x2f,0x56,0x13,0x5a,0x20, + 0x2d,0x03,0x95,0xad,0x73,0x29,0x11,0xd8,0x6b,0x5a,0x0c,0x2d,0xd8,0x6a,0x9b,0xf1, + 0x1f,0x46,0x1c,0x05,0x19,0xe5,0xa9,0x5f,0x36,0x30,0xa5,0xf0,0x56,0xcd,0x5e,0x3a, + 0xe3,0xc6,0x53,0xde,0x1a,0x26,0x18,0xb4,0xc7,0x0e,0x2a,0x5d,0x62,0x2e,0xe6,0xc7, + 0x08,0x9d,0x71,0xce,0x1b,0x25,0x04,0xa1,0xb4,0x0c,0xa2,0x8c,0x05,0xcc,0x01,0xb6, + 0x63,0x44,0xc2,0x32,0x58,0x21,0xd4,0x83,0xcb,0xce,0xc3,0xed,0x7b,0xec,0x6d,0x9d, + 0xd8,0x74,0x4b,0x9b,0x8d,0x82,0x9b,0xa9,0xb2,0x54,0x4d,0xf9,0xfb,0x4c,0x1f,0x0a, + 0x23,0x00,0xbc,0x7b,0xb3,0x3d,0x2e,0x5a,0x91,0x3c,0x59,0xa6,0xeb,0xd4,0x88,0x6d, + 0xde,0x50,0x2f,0xa9,0xed,0x32,0xdc,0xe9,0x5d,0x13,0x70,0x27,0x76,0x7b,0x5c,0xba, + 0x05,0x19,0x7e,0x01,0xec,0xfb,0x73,0x99,0xe3,0x82,0xd9,0x7d,0x19,0xe8,0x1d,0x34, + 0xf0,0x08,0xd4,0x0b,0x14,0xcc,0x12,0xec,0xe0,0x33,0x8e,0xc6,0xfe,0x7a,0x1c,0x44, + 0x7e,0xdd,0xa6,0xa4,0xdb,0x65,0x84,0x92,0x89,0xb5,0xee,0x17,0x1e,0xff,0xf7,0x60, + 0x2b,0xba,0xec,0x85,0xbe,0xc8,0x53,0xb0,0x67,0x78,0xcc,0x55,0xd2,0x7c,0x7f,0xfc, + 0x49,0xec,0xa7,0xcc,0xb3,0x76,0x6b,0xd4,0x6f,0xf0,0xf4,0xd4,0x9e,0x34,0x86,0x53, + 0x4d,0xaa,0xaf,0xf7,0x46,0xb1,0x75,0x01,0xbd,0xf6,0x9f,0x05,0x54,0xd6,0x32,0xee, + 0x6b,0xe8,0xdf,0xab,0x9f,0x28,0xc9,0x56,0x4c,0xc8,0x15,0x5f,0x67,0xd5,0x3c,0xfe, + 0x9e,0x09,0xf1,0xe3,0x3f,0x81,0x25,0x7f,0xb3,0x51,0xa4,0x53,0x02,0x86,0xf8,0x75, + 0xa8,0x01,0x3f,0x77,0xa8,0x77,0x37,0xd3,0x9b,0xea,0x5d,0x5f,0xb8,0x85,0xb7,0x76, + 0x52,0x87,0x03,0xe7,0x1a,0x5e,0x9c,0x3d,0xb0,0x2a,0x5f,0xdc,0x18,0xd6,0x86,0x18, + 0x09,0x07,0xc6,0x0c,0x6a,0x91,0xc0,0x6c,0x4a,0x7f,0x40,0x68,0x5a,0x7e,0x8e,0x08, + 0x38,0x1b,0x5f,0x4e,0x37,0x35,0x06,0xfc,0xc2,0xca,0x32,0xcd,0x17,0x3f,0x42,0x4d, + 0xa8,0x8c,0x52,0x5f,0x3b,0x93,0x6f,0x1a,0xd2,0xd1,0xef,0x0d,0xee,0xf5,0xb9,0xa2, + 0xad,0x95,0x4f,0xdf,0x99,0x51,0x05,0x89,0x83,0x6e,0xcf,0xbf,0x98,0x5f,0xdf,0xea, + 0xe4,0xcd,0x13,0x3b,0xe8,0xa3,0xcf,0x50,0xbf,0x82,0xfa,0xe6,0x74,0x44,0x84,0x8d, + 0x66,0x85,0x2c,0x92,0x17,0x33,0x80,0xcd,0x7a,0xe1,0x54,0xa5,0x52,0xeb,0x5a,0x0b, + 0x21,0x3d,0x9b,0xfd,0x6f,0xb9,0xf9,0xd0,0x18,0x53,0xfd,0xff,0x3d,0x78,0x50,0x69, + 0xe4,0x87,0x12,0x55,0x34,0x5e,0x66,0x2a,0xc3,0x89,0x79,0x0c,0x86,0x16,0x64,0x30, + 0xfd,0x7f,0xf1,0x96,0xb5,0x1b,0x72,0xe6,0x44,0xf4,0xaa,0x99,0xf5,0xe0,0x6e,0x9f, + 0x87,0x8b,0x50,0x66,0xb6,0x3a,0xe8,0xd2,0x59,0x95,0xa0,0xf2,0xe8,0x50,0x65,0xc7, + 0xaf,0x0b,0xf9,0xd2,0xa5,0xec,0xd6,0xba,0x8e,0x7c,0x37,0x0c,0x95,0x76,0x09,0xe4, + 0x3e,0xc5,0xd6,0x10,0x45,0xaf,0x20,0x8b,0x22,0xa9,0xec,0x48,0xbb,0xa5,0x43,0xca, + 0x00,0x73,0x8a,0x6c,0xe8,0x19,0x4c,0x71,0xb1,0x74,0x7f,0xaa,0x77,0x92,0x92,0xe5, + 0x80,0x34,0x07,0x50,0xe8,0xf5,0xd6,0xa8,0x41,0xc1,0x7a,0xf3,0x89,0x49,0xdc,0x2f, + 0xbf,0x3c,0x14,0x33,0x01,0x57,0x9f,0x50,0x06,0x5b,0x73,0xff,0x78,0x15,0xcc,0xeb, + 0x0d,0x94,0x91,0xf4,0x2e,0xa5,0xbf,0xc6,0x3a,0x8a,0xf0,0x3d,0x30,0x4b,0x28,0xaa, + 0x3d,0xbc,0xe1,0x31,0xdc,0x3e,0x10,0x63,0x4f,0x8c,0xfc,0xd0,0x5f,0xfc,0x9c,0x31, + 0x09,0x07,0xe8,0xa2,0x1f,0x56,0x21,0x58,0x78,0x3b,0x6c,0xfa,0x16,0x3a,0xa3,0xcb, + 0xdc,0x88,0x58,0xdd,0x9e,0xa4,0x4f,0x01,0xfd,0xda,0x76,0x54,0xe6,0x1b,0xa6,0x7c, + 0x89,0x05,0xa8,0x98,0x76,0xde,0x26,0x9d,0xc9,0xee,0xfd,0x4a,0x56,0x63,0x9d,0xd8, + 0x22,0x20,0x9b,0x64,0xc8,0xb3,0xf4,0xfb,0x39,0xd8,0xfa,0x36,0x8b,0x5d,0x66,0x70, + 0xb4,0x6c,0xba,0xf4,0x55,0xa5,0x7f,0xb0,0x9c,0x5c,0xbf,0xa5,0x36,0x8b,0x89,0xfd, + 0x65,0x8d,0x35,0xf8,0xdc,0xbf,0xb1,0x5e,0x13,0x93,0xff,0xe0,0x2a,0xf8,0x07,0x43, + 0xf9,0x8b,0xd3,0x91,0x54,0x30,0x43,0x8a,0x0e,0x02,0x87,0x58,0x8e,0xd3,0x3c,0x46, + 0x7a,0x5d,0xda,0xeb,0xe8,0x19,0x0d,0x84,0x8d,0xc5,0x8c,0xf7,0x1a,0x59,0xd7,0x62, + 0x2f,0x3a,0x2c,0xf7,0x46,0x40,0xbc,0xd2,0x08,0xd8,0x6c,0x07,0x22,0xf1,0x5f,0xfe, + 0x4d,0xbf,0x74,0x59,0xb7,0x86,0x2f,0xa4,0x8e,0xe7,0x63,0x55,0xaa,0x88,0x75,0x57, + 0x86,0x2f,0x78,0xe9,0x83,0xb3,0x00,0xc8,0xdf,0x22,0xa3,0xaa,0xf7,0xec,0x58,0xa7, + 0x1f,0x7d,0xd4,0x7d,0xb0,0xfa,0x48,0x97,0x87,0xdb,0x01,0x7a,0x7a,0xd1,0xbb,0x5a, + 0x65,0xdb,0x6e,0x1e,0x72,0xbf,0x59,0x7a,0x05,0x9b,0x91,0xad,0x72,0x83,0x9f,0x74, + 0x23,0x3c,0xed,0x6f,0x8f,0x90,0x04,0x93,0x1d,0xb4,0x8d,0xbe,0xaf,0xfe,0x20,0x5a, + 0xac,0xfb,0x59,0xf4,0xbb,0xb9,0x30,0x96,0x4c,0x74,0x81,0x72,0x72,0x5d,0xa6,0x1a, + 0x57,0x9a,0xe4,0xf5,0x02,0x29,0xe0,0x6e,0x07,0xc4,0x2a,0x1e,0x01,0xb3,0x72,0x9d, + 0x29,0x6d,0x49,0xe6,0x86,0x37,0xd2,0x89,0x53,0x5b,0xc4,0x16,0x3c,0xb2,0x11,0xdc, + 0xa8,0x14,0x76,0x4b,0xf3,0x60,0xd4,0xc7,0x32,0xaf,0xf6,0x1f,0x01,0xb1,0x16,0x1b, + 0xb7,0xdd,0xec,0x3f,0xa7,0x12,0x77,0x88,0xdb,0x59,0xa6,0xa3,0x58,0xbe,0xb8,0xff, + 0xf4,0x11,0xfe,0x03,0x34,0x8f,0x6e,0x27,0x64,0x93,0x93,0xa0,0x7e,0x86,0x9b,0xe3, + 0x85,0x8c,0xf6,0x13,0x35,0xaa,0xc8,0x17,0xe0,0xee,0xa0,0xc7,0x77,0x65,0x07,0x29, + 0xe3,0x0a,0x21,0x77,0xf2,0xa5,0x6f,0x26,0x61,0xed,0xa9,0xd6,0xfa,0x07,0x5b,0x12, + 0x6a,0x67,0x6b,0x24,0xfd,0x8c,0xcd,0xf6,0x0b,0xb2,0xcf,0xb1,0xff,0x85,0xa4,0x22, + 0xf5,0x61,0x57,0x37,0x30,0x87,0x28,0x64,0xa2,0xc5,0x7c,0x40,0xbb,0x85,0x48,0x2e, + 0x62,0x01,0xe8,0xd2,0x15,0xf6,0x20,0xc0,0xd9,0xb0,0xca,0xa6,0xb8,0x21,0x79,0xbe, + 0x0d,0x80,0x52,0xb6,0xe6,0x16,0x39,0x92,0x46,0xeb,0x8f,0x87,0xd6,0xe3,0x2b,0x53, + 0x82,0x65,0x19,0x37,0x60,0x42,0xf9,0x82,0xe5,0xb3,0xe7,0x97,0xb1,0x62,0x92,0xf8, + 0xd8,0xb9,0x22,0x7e,0x7a,0x4f,0x2c,0x14,0x29,0x4c,0xaa,0xd2,0xf4,0x65,0x78,0xeb, + 0x85,0x04,0x8e,0xf1,0x11,0x69,0x3a,0xb2,0x6d,0xe2,0x29,0x45,0xa5,0xb0,0x7d,0x0f, + 0x69,0x89,0xfd,0x0a,0xbc,0x91,0x6a,0x5a,0xee,0xc3,0x6e,0xa9,0xba,0x81,0xf4,0xe9, + 0x19,0xba,0x8c,0x0f,0x72,0x4f,0x63,0x29,0x29,0xb4,0x20,0x98,0x13,0x66,0x1b,0xa9, + 0xef,0xb3,0xfa,0xb7,0xeb,0x40,0x86,0x94,0x94,0xb7,0xac,0x6b,0x7e,0xb7,0xcb,0x27, + 0x63,0x8e,0x35,0x1b,0xf2,0xdc,0xc4,0x74,0xaa,0x72,0x49,0x83,0xae,0xce,0x83,0xf9, + 0x02,0x04,0x07,0xb3,0x63,0x4c,0x39,0x52,0xb2,0x0c,0xd3,0x1e,0xbc,0xcf,0x35,0xe9, + 0x7e,0xac,0x2c,0x2e,0xef,0xf9,0x65,0xad,0xab,0x90,0x8d,0x83,0x26,0xce,0x7a,0x87, + 0x81,0x51,0xfa,0x21,0xdb,0xb3,0x6a,0xa7,0x44,0xfd,0x33,0x00,0x76,0x13,0xac,0xe2, + 0x43,0x96,0xbe,0x87,0x92,0x92,0x0f,0x43,0xe5,0xdc,0x3c,0xd6,0xc6,0x14,0x5f,0x8a, + 0xd8,0xbd,0xba,0x96,0xf7,0x3d,0x83,0x90,0x41,0xd3,0x71,0xe7,0x7c,0x7e,0x73,0x96, + 0x00,0x52,0xf3,0x21,0xda,0x3c,0x4f,0x03,0x0a,0x37,0xa5,0x5a,0x9a,0x7c,0x44,0x44, + 0x76,0x45,0xbd,0xb7,0x10,0xbd,0xf4,0x93,0xc1,0xd7,0x86,0xe2,0xba,0x17,0x8c,0x60, + 0x41,0x6a,0x0c,0x68,0x15,0x38,0x27,0xd7,0xc2,0xea,0xe2,0xdc,0x75,0x77,0xe6,0x64, + 0x7e,0x95,0xe5,0x4f,0xb3,0xa4,0xb2,0x12,0x6e,0x5b,0x71,0x14,0x51,0x36,0xf6,0x61, + 0x47,0x48,0x36,0xf2,0x12,0x2c,0x03,0x13,0xe7,0x6a,0xed,0x97,0x04,0x12,0x5c,0x86, + 0x50,0xb7,0x06,0xf7,0x3e,0x5b,0x86,0xdb,0x04,0xf9,0x16,0xdf,0x0c,0xfd,0x70,0x9f, + 0x88,0x58,0x3a,0xfe,0xd2,0x3a,0xbe,0xca,0x0b,0xde,0xa0,0x5e,0x1b,0x5c,0xa7,0xfb, + 0xca,0x9d,0x73,0xef,0x53,0xcb,0x2f,0x99,0xfd,0xf5,0x85,0x7f,0x13,0x3e,0x71,0x9e, + 0x08,0x84,0x4f,0x2d,0xdb,0xc4,0x61,0xbe,0xcd,0x5d,0xe1,0xba,0x58,0xa4,0xe9,0xa7, + 0xf7,0xc3,0x46,0x92,0xb7,0x5e,0x64,0xd8,0xf9,0xf3,0xee,0xdd,0x5c,0xd3,0x1c,0xe2, + 0x05,0x5f,0x31,0x1b,0xd2,0x1e,0xb9,0x0b,0xe7,0x50,0xa0,0x5d,0x5f,0xdc,0x87,0x79, + 0x89,0xab,0x6c,0x48,0x29,0x01,0xf7,0x9a,0x49,0xdd,0x07,0x93,0x90,0x5d,0xd7,0xea, + 0x8f,0x53,0x28,0xae,0x99,0xe9,0xa6,0xde,0x4a,0x33,0xce,0x0e,0x7f,0xf2,0x5e,0x04, + 0xe5,0x03,0x98,0xf5,0x32,0xc5,0x83,0xc0,0x3f,0xe0,0xcf,0xdc,0x52,0x30,0xd7,0x60, + 0x2b,0x5e,0x05,0x69,0x88,0xfd,0x65,0x38,0x41,0x71,0x07,0x74,0xf4,0x34,0x53,0xf0, + 0x08,0xc3,0x99,0xf4,0xba,0xe3,0xec,0x22,0xf3,0x45,0x5c,0x59,0x55,0xef,0x17,0x3f, + 0x0a,0x75,0x12,0x59,0x74,0x9c,0x1b,0xcf,0x45,0x38,0x2e,0x08,0xf7,0x9f,0xb4,0xb1, + 0x28,0x24,0xa8,0x42,0x91,0x15,0x8f,0x09,0xcb,0x32,0xc8,0x99,0xa3,0x87,0xa8,0xf7, + 0xfc,0x8f,0x96,0xf7,0xe6,0x03,0xd8,0x61,0x61,0xa1,0x86,0x70,0x34,0x20,0xf2,0x62, + 0xfb,0xe8,0x4d,0x3c,0x5c,0x57,0x39,0x13,0x0e,0xa5,0x0a,0x97,0xe6,0x17,0x6a,0xd7, + 0xa9,0x4a,0x7a,0xa4,0xb5,0xbc,0x27,0x91,0xc3,0xfa,0x2a,0x84,0x5b,0xa6,0x99,0x7a, + 0x8c,0x97,0xdb,0x2a,0xf5,0x19,0xbc,0xd3,0xe1,0x8a,0x0d,0x61,0x5a,0x6b,0x70,0x15, + 0x75,0x26,0xb9,0xbb,0xea,0xe8,0x60,0x53,0x35,0x66,0xd2,0x5c,0xaa,0xab,0x79,0x09, + 0x1e,0xcb,0xb5,0x6d,0x63,0x07,0xac,0xf8,0x31,0x8b,0x6d,0xed,0x7d,0x15,0x8b,0x69, + 0xef,0x0c,0x84,0x60,0x44,0x26,0x9b,0x49,0xaf,0x4c,0xa7,0xb2,0x09,0xc8,0x39,0x69, + 0x71,0x02,0x39,0x38,0xe5,0x07,0xb2,0xea,0xee,0xc1,0xac,0x8c,0x5a,0x69,0x85,0x64, + 0x21,0x78,0x06,0x2d,0x35,0x5b,0x24,0x98,0x4b,0xf0,0xc4,0x9c,0x3d,0x1b,0xb8,0x6d, + 0x8a,0xe7,0x9b,0x4b,0x7e,0x51,0x88,0x4c,0x6f,0x31,0xe1,0xbd,0x35,0xaa,0x39,0x60, + 0xc8,0x14,0xd5,0xbd,0xfe,0xab,0x49,0x4b,0x0c,0x60,0x85,0x78,0xfb,0x4b,0x90,0xe0, + 0xdf,0xf5,0x1f,0x36,0xd0,0x6f,0x14,0xdb,0xc5,0x5a,0x00,0xc4,0x1c,0xb3,0xd3,0x7a, + 0x2e,0xd3,0x1c,0x12,0x18,0x4f,0x44,0x5a,0x71,0x90,0x47,0x4e,0x75,0x4a,0x1d,0x7d, + 0x08,0x9f,0x65,0x22,0x51,0x29,0xb2,0x21,0xc6,0xa0,0x4a,0xd4,0xde,0x21,0x6d,0x46, + 0x44,0x3c,0x97,0x64,0xc1,0x1e,0x2f,0xb2,0x1a,0x5e,0x3d,0x33,0xa1,0xa2,0x73,0x2a, + 0x59,0xd9,0xec,0xc2,0xb1,0x05,0x13,0x19,0xd3,0x42,0xa6,0xc4,0x9d,0x90,0x94,0xa1, + 0x5f,0xf9,0x13,0x3e,0x99,0xf8,0x28,0x89,0xb1,0x7a,0x01,0x1a,0x77,0x4e,0x1b,0xfa, + 0xc5,0x69,0xb5,0xfe,0xac,0x0b,0x5a,0xa4,0x38,0x79,0xcd,0xc3,0x1f,0x3c,0x0b,0x02, + 0xa6,0xb7,0x7a,0x28,0xa5,0xfa,0x2d,0x53,0x0a,0xa7,0x97,0xd3,0x0b,0xe6,0xb5,0x79, + 0x50,0x37,0x35,0xc9,0xf6,0x72,0xe2,0x54,0x48,0xde,0x1a,0xc1,0xa2,0x07,0x74,0x86, + 0x15,0x36,0x6e,0x3b,0xc6,0x62,0xba,0x45,0x49,0x76,0xd6,0xb9,0xde,0x9c,0x77,0x78, + 0x86,0xdb,0xaf,0x8b,0xb5,0x5b,0x17,0xf2,0x4d,0x50,0x0e,0x31,0x7f,0xbe,0x8f,0xe9, + 0xcf,0x1c,0xaf,0xec,0xdb,0xb1,0x9f,0xc9,0x8f,0x5c,0x00,0x5d,0xfb,0x98,0xf6,0xb8, + 0xc5,0x4d,0xb4,0xce,0xc9,0xd2,0xda,0x98,0xa4,0xff,0x2d,0xee,0x97,0x36,0x7c,0x24, + 0x94,0x39,0xaf,0xb8,0xe9,0xb5,0x2e,0x09,0x4d,0x70,0xa5,0xfe,0x7b,0x4d,0x19,0xf6, + 0x47,0x54,0xbe,0x7c,0x1b,0x48,0x09,0x4a,0x0f,0x78,0x0a,0x03,0xfe,0x41,0x78,0x39, + 0x4f,0x34,0xeb,0xfb,0x30,0xfe,0x2b,0xca,0x93,0x70,0x53,0x8c,0xdd,0x59,0x9b,0x73, + 0x79,0x89,0xbe,0xb5,0xda,0x03,0x80,0x5f,0x9a,0xcb,0x42,0x1b,0x3e,0xff,0x12,0x12, + 0x93,0x40,0xee,0xb4,0xfa,0xa2,0x38,0xba,0x65,0x4c,0x23,0x76,0xf0,0x9c,0x21,0xeb, + 0x69,0xf3,0xff,0xb4,0x79,0xa1,0x31,0xcb,0x35,0xcb,0xee,0xa1,0x84,0x1c,0xba,0xb0, + 0x7d,0x40,0xb7,0xb0,0xf1,0x3f,0xe0,0x16,0x60,0x3c,0xb1,0x57,0x25,0xe0,0xc8,0x2c, + 0x61,0x24,0x16,0xd3,0x30,0x29,0xa7,0x82,0xc0,0x0c,0xc8,0x71,0xd0,0x4c,0x70,0x00, + 0x07,0x0a,0xe2,0xd1,0x50,0xc5,0x20,0x12,0x02,0x65,0xa0,0x07,0x63,0xe2,0x39,0xc3, + 0x83,0x64,0x41,0x54,0xe2,0xdb,0x9d,0x03,0x83,0x06,0xae,0x07,0x93,0x26,0x71,0x01, + 0xc3,0x08,0x99,0x37,0x97,0x87,0x21,0xf3,0xc6,0x7e,0x26,0x70,0xac,0x98,0x59,0x08, + 0x0e,0xd8,0x7d,0x7e,0x72,0x6b,0xbe,0x0c,0x99,0xb5,0x25,0x9d,0x5e,0x4b,0xda,0x3c, + 0xa8,0x96,0x1d,0x62,0xd3,0xf8,0x43,0xf8,0xec,0xe6,0xf2,0x5e,0xae,0x2b,0x92,0x17, + 0xa2,0xfe,0x78,0x4a,0x65,0x8c,0x38,0x52,0xe9,0x9a,0x82,0xef,0x79,0x95,0xbf,0x7b, + 0x06,0x8d,0x83,0x99,0x70,0x88,0xc9,0x31,0x6c,0xe4,0x1c,0x49,0xfd,0x6d,0x22,0x08, + 0x0c,0x01,0xd5,0x9f,0x76,0x51,0x08,0x69,0xe9,0x4a,0x42,0x1f,0x62,0xcd,0x72,0x08, + 0x2b,0x02,0x80,0xa2,0xb8,0x2b,0x56,0xef,0x0b,0x42,0xc0,0xf8,0x26,0xeb,0x49,0x48, + 0x29,0x6b,0xa3,0x0c,0x21,0x23,0xdb,0x11,0x69,0x48,0xc2,0x92,0xfe,0x95,0x73,0x09, + 0x8a,0x00,0xc7,0xa6,0x3a,0xa5,0x3b,0x3d,0xf7,0xcd,0xbb,0x39,0x95,0x62,0x94,0xc7, + 0xc9,0x81,0x87,0xf7,0x5a,0xb1,0x29,0x70,0x3c,0xfb,0xf4,0xe5,0x89,0x7d,0x99,0x03, + 0x59,0xce,0xde,0x24,0xce,0x9e,0x64,0x10,0x8a,0x72,0x96,0xb0,0xd2,0x77,0x63,0xbd, + 0x5f,0xbf,0x7a,0x76,0x9e,0x9f,0x6d,0x81,0x00,0xf6,0xdf,0x5b,0x53,0x7f,0x9d,0xf3, + 0x4a,0x62,0x5d,0xd2,0x58,0x50,0x7d,0xb3,0xb8,0x5e,0x91,0x56,0x50,0xf9,0xb4,0xa2, + 0x61,0xe4,0xfa,0xfc,0xbf,0xb2,0x34,0xa1,0x95,0x59,0xea,0x99,0xd1,0x11,0x44,0x72, + 0xd2,0x1a,0xdd,0xd5,0xb3,0x55,0x50,0x0b,0xc2,0xdd,0xb9,0x09,0xf0,0xd8,0x4f,0xe1, + 0x01,0x10,0xc4,0x85,0xfa,0x9d,0x1f,0x1a,0x41,0x50,0xeb,0x05,0x51,0xad,0xf9,0xaa, + 0x00,0x11,0x93,0xfd,0x4c,0x9a,0xdd,0x13,0x88,0xb6,0x4e,0xc5,0xfb,0xc8,0xb2,0xea, + 0xc3,0x89,0xe0,0xb1,0xd1,0x7b,0xd2,0x2d,0x66,0xd2,0x6d,0x4e,0xd9,0xf2,0x76,0x9c, + 0xc9,0x98,0xa8,0xa0,0x1f,0x9d,0x25,0x89,0xc8,0xd8,0xe0,0xde,0x3a,0xa6,0x97,0xfa, + 0xc4,0xb1,0xe1,0xb1,0xbb,0xfa,0x13,0xd0,0xc9,0x78,0xe8,0x4f,0x7a,0x52,0xe5,0xbd, + 0x16,0xa6,0x18,0x38,0x34,0x96,0xd6,0x4a,0x6d,0xd6,0xe7,0xdf,0xba,0xc4,0x4e,0x5d, + 0xd7,0x13,0x53,0x8b,0xf8,0x2c,0xd7,0x6c,0x04,0xba,0xec,0x5d,0x02,0xe3,0x36,0x5a, + 0x2e,0x39,0xac,0xd4,0x3a,0x9d,0xcf,0x87,0xaa,0x3f,0x84,0xfd,0xa5,0xc2,0x27,0x8d, + 0xf5,0x93,0xcf,0x4d,0x53,0x8f,0x47,0x8b,0xee,0xfe,0x17,0x98,0xfb,0x12,0x77,0x89, + 0xa3,0x10,0x91,0xf4,0xb7,0x3b,0x15,0xec,0xcb,0x52,0xe5,0x63,0x08,0xd2,0x21,0x78, + 0x65,0x84,0xb2,0x4c,0xeb,0x2d,0xe6,0xa0,0xc4,0xba,0x38,0x31,0xb5,0xef,0x42,0x23, + 0x35,0x2e,0x96,0xb3,0xcb,0x0c,0x80,0xc1,0x23,0xd1,0xf2,0xcd,0xf6,0xe7,0x43,0x01, + 0xa0,0x09,0xf7,0xb7,0x63,0xcc,0x11,0x3b,0xf7,0x5a,0xd1,0x66,0x21,0xef,0x89,0x61, + 0xe7,0x75,0x79,0x89,0x94,0x63,0x81,0xc0,0xab,0xc5,0xb5,0xd1,0x74,0x69,0x00,0x02, + 0x00,0x89,0x1b,0xa4,0xff,0xf5,0x08,0x46,0xa7,0x6b,0x0f,0x34,0x15,0x14,0x62,0x42, + 0xa4,0x83,0x6d,0x25,0x67,0x23,0x6b,0x81,0x3f,0xc3,0x86,0x4f,0x47,0xa8,0x6b,0x47, + 0x25,0x8b,0x4d,0xd5,0x86,0xae,0xe0,0x90,0xfa,0x69,0x61,0x8f,0x17,0xab,0xe1,0x63, + 0xe4,0xa7,0xe8,0x17,0xdf,0x0c,0xf1,0x36,0x66,0x4d,0x87,0x4b,0x9f,0xec,0x5c,0x0d, + 0xad,0xc9,0xf8,0xdf,0x6c,0xb7,0x12,0xf2,0xed,0xf7,0xcd,0xcc,0xde,0xc0,0xd5,0x69, + 0x67,0xea,0x7e,0x8d,0x77,0x04,0x42,0x1a,0xad,0x6d,0xc2,0xbc,0x54,0x36,0x1d,0xbf, + 0xe4,0x87,0x99,0xe9,0x11,0x07,0x19,0xfb,0x90,0x61,0x49,0x4d,0x9f,0x55,0xd0,0x64, + 0xed,0x9a,0x7b,0x8c,0xff,0xa3,0x43,0x07,0x26,0x3a,0x83,0xef,0x26,0xe4,0x1a,0xc8, + 0x0f,0xe1,0xf3,0x4a,0x9e,0xde,0x89,0x88,0xcc,0xe4,0xcc,0x8e,0x7d,0xac,0x50,0xb8, + 0x8d,0x85,0xeb,0x1e,0x57,0x20,0x02,0xf8,0x46,0xf2,0xec,0x1c,0xa0,0x40,0x1b,0xc9, + 0x8f,0xeb,0xdd,0x63,0x13,0x28,0x8a,0x09,0x8d,0x71,0xf5,0x12,0x37,0x3f,0x9f,0xb9, + 0x0d,0x87,0x95,0x77,0x1f,0x5f,0x43,0x2b,0xcb,0xc0,0xec,0xfb,0xa9,0x4e,0xc1,0x72, + 0xa4,0x8f,0x70,0x15,0x48,0x1f,0x66,0x05,0x62,0xf3,0xcc,0x24,0x7d,0x4f,0xbc,0x63, + 0x86,0xd1,0x3f,0x65,0x13,0xdd,0xbb,0xc8,0x0d,0xdc,0x84,0x66,0x8e,0xfe,0x1e,0xf3, + 0x24,0x84,0x71,0xf4,0x92,0x14,0xf6,0x4b,0xdb,0xd6,0x8d,0x77,0x03,0xfd,0x1f,0xa3, + 0x22,0xd2,0x93,0x26,0x7f,0x42,0x2f,0x0b,0x0e,0x97,0xdd,0xf6,0x71,0xfe,0x04,0x86, + 0xa6,0x99,0x61,0xb4,0xdd,0x85,0xf4,0xf3,0x5a,0x7a,0x67,0xd7,0xd7,0x0b,0xe4,0x06, + 0x44,0xf5,0x13,0x27,0x0f,0x4a,0x01,0x90,0x24,0x6a,0xa6,0x30,0x0b,0x5a,0x6f,0xc1, + 0x05,0x90,0xc5,0xd3,0xdd,0xa7,0xe3,0x8c,0x64,0xfe,0xcb,0xde,0xd8,0x29,0x15,0x51, + 0xa2,0xcd,0xd3,0xff,0xd6,0xf7,0x05,0x91,0xa6,0xf7,0x5d,0x07,0x6d,0x24,0x78,0x33, + 0x2c,0x3c,0xd8,0x3f,0xd5,0x3b,0x0c,0x1a,0xc2,0x9a,0xbc,0xaa,0xdf,0xfe,0x95,0xd4, + 0x98,0xfa,0x1d,0x3a,0xc1,0xda,0x86,0x49,0x0f,0xc9,0xde,0xff,0xf9,0xf4,0xed,0x37, + 0x88,0xc6,0xc1,0xb3,0x57,0x39,0x63,0x37,0xdf,0xe1,0xbf,0x0a,0x1d,0xf5,0x49,0xf9, + 0x16,0x84,0x6f,0x3e,0x8d,0x6e,0x87,0x48,0x87,0xb7,0xf5,0x44,0x5e,0xfd,0x1e,0x48, + 0x2b,0x95,0xfe,0xde,0xd7,0xad,0x0e,0x68,0x67,0x63,0x88,0xe9,0x8f,0xf3,0x34,0x25, + 0x8c,0x9b,0x93,0xbc,0x7e,0xfd,0x46,0xaa,0x67,0xd2,0xde,0xae,0xde,0x75,0x3d,0x36, + 0x0d,0xfb,0xbf,0xda,0x3c,0x96,0x4f,0x3b,0x15,0xd1,0x43,0x94,0x5d,0xf8,0x3f,0xf4, + 0x0e,0x15,0x97,0xac,0x87,0x30,0x21,0xce,0xfb,0x9d,0xdf,0x1d,0xdb,0xff,0xa8,0x38, + 0x33,0x12,0x6c,0x84,0xec,0x00,0x12,0x46,0x3c,0x0f,0x37,0xbb,0xbb,0xd6,0xc8,0x76, + 0x20,0xeb,0x59,0x0b,0x2f,0x95,0x41,0x20,0xe4,0x2f,0x2a,0x2b,0xbd,0xce,0xb9,0xe1, + 0xa9,0x19,0x2d,0x47,0x13,0xf6,0x2b,0xc9,0xd2,0x0d,0xcf,0xbf,0xd4,0xb6,0x59,0x11, + 0xc2,0x02,0x29,0x0f,0x1d,0xae,0x7b,0x41,0xc0,0xd1,0xaf,0xc4,0x31,0x23,0xe7,0x6d, + 0xda,0x95,0x67,0x79,0xf3,0x8b,0x31,0x20,0x52,0xd0,0x43,0x63,0xf3,0xfb,0xdb,0xa3, + 0x7f,0xaa,0xae,0x85,0x12,0x65,0xbb,0x1b,0xe4,0x29,0x8c,0x0e,0x25,0xca,0x7b,0xb2, + 0xfa,0xa9,0x93,0x36,0xf0,0x4a,0x46,0x7a,0xb6,0x5d,0x65,0x07,0xae,0xc9,0x19,0xd5, + 0xda,0xce,0xd5,0xba,0x7a,0xed,0x66,0xe2,0xe1,0xea,0x89,0x9d,0xa4,0xaa,0x11,0xc9, + 0x8f,0x99,0xfc,0x9a,0xf3,0xce,0xaa,0x18,0x9a,0x07,0x3a,0xa6,0xcc,0xfc,0x0e,0xe4, + 0x81,0xf2,0xe8,0x02,0xcf,0xdd,0xe2,0xd0,0x49,0x04,0x1e,0xfa,0xcb,0x6a,0xc3,0x69, + 0x98,0x44,0xdd,0x9e,0x88,0x85,0x4a,0x27,0xab,0x6a,0x36,0x36,0xb3,0x1e,0x23,0xf5, + 0x6d,0x70,0x6c,0xee,0x43,0x80,0x19,0xdf,0xe9,0x9b,0x78,0xc6,0x11,0x9c,0x3c,0xec, + 0xff,0x8f,0xbd,0xb4,0x1a,0x57,0xc5,0x18,0xca,0x53,0x2d,0x97,0xd5,0xc1,0x62,0x65, + 0xe0,0x49,0x94,0xf1,0x1f,0xd8,0x12,0x70,0x9b,0xbc,0xa3,0x0d,0x79,0x7b,0xe5,0xba, + 0xa0,0x85,0x13,0xbc,0xac,0x2d,0x68,0x19,0x4a,0x58,0x87,0xf6,0xb9,0x6a,0x11,0x5a, + 0xfd,0xfa,0x5c,0x63,0xef,0x6d,0x7c,0xd9,0xf8,0xd9,0xd3,0x6d,0xe8,0xe5,0x1a,0xdc, + 0xb2,0x1a,0x66,0x97,0x0e,0xd6,0x44,0x39,0x6a,0xdd,0x14,0x55,0xa2,0x30,0xd3,0xa5, + 0x5a,0x20,0xee,0x90,0xcd,0x75,0x8c,0xd6,0x9a,0xaa,0xc2,0x87,0x75,0xda,0x91,0x21, + 0xca,0x60,0xbf,0x76,0x7a,0x99,0x4c,0xa1,0x47,0x49,0x36,0x93,0x2c,0x97,0xcd,0x3d, + 0xa1,0x08,0x3e,0x92,0x65,0xe5,0x19,0x35,0xc4,0xf2,0xaf,0xb1,0x74,0x65,0xab,0xd3, + 0x04,0x50,0xfa,0x64,0x53,0x30,0x2d,0x1b,0xb3,0x89,0x00,0x77,0x2f,0xd9,0x34,0xd4, + 0x96,0x57,0x9c,0x70,0xfb,0x16,0x5e,0x82,0xdc,0x51,0xe2,0x50,0x12,0x71,0x63,0x60, + 0x2e,0xbd,0xa4,0x85,0xf6,0x92,0x7e,0x9b,0xc0,0xbb,0x5e,0x95,0x72,0x69,0x0d,0xf3, + 0x02,0xc8,0x19,0x3d,0x98,0xfa,0x9d,0x36,0x1a,0xd1,0xbc,0xb5,0xef,0xd3,0xe7,0xee, + 0xd7,0x76,0x21,0x13,0x53,0x8e,0x2c,0x57,0xe8,0x79,0x37,0xb6,0xe4,0xcc,0x2e,0x72, + 0x40,0xf8,0x2d,0xaa,0xe5,0xdc,0xd9,0x3a,0xe9,0xf3,0xff,0x1c,0xaf,0xc6,0x39,0xa1, + 0x76,0x91,0x07,0x7c,0x6a,0x7a,0x4e,0x2d,0x4d,0x51,0xc9,0xa2,0xbe,0x34,0x6e,0xd9, + 0xe9,0x55,0xd1,0xae,0xbd,0x90,0x27,0x69,0xb5,0xf0,0xa1,0x00,0x91,0x8c,0xf2,0xaa, + 0xd5,0xb8,0x39,0x8b,0xd3,0x5f,0xa9,0x92,0x0b,0x58,0x06,0xb0,0xb2,0x1f,0xea,0x29, + 0x88,0x5d,0xd0,0x78,0xa9,0x37,0x83,0x07,0xeb,0x3d,0x8c,0x1a,0x92,0xfe,0x15,0xcf, + 0x62,0x7d,0x20,0x3d,0x3a,0x21,0x35,0xeb,0xeb,0xde,0x58,0x05,0x85,0xd3,0xf6,0x5d, + 0xa9,0x1a,0xd3,0xae,0xfc,0xbe,0xf2,0x82,0x76,0xf2,0x1f,0x58,0x59,0xd2,0x31,0x11, + 0x4b,0x88,0xc3,0x02,0xe8,0xe4,0xb7,0x50,0xbb,0x82,0x67,0x35,0xa2,0x33,0x00,0xea, + 0xc9,0xc3,0x0f,0x21,0x7e,0x04,0xd0,0xb7,0xc5,0x41,0xcb,0x8e,0x9d,0xb2,0x07,0xcb, + 0x8d,0x39,0x12,0x00,0x40,0x67,0xa9,0x52,0xc5,0xd2,0x97,0x9c,0xae,0x46,0xe6,0xeb, + 0xf2,0x46,0x29,0xe6,0x75,0xe3,0x03,0xdb,0x51,0x8c,0x5b,0x24,0xeb,0x05,0xc0,0xb1, + 0x28,0x70,0x2a,0x29,0x9b,0x09,0x4d,0x84,0x66,0xa7,0xd0,0xef,0xdb,0x69,0xd1,0x0d, + 0x01,0x7f,0xc8,0x96,0x33,0xc9,0x06,0x74,0xa6,0x46,0xf8,0x88,0xda,0x48,0x33,0x31, + 0x31,0x7a,0xb1,0x37,0x16,0x20,0x61,0x93,0x51,0xf7,0x16,0x98,0x37,0x60,0xbb,0x18, + 0x7a,0xbb,0xd3,0xc4,0xbd,0x08,0x8b,0x80,0x4b,0xca,0xad,0xe8,0x22,0x6e,0xfd,0x22, + 0x0a,0xdb,0x0a,0x84,0x88,0x3c,0x6b,0xd6,0xa9,0x37,0x88,0xdd,0x96,0x43,0xd5,0xdd, + 0xe4,0x71,0xee,0xd8,0x8f,0xaa,0x60,0x38,0xfe,0x60,0x09,0x39,0x89,0x3f,0xd8,0xe3, + 0xfb,0x47,0x06,0x14,0xf7,0xde,0xdf,0x58,0x91,0x3c,0xd1,0x2b,0x20,0xae,0xcc,0xeb, + 0x0d,0x94,0x48,0xe4,0x55,0xf8,0xb0,0xb1,0xce,0xab,0x1c,0xa0,0xb6,0x5d,0x5f,0x8d, + 0xcc,0xec,0xb6,0x3c,0xd4,0xaf,0x8d,0x96,0x4e,0x8e,0xd2,0x84,0xb7,0xef,0xaa,0x03, + 0x69,0x00,0xbe,0xcd,0x31,0x00,0x78,0x24,0xeb,0x20,0xfc,0x96,0x0a,0xa0,0x6b,0x46, + 0x6f,0xf1,0x9d,0xef,0x11,0x03,0x74,0x2c,0x33,0xd5,0xe9,0x6d,0x4c,0xe4,0x13,0x7c, + 0x2c,0xa7,0x3b,0x2f,0x1f,0xb0,0xbf,0x25,0xc1,0xd1,0xf9,0x99,0x50,0x42,0x63,0x80, + 0x6c,0xd2,0x96,0x82,0xb1,0xa6,0x4c,0xae,0x84,0x2f,0xca,0x1b,0x9d,0x23,0x75,0x16, + 0x80,0x9a,0xf2,0x99,0x7b,0xff,0xdb,0xc1,0xc6,0x58,0x82,0x0f,0x1f,0x46,0x7d,0xcf, + 0x24,0xc4,0x04,0x9d,0x28,0x06,0x6c,0xa3,0x41,0xbc,0xe3,0x19,0x1f,0x21,0xaf,0x7b, + 0xbb,0xde,0xcc,0x37,0x63,0x0c,0x1d,0x59,0x86,0xd7,0xc3,0x0e,0x1c,0x60,0x5c,0x38, + 0x8a,0x99,0x1b,0x39,0xd7,0x37,0x6f,0xce,0x60,0x6c,0x24,0x04,0xda,0x59,0x8f,0x89, + 0xda,0x29,0xd4,0x29,0xc2,0xd6,0xc5,0x82,0x33,0xdc,0xa2,0x14,0x73,0x70,0xc9,0x5c, + 0x59,0x0b,0x1a,0x39,0x4b,0x17,0xe6,0x8c,0x45,0x86,0x21,0x05,0x1f,0x3c,0x16,0x57, + 0xfe,0x54,0x16,0xa4,0xcb,0x46,0xfd,0xb2,0x8b,0xc2,0x4e,0x15,0x9f,0x06,0xd9,0x88, + 0x28,0x63,0x9c,0x7d,0xfa,0x17,0x57,0xea,0x24,0x23,0xe0,0x14,0x97,0x6b,0x89,0x78, + 0xcd,0x66,0xd0,0x0c,0xc1,0xfd,0x2e,0xa7,0x2d,0x54,0x89,0x07,0x8e,0xf7,0x36,0x63, + 0xbe,0xd7,0x41,0x7e,0x76,0xaa,0x33,0x2f,0xdd,0x73,0x00,0x12,0x08,0x29,0x76,0x9a, + 0x0a,0x80,0x1c,0x98,0x69,0x6d,0x66,0xbb,0x4a,0x9a,0xd7,0x39,0x01,0xba,0x5d,0x28, + 0x82,0x21,0x98,0xc8,0xd7,0x6d,0xe3,0xdc,0x16,0xcc,0x88,0xd3,0x8b,0x5f,0x50,0xe3, + 0x4e,0x99,0x15,0xf9,0x9e,0x42,0xcc,0xc7,0x7f,0x18,0xac,0x9f,0x37,0xbc,0x1f,0x0c, + 0x64,0x4f,0x34,0x3c,0x32,0xb3,0xc5,0xd7,0x5e,0x4f,0x64,0x1c,0x8a,0x5e,0x16,0xa1, + 0xce,0x9b,0xc9,0xe2,0x3b,0x1b,0x2f,0xdf,0x3b,0x0e,0x58,0xd2,0x7a,0x6e,0x59,0x9f, + 0xa5,0x0b,0xe3,0xc4,0x14,0xb4,0x06,0x18,0x46,0xf8,0xee,0x22,0xdd,0xdd,0xf7,0x98, + 0xa4,0xbe,0x9b,0x72,0xea,0x20,0x5e,0x0b,0x7d,0x03,0xe1,0x4c,0xc3,0x6b,0x52,0xe9, + 0x2c,0x4f,0x0f,0xc3,0x9a,0x39,0x36,0x43,0x3f,0x4b,0xf7,0x23,0xb3,0x66,0x96,0xf1, + 0xa7,0x05,0xb1,0x11,0x14,0x01,0x45,0x34,0xf2,0x35,0x5a,0xc5,0xed,0x52,0xcf,0xdf, + 0xfd,0xa9,0xf8,0x14,0x1a,0x2b,0x06,0x1d,0xa9,0xbd,0xe8,0xb4,0xed,0x6b,0x37,0x22, + 0xc1,0x05,0xc2,0x14,0xb0,0x23,0x60,0x20,0x63,0x4a,0xe0,0x24,0x57,0x6a,0xca,0xdf, + 0x75,0x47,0xa1,0xe5,0x2e,0x2b,0xc1,0xe3,0x42,0xce,0xe9,0x35,0xda,0x69,0x32,0x16, + 0x7e,0xb1,0x99,0x44,0x32,0xaf,0xc9,0x0e,0xcd,0x25,0x06,0x9b,0xd5,0x9e,0x22,0xcc, + 0xa9,0x82,0xdb,0x1b,0xfd,0x46,0xaa,0xd6,0xb5,0x26,0xeb,0x4a,0xa7,0xe3,0x38,0xe7, + 0xf0,0x4b,0xbe,0x22,0x39,0x0b,0x09,0x28,0xa2,0xf8,0xca,0xbd,0x11,0xe2,0x84,0xf8, + 0x2b,0x4a,0xe1,0x0c,0x9b,0x6a,0xf0,0xe9,0x84,0xe7,0x84,0xa9,0xdb,0x11,0x04,0x8a, + 0x28,0x94,0x0c,0x66,0x97,0x2d,0x3b,0x30,0x81,0xda,0xd3,0x10,0x59,0xab,0x79,0x38, + 0x8a,0x13,0xc3,0xae,0xb6,0xa7,0x18,0xd5,0xb5,0x20,0xb0,0xe8,0x71,0xba,0xda,0xa7, + 0xf0,0xa0,0x4f,0x3e,0x58,0x22,0xca,0xdd,0xbc,0xb0,0x8a,0x58,0xba,0x62,0xf8,0x39, + 0x0a,0x18,0x44,0xaf,0x18,0x2d,0x0a,0xd7,0x6f,0xb8,0x13,0x8c,0x42,0x68,0xc4,0xc2, + 0xe8,0x0b,0xb3,0xdf,0xb9,0x0d,0x49,0xab,0x34,0x92,0xbb,0x3d,0xca,0xef,0x17,0x68, + 0xfe,0x5d,0xe1,0x44,0x91,0xb8,0x1c,0xb0,0x81,0x42,0xce,0x89,0x4c,0x6f,0x8e,0xb0, + 0x51,0x71,0x31,0xd3,0xfb,0xd9,0x1a,0x58,0x99,0xfc,0x09,0x5e,0xd4,0x1d,0x5d,0x84, + 0x82,0x83,0x8d,0x67,0x8f,0x12,0xed,0x85,0x1d,0x59,0x2d,0x5a,0x93,0xe3,0xcd,0xe8, + 0x35,0xbe,0x85,0x91,0x19,0x8d,0x0a,0x57,0xd2,0xe6,0x7a,0x4b,0x55,0x9e,0x1d,0x6a, + 0xcb,0xcc,0xfc,0x14,0xff,0xbc,0xad,0x93,0x58,0x36,0x78,0x7a,0x71,0x64,0xb4,0xf4, + 0x54,0x23,0xb5,0x36,0xb1,0xd6,0x98,0x92,0x20,0xea,0xcc,0x74,0x86,0x7a,0xbd,0xc9, + 0x4b,0xee,0xc4,0x27,0x13,0xbc,0xa8,0xc5,0x60,0x5e,0x8f,0x82,0x8e,0x34,0x92,0x13, + 0x90,0xbb,0x19,0xb7,0xf0,0xc9,0x25,0x93,0xa0,0x28,0x62,0xc4,0x52,0xd6,0x93,0x3a, + 0xd7,0x08,0x3b,0xbd,0x99,0x07,0xae,0xd9,0x10,0x51,0x52,0x53,0x1b,0x72,0xbb,0x7e, + 0xa9,0x61,0x4d,0x6c,0x0d,0x08,0x1f,0x48,0x2d,0x16,0x21,0x5e,0x65,0x7d,0x3d,0x7a, + 0xd0,0x01,0x2b,0x1e,0xff,0x30,0x16,0xdb,0xfa,0x15,0x02,0x29,0xfb,0x0b,0x31,0xb4, + 0x4b,0xc4,0xf6,0xfb,0x46,0xb0,0x8f,0x51,0x19,0x16,0xf4,0x99,0x74,0xf6,0xfe,0xf8, + 0x2e,0xa3,0xbe,0x4e,0x3f,0x35,0x2e,0x6a,0x48,0x29,0xee,0x13,0x83,0xdd,0x35,0xfc, + 0xc2,0xd7,0xae,0x98,0x6c,0xbd,0x66,0x28,0xd4,0x52,0x05,0xec,0x18,0x69,0x06,0xaf, + 0xc8,0x1e,0xfd,0x2f,0x16,0x31,0x6f,0xb9,0xaa,0x51,0xef,0xdc,0x5b,0xc1,0x11,0x3b, + 0xaf,0x9a,0xb7,0xfa,0x1a,0xb7,0x3f,0x59,0xe9,0xd4,0xc8,0x79,0xdb,0xe5,0x94,0x60, + 0x89,0x76,0xc5,0xc6,0xb7,0xbb,0x0e,0x1a,0xc9,0x46,0xe9,0x2d,0xb1,0x91,0xd3,0x96, + 0x26,0x92,0x97,0xf4,0x95,0xc3,0x2f,0x52,0x0d,0xaf,0x2d,0x48,0xf6,0x91,0xde,0x79, + 0x4e,0x8d,0xb6,0x83,0x97,0xe3,0x33,0x63,0x0b,0x6f,0xa3,0xe7,0xd2,0xe8,0x70,0x34, + 0x20,0xc1,0xf0,0x2f,0x93,0xa9,0x5b,0x23,0xc4,0xf3,0x99,0xb9,0xe6,0x72,0x19,0x33, + 0x53,0x92,0xba,0xdf,0xb5,0xa2,0x22,0xfd,0xb1,0x85,0x88,0x14,0xa9,0xa6,0x00,0x6f, + 0xec,0xc1,0x13,0xb4,0xb6,0x2f,0x79,0x94,0x63,0xb9,0x78,0x97,0x5a,0xe3,0xf1,0xe6, + 0x71,0x0d,0x69,0x82,0x37,0x2c,0x4b,0x8b,0x78,0x89,0xad,0xd2,0x37,0x19,0x33,0xd8, + 0xf1,0x28,0x96,0xb5,0x15,0xef,0xc6,0x3c,0x52,0x1a,0x0f,0xb1,0x76,0x65,0x2d,0x4f, + 0xad,0x17,0x32,0x75,0xbf,0xb3,0x08,0xc2,0xbc,0x87,0x0a,0x69,0x52,0xee,0x11,0x84, + 0x0e,0x29,0xca,0x95,0x1e,0xa6,0xaa,0xd2,0xb5,0x84,0xbe,0x51,0xd0,0xf2,0x97,0x69, + 0x01,0x7c,0xb4,0x69,0x11,0xc8,0x32,0x58,0xb4,0x85,0xd6,0xef,0x7f,0x91,0xeb,0x62, + 0x19,0xc5,0xa1,0x1d,0x3e,0xad,0xc4,0xfc,0x0f,0x4b,0x9e,0xa9,0xde,0x59,0xc6,0x6e, + 0xe7,0x3d,0x28,0x3c,0xbd,0xaa,0xdb,0x4e,0xc3,0x61,0x8a,0x9e,0xf3,0x5d,0x14,0x5c, + 0xee,0x0e,0x62,0xab,0x7c,0xdc,0xe5,0xe8,0x4f,0x8c,0x01,0x8e,0xf2,0x1c,0x75,0x29, + 0xee,0x88,0x6b,0x83,0x3d,0xa8,0x2b,0xf9,0x86,0x63,0x33,0x4f,0xdc,0xe3,0x0e,0xa8, + 0x03,0xce,0x93,0xdd,0xbe,0x5e,0x45,0xd3,0x42,0xad,0x3b,0x5f,0xdd,0xe2,0xe2,0x73, + 0x5c,0x30,0xb7,0x02,0x37,0xcb,0x24,0xd5,0x68,0x9d,0x53,0x59,0x95,0x76,0xff,0x16, + 0x7c,0x24,0xe4,0xbb,0xb5,0x71,0x84,0x4d,0xea,0x57,0x10,0xd0,0xab,0x2c,0x7c,0x1c, + 0x01,0x99,0xb5,0x06,0xfc,0x39,0x37,0x45,0xd7,0x47,0xb5,0x59,0xc7,0x79,0x95,0xd4, + 0x67,0x11,0xf4,0x9c,0x50,0xc2,0xbd,0xf3,0xa5,0x2e,0xa7,0xb5,0x1e,0xfc,0xd7,0x20, + 0x02,0xda,0x64,0x24,0xb4,0xfc,0xf3,0x00,0xe4,0xd7,0xcc,0x1c,0x70,0xf5,0x35,0xdd, + 0xc0,0xd4,0x8c,0x92,0x0c,0xba,0x76,0xe7,0xc4,0xd3,0xf4,0xe6,0x48,0xd5,0x71,0x05, + 0xca,0x1b,0x3c,0x37,0xbe,0xb9,0xc4,0x81,0xa5,0xd9,0xb8,0x85,0x79,0x60,0xd6,0x35, + 0xb7,0x6a,0x8d,0x93,0xc8,0x3a,0x2d,0x62,0x84,0xf7,0xdd,0xf3,0xc8,0xf7,0x2e,0x3b, + 0xa9,0x1b,0xb4,0x4e,0x3a,0xb2,0x3c,0xa8,0xcb,0x99,0xf7,0xc8,0x1d,0xfc,0x70,0xa3, + 0x69,0x14,0xbc,0x9f,0xc6,0x34,0x40,0xef,0x5e,0x0b,0x62,0xd8,0x8a,0xe9,0x1d,0x6d, + 0x2c,0x6b,0x32,0xf1,0x1f,0x87,0x6e,0xa0,0x09,0x65,0xd1,0x4d,0xd8,0xe1,0x51,0xa3, + 0xce,0xc9,0x7b,0x65,0x54,0x71,0x87,0x41,0x14,0xb7,0x07,0x40,0x70,0x56,0x9e,0x22, + 0x88,0x41,0x9e,0x4c,0x3b,0x67,0x0e,0x68,0x4c,0xbe,0x4d,0x3e,0x76,0x85,0xfe,0xa8, + 0x47,0x96,0xce,0xbc,0x7c,0x43,0x2e,0xe2,0x0c,0xbd,0xb3,0x84,0xdc,0x0d,0x9f,0xc3, + 0x53,0xd1,0xe5,0x2d,0x3c,0xf6,0x2d,0xfe,0x4d,0xd8,0xef,0xfe,0xf8,0xff,0x11,0x3b, + 0xcc,0xbf,0x97,0x5d,0xd1,0xdc,0x07,0x79,0xea,0x25,0xf8,0x21,0x60,0xbe,0x3a,0xe8, + 0x52,0x4f,0xf3,0x42,0x16,0x1b,0xc9,0x96,0x7b,0xf2,0xe8,0xa6,0x51,0xe7,0xfe,0x7c, + 0xa0,0x6d,0x29,0x82,0x12,0x61,0x1f,0x89,0xa0,0xee,0x34,0xab,0xae,0xfc,0x51,0x18, + 0xd0,0x04,0xa0,0x72,0x1d,0x39,0xd1,0xa1,0x30,0x41,0xa9,0xdf,0x7c,0x6f,0x6b,0x80, + 0x80,0x63,0x9d,0xb7,0xb3,0x13,0x8e,0xd9,0x83,0x0e,0x7a,0xcb,0x2c,0x78,0x11,0x33, + 0x2c,0x85,0xb8,0x02,0x72,0x66,0xfc,0x13,0x28,0xe2,0xae,0xc5,0xb9,0x27,0x98,0xaa, + 0x68,0x0d,0xd8,0x61,0x1c,0x26,0x8a,0xb0,0x07,0xce,0x82,0x26,0x6b,0x27,0xc1,0xba, + 0x63,0xa5,0x12,0xe3,0x93,0x6c,0x87,0x12,0xa0,0xe0,0xaf,0xc0,0x33,0x59,0x49,0x42, + 0xf7,0x2f,0x5b,0x71,0xa0,0xf3,0xa6,0x82,0xa1,0xe8,0xc9,0x3c,0x72,0x6e,0x58,0x09, + 0xaf,0x0b,0xc6,0x88,0x18,0xea,0xed,0x5b,0x34,0x24,0x12,0x72,0xd5,0x0a,0x18,0xe3, + 0xf6,0x65,0xda,0x15,0xba,0x32,0x52,0x9d,0xb6,0x25,0x65,0xbe,0x58,0xee,0x45,0xd5, + 0x61,0xa3,0xda,0x9c,0x3d,0x2c,0xf4,0xe9,0xd5,0x08,0x38,0xa8,0x4b,0x55,0xcf,0x28, + 0x28,0xaa,0x49,0x7b,0x1b,0x28,0x79,0xa8,0xca,0x8b,0x20,0xdf,0x75,0x96,0xf7,0xe9, + 0xbe,0x0f,0x78,0xbd,0xb9,0x4c,0x04,0x56,0x28,0xb9,0x85,0xe8,0x7a,0xdb,0x8a,0x85, + 0x78,0xa0,0x26,0x33,0xc5,0xa6,0xf2,0x5d,0xce,0x7c,0x22,0x55,0x5d,0x6c,0xf4,0xec, + 0x7e,0x4d,0xf1,0x0a,0x94,0xd1,0x05,0x4d,0x4f,0x6f,0xeb,0x8d,0xb4,0xe5,0xd8,0xdd, + 0xfd,0x95,0xeb,0xb7,0xae,0x39,0xb3,0x49,0x49,0x4b,0x9b,0x1f,0xf8,0xbe,0x97,0x50, + 0x28,0xef,0x48,0xe6,0x71,0x10,0xb0,0xdf,0xc3,0xf0,0xaa,0x70,0x32,0xdf,0x47,0xa1, + 0x5d,0x53,0xb4,0xc4,0x33,0x3e,0x62,0x8d,0x52,0xd3,0xe2,0x89,0x98,0xbb,0xba,0x91, + 0x1f,0x99,0xfd,0x07,0xb9,0x56,0x82,0xa3,0x25,0xdf,0x06,0xd6,0xbb,0xf0,0x45,0x74, + 0x1c,0x1c,0xed,0xd5,0xbf,0x3e,0xa5,0x4e,0x08,0xa2,0xc3,0x57,0xf5,0xf6,0x3c,0x68, + 0xc9,0x27,0x83,0x40,0x44,0x80,0xd0,0x64,0x37,0x5e,0x6b,0x77,0x5c,0xa9,0x8c,0x6c, + 0xd1,0xee,0x77,0x14,0x3d,0x59,0x58,0x83,0x1e,0xd3,0x7f,0x50,0xaf,0x16,0x1e,0xfa, + 0xd9,0xce,0x9f,0xc7,0xb4,0x85,0xb9,0x92,0xc1,0xd0,0xb3,0x41,0xf1,0xb6,0x27,0x2d, + 0x7d,0x55,0xf3,0xa8,0x71,0x17,0x5d,0x31,0xe7,0x7e,0xf8,0xc8,0xeb,0x40,0x38,0xb5, + 0x40,0xb1,0x8c,0x88,0x9b,0x35,0xba,0x37,0x6b,0x88,0x03,0x57,0x91,0x77,0xd2,0xf7, + 0x8a,0xec,0x84,0xbc,0x9a,0x34,0x56,0x7d,0x82,0x3d,0xb8,0x68,0xda,0xfc,0x15,0x51, + 0xae,0x10,0x8d,0x9d,0x1b,0x37,0xd7,0x69,0xc6,0x18,0x46,0x57,0x11,0x8b,0x9c,0xa7, + 0xd1,0xae,0x85,0xdd,0x1a,0x3d,0xa0,0x5b,0xa1,0xaa,0xb9,0x5f,0xf8,0xd4,0x13,0xc8, + 0xfe,0x9f,0xce,0xd4,0x3c,0xef,0x9d,0x2e,0x42,0x47,0x51,0x5a,0x93,0x5f,0x9c,0xcb, + 0x41,0xfe,0xee,0xcc,0x08,0x49,0x07,0xbb,0xce,0x02,0x8e,0x0e,0x5a,0xb4,0xe0,0x78, + 0x62,0x9d,0x5b,0x49,0xcc,0x9a,0xf4,0x9f,0x15,0xe1,0xad,0x0d,0xf6,0xd3,0x8f,0x65, + 0x59,0xbe,0x15,0xdc,0x36,0x92,0x5e,0x9f,0x54,0xe9,0x33,0x8e,0xd1,0xf9,0x18,0x32, + 0x9e,0x2f,0x27,0xe4,0x93,0xa0,0x8f,0xa6,0x47,0xaa,0xc8,0xa4,0x55,0x07,0x56,0x15, + 0x03,0x83,0xec,0xf0,0x97,0xe9,0xec,0xcd,0xc8,0x47,0xc7,0xc9,0x53,0xa8,0x81,0x71, + 0xe6,0xd3,0x09,0x03,0x75,0xb9,0x11,0xaa,0xc2,0xc8,0xeb,0x26,0x77,0x6f,0xa7,0x0c, + 0xf1,0x57,0x63,0xe7,0x99,0xac,0xac,0xf3,0x87,0x3e,0xaf,0x71,0x93,0xa2,0x76,0xe3, + 0xed,0xa7,0xe8,0x42,0x96,0x67,0x7a,0x00,0x05,0x33,0xdf,0x0d,0x8f,0x11,0x38,0xd6, + 0x71,0xdf,0x8a,0x52,0x14,0xe6,0x64,0x0a,0x41,0x9f,0x54,0x09,0x9d,0xc6,0xda,0xf2, + 0xa4,0x29,0xb8,0x48,0x73,0xca,0x09,0x43,0x92,0x86,0xe2,0xe3,0x9d,0xd5,0x7f,0xf6, + 0x6c,0xe4,0x33,0x53,0x17,0x76,0x99,0xf7,0x8e,0xe7,0x42,0xe4,0xf5,0xed,0x35,0x11, + 0x7c,0x1c,0xc2,0x4a,0x0b,0xa7,0x28,0x2f,0xb3,0x1d,0x8c,0x5e,0x7f,0x88,0x14,0x27, + 0x80,0x2f,0x75,0xfc,0xb1,0x22,0xee,0x06,0xa6,0x8d,0x27,0x0d,0xd8,0xa9,0xb6,0x79, + 0x67,0x7b,0xc3,0x4b,0xbd,0x21,0x67,0x3a,0xe6,0x41,0x73,0x47,0x11,0xa8,0x35,0xdb, + 0xe7,0x26,0x54,0xfd,0x1f,0xe3,0x01,0x8b,0x2b,0x64,0x2b,0xbb,0xab,0x9e,0xd9,0xfb, + 0x28,0x23,0xbb,0x50,0xfb,0x53,0x2b,0x71,0xab,0xa0,0x70,0x70,0x7c,0x18,0x40,0x29, + 0x7b,0x29,0x57,0xc5,0x7c,0xa9,0x2a,0x4b,0x57,0xcc,0xc7,0x25,0xa3,0x5c,0xb3,0xda, + 0xf6,0x8a,0x4f,0xca,0x65,0xc2,0x11,0x6e,0xcd,0x5e,0xa7,0x64,0xaa,0x52,0xfc,0xb9, + 0x6f,0x2b,0x92,0x33,0x0d,0xa5,0xed,0x6f,0xef,0x0f,0x3b,0xae,0xe5,0x83,0x37,0xb8, + 0x18,0x8b,0x2c,0x85,0x95,0x38,0x14,0xc8,0x40,0xd1,0xb8,0xf9,0xc9,0x0c,0x8b,0xae, + 0xf1,0x20,0x8c,0xf4,0x74,0xb5,0x65,0x87,0xc0,0xd8,0xd6,0x5a,0xab,0xb3,0x21,0x07, + 0xa6,0xa2,0xa1,0x65,0x36,0xfa,0xb5,0xa7,0xcc,0x45,0x1e,0xc9,0x21,0x89,0x0a,0xab, + 0x75,0xe2,0xd5,0x7f,0xb3,0xfe,0xbd,0x92,0x17,0xd0,0x72,0x4f,0x9e,0xf0,0x5c,0x3d, + 0x93,0xd6,0x7b,0x54,0x3e,0xbc,0x2e,0xe0,0xd5,0x89,0xe4,0x95,0x54,0x72,0x33,0x8e, + 0xaa,0x38,0xf4,0xd2,0xb0,0xd4,0xbd,0x8d,0xea,0xb7,0x28,0x64,0x57,0x58,0xb6,0x48, + 0xd5,0x23,0xe3,0x2f,0x2a,0x7b,0x6f,0xe1,0x74,0xdc,0xf1,0x27,0xe9,0x5b,0x38,0x5c, + 0x18,0x3a,0x7d,0xc8,0x8b,0xf5,0x82,0x34,0x5a,0x21,0x2d,0x65,0xff,0xfd,0x20,0xb7, + 0xac,0x14,0xbc,0x8f,0x1f,0x8b,0xf6,0x2b,0xee,0x24,0x51,0x5f,0x56,0x76,0x7a,0x64, + 0x52,0x08,0x55,0xb9,0x9c,0x46,0xba,0x7d,0xed,0xf9,0x6a,0x6c,0xb5,0x08,0x1d,0x78, + 0x8e,0x35,0xc7,0xcf,0x3d,0xb7,0x4f,0xc9,0x0e,0xba,0xe9,0x0b,0x22,0x51,0x70,0x64, + 0x92,0xbb,0xcf,0xdf,0x53,0x36,0x93,0xfb,0xe9,0xfa,0xa8,0xcc,0x85,0xf2,0x37,0x44, + 0x99,0xde,0x2d,0xe5,0xbc,0x4a,0xcf,0x9a,0xee,0xca,0xba,0x1f,0xdd,0xbc,0x38,0x29, + 0x45,0x40,0x5a,0xbc,0xd4,0x0c,0x5e,0xef,0xed,0xd9,0xfa,0x7a,0x5f,0x5c,0x32,0xcb, + 0x53,0x3f,0x8d,0xad,0x55,0x2f,0x7f,0xfb,0x69,0xef,0xc9,0xd6,0x7c,0xfb,0x39,0x6b, + 0x44,0x1c,0xb5,0x20,0x54,0xbc,0x75,0x99,0xae,0xd7,0xe9,0x5e,0x00,0x52,0x50,0xbc, + 0xf7,0xab,0x10,0x76,0xfb,0x91,0xe8,0x23,0xf3,0x02,0xae,0x84,0xf7,0xcd,0xc8,0x30, + 0x7b,0x0c,0x70,0x1c,0xb6,0xfa,0x70,0xc3,0xcd,0x4c,0x0b,0x46,0x3b,0xd0,0x79,0x05, + 0x69,0x93,0xff,0x39,0xa3,0x0e,0x9b,0x3e,0xc6,0x8a,0x82,0x14,0xa4,0xcd,0x72,0x36, + 0x20,0xa2,0xec,0xe8,0x13,0x58,0x67,0x19,0x6d,0x4e,0xe7,0x0c,0x99,0x12,0x1a,0xf2, + 0x7a,0xab,0xf8,0xbe,0xbe,0x29,0x22,0x44,0xfb,0xef,0x6f,0x34,0x73,0x2b,0x36,0x57, + 0xa2,0x5a,0x73,0xb6,0xbf,0xd8,0x4f,0x83,0xc7,0xc8,0xb8,0xc2,0xc4,0x27,0xe1,0x33, + 0xe0,0x61,0xbe,0x61,0x79,0x42,0x29,0x75,0x22,0xc7,0xb1,0x67,0x44,0x6b,0x72,0x61, + 0x8f,0xf8,0xb1,0x71,0x78,0x43,0x0b,0xc2,0xe7,0x7a,0xd6,0xbc,0x51,0x63,0xd6,0xf3, + 0xe1,0x4b,0x8a,0xe2,0xe3,0x6a,0x6c,0x01,0x90,0x0c,0xb2,0x1f,0x2f,0x5e,0xed,0x62, + 0xdf,0x01,0xd5,0xde,0x2a,0xa5,0xae,0x5a,0xaa,0x42,0xc1,0x3c,0x5f,0x80,0x50,0xf3, + 0x07,0xb7,0x9e,0xc1,0xeb,0x1c,0x30,0x2e,0x69,0x15,0x4c,0xaf,0x20,0xc0,0x0c,0x0a, + 0xf1,0x18,0x33,0xee,0x98,0x3b,0x9b,0x57,0x2a,0x40,0x93,0x22,0xbb,0xbf,0x7f,0x8f, + 0xd4,0x04,0x6e,0x3f,0x9e,0x9a,0x44,0x0a,0x2a,0xdf,0x37,0x0e,0xd8,0xab,0xb1,0x22, + 0x84,0xdb,0xb4,0x5b,0xba,0x82,0xae,0x8b,0xc7,0x40,0xe0,0x83,0xa6,0xf6,0x46,0x27, + 0xea,0x6e,0xfd,0x4a,0x48,0x6f,0x2d,0x6f,0x2b,0xcd,0xb8,0xe9,0x83,0x54,0x03,0x45, + 0x32,0x8e,0x5e,0x7a,0x3a,0x80,0xa0,0x5e,0x6a,0xb0,0xdb,0x90,0xd3,0xee,0x00,0x62, + 0x04,0x9d,0x92,0xe6,0xcf,0x9d,0x4e,0x71,0x58,0x4f,0x29,0x44,0x5c,0xdb,0x3b,0x96, + 0xd2,0x53,0xb2,0xac,0x8e,0x6a,0x09,0x5a,0x98,0x1e,0x8c,0x90,0x42,0x91,0x78,0x05, + 0xe5,0xb9,0x92,0x01,0xc6,0x04,0xad,0x5a,0x83,0x26,0xed,0xa1,0x0d,0x30,0x87,0x97, + 0x5d,0x57,0x8d,0x6c,0x41,0xa8,0x47,0x2d,0xd9,0x11,0x36,0xf2,0xff,0xaf,0xe8,0x45, + 0xb1,0x8b,0x14,0xb6,0x01,0x31,0xf0,0xc4,0x28,0xb5,0xc4,0x41,0x32,0xf9,0x5c,0xa6, + 0x67,0xe9,0xac,0xd6,0x66,0x38,0x02,0x12,0x67,0xf8,0x92,0x87,0x38,0xd1,0xba,0x61, + 0xd2,0xe6,0x3d,0x41,0x91,0xb4,0x72,0xe7,0x32,0x32,0x8c,0x6a,0x55,0xd4,0x47,0x91, + 0x7e,0x13,0x09,0x53,0xd9,0x36,0xcb,0xf5,0xe1,0x52,0x17,0x17,0x13,0xf6,0x78,0xa4, + 0xf4,0x69,0xb3,0x08,0x02,0x38,0x9c,0x76,0x89,0x57,0x52,0x66,0xc3,0x47,0xb6,0x78, + 0x19,0xad,0xdc,0xe2,0x9a,0x5c,0xa5,0x5a,0xc5,0xa4,0x8e,0xba,0xd8,0xe6,0x5d,0x58, + 0x90,0x05,0xb9,0xa0,0xbe,0xe9,0x2a,0x2d,0xad,0x6f,0xcd,0x45,0x80,0x38,0xaf,0x83, + 0x25,0x16,0x30,0x7f,0x50,0xaa,0x67,0xd2,0xef,0x93,0xc5,0x8e,0x81,0xd4,0xc7,0x97, + 0x6b,0x9c,0x90,0xc8,0x93,0x82,0x6b,0xd9,0xcb,0xdd,0xc7,0x1f,0xfe,0xf7,0x04,0x67, + 0xf6,0xc1,0x97,0x47,0x9c,0x58,0x0c,0x5f,0x4f,0xd6,0x7e,0x0f,0x46,0x89,0xe8,0xcb, + 0xea,0xe2,0xa7,0xcf,0x28,0x33,0x9e,0x1a,0x6e,0xd3,0xe2,0x5c,0x59,0x8b,0xf2,0x87, + 0x56,0x03,0xf7,0x35,0x2d,0x70,0x9c,0xd5,0x00,0x1b,0xc4,0xd9,0x06,0xa7,0x95,0x3e, + 0xfc,0xa3,0x18,0xf5,0x1d,0xdb,0x3d,0xd3,0x28,0xa0,0x64,0x3d,0x72,0x74,0x08,0x1f, + 0xcd,0x10,0xc2,0xea,0xcb,0xe3,0x40,0x15,0xb8,0xce,0xf1,0xb2,0x23,0x94,0x12,0xa3, + 0x78,0x13,0xcb,0xeb,0x4a,0x59,0xf1,0x77,0x41,0x1f,0xe5,0x19,0x9b,0x17,0x78,0x3c, + 0xf9,0x36,0x66,0xef,0x7c,0x69,0x1f,0x1e,0x41,0x67,0x83,0xdc,0x66,0x16,0xe4,0xbc, + 0xf7,0xea,0xf3,0x62,0xb7,0x3b,0xe0,0x71,0x3a,0x80,0x14,0x8d,0xa7,0x67,0x84,0xcd, + 0x06,0x05,0xd3,0xea,0xe0,0xe4,0xc1,0x43,0xe6,0x44,0x49,0x8d,0x14,0x05,0x82,0x03, + 0x9e,0xdb,0x55,0x25,0xea,0x59,0x57,0x5f,0x4a,0x87,0xd1,0x89,0xd0,0x56,0x81,0x6b, + 0x07,0xc7,0x32,0x57,0xe8,0x37,0x6e,0x80,0x43,0x4a,0xe1,0x63,0x2e,0x68,0xf6,0x30, + 0x2a,0x7d,0xb0,0xf0,0xf7,0x39,0xa3,0x2d,0x4a,0x00,0xe0,0x10,0x72,0xaa,0x70,0xfc, + 0x65,0xf8,0x3f,0x59,0xd7,0x03,0x8e,0x49,0x75,0xc6,0x01,0xd8,0x4d,0x14,0x34,0x8f, + 0xc3,0xc0,0x99,0xfc,0xa0,0x07,0x1a,0x58,0xfc,0xc5,0x34,0x5b,0xef,0x5d,0xeb,0x3b, + 0x8f,0x00,0xe3,0xcf,0x74,0x7a,0x05,0x0e,0xee,0x46,0x43,0x1b,0x01,0x5a,0xca,0x72, + 0x6d,0xe0,0xbd,0x4e,0x21,0x73,0x20,0xdd,0xa5,0xa8,0xea,0x6a,0xd9,0x8f,0x52,0xa5, + 0x9e,0xf0,0x2a,0xde,0xef,0xe1,0x68,0x37,0xa4,0x89,0xf5,0x65,0xa6,0xe2,0x74,0xcf, + 0xae,0x65,0x3a,0xf1,0xa5,0x2b,0xe3,0x05,0xa6,0xc3,0xa9,0xe3,0xa2,0xac,0x42,0x53, + 0x0f,0xcf,0xb9,0x19,0xb1,0xe3,0x41,0xcb,0x21,0x60,0x7c,0xc0,0x9f,0xb1,0xdf,0xa5, + 0x85,0x1f,0xdb,0x7e,0x34,0xcb,0xc6,0xd1,0x54,0xdf,0x14,0xd4,0x16,0x97,0x74,0x96, + 0xad,0x8e,0x73,0xac,0x42,0x84,0x1c,0xae,0x63,0xe9,0x7c,0x97,0x5a,0xb3,0x7d,0x87, + 0x51,0x1d,0x32,0x76,0xc6,0x11,0x81,0xd0,0xdc,0xdd,0x95,0x83,0x1d,0x43,0x73,0xa6, + 0xa9,0xd1,0x6d,0xf2,0x1d,0xdf,0x76,0x88,0xd9,0x46,0xad,0x86,0xc6,0x13,0xdf,0x88, + 0x36,0x90,0x84,0xc4,0xf8,0xb9,0x4e,0x52,0x88,0x7b,0xac,0xf7,0x2a,0x03,0x17,0x2d, + 0x44,0xf9,0xd4,0x84,0x74,0x45,0xdd,0xf5,0xcb,0xb0,0xf7,0x16,0x3f,0x45,0xe5,0x84, + 0x88,0x88,0xaf,0xda,0xa6,0xf9,0xd1,0xc7,0x7a,0x92,0xf5,0xe6,0xa2,0x4b,0x7a,0x57, + 0x87,0x7c,0xb3,0x35,0xa3,0x32,0x45,0x0d,0x4b,0xda,0x8a,0xf7,0xff,0x67,0xac,0xcc, + 0x4f,0x67,0xff,0xc8,0x99,0x1e,0xa7,0x95,0x54,0x0d,0x1d,0xe9,0x72,0x24,0xb8,0x7a, + 0xce,0x12,0xf9,0xe4,0x3e,0x59,0x3b,0xd1,0x0c,0x29,0xe4,0xa9,0x05,0xbb,0x5f,0xac, + 0x0f,0x37,0xf7,0xfc,0xc0,0xf8,0x26,0x2f,0xf5,0x40,0x73,0x65,0x47,0xc5,0x8a,0xb2, + 0x1e,0x16,0x91,0xa2,0x1a,0xab,0x27,0xbf,0x65,0x73,0xaf,0xa4,0x5c,0x64,0xd9,0x28, + 0x8a,0x0d,0xbf,0x51,0x99,0xba,0xe6,0x1a,0x25,0x8d,0x36,0xf7,0xb5,0x92,0xec,0xe8, + 0x4f,0xf3,0xda,0x38,0x9a,0x42,0x30,0xd6,0xdc,0x90,0x9c,0xfe,0x7e,0x9d,0xf7,0xa0, + 0xc5,0x91,0xc7,0x55,0x1f,0xa5,0x0e,0x94,0x49,0x55,0x48,0x7d,0x01,0x23,0x11,0xdd, + 0x4e,0x1c,0xa5,0x3d,0x9c,0x3f,0x80,0xdf,0x43,0xba,0x20,0x00,0xdb,0xbe,0xa7,0x38, + 0xd8,0xb1,0xbf,0x5b,0xc5,0xbd,0x68,0xa4,0x4b,0x23,0xd8,0xbd,0x56,0xa8,0x44,0x9d, + 0xa0,0xae,0x46,0x90,0x3c,0xa0,0x31,0x46,0xb6,0xbc,0xa0,0xcb,0xdc,0xc7,0x5b,0x1d, + 0xfc,0x40,0x2a,0x2a,0x83,0x77,0x29,0xde,0x51,0x3f,0xa5,0x47,0x27,0x07,0x5d,0xe0, + 0xfd,0xf3,0x99,0x08,0x9d,0x61,0xb5,0xaf,0xc2,0xe3,0x8e,0x4b,0x1b,0xf2,0xca,0x63, + 0xf7,0x0b,0x68,0x49,0x97,0x24,0x28,0x1d,0x61,0x55,0xc0,0x91,0xb3,0x6b,0xef,0x78, + 0x60,0x4a,0x37,0xb6,0x91,0xa2,0x66,0x58,0x45,0x44,0x92,0x96,0x72,0x8f,0xf5,0x3e, + 0x21,0x47,0xa1,0xf7,0xa3,0xad,0x91,0x41,0x94,0xb9,0xcd,0x02,0x3b,0x77,0xde,0xd5, + 0xa3,0x05,0xd0,0x37,0x71,0xd8,0x3f,0xf5,0xe3,0x6d,0x6e,0x40,0xd5,0xbd,0x62,0xbe, + 0xcc,0x05,0x99,0x4c,0x6f,0x1d,0xb8,0x57,0x8d,0x1c,0xda,0x31,0x5e,0xa0,0x88,0x9a, + 0xe3,0x7d,0x3b,0xc9,0xf8,0x96,0x1e,0x11,0x4f,0x63,0x36,0x43,0x83,0xb4,0x41,0x78, + 0xf8,0x01,0x5c,0x25,0x24,0x30,0x43,0x38,0xbc,0x1a,0xa7,0xa9,0x9d,0xb5,0x33,0xea, + 0xf5,0x67,0x4b,0x74,0x8e,0x69,0xc8,0x5b,0x36,0x57,0xf8,0xfd,0xdd,0x6f,0x7a,0xbb, + 0x32,0x4e,0x43,0xc8,0x7c,0x69,0x92,0x48,0x22,0xb3,0xe7,0x23,0xa7,0x10,0xe7,0x2a, + 0xbc,0x50,0xb2,0x5e,0xe6,0x2b,0x2e,0xfc,0x6b,0x48,0xca,0xdd,0x38,0x92,0x88,0x62, + 0x17,0xf3,0xa3,0xff,0xab,0xd3,0x6d,0x41,0xcc,0x4f,0x89,0xf0,0xe6,0x2c,0xe7,0xca, + 0xb3,0x05,0xb9,0x35,0x3a,0x29,0x01,0x90,0xf7,0x0d,0xa3,0x8d,0x78,0xce,0xbd,0xc7, + 0xfa,0x18,0xdd,0x70,0xd7,0x72,0xcf,0xa3,0x1f,0x5c,0x45,0x5a,0x8d,0x01,0x55,0xbc, + 0x84,0xe0,0xaa,0x10,0x70,0x59,0x3a,0x65,0x60,0xf5,0xe2,0x14,0x77,0xb9,0x80,0xa1, + 0xe2,0x02,0x07,0xe8,0xb6,0x38,0xcc,0x97,0xdf,0x43,0xeb,0x04,0x05,0x21,0xf2,0xe3, + 0xd7,0xcc,0x4d,0xb0,0xbf,0x71,0x54,0xf0,0x9a,0x5f,0xa9,0xd7,0x02,0x16,0x64,0x0b, + 0xc3,0x4b,0x7c,0x83,0xf0,0x64,0x6c,0x30,0x99,0x5b,0x14,0xc4,0x1a,0x8b,0x04,0xa1, + 0x40,0x9b,0xae,0x50,0x10,0x9a,0x56,0xf4,0xc0,0xae,0xa8,0x70,0x53,0xb8,0xfc,0x86, + 0x68,0x27,0xcd,0x23,0xb4,0x1d,0x35,0xa0,0x1b,0x5b,0xeb,0xd0,0xf4,0x77,0xdc,0x55, + 0x83,0x15,0x0d,0x34,0x41,0x75,0x8d,0x75,0x9e,0xd1,0xd5,0xed,0x88,0x57,0x2d,0xf7, + 0xf9,0xc5,0x9c,0x1a,0x3e,0x71,0x4d,0xbf,0x6e,0xa2,0xae,0x57,0x7e,0x81,0xb7,0xdf, + 0xf3,0x13,0x4e,0xe4,0x2f,0x78,0xde,0xc4,0x77,0x1b,0x33,0xc3,0xe4,0xec,0x1f,0x8d, + 0xdb,0xe5,0xb9,0x09,0x93,0x2f,0x4c,0x09,0xb4,0x3a,0xdb,0xe3,0x0d,0x26,0xcb,0x71, + 0x69,0xd6,0x2c,0xa5,0x65,0x8a,0xd3,0xc5,0x96,0x1b,0x8c,0x86,0x81,0x8e,0x7e,0x39, + 0x89,0x5c,0xc6,0xd8,0x3c,0x2f,0x36,0xac,0x24,0x51,0x61,0xd9,0x7c,0xf5,0x5e,0xe9, + 0xd4,0xb6,0xb0,0xe9,0x58,0xb4,0x66,0x70,0xe9,0x75,0xfe,0xf5,0x18,0x8f,0x27,0xeb, + 0xa2,0x5c,0xc7,0xcf,0x13,0xb3,0xa8,0xae,0xe4,0x5d,0x90,0x05,0xcd,0xbe,0x37,0xdd, + 0x16,0x5d,0xd9,0xe8,0x08,0x72,0xe4,0x9b,0xa8,0xe0,0x4a,0x79,0xdb,0x5c,0x1e,0xa3, + 0x37,0x04,0xb2,0x95,0x96,0xa4,0x8d,0x68,0xa1,0x1f,0xbb,0x55,0x28,0x61,0xbb,0x61, + 0x71,0xed,0x6c,0x93,0x56,0x53,0xf8,0xf3,0x33,0x1c,0xee,0x0a,0x53,0x29,0xc3,0xed, + 0x65,0x2d,0x2a,0x65,0x6b,0xc0,0xdd,0xbc,0xc5,0x62,0xb3,0xd4,0x50,0x6f,0x4f,0x2e, + 0x86,0xda,0xb9,0x75,0xd7,0xe1,0x41,0x0c,0xe7,0x82,0xdc,0xb3,0x90,0xc6,0x74,0xb2, + 0xc5,0xd5,0xc4,0x0a,0xb5,0xa2,0x60,0xc3,0xe7,0x3b,0xe1,0x95,0x66,0x6e,0x97,0x3f, + 0x26,0xe7,0xec,0xb4,0x11,0xfc,0x01,0x0d,0xe0,0x84,0xe8,0xea,0xa8,0x48,0xa1,0x63, + 0x84,0x8b,0xc1,0x17,0x37,0x2e,0x2b,0x6c,0xae,0xd7,0x89,0x87,0xa4,0xa4,0x33,0xce, + 0xfb,0xc5,0x5d,0xd3,0xc0,0xa8,0xf8,0x32,0x86,0x86,0x6f,0x86,0x74,0x27,0x1c,0x33, + 0x64,0x59,0xa6,0xb8,0x2f,0xe3,0x22,0x2b,0x40,0x8a,0x72,0x7a,0xab,0x84,0xd1,0x3d, + 0xac,0x76,0xa2,0x1b,0x3d,0x59,0xe5,0x3b,0x4b,0x20,0x17,0x41,0xc0,0xb6,0xe3,0xca, + 0x94,0x87,0x19,0xc8,0x5e,0xaa,0x2b,0x23,0x49,0xea,0x54,0xd0,0x2d,0x3c,0x72,0x86, + 0x28,0x34,0x68,0xf7,0xa2,0x66,0xe1,0xbf,0xac,0x91,0x84,0x12,0x22,0x76,0x72,0xeb, + 0x6d,0x73,0x3d,0x4f,0x18,0xe5,0xad,0x6a,0x39,0x4c,0xc0,0x5e,0x95,0x43,0x7b,0xde, + 0x2f,0x8f,0xfa,0x5e,0x03,0xef,0x72,0xdd,0x2c,0xed,0x3a,0x5e,0xba,0xe7,0x1b,0xbb, + 0x29,0x2f,0xfd,0xcb,0xeb,0xdc,0xb3,0x17,0xbb,0xc8,0x53,0x1d,0xbc,0x69,0x53,0xcb, + 0x2c,0xdf,0xb3,0x13,0xac,0xbd,0x03,0xf9,0xc6,0x12,0xbf,0xfb,0xff,0xc5,0x07,0x60, + 0xc4,0x6f,0x87,0xba,0xec,0x41,0xf4,0xd7,0x03,0x92,0xe0,0x98,0x56,0xb2,0x77,0x92, + 0x23,0x21,0x57,0xb1,0x94,0x4e,0x8d,0x36,0x46,0xe6,0x5b,0xd8,0xa3,0xf9,0x96,0x61, + 0x5c,0xb1,0x65,0xd3,0x1c,0xbf,0xf4,0x7e,0xe2,0x2b,0x2a,0x66,0x79,0x8f,0x43,0xc9, + 0x58,0x0f,0x41,0x04,0xcd,0x6e,0xe6,0x85,0x9a,0xc2,0x7c,0x33,0xb0,0xd6,0x74,0x7b, + 0x87,0x0b,0x9a,0xee,0x75,0x44,0x0c,0x60,0x6f,0x69,0xca,0xd3,0xd5,0x7f,0x73,0x89, + 0xaa,0x68,0xd2,0xfe,0x74,0x45,0xa3,0x56,0x61,0x2c,0xc2,0xde,0xd0,0x55,0xd1,0xa1, + 0x5d,0xd4,0xfd,0xe7,0xfc,0xa7,0x4d,0xb3,0xe2,0xd9,0xef,0xd6,0x9a,0xe9,0x0f,0xfb, + 0x52,0x11,0xf5,0xc7,0x56,0x08,0x1f,0x77,0xcc,0x51,0x6b,0x84,0x9b,0x9b,0x20,0x2b, + 0x2a,0xb2,0xc0,0xb6,0x3d,0x68,0x6d,0x91,0x17,0x00,0x76,0xfa,0xc9,0x59,0xc2,0x05, + 0x2c,0x39,0x6e,0xca,0xca,0xd7,0xfe,0xdf,0xb2,0x42,0x6d,0xf9,0x73,0x26,0xf3,0xe9, + 0x53,0x07,0x80,0x89,0x6c,0xde,0x82,0x63,0x58,0x30,0xa0,0x50,0x15,0x6b,0xef,0x5a, + 0x83,0x06,0x10,0x04,0x48,0x2d,0x8d,0x42,0xdd,0x27,0x00,0x3a,0x02,0xb9,0x66,0x0a, + 0x14,0x17,0xfa,0x0c,0x5d,0x30,0x56,0x34,0xec,0xf4,0x94,0xf3,0x7d,0xbc,0xd6,0x0a, + 0x8c,0x62,0xe3,0xac,0x9c,0x36,0x06,0x78,0xef,0x55,0x19,0x03,0xbc,0xbf,0x7d,0xfa, + 0x9e,0x81,0xf1,0xfa,0xb8,0xbf,0x48,0x89,0xad,0x61,0xeb,0x23,0xda,0x25,0x36,0x1f, + 0x0a,0x1e,0x43,0xee,0xd3,0xfd,0x47,0xab,0xeb,0xd0,0x64,0xcd,0x88,0x09,0xdf,0xd2, + 0x06,0x28,0x16,0x80,0x30,0x22,0xef,0x07,0xe1,0xbc,0x2f,0x15,0xf1,0xe1,0xf0,0x18, + 0xfc,0x4e,0x80,0x05,0xed,0xc0,0xd8,0xe8,0x6f,0x4b,0xca,0x82,0xba,0x05,0x76,0xe9, + 0x62,0xdf,0xb9,0xc2,0x52,0x02,0xe9,0x29,0x3d,0x0d,0x7a,0xd6,0x54,0xef,0x69,0xa6, + 0x62,0x0e,0x49,0x21,0xc5,0xa8,0x9b,0xd9,0x19,0x88,0x09,0xc6,0x55,0xee,0xd3,0x7f, + 0x7a,0x46,0x55,0xa2,0xb7,0x4a,0xf0,0x13,0x7e,0x97,0x10,0xa5,0x23,0xe5,0x5e,0x6c, + 0x05,0x04,0x60,0xe4,0x20,0xb3,0xe6,0xf5,0xf4,0x20,0x8a,0xfe,0x55,0x9d,0x96,0x6e, + 0xe1,0x6b,0xa3,0x54,0x93,0x9c,0x2f,0x66,0x63,0x03,0x81,0x96,0x56,0xeb,0x09,0x23, + 0x20,0x8c,0x71,0xbd,0x37,0x68,0x61,0xf4,0x7c,0xfa,0x61,0xf1,0xd8,0x87,0xae,0x9a, + 0x0a,0x02,0x7a,0x3d,0x74,0x6a,0x90,0x6e,0x2a,0x09,0xc0,0x9b,0xb3,0x0c,0xbe,0x7a, + 0xba,0x6c,0x0a,0x0d,0xe5,0xc8,0xe2,0x09,0x25,0x0b,0x39,0xcf,0xdd,0xe4,0x57,0x6b, + 0xc8,0x05,0x93,0x8d,0x39,0xad,0x29,0xda,0xa4,0xc1,0x03,0x1c,0x79,0xeb,0x33,0xf2, + 0x25,0x06,0x4b,0x58,0xe0,0x8b,0x0b,0xb9,0x68,0x25,0xc9,0x8b,0x32,0x0f,0x85,0x79, + 0x7e,0x4e,0x02,0x15,0xd0,0xb1,0x44,0x0a,0xb5,0xd1,0xea,0x96,0xf6,0x61,0x32,0x67, + 0x73,0x4f,0x5a,0x37,0x15,0x4f,0xff,0x9a,0x4d,0x9d,0x92,0x74,0x5d,0x47,0x53,0xe8, + 0xe9,0xf1,0xbb,0x6a,0x63,0x21,0x93,0xd5,0xa2,0x13,0x7f,0xf2,0x2b,0xb8,0xd2,0xb6, + 0x62,0xbe,0x81,0xe0,0x24,0x74,0x43,0x02,0x9a,0x44,0x5d,0x03,0x78,0x0a,0x64,0x37, + 0xcb,0x50,0xfa,0x83,0x14,0x91,0x72,0xf9,0x63,0x63,0x04,0xbb,0x4c,0xc4,0x72,0xf2, + 0xd2,0x74,0x2c,0xe6,0x53,0xf6,0x0c,0x11,0xc0,0xf8,0xa2,0xed,0x33,0x8e,0x45,0xe4, + 0x22,0xf5,0xbd,0xb5,0x76,0x9d,0x4f,0x3c,0x9c,0x10,0x86,0xd7,0x1b,0xc3,0x35,0x6a, + 0x0d,0x1e,0xf3,0x92,0x95,0x3e,0x8b,0x51,0xdd,0x11,0xa3,0x8c,0x7c,0x85,0xd1,0x44, + 0x02,0x16,0x28,0x56,0x64,0x3c,0x0d,0xef,0x87,0x38,0x14,0x25,0x41,0x36,0xdf,0xf3, + 0x8e,0xb5,0x60,0xab,0xe9,0xca,0xde,0xf2,0x61,0x17,0x63,0x6f,0x86,0xd3,0x7d,0x51, + 0x01,0xb6,0xd5,0x83,0xd0,0x77,0x37,0xe4,0xe1,0x36,0x56,0x11,0x09,0x18,0x5a,0xf2, + 0x32,0x56,0x76,0x4f,0x44,0x2c,0x8e,0x94,0x6e,0xfa,0xa5,0xb5,0xeb,0x35,0xfd,0xaf, + 0x89,0xe7,0x79,0x64,0xe2,0x75,0x06,0x01,0xc9,0xc7,0xde,0x55,0x1b,0x8a,0x0b,0x1a, + 0xc7,0x56,0x1e,0x67,0xf8,0xb3,0x8f,0x88,0xe8,0x26,0xca,0xde,0x10,0x08,0x5e,0x99, + 0xae,0x18,0x7c,0xf2,0x35,0xec,0xa3,0xcb,0x13,0xf7,0x81,0x94,0xfe,0x7b,0xb4,0x7b, + 0x1e,0x7e,0x08,0x8d,0x1a,0x86,0x25,0x08,0xd1,0x04,0xc7,0xc4,0x10,0xca,0x18,0xe5, + 0xf4,0xb7,0x27,0xaa,0xb7,0x5e,0xc9,0x7a,0x62,0x56,0x9a,0x04,0x8f,0x88,0x70,0x38, + 0x62,0xe4,0x94,0xde,0x88,0xe4,0x9e,0x44,0xa3,0x1d,0xd8,0xa9,0x92,0x95,0x54,0x1b, + 0x2f,0xbf,0xb8,0x8a,0x47,0x88,0xd3,0x6d,0x9c,0x65,0xaf,0x69,0xae,0xab,0x17,0xd1, + 0xad,0x45,0xae,0x1d,0xff,0xb2,0x89,0xca,0xd8,0xea,0x73,0x6f,0xa7,0x77,0xd9,0x25, + 0xa5,0xff,0x36,0x75,0x78,0xcc,0x52,0x23,0x45,0xbb,0x20,0x55,0x25,0x51,0x5a,0x74, + 0xf2,0x91,0x8c,0x81,0x31,0x0c,0x0d,0x2d,0x75,0x83,0xeb,0xc5,0xd9,0xec,0x18,0x41, + 0x25,0x99,0xc3,0x1a,0x97,0xe2,0x86,0x16,0xc2,0x18,0xcf,0x21,0x3d,0x9b,0x91,0xec, + 0x64,0x1c,0xb2,0x2f,0x7e,0xe7,0x29,0x9a,0x64,0x6c,0x29,0xdf,0x41,0xae,0x7e,0x7a, + 0x27,0x44,0xe0,0x81,0xeb,0xd2,0xdf,0xe6,0x30,0x83,0x4f,0x84,0xbf,0xfc,0x30,0xd7, + 0x64,0xa5,0x89,0x96,0x0b,0xd8,0xc2,0x8d,0x49,0x7a,0x86,0x70,0xb6,0x66,0x5f,0x7f, + 0xef,0x17,0xbb,0x45,0x25,0x7f,0x79,0xd2,0xf5,0x12,0xe7,0x05,0xb6,0xec,0xb2,0x53, + 0x37,0xf6,0xfe,0x39,0xe5,0xcb,0xd5,0x9b,0x42,0x8a,0x98,0xf3,0xdc,0x7e,0x5d,0xc8, + 0xad,0x97,0x98,0xbf,0x21,0x07,0x27,0x0d,0xed,0x67,0x4d,0xc6,0xe0,0xa5,0xf9,0xe4, + 0xf4,0xba,0x92,0x2e,0xcb,0x06,0xac,0xbe,0x14,0xe5,0x81,0x4e,0xdd,0xf6,0x9e,0x36, + 0x73,0xd7,0x07,0x2b,0x29,0x0b,0xa2,0x10,0xfc,0x3f,0x24,0xc9,0xf8,0x5c,0x54,0x61, + 0xbf,0x14,0x0b,0x6d,0xff,0x6c,0x01,0xc4,0x30,0xa7,0x02,0x4f,0x5d,0xfd,0x63,0x48, + 0x46,0xe0,0xf8,0x4c,0xdc,0xa8,0x15,0x9a,0xce,0x8e,0xe0,0x8e,0xb5,0xa8,0x03,0xb1, + 0x09,0x8c,0x52,0xb1,0x2c,0x58,0xba,0xc6,0x97,0x8f,0x75,0x18,0x60,0xcd,0xb7,0x15, + 0xa0,0x52,0xab,0xcb,0xad,0xfa,0x24,0x15,0xcd,0xaf,0xc9,0xdf,0x4c,0xac,0x86,0xab, + 0x28,0x2e,0x53,0x72,0x38,0xe2,0x2c,0x99,0xcc,0xbd,0x22,0xcc,0xe4,0x92,0x9b,0x60, + 0x9b,0x96,0xee,0x9b,0x74,0xd5,0xd8,0xd9,0xfa,0x4d,0xb6,0x55,0x00,0x5d,0xb3,0x92, + 0x25,0x91,0xba,0xf4,0xca,0x1c,0xfb,0x8f,0x63,0xd0,0xf4,0xd7,0x16,0x03,0xd3,0x70, + 0xa2,0x90,0xdd,0xa3,0x5d,0xa8,0xd4,0xe3,0xea,0x59,0x26,0xe0,0x3e,0x4a,0x2d,0xe1, + 0x27,0x74,0x63,0x32,0x42,0x4e,0x69,0x43,0x1a,0xdc,0xab,0x8b,0xf3,0xf2,0x84,0x46, + 0x05,0x55,0xbd,0xf8,0x91,0xa4,0xcc,0x82,0x62,0xf9,0xd5,0xc2,0x9d,0x90,0xd4,0x2c, + 0x37,0xd8,0x62,0xc5,0x7a,0xad,0x24,0x1f,0x54,0xbf,0x83,0x72,0x24,0x3b,0x49,0x0c, + 0x95,0x1a,0x1d,0xe3,0x57,0x19,0x6b,0x0b,0xd1,0x1b,0xcd,0x1d,0x5a,0xfb,0x12,0x89, + 0x52,0x0b,0xbd,0xc2,0xf3,0x3c,0xc5,0x13,0x80,0xcc,0x6d,0xc5,0x00,0x56,0x5c,0x68, + 0xa3,0x83,0xb4,0xcc,0x18,0xc5,0x6c,0x4c,0x04,0x39,0xe2,0xcc,0x15,0x89,0x96,0x14, + 0x2c,0x09,0xd5,0xe1,0x45,0x06,0x7c,0x58,0x31,0xdd,0x09,0x87,0x7b,0xd8,0x0f,0xed, + 0x32,0x88,0xd8,0x2a,0x76,0xb7,0xf7,0x8b,0xee,0xd7,0xef,0x6e,0x04,0x2b,0x4f,0x2c, + 0x0a,0x96,0x95,0x27,0x4e,0xfa,0x13,0x4b,0x4a,0x7a,0xa3,0x7f,0xec,0x4e,0x59,0x53, + 0x0d,0xbc,0xee,0xff,0x2f,0x13,0x97,0x8c,0xd5,0x6d,0xe8,0x15,0x9f,0x9f,0x91,0xa0, + 0x01,0x42,0xd6,0xee,0x3d,0x12,0x6e,0x12,0xfb,0x90,0xc5,0x8e,0xff,0xe2,0x24,0xb0, + 0xc6,0x93,0xee,0xbc,0xaf,0x1f,0x4d,0x53,0xcc,0x33,0x8c,0x90,0x73,0x48,0x51,0xe3, + 0xd3,0x30,0x4f,0xad,0xdd,0xa9,0x82,0x13,0x1b,0x92,0xa5,0xfd,0x6d,0xbe,0x12,0xff, + 0xfb,0x8d,0x76,0xc2,0xb1,0x3b,0xa0,0x57,0x4e,0x9f,0xb6,0xc6,0xdc,0x21,0x1f,0xe3, + 0x85,0xdc,0x06,0x25,0xb0,0xa0,0x66,0x69,0xc3,0xa6,0x67,0xd8,0xf1,0x5a,0x53,0xfe, + 0x73,0xff,0xa4,0xe3,0xb4,0x8f,0x81,0xc9,0xff,0x8f,0x51,0x05,0xb1,0xd9,0x5a,0xe2, + 0x0d,0x0e,0xa4,0xe6,0x15,0xae,0xf1,0xd3,0xb6,0x43,0x5e,0xb1,0xf1,0x3a,0x9b,0xcb, + 0x7d,0x0f,0xfe,0x3c,0x6e,0x66,0x0a,0x29,0x3e,0x06,0x89,0xba,0x21,0xa3,0x48,0x22, + 0xf8,0x47,0x0c,0xd1,0x1d,0xaf,0x66,0x48,0xce,0x93,0x01,0xc2,0x68,0xb3,0x7f,0x90, + 0x3d,0x5d,0xce,0x79,0x33,0x19,0x1d,0xa9,0x63,0x99,0x8e,0x64,0xed,0x46,0x54,0x9d, + 0x62,0xf8,0x0e,0xa6,0xb5,0x4b,0x51,0x61,0x9f,0xb0,0x22,0x88,0x81,0x25,0x7d,0xad, + 0xc2,0x05,0xd0,0xbf,0xf3,0x4c,0xcd,0x35,0x33,0x48,0xa8,0xdf,0x34,0xc5,0x31,0xa8, + 0x2f,0xbd,0xb2,0x2c,0x4d,0x86,0x47,0xe9,0x4f,0x4b,0xd2,0x4d,0x3a,0x04,0x78,0x7b, + 0xf0,0xb5,0x13,0x8f,0x7e,0xb8,0xce,0xd7,0xff,0x9d,0x05,0x6a,0x12,0xd2,0xab,0xea, + 0x05,0x86,0x2b,0x6f,0xfb,0xec,0x28,0x4a,0x90,0x40,0x8d,0x08,0xdf,0x6a,0xfd,0x0f, + 0xc0,0xa6,0xff,0xdf,0x3c,0x83,0xd0,0x16,0x29,0xa8,0xd5,0x7e,0xdd,0x2f,0x9e,0xfa, + 0xaa,0x92,0x1d,0xaf,0x35,0x6f,0x62,0xfa,0xad,0xfd,0xea,0x1a,0x1b,0x22,0x0b,0x38, + 0x77,0x4c,0x13,0xc8,0x94,0xa4,0xc4,0xed,0xc1,0xf6,0x13,0x8d,0x98,0x75,0xff,0x3b, + 0x70,0x14,0xc4,0xb8,0x9d,0x97,0x23,0xd9,0x93,0x0d,0x63,0xcf,0x9b,0x8f,0x64,0xc4, + 0x5b,0x9b,0x92,0xbc,0xdb,0x74,0x49,0xbc,0x66,0x71,0x23,0x91,0x76,0xda,0xac,0xe2, + 0x82,0x17,0x28,0xb0,0x52,0xd5,0xdc,0x71,0xa1,0x13,0x0d,0xca,0xbb,0x40,0x85,0x63, + 0x22,0x5a,0xbf,0x35,0x56,0x9d,0xc5,0x25,0xc9,0x17,0xc0,0xe2,0x0d,0xd4,0xdd,0xd5, + 0x02,0x76,0x9a,0x66,0x35,0xbe,0x16,0x23,0xe7,0x49,0xd5,0xa1,0x25,0x42,0x59,0x44, + 0x0c,0xd3,0xcb,0x21,0x8f,0x9b,0x6a,0xd9,0xc5,0x52,0xe7,0x82,0x8d,0xf5,0x4b,0x20, + 0x5e,0xe4,0xb2,0xd3,0xca,0x94,0xdd,0x96,0x94,0x45,0x8c,0x83,0x69,0x6e,0x85,0x71, + 0xb4,0x1e,0x65,0x60,0x78,0x3b,0x05,0xfc,0x41,0x4d,0x2a,0x63,0xa8,0x8b,0x33,0xd7, + 0x42,0x94,0x6d,0x2e,0x42,0x94,0xe5,0x0e,0xe5,0xce,0x11,0x93,0xd0,0xf5,0x7e,0xaf, + 0x0c,0x91,0xd4,0x3a,0xd3,0x5c,0x8c,0x2c,0x1c,0x6d,0x31,0x80,0xe0,0x69,0x08,0x38, + 0x4a,0xab,0xf0,0x9a,0xd8,0xba,0x88,0xbb,0xe9,0x39,0xa0,0x94,0x9a,0x70,0x83,0x76, + 0x5c,0x19,0x17,0x7d,0xa1,0x8b,0xd7,0xd0,0xd5,0x18,0x92,0x06,0xa4,0xb4,0x9c,0x6a, + 0x2d,0x96,0x7d,0x6e,0x35,0x7a,0xdf,0x99,0x88,0xd6,0x0f,0x4d,0xa7,0xda,0x23,0x3b, + 0xa6,0x97,0x62,0x36,0x3c,0x84,0x61,0x6c,0x2c,0x2d,0x8f,0xd7,0xdf,0xfe,0x0c,0x26, + 0xd6,0x71,0x2d,0x9c,0x3d,0x39,0x5f,0x9e,0xe9,0x59,0x61,0xb6,0x6b,0x79,0x43,0x2b, + 0x43,0xb4,0xf3,0x33,0x03,0x50,0x0e,0xe5,0x4f,0xa1,0x28,0x1d,0xf2,0x62,0xac,0x19, + 0xb1,0xe2,0x4d,0xb6,0x34,0x99,0x0f,0xa6,0x48,0x3a,0x5f,0xba,0xd5,0x61,0x58,0x26, + 0xa1,0xec,0xde,0x01,0x30,0x0d,0x74,0xca,0x73,0x0d,0xf0,0x44,0x75,0x0a,0x92,0x22, + 0x06,0x2e,0x90,0x26,0xc5,0x0e,0x80,0xd2,0x09,0xda,0xc6,0x1a,0xbe,0xf0,0xe5,0xf8, + 0xb7,0xb6,0x32,0x36,0x35,0x03,0x69,0x3b,0xf7,0xf6,0xeb,0xd8,0x3f,0xd3,0x89,0x61, + 0xe7,0xb5,0x09,0x65,0xf7,0x04,0x9d,0xd5,0xd5,0x8c,0x83,0xdc,0xb6,0x6f,0xbb,0x34, + 0x8b,0xe6,0xd4,0xad,0x9b,0x02,0x29,0x56,0xe3,0x65,0x30,0xaa,0x6c,0x69,0x60,0x0e, + 0x64,0x8e,0xfb,0x42,0xea,0xc9,0x7a,0x7f,0xbb,0x54,0x69,0x4c,0x6f,0x10,0x8d,0xc7, + 0xe4,0x5c,0x31,0x87,0x9f,0xa5,0x62,0x90,0xbe,0xc5,0xa8,0x45,0x71,0x53,0xfe,0xa0, + 0x03,0x0a,0x8b,0x53,0x94,0x97,0x07,0x4b,0x1b,0x76,0xe8,0x49,0xbb,0xa5,0x5c,0x0d, + 0x28,0x03,0xdc,0x09,0x38,0x23,0x9a,0xb2,0xad,0xd3,0xa7,0xaa,0x7c,0xd0,0x8a,0x68, + 0x6f,0x6e,0x90,0xae,0xed,0x06,0x22,0x1e,0x7e,0xa4,0xaa,0x85,0xfc,0xe2,0xba,0x3a, + 0xf0,0x25,0x79,0x23,0x77,0xee,0xea,0xdd,0x25,0x72,0x8b,0x4f,0x86,0xa8,0x55,0x1c, + 0x2c,0xca,0x0f,0x3b,0xfe,0xe1,0x60,0xa4,0xfa,0x4c,0x7d,0x64,0x64,0x57,0x30,0xc1, + 0xe5,0xe8,0xf2,0x76,0x2a,0x51,0x52,0x6f,0x86,0x5d,0x79,0xb0,0x58,0x96,0x86,0xc8, + 0x0f,0x85,0xf8,0x35,0x90,0x0b,0x69,0x9c,0xcd,0xce,0x3a,0xd3,0xac,0x60,0x39,0x4a, + 0x2d,0x73,0x0f,0xdd,0x82,0xa4,0x64,0x83,0x84,0x63,0x26,0xeb,0xae,0x5c,0x2e,0x24, + 0x89,0x0c,0x3f,0x1f,0xeb,0xed,0x7e,0x99,0xfc,0x0d,0xa2,0x69,0x78,0xf4,0x76,0x34, + 0x00,0x2f,0xfa,0x64,0x68,0x34,0xcb,0x52,0xa5,0x21,0x22,0x22,0x54,0xd3,0x13,0xe2, + 0x29,0x3e,0xd4,0x8b,0xf5,0xf0,0x64,0xba,0x06,0xbf,0x44,0x32,0x55,0xf3,0x1f,0x33, + 0x82,0x0d,0xdd,0xf4,0xc0,0x19,0xf5,0x83,0xfd,0xdf,0x8b,0x8f,0x57,0x73,0x8d,0x89, + 0x29,0x6e,0xd3,0x90,0x14,0x6c,0xaa,0x37,0xc5,0xdf,0x85,0xa7,0x56,0x5e,0xa4,0x72, + 0x69,0xd6,0x30,0x86,0x22,0xc9,0xcb,0x00,0xca,0x79,0x8f,0x0e,0xb2,0xbb,0xad,0x92, + 0x7f,0x1e,0x51,0xeb,0xc8,0x9d,0x6b,0x10,0x61,0xec,0xaa,0x05,0xf3,0x7e,0xb1,0x75, + 0xa0,0x15,0x72,0x38,0x36,0x16,0x66,0x01,0x4a,0x7b,0x65,0x17,0xc6,0x57,0x31,0xee, + 0x4c,0xd3,0x10,0xf3,0x95,0x14,0x68,0x77,0x9a,0x8a,0xc8,0x46,0x95,0x58,0x5e,0x96, + 0x08,0x37,0x12,0xec,0xc3,0x15,0x0c,0x48,0x30,0x2f,0x20,0x2a,0x5c,0xab,0x50,0x9d, + 0x09,0xa8,0xf0,0x7c,0x39,0x14,0x33,0x3e,0x70,0x33,0x80,0x92,0xde,0x59,0x87,0xf9, + 0xce,0x5d,0xae,0xbe,0x1d,0xfb,0xb0,0xc4,0xea,0x08,0x89,0x86,0x5f,0x9f,0x56,0xfd, + 0x20,0x6d,0x21,0xad,0x56,0xff,0xff,0xc3,0x34,0xdd,0x29,0x9e,0x73,0xba,0x5c,0x7a, + 0xb4,0x33,0x3a,0x33,0x52,0x07,0x3e,0xee,0xeb,0x3d,0x52,0xca,0x50,0x23,0xe9,0x9b, + 0x2d,0xdc,0xb7,0x41,0x9a,0xb6,0xaa,0x7c,0x1f,0x20,0x80,0x4f,0x96,0x7e,0xc3,0x3b, + 0xa6,0x91,0xf2,0x4b,0x88,0xbe,0xe7,0xf0,0xc4,0xa3,0x5b,0x9c,0x94,0x08,0xc8,0xe3, + 0xd0,0xbf,0x7e,0xff,0x99,0x5d,0x61,0x5a,0xce,0x66,0x1c,0x0c,0x9d,0xbe,0xb7,0xd4, + 0x77,0x00,0xfe,0x03,0xb1,0x5f,0x2a,0xda,0xbb,0x3d,0x6f,0x5e,0x26,0xbf,0x5e,0x6e, + 0x6b,0x82,0x48,0xd5,0x5a,0xbc,0x60,0xce,0xb8,0x72,0x87,0x62,0x57,0x40,0xbe,0x30, + 0xea,0xad,0x2d,0x7f,0x0e,0xbd,0x86,0xde,0x75,0xe1,0x51,0x05,0x44,0x20,0x77,0xa1, + 0xa5,0xae,0xf1,0x0c,0xf2,0x43,0x66,0x4b,0xf3,0xdc,0x82,0xb1,0x89,0x0f,0x0a,0xbb, + 0xa1,0x02,0xd6,0xf0,0xed,0x89,0xf3,0xc5,0x9e,0xc7,0xf8,0x17,0xde,0xe2,0xb3,0xb2, + 0xa2,0x8f,0x2a,0x4b,0xdd,0xa8,0x62,0x41,0x25,0xea,0x1f,0x45,0x61,0x27,0x61,0x7d, + 0x23,0x8c,0xb9,0xf4,0xf8,0x89,0x72,0xd0,0x1a,0x85,0xd1,0xa5,0xc0,0xed,0x36,0xb3, + 0x22,0x88,0xb7,0xc6,0xf8,0xa1,0x08,0x02,0xa9,0xc4,0xc9,0xd4,0xb0,0x98,0x54,0x38, + 0xf7,0xa7,0x15,0xf3,0xf9,0xfb,0x82,0xd2,0x2b,0x59,0x3b,0x52,0xcd,0x14,0xf5,0xeb, + 0x6f,0x48,0x28,0x6a,0x9b,0xee,0xa8,0x80,0xa2,0x2d,0xad,0x8d,0xad,0xea,0xd5,0x7a, + 0xea,0x89,0x78,0x0f,0x51,0x31,0x04,0xda,0x4c,0xc1,0x2c,0x62,0x28,0xe9,0x51,0x31, + 0xe1,0xa8,0x04,0xff,0xe2,0x0b,0x23,0xc7,0x34,0x27,0x2c,0x8c,0xdf,0xdb,0x22,0x4a, + 0x76,0x03,0x42,0x5f,0x70,0xfa,0x29,0x9b,0x24,0x20,0xaa,0x9d,0xf9,0x2c,0x72,0xda, + 0x29,0x3d,0xad,0xad,0xc9,0x6d,0x12,0xe1,0xc6,0xc0,0x8d,0x8c,0xa4,0x62,0xd3,0xcd, + 0x81,0xac,0xe5,0xf9,0x44,0x81,0x6d,0xcc,0x08,0xce,0xed,0xc5,0xdc,0x6f,0x33,0xdb, + 0x6d,0x3d,0xb5,0x6b,0x70,0xca,0x3d,0xc9,0x34,0xc4,0x6f,0x9f,0xff,0xe4,0xf9,0x78, + 0x20,0xef,0x44,0xa4,0x6e,0x2b,0x6a,0xa6,0x03,0x65,0x7a,0x87,0xe7,0x55,0xa0,0xe3, + 0x4b,0x90,0x27,0x11,0xa2,0x0e,0x8c,0x4c,0xe1,0xaa,0x1b,0x90,0xf4,0x81,0xde,0x81, + 0xa4,0xa2,0x03,0xdb,0x3d,0x50,0x43,0x8d,0x0b,0x36,0x29,0x86,0x47,0x3c,0x09,0x62, + 0xcf,0x9e,0x72,0x65,0x59,0x42,0xbd,0x33,0x07,0xb7,0x0d,0xc7,0x0e,0x31,0x1d,0x59, + 0x87,0xcb,0xb6,0xcc,0xd6,0x93,0x5c,0xc8,0x8b,0xd7,0x73,0xe2,0xa6,0x10,0x6e,0x2b, + 0xca,0xdf,0xcd,0xe2,0xcb,0xce,0x88,0x63,0x0d,0x8a,0x18,0x24,0x7f,0x73,0x7b,0x15, + 0x76,0x19,0xf4,0x69,0x56,0xa3,0x33,0x49,0x1d,0xfb,0xed,0x0a,0xfc,0x14,0xee,0x33, + 0x63,0xba,0xcd,0x17,0x30,0x71,0x9d,0x39,0xe3,0xfa,0x55,0x38,0x50,0x0a,0x96,0xfb, + 0x6f,0x9a,0x46,0xad,0x7e,0x35,0x4c,0xaa,0xcb,0x43,0xca,0x7e,0x99,0x87,0x6e,0x2f, + 0xd0,0x5b,0xb5,0x20,0xce,0x7b,0x13,0x5a,0x12,0x79,0x85,0xc8,0x02,0x79,0xf8,0xfa, + 0x82,0x5b,0xdc,0x8d,0xc4,0xc5,0x35,0xdf,0x6a,0x9d,0x17,0x4c,0x5e,0x3a,0x4f,0xfc, + 0x2b,0xfc,0x9f,0x60,0xbf,0x82,0x20,0xfe,0x2b,0xbb,0xc4,0xdd,0x86,0x5b,0x3e,0xa8, + 0x22,0xac,0x71,0xe8,0x51,0x33,0x07,0xd5,0x95,0xf1,0x9c,0xf9,0xf8,0x7f,0x2e,0x6e, + 0x20,0x12,0xde,0x65,0x9a,0x22,0xe1,0x6b,0x0d,0x80,0x92,0x0c,0x77,0x72,0xf8,0xd2, + 0x09,0x9a,0x47,0xbe,0x88,0x7c,0x81,0x55,0x1d,0x32,0x94,0x0f,0x78,0x36,0x16,0x40, + 0x0e,0xe0,0x7b,0xbf,0x50,0x7b,0x39,0x48,0xea,0x0f,0xf8,0xfb,0x2b,0x1b,0x5e,0x04, + 0x67,0x45,0x60,0xc7,0x5f,0xad,0xd3,0x06,0x27,0xd1,0x1c,0x59,0x68,0x1f,0x10,0xe1, + 0x27,0xef,0x04,0x89,0x14,0x21,0x8a,0x8e,0xae,0xa5,0xd8,0x34,0x54,0xec,0x77,0xb3, + 0x6f,0xe6,0x5e,0xef,0x18,0x6f,0xa6,0xd0,0x40,0x49,0x0a,0x8b,0x23,0xa3,0x4f,0x2b, + 0xa1,0x08,0xae,0xac,0xd1,0xac,0x01,0x17,0x32,0xce,0xcb,0x3f,0xd5,0xe9,0xa0,0x83, + 0x14,0x89,0xbe,0x75,0x06,0x0b,0x72,0xf1,0x68,0x1b,0x37,0x5b,0x50,0xe5,0x08,0x50, + 0x7e,0x88,0xd6,0xfe,0xdd,0xd6,0x42,0xed,0xb8,0x4e,0x00,0xf2,0x77,0xe7,0x01,0xe3, + 0xda,0x89,0xd3,0x01,0x04,0xca,0xb1,0xab,0xc6,0xaa,0xa5,0x08,0x75,0x67,0x7b,0x57, + 0x05,0x84,0x97,0x4c,0x7e,0x44,0x7b,0xed,0x30,0xc4,0xa3,0x76,0x74,0xa5,0x33,0x3b, + 0x62,0x27,0x62,0xcf,0x09,0xa5,0x4d,0xd2,0x4c,0x8a,0x2e,0xac,0x17,0x0f,0xf8,0xe9, + 0x81,0x84,0x3a,0x51,0xe4,0xd5,0x46,0x58,0xb6,0x88,0x14,0x1d,0xc8,0xcc,0x83,0xfb, + 0x68,0x29,0xc3,0xb9,0xc4,0xa5,0x34,0x6c,0x4e,0x2d,0xa5,0x4d,0xf3,0xcf,0xd4,0x3f, + 0x64,0xe8,0x02,0x60,0x08,0xf6,0x61,0x13,0xa5,0xba,0x12,0x1c,0x04,0xce,0xa7,0xa8, + 0x8c,0x4b,0x80,0x4e,0xf5,0x38,0xcc,0xc2,0xaf,0x13,0xe2,0xc7,0xaf,0xe3,0x0a,0xec, + 0x1d,0x80,0x8b,0xfe,0xc9,0x12,0x44,0xca,0x85,0xde,0x21,0x7c,0x20,0x94,0x2f,0x29, + 0xce,0x81,0xbd,0x40,0x92,0xe0,0x8c,0x69,0xe0,0xa0,0x47,0x14,0x7d,0xaf,0x94,0xa9, + 0xae,0x1d,0xc2,0x30,0x0e,0x6a,0x45,0xde,0x05,0x2c,0xa0,0x7d,0xa4,0x76,0x1a,0xe0, + 0x97,0xf5,0x0e,0x98,0x56,0x44,0x7c,0x13,0xb8,0x94,0x34,0x17,0xaa,0xbe,0xd5,0xb5, + 0x84,0xee,0x64,0x12,0x15,0x10,0x47,0x36,0x6e,0x89,0x9c,0xe7,0xd4,0x79,0x1d,0x68, + 0x08,0x9f,0xf3,0xe9,0xb2,0xb3,0x96,0xa4,0x48,0xdf,0xf7,0x61,0xb0,0xf4,0xbd,0x11, + 0x4b,0x3e,0xf4,0x82,0x60,0xdf,0x06,0x51,0x39,0x97,0x3d,0x55,0x77,0xf7,0x04,0x74, + 0x2d,0x99,0xc5,0xc1,0xbb,0x32,0x4a,0x56,0x06,0x2b,0xcc,0x19,0xb7,0x96,0x14,0x56, + 0x2c,0x34,0xec,0x96,0x55,0x08,0x83,0x0c,0x43,0xbb,0x9c,0xb2,0x24,0xfa,0xc2,0x21, + 0x66,0x3b,0x85,0xb4,0x3a,0x30,0x8a,0x90,0x8c,0x55,0x31,0x62,0xb5,0xd6,0x55,0x29, + 0x0b,0x9a,0x8f,0x55,0x46,0x31,0x3d,0xcc,0xef,0xbb,0x42,0xa5,0xf9,0x7d,0x1e,0x70, + 0x80,0x95,0x62,0xd0,0x32,0xa6,0x95,0xad,0xc0,0xbd,0x25,0xcc,0x3d,0xd8,0x9a,0xf8, + 0xd2,0xd8,0x3b,0x1a,0x15,0x6b,0x64,0xf2,0x15,0x76,0x9e,0x3b,0xf8,0x7b,0x58,0xac, + 0x0d,0x45,0xda,0x70,0xdf,0x3d,0x0f,0x9a,0x4d,0x45,0xcf,0xcd,0xbd,0xba,0x11,0x2f, + 0x4d,0x64,0x97,0x67,0xbd,0x4a,0x9f,0xc9,0x8f,0x1c,0xdf,0xbd,0xb4,0xf6,0x19,0xed, + 0x8f,0x43,0xe6,0x8e,0x4e,0xfe,0x5e,0x28,0xba,0x7f,0x72,0xc9,0xdd,0x48,0xbe,0x8a, + 0x29,0x9f,0x5a,0xbc,0xd4,0xf9,0x59,0x52,0x86,0xae,0xb4,0xeb,0xfd,0xb5,0xd3,0xa9, + 0x51,0x98,0xf7,0x66,0x1f,0xa1,0xd0,0x5f,0x3e,0x3d,0x57,0xf5,0x72,0xf3,0xf3,0xdf, + 0x8c,0x0b,0xce,0xd8,0x30,0x39,0x21,0x19,0xeb,0x5a,0x67,0x1d,0xdb,0xff,0x2f,0x7f, + 0xd9,0x9c,0x08,0x06,0xb1,0xaa,0x06,0x15,0x46,0x41,0x27,0x08,0x74,0x94,0xf1,0xd7, + 0xf8,0x87,0xc2,0xea,0xb2,0x27,0xd8,0x10,0x5a,0x4c,0xa0,0x64,0x53,0x6e,0xba,0x5b, + 0x61,0x7d,0x5e,0xe7,0x3c,0x2f,0x51,0x43,0xe1,0x31,0x82,0xa7,0x50,0xca,0x09,0x6b, + 0x43,0x43,0x81,0x90,0x30,0xa9,0x01,0x25,0xc7,0x42,0xa3,0xb7,0x59,0xbb,0xc1,0xb3, + 0xe2,0x48,0x6b,0xc1,0x81,0x1b,0xa6,0xa0,0x52,0x06,0xd8,0x71,0x61,0x81,0xe3,0xb8, + 0x47,0x69,0x08,0xb5,0x1f,0x19,0xec,0x0b,0xe0,0xb5,0x20,0x69,0xad,0xb5,0x20,0x3a, + 0x57,0x9b,0xbe,0x1a,0x27,0xda,0x5e,0x63,0x33,0x49,0xee,0x83,0xc2,0x9b,0x9d,0x0f, + 0xad,0xdb,0x76,0x1e,0x95,0x26,0xe6,0x01,0x97,0x4c,0x2c,0x51,0x0f,0xa4,0x0a,0x81, + 0xe9,0xb9,0x75,0xee,0xb9,0xa2,0x5f,0x4a,0x0a,0x47,0xea,0xae,0xd8,0x00,0x6a,0xaf, + 0xe8,0x4b,0x77,0xfe,0xb8,0xa3,0xda,0x19,0x33,0x25,0xa3,0xc0,0x55,0x2b,0xfc,0x73, + 0xea,0xd5,0x6c,0xef,0x39,0xa0,0x2d,0xfd,0x8a,0x95,0xad,0x15,0x7b,0x91,0x41,0x27, + 0x8f,0xbb,0xf4,0xff,0x1b,0x03,0xf8,0xf9,0x81,0x09,0x06,0x66,0xdf,0x92,0x2b,0xa3, + 0xe1,0xb8,0x8e,0xc8,0x3a,0x8d,0xe3,0x4c,0x21,0xfd,0x8c,0xd9,0x52,0x6a,0xca,0x9e, + 0x99,0x0e,0x0e,0x02,0x15,0x33,0x04,0x45,0x95,0xe6,0x5d,0x83,0xb2,0xae,0xe0,0x53, + 0xe1,0x7a,0x9a,0x58,0x4f,0x42,0x77,0x98,0xbe,0x42,0xf3,0xa9,0x7b,0xe4,0xa8,0xa2, + 0x62,0xa8,0xb6,0xb2,0x6a,0x6d,0x0b,0xab,0x22,0x85,0x77,0xe2,0xd8,0xcf,0xc4,0x99, + 0xeb,0xed,0xbe,0x28,0xdb,0x54,0x94,0xcc,0xdf,0xf0,0xb4,0xe1,0xd1,0x79,0xf5,0x68, + 0x29,0xaa,0x8c,0x6d,0x3d,0x73,0x0c,0x24,0x76,0x1f,0x18,0x30,0x4c,0xcd,0x90,0x6e, + 0x55,0x41,0x45,0xd0,0x94,0xa9,0x83,0xa0,0xc3,0x13,0x10,0x58,0x41,0xa9,0x0d,0x13, + 0x4f,0x5e,0x8a,0x46,0x65,0x02,0xdf,0x59,0xe7,0x1e,0x9b,0x8c,0x71,0x6e,0x3f,0xe7, + 0x83,0xab,0x3c,0xcc,0x95,0x24,0xc3,0xdb,0x16,0xc1,0xe9,0x60,0x70,0x1d,0xb1,0x3c, + 0x23,0xa8,0xf2,0xac,0x4f,0x77,0x62,0x54,0x65,0x86,0x96,0x95,0xbb,0x0f,0x1c,0x4f, + 0x07,0xc9,0x3d,0xcd,0x15,0xc9,0x42,0x65,0xbd,0xcd,0xb5,0x52,0x0b,0x34,0xd8,0x2a, + 0x16,0x84,0xc2,0xe9,0x12,0x88,0x16,0xc0,0xc1,0xf8,0xa5,0x71,0xb0,0xec,0x3e,0x77, + 0x5f,0x18,0x21,0xa0,0x3e,0xf0,0x64,0xa9,0x2e,0x43,0xf6,0xae,0x75,0xf3,0x0e,0x1c, + 0x71,0xb7,0x8c,0x6f,0xbd,0xb4,0x1a,0x3c,0x4c,0xf8,0x90,0xde,0x3a,0x84,0xc7,0x59, + 0x06,0x81,0x3d,0x72,0x05,0xbb,0x87,0xcf,0x13,0xa1,0x68,0x4f,0x7a,0x7e,0xb0,0xb4, + 0x16,0xc6,0x5e,0x19,0xf4,0xfb,0xc0,0x73,0x9e,0x6b,0xe7,0x7a,0xdd,0x15,0x3d,0x4c, + 0x73,0x18,0x9d,0xcc,0xb7,0x27,0x06,0x96,0x00,0xad,0x16,0x3c,0x69,0xd1,0xb3,0x1f, + 0x2d,0xa5,0xee,0x2f,0x98,0x2f,0x97,0xc9,0x1f,0xf2,0x1e,0x2c,0x0c,0x7b,0x7f,0x27, + 0x06,0x13,0xf1,0xab,0x60,0xb5,0x29,0xd4,0xec,0x8d,0x05,0xfe,0x94,0x71,0xb9,0x99, + 0xe9,0xc2,0x77,0xad,0x3b,0x99,0xcc,0x87,0x81,0xee,0x29,0x8e,0xff,0x7d,0x4e,0x6d, + 0x78,0xff,0x04,0x64,0x57,0x5d,0x24,0x9b,0x04,0xcf,0xb5,0xdb,0xe5,0x3b,0xa8,0xeb, + 0x05,0xef,0x0f,0x3e,0x88,0x1c,0x3e,0xb6,0x6d,0xf9,0x78,0xd6,0xcb,0xa3,0x98,0xbf, + 0x33,0x19,0xd9,0x23,0x40,0x43,0xf1,0x02,0xdd,0xcb,0x35,0xa3,0xe9,0x5e,0x16,0x81, + 0x85,0x1e,0x04,0x59,0x64,0xff,0x7b,0xd1,0x2c,0x69,0xe5,0xa5,0x3c,0x72,0x6e,0xf0, + 0x25,0x44,0xf0,0x68,0x10,0xa5,0x62,0x9c,0xad,0x87,0xca,0x95,0x30,0xe0,0x48,0x42, + 0xb3,0x52,0x44,0xd3,0xc2,0xc7,0x2c,0x35,0x8d,0x6f,0xc0,0xa6,0x0b,0x1a,0x3b,0x19, + 0x31,0xf9,0xf7,0xaf,0xda,0x7a,0x4b,0x90,0xec,0x6b,0xf6,0xe5,0x56,0xac,0xdc,0xec, + 0x5a,0xfa,0x80,0xbc,0x6c,0x5b,0x31,0xdb,0x2e,0x16,0x55,0x04,0xb1,0x11,0x40,0x0b, + 0x0d,0xba,0x62,0x5a,0xf9,0x57,0x70,0xd4,0x4a,0xe9,0xc0,0x2a,0x58,0x84,0x78,0xe5, + 0x8f,0x6e,0x6a,0x4b,0x39,0xd4,0x3c,0xbe,0x65,0x63,0x84,0x07,0xd0,0x6f,0x19,0x32, + 0x73,0x17,0x06,0x09,0x08,0xce,0x7d,0x6c,0x1a,0xc0,0x23,0x5d,0x37,0x5b,0x97,0x9f, + 0xce,0x5e,0xb9,0x0f,0x76,0xef,0x39,0xd9,0x31,0x2a,0xf9,0xff,0x5a,0xed,0xcd,0x14, + 0xbb,0x50,0x5f,0x11,0x18,0x8d,0x60,0x7a,0xb1,0x41,0x8c,0xda,0xdc,0x0b,0xfa,0x28, + 0xf0,0x70,0xfe,0x6a,0x3b,0x20,0x72,0x7a,0x87,0x8e,0xdc,0xa6,0xfc,0xaf,0x0b,0x89, + 0x08,0x7b,0x67,0xb4,0x27,0xec,0x25,0x52,0x39,0x65,0xce,0xeb,0x9d,0xc7,0xab,0x02, + 0xe1,0x82,0xb2,0x6d,0x38,0xbf,0x77,0x54,0xed,0x9a,0xb1,0x87,0x5d,0x08,0xf5,0x7c, + 0xf9,0xed,0x01,0x80,0xa0,0xd4,0xf4,0xde,0xfc,0xd6,0xf4,0x99,0x7c,0x9c,0xc4,0xf0, + 0x44,0xb1,0x09,0x90,0xa1,0xd5,0x44,0x30,0x60,0xbb,0x1b,0x21,0x1e,0x57,0x8a,0xa7, + 0x26,0x75,0x9d,0x78,0x18,0xbf,0x3d,0x14,0x87,0xf2,0x9d,0x65,0x20,0x34,0x75,0x5a, + 0x4e,0x72,0x19,0xb0,0x68,0xbc,0x05,0x63,0x12,0xdc,0x3d,0x46,0x37,0xb3,0x1b,0x05, + 0x9b,0x22,0x9c,0x06,0x3c,0xa4,0x0a,0xdb,0x2e,0xf7,0x68,0x64,0xab,0xfb,0x76,0xd0, + 0xb5,0x9d,0xad,0xb0,0x04,0xa0,0x6c,0x7a,0x54,0x35,0x53,0x04,0x14,0x6b,0x3f,0xc1, + 0x15,0xcb,0x5d,0x2f,0x5a,0xf9,0x55,0xa0,0xc2,0x94,0xaf,0xe6,0x55,0xf0,0xae,0x95, + 0xc5,0xdb,0x15,0x3f,0x57,0x2a,0xd6,0xb4,0xe9,0x0b,0x85,0x75,0x2a,0x88,0x18,0xbf, + 0xa1,0x3e,0x12,0xf1,0x9f,0xcc,0x56,0xee,0x4d,0x55,0x8c,0x5d,0xaa,0x57,0xb8,0xab, + 0x8c,0x38,0x38,0x7c,0x91,0x14,0xb6,0x76,0xce,0xdf,0xc0,0x24,0x96,0x3c,0x28,0x4b, + 0xaf,0x37,0x07,0x81,0x30,0x17,0x4f,0x8c,0x4f,0xdc,0x50,0x5e,0x26,0xea,0x17,0x64, + 0xce,0xf6,0xbe,0x7d,0x49,0x8a,0xb7,0x6f,0x4e,0xdd,0xc1,0x88,0x96,0x5e,0xb6,0xc8, + 0x3c,0x61,0x1e,0xc6,0xbe,0xbe,0xb2,0x20,0xd5,0x83,0x49,0x0c,0xda,0x0d,0x15,0xfd, + 0x8e,0x22,0x02,0xa5,0xa1,0x36,0xbe,0xda,0x4b,0xc6,0x2a,0x2e,0xfe,0x45,0xa7,0x92, + 0xc0,0x93,0xbe,0xf8,0x1b,0xc1,0x29,0x09,0xea,0x43,0xcd,0x4a,0x3f,0x9d,0xc3,0xb4, + 0xa9,0x27,0xcf,0x35,0xce,0xa9,0xf9,0xa5,0x62,0xbd,0x00,0xd9,0xdd,0x72,0xd4,0x52, + 0x2e,0x8a,0xd0,0xfa,0x1c,0x8b,0x90,0xe7,0x64,0x2c,0xee,0x22,0xb1,0xe3,0xf1,0xf2, + 0x83,0xfd,0x48,0xe5,0xae,0x83,0x42,0xcf,0xaa,0x90,0x7c,0xca,0x32,0x41,0x39,0x5c, + 0x02,0xfe,0x7c,0x15,0xfb,0x5d,0x81,0xd0,0xb8,0x62,0x00,0xd6,0x5c,0xef,0x74,0x62, + 0x98,0x0c,0xd7,0xfa,0xc5,0x20,0x67,0x0c,0x43,0x84,0x7d,0x2b,0xed,0xcc,0x95,0x2f, + 0x6a,0x09,0xbe,0x42,0xf3,0xa7,0xd0,0xbc,0x44,0x5f,0x7c,0x26,0xd1,0xb0,0x36,0x56, + 0xe2,0x86,0x57,0xb4,0x73,0xd8,0x42,0x37,0x9d,0x4f,0xa6,0xe7,0x38,0xe3,0x57,0x23, + 0xe2,0x48,0xe1,0xb6,0x1e,0x2b,0x41,0x07,0x3d,0xeb,0x33,0x7a,0x1c,0xeb,0xbd,0xa2, + 0x0f,0x47,0x5a,0xab,0xcb,0x90,0xdf,0x8d,0x25,0xbc,0x59,0x2b,0x22,0xbb,0x62,0x57, + 0xbb,0xa5,0xfb,0xf7,0x73,0x57,0xb0,0x4a,0x23,0x47,0x81,0x5e,0xa3,0xc5,0xf0,0x6b, + 0x14,0x06,0xd4,0xf3,0x3b,0x2a,0x6c,0x37,0xe8,0xb8,0xa8,0xc3,0xa0,0x05,0x8a,0xeb, + 0x0a,0xf6,0xc0,0xfc,0x27,0x4a,0x94,0x1b,0x37,0x4c,0x8d,0xdc,0x7b,0x2a,0xbf,0x6a, + 0xd8,0x04,0xf2,0xe6,0x6d,0xf4,0x09,0xdb,0x22,0xda,0x7c,0x4e,0x7a,0xe2,0x02,0x2d, + 0xde,0xe4,0xc4,0x23,0x98,0x28,0x15,0xec,0x7b,0x2f,0x7d,0x17,0x87,0xb8,0x4c,0xb0, + 0x83,0xc0,0x08,0x23,0x96,0xab,0x4e,0x1e,0xb4,0xe0,0xbd,0x8d,0x89,0x2d,0xe4,0x01, + 0xaa,0xff,0xd5,0x2f,0xee,0x25,0x03,0x70,0xc0,0x55,0x30,0x72,0x04,0xc1,0x6b,0x51, + 0xb8,0x4b,0x1b,0x1d,0x99,0xd2,0x41,0x3e,0x15,0x45,0x70,0x13,0x0e,0x93,0x3c,0x7f, + 0xad,0xa6,0xf3,0x6c,0xd2,0x72,0x72,0x9c,0x63,0x90,0x93,0xa6,0xf3,0x31,0xcc,0xe9, + 0xf8,0x7f,0xc8,0x10,0x47,0x69,0x39,0x89,0x79,0x55,0x23,0xef,0x1a,0x7e,0xbe,0x1b, + 0xa3,0x30,0x56,0xfd,0x92,0xe2,0xb6,0x9d,0x3c,0xa3,0x38,0xde,0x6d,0xce,0xb2,0x03, + 0xb2,0xce,0x4d,0xe0,0xb0,0xce,0xa5,0xc2,0x99,0xcc,0x1d,0xce,0xf7,0x72,0x3e,0xa0, + 0x3c,0x9f,0xdc,0x60,0xbf,0xb2,0x44,0x41,0xc3,0x6d,0x63,0xc0,0xfd,0x76,0x90,0xb2, + 0xd4,0x28,0xcc,0xd6,0x73,0x88,0x5a,0x40,0x00,0xdb,0xb4,0xea,0xb5,0x81,0x0e,0xfc, + 0xa4,0x1c,0xc7,0x05,0xf2,0xad,0x0d,0xc4,0x5e,0xd5,0x62,0xe4,0x7f,0x7a,0x5f,0xd1, + 0x1c,0x9a,0xdf,0x2f,0x40,0xaa,0xc8,0x75,0xc3,0x55,0x3b,0x04,0x39,0x37,0x64,0x8c, + 0x29,0xb8,0x9c,0x8d,0x6d,0x31,0x28,0x94,0x97,0xc5,0x06,0x44,0x34,0xa4,0x9e,0x70, + 0xd7,0x54,0xc3,0x9b,0x3f,0x71,0xa9,0xb9,0xe4,0x55,0xf7,0x57,0x86,0x3b,0x17,0x04, + 0xac,0x74,0x81,0x70,0xb4,0x78,0xec,0x8d,0x67,0x58,0x3b,0x28,0x2d,0x18,0xf4,0x91, + 0x0c,0xe4,0x6d,0x19,0xc4,0x08,0x77,0xa7,0x1e,0xaf,0x8f,0x40,0x04,0x39,0x14,0x6c, + 0xb6,0x58,0x02,0x49,0x34,0xb6,0x6d,0x0a,0x6c,0x5d,0x88,0x7e,0x7e,0x80,0x08,0x91, + 0x73,0xed,0x08,0x26,0xb6,0xbb,0x66,0x17,0xe6,0xab,0xde,0xe3,0xa5,0xd6,0x39,0xce, + 0x5f,0x11,0x00,0x36,0x98,0x5d,0x86,0x8b,0x5d,0x3b,0xe8,0xb2,0x91,0xa8,0x6f,0x1f, + 0x8f,0x1c,0xc8,0x1d,0xb3,0xaf,0xe6,0x67,0xe8,0x6f,0xb8,0xf0,0x1a,0xd0,0x40,0x42, + 0xb9,0x0b,0x17,0xf9,0x97,0xae,0x60,0x3b,0x50,0xdb,0x90,0xcc,0x37,0xe4,0x57,0x90, + 0x04,0x7e,0x8f,0x60,0x34,0x99,0x06,0x0a,0x9b,0x6e,0xab,0x0f,0xbe,0xa5,0x25,0xe1, + 0xa6,0x7d,0x41,0x38,0xb0,0xb9,0x27,0x45,0x3b,0xae,0xd0,0xe7,0x86,0x4f,0x11,0x33, + 0x24,0xbc,0x45,0x85,0xd9,0xab,0x2a,0xda,0xcd,0xfe,0x83,0x86,0xe9,0x4c,0xda,0x05, + 0x35,0xa0,0x0c,0xd4,0x25,0xae,0xf6,0x9e,0xa0,0x3f,0x4d,0x39,0x82,0x21,0x10,0x60, + 0xfc,0x70,0x10,0xad,0x68,0x85,0xe8,0x39,0xba,0xf9,0xa6,0x44,0x53,0xa9,0x83,0xd3, + 0x4e,0x2f,0x60,0xaf,0xb2,0x5b,0xa5,0xe7,0xf7,0xa5,0x56,0x50,0x3d,0x43,0x73,0x40, + 0xee,0xbf,0x69,0x33,0xff,0x5c,0x23,0x8c,0x38,0x18,0x98,0x64,0xd6,0x73,0xfd,0x0a, + 0x28,0x93,0x22,0x9a,0x38,0x73,0x9e,0xb9,0x3c,0xc2,0x16,0x5c,0xd2,0x17,0x92,0xe1, + 0x8f,0x6e,0x31,0x2c,0x6a,0x8d,0xfa,0x52,0x4d,0xa5,0x1a,0x4c,0x3f,0xdf,0xd3,0x6d, + 0x7f,0x9a,0x87,0xf2,0x1d,0xe8,0x72,0x74,0x75,0x36,0xe9,0xaf,0xa4,0x45,0xd3,0x79, + 0x7a,0xee,0x74,0x5d,0x9b,0x83,0x84,0xa8,0xb1,0x16,0xc5,0x38,0x20,0xe4,0x5c,0x03, + 0x2f,0xdd,0xe0,0xca,0x05,0xc8,0x45,0x33,0xaf,0x53,0xd4,0x2f,0x86,0x47,0xca,0x28, + 0x65,0x65,0xb0,0xd2,0x6b,0xef,0x1c,0x23,0x4c,0xce,0xaa,0xe0,0xa4,0x16,0x5d,0x03, + 0xf6,0x21,0xc3,0xf0,0x7f,0x71,0x0d,0xdb,0x3f,0xa2,0x56,0x6a,0x59,0xf8,0x15,0x5c, + 0x2e,0xb0,0xe4,0x44,0x3e,0x10,0x21,0xe6,0xbf,0x8d,0xfb,0xbd,0x5c,0xa9,0x44,0x35, + 0x83,0x9d,0xf4,0xa7,0x36,0xb1,0xcb,0x53,0xdb,0xe3,0xa4,0x8c,0x72,0xf1,0xec,0xeb, + 0xfc,0xfd,0x2a,0x7e,0x06,0x7a,0xc1,0xa2,0x0e,0xae,0x10,0x33,0xa0,0x93,0x5e,0xa4, + 0x05,0x2d,0xb7,0x9e,0x96,0xc0,0x65,0x5d,0xe8,0x79,0xa3,0x4f,0xb8,0x2e,0x92,0x01, + 0xd5,0x4e,0xad,0x9f,0xd2,0x93,0xfd,0x42,0x5a,0x71,0xd4,0x5c,0x0a,0xb1,0x22,0xe3, + 0x51,0x53,0xdb,0xa6,0x3e,0x06,0xdf,0x8c,0xb3,0x28,0x97,0xb8,0xc3,0x28,0xd4,0xe2, + 0xd8,0xd3,0x69,0xa9,0xb8,0x23,0x53,0xea,0xe7,0x89,0x4e,0xe9,0x9b,0x5e,0xba,0x5a, + 0x95,0x04,0x5a,0x80,0x6c,0xbe,0xc8,0xbc,0x3f,0x4b,0x5a,0x88,0x2b,0x22,0xfa,0x57, + 0xf0,0xd5,0xa5,0xc3,0x37,0xa7,0xd2,0x88,0x3a,0x96,0xcb,0xf5,0x9c,0x72,0x44,0x8b, + 0x2f,0x68,0x0e,0xae,0x18,0xf6,0x68,0x45,0x3c,0xdb,0xa6,0xa0,0x81,0xf7,0x2a,0x5a, + 0x69,0x82,0xbc,0x65,0xb0,0xdb,0xff,0xa0,0x9a,0x6d,0x86,0x8e,0xed,0xbb,0x7e,0x67, + 0x49,0x1c,0xb7,0xab,0x55,0x13,0x4e,0x50,0x87,0xa5,0x88,0x9e,0x5d,0x5b,0xe3,0xfd, + 0x4f,0xbb,0xb9,0xfd,0xdd,0xdf,0xc0,0x4a,0x52,0xe8,0xaf,0x67,0xfb,0xf9,0x36,0xd3, + 0x44,0x47,0x59,0xb7,0x1f,0x3c,0x2f,0xce,0x0d,0xc4,0xf4,0xa8,0xec,0x58,0x2d,0xbc, + 0x4e,0xbd,0x41,0xa0,0xe2,0xfc,0x46,0x05,0x98,0x66,0xd9,0x0f,0xe3,0x3d,0x95,0x36, + 0x80,0x85,0x64,0x71,0xfe,0xb2,0x8f,0x69,0x6e,0xdf,0x27,0xf5,0x36,0x9d,0x7d,0x24, + 0x29,0x6e,0x03,0x5f,0x43,0x9f,0x7b,0x0b,0xcf,0x6e,0x17,0x75,0xdd,0x29,0x7f,0xfd, + 0x00,0x0e,0xe0,0x40,0x2d,0x2f,0xcd,0x46,0xb3,0x50,0x5a,0xdf,0x23,0x60,0x58,0x19, + 0x08,0x07,0x77,0x53,0xd3,0x11,0xab,0x50,0x47,0x8b,0x25,0x6b,0x57,0xd1,0x69,0x87, + 0x7c,0x43,0xe1,0x07,0x58,0x2f,0xa9,0xda,0x3c,0x6b,0x3a,0x4b,0x05,0x9e,0xfb,0x08, + 0x20,0xbc,0x81,0x01,0x6c,0x4d,0x39,0x2f,0xe0,0xb7,0xf7,0x6a,0x28,0x9f,0xbf,0x2e, + 0x74,0xdb,0x0c,0x22,0x33,0xa4,0xfc,0x44,0xc5,0x94,0x70,0x16,0x30,0x60,0xe4,0xcb, + 0xd6,0x0f,0x91,0x77,0xb6,0xa9,0x60,0x8f,0x59,0x28,0xc0,0x70,0xde,0x24,0x81,0x91, + 0x26,0xf9,0xfb,0xad,0x2a,0x69,0x0c,0x32,0x6f,0xe7,0xaf,0x62,0x73,0xbf,0x4b,0x2e, + 0x56,0x03,0x83,0x48,0x6c,0x3c,0x99,0xcd,0xab,0x4a,0x66,0x95,0x72,0xbc,0x1a,0xa4, + 0x3b,0x8a,0xe0,0xe6,0x19,0xe8,0x0e,0x0c,0xc7,0x4a,0x2d,0xeb,0x92,0x22,0xad,0xfa, + 0xe9,0xad,0x1d,0xfe,0x3d,0x65,0x72,0x47,0x29,0x09,0x0a,0x43,0xd4,0xcf,0xbb,0xf6, + 0x61,0xc0,0xe3,0x49,0xa5,0x27,0xa4,0x28,0x45,0x46,0x9b,0x28,0x04,0x20,0x73,0x34, + 0x62,0x9a,0xe5,0x77,0xbb,0xc6,0x65,0xae,0x28,0x98,0xd7,0xfd,0xdd,0x9f,0xc2,0x33, + 0xdf,0xf0,0xf7,0x2a,0x97,0xda,0x2c,0x15,0xe6,0x41,0xf2,0x91,0x78,0xd7,0x5c,0x95, + 0xe0,0x77,0x72,0xa3,0x28,0x18,0xd6,0x88,0xb4,0x42,0xd2,0x03,0x0e,0x64,0xf8,0x16, + 0x63,0x8d,0x8b,0x54,0xa9,0x7a,0x2d,0x89,0x48,0x4a,0xd1,0x97,0xdc,0x87,0x75,0xe8, + 0xe3,0x95,0x73,0x60,0x3c,0xa2,0x3b,0x7b,0x82,0x42,0x5b,0x3a,0xff,0x01,0x6e,0xaf, + 0x50,0x45,0xbe,0x0a,0x87,0xbd,0x26,0xa4,0xe5,0x46,0xea,0xa2,0x91,0xf3,0xaa,0x14, + 0x00,0x57,0xf5,0x96,0x3d,0x73,0x42,0xbf,0x65,0x1f,0x84,0xa5,0x8d,0x90,0x90,0x78, + 0x21,0x89,0xe0,0x6e,0x51,0x24,0xb4,0xbb,0x7c,0xe6,0x72,0x56,0x7c,0x7f,0x9d,0x13, + 0x21,0xab,0x0a,0xe1,0x93,0x9d,0x7c,0x11,0x37,0xec,0x5d,0xd9,0x4e,0xd3,0x40,0x22, + 0xa0,0x5c,0x6f,0x9b,0xcb,0xc8,0xed,0xbe,0xbf,0x29,0xf3,0x15,0xee,0x66,0xc4,0xb9, + 0x80,0x70,0x92,0xe7,0x3f,0x9e,0xea,0x03,0x8b,0xfe,0xa3,0xbe,0xce,0x69,0x5e,0xb3, + 0x01,0x10,0x66,0xf3,0x6e,0xd3,0xfa,0xff,0x06,0xa2,0x3d,0x6f,0xd0,0xa0,0x35,0x53, + 0xa6,0x7d,0xff,0xd4,0x36,0x21,0x6f,0xf5,0x66,0x41,0x6f,0x47,0xe3,0xb2,0x3e,0xda, + 0x6b,0x78,0x81,0xfe,0xb5,0xce,0xc9,0xa8,0xeb,0x56,0x00,0xae,0xd1,0x7e,0x4c,0x1a, + 0xc7,0x54,0xb4,0x07,0xc2,0xb4,0xa1,0xe3,0x90,0xd3,0xe6,0x54,0x46,0xb4,0xeb,0x1b, + 0xac,0x10,0x78,0xff,0x6e,0xe5,0xf7,0x96,0xcc,0xe6,0x65,0x25,0x9b,0x85,0x55,0x0c, + 0x0a,0x7e,0xec,0x67,0x9d,0x47,0x9b,0x48,0x4a,0x59,0x87,0xac,0x10,0xa1,0x7e,0x18, + 0xdd,0x13,0x67,0xd6,0xa6,0x88,0x70,0x51,0xba,0xf8,0xa0,0xc6,0x08,0xb9,0xe1,0xa6, + 0xf6,0x5f,0xaf,0x7c,0xed,0x82,0xda,0x3e,0xf9,0x5e,0x01,0xfc,0xf8,0x73,0x7f,0x19, + 0x51,0x11,0x99,0xc2,0xbe,0x70,0x84,0xf2,0x81,0x2a,0xe4,0xe5,0x1e,0xcb,0x57,0x0e, + 0x29,0x17,0x10,0xdd,0x38,0x31,0xbc,0x02,0x94,0x5f,0x3f,0xc2,0xdf,0x11,0xf9,0x9d, + 0x3b,0x0e,0x27,0xa0,0xdf,0x2d,0x4e,0xb4,0x2f,0x66,0xfc,0x02,0x23,0xe0,0xfc,0xef, + 0x84,0x5a,0x49,0xf8,0xf4,0x97,0x02,0xc1,0x93,0x6e,0x65,0x37,0x62,0xe4,0x07,0x2e, + 0xa2,0x2d,0x0d,0x88,0x2b,0x2f,0xb1,0xd2,0x06,0x42,0x6e,0x3a,0xaf,0xe2,0x8f,0x97, + 0xda,0xcf,0xd4,0x65,0x07,0xbc,0xde,0xc2,0x1f,0xd3,0xe4,0xde,0xd3,0xe1,0x1e,0x9a, + 0x02,0xfe,0xb9,0x7c,0xb1,0xe5,0x3a,0x1d,0xe5,0xaa,0x60,0xa1,0x54,0x11,0xd7,0xc2, + 0x26,0xb5,0x44,0x14,0x94,0x71,0x7c,0x35,0xc6,0xcb,0x5b,0xe0,0x8b,0x03,0xc2,0x1d, + 0x7f,0x5a,0x0d,0xc7,0x6a,0x86,0xe1,0xa4,0xc4,0x33,0xf5,0x20,0x57,0xe8,0x6b,0xb3, + 0xed,0x81,0x0b,0x48,0x59,0x2a,0xda,0xe5,0x1b,0x21,0xc3,0x84,0x1d,0x4c,0xf9,0x95, + 0x73,0x06,0x99,0xae,0xf1,0x4a,0x4c,0xb0,0x99,0x55,0x81,0x5c,0xb7,0x09,0x75,0x0f, + 0x0b,0xb0,0xe6,0x9a,0x41,0x60,0x99,0x0c,0x91,0x2c,0x67,0xa8,0x5e,0x0b,0x96,0x33, + 0x38,0xfb,0x53,0xdc,0x9a,0x83,0x98,0x74,0x35,0x36,0x8d,0x1a,0x51,0xf1,0x8e,0xe7, + 0x53,0x70,0x91,0x58,0x03,0xd4,0x65,0x08,0xc9,0x60,0xe1,0x58,0xb5,0x0a,0x6a,0xef, + 0xef,0x83,0x9c,0xdd,0x75,0x2a,0x48,0x99,0x84,0x67,0x90,0x6a,0xb5,0x29,0x52,0x8a, + 0xd0,0x82,0x0d,0xaf,0xc5,0xbd,0x5d,0xe5,0x24,0x7b,0xfb,0x8d,0xbf,0xa1,0xf3,0xc9, + 0x8b,0xe4,0x63,0xbc,0x48,0x01,0x11,0x6f,0x1e,0x18,0x8d,0x58,0xb5,0x4b,0x0b,0x1f, + 0xa0,0x04,0x95,0xc5,0x4a,0x32,0x7a,0x88,0x1d,0x13,0x9a,0x65,0x0f,0x5b,0x7e,0x0b, + 0x87,0xf5,0x1b,0xc9,0xa1,0x6d,0x06,0x5d,0xe6,0x98,0x18,0x23,0xd7,0xb1,0xda,0x71, + 0x46,0x13,0xf7,0x96,0x33,0x01,0x04,0x62,0xb8,0xae,0x19,0x07,0x8d,0x6b,0x7f,0x1b, + 0x07,0x94,0x0c,0xf4,0xf3,0x0d,0x15,0xc1,0x53,0xb7,0x12,0x02,0x2c,0x71,0x55,0x7b, + 0x9e,0xde,0xc3,0xe8,0x3a,0x15,0x84,0xe2,0x46,0x0c,0x0a,0x7a,0xf3,0xd8,0xb0,0x32, + 0x2e,0x9b,0x04,0xf9,0x12,0xb2,0x1c,0x20,0xe0,0x21,0xb4,0xd9,0x7e,0x98,0x30,0x89, + 0xda,0x1c,0x5d,0xb6,0x33,0xd9,0x25,0xe4,0xc2,0xdc,0x5b,0x61,0x96,0x5a,0xf5,0xdc, + 0x9a,0xd4,0xc5,0x77,0x17,0x3f,0xe5,0x43,0x8c,0xa5,0xdd,0x25,0x22,0x30,0x69,0x8f, + 0x86,0xd5,0x7d,0x2a,0xa7,0x45,0xfb,0x1b,0x8c,0x9a,0x9b,0x06,0x35,0xb7,0x5d,0x82, + 0x89,0x27,0xec,0xce,0x7c,0x4c,0x8b,0xf7,0x93,0xde,0x7b,0x2a,0x3f,0xbd,0xee,0x4e, + 0xad,0x4d,0x02,0x0d,0x32,0xb3,0x8a,0xc5,0xce,0x64,0x6a,0x51,0x53,0x5f,0x90,0x56, + 0x58,0x40,0xed,0x8d,0xac,0x47,0xbf,0xa9,0x19,0xd5,0x1b,0x2a,0x07,0x57,0xe4,0x84, + 0xf2,0x80,0x2f,0x80,0xb2,0x16,0xfb,0x3e,0xae,0x28,0x87,0x51,0x40,0x0a,0x58,0xe7, + 0x0f,0x3c,0xbc,0x66,0x42,0x13,0x7c,0xee,0xc9,0x9d,0x88,0x70,0x95,0x0a,0xca,0x9c, + 0x7b,0x10,0x90,0xd9,0x9e,0x62,0x01,0x1c,0x5c,0x86,0x9d,0xa0,0x8e,0x21,0xb8,0xcf, + 0xa8,0xa4,0x47,0xbd,0xdc,0xba,0x2e,0x1a,0x4b,0x54,0xa9,0x74,0xee,0x51,0x11,0xa6, + 0x44,0x94,0xb5,0x7f,0xc3,0x10,0xc5,0x1b,0xa7,0xc4,0x50,0x84,0x22,0x2b,0xb2,0x1f, + 0xec,0xaf,0xbf,0x81,0xeb,0xbd,0xcb,0x20,0x3f,0xd2,0x02,0x00,0xdf,0x62,0xa0,0x9a, + 0x95,0x95,0x18,0x4b,0xe8,0xdd,0xa9,0x56,0xa3,0x51,0xf0,0x2a,0x68,0x95,0x37,0xf0, + 0x60,0x42,0x99,0x00,0xef,0xdd,0xd1,0x38,0x00,0x59,0x26,0x24,0x5d,0x6e,0xac,0x0a, + 0xea,0x77,0x19,0xd2,0x93,0xd6,0x9d,0xf7,0xa3,0x02,0x00,0xb1,0xa8,0xfb,0x38,0x59, + 0xf8,0x54,0x3b,0x46,0x56,0xf8,0x68,0x8f,0xbf,0xe5,0x92,0x04,0x7a,0xe5,0x92,0x69, + 0x05,0x2f,0x67,0x70,0xc7,0xa6,0xe1,0x92,0xef,0x38,0x42,0xee,0xd3,0x17,0x3d,0x33, + 0x79,0x8d,0xfa,0x1b,0x4f,0x9b,0x69,0xe5,0xea,0xc2,0xd3,0x85,0xf2,0x24,0x9b,0x33, + 0x70,0xac,0x6e,0xe4,0x7a,0xed,0x21,0x81,0xf8,0xf6,0xc9,0x51,0xc1,0x25,0x82,0xce, + 0x9a,0x0b,0x86,0x4b,0x99,0x26,0x4b,0x06,0xed,0xc8,0x2d,0x4c,0xef,0xcc,0x62,0xda, + 0x8f,0xfc,0xac,0x1b,0xdf,0x8d,0x40,0xe9,0x71,0x56,0x3e,0x5e,0x7a,0x09,0xe0,0xf2, + 0xf7,0x0a,0x24,0x0b,0x4c,0x4e,0xeb,0x0d,0x29,0x75,0x0a,0x2b,0x10,0x53,0x9b,0x02, + 0xb1,0xf6,0x2b,0x8a,0x60,0xa7,0xa3,0x59,0xbd,0x09,0x77,0x3f,0xd1,0x07,0x3a,0x5d, + 0xea,0xd9,0xe5,0xae,0xfa,0x8d,0x92,0x48,0x60,0x41,0xcd,0x46,0xda,0x0e,0xe6,0xdd, + 0xde,0x6f,0x1e,0xa2,0xe6,0xac,0x23,0x06,0xec,0x0c,0x1e,0x57,0x5d,0xd7,0x3b,0xa1, + 0x86,0xd2,0xfb,0xb2,0x73,0x21,0xa8,0x99,0x81,0xbf,0x83,0x49,0xd8,0x2c,0x22,0xb2, + 0x74,0x84,0xda,0xae,0xf5,0xf2,0xf3,0x5d,0x4e,0xae,0x4d,0x7f,0xcb,0x2d,0x56,0x33, + 0x26,0x11,0xfb,0x79,0x30,0x3e,0xb4,0x9b,0xe4,0xcf,0xaf,0x63,0xba,0xfa,0x37,0x72, + 0x8d,0xac,0x4c,0xb4,0x23,0x2a,0x96,0x72,0x67,0xb9,0x56,0x56,0x91,0x2a,0x2c,0x05, + 0x88,0x96,0xed,0x03,0x4c,0x73,0xd5,0x68,0x84,0x10,0xdd,0x9c,0x01,0xd6,0x75,0x61, + 0x3d,0xe2,0x0b,0xcb,0x3c,0x51,0x9f,0xb8,0x5b,0xa3,0x9d,0x84,0xfa,0x8c,0x18,0xc5, + 0xf3,0xe9,0x28,0x44,0xce,0x14,0x6a,0x34,0x02,0x8b,0xe2,0xec,0x99,0xf1,0x8c,0xf1, + 0x75,0x18,0x2e,0xcb,0xfd,0x9e,0x24,0xc2,0x9c,0x4e,0x73,0x07,0xa3,0x81,0x6e,0x31, + 0x40,0xc7,0x69,0x87,0x31,0xe2,0xaa,0x92,0xa9,0xa2,0x7d,0x6f,0x2f,0xcb,0xb2,0x21, + 0x6f,0xc6,0xab,0xd1,0xd8,0xb1,0x77,0x82,0x40,0x18,0xfa,0x04,0x6f,0x65,0x7f,0xee, + 0xdf,0x93,0x2d,0x09,0xab,0x07,0xb8,0x8c,0x1f,0x58,0x2f,0x1d,0xdb,0xa7,0xf6,0xbc, + 0x0b,0xba,0x4e,0xbc,0xbd,0x34,0xa5,0x08,0x99,0x86,0xf8,0x78,0x7a,0xfb,0x49,0xb4, + 0x1b,0xc7,0x78,0x7d,0x8b,0xab,0x4d,0x58,0x94,0xa5,0x22,0x6c,0x45,0x14,0x5e,0xb9, + 0xcb,0xb8,0xf0,0x19,0x92,0x5b,0xb8,0xbf,0x02,0x3f,0xc5,0x95,0x85,0xd4,0x86,0xe8, + 0xf2,0x5e,0x46,0xbe,0xd1,0xf9,0x57,0x97,0xcd,0x1d,0x3e,0x66,0x58,0xaa,0x36,0xa2, + 0xc0,0x12,0x4f,0x2f,0xdb,0x71,0x64,0x40,0x80,0x39,0x29,0x3e,0xf8,0x3b,0x53,0xc8, + 0x15,0x4b,0xb9,0xfa,0xd1,0x9b,0xea,0xd0,0x01,0x1a,0xa8,0xd3,0x0c,0x8b,0x7d,0xf4, + 0x54,0xb2,0xae,0xc7,0x6b,0x8b,0xb3,0x86,0x21,0x1b,0x68,0xd9,0x98,0x64,0x7e,0xe0, + 0x40,0x05,0xea,0xe4,0x55,0xe0,0xba,0x3d,0x42,0x08,0x50,0x92,0x76,0x23,0x12,0xa2, + 0xe7,0xc3,0x28,0x08,0xf1,0x55,0xf8,0xfb,0x21,0xfc,0x9e,0x5f,0xd9,0x6a,0x33,0xc4, + 0x6f,0xc6,0xdf,0x94,0xff,0x24,0x6f,0x18,0x40,0x5d,0xb4,0x34,0xe1,0xa6,0x39,0x59, + 0x83,0xa2,0x1f,0xe6,0x7d,0xe3,0x2f,0x51,0xa5,0x50,0xbd,0xd5,0xd3,0xc8,0xba,0x7b, + 0x00,0xae,0xb2,0x70,0xfd,0x67,0xd8,0x56,0xc3,0x65,0xeb,0x12,0xd6,0x84,0x1f,0xc4, + 0xd4,0xc4,0x48,0xa6,0x9f,0x76,0xd2,0x94,0x74,0xc2,0xf8,0x52,0xd8,0xe7,0xb3,0x3c, + 0x25,0x36,0xbb,0x05,0xea,0x09,0xb1,0xdf,0x26,0xdd,0x31,0x87,0xa7,0x1d,0xc2,0x2c, + 0x52,0x0c,0x5e,0x51,0x60,0x0c,0x23,0x77,0x60,0xd7,0x4e,0x76,0x5a,0xeb,0xfb,0x70, + 0xaf,0xed,0xfc,0x3c,0x18,0xe4,0x4c,0x2c,0xad,0x4b,0x8e,0x08,0x3a,0x65,0x52,0x0e, + 0xed,0x08,0x8d,0xef,0x81,0xbb,0xfa,0x6e,0xce,0x8b,0x5a,0x01,0x79,0x55,0x1c,0xe9, + 0x71,0x21,0xc2,0x01,0x4c,0xde,0xc7,0xaf,0x81,0x0a,0x67,0xd0,0x5f,0xe4,0x3c,0xe8, + 0x09,0x06,0x43,0x95,0xbf,0x7d,0xb1,0xb0,0xcb,0x03,0x04,0x64,0x2d,0x81,0x54,0x76, + 0x08,0xad,0xea,0x4e,0xd6,0x66,0x28,0xa2,0xe9,0x41,0x9a,0x70,0x98,0x18,0x33,0x66, + 0x09,0x8c,0xb8,0x65,0x71,0x38,0xa1,0x0c,0x7c,0x19,0xa4,0xec,0x1f,0x42,0xa1,0x29, + 0x71,0x05,0xef,0x60,0xf4,0xfb,0x2a,0x64,0x29,0xd5,0x15,0x1d,0x35,0x48,0xcb,0x39, + 0x74,0xcd,0x39,0x5b,0xc0,0x34,0x81,0xff,0xb2,0xfc,0x49,0x8c,0x33,0x44,0xe4,0xdb, + 0x41,0x2f,0x0d,0xf9,0xa1,0xf2,0x0c,0xe5,0x6a,0x6f,0x14,0x56,0xcc,0x23,0x01,0xe9, + 0xbc,0xea,0xba,0x7e,0x79,0x6d,0x06,0x17,0x96,0x25,0x39,0xab,0x8b,0xf1,0x9e,0x33, + 0x68,0xcd,0xb5,0x46,0xb2,0xb3,0x81,0xc1,0x9c,0x6d,0xcb,0xa0,0x0d,0xfd,0x29,0xf8, + 0x24,0x9e,0x01,0x12,0x60,0xd1,0x9d,0xad,0x69,0xb6,0xb9,0xab,0x75,0x3e,0x1c,0x6e, + 0xd1,0xd5,0xc3,0x37,0xaa,0xa6,0xcf,0x71,0xea,0xdc,0x63,0x62,0x56,0xb0,0x54,0x3c, + 0x8b,0x98,0x93,0xe9,0xc9,0x60,0x1b,0x0d,0x92,0x53,0x6b,0x72,0x5f,0x37,0x5a,0x47, + 0x86,0x89,0x0d,0x4d,0x94,0x60,0xf0,0x8c,0x1d,0x2b,0xcd,0x19,0x95,0x53,0x90,0xac, + 0xcf,0x9a,0x1e,0xec,0x4d,0x22,0x7d,0x0d,0x67,0xe5,0x46,0x15,0x94,0x13,0x7c,0xc8, + 0x50,0xa7,0xcf,0x65,0xc3,0x33,0x82,0xc8,0xe1,0xba,0xb5,0xac,0xa5,0xb9,0x13,0xd0, + 0xde,0x22,0x89,0x1a,0x15,0x99,0x85,0x02,0xb4,0x24,0xa9,0x3a,0x76,0xb1,0x7d,0x88, + 0xda,0x86,0x01,0xb7,0xba,0xbb,0xec,0xab,0x94,0x25,0x8d,0x54,0x9f,0xb0,0x2b,0x59, + 0x0c,0xa4,0xd0,0xf1,0xbb,0x9a,0x10,0xfc,0xe3,0x44,0x87,0x40,0x70,0x99,0xa6,0xeb, + 0x19,0xc1,0x95,0x0c,0xbd,0xfa,0xcb,0xd7,0x85,0x98,0x61,0x6a,0x5e,0x48,0x7e,0xf0, + 0x29,0x9f,0xf6,0x5a,0x7d,0xb4,0xfd,0x3a,0x7f,0xa0,0x69,0x7a,0x57,0x2f,0x1f,0xec, + 0x13,0xdc,0x50,0xeb,0x43,0x3c,0x4d,0x57,0xe8,0x36,0xcf,0x11,0x9d,0x79,0x5f,0xb9, + 0x18,0xfa,0x29,0x4f,0x9e,0x4d,0xe8,0x04,0x0e,0x0c,0x44,0x1d,0xdb,0xff,0xad,0x7f, + 0x9d,0x42,0xce,0x2e,0x92,0x24,0x62,0x21,0x18,0xbb,0xf1,0x84,0x86,0xdf,0xa1,0x7e, + 0x6a,0x22,0x90,0x11,0x72,0xde,0x83,0x3b,0xc3,0x49,0x78,0x0b,0x75,0x0f,0x1b,0xc7, + 0x15,0xff,0x89,0x67,0xf1,0x77,0x31,0xdd,0xc4,0x00,0x4e,0x25,0x53,0x6c,0x09,0xe2, + 0xa3,0x00,0xf1,0x97,0x19,0x72,0xef,0xc1,0xc9,0x4c,0xd9,0x0a,0xd9,0x0f,0x80,0xb0, + 0x05,0xb5,0xfe,0xe0,0x14,0x25,0x30,0x3f,0xf5,0xf9,0xcb,0xec,0xf7,0xe2,0x33,0x17, + 0xdd,0x0f,0x7c,0x27,0x4c,0x2a,0xe5,0x92,0xc1,0xb9,0x18,0x95,0x8a,0x98,0x81,0x80, + 0x87,0x0b,0xb8,0x36,0xc5,0x29,0x29,0xe3,0x1f,0x79,0xd5,0x25,0xda,0x27,0xcb,0x0e, + 0x72,0xfb,0xf7,0xf1,0x95,0x06,0x20,0x02,0xd6,0x48,0xc3,0x74,0x86,0x6e,0x05,0x90, + 0x3b,0xa9,0xba,0xbe,0x10,0xaa,0x4b,0xac,0xa1,0x39,0xba,0xee,0xa1,0xe4,0x10,0xde, + 0xd0,0xf4,0xf2,0x98,0x3b,0x9c,0xdd,0x5a,0x0a,0x96,0xe4,0xaf,0x32,0xdf,0xbb,0x24, + 0x77,0x48,0xb9,0x8f,0x10,0x7b,0xeb,0x0d,0x4a,0x49,0xd9,0xcf,0x99,0x7a,0x24,0x77, + 0x06,0xbd,0xd3,0x18,0x9d,0x3b,0x63,0xbb,0xcc,0x81,0x9a,0x23,0x3d,0x9f,0xe9,0x33, + 0xdf,0xbc,0x1e,0xc8,0x18,0x29,0x32,0x28,0xf7,0xc7,0x52,0x2b,0x7e,0x2e,0xe5,0x7c, + 0x89,0xf1,0xf4,0x3d,0xb8,0xa6,0x25,0xfa,0x4a,0xb2,0x62,0x01,0x78,0x0d,0x63,0x87, + 0x57,0xd3,0xfd,0x2d,0x39,0x4b,0x57,0x8b,0xe8,0xb1,0x8f,0x18,0xe9,0x9e,0x31,0xa9, + 0x83,0x00,0x96,0x6c,0xbd,0x6d,0x63,0x59,0x6a,0x70,0x9a,0x1b,0xae,0x66,0xa0,0x82, + 0x74,0xbd,0xe4,0x86,0x56,0x3f,0x54,0xdd,0x2a,0xfa,0x9e,0xa0,0xd3,0x76,0xb3,0xa1, + 0x40,0xbe,0xac,0x7d,0x13,0x4a,0x1d,0x32,0x64,0xab,0xe4,0x36,0x53,0x83,0x1f,0x05, + 0xa3,0x12,0x31,0xfa,0x13,0x69,0x5b,0x70,0xc4,0x1c,0xc5,0x3c,0x93,0x52,0xad,0xe3, + 0xd7,0xbc,0x89,0x7d,0x83,0xa8,0x47,0xb4,0x42,0x11,0xa5,0xe5,0xf9,0x7c,0xbb,0xa2, + 0x02,0x19,0xbc,0x46,0xdc,0x9b,0x55,0x92,0xe0,0x70,0x88,0x01,0x74,0xae,0x1c,0x5d, + 0x17,0xb8,0xcc,0xd4,0x33,0xb8,0x5c,0x0d,0x6b,0x17,0x2c,0xe1,0x3b,0xfc,0x38,0x3c, + 0xa2,0x57,0x05,0x45,0xcf,0x36,0xc4,0x03,0xe6,0x46,0x1a,0x61,0xd1,0xe2,0x01,0x16, + 0x61,0x17,0xad,0x62,0x50,0x38,0x10,0xf6,0x63,0x69,0x4d,0xae,0x0e,0xcb,0xa2,0xea, + 0xd7,0x7b,0xa6,0x75,0x30,0xe3,0x46,0x77,0xcd,0x87,0xf6,0x0c,0x2e,0xf5,0x99,0x67, + 0xdc,0x9a,0x89,0x8e,0xb6,0x3b,0x05,0x83,0x5a,0xfb,0xc4,0xb9,0xda,0xf4,0x61,0xeb, + 0x5f,0x97,0x87,0x70,0xa8,0x7a,0x16,0xcf,0x17,0x18,0xef,0x2f,0xfd,0xb0,0xdf,0x86, + 0x2d,0xb4,0x38,0x9c,0x34,0x37,0xa7,0x3b,0xcb,0x6b,0x60,0x39,0xd2,0x98,0x4e,0xcc, + 0x60,0x36,0x56,0x8e,0x9b,0x30,0x0f,0xfa,0x8f,0xa3,0xfd,0x92,0xab,0x3e,0x70,0x1c, + 0xa6,0xeb,0x6e,0x9e,0xb8,0x96,0xcd,0x7c,0x60,0x2f,0x73,0xb2,0x8e,0x21,0x79,0x1d, + 0xe8,0xe1,0xbf,0x8f,0x36,0x32,0x6d,0x17,0x89,0x8e,0x48,0xaf,0x67,0x83,0x07,0xdd, + 0xe3,0x55,0xa7,0x55,0xbd,0x3f,0xe0,0x1b,0x88,0x15,0x1f,0x80,0x7a,0x13,0x28,0x07, + 0xb1,0x84,0xa0,0xfb,0x1c,0xe2,0x0a,0xc0,0xc6,0xc3,0x06,0xd7,0xbc,0xa4,0x07,0xe1, + 0x27,0x3c,0x38,0x94,0x95,0x22,0x40,0xb0,0x67,0x73,0xd9,0x38,0x85,0x95,0x23,0x78, + 0x5d,0xdf,0xec,0x00,0x14,0x3f,0xf6,0x41,0x87,0x7d,0xef,0x15,0x94,0xae,0x57,0xb2, + 0x71,0x80,0xf3,0x39,0x36,0x78,0x03,0xd1,0x47,0xc7,0x9e,0xc6,0x49,0x71,0x00,0x1d, + 0xb9,0x79,0xf0,0xe7,0xff,0x1e,0xaf,0x62,0x62,0xc2,0x70,0x21,0x72,0x8a,0x57,0xb0, + 0x85,0x79,0x37,0x14,0x11,0x8d,0x00,0xf6,0x65,0x70,0x9e,0x07,0x54,0x37,0x19,0xc1, + 0x5b,0xd9,0x99,0x63,0xe1,0x82,0x51,0x23,0xa5,0x39,0x61,0x14,0xb7,0x8a,0x14,0x3c, + 0x24,0x81,0x9e,0xbf,0x75,0x7a,0x21,0xfe,0x45,0xc3,0x39,0x0a,0xe6,0xe4,0x95,0xab, + 0x28,0x25,0x82,0xf3,0x3e,0x13,0x2d,0x48,0xce,0xcb,0x5a,0xa4,0x7e,0x3e,0x3a,0x7c, + 0x0b,0x83,0x34,0x5e,0x90,0x24,0x65,0xca,0x49,0xc6,0xd2,0xb8,0xa1,0xa8,0x39,0xeb, + 0xdc,0x91,0x27,0xf7,0x9c,0xe8,0xf6,0xc9,0x4e,0x82,0xcc,0xd2,0xdc,0xe4,0x2b,0x04, + 0x09,0x5f,0x4c,0xe0,0x7c,0x7d,0x5b,0x9f,0x8c,0x89,0xdb,0x9f,0x83,0xe6,0xcd,0xa0, + 0xe7,0xd4,0x1a,0x46,0xe3,0xe3,0x6c,0x08,0x6f,0x6e,0x73,0x7f,0x7c,0xce,0x30,0x5b, + 0xac,0x8e,0xf1,0xdc,0xf1,0xe2,0x60,0x7b,0x6e,0x6d,0xbe,0x6f,0x59,0xc6,0x1b,0xc9, + 0x8f,0xf3,0xba,0xf0,0x98,0x7d,0x13,0x68,0xfa,0xc3,0xf5,0x6d,0xce,0xed,0x94,0xa0, + 0x0d,0x87,0x50,0xbd,0x33,0x52,0xbb,0x16,0xf0,0xc5,0x20,0x7d,0xd3,0xad,0x80,0x72, + 0x20,0x9f,0xcc,0x77,0xf2,0xb0,0x4c,0x20,0x46,0x60,0x6b,0xf6,0xf6,0x57,0xec,0xf4, + 0x4c,0xe0,0x29,0xe4,0xde,0x37,0x44,0xb0,0x69,0x5a,0x53,0x4c,0x51,0x0a,0xb5,0x9c, + 0x98,0x89,0x82,0x10,0xdf,0x14,0x65,0xba,0xa4,0x5f,0x98,0xd5,0x57,0x97,0x35,0xa6, + 0x4c,0xe2,0x0e,0xa1,0x69,0x56,0x39,0x51,0xe3,0x39,0x42,0xc5,0x02,0x4c,0x5a,0x07, + 0xa9,0x12,0x24,0x42,0x1d,0x32,0xe7,0x66,0x6d,0x9c,0x4b,0x69,0x89,0x29,0xa0,0xa1, + 0x6c,0x17,0x94,0x54,0x3e,0xd1,0xeb,0x0d,0x33,0x02,0x9b,0x88,0xa5,0xfd,0x65,0x83, + 0xa2,0x34,0x85,0x87,0x18,0x3b,0x4f,0x01,0x85,0x26,0x14,0x19,0x7b,0x0b,0x92,0xa0, + 0xe4,0xfb,0xd5,0x87,0xbf,0xb8,0xfc,0x99,0x90,0x42,0x79,0x30,0x77,0xd7,0x7e,0x92, + 0x1f,0xea,0xf8,0xbd,0x30,0x13,0x47,0x28,0x69,0xbc,0xd6,0x18,0xb8,0xf5,0x1c,0x65, + 0xd9,0x96,0x0f,0x84,0xa1,0x0d,0x5e,0xb8,0x6c,0xd4,0xf6,0x26,0xff,0x3e,0x9f,0x7a, + 0x0f,0x69,0x95,0x8e,0x39,0xac,0x6d,0xbb,0x4f,0x9b,0xcc,0xd4,0x71,0x6c,0x0f,0x92, + 0x44,0xea,0xf1,0x90,0xaf,0xf5,0x45,0xdb,0xb9,0x99,0xfc,0xdd,0x84,0xf2,0x81,0x0a, + 0x2a,0x3c,0x8e,0x0c,0xbd,0xf8,0xa9,0x1e,0x51,0x1a,0x5a,0x2e,0xc7,0xbd,0x14,0xa8, + 0x8c,0x9b,0x86,0xbc,0x19,0xd3,0xfe,0x93,0x78,0x29,0xd2,0x7b,0xf6,0x9d,0x2d,0xef, + 0x2c,0x62,0x8f,0xc8,0x3d,0xb1,0xae,0xeb,0x0f,0x61,0xdb,0xfa,0x77,0xae,0xc0,0x34, + 0x52,0x90,0xb6,0x8c,0x1a,0x39,0xaf,0x7f,0x97,0x76,0xd3,0xe7,0x77,0xdd,0x00,0x43, + 0x04,0x24,0x20,0x77,0xb3,0xa3,0xd0,0x9c,0x88,0xc8,0x96,0x11,0xb9,0x81,0x08,0x54, + 0xef,0x9e,0xf0,0x33,0xec,0x2e,0x60,0x14,0xc3,0x65,0xa6,0x10,0x57,0xd9,0x5f,0x01, + 0x08,0x68,0xb7,0xf6,0x1c,0xff,0x19,0xc3,0x81,0x46,0x3d,0xb7,0x8c,0x6a,0x09,0x11, + 0x84,0xe4,0x19,0xe9,0x75,0xd8,0x92,0x53,0x80,0x47,0xae,0xdd,0x0f,0x2e,0xa8,0x7d, + 0xe9,0x40,0x95,0xe5,0x30,0xde,0x30,0x20,0xe0,0x99,0xc9,0xc2,0x1e,0xc9,0xec,0x32, + 0xf4,0x8e,0xc8,0xd6,0x1a,0x98,0xc8,0xf2,0x42,0xa2,0xc2,0x8b,0x55,0x5c,0x7b,0xf1, + 0x2c,0xa9,0x95,0xe5,0xb8,0x25,0x29,0x46,0x3f,0x49,0xcb,0x85,0x82,0xcd,0xa5,0x6c, + 0x68,0x43,0xf1,0x85,0x64,0x28,0x63,0x93,0x41,0x4f,0xaa,0xf1,0xf8,0x0c,0xfb,0x08, + 0x08,0x20,0x93,0xe1,0x74,0x83,0x6a,0xac,0x6b,0x54,0x6d,0xcc,0x4c,0x73,0xdc,0x18, + 0x0f,0x0a,0xb9,0xc9,0x1f,0x40,0xf6,0xaa,0x49,0x41,0xd8,0x7c,0x09,0x6d,0xf5,0xe2, + 0x88,0x26,0xd0,0x24,0x60,0x30,0x73,0x2a,0x9d,0x47,0x26,0x4b,0x55,0xec,0x3c,0x79, + 0xdb,0x10,0xbf,0x0e,0xf5,0xf3,0x1c,0xd1,0xdb,0x06,0x1d,0xd5,0x65,0x26,0x78,0xf8, + 0xa4,0xa3,0x76,0x2e,0x59,0xf3,0xa0,0x0a,0x09,0x93,0x12,0xb8,0x10,0x2d,0x48,0xa7, + 0x2f,0x4f,0xb2,0xde,0x12,0xf0,0x50,0x38,0xe8,0x4b,0x21,0xfe,0x5a,0x88,0xe7,0x2b, + 0x07,0xd8,0xbb,0x6a,0xf9,0xde,0x2b,0x0b,0x89,0xbe,0xb3,0x2d,0x36,0x63,0x02,0x13, + 0x6a,0xa0,0xf3,0x0d,0x9f,0x20,0x53,0xcb,0x3e,0x40,0xe3,0x3a,0x0d,0x03,0x54,0x31, + 0x04,0x45,0x3b,0xc3,0xe6,0x38,0x14,0x24,0x49,0x22,0x54,0xc9,0x14,0x3e,0x08,0xfb, + 0xa0,0x1c,0x1c,0x69,0x31,0x70,0x64,0x97,0x9c,0x5e,0xa4,0x4f,0x90,0x12,0x98,0xaa, + 0xd1,0x69,0x87,0xfa,0x66,0xcd,0x75,0x01,0xa6,0xdf,0x05,0x81,0x51,0xd3,0x57,0xb9, + 0xc9,0x09,0x61,0x15,0x4d,0x13,0x8d,0xc3,0x12,0xce,0xe6,0x72,0x0c,0xc5,0xc0,0xa0, + 0x3e,0x9f,0x6c,0xec,0x22,0x7b,0xa1,0x92,0xc1,0x52,0x38,0x64,0x8e,0x54,0x9f,0x2e, + 0xfe,0x9f,0xcd,0x32,0xb6,0x64,0xa7,0x12,0xc2,0xdf,0xe4,0x07,0x07,0xd1,0xc1,0xfc, + 0x5d,0x9b,0xc4,0x23,0xa2,0x79,0x5d,0x4f,0x43,0xdc,0x79,0x67,0xf3,0xb3,0x36,0x8e, + 0x20,0x19,0x94,0xcf,0xd4,0xf1,0xda,0x13,0x61,0x5f,0x32,0xc8,0x75,0x82,0x7b,0x78, + 0xcc,0xbb,0x2a,0xce,0xbb,0x3e,0xba,0x3b,0x31,0x52,0x2d,0x36,0x79,0x98,0x75,0x61, + 0x21,0x17,0xf6,0x1e,0x38,0x86,0xde,0x98,0x43,0x54,0xfd,0x42,0x5d,0x15,0xc9,0xc3, + 0x11,0x06,0x8f,0x52,0xdb,0xaa,0xd1,0x59,0xb6,0xcb,0x28,0x36,0x07,0xa7,0x37,0x72, + 0xde,0x1b,0xb7,0x2f,0xe9,0xbb,0xe0,0x4b,0xc8,0x6b,0xa0,0x22,0x06,0xe6,0xa6,0xf7, + 0x0e,0x10,0x56,0x8b,0xc7,0x8a,0x27,0x96,0xc9,0x39,0x65,0xd0,0x86,0x8d,0xea,0x9a, + 0xaf,0x11,0x62,0xac,0xbb,0xbb,0x52,0x9f,0xca,0xd5,0x61,0xc5,0x90,0x39,0x7f,0x8b, + 0x09,0x12,0x38,0xb3,0x68,0xe1,0xe8,0x0b,0xce,0x58,0x47,0x9f,0x09,0xcc,0x27,0x28, + 0x28,0x1d,0xef,0x1d,0xab,0x53,0x5b,0x1b,0x94,0xd6,0xe5,0x41,0x10,0x1b,0x81,0x64, + 0xfb,0x9b,0x86,0x2e,0x49,0xbb,0xdc,0xb0,0x25,0xca,0x1c,0xb9,0x55,0x80,0x90,0xd5, + 0xc7,0x03,0xa9,0x65,0x21,0xee,0x18,0x5c,0x41,0x18,0xe1,0x60,0xf0,0x61,0x07,0x65, + 0xf8,0xcd,0x7d,0x74,0xac,0xed,0x37,0xa7,0xef,0x44,0x71,0xc6,0xde,0xa3,0x21,0x92, + 0xfa,0xe3,0x39,0x50,0xae,0xe7,0xfc,0x41,0x36,0x7c,0x41,0xb3,0xf6,0x2e,0x7a,0xaa, + 0xce,0x4b,0x70,0xd7,0x01,0x0f,0xc4,0x1d,0xe5,0x85,0x17,0x26,0x5a,0x8a,0x92,0x14, + 0x4b,0xc9,0xda,0x66,0xd4,0x0a,0x6f,0x71,0x2c,0x14,0x80,0x52,0x51,0x14,0xc9,0x4f, + 0xb5,0xa2,0x99,0x43,0x7f,0xfc,0xb1,0xdf,0x7a,0x6d,0xd1,0x66,0x5b,0xec,0xa9,0xbb, + 0x17,0x48,0x49,0x24,0x34,0x24,0x51,0x8a,0xf7,0x5c,0xc4,0x8a,0xe7,0x3c,0xe2,0xc3, + 0x80,0x8e,0x1c,0xe6,0x94,0x6e,0xef,0xaa,0x7b,0x29,0xeb,0x78,0xf9,0x86,0x2e,0xf8, + 0x29,0x04,0x6a,0x43,0xe4,0xa1,0xd7,0xd7,0x35,0x92,0x65,0x3f,0x5b,0xa0,0x2f,0x0c, + 0x2d,0x02,0xe1,0x1c,0xf5,0xa5,0x4e,0xc1,0xca,0x1a,0xd1,0x27,0xdd,0x5a,0x72,0x08, + 0x2a,0xca,0x2f,0x20,0xf4,0xea,0xce,0xd2,0xdd,0xd0,0xa5,0xbb,0xd8,0x2d,0xca,0x52, + 0x8b,0x8c,0xd4,0xbd,0x92,0xa1,0xc0,0x79,0x01,0xc4,0x40,0xea,0x68,0x33,0x2a,0x65, + 0x07,0xe1,0x7a,0x2c,0x2c,0x19,0xe9,0x44,0x37,0x8d,0x3c,0x7b,0x59,0xff,0x8b,0x4f, + 0xaa,0xe0,0x18,0x68,0x3f,0x51,0x55,0xa3,0xc7,0x3b,0x33,0xab,0xde,0xed,0x43,0x99, + 0x72,0x05,0x11,0xb7,0x79,0xe0,0xb4,0x83,0x4d,0xc7,0xfb,0x7b,0xa6,0x5f,0xfb,0x9e, + 0x22,0x20,0x7b,0x87,0xb4,0xf0,0x1b,0xd8,0xbd,0x92,0x57,0x58,0x50,0x8c,0xb3,0x00, + 0x2d,0x9b,0x4c,0xa9,0x11,0x3c,0xbe,0xaa,0xe5,0xbc,0x7c,0x36,0x09,0x8c,0x07,0xa7, + 0x29,0x3f,0x7a,0x87,0x37,0xbc,0xaf,0xd3,0xd7,0x89,0x0a,0xe8,0xc7,0xd8,0xa9,0x17, + 0xd3,0xa8,0xd3,0xa2,0xd6,0xfc,0xad,0xc0,0xf2,0xbf,0xab,0xd5,0x9d,0xfe,0xa4,0x82, + 0x8b,0x9a,0xde,0x59,0xc9,0x39,0xb4,0x9f,0xa4,0xd2,0xcc,0xde,0x85,0x49,0xc8,0x10, + 0x84,0x9b,0x8c,0x76,0x25,0xb6,0x1c,0xb3,0xca,0xd8,0x53,0xd2,0x57,0x34,0x0d,0x01, + 0x22,0x98,0x06,0x39,0x92,0xf7,0x7d,0x36,0x47,0x29,0xad,0x04,0x2b,0x6b,0x55,0x77, + 0x25,0x9f,0x6b,0xdf,0xd4,0xa1,0x37,0x0d,0x44,0x96,0xbd,0x30,0xc4,0xd0,0x8e,0xba, + 0xa9,0xf9,0xb0,0xbb,0x3a,0xb9,0x54,0x36,0x6f,0xca,0xa4,0xa4,0x7a,0xfb,0xe7,0x1c, + 0x2b,0x92,0xaa,0xde,0x75,0x4c,0x60,0x58,0x69,0x64,0xde,0x0c,0x4e,0xf4,0xe7,0x37, + 0x81,0xd8,0xe7,0xed,0x33,0x3c,0x00,0x67,0xa4,0x80,0xa7,0x2b,0xfe,0x93,0xbd,0x1f, + 0xc3,0x3e,0x39,0x1b,0xa8,0xab,0x0d,0x8b,0x2e,0x74,0xbd,0x5d,0xd9,0x70,0x92,0xb8, + 0x8d,0x9a,0x9e,0xe9,0x5d,0xba,0xf8,0x3a,0x54,0xdf,0x4e,0x7c,0x0e,0xee,0x6a,0x38, + 0x8e,0x17,0x96,0xf9,0x5c,0xbf,0x72,0x3f,0x7e,0x45,0xda,0xbe,0x7b,0x93,0x6f,0x6d, + 0x0f,0x16,0x9f,0xeb,0xdd,0xa8,0x27,0x36,0xab,0x46,0x4f,0x9f,0x7e,0x78,0xe8,0x8b, + 0x0f,0x90,0x97,0xfb,0xb9,0x46,0x71,0x3e,0xe0,0x25,0x6f,0xb8,0xdb,0x91,0x40,0x3f, + 0x08,0x6c,0x7f,0xe6,0x34,0xdd,0x78,0xd1,0xc3,0x50,0x98,0xa0,0x52,0x99,0x30,0x01, + 0x5d,0xf6,0x37,0x8f,0xee,0x60,0x70,0xf2,0xe0,0x02,0x08,0xb6,0x3f,0xa0,0x29,0xc3, + 0x7d,0x01,0x6d,0x9e,0x91,0xa2,0xd1,0x34,0x77,0x4c,0x00,0x0b,0x64,0x37,0x09,0x10, + 0xd5,0x0d,0x25,0x6e,0x4f,0xdc,0x79,0x91,0xcd,0xce,0xc3,0x20,0x72,0x06,0xbf,0xbf, + 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, + 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, + 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, + 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0x6a,0x8e, + 0xf4,0x49,0x12,0x7e,0x2b,0xbd,0x6a,0x88,0xb7,0xf7,0xc8,0xd3,0xfb,0x29,0xf2,0x6a, + 0x3a,0xdf,0x3f,0xfa,0x9c,0xaa,0x1e,0xda,0x6d,0x4f,0x65,0x4e,0xfa,0x94,0x5a,0x93, + 0xeb,0xf5,0x7b,0x05,0x3f,0x31,0x73,0x89,0xc4,0xc1,0xf3,0x6d,0x76,0x67,0xf3,0xf1, + 0x2d,0x80,0x0b,0xfd,0xdb,0x65,0x17,0x47,0x68,0xc1,0xe3,0x19,0x5b,0x88,0xbd,0xb7, + 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, + 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, + 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, + 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0x24,0x95, + 0xad,0x9d,0x11,0x73,0x14,0xbd,0x11,0x1f,0x68,0x30,0x11,0x20,0x58,0xa4,0xf7,0xb4, + 0xae,0x13,0x4c,0x54,0x1c,0xe6,0xdc,0x10,0xce,0x58,0xa4,0xe4,0x31,0x7e,0xe2,0x7e, + 0x41,0xc4,0x7e,0xfb,0xd0,0xa3,0xd5,0x41,0x7e,0x13,0x05,0x27,0x70,0xfa,0xba,0x90, + 0x2c,0x1f,0xcd,0x62,0x95,0xbe,0x99,0x0e,0xed,0x33,0x0d,0x31,0x87,0x2b,0xbb,0x3f, + 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, + 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, + 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, + 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0x6e,0x88, + 0x43,0xfc,0xdf,0x0c,0x9f,0x3e,0x96,0x48,0xf6,0x1a,0x56,0xd9,0x79,0x39,0xee,0xa7, + 0x0d,0x57,0xcb,0x7a,0x1d,0xc4,0x1e,0x45,0x79,0xe2,0xb9,0x4a,0x5d,0x7f,0x03,0x89, + 0x2b,0x14,0xf1,0xc7,0x1b,0x21,0x88,0xa0,0xcc,0x81,0x28,0x9d,0xb4,0x61,0x4f,0xeb, + 0x42,0x92,0xa9,0x49,0x1a,0xbe,0x51,0x55,0x69,0x60,0x97,0xda,0x04,0x74,0xb9,0x37, + 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, + 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, + 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, + 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xe4, + 0xe5,0x90,0xa1,0x82,0x62,0x6c,0x4f,0xc0,0xc6,0xe8,0xa2,0x54,0xf7,0x85,0x77,0xd0, + 0x36,0x0d,0x28,0x6a,0xe3,0xa7,0x40,0x16,0x43,0xc2,0x78,0x1a,0x9c,0xe0,0xd9,0x27, + 0xf7,0xb4,0x7e,0xf3,0xe3,0xe2,0x0e,0x41,0x85,0xe2,0xeb,0xd8,0x77,0xa3,0x91,0xfd, + 0x95,0xce,0xa1,0x5a,0xf6,0xc3,0xc5,0x53,0xc9,0x34,0x3e,0x32,0xd3,0x7a,0x9f,0xbd, + 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, + 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, + 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, + 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdf,0xf7, + 0xcf,0x53,0xda,0x8c,0x1d,0xf0,0xb6,0x2f,0x48,0x31,0x13,0x0a,0xd9,0x6b,0x86,0x64, + 0x6c,0x8d,0x51,0x60,0x7d,0xa9,0xaa,0xbe,0x6f,0xa6,0xe3,0x10,0xfa,0xa8,0xc4,0x0f, + 0xa1,0x74,0x99,0xed,0xb8,0x27,0x36,0xaf,0xef,0xbc,0x1f,0xdf,0xcc,0x1c,0x49,0x19, + 0x8c,0xcb,0x6b,0xdf,0xb0,0x7c,0x63,0x3e,0xc9,0x32,0xeb,0x32,0x95,0xa7,0x9d,0xb5, + 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, + 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, + 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, + 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0x7d,0x81, + 0xc3,0x96,0xb3,0x79,0xd5,0x13,0x64,0x4f,0x6c,0x90,0x24,0x24,0x75,0x0e,0x54,0x54, + 0x91,0xd0,0x8c,0x6b,0x24,0x0a,0x63,0xf0,0xd9,0xcb,0x43,0x49,0x8a,0x0e,0x2d,0x2c, + 0x07,0x12,0xdd,0x79,0x90,0x69,0x75,0x99,0x97,0xf6,0x8f,0x45,0xd0,0x0d,0x17,0x60, + 0xd8,0x3c,0xf8,0x6f,0xb5,0xf1,0x8c,0x66,0x9a,0xdf,0x42,0x48,0x0a,0x0c,0x9b,0x3d, + 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, + 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, + 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, + 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0x7e,0xcc, + 0x04,0xd4,0x38,0xce,0x18,0xfa,0xed,0xbd,0x68,0xb1,0x49,0x51,0x83,0x07,0x16,0xca, + 0xad,0x96,0x31,0x0f,0x76,0x13,0x5e,0xb8,0x6c,0xd4,0x41,0x41,0x82,0x06,0xb1,0x09, + 0x2c,0x12,0xef,0xcf,0xba,0xb8,0xd8,0x2f,0xdd,0xc5,0x48,0x50,0x03,0x05,0xbf,0xd9, + 0x0c,0x97,0xe1,0xbb,0xbb,0xb1,0x4d,0x95,0xe1,0x50,0x40,0x40,0x02,0x04,0x99,0x35, + 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, + 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, + 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, + 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x00,0x00,0xff,0xff, + 0xff,0xff,0x7f,0xfb,0xef,0xdf,0xef,0xdf,0xbf,0xbf,0x6f,0xdb,0xaf,0x9f,0xf7,0xef, + 0xfe,0xfe,0x77,0xeb,0xee,0xde,0xe7,0xcf,0xbe,0xbe,0x67,0xcb,0xae,0x9e,0xfe,0xfe, + 0x7f,0xfd,0x7e,0xfa,0x6f,0xdd,0xee,0xde,0x3f,0xbd,0x6e,0xda,0x2f,0x9d,0xf6,0xee, + 0x7e,0xfc,0x76,0xea,0x6e,0xdc,0xe6,0xce,0x3e,0xbc,0x66,0xca,0x2e,0x9c,0xbf,0xbf, + 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, + 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, + 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, + 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0xfd,0xf7, + 0xf7,0xf7,0x7d,0xf3,0xe7,0xd7,0xed,0xd7,0xb7,0xb7,0x6d,0xd3,0xa7,0x97,0xf5,0xe7, + 0xf6,0xf6,0x75,0xe3,0xe6,0xd6,0xe5,0xc7,0xb6,0xb6,0x65,0xc3,0xa6,0x96,0xfc,0xf6, + 0x77,0xf5,0x7c,0xf2,0x67,0xd5,0xec,0xd6,0x37,0xb5,0x6c,0xd2,0x27,0x95,0xf4,0xe6, + 0x76,0xf4,0x74,0xe2,0x66,0xd4,0xe4,0xc6,0x36,0xb4,0x64,0xc2,0x26,0x94,0xbd,0xb7, + 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, + 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, + 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, + 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0xfb,0x7f, + 0xdf,0xef,0x7b,0x7b,0xcf,0xcf,0xeb,0x5f,0x9f,0xaf,0x6b,0x5b,0x8f,0x8f,0xf3,0x6f, + 0xde,0xee,0x73,0x6b,0xce,0xce,0xe3,0x4f,0x9e,0xae,0x63,0x4b,0x8e,0x8e,0xfa,0x7e, + 0x5f,0xed,0x7a,0x7a,0x4f,0xcd,0xea,0x5e,0x1f,0xad,0x6a,0x5a,0x0f,0x8d,0xf2,0x6e, + 0x5e,0xec,0x72,0x6a,0x4e,0xcc,0xe2,0x4e,0x1e,0xac,0x62,0x4a,0x0e,0x8c,0xbb,0x3f, + 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, + 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, + 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, + 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0xf9,0x77, + 0xd7,0xe7,0x79,0x73,0xc7,0xc7,0xe9,0x57,0x97,0xa7,0x69,0x53,0x87,0x87,0xf1,0x67, + 0xd6,0xe6,0x71,0x63,0xc6,0xc6,0xe1,0x47,0x96,0xa6,0x61,0x43,0x86,0x86,0xf8,0x76, + 0x57,0xe5,0x78,0x72,0x47,0xc5,0xe8,0x56,0x17,0xa5,0x68,0x52,0x07,0x85,0xf0,0x66, + 0x56,0xe4,0x70,0x62,0x46,0xc4,0xe0,0x46,0x16,0xa4,0x60,0x42,0x06,0x84,0xb9,0x37, + 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, + 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, + 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, + 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xfd, + 0xfb,0x7f,0x5f,0xf9,0xeb,0x5f,0xcf,0xdd,0xbb,0x3f,0x4f,0xd9,0xab,0x1f,0xd7,0xed, + 0xfa,0x7e,0x57,0xe9,0xea,0x5e,0xc7,0xcd,0xba,0x3e,0x47,0xc9,0xaa,0x1e,0xde,0xfc, + 0x7b,0x7d,0x5e,0xf8,0x6b,0x5d,0xce,0xdc,0x3b,0x3d,0x4e,0xd8,0x2b,0x1d,0xd6,0xec, + 0x7a,0x7c,0x56,0xe8,0x6a,0x5c,0xc6,0xcc,0x3a,0x3c,0x46,0xc8,0x2a,0x1c,0x9f,0xbd, + 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, + 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, + 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, + 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdd,0xf5, + 0xf3,0x77,0x5d,0xf1,0xe3,0x57,0xcd,0xd5,0xb3,0x37,0x4d,0xd1,0xa3,0x17,0xd5,0xe5, + 0xf2,0x76,0x55,0xe1,0xe2,0x56,0xc5,0xc5,0xb2,0x36,0x45,0xc1,0xa2,0x16,0xdc,0xf4, + 0x73,0x75,0x5c,0xf0,0x63,0x55,0xcc,0xd4,0x33,0x35,0x4c,0xd0,0x23,0x15,0xd4,0xe4, + 0x72,0x74,0x54,0xe0,0x62,0x54,0xc4,0xc4,0x32,0x34,0x44,0xc0,0x22,0x14,0x9d,0xb5, + 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, + 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, + 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, + 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0xdb,0x7d, + 0xdb,0x6f,0x5b,0x79,0xcb,0x4f,0xcb,0x5d,0x9b,0x2f,0x4b,0x59,0x8b,0x0f,0xd3,0x6d, + 0xda,0x6e,0x53,0x69,0xca,0x4e,0xc3,0x4d,0x9a,0x2e,0x43,0x49,0x8a,0x0e,0xda,0x7c, + 0x5b,0x6d,0x5a,0x78,0x4b,0x4d,0xca,0x5c,0x1b,0x2d,0x4a,0x58,0x0b,0x0d,0xd2,0x6c, + 0x5a,0x6c,0x52,0x68,0x4a,0x4c,0xc2,0x4c,0x1a,0x2c,0x42,0x48,0x0a,0x0c,0x9b,0x3d, + 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, + 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, + 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, + 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0xd9,0x75, + 0xd3,0x67,0x59,0x71,0xc3,0x47,0xc9,0x55,0x93,0x27,0x49,0x51,0x83,0x07,0xd1,0x65, + 0xd2,0x66,0x51,0x61,0xc2,0x46,0xc1,0x45,0x92,0x26,0x41,0x41,0x82,0x06,0xd8,0x74, + 0x53,0x65,0x58,0x70,0x43,0x45,0xc8,0x54,0x13,0x25,0x48,0x50,0x03,0x05,0xd0,0x64, + 0x52,0x64,0x50,0x60,0x42,0x44,0xc0,0x44,0x12,0x24,0x40,0x40,0x02,0x04,0x99,0x35, + 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, + 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, + 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, + 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x00,0x00,0xff,0xff, + 0xff,0xff,0x7f,0xfb,0xef,0xdf,0xef,0xdf,0xbf,0xbf,0x6f,0xdb,0xaf,0x9f,0xf7,0xef, + 0xfe,0xfe,0x77,0xeb,0xee,0xde,0xe7,0xcf,0xbe,0xbe,0x67,0xcb,0xae,0x9e,0xfe,0xfe, + 0x7f,0xfd,0x7e,0xfa,0x6f,0xdd,0xee,0xde,0x3f,0xbd,0x6e,0xda,0x2f,0x9d,0xf6,0xee, + 0x7e,0xfc,0x76,0xea,0x6e,0xdc,0xe6,0xce,0x3e,0xbc,0x66,0xca,0x2e,0x9c,0xbf,0xbf, + 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, + 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, + 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, + 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0xfd,0xf7, + 0xf7,0xf7,0x7d,0xf3,0xe7,0xd7,0xed,0xd7,0xb7,0xb7,0x6d,0xd3,0xa7,0x97,0xf5,0xe7, + 0xf6,0xf6,0x75,0xe3,0xe6,0xd6,0xe5,0xc7,0xb6,0xb6,0x65,0xc3,0xa6,0x96,0xfc,0xf6, + 0x77,0xf5,0x7c,0xf2,0x67,0xd5,0xec,0xd6,0x37,0xb5,0x6c,0xd2,0x27,0x95,0xf4,0xe6, + 0x76,0xf4,0x74,0xe2,0x66,0xd4,0xe4,0xc6,0x36,0xb4,0x64,0xc2,0x26,0x94,0xbd,0xb7, + 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, + 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, + 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, + 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0xfb,0x7f, + 0xdf,0xef,0x7b,0x7b,0xcf,0xcf,0xeb,0x5f,0x9f,0xaf,0x6b,0x5b,0x8f,0x8f,0xf3,0x6f, + 0xde,0xee,0x73,0x6b,0xce,0xce,0xe3,0x4f,0x9e,0xae,0x63,0x4b,0x8e,0x8e,0xfa,0x7e, + 0x5f,0xed,0x7a,0x7a,0x4f,0xcd,0xea,0x5e,0x1f,0xad,0x6a,0x5a,0x0f,0x8d,0xf2,0x6e, + 0x5e,0xec,0x72,0x6a,0x4e,0xcc,0xe2,0x4e,0x1e,0xac,0x62,0x4a,0x0e,0x8c,0xbb,0x3f, + 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, + 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, + 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, + 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0xf9,0x77, + 0xd7,0xe7,0x79,0x73,0xc7,0xc7,0xe9,0x57,0x97,0xa7,0x69,0x53,0x87,0x87,0xf1,0x67, + 0xd6,0xe6,0x71,0x63,0xc6,0xc6,0xe1,0x47,0x96,0xa6,0x61,0x43,0x86,0x86,0xf8,0x76, + 0x57,0xe5,0x78,0x72,0x47,0xc5,0xe8,0x56,0x17,0xa5,0x68,0x52,0x07,0x85,0xf0,0x66, + 0x56,0xe4,0x70,0x62,0x46,0xc4,0xe0,0x46,0x16,0xa4,0x60,0x42,0x06,0x84,0xb9,0x37, + 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, + 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, + 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, + 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xfd, + 0xfb,0x7f,0x5f,0xf9,0xeb,0x5f,0xcf,0xdd,0xbb,0x3f,0x4f,0xd9,0xab,0x1f,0xd7,0xed, + 0xfa,0x7e,0x57,0xe9,0xea,0x5e,0xc7,0xcd,0xba,0x3e,0x47,0xc9,0xaa,0x1e,0xde,0xfc, + 0x7b,0x7d,0x5e,0xf8,0x6b,0x5d,0xce,0xdc,0x3b,0x3d,0x4e,0xd8,0x2b,0x1d,0xd6,0xec, + 0x7a,0x7c,0x56,0xe8,0x6a,0x5c,0xc6,0xcc,0x3a,0x3c,0x46,0xc8,0x2a,0x1c,0x9f,0xbd, + 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, + 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, + 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, + 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdd,0xf5, + 0xf3,0x77,0x5d,0xf1,0xe3,0x57,0xcd,0xd5,0xb3,0x37,0x4d,0xd1,0xa3,0x17,0xd5,0xe5, + 0xf2,0x76,0x55,0xe1,0xe2,0x56,0xc5,0xc5,0xb2,0x36,0x45,0xc1,0xa2,0x16,0xdc,0xf4, + 0x73,0x75,0x5c,0xf0,0x63,0x55,0xcc,0xd4,0x33,0x35,0x4c,0xd0,0x23,0x15,0xd4,0xe4, + 0x72,0x74,0x54,0xe0,0x62,0x54,0xc4,0xc4,0x32,0x34,0x44,0xc0,0x22,0x14,0x9d,0xb5, + 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, + 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, + 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, + 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0xdb,0x7d, + 0xdb,0x6f,0x5b,0x79,0xcb,0x4f,0xcb,0x5d,0x9b,0x2f,0x4b,0x59,0x8b,0x0f,0xd3,0x6d, + 0xda,0x6e,0x53,0x69,0xca,0x4e,0xc3,0x4d,0x9a,0x2e,0x43,0x49,0x8a,0x0e,0xda,0x7c, + 0x5b,0x6d,0x5a,0x78,0x4b,0x4d,0xca,0x5c,0x1b,0x2d,0x4a,0x58,0x0b,0x0d,0xd2,0x6c, + 0x5a,0x6c,0x52,0x68,0x4a,0x4c,0xc2,0x4c,0x1a,0x2c,0x42,0x48,0x0a,0x0c,0x9b,0x3d, + 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, + 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, + 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, + 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0xd9,0x75, + 0xd3,0x67,0x59,0x71,0xc3,0x47,0xc9,0x55,0x93,0x27,0x49,0x51,0x83,0x07,0xd1,0x65, + 0xd2,0x66,0x51,0x61,0xc2,0x46,0xc1,0x45,0x92,0x26,0x41,0x41,0x82,0x06,0xd8,0x74, + 0x53,0x65,0x58,0x70,0x43,0x45,0xc8,0x54,0x13,0x25,0x48,0x50,0x03,0x05,0xd0,0x64, + 0x52,0x64,0x50,0x60,0x42,0x44,0xc0,0x44,0x12,0x24,0x40,0x40,0x02,0x04,0x99,0x35, + 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, + 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, + 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, + 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x00,0x00,0xff,0xff, + 0xff,0xff,0x7f,0xfb,0xef,0xdf,0xef,0xdf,0xbf,0xbf,0x6f,0xdb,0xaf,0x9f,0xf7,0xef, + 0xfe,0xfe,0x77,0xeb,0xee,0xde,0xe7,0xcf,0xbe,0xbe,0x67,0xcb,0xae,0x9e,0xfe,0xfe, + 0x7f,0xfd,0x7e,0xfa,0x6f,0xdd,0xee,0xde,0x3f,0xbd,0x6e,0xda,0x2f,0x9d,0xf6,0xee, + 0x7e,0xfc,0x76,0xea,0x6e,0xdc,0xe6,0xce,0x3e,0xbc,0x66,0xca,0x2e,0x9c,0xbf,0xbf, + 0xfd,0xfb,0x3f,0xbb,0xed,0xdb,0xaf,0x9f,0xbd,0xbb,0x2f,0x9b,0xad,0x9b,0xb7,0xaf, + 0xfc,0xfa,0x37,0xab,0xec,0xda,0xa7,0x8f,0xbc,0xba,0x27,0x8b,0xac,0x9a,0xbe,0xbe, + 0x7d,0xf9,0x3e,0xba,0x6d,0xd9,0xae,0x9e,0x3d,0xb9,0x2e,0x9a,0x2d,0x99,0xb6,0xae, + 0x7c,0xf8,0x36,0xaa,0x6c,0xd8,0xa6,0x8e,0x3c,0xb8,0x26,0x8a,0x2c,0x98,0xfd,0xf7, + 0xf7,0xf7,0x7d,0xf3,0xe7,0xd7,0xed,0xd7,0xb7,0xb7,0x6d,0xd3,0xa7,0x97,0xf5,0xe7, + 0xf6,0xf6,0x75,0xe3,0xe6,0xd6,0xe5,0xc7,0xb6,0xb6,0x65,0xc3,0xa6,0x96,0xfc,0xf6, + 0x77,0xf5,0x7c,0xf2,0x67,0xd5,0xec,0xd6,0x37,0xb5,0x6c,0xd2,0x27,0x95,0xf4,0xe6, + 0x76,0xf4,0x74,0xe2,0x66,0xd4,0xe4,0xc6,0x36,0xb4,0x64,0xc2,0x26,0x94,0xbd,0xb7, + 0xf5,0xf3,0x3d,0xb3,0xe5,0xd3,0xad,0x97,0xb5,0xb3,0x2d,0x93,0xa5,0x93,0xb5,0xa7, + 0xf4,0xf2,0x35,0xa3,0xe4,0xd2,0xa5,0x87,0xb4,0xb2,0x25,0x83,0xa4,0x92,0xbc,0xb6, + 0x75,0xf1,0x3c,0xb2,0x65,0xd1,0xac,0x96,0x35,0xb1,0x2c,0x92,0x25,0x91,0xb4,0xa6, + 0x74,0xf0,0x34,0xa2,0x64,0xd0,0xa4,0x86,0x34,0xb0,0x24,0x82,0x24,0x90,0xfb,0x7f, + 0xdf,0xef,0x7b,0x7b,0xcf,0xcf,0xeb,0x5f,0x9f,0xaf,0x6b,0x5b,0x8f,0x8f,0xf3,0x6f, + 0xde,0xee,0x73,0x6b,0xce,0xce,0xe3,0x4f,0x9e,0xae,0x63,0x4b,0x8e,0x8e,0xfa,0x7e, + 0x5f,0xed,0x7a,0x7a,0x4f,0xcd,0xea,0x5e,0x1f,0xad,0x6a,0x5a,0x0f,0x8d,0xf2,0x6e, + 0x5e,0xec,0x72,0x6a,0x4e,0xcc,0xe2,0x4e,0x1e,0xac,0x62,0x4a,0x0e,0x8c,0xbb,0x3f, + 0xdd,0xeb,0x3b,0x3b,0xcd,0xcb,0xab,0x1f,0x9d,0xab,0x2b,0x1b,0x8d,0x8b,0xb3,0x2f, + 0xdc,0xea,0x33,0x2b,0xcc,0xca,0xa3,0x0f,0x9c,0xaa,0x23,0x0b,0x8c,0x8a,0xba,0x3e, + 0x5d,0xe9,0x3a,0x3a,0x4d,0xc9,0xaa,0x1e,0x1d,0xa9,0x2a,0x1a,0x0d,0x89,0xb2,0x2e, + 0x5c,0xe8,0x32,0x2a,0x4c,0xc8,0xa2,0x0e,0x1c,0xa8,0x22,0x0a,0x0c,0x88,0xf9,0x77, + 0xd7,0xe7,0x79,0x73,0xc7,0xc7,0xe9,0x57,0x97,0xa7,0x69,0x53,0x87,0x87,0xf1,0x67, + 0xd6,0xe6,0x71,0x63,0xc6,0xc6,0xe1,0x47,0x96,0xa6,0x61,0x43,0x86,0x86,0xf8,0x76, + 0x57,0xe5,0x78,0x72,0x47,0xc5,0xe8,0x56,0x17,0xa5,0x68,0x52,0x07,0x85,0xf0,0x66, + 0x56,0xe4,0x70,0x62,0x46,0xc4,0xe0,0x46,0x16,0xa4,0x60,0x42,0x06,0x84,0xb9,0x37, + 0xd5,0xe3,0x39,0x33,0xc5,0xc3,0xa9,0x17,0x95,0xa3,0x29,0x13,0x85,0x83,0xb1,0x27, + 0xd4,0xe2,0x31,0x23,0xc4,0xc2,0xa1,0x07,0x94,0xa2,0x21,0x03,0x84,0x82,0xb8,0x36, + 0x55,0xe1,0x38,0x32,0x45,0xc1,0xa8,0x16,0x15,0xa1,0x28,0x12,0x05,0x81,0xb0,0x26, + 0x54,0xe0,0x30,0x22,0x44,0xc0,0xa0,0x06,0x14,0xa0,0x20,0x02,0x04,0x80,0xdf,0xfd, + 0xfb,0x7f,0x5f,0xf9,0xeb,0x5f,0xcf,0xdd,0xbb,0x3f,0x4f,0xd9,0xab,0x1f,0xd7,0xed, + 0xfa,0x7e,0x57,0xe9,0xea,0x5e,0xc7,0xcd,0xba,0x3e,0x47,0xc9,0xaa,0x1e,0xde,0xfc, + 0x7b,0x7d,0x5e,0xf8,0x6b,0x5d,0xce,0xdc,0x3b,0x3d,0x4e,0xd8,0x2b,0x1d,0xd6,0xec, + 0x7a,0x7c,0x56,0xe8,0x6a,0x5c,0xc6,0xcc,0x3a,0x3c,0x46,0xc8,0x2a,0x1c,0x9f,0xbd, + 0xf9,0x7b,0x1f,0xb9,0xe9,0x5b,0x8f,0x9d,0xb9,0x3b,0x0f,0x99,0xa9,0x1b,0x97,0xad, + 0xf8,0x7a,0x17,0xa9,0xe8,0x5a,0x87,0x8d,0xb8,0x3a,0x07,0x89,0xa8,0x1a,0x9e,0xbc, + 0x79,0x79,0x1e,0xb8,0x69,0x59,0x8e,0x9c,0x39,0x39,0x0e,0x98,0x29,0x19,0x96,0xac, + 0x78,0x78,0x16,0xa8,0x68,0x58,0x86,0x8c,0x38,0x38,0x06,0x88,0x28,0x18,0xdd,0xf5, + 0xf3,0x77,0x5d,0xf1,0xe3,0x57,0xcd,0xd5,0xb3,0x37,0x4d,0xd1,0xa3,0x17,0xd5,0xe5, + 0xf2,0x76,0x55,0xe1,0xe2,0x56,0xc5,0xc5,0xb2,0x36,0x45,0xc1,0xa2,0x16,0xdc,0xf4, + 0x73,0x75,0x5c,0xf0,0x63,0x55,0xcc,0xd4,0x33,0x35,0x4c,0xd0,0x23,0x15,0xd4,0xe4, + 0x72,0x74,0x54,0xe0,0x62,0x54,0xc4,0xc4,0x32,0x34,0x44,0xc0,0x22,0x14,0x9d,0xb5, + 0xf1,0x73,0x1d,0xb1,0xe1,0x53,0x8d,0x95,0xb1,0x33,0x0d,0x91,0xa1,0x13,0x95,0xa5, + 0xf0,0x72,0x15,0xa1,0xe0,0x52,0x85,0x85,0xb0,0x32,0x05,0x81,0xa0,0x12,0x9c,0xb4, + 0x71,0x71,0x1c,0xb0,0x61,0x51,0x8c,0x94,0x31,0x31,0x0c,0x90,0x21,0x11,0x94,0xa4, + 0x70,0x70,0x14,0xa0,0x60,0x50,0x84,0x84,0x30,0x30,0x04,0x80,0x20,0x10,0xdb,0x7d, + 0xdb,0x6f,0x5b,0x79,0xcb,0x4f,0xcb,0x5d,0x9b,0x2f,0x4b,0x59,0x8b,0x0f,0xd3,0x6d, + 0xda,0x6e,0x53,0x69,0xca,0x4e,0xc3,0x4d,0x9a,0x2e,0x43,0x49,0x8a,0x0e,0xda,0x7c, + 0x5b,0x6d,0x5a,0x78,0x4b,0x4d,0xca,0x5c,0x1b,0x2d,0x4a,0x58,0x0b,0x0d,0xd2,0x6c, + 0x5a,0x6c,0x52,0x68,0x4a,0x4c,0xc2,0x4c,0x1a,0x2c,0x42,0x48,0x0a,0x0c,0x9b,0x3d, + 0xd9,0x6b,0x1b,0x39,0xc9,0x4b,0x8b,0x1d,0x99,0x2b,0x0b,0x19,0x89,0x0b,0x93,0x2d, + 0xd8,0x6a,0x13,0x29,0xc8,0x4a,0x83,0x0d,0x98,0x2a,0x03,0x09,0x88,0x0a,0x9a,0x3c, + 0x59,0x69,0x1a,0x38,0x49,0x49,0x8a,0x1c,0x19,0x29,0x0a,0x18,0x09,0x09,0x92,0x2c, + 0x58,0x68,0x12,0x28,0x48,0x48,0x82,0x0c,0x18,0x28,0x02,0x08,0x08,0x08,0xd9,0x75, + 0xd3,0x67,0x59,0x71,0xc3,0x47,0xc9,0x55,0x93,0x27,0x49,0x51,0x83,0x07,0xd1,0x65, + 0xd2,0x66,0x51,0x61,0xc2,0x46,0xc1,0x45,0x92,0x26,0x41,0x41,0x82,0x06,0xd8,0x74, + 0x53,0x65,0x58,0x70,0x43,0x45,0xc8,0x54,0x13,0x25,0x48,0x50,0x03,0x05,0xd0,0x64, + 0x52,0x64,0x50,0x60,0x42,0x44,0xc0,0x44,0x12,0x24,0x40,0x40,0x02,0x04,0x99,0x35, + 0xd1,0x63,0x19,0x31,0xc1,0x43,0x89,0x15,0x91,0x23,0x09,0x11,0x81,0x03,0x91,0x25, + 0xd0,0x62,0x11,0x21,0xc0,0x42,0x81,0x05,0x90,0x22,0x01,0x01,0x80,0x02,0x98,0x34, + 0x51,0x61,0x18,0x30,0x41,0x41,0x88,0x14,0x11,0x21,0x08,0x10,0x01,0x01,0x90,0x24, + 0x50,0x60,0x10,0x20,0x40,0x40,0x80,0x04,0x10,0x20,0x00,0x00,0x68,0xf7,0x80,0x0c, + 0xcc,0x40,0x3b,0xa1,0xe7,0xdd,0x4e,0xb6,0x98,0xeb,0xa8,0xdb,0xa5,0x03,0xbf,0x11, + 0x8c,0x0d,0x33,0xa5,0x1f,0x8e,0x7e,0xc1,0x83,0xc1,0xe6,0xa4,0xa4,0xc2,0x04,0x19, + 0x0f,0x00,0x97,0x95,0x7b,0xa0,0xf7,0x67,0x21,0xed,0x6a,0x5a,0xb8,0xe0,0x61,0x6e, + 0xc2,0x63,0x4d,0x17,0x9f,0x8e,0x67,0xaf,0x2a,0xb5,0x5d,0xc6,0xdf,0x67,0x1e,0x4f, + 0x46,0x4a,0x6c,0x06,0x91,0xd0,0x76,0x4c,0x0c,0xe9,0xe8,0x9b,0xa7,0x07,0x6e,0xef, + 0xfc,0xa1,0x17,0x54,0x93,0x65,0x6a,0x4e,0xe0,0xe4,0xa6,0xf9,0xa6,0xe6,0x20,0xe1, + 0x54,0xb9,0x81,0xe5,0x82,0xa6,0x43,0x90,0x61,0x06,0x2a,0x1a,0xb2,0x6a,0xba,0xaf, + 0x4b,0xb0,0x16,0x54,0x4f,0x45,0x1b,0x82,0x81,0x9a,0x7f,0x86,0xc5,0x63,0x1a,0x05, + 0x6b,0x68,0xd4,0x3d,0xb9,0xd7,0x4c,0xb3,0x58,0xe7,0x56,0x5f,0x32,0xc9,0xf1,0x47, + 0x4a,0x96,0x35,0x2d,0x5b,0x86,0x44,0x0f,0xc8,0xe6,0x4e,0xc2,0xa4,0xc8,0x94,0xf6, + 0x69,0xd9,0xbd,0xbd,0xb6,0xf5,0x70,0xd8,0x2c,0xfe,0xab,0xd2,0x31,0xe9,0xa4,0xdb, + 0x0a,0x4d,0xc9,0x63,0xf3,0x49,0x2d,0xc8,0x29,0x0b,0xd9,0xce,0x9b,0xb6,0x3d,0x5b, + 0xf8,0x93,0x92,0x40,0x5a,0xd7,0x04,0xed,0xa1,0x2e,0x91,0x53,0x58,0xb7,0x28,0x58, + 0x08,0x6d,0xce,0x43,0x59,0x86,0x3c,0x1a,0xbc,0xb0,0xda,0xf8,0x47,0xee,0x76,0xc1, + 0x33,0x60,0x43,0x4f,0x9e,0xd5,0xe4,0xe5,0x37,0x2d,0xd3,0x56,0xba,0xf5,0xcb,0x5d, + 0x16,0x5a,0x0b,0x59,0x72,0x6d,0x4d,0x1b,0x34,0x92,0x64,0x4c,0x7a,0x90,0x12,0x78, + 0x20,0x52,0x84,0xbf,0x58,0xab,0xcb,0xa1,0xbc,0x52,0x2b,0x01,0xba,0x7d,0x34,0x6f, + 0xd4,0x72,0x33,0x7c,0x35,0x5d,0x7a,0x39,0x62,0x31,0x63,0xca,0x5f,0xae,0x80,0x31, + 0x5d,0xb3,0x85,0x01,0xac,0xb1,0xc8,0xa5,0x5d,0x3c,0x6e,0xda,0x98,0x7f,0x22,0xee, + 0x78,0x8c,0x59,0xcb,0x9f,0xef,0x9d,0xb5,0x0e,0xfe,0x22,0x84,0xf7,0xdc,0x7a,0x55, + 0xad,0x92,0xa2,0xf9,0x33,0x54,0x0a,0x0f,0x70,0x06,0x6f,0x55,0x64,0xdb,0xdc,0xb0, + 0x21,0xb1,0x98,0x74,0x92,0x17,0xdc,0xf4,0x25,0xf8,0xe2,0x74,0xfe,0xd3,0x45,0x81, + 0xc0,0xbb,0x45,0xd4,0xd8,0x9b,0xd5,0xe5,0xca,0x64,0x14,0xe1,0xb2,0x7c,0x8d,0xd7, + 0x6b,0x35,0x93,0x44,0x21,0x9c,0x9b,0x36,0x21,0x57,0x8d,0xb5,0xff,0x37,0x56,0x80, + 0x64,0xa5,0xef,0x67,0x50,0xfa,0xc6,0x08,0xc9,0xf8,0x56,0xd2,0x12,0x5a,0xda,0x62, + 0xc0,0xa8,0xc8,0x6f,0x73,0x9d,0x9a,0xca,0x82,0x0b,0x58,0x82,0x33,0x8c,0x11,0xeb, + 0x53,0x87,0xf9,0x19,0x4d,0x99,0x49,0x25,0xe0,0x5e,0xe9,0x2c,0x30,0x2b,0x25,0x49, + 0x0a,0x93,0xdf,0x15,0x9b,0x4b,0xa2,0xc9,0xed,0x50,0x5d,0xa3,0x3f,0x8f,0xe2,0xbb, + 0xdf,0xb8,0x04,0x4e,0x51,0xde,0x5e,0xc9,0x83,0x1d,0xd0,0x40,0x93,0x5f,0xc4,0xda, + 0x73,0xb9,0x90,0x55,0x99,0x39,0xfe,0xeb,0x61,0x39,0x98,0x76,0x10,0xbf,0xf8,0x2b, + 0xac,0x6e,0xc3,0x3c,0xa8,0x28,0x4f,0x69,0x22,0x1c,0x87,0x8f,0xf0,0xd5,0x8f,0xdf, + 0x63,0x3d,0x48,0x2c,0xf1,0x29,0x61,0x87,0x23,0xa2,0xb7,0x0c,0xb5,0x5f,0x97,0x26, + 0x22,0xc0,0xde,0x83,0xfd,0x43,0x98,0xa8,0x94,0x54,0xe6,0xa3,0xbf,0x82,0x9f,0x13, + 0x88,0x8d,0x7a,0xb3,0xe2,0x5c,0xb8,0xf4,0xd7,0xc2,0x47,0x45,0x33,0x82,0x21,0x27, + 0x0b,0x80,0xb7,0x65,0x6b,0x0f,0x16,0x38,0xaf,0xb6,0x8f,0x92,0xbc,0xef,0x41,0xe2, + 0x8f,0x67,0xbf,0x87,0x7e,0x21,0xda,0xc8,0xe7,0xd3,0x42,0x48,0xbd,0x61,0x76,0x2c, + 0x89,0x02,0x0c,0xd5,0x18,0xae,0xa4,0x9c,0xbb,0x65,0x4b,0xc3,0xa1,0x19,0xe8,0x05, + 0x6c,0xfa,0xd6,0xf2,0x36,0x05,0x2e,0xf7,0xac,0xe7,0x43,0xc6,0x9b,0x4a,0x61,0x83, + 0x8a,0xc6,0x65,0x43,0xde,0xf5,0x33,0x90,0xc0,0x1b,0xe3,0x25,0x3d,0x94,0xed,0xa2, + 0x38,0x84,0xb7,0xcf,0x9f,0xa3,0x91,0x6e,0xe5,0x11,0x38,0x48,0x85,0x1a,0x7c,0x8e, + 0x8d,0x23,0x19,0xbf,0x12,0x07,0x30,0xd7,0x4c,0xcc,0xcc,0xbe,0xa9,0x4b,0x02,0x5c, + 0x51,0x7c,0xe8,0x9a,0x19,0x89,0x7f,0x9a,0x59,0x49,0xfe,0x2d,0x1f,0xab,0xe7,0x1c, + 0xe7,0x08,0x67,0xfc,0x96,0x0e,0xb3,0xd6,0xc4,0x3e,0x77,0xdc,0xd2,0x45,0xbd,0xe7, + 0x8d,0x3e,0x58,0x20,0xf1,0x70,0xe4,0x3f,0x4d,0x8b,0x13,0x22,0x21,0xb9,0xca,0xc0, + 0x65,0x18,0x66,0x3c,0xf5,0x3e,0x0d,0xca,0xfd,0x73,0x26,0xfd,0xff,0x33,0x34,0x55, + 0x4b,0xc3,0xf2,0x5b,0x1b,0xcd,0x89,0x04,0x87,0x7a,0x41,0xdb,0xa8,0x10,0x63,0xba, + 0x56,0xce,0xdd,0xcb,0xff,0xee,0x55,0xd4,0x33,0x6a,0x4c,0x5e,0x7f,0x11,0x0a,0xfb, + 0xd3,0x16,0xc2,0x2c,0x9d,0xc3,0x44,0x68,0x3d,0x52,0xed,0xf2,0x34,0x9d,0x25,0x71, + 0xee,0x3b,0xa5,0x77,0x3a,0x54,0x7f,0x53,0x2e,0x64,0x52,0xd4,0x9f,0x56,0x0b,0x63, + 0xc9,0x9d,0x79,0x67,0x3b,0x55,0xab,0x3a,0x47,0xa1,0x5f,0xa9,0xab,0x5e,0x42,0x8b, + 0xcf,0x57,0xfb,0x17,0x35,0xb6,0x6b,0x37,0x65,0x76,0xeb,0x35,0xf0,0x26,0x73,0xa0, + 0x25,0x38,0xf3,0x07,0x34,0x1e,0x6b,0xc0,0x8f,0x7b,0xda,0x46,0x27,0xb3,0xc0,0xb1, + 0xd3,0x9b,0xba,0x52,0x34,0x1f,0x0c,0x66,0x7a,0x1c,0xaa,0x6e,0xe4,0x5f,0x2a,0x47, + 0xce,0x97,0x8d,0x27,0x2d,0xb6,0xdc,0xe1,0x6d,0xb1,0xa2,0x67,0xe5,0x5e,0xd1,0xb0, + 0x5b,0x99,0x23,0xc6,0xdd,0xa4,0x55,0xfa,0x2e,0x94,0xb0,0x05,0x76,0x06,0x33,0x31, + 0xa3,0x12,0xbd,0xda,0x93,0x1a,0x43,0x8d,0x44,0xb2,0x3f,0x37,0x9c,0x15,0x14,0x9a, + 0xa9,0x8e,0xf0,0xdf,0x5e,0xb3,0x64,0x4a,0x3e,0x2d,0xc8,0x98,0x97,0x1d,0x70,0x95, + 0x7f,0xd7,0x99,0xa3,0xce,0xfb,0x45,0x3e,0x71,0x5a,0x8c,0xf8,0xef,0x56,0x04,0x91, + 0x74,0x2e,0xe4,0xb0,0xdc,0x65,0x25,0x55,0x14,0xd9,0xe9,0x9c,0xec,0x55,0x4e,0x3b, + 0x7b,0x24,0x2a,0x2f,0x40,0x1a,0x80,0x8a,0x4c,0x24,0x9c,0x4e,0x25,0xbb,0xd5,0x28, + 0x46,0xde,0xa6,0xff,0x1c,0x43,0x48,0x95,0xcd,0xae,0xf2,0x1f,0x6c,0xea,0x2a,0x29, + 0x25,0xc0,0xfc,0x26,0x3f,0xff,0x16,0x7c,0x93,0x9c,0x7b,0x62,0x83,0xff,0x19,0x4f, + 0x5b,0x3d,0xdd,0x6a,0x49,0x0b,0xf7,0xeb,0x2b,0xd0,0xa9,0x66,0xdd,0xfd,0x71,0xea, + 0x8c,0x0e,0x6a,0x6f,0x42,0x1e,0x93,0x7b,0x13,0xff,0x24,0xff,0x07,0x7e,0x5b,0x00, + 0x06,0x70,0x7f,0xa1,0xda,0x2d,0x75,0xce,0xd9,0xbd,0x55,0x57,0x7a,0x63,0xf7,0x6e, + 0x2f,0xde,0x77,0x6a,0x3f,0xfe,0x9a,0xdd,0x49,0x1a,0x47,0xb6,0xd1,0xe1,0x53,0x7e, + 0xe8,0x0f,0x7a,0x7a,0xf8,0x2f,0x3c,0xcc,0xc8,0x46,0xa9,0x31,0xa7,0x74,0xb6,0x21, + 0x00,0xac,0x36,0x24,0xd7,0x8c,0x7c,0xd8,0xc2,0x37,0x42,0xbf,0xae,0x61,0xc0,0x07, + 0x2c,0xd8,0x82,0xb7,0x50,0xaf,0x94,0x5a,0x2a,0xd9,0x11,0x7e,0x39,0x06,0x5a,0x02, + 0xe8,0xe7,0x0e,0x26,0x79,0xe7,0xdc,0x74,0x0f,0x04,0x18,0x68,0x38,0x57,0x95,0x1f, + 0x11,0x39,0xc0,0x74,0xdc,0x89,0xbd,0xf3,0xc2,0x4c,0xd5,0x67,0xe2,0xcd,0xf2,0xe1, + 0x5b,0xa8,0xb7,0xc1,0x5b,0x85,0x7f,0xf9,0x05,0xe3,0xea,0x84,0xc5,0x32,0xc7,0x76, + 0x6a,0xec,0x40,0x72,0x72,0x8a,0x55,0x26,0x1e,0x7c,0x31,0xbc,0x84,0xca,0x34,0x98, + 0x61,0xf8,0xcf,0xef,0x03,0xf4,0xd9,0x13,0x17,0x0b,0x5c,0x7e,0xd9,0xc2,0x7d,0x85, + 0x08,0x0b,0xfd,0x9c,0x65,0x8b,0xd4,0x06,0x92,0x1f,0xcd,0xb9,0x00,0xc1,0xf4,0x6b, + 0xa7,0xd4,0xdd,0x95,0x72,0x39,0x9e,0xb4,0x36,0x28,0xec,0x38,0xc7,0xc6,0x80,0x3b, + 0x2c,0x0f,0x62,0x5f,0x58,0x48,0x17,0xff,0x21,0xea,0x8c,0xe9,0x52,0x68,0x4b,0xb5, + 0x03,0x56,0xf2,0xaf,0x15,0x2e,0x7c,0xfc,0x9d,0xe9,0x84,0xf5,0xab,0xc6,0x7b,0x68, + 0xa8,0x9e,0xfb,0xbe,0x9c,0x4b,0x57,0x98,0x08,0x6e,0x12,0x9c,0xdc,0x9e,0x2e,0xb0, + 0x88,0x0b,0x28,0xa6,0xc9,0x6f,0x9f,0xe6,0xa0,0xf9,0x1a,0x2b,0xb0,0x0d,0x12,0xe2, + 0xdf,0xcd,0xc4,0xbb,0x38,0x5c,0x50,0xd3,0x6a,0x3e,0xac,0xb0,0x07,0x66,0xc9,0x63, + 0x3f,0xcc,0xab,0x15,0xcc,0xb0,0x3a,0x24,0xe5,0xf5,0x47,0x3e,0x0e,0x7b,0xd1,0x7f, + 0x5d,0xb3,0xad,0x47,0x6c,0x30,0x77,0xa1,0xe1,0xeb,0x4a,0x67,0x70,0xf2,0x5b,0x1d, + 0x4a,0x41,0xcd,0x66,0xab,0xbe,0x5b,0xb6,0x40,0x8c,0x3e,0x25,0x2d,0xd1,0x16,0x4b, + 0x95,0x28,0x06,0xc5,0x59,0xd6,0x0a,0xfa,0x62,0xf0,0x2f,0xc3,0xd3,0x8b,0x6c,0xc4, + 0x1c,0x35,0xec,0xc9,0x58,0xb7,0xde,0x36,0xf1,0x51,0xe9,0x7c,0x75,0x05,0xfa,0x8a, + 0x9d,0x36,0xa4,0x34,0xa0,0x31,0xc3,0xfa,0x89,0x22,0x60,0x71,0x46,0x94,0x94,0x5a, + 0x98,0x1d,0xac,0x24,0xf9,0x35,0x5a,0xb7,0x71,0xfc,0x96,0x0e,0x03,0x78,0x38,0x2c, + 0x0a,0x15,0xd4,0x07,0xd3,0x2a,0xa2,0xca,0x97,0x2d,0xa8,0x34,0x8c,0x0a,0xd3,0x99, + 0x1e,0x2f,0x8e,0x9e,0x3d,0xc2,0x5b,0x3c,0x75,0xc3,0x35,0x19,0xac,0x67,0x13,0x29, + 0xf8,0x0a,0xd7,0x85,0xf8,0xc1,0xd1,0x87,0xfa,0x6f,0xce,0xa9,0x75,0x19,0x52,0x59, + 0x29,0xcb,0x0f,0x82,0xaf,0xce,0x60,0x83,0x4a,0x19,0xe2,0x8d,0x78,0xd4,0xe3,0x51, + 0xbe,0xce,0x98,0x58,0x32,0x97,0x75,0xe8,0xa2,0xbd,0x16,0xf4,0x29,0xd8,0xff,0x44, + 0x93,0xef,0x9e,0xaf,0x39,0xbf,0xb6,0x72,0x08,0x7d,0x7a,0x82,0xd8,0x18,0x62,0x54, + 0x16,0xac,0x01,0x47,0xd1,0x2c,0x70,0x18,0x76,0xbe,0x16,0xeb,0x32,0x4c,0x8f,0xd4, + 0xb5,0xe0,0xd7,0x50,0xf9,0x36,0x49,0x64,0x00,0xad,0x60,0x1f,0x98,0x3f,0x17,0x32, + 0x77,0x80,0x9e,0x96,0x7f,0xaf,0x56,0x40,0xb3,0x3d,0xe4,0x86,0xf5,0x20,0x3e,0x70, + 0xfa,0x5c,0xbe,0x9b,0xfe,0xd3,0xec,0xcc,0xb8,0x60,0x98,0x26,0x22,0xf7,0xe1,0x0e, + 0xe6,0x7f,0x21,0x35,0x60,0xad,0x27,0x41,0x3b,0x1f,0x6a,0xad,0xab,0xe5,0xfd,0xed, + 0x78,0x02,0x12,0xa6,0x83,0x0c,0xfb,0xc0,0x83,0x1e,0x66,0x97,0x01,0x61,0xe3,0x31, + 0x3a,0x05,0x62,0x41,0x4c,0xe4,0x71,0x10,0xad,0x52,0x70,0x64,0x06,0x4f,0x0d,0xbc, + 0x9e,0x78,0x08,0x69,0x33,0xcb,0xbe,0x45,0x2c,0x60,0xcb,0x87,0x41,0xf9,0x29,0xbc, + 0x67,0x05,0xe7,0xb6,0x15,0xa8,0x57,0xf7,0x22,0x62,0x31,0x7a,0xbd,0xd4,0x44,0xbe, + 0x8f,0xf3,0xa9,0x68,0x9f,0xcb,0x59,0x00,0xaf,0x6c,0xa7,0xf2,0xd3,0x6a,0x0a,0xf9, + 0x12,0x55,0x63,0x9f,0x16,0xac,0x64,0xbb,0xa7,0x6a,0x15,0xbf,0x37,0x2a,0x9d,0x82, + 0xf0,0xea,0x2e,0x82,0x9e,0xa7,0x7f,0x44,0x27,0xdb,0x9a,0xeb,0xa7,0xa9,0x71,0x1c, + 0x67,0xd8,0x80,0x9e,0x9a,0xea,0x8c,0x1a,0xd6,0x65,0x94,0xde,0x92,0x66,0x4d,0x79, + 0x7a,0x76,0x4b,0x20,0xb9,0xc5,0x45,0xb3,0x05,0x9a,0x2e,0x4c,0xf7,0xe8,0x25,0x44, + 0x58,0xb8,0xca,0x8c,0xc2,0xae,0x0a,0x62,0xae,0x63,0x8c,0xef,0xb7,0xce,0x69,0xda, + 0xe6,0xfc,0xae,0xaf,0x5d,0xbb,0x38,0x09,0x45,0xcc,0xb2,0x6d,0x15,0xa9,0xa4,0x49, + 0xd0,0x8d,0xdd,0xee,0xbc,0xa3,0x41,0x18,0xcc,0xc5,0x5f,0xfc,0xd8,0xe4,0x79,0x9b, + 0x70,0x02,0xb5,0xce,0x1d,0x04,0x43,0x66,0x4a,0xd9,0xdd,0xef,0x53,0xe2,0x1a,0xaf, + 0x44,0x9a,0x32,0x7a,0x34,0x05,0x37,0x7a,0xac,0xa2,0x72,0xd8,0x16,0x44,0xd5,0xd9, + 0xd8,0xad,0x29,0x26,0xc8,0x10,0x87,0x50,0xc9,0x2c,0x82,0x17,0x57,0xfc,0xda,0xf1, + 0xc6,0xa4,0xb3,0x7f,0xb4,0xf0,0x95,0xb0,0xf2,0xb6,0xcb,0x33,0x74,0xc3,0xf0,0x92, + 0x39,0x21,0x95,0x64,0xe7,0x6e,0x45,0x43,0xed,0x72,0x3f,0x4b,0x67,0x08,0xb0,0x51, + 0x87,0x4b,0x76,0x56,0x17,0x97,0x4e,0x53,0x30,0x7b,0xe2,0x77,0x9d,0x56,0xd7,0x77, + 0xd0,0x68,0xee,0x36,0x76,0x1e,0x49,0x6f,0x61,0xa5,0xbe,0x06,0x73,0x54,0xda,0xf2, + 0x07,0x69,0xa7,0xa7,0xc4,0x37,0xb6,0xcc,0xbc,0x89,0xcf,0x56,0xb4,0x59,0x7b,0x42, + 0x4c,0x35,0x2d,0xcb,0xdc,0x85,0xb8,0x0c,0xc9,0x71,0xbc,0x04,0xe5,0x7a,0x87,0x16, + 0xb4,0x6a,0x72,0x7d,0x22,0x03,0xf1,0x59,0x32,0x55,0xce,0xac,0x3c,0x23,0x6e,0xe9, + 0x11,0x18,0x6f,0x5e,0x31,0xf9,0x8b,0x23,0xda,0xec,0xfc,0xa1,0x37,0x54,0x07,0x16, + 0x8e,0x0a,0xa5,0xf4,0x33,0x1c,0x61,0x37,0x07,0x08,0xd6,0x52,0xdf,0x2e,0x67,0x64, + 0x4c,0x18,0x29,0xab,0x47,0x3b,0xf8,0x3f,0xf1,0xa9,0xfc,0x81,0xe3,0xe0,0xdd,0x7b, + 0x6c,0x33,0xd5,0x3f,0x28,0xb7,0x4e,0x14,0x93,0x7d,0xa0,0x7b,0x95,0x1e,0x10,0xdd, + 0x8e,0x32,0x3c,0x2f,0x39,0x4d,0x85,0x85,0x07,0x7f,0x7e,0xcc,0x8b,0xf2,0x25,0xd8, + 0xe4,0xda,0xb9,0x4a,0xb6,0xba,0x4f,0x14,0x1b,0xbd,0xc9,0x6a,0x95,0xf1,0xaf,0xfc, + 0x0e,0x30,0xb1,0x56,0x4f,0x14,0x01,0x6a,0x1a,0x7c,0xe9,0x73,0x14,0xad,0xbb,0xb1, + 0x1a,0xaf,0x9a,0x00,0x31,0x40,0x06,0xb8,0xab,0xd2,0x38,0x3c,0xd2,0x56,0x3d,0x63, + 0x03,0x88,0xe0,0x92,0xed,0x60,0xdd,0x43,0x7d,0xe0,0x9a,0xf2,0x45,0x65,0x44,0x10, + 0x8a,0x06,0x01,0x0d,0x9e,0x2c,0xaa,0x90,0xde,0xed,0xd9,0x47,0xf2,0xaf,0x0b,0x71, + 0x8d,0x43,0xa1,0x77,0x10,0x2c,0x0a,0xc2,0xc7,0xce,0x19,0x73,0xc5,0x65,0x10,0x5f, + 0x6e,0x1f,0xfa,0xc3,0xbe,0x38,0x38,0x67,0xc1,0x4b,0x34,0x97,0xf1,0xef,0xd1,0xb8, + 0xbc,0x48,0xe6,0x53,0x86,0x2a,0xef,0x98,0xbc,0xc8,0x3f,0x87,0xf0,0x38,0x39,0x33, + 0x25,0x02,0xef,0x43,0x03,0x7a,0x39,0x03,0xe4,0x0a,0xd5,0xe2,0xf6,0x1b,0x37,0xf4, + 0x91,0x4a,0x7d,0x1f,0x5a,0x63,0xa3,0xbb,0x38,0xec,0x3a,0x31,0x70,0x5a,0x07,0x1d, + 0xf3,0xb5,0xaa,0x0b,0x99,0x6c,0x6c,0xa9,0xa1,0x6a,0xf7,0xec,0xf9,0xe2,0x39,0xe9, + 0x5f,0x18,0x8b,0x9e,0x18,0xd6,0x04,0x4b,0x6d,0x42,0x41,0x28,0x22,0x6f,0x5b,0x45, + 0xe3,0xb8,0xab,0xcf,0xf3,0x24,0xbf,0xba,0xce,0x40,0x44,0xcf,0xa7,0x6a,0x55,0x94, + 0x79,0xa0,0xb3,0x3d,0x38,0x4b,0xdd,0x2a,0x9b,0x0f,0xc0,0x3d,0x5b,0x23,0xbd,0xe8, + 0xe7,0x8c,0xeb,0x02,0xd3,0x48,0x62,0x37,0x21,0x78,0xb5,0x28,0xf9,0x71,0x91,0x58, + 0xdf,0x4c,0x74,0x5e,0xed,0x5a,0xda,0x74,0x8c,0x0d,0x36,0xfc,0xa7,0x4d,0x98,0x48, + 0x0a,0x4e,0x6a,0x92,0x23,0xf0,0x53,0x98,0x42,0xb1,0xb0,0x3c,0x79,0x2f,0xf4,0xf9, + 0x6e,0x8f,0xcf,0x49,0x03,0x6b,0x58,0x78,0x2a,0x29,0x77,0x3f,0x58,0xbb,0x41,0x1f, + 0x4b,0x42,0x3c,0x77,0x58,0x22,0xd5,0xa6,0xa8,0x62,0x84,0xc6,0xc3,0x15,0x34,0x6f, + 0xc8,0xd2,0x34,0x6b,0x3f,0x77,0xdc,0xbd,0x24,0xf1,0x65,0x93,0xd0,0x0e,0x6f,0xf2, + 0xce,0xb3,0x3d,0x76,0xc8,0x20,0xb1,0xdf,0x3c,0x5d,0xad,0x4e,0x5c,0x7f,0xd9,0x6f, + 0x5c,0xb2,0x8a,0xea,0x93,0xde,0xde,0xc2,0xb7,0x58,0x31,0x31,0xed,0x97,0x96,0x48, + 0x87,0xbb,0xe3,0x26,0xd2,0xe5,0x7d,0xe7,0x63,0xd4,0x5b,0x60,0x2a,0x66,0x32,0x60, + 0x33,0x58,0xb5,0xf3,0x92,0x24,0xd6,0x06,0xbc,0xd8,0x9d,0xcb,0x45,0x37,0x93,0x29, + 0x45,0x5b,0x3e,0xe1,0x7b,0x39,0x2f,0x35,0x62,0x76,0x62,0x4c,0xf4,0xc6,0x33,0x60, + 0x81,0x07,0xb5,0x86,0x10,0x28,0x7d,0xfc,0xeb,0x17,0xda,0x7d,0x0f,0xe4,0xc7,0x7b, + 0x3e,0xc5,0x02,0x4b,0xb8,0x18,0x96,0xb9,0x32,0xf7,0xce,0x0d,0x13,0x49,0x30,0xa5, + 0x41,0x1a,0xde,0xea,0x35,0x57,0x26,0x47,0x47,0xff,0x63,0xda,0x92,0x88,0x51,0x00, + 0x43,0x28,0x2b,0x0b,0xa8,0xc7,0xb7,0xba,0xb2,0x3e,0x93,0xaf,0x88,0x61,0x71,0x1d, + 0x29,0xea,0xaf,0x9c,0x34,0x7d,0x27,0x47,0x14,0xfa,0xde,0xdb,0x12,0x78,0x87,0xbb, + 0x0c,0x1f,0xf8,0xca,0x70,0x78,0x54,0xe0,0x68,0x5d,0xf6,0x65,0x86,0x0f,0xdd,0x78, + 0x7b,0x0d,0xf6,0x74,0x98,0x7c,0x32,0x8a,0x1c,0x7d,0x18,0xd3,0x2a,0xdd,0x7f,0xc1, + 0x62,0x1d,0x9f,0xc9,0xf0,0x5a,0x5f,0xeb,0x68,0xee,0x91,0x40,0x07,0x77,0x6f,0x59, + 0x63,0xee,0x3a,0xdc,0xaf,0x0b,0xbb,0x99,0x19,0x3a,0x54,0x8e,0xae,0x2a,0x63,0xe2, + 0xcc,0x52,0x20,0x0a,0x67,0xbb,0x16,0xaf,0xc8,0xcd,0xa0,0x44,0xe7,0x85,0x10,0xed, + 0x2b,0x27,0x2c,0x12,0x0d,0x4f,0xf9,0x34,0x8d,0xf3,0x41,0x11,0xf4,0x9e,0x81,0x10, + 0xde,0xe6,0xdb,0x61,0xd6,0xa9,0xce,0x04,0x65,0x66,0x89,0xcc,0x78,0xef,0x11,0xed, + 0x78,0x22,0xbb,0x26,0xb6,0xc3,0x9d,0x6c,0x66,0xa6,0x15,0xb3,0xc9,0x07,0xbf,0x43, + 0x86,0xc4,0x41,0x41,0xb7,0xe5,0xc4,0x88,0xa7,0xa2,0xa5,0x79,0x60,0x50,0x31,0xbc, + 0xa2,0x7a,0x1d,0xa8,0x13,0xc8,0x58,0x73,0xe0,0xd5,0xf3,0x76,0x3c,0x5d,0xbe,0x43, + 0x5a,0xa5,0xa9,0x43,0x7b,0xe7,0xc5,0x23,0xca,0x09,0x24,0x68,0xa4,0x4d,0x39,0x20, + 0xc7,0x5c,0x79,0x5c,0x13,0xf3,0x96,0x81,0x47,0xf6,0xf9,0x86,0x82,0x54,0x1a,0xf5, + 0xf9,0xeb,0x22,0x02,0x04,0x29,0x8d,0xc8,0xcc,0x2a,0xea,0x3e,0xb7,0xd9,0x54,0x82, + 0xf8,0x2a,0x2b,0xfb,0x2e,0xd6,0xff,0x3d,0xec,0x16,0x61,0x2a,0x26,0xef,0xd8,0x74, + 0xe4,0x18,0xc8,0x6f,0x90,0xea,0x15,0xb3,0x48,0x6e,0x93,0x76,0xa3,0xca,0xee,0xe8, + 0x93,0x20,0x13,0xec,0xad,0xb9,0x8f,0x59,0x32,0x6f,0xe0,0x3f,0x5f,0xa3,0x66,0x48, + 0x0a,0x57,0x46,0x3c,0x90,0xed,0x48,0xed,0xe2,0xd3,0x2d,0x90,0x29,0x1b,0x20,0xc7, + 0xe4,0x9e,0xdb,0xbc,0xc2,0x39,0x53,0x3d,0x61,0x41,0xe2,0x88,0xb6,0x9e,0x63,0x55, + 0xa8,0x73,0x5c,0x54,0x3d,0x2b,0x39,0x7e,0xae,0x5e,0x33,0x77,0x26,0x13,0x32,0xb0, + 0x2a,0x20,0x93,0x6d,0xaf,0x73,0x31,0x66,0x8e,0xce,0xe9,0x18,0x20,0x40,0x7a,0x1b, + 0xd4,0x3b,0x21,0x6e,0x87,0xfd,0x0c,0x5d,0x91,0xb3,0xf5,0xc0,0x9f,0x81,0x1f,0x63, + 0x77,0x5d,0x40,0x94,0x3d,0xdd,0x42,0x2a,0x90,0x72,0x82,0x8b,0x1d,0xf2,0xe6,0x47, + 0xcf,0xe0,0x5a,0x27,0x5d,0xd2,0xce,0xdc,0x8c,0x40,0xf4,0xc1,0x1f,0x63,0x0b,0x0f, + 0x21,0x37,0x4d,0x9e,0x48,0x39,0xf8,0x40,0xfb,0x58,0xc3,0x83,0x1c,0x82,0xf7,0x62, + 0x76,0x34,0x44,0xc8,0xba,0xb9,0x8b,0x32,0x18,0xd7,0xfb,0x06,0x72,0x54,0x6d,0xd0, + 0x2b,0x31,0x7c,0x16,0x73,0x51,0x87,0x80,0xe9,0xb0,0x79,0x7b,0x88,0xb7,0x43,0xfb, + 0x92,0x92,0x9b,0x25,0x1a,0xbb,0x4b,0xea,0xa5,0x24,0xfa,0x77,0x4d,0xb4,0xfa,0xef, + 0x6f,0xe6,0x95,0xde,0x5a,0x85,0x65,0xf2,0xb3,0x2b,0xfa,0x7f,0x77,0xba,0x61,0x8d, + 0x8d,0x67,0x65,0xc9,0x32,0x17,0xb6,0x9b,0x7a,0x77,0xa0,0x96,0x97,0x79,0x91,0xab, + 0x8c,0x66,0x96,0x3e,0xd0,0x39,0x40,0x33,0x25,0xfb,0xee,0xfe,0x3d,0x0c,0xf3,0x18, + 0x0d,0x45,0x33,0x0d,0x26,0xb0,0xf6,0xd9,0x86,0xe8,0x89,0x92,0x73,0x5c,0x94,0x3e, + 0x5a,0x66,0x47,0x87,0x3d,0xfb,0x1f,0x29,0xb5,0x66,0x28,0xbd,0xf9,0x0e,0xf7,0x0c, + 0x2e,0x9a,0x76,0x61,0xc9,0x5c,0x3c,0xa8,0x06,0xd1,0xc8,0xb3,0x9d,0x03,0x16,0x7a, + 0xd0,0x22,0x52,0x57,0x1b,0x89,0x44,0x7d,0xc3,0x82,0x09,0x00,0x9e,0xf2,0x6f,0xa5, + 0xcd,0xbe,0x5b,0x3c,0x1d,0x8e,0x6f,0xc1,0xef,0xc9,0x37,0xf6,0xec,0xf8,0x07,0x19, + 0x2c,0xdb,0x4f,0xd1,0x33,0x32,0x45,0x7c,0x43,0xc0,0x97,0x3d,0x79,0x0a,0x90,0x46, + 0xfc,0xab,0xc4,0x80,0x10,0xe1,0xeb,0x3b,0xbf,0xeb,0x26,0x46,0xa7,0x66,0xf4,0xe0, + 0x09,0x0e,0x48,0x10,0xe2,0x25,0x9c,0xc1,0xfe,0xc1,0x7b,0x73,0x8f,0x69,0x70,0x00, + 0x02,0x0a,0xa1,0x1d,0x6c,0x41,0xec,0x88,0xe2,0x9d,0x99,0x12,0x71,0x0e,0xe1,0x3b, + 0x06,0xf6,0x8f,0x2a,0xbf,0x61,0x47,0xde,0xc7,0xe8,0x1d,0xf2,0x51,0x43,0x40,0x40, + 0x02,0x04,0xc0,0x44,0x12,0x24,0x50,0x60,0x42,0x44,0xd0,0x64,0x52,0x64,0x48,0x50, + 0x03,0x05,0xc8,0x54,0x13,0x25,0x58,0x70,0x43,0x45,0xd8,0x74,0x53,0x65,0x41,0x41, + 0x82,0x06,0xc1,0x45,0x92,0x26,0x51,0x61,0xc2,0x46,0xd1,0x65,0xd2,0x66,0x49,0x51, + 0x83,0x07,0xc9,0x55,0x93,0x27,0x59,0x71,0xc3,0x47,0xd9,0x75,0xd3,0x67,0x62,0x4c, + 0x04,0x83,0x04,0x21,0x2b,0x27,0xef,0xb9,0x23,0x37,0x3e,0xec,0xfb,0x29,0x8a,0x7a, + 0x48,0x49,0xea,0x7c,0x53,0x24,0x44,0xd7,0x1b,0xe2,0x36,0x7e,0xda,0xc4,0x84,0xeb, + 0x0a,0x42,0xd9,0x08,0x3f,0x6b,0x90,0x89,0x7b,0xf5,0x7f,0xad,0x24,0x4a,0x73,0x7b, + 0xca,0xd4,0x27,0x8f,0x98,0x21,0xe6,0x3c,0xa2,0x34,0x8b,0xdd,0x91,0x6b,0x42,0x48, + 0x0a,0x0c,0xc2,0x4c,0x1a,0x2c,0x52,0x68,0x4a,0x4c,0xd2,0x6c,0x5a,0x6c,0x4a,0x58, + 0x0b,0x0d,0xca,0x5c,0x1b,0x2d,0x5a,0x78,0x4b,0x4d,0xda,0x7c,0x5b,0x6d,0x43,0x49, + 0x8a,0x0e,0xc3,0x4d,0x9a,0x2e,0x53,0x69,0xca,0x4e,0xd3,0x6d,0xda,0x6e,0x4b,0x59, + 0x8b,0x0f,0xcb,0x5d,0x9b,0x2f,0x5b,0x79,0xcb,0x4f,0xdb,0x7d,0xdb,0x6f,0xdf,0xf2, + 0x9f,0xaf,0x68,0x04,0xcc,0x10,0xb4,0xb3,0x63,0x34,0xf6,0x24,0x70,0x30,0x6d,0xe2, + 0xde,0xce,0xb4,0x67,0x33,0x95,0x3c,0xb1,0xec,0x17,0x26,0xb6,0xde,0x77,0xfa,0x7f, + 0xa6,0x62,0x29,0x07,0xb1,0x27,0x2d,0x41,0xec,0x3c,0xb5,0x4f,0xf6,0xe2,0xcd,0x89, + 0x59,0x9e,0xe2,0x14,0x79,0xed,0x9e,0x11,0xb5,0x63,0x95,0x6a,0x10,0x7c,0x44,0xc0, + 0x22,0x14,0xc4,0xc4,0x32,0x34,0x54,0xe0,0x62,0x54,0xd4,0xe4,0x72,0x74,0x4c,0xd0, + 0x23,0x15,0xcc,0xd4,0x33,0x35,0x5c,0xf0,0x63,0x55,0xdc,0xf4,0x73,0x75,0x45,0xc1, + 0xa2,0x16,0xc5,0xc5,0xb2,0x36,0x55,0xe1,0xe2,0x56,0xd5,0xe5,0xf2,0x76,0x4d,0xd1, + 0xa3,0x17,0xcd,0xd5,0xb3,0x37,0x5d,0xf1,0xe3,0x57,0xdd,0xf5,0xf3,0x77,0xf9,0x76, + 0x2e,0xa8,0x46,0x9f,0xe7,0x5a,0x30,0x69,0xec,0xfc,0x06,0xad,0x58,0x78,0xce,0x98, + 0x6d,0x58,0x3d,0x18,0xc1,0x1b,0x66,0x3c,0x31,0x25,0x9e,0xbc,0x79,0x79,0x32,0xfb, + 0x57,0xc5,0x67,0xb2,0x44,0x58,0x5f,0xae,0x8b,0x7a,0x97,0xad,0xf8,0x7a,0xe3,0x19, + 0x55,0x3b,0xbc,0x1d,0x9d,0x55,0xaf,0xa5,0x08,0x38,0x9f,0xbd,0xf9,0x7b,0x46,0xc8, + 0x2a,0x1c,0xc6,0xcc,0x3a,0x3c,0x56,0xe8,0x6a,0x5c,0xd6,0xec,0x7a,0x7c,0x4e,0xd8, + 0x2b,0x1d,0xce,0xdc,0x3b,0x3d,0x5e,0xf8,0x6b,0x5d,0xde,0xfc,0x7b,0x7d,0x47,0xc9, + 0xaa,0x1e,0xc7,0xcd,0xba,0x3e,0x57,0xe9,0xea,0x5e,0xd7,0xed,0xfa,0x7e,0x4f,0xd9, + 0xab,0x1f,0xcf,0xdd,0xbb,0x3f,0x5f,0xf9,0xeb,0x5f,0xdf,0xfd,0xfb,0x7f,0x58,0x80, + 0x01,0x60,0x5e,0x84,0xea,0x1f,0x60,0x82,0xf7,0x7f,0xee,0x31,0x5c,0xe0,0xa0,0x06, + 0xa4,0x09,0xd6,0x10,0xf4,0x22,0x50,0xf0,0xc3,0x34,0x28,0xf1,0x57,0x14,0x7b,0x1e, + 0x27,0x84,0x99,0xf9,0xf4,0xae,0x82,0xdd,0x38,0x3d,0xd9,0xe5,0x52,0x17,0xa9,0xf1, + 0x24,0x09,0xde,0xe4,0x19,0x5e,0xa9,0xf4,0xc7,0x36,0xbd,0x70,0x54,0xed,0x60,0x42, + 0x06,0x84,0xe0,0x46,0x16,0xa4,0x70,0x62,0x46,0xc4,0xf0,0x66,0x56,0xe4,0x68,0x52, + 0x07,0x85,0xe8,0x56,0x17,0xa5,0x78,0x72,0x47,0xc5,0xf8,0x76,0x57,0xe5,0x61,0x43, + 0x86,0x86,0xe1,0x47,0x96,0xa6,0x71,0x63,0xc6,0xc6,0xf1,0x67,0xd6,0xe6,0x69,0x53, + 0x87,0x87,0xe9,0x57,0x97,0xa7,0x79,0x73,0xc7,0xc7,0xf9,0x77,0xd7,0xe7,0xd9,0xe8, + 0x0a,0x38,0xda,0x70,0x5c,0x22,0x36,0x6d,0xcd,0xc6,0x0d,0x8e,0xfd,0x48,0xba,0x9e, + 0x55,0x81,0xd2,0x9c,0x3c,0xdb,0xfa,0x23,0x12,0x34,0x39,0xfc,0xde,0xaf,0xd0,0x6b, + 0xec,0x81,0x74,0x8d,0x62,0x15,0x90,0xeb,0x10,0xe0,0x34,0x90,0xdc,0xca,0xf4,0x17, + 0x8b,0x3b,0xf1,0x1e,0x3e,0xea,0x23,0xd5,0x05,0xe1,0x0c,0x1b,0xdb,0x5b,0x62,0x4a, + 0x0e,0x8c,0xe2,0x4e,0x1e,0xac,0x72,0x6a,0x4e,0xcc,0xf2,0x6e,0x5e,0xec,0x6a,0x5a, + 0x0f,0x8d,0xea,0x5e,0x1f,0xad,0x7a,0x7a,0x4f,0xcd,0xfa,0x7e,0x5f,0xed,0x63,0x4b, + 0x8e,0x8e,0xe3,0x4f,0x9e,0xae,0x73,0x6b,0xce,0xce,0xf3,0x6f,0xde,0xee,0x6b,0x5b, + 0x8f,0x8f,0xeb,0x5f,0x9f,0xaf,0x7b,0x7b,0xcf,0xcf,0xfb,0x7f,0xdf,0xef,0x88,0xc0, + 0xa7,0x44,0xe4,0xb9,0x3c,0xdc,0xcb,0x60,0xe7,0x96,0xb4,0xa6,0x74,0xf0,0xd1,0x3b, + 0x07,0x4e,0x43,0x66,0x6d,0xbe,0x2e,0x12,0x3d,0x83,0xbc,0xb6,0x75,0xf1,0xde,0x9c, + 0x5b,0x39,0x8d,0x45,0x36,0xba,0x82,0x87,0xc6,0xe2,0xb5,0xa7,0xf4,0xf2,0xa9,0x62, + 0x1a,0x13,0xcd,0xd7,0x4e,0xbe,0x0a,0x1b,0x19,0xb0,0xbd,0xb7,0xf5,0xf3,0x64,0xc2, + 0x26,0x94,0xe4,0xc6,0x36,0xb4,0x74,0xe2,0x66,0xd4,0xf4,0xe6,0x76,0xf4,0x6c,0xd2, + 0x27,0x95,0xec,0xd6,0x37,0xb5,0x7c,0xf2,0x67,0xd5,0xfc,0xf6,0x77,0xf5,0x65,0xc3, + 0xa6,0x96,0xe5,0xc7,0xb6,0xb6,0x75,0xe3,0xe6,0xd6,0xf5,0xe7,0xf6,0xf6,0x6d,0xd3, + 0xa7,0x97,0xed,0xd7,0xb7,0xb7,0x7d,0xf3,0xe7,0xd7,0xfd,0xf7,0xf7,0xf7,0x78,0x65, + 0x2a,0x33,0xd4,0x97,0x7c,0x43,0xf6,0xbb,0x12,0x75,0xb6,0xae,0x7c,0xf8,0x2d,0x3a, + 0x9e,0x26,0xae,0x5c,0xbe,0xff,0x66,0x32,0x84,0xca,0xbe,0xbe,0x7d,0xf9,0xda,0x1a, + 0xc7,0xe5,0xa3,0x8d,0xb8,0x41,0x26,0x3b,0x85,0xb9,0xb7,0xaf,0xfc,0xfa,0x71,0x74, + 0xbb,0x0f,0x18,0xbb,0x3f,0xb3,0x93,0x29,0xe9,0xd3,0xbf,0xbf,0xfd,0xfb,0x66,0xca, + 0x2e,0x9c,0xe6,0xce,0x3e,0xbc,0x76,0xea,0x6e,0xdc,0xf6,0xee,0x7e,0xfc,0x6e,0xda, + 0x2f,0x9d,0xee,0xde,0x3f,0xbd,0x7e,0xfa,0x6f,0xdd,0xfe,0xfe,0x7f,0xfd,0x67,0xcb, + 0xae,0x9e,0xe7,0xcf,0xbe,0xbe,0x77,0xeb,0xee,0xde,0xf7,0xef,0xfe,0xfe,0x6f,0xdb, + 0xaf,0x9f,0xef,0xdf,0xbf,0xbf,0x7f,0xfb,0xef,0xdf,0xff,0xff,0x88,0x9f,*/ +}; +#endif + +#endif \ No newline at end of file diff --git a/drivers/input/touchscreen/gt9xx_2/gt9xx_update.c b/drivers/input/touchscreen/gt9xx_2/gt9xx_update.c new file mode 100644 index 00000000000..4c5a63c052b --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2/gt9xx_update.c @@ -0,0 +1,1552 @@ +/* drivers/input/touchscreen/gt9xx_update.c + * + * 2010 - 2012 Goodix Technology. + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Latest Version:1.6 + * Author: andrew@goodix.com + * Revision Record: + * V1.0: + * first release. By Andrew, 2012/08/31 + * V1.2: + * add force update,GT9110P pid map. By Andrew, 2012/10/15 + * V1.4: + * 1. add config auto update function; + * 2. modify enter_update_mode; + * 3. add update file cal checksum. + * By Andrew, 2012/12/12 + * V1.6: + * 1. replace guitar_client with i2c_connect_client; + * 2. support firmware header array update. + * By Meta, 2013/03/11 + */ +#include "gt9xx.h" +#include +#include +#include + +#define FIRMWARE_NAME_LEN_MAX 256 + +#define GUP_REG_HW_INFO 0x4220 +#define GUP_REG_FW_MSG 0x41E4 +#define GUP_REG_PID_VID 0x8140 + +#define GOODIX_FIRMWARE_FILE_NAME "_goodix_update_.bin" +#define GOODIX_CONFIG_FILE_NAME "_goodix_config_.cfg" + +#define FW_HEAD_LENGTH 14 +#define FW_SECTION_LENGTH 0x2000 +#define FW_DSP_ISP_LENGTH 0x1000 +#define FW_DSP_LENGTH 0x1000 +#define FW_BOOT_LENGTH 0x800 + +#define PACK_SIZE 256 +#define MAX_FRAME_CHECK_TIME 5 + +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 + +#define FAIL 0 +#define SUCCESS 1 + +struct st_fw_head { + u8 hw_info[4]; /* hardware info */ + u8 pid[8]; /* product id */ + u16 vid; /* version id */ +} __packed; + +struct st_update_msg { + u8 force_update; + u8 fw_flag; + bool need_free; + u8 *fw_data; + u32 fw_len; + struct st_fw_head ic_fw_msg; +}; + +static struct st_update_msg update_msg; +u16 show_len; +u16 total_len; +u8 got_file_flag; +u8 searching_file; +/******************************************************* +Function: + Read data from the i2c slave device. +Input: + client: i2c device. + buf[0~1]: read start address. + buf[2~len-1]: read data buffer. + len: GTP_ADDR_LENGTH + read bytes count +Output: + numbers of i2c_msgs to transfer: + 2: succeed, otherwise: failed +*********************************************************/ +static s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len) +{ + s32 ret = -1; + u8 retries = 0; + struct i2c_msg msgs[2] = { + { + .flags = !I2C_M_RD, + .addr = client->addr, + .len = GTP_ADDR_LENGTH, + .buf = &buf[0], + }, + { + .flags = I2C_M_RD, + .addr = client->addr, + .len = len - GTP_ADDR_LENGTH, + .buf = &buf[GTP_ADDR_LENGTH], + }, + }; + + while (retries < 5) { + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret == 2) + break; + retries++; + } + + if (retries == 5) { + dev_err(&client->dev, "I2C read retry limit over.\n"); + ret = -EIO; + } + + return ret; +} + +/******************************************************* +Function: + Write data to the i2c slave device. +Input: + client: i2c device. + buf[0~1]: write start address. + buf[2~len-1]: data buffer + len: GTP_ADDR_LENGTH + write bytes count +Output: + numbers of i2c_msgs to transfer: + 1: succeed, otherwise: failed +*********************************************************/ +s32 gup_i2c_write(struct i2c_client *client, u8 *buf, s32 len) +{ + s32 ret = -1; + u8 retries = 0; + struct i2c_msg msg = { + .flags = !I2C_M_RD, + .addr = client->addr, + .len = len, + .buf = buf, + }; + + while (retries < 5) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret == 1) + break; + retries++; + } + + if (retries == 5) { + dev_err(&client->dev, "I2C write retry limit over.\n"); + ret = -EIO; + } + + return ret; +} + +static s32 gup_init_panel(struct goodix_ts_data *ts) +{ + struct i2c_client *client = ts->client; + u8 *config_data; + s32 ret = 0; + s32 i = 0; + u8 check_sum = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + + for (i = 0; i < GOODIX_MAX_CFG_GROUP; i++) + if (ts->pdata->config_data_len[i]) + break; + + if (i == GOODIX_MAX_CFG_GROUP) { + sensor_id = 0; + } else { + ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID, + &sensor_id, 1); + if (SUCCESS == ret) { + if (sensor_id >= GOODIX_MAX_CFG_GROUP) { + pr_err("Invalid sensor_id(0x%02X), No Config Sent!", + sensor_id); + return -EINVAL; + } + } else { + pr_err("Failed to get sensor_id, No config sent!"); + return -EINVAL; + } + } + + pr_debug("Sensor ID selected: %d", sensor_id); + + if (ts->pdata->config_data_len[sensor_id] < GTP_CONFIG_MIN_LENGTH || + !ts->pdata->config_data_len[sensor_id]) { + pr_err("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP!", + sensor_id); + return -EINVAL; + } + + ret = gtp_i2c_read_dbl_check(client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + pr_debug("CFG_GROUP%d Config Version: %d, IC Config Version: %d", + sensor_id + 1, + ts->pdata->config_data[sensor_id][0], + opr_buf[0]); + + ts->pdata->config_data[sensor_id][0] = opr_buf[0]; + ts->fixed_cfg = 0; + } else { + pr_err("Failed to get ic config version!No config sent!"); + return -EINVAL; + } + + config_data = ts->pdata->config_data[sensor_id]; + ts->config_data = ts->pdata->config_data[sensor_id]; + ts->gtp_cfg_len = ts->pdata->config_data_len[sensor_id]; + + pr_debug("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", + ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type); + + config_data[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH; + config_data[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8); + config_data[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT; + config_data[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8); + + if (GTP_INT_TRIGGER == 0) /* RISING */ + config_data[TRIGGER_LOC] &= 0xfe; + else if (GTP_INT_TRIGGER == 1) /* FALLING */ + config_data[TRIGGER_LOC] |= 0x01; + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++) + check_sum += config_data[i]; + + config_data[ts->gtp_cfg_len] = (~check_sum) + 1; + + ret = gtp_send_cfg(ts); + if (ret < 0) + pr_err("Send config error."); + + ts->config_data = NULL; + ts->gtp_cfg_len = 0; + msleep(20); + return 0; +} + +static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len) +{ + u8 i = 0; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + + for (i = 0; i < 5; i++) + if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) + break; + + if (i >= 5) { + pr_err("Read data from 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) +{ + u8 i = 0; + u8 msg[3] = { + (addr >> 8) & 0xff, + addr & 0xff, + val, + }; + + for (i = 0; i < 5; i++) + if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) + break; + + if (i >= 5) { + pr_err("Set data to 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_get_ic_fw_msg(struct i2c_client *client) +{ + s32 ret = -1; + u8 retry = 0; + u8 buf[16]; + u8 i; + + /* step1:get hardware info */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, + &buf[GTP_ADDR_LENGTH], 4); + if (ret == FAIL) { + pr_err("get hw_info failed,exit"); + return FAIL; + } + + /* buf[2~5]: 00 06 90 00 */ + /* hw_info: 00 90 06 00 */ + for (i = 0; i < 4; i++) + update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; + + pr_debug("IC Hardware info:%02x%02x%02x%02x", + update_msg.ic_fw_msg.hw_info[0], + update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], + update_msg.ic_fw_msg.hw_info[3]); + + /* step2:get firmware message */ + for (retry = 0; retry < 2; retry++) { + ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); + if (ret == FAIL) { + pr_err("Read firmware message fail."); + return ret; + } + + update_msg.force_update = buf[GTP_ADDR_LENGTH]; + if ((0xBE != update_msg.force_update) && (!retry)) { + pr_info("The check sum in ic is error."); + pr_info("The IC will be updated by force."); + continue; + } + break; + } + pr_debug("IC force update flag:0x%x", update_msg.force_update); + + /* step3:get pid & vid */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, + &buf[GTP_ADDR_LENGTH], 6); + if (ret == FAIL) { + pr_err("get pid & vid failed,exit"); + return FAIL; + } + + memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); + memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); + pr_debug("IC Product id:%s", update_msg.ic_fw_msg.pid); + + /* GT9XX PID MAPPING + |-----FLASH-----RAM-----| + |------918------918-----| + |------968------968-----| + |------913------913-----| + |------913P-----913P----| + |------927------927-----| + |------927P-----927P----| + |------9110-----9110----| + |------9110P----9111----|*/ + if (update_msg.ic_fw_msg.pid[0] != 0) { + if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) { + pr_debug("IC Mapping Product id:%s", + update_msg.ic_fw_msg.pid); + memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); + } + } + + update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] + + (buf[GTP_ADDR_LENGTH + 5] << 8); + pr_debug("IC version id:%04x", update_msg.ic_fw_msg.vid); + + return SUCCESS; +} + +s32 gup_enter_update_mode(struct i2c_client *client) +{ + s32 ret = -1; + u8 retry = 0; + u8 rd_buf[3]; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + /* step1:RST output low last at least 2ms */ + gpio_direction_output(ts->pdata->reset_gpio, 0); + usleep_range(20000, 20000);//usleep(20000); + + /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */ + gpio_direction_output(ts->pdata->irq_gpio, + (client->addr == GTP_I2C_ADDRESS_HIGH)); + msleep(20); + + /* step3:RST output high reset guitar */ + gpio_direction_output(ts->pdata->reset_gpio, 1); + + /* 20121211 modify start */ + msleep(20); + while (retry++ < 200) { + /* step4:Hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + pr_debug("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + + /* step5:Confirm hold */ + ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); + if (ret <= 0) { + pr_debug("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) { + pr_debug("Hold ss51 & dsp confirm SUCCESS"); + break; + } + pr_debug("Hold ss51 & dsp confirm 0x4180 failed,value:%d", + rd_buf[GTP_ADDR_LENGTH]); + } + if (retry >= 200) { + pr_err("Enter update Hold ss51 failed."); + return FAIL; + } + + /* step6:DSP_CK and DSP_ALU_CK PowerOn */ + ret = gup_set_ic_msg(client, 0x4010, 0x00); + + /* 20121211 modify end */ + return ret; +} + +void gup_leave_update_mode(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + gpio_direction_input(ts->pdata->irq_gpio); + pr_debug("reset chip."); + gtp_reset_guitar(ts, 20); +} + +/* Get the correct nvram data + The correct conditions: + 1. the hardware info is the same + 2. the product id is the same + 3. the firmware version in update file is greater than the firmware + version in ic or the check sum in ic is wrong + + Update Conditions: + 1. Same hardware info + 2. Same PID + 3. File PID > IC PID + + Force Update Conditions: + 1. Wrong ic firmware checksum + 2. INVALID IC PID or VID + 3. IC PID == 91XX || File PID == 91XX +*/ + +static u8 gup_enter_update_judge(struct i2c_client *client, + struct st_fw_head *fw_head) +{ + u16 u16_tmp; + s32 i = 0; + + u16_tmp = fw_head->vid; + fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); + + pr_debug("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], + fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]); + pr_debug("FILE PID:%s", fw_head->pid); + pr_debug("FILE VID:%04x", fw_head->vid); + + pr_debug("IC HARDWARE INFO:%02x%02x%02x%02x", + update_msg.ic_fw_msg.hw_info[0], + update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], + update_msg.ic_fw_msg.hw_info[3]); + pr_debug("IC PID:%s", update_msg.ic_fw_msg.pid); + pr_debug("IC VID:%04x", update_msg.ic_fw_msg.vid); + + /* First two conditions */ + if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, + sizeof(update_msg.ic_fw_msg.hw_info))) { + pr_debug("Get the same hardware info."); + if (update_msg.force_update != 0xBE) { + pr_info("FW chksum error,need enter update."); + return SUCCESS; + } + + /* 20130523 start */ + if (strlen(update_msg.ic_fw_msg.pid) < 3) { + pr_info("Illegal IC pid, need enter update"); + return SUCCESS; + } else { + for (i = 0; i < 3; i++) { + if ((update_msg.ic_fw_msg.pid[i] < 0x30) || + (update_msg.ic_fw_msg.pid[i] > 0x39)) { + pr_info("Illegal IC pid, out of bound, need enter update"); + return SUCCESS; + } + } + } + /* 20130523 end */ + + if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, + (strlen(fw_head->pid) < 3 ? 3 : strlen(fw_head->pid)))) || + (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) || + (!memcmp(fw_head->pid, "91XX", 4))) { + if (!memcmp(fw_head->pid, "91XX", 4)) + pr_debug("Force none same pid update mode."); + else + pr_debug("Get the same pid."); + + /* The third condition */ + if (fw_head->vid > update_msg.ic_fw_msg.vid) { + pr_info("Need enter update."); + return SUCCESS; + } + pr_err("Don't meet the third condition."); + pr_err("File VID <= Ic VID, update aborted!"); + } else { + pr_err("File PID != Ic PID, update aborted!"); + } + } else { + pr_err("Different Hardware, update aborted!"); + } + + return FAIL; +} + +static s8 gup_update_config(struct i2c_client *client, + const struct firmware *cfg) +{ + s32 ret = 0; + s32 i = 0; + s32 file_cfg_len = 0; + u32 chip_cfg_len = 0; + s32 count = 0; + u8 *buf; + u8 *file_config; + u8 pid[8]; + u8 high, low; + + if (!cfg || !cfg->data) { + pr_err("No need to upgrade config!"); + return FAIL; + } + + ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6); + if (ret == FAIL) { + pr_err("Read product id & version id fail."); + return FAIL; + } + pid[5] = '\0'; + pr_debug("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]); + + chip_cfg_len = 186; + if (!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) || + !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) || + !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3)) { + chip_cfg_len = 228; + } + pr_debug("config file ASCII len:%zu", cfg->size); + pr_debug("need config binary len:%d", chip_cfg_len); + if ((cfg->size + 5) < chip_cfg_len * 5) { + pr_err("Config length error"); + return -EINVAL; + } + + buf = devm_kzalloc(&client->dev, cfg->size, GFP_KERNEL); + if (!buf) { + dev_err(&client->dev, "Memory allocation failed for buf."); + return -ENOMEM; + } + + file_config = devm_kzalloc(&client->dev, chip_cfg_len + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!file_config) { + dev_err(&client->dev, "Memory allocation failed."); + return -ENOMEM; + } + + pr_debug("Delete illgal charactor."); + for (i = 0, count = 0; i < cfg->size; i++) { + if (cfg->data[i] == ' ' || cfg->data[i] == '\r' + || cfg->data[i] == '\n') + continue; + buf[count++] = cfg->data[i]; + } + + pr_debug("Ascii to hex."); + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + for (i = 0, file_cfg_len = GTP_ADDR_LENGTH; i < count; i = i + 5) { + if ((buf[i] == '0') && ((buf[i + 1] == 'x') || + (buf[i + 1] == 'X'))) { + ret = hex2bin(&high, &buf[i + 2], 1); + if (ret) { + pr_err("Failed to convert high address from hex2bin"); + return ret; + } + ret = hex2bin(&low, &buf[i + 3], 1); + if (ret) { + pr_err("Failed to convert low address from hex2bin"); + return ret; + } + + if ((high == 0xFF) || (low == 0xFF)) { + ret = 0; + pr_err("Illegal config file."); + return ret; + } + file_config[file_cfg_len++] = (high<<4) + low; + } else { + ret = 0; + pr_err("Illegal config file."); + return ret; + } + } + + i = 0; + while (i++ < 5) { + ret = gup_i2c_write(client, file_config, file_cfg_len); + if (ret > 0) { + pr_info("Send config SUCCESS."); + break; + } + pr_err("Send config i2c error."); + } + + return ret; +} + +static s32 gup_get_firmware_file(struct i2c_client *client, + struct st_update_msg *msg, u8 *path) +{ + s32 ret; + const struct firmware *fw = NULL; + + ret = request_firmware(&fw, path, &client->dev); + if (ret < 0) { + dev_info(&client->dev, "Cannot get firmware - %s (%d)\n", + path, ret); + return -EEXIST; + } + + dev_dbg(&client->dev, "Config File: %s size=%zu", path, fw->size); + msg->fw_data = + devm_kzalloc(&client->dev, fw->size, GFP_KERNEL); + if (!msg->fw_data) { + dev_err(&client->dev, + "Not enough memory for firmware data."); + release_firmware(fw); + return -ENOMEM; + } + + memcpy(msg->fw_data, fw->data, fw->size); + msg->fw_len = fw->size; + msg->need_free = true; + release_firmware(fw); + return 0; +} + +static u8 gup_check_firmware_name(struct i2c_client *client, + u8 **path_p) +{ + u8 len; + u8 *fname; + + if (!(*path_p)) { + *path_p = GOODIX_FIRMWARE_FILE_NAME; + return 0; + } + + len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX); + if (len >= FIRMWARE_NAME_LEN_MAX) { + dev_err(&client->dev, "firmware name too long!"); + return -EINVAL; + } + + fname = strrchr(*path_p, '/'); + if (fname) { + fname = fname + 1; + *path_p = fname; + } + return 0; +} + +static u8 gup_check_update_file(struct i2c_client *client, + struct st_fw_head *fw_head, u8 *path) +{ + s32 ret = 0; + s32 i = 0; + s32 fw_checksum = 0; + u16 temp; + const struct firmware *fw = NULL; + + ret = request_firmware(&fw, GOODIX_CONFIG_FILE_NAME, &client->dev); + if (ret < 0) { + dev_info(&client->dev, "Cannot get config file - %s (%d)\n", + GOODIX_CONFIG_FILE_NAME, ret); + } else { + dev_dbg(&client->dev, + "Update config File: %s", GOODIX_CONFIG_FILE_NAME); + ret = gup_update_config(client, fw); + if (ret <= 0) + dev_err(&client->dev, "Update config failed."); + release_firmware(fw); + } + + update_msg.need_free = false; + update_msg.fw_len = 0; + + if (gup_check_firmware_name(client, &path)) + goto load_failed; + + if (gup_get_firmware_file(client, &update_msg, path)) + goto load_failed; + + memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH); + + /* check firmware legality */ + fw_checksum = 0; + for (i = 0; i < FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH; i += 2) { + temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) + + update_msg.fw_data[FW_HEAD_LENGTH + i + 1]; + fw_checksum += temp; + } + + pr_debug("firmware checksum:%x", fw_checksum & 0xFFFF); + if (fw_checksum & 0xFFFF) { + dev_err(&client->dev, "Illegal firmware file."); + goto load_failed; + } + + return SUCCESS; + +load_failed: + if (update_msg.need_free) { + devm_kfree(&client->dev, update_msg.fw_data); + update_msg.need_free = false; + } + return FAIL; +} + +static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, + u16 total_length) +{ + s32 ret = 0; + u16 burn_addr = start_addr; + u16 frame_length = 0; + u16 burn_length = 0; + u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 retry = 0; + + pr_debug("Begin burn %dk data to addr 0x%x", (total_length / 1024), + start_addr); + while (burn_length < total_length) { + pr_debug("B/T:%04d/%04d", burn_length, total_length); + frame_length = ((total_length - burn_length) > PACK_SIZE) + ? PACK_SIZE : (total_length - burn_length); + wr_buf[0] = (u8)(burn_addr>>8); + rd_buf[0] = wr_buf[0]; + wr_buf[1] = (u8)burn_addr; + rd_buf[1] = wr_buf[1]; + memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], + frame_length); + + for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) { + ret = gup_i2c_write(client, wr_buf, + GTP_ADDR_LENGTH + frame_length); + if (ret <= 0) { + pr_err("Write frame data i2c error."); + continue; + } + ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + + frame_length); + if (ret <= 0) { + pr_err("Read back frame data i2c error."); + continue; + } + + if (memcmp(&wr_buf[GTP_ADDR_LENGTH], + &rd_buf[GTP_ADDR_LENGTH], frame_length)) { + pr_err("Check frame data fail,not equal."); + continue; + } else { + break; + } + } + if (retry >= MAX_FRAME_CHECK_TIME) { + pr_err("Burn frame data time out,exit."); + return FAIL; + } + burn_length += frame_length; + burn_addr += frame_length; + } + return SUCCESS; +} + +static u8 gup_load_section_file(u8 *buf, u16 offset, u16 length) +{ + if (!update_msg.fw_data || + update_msg.fw_len < FW_HEAD_LENGTH + offset + length) { + pr_err( + "<<-GTP->> cannot load section data. fw_len=%d read end=%d\n", + update_msg.fw_len , + FW_HEAD_LENGTH + offset + length); + return FAIL; + } + memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset], length); + + return SUCCESS; +} + +static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src, + u16 start_rd_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + s32 ret = 0; + u16 recall_addr = start_rd_addr; + u16 recall_length = 0; + u16 frame_length = 0; + + while (recall_length < chk_length) { + frame_length = ((chk_length - recall_length) > PACK_SIZE) + ? PACK_SIZE : (chk_length - recall_length); + ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); + if (ret <= 0) { + pr_err("recall i2c error,exit"); + return FAIL; + } + + if (memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], + frame_length)) { + pr_err("Recall frame data fail,not equal."); + return FAIL; + } + + recall_length += frame_length; + recall_addr += frame_length; + } + pr_debug("Recall check %dk firmware success.", (chk_length/1024)); + + return SUCCESS; +} + +static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, + u16 start_addr, u8 bank_cmd) +{ + s32 ret = 0; + u8 rd_buf[5]; + + /* step1:hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + pr_err("hold ss51 & dsp fail."); + return FAIL; + } + + /* step2:set scramble */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + pr_err("set scramble fail."); + return FAIL; + } + + /* step3:select bank */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, + (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + pr_err("select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step4:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + pr_err("enable accessing code fail."); + return FAIL; + } + + /* step5:burn 8k fw section */ + ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); + if (ret == FAIL) { + pr_err("burn fw_section fail."); + return FAIL; + } + + /* step6:hold ss51 & release dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + pr_err("hold ss51 & release dsp fail."); + return FAIL; + } + /* must delay */ + msleep(20); + + /* step7:send burn cmd to move data to flash from sram */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); + if (ret <= 0) { + pr_err("send burn cmd fail."); + return FAIL; + } + pr_debug("Wait for the burn is complete."); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + pr_err("Get burn state fail"); + return FAIL; + } + msleep(20); + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:select bank */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, + (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + pr_err("select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step9:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + pr_err("enable accessing code fail."); + return FAIL; + } + + /* step10:recall 8k fw section */ + ret = gup_recall_check(client, fw_section, start_addr, + FW_SECTION_LENGTH); + if (ret == FAIL) { + pr_err("recall check 8k firmware fail."); + return FAIL; + } + + /* step11:disable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); + if (ret <= 0) { + pr_err("disable accessing code fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_dsp_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp_isp = NULL; + u8 retry = 0; + + pr_debug("Begin burn dsp isp."); + + /* step1:alloc memory */ + pr_debug("step1:alloc memory"); + while (retry++ < 5) { + fw_dsp_isp = devm_kzalloc(&client->dev, FW_DSP_ISP_LENGTH, + GFP_KERNEL); + if (fw_dsp_isp == NULL) { + continue; + } else { + pr_info("Alloc %dk byte memory success.", + (FW_DSP_ISP_LENGTH/1024)); + break; + } + } + if (retry == 5) { + pr_err("Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load dsp isp file data */ + pr_debug("step2:load dsp isp file data"); + ret = gup_load_section_file(fw_dsp_isp, (4 * FW_SECTION_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH); + if (ret == FAIL) { + pr_err("load firmware dsp_isp fail."); + return FAIL; + } + + /* step3:disable wdt,clear cache enable */ + pr_debug("step3:disable wdt,clear cache enable"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); + if (ret <= 0) { + pr_err("disable wdt fail."); + return FAIL; + } + ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); + if (ret <= 0) { + pr_err("clear cache enable fail."); + return FAIL; + } + + /* step4:hold ss51 & dsp */ + pr_debug("step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + pr_err("hold ss51 & dsp fail."); + return FAIL; + } + + /* step5:set boot from sram */ + pr_debug("step5:set boot from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); + if (ret <= 0) { + pr_err("set boot from sram fail."); + return FAIL; + } + + /* step6:software reboot */ + pr_debug("step6:software reboot"); + ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); + if (ret <= 0) { + pr_err("software reboot fail."); + return FAIL; + } + + /* step7:select bank2 */ + pr_debug("step7:select bank2"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); + if (ret <= 0) { + pr_err("select bank2 fail."); + return FAIL; + } + + /* step8:enable accessing code */ + pr_debug("step8:enable accessing code"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + pr_err("enable accessing code fail."); + return FAIL; + } + + /* step9:burn 4k dsp_isp */ + pr_debug("step9:burn 4k dsp_isp"); + ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); + if (ret == FAIL) { + pr_err("burn dsp_isp fail."); + return FAIL; + } + + /* step10:set scramble */ + pr_debug("step10:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + pr_err("set scramble fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_fw_ss51(struct i2c_client *client) +{ + u8 *fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + pr_debug("Begin burn ss51 firmware."); + + /* step1:alloc memory */ + pr_debug("step1:alloc memory"); + while (retry++ < 5) { + fw_ss51 = devm_kzalloc(&client->dev, FW_SECTION_LENGTH, + GFP_KERNEL); + if (fw_ss51 == NULL) { + continue; + } else { + pr_info("Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry == 5) { + pr_err("Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load ss51 firmware section 1 file data */ + pr_debug("step2:load ss51 firmware section 1 file data"); + ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH); + if (ret == FAIL) { + pr_err("load ss51 firmware section 1 fail."); + return FAIL; + } + + /* step3:clear control flag */ + pr_debug("step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + pr_err("clear control flag fail."); + return FAIL; + } + + /* step4:burn ss51 firmware section 1 */ + pr_debug("step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if (ret == FAIL) { + pr_err("burn ss51 firmware section 1 fail."); + return FAIL; + } + + /* step5:load ss51 firmware section 2 file data */ + pr_debug("step5:load ss51 firmware section 2 file data"); + ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, + FW_SECTION_LENGTH); + if (ret == FAIL) { + pr_err("[burn_fw_ss51]load ss51 firmware section 2 fail."); + return FAIL; + } + + /* step6:burn ss51 firmware section 2 */ + pr_debug("step6:burn ss51 firmware section 2"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); + if (ret == FAIL) { + pr_err("burn ss51 firmware section 2 fail."); + return FAIL; + } + + /* step7:load ss51 firmware section 3 file data */ + pr_debug("step7:load ss51 firmware section 3 file data"); + ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, + FW_SECTION_LENGTH); + if (ret == FAIL) { + pr_err("load ss51 firmware section 3 fail."); + return FAIL; + } + + /* step8:burn ss51 firmware section 3 */ + pr_debug("step8:burn ss51 firmware section 3"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); + if (ret == FAIL) { + pr_err("burn ss51 firmware section 3 fail."); + return FAIL; + } + + /* step9:load ss51 firmware section 4 file data */ + pr_debug("step9:load ss51 firmware section 4 file data"); + ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, + FW_SECTION_LENGTH); + if (ret == FAIL) { + pr_err("load ss51 firmware section 4 fail."); + return FAIL; + } + + /* step10:burn ss51 firmware section 4 */ + pr_debug("step10:burn ss51 firmware section 4"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); + if (ret == FAIL) { + pr_err("burn ss51 firmware section 4 fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_fw_dsp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + pr_debug("Begin burn dsp firmware."); + /* step1:alloc memory */ + pr_debug("step1:alloc memory"); + while (retry++ < 5) { + fw_dsp = devm_kzalloc(&client->dev, FW_DSP_LENGTH, + GFP_KERNEL); + if (fw_dsp == NULL) { + continue; + } else { + pr_info("Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry == 5) { + pr_err("Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware dsp */ + pr_debug("step2:load firmware dsp"); + ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH); + if (ret == FAIL) { + pr_err("load firmware dsp fail."); + return ret; + } + + /* step3:select bank3 */ + pr_debug("step3:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + pr_err("select bank3 fail."); + return FAIL; + } + + /* Step4:hold ss51 & dsp */ + pr_debug("step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + pr_err("hold ss51 & dsp fail."); + return FAIL; + } + + /* step5:set scramble */ + pr_debug("step5:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + pr_err("set scramble fail."); + return FAIL; + } + + /* step6:release ss51 & dsp */ + pr_debug("step6:release ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + pr_err("release ss51 & dsp fail."); + return FAIL; + } + /* must delay */ + msleep(20); + + /* step7:burn 4k dsp firmware */ + pr_debug("step7:burn 4k dsp firmware"); + ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (ret == FAIL) { + pr_err("[burn_fw_dsp]burn fw_section fail."); + return ret; + } + + /* step8:send burn cmd to move data to flash from sram */ + pr_debug("step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); + if (ret <= 0) { + pr_err("send burn cmd fail."); + return ret; + } + pr_debug("Wait for the burn is complete."); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + pr_err("Get burn state fail"); + return ret; + } + msleep(20); + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step9:recall check 4k dsp firmware */ + pr_debug("step9:recall check 4k dsp firmware"); + ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (ret == FAIL) { + pr_err("recall check 4k dsp firmware fail."); + return ret; + } + + return SUCCESS; +} + +static u8 gup_burn_fw_boot(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_boot = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + pr_debug("Begin burn bootloader firmware."); + + /* step1:Alloc memory */ + pr_debug("step1:Alloc memory"); + while (retry++ < 5) { + fw_boot = devm_kzalloc(&client->dev, FW_BOOT_LENGTH, + GFP_KERNEL); + if (fw_boot == NULL) { + continue; + } else { + pr_info("Alloc %dk byte memory success.", + (FW_BOOT_LENGTH/1024)); + break; + } + } + if (retry == 5) { + pr_err("Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware bootloader */ + pr_debug("step2:load firmware bootloader"); + ret = gup_load_section_file(fw_boot, (4 * FW_SECTION_LENGTH + + FW_DSP_LENGTH), FW_BOOT_LENGTH); + if (ret == FAIL) { + pr_err("load firmware dsp fail."); + return ret; + } + + /* step3:hold ss51 & dsp */ + pr_debug("step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + pr_err("hold ss51 & dsp fail."); + return FAIL; + } + + /* step4:set scramble */ + pr_debug("step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + pr_err("set scramble fail."); + return FAIL; + } + + /* step5:release ss51 & dsp */ + pr_debug("step5:release ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + pr_err("release ss51 & dsp fail."); + return FAIL; + } + /* must delay */ + msleep(20); + + /* step6:select bank3 */ + pr_debug("step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + pr_err("select bank3 fail."); + return FAIL; + } + + /* step7:burn 2k bootloader firmware */ + pr_debug("step7:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (ret == FAIL) { + pr_err("burn fw_section fail."); + return ret; + } + + /* step7:send burn cmd to move data to flash from sram */ + pr_debug("step7:send burn cmd to flash data from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); + if (ret <= 0) { + pr_err("send burn cmd fail."); + return ret; + } + pr_debug("Wait for the burn is complete."); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + pr_err("Get burn state fail"); + return ret; + } + msleep(20); + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:recall check 2k bootloader firmware */ + pr_debug("step8:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (ret == FAIL) { + pr_err("recall check 4k dsp firmware fail."); + return ret; + } + + /* step9:enable download DSP code */ + pr_debug("step9:enable download DSP code "); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); + if (ret <= 0) { + pr_err("enable download DSP code fail."); + return FAIL; + } + + /* step10:release ss51 & hold dsp */ + pr_debug("step10:release ss51 & hold dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); + if (ret <= 0) { + pr_err("release ss51 & hold dsp fail."); + return FAIL; + } + + return SUCCESS; +} + +s32 gup_update_proc(void *dir) +{ + s32 ret = 0; + u8 retry = 0; + struct st_fw_head fw_head; + struct goodix_ts_data *ts = NULL; + + pr_debug("Begin update."); + + if (!i2c_connect_client) { + pr_err("No i2c connect client for %s\n", __func__); + return -EIO; + } + + show_len = 1; + total_len = 100; + + ts = i2c_get_clientdata(i2c_connect_client); + + if (searching_file) { + /* exit .bin update file searching */ + searching_file = 0; + pr_info("Exiting searching .bin update file."); + /* wait for auto update quitted completely */ + while ((show_len != 200) && (show_len != 100)) + msleep(100); + } + + ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8 *)dir); + if (ret == FAIL) { + pr_err("check update file fail."); + goto file_fail; + } + + /* gtp_reset_guitar(i2c_connect_client, 20); */ + ret = gup_get_ic_fw_msg(i2c_connect_client); + if (ret == FAIL) { + pr_err("get ic message fail."); + goto file_fail; + } + + if (ts->force_update) { + dev_dbg(&ts->client->dev, "Enter force update."); + } else { + ret = gup_enter_update_judge(ts->client, &fw_head); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "Check *.bin file fail."); + goto file_fail; + } + } + + ts->enter_update = 1; + gtp_irq_disable(ts); +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_OFF); +#endif + ret = gup_enter_update_mode(i2c_connect_client); + if (ret == FAIL) { + pr_err("enter update mode fail."); + goto update_fail; + } + + while (retry++ < 5) { + show_len = 10; + total_len = 100; + ret = gup_burn_dsp_isp(i2c_connect_client); + if (ret == FAIL) { + pr_err("burn dsp isp fail."); + continue; + } + + show_len += 10; + ret = gup_burn_fw_ss51(i2c_connect_client); + if (ret == FAIL) { + pr_err("burn ss51 firmware fail."); + continue; + } + + show_len += 40; + ret = gup_burn_fw_dsp(i2c_connect_client); + if (ret == FAIL) { + pr_err("burn dsp firmware fail."); + continue; + } + + show_len += 20; + ret = gup_burn_fw_boot(i2c_connect_client); + if (ret == FAIL) { + pr_err("burn bootloader fw fail."); + continue; + } + show_len += 10; + pr_info("UPDATE SUCCESS."); + break; + } + if (retry >= 5) { + pr_err("retry timeout,UPDATE FAIL."); + goto update_fail; + } + + pr_debug("leave update mode."); + gup_leave_update_mode(i2c_connect_client); + + msleep(100); + + if (ts->fw_error) { + pr_info("firmware error auto update, resent config!"); + gup_init_panel(ts); + } + show_len = 100; + total_len = 100; + ts->enter_update = 0; + gtp_irq_enable(ts); + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_ON); +#endif + if (update_msg.need_free) { + devm_kfree(&ts->client->dev, update_msg.fw_data); + update_msg.need_free = false; + } + + return SUCCESS; + +update_fail: + ts->enter_update = 0; + gtp_irq_enable(ts); + +#if GTP_ESD_PROTECT + gtp_esd_switch(ts->client, SWITCH_ON); +#endif + +file_fail: + show_len = 200; + total_len = 100; + if (update_msg.need_free) { + devm_kfree(&ts->client->dev, update_msg.fw_data); + update_msg.need_free = false; + } + return FAIL; +} + +static void gup_update_work(struct work_struct *work) +{ + if (gup_update_proc(NULL) == FAIL) + pr_err("Goodix update work fail!\n"); +} + +u8 gup_init_update_proc(struct goodix_ts_data *ts) +{ + dev_dbg(&ts->client->dev, "Ready to run update work."); + + INIT_DELAYED_WORK(&ts->goodix_update_work, gup_update_work); + schedule_delayed_work(&ts->goodix_update_work, + msecs_to_jiffies(3000)); + + return 0; +} -- 2.25.1 From ac156819b13b037f93848631a1d65cafaf167129 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Jan 2020 16:03:55 -0500 Subject: [PATCH 04/76] MeiG Patch 20191123 huangshifang:add temperature sensor and pressure sensor Change-Id: Ice5b05bcfd699db7ee090ac3abad409a6ddc2c69 --- drivers/input/misc/bmp280_core.c | 142 +++++++++++++++++++++++++++++-- drivers/input/misc/bmp280_core.h | 4 + include/linux/sensors.h | 1 + 3 files changed, 141 insertions(+), 6 deletions(-) diff --git a/drivers/input/misc/bmp280_core.c b/drivers/input/misc/bmp280_core.c index 20d833b166c..bf81e981dbf 100755 --- a/drivers/input/misc/bmp280_core.c +++ b/drivers/input/misc/bmp280_core.c @@ -101,14 +101,23 @@ struct bmp_client_data { //add by liangdi struct sensors_classdev cdev; //add end + //add by huangshifang + struct sensors_classdev temp_cdev; + //add end #ifdef CONFIG_HAS_EARLYSUSPEND /*!early suspend variable */ struct early_suspend early_suspend; #endif /*!indicate input device; register to input core in kernel */ struct input_dev *input; + //add by huangshifang + struct input_dev *input_temp; + //add end /*!register to work queue */ struct delayed_work work; + //add by huangshifang + struct delayed_work temp_work; + //add end /*!delay time used by input event */ uint32_t delay; /*!enable/disable sensor output */ @@ -122,7 +131,7 @@ struct bmp_client_data { }; //add by liangdi -static struct sensors_classdev sensors_cdev = { +static struct sensors_classdev press_cdev = { .name = "bmp280-pressure", .vendor = "Bosch", .version = 1, @@ -141,6 +150,26 @@ static struct sensors_classdev sensors_cdev = { }; //add end +//add by huangshifang +static struct sensors_classdev temper_cdev = { + .name = "bmp280-temperature", + .vendor = "Bosch", + .version = 1, + .handle = SENSORS_AMBIENT_TEMPERATURE_HANDLE, + .type = SENSOR_TYPE_AMBIENT_TEMPERATURE, + .max_range = "65.0", + .resolution = "0.01", + .sensor_power = "0.67", + .min_delay = 20000, /* microsecond */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, /* millisecond */ + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; +//add end + #ifdef CONFIG_HAS_EARLYSUSPEND static void bmp_early_suspend(struct early_suspend *h); static void bmp_late_resume(struct early_suspend *h); @@ -765,6 +794,19 @@ static ssize_t bmp280_poll_delay_set(struct sensors_classdev *sensors_cdev, } //add end +//add by huangshifang +static ssize_t bmp280_temp_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_msec) +{ + struct bmp_client_data *data = container_of(sensors_cdev, + struct bmp_client_data, temp_cdev); + mutex_lock(&data->lock); + data->delay = delay_msec; + mutex_unlock(&data->lock); + pr_err("bmp280_poll_delay_set delay=%d\n",data->delay); + return 0; +} +//add end /* sysfs callbacks */ /*! * @brief get delay value via sysfs node @@ -1180,6 +1222,41 @@ static ssize_t bmp280_enable_set(struct sensors_classdev *sensors_cdev, //add end +//add by huangshifang +static ssize_t bmp280_enable_set_temp(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmp_client_data *data = container_of(sensors_cdev, + struct bmp_client_data, temp_cdev); + struct device *dev = data->dev; + + enable = enable ? 1 : 0; + mutex_lock(&data->lock); + if (data->enable != enable) { + if (enable) { + #ifdef CONFIG_PM + bmp_enable(dev); + #endif + bmp_set_op_mode(data, \ + BMP_VAL_NAME(NORMAL_MODE)); + schedule_delayed_work(&data->temp_work, + msecs_to_jiffies(data->delay)); + } else{ + cancel_delayed_work_sync(&data->temp_work); + bmp_set_op_mode(data, \ + BMP_VAL_NAME(SLEEP_MODE)); + #ifdef CONFIG_PM + bmp_disable(dev); + #endif + } + data->enable = enable; + } + mutex_unlock(&data->lock); + pr_err("bmp280_enable_set en_state=%d\n",data->enable); + + return 0; +} +//add end /*! * @brief get sensor work state via sysfs node * @@ -1439,13 +1516,36 @@ static void bmp_work_func(struct work_struct *work) mutex_unlock(&client_data->lock); if (status == 0) { //pr_err("bmp280 pressure value :%d Pa\n", pressure); - input_event(client_data->input, EV_MSC, MSC_RAW, pressure); + input_event(client_data->input, EV_ABS, MSC_RAW, pressure); input_sync(client_data->input); } schedule_delayed_work(&client_data->work, delay-(jiffies-j1)); } +//add by huangshifang +static void bmp_temp_work_func(struct work_struct *work) +{ + struct bmp_client_data *client_data = + container_of((struct delayed_work *)work, + struct bmp_client_data, temp_work); + uint32_t delay = msecs_to_jiffies(client_data->delay); + uint32_t j1 = jiffies; + uint32_t temperature; + int status; + + mutex_lock(&client_data->lock); + status = bmp_get_temperature(client_data, &temperature); + mutex_unlock(&client_data->lock); + if (status == 0) { + //pr_err("bmp280 temperature value :%d Pa\n", temperature); + input_event(client_data->input_temp, EV_ABS, MSC_RAW, temperature); + input_sync(client_data->input_temp); + } + + schedule_delayed_work(&client_data->temp_work, delay-(jiffies-j1)); +} +//add end /*! * @brief initialize input device * @@ -1463,10 +1563,10 @@ static int bmp_input_init(struct bmp_client_data *data) dev = input_allocate_device(); if (!dev) return -ENOMEM; - dev->name = BMP_NAME; + dev->name = BMP_PRESS_NAME; dev->id.bustype = BUS_I2C; - input_set_capability(dev, EV_MSC, MSC_RAW); + input_set_capability(dev, EV_ABS, MSC_RAW); input_set_drvdata(dev, data); err = input_register_device(dev); @@ -1475,7 +1575,23 @@ static int bmp_input_init(struct bmp_client_data *data) return err; } data->input = dev; + //add by huangshifang + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + dev->name = BMP_TEMPER_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, MSC_RAW); + input_set_drvdata(dev, data); + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + data->input_temp = dev; + //add end return 0; } @@ -1593,7 +1709,7 @@ int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus) goto error_sysfs; //add by liangdi - data->cdev = sensors_cdev; + data->cdev = press_cdev; data->cdev.sensors_enable = bmp280_enable_set; data->cdev.sensors_poll_delay = bmp280_poll_delay_set; err = sensors_classdev_register(&data->input->dev, &data->cdev); @@ -1602,9 +1718,23 @@ int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus) goto error_class_sysfs; } //add end - + + //add by huangshifang + data->temp_cdev = temper_cdev; + data->temp_cdev.sensors_enable = bmp280_enable_set_temp; + data->temp_cdev.sensors_poll_delay = bmp280_temp_poll_delay_set; + err = sensors_classdev_register(&data->input_temp->dev, &data->temp_cdev); + if (err) { + pr_err("class device create failed: %d\n", err); + goto error_class_sysfs; + } + //add end + /* workqueue init */ INIT_DELAYED_WORK(&data->work, bmp_work_func); + //add by huangshifang + INIT_DELAYED_WORK(&data->temp_work, bmp_temp_work_func); + //add end #ifdef CONFIG_HAS_EARLYSUSPEND data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; diff --git a/drivers/input/misc/bmp280_core.h b/drivers/input/misc/bmp280_core.h index ee25a7fb408..69cd5334027 100755 --- a/drivers/input/misc/bmp280_core.h +++ b/drivers/input/misc/bmp280_core.h @@ -21,6 +21,10 @@ /*! define BMP device name */ #define BMP_NAME "bmp280" +//add by huangshifang +#define BMP_PRESS_NAME "bmp280-pressure" +#define BMP_TEMPER_NAME "bmp280-temperature" +//add end /*! define BMP register name according to API */ #define BMP_REG_NAME(name) BMP280_##name /*! define BMP value name according to API */ diff --git a/include/linux/sensors.h b/include/linux/sensors.h index 56a0d731424..472f9b65bd3 100644 --- a/include/linux/sensors.h +++ b/include/linux/sensors.h @@ -24,6 +24,7 @@ #define SENSORS_PROXIMITY_HANDLE 4 #define SENSORS_GYROSCOPE_HANDLE 5 #define SENSORS_PRESSURE_HANDLE 6 +#define SENSORS_AMBIENT_TEMPERATURE_HANDLE 7 #define SENSOR_TYPE_ACCELEROMETER 1 #define SENSOR_TYPE_GEOMAGNETIC_FIELD 2 -- 2.25.1 From 82ea2ecaa3d0009ac5c429c28de68efd0bf6a9c8 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Jan 2020 18:03:16 -0500 Subject: [PATCH 05/76] MeiG Patch 20191130 huangshifang:add gpio_pwm control interface Change-Id: Ibc9756b0e0552f7f8f98eb76f99d2c708955a2a9 --- arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi | 6 +- arch/arm/configs/msm8909-perf_defconfig | 31 +- arch/arm/configs/msm8909_defconfig | 2 +- drivers/Kconfig | 2 + drivers/Makefile | 3 + drivers/mg_driver/Kconfig | 16 + drivers/mg_driver/Makefile | 8 + drivers/mg_driver/mgdrv/Kconfig | 9 + drivers/mg_driver/mgdrv/Makefile | 1 + drivers/mg_driver/mgdrv/mg_drv.c | 292 +++++++++++++++++++ 10 files changed, 349 insertions(+), 21 deletions(-) create mode 100755 drivers/mg_driver/Kconfig create mode 100755 drivers/mg_driver/Makefile create mode 100755 drivers/mg_driver/mgdrv/Kconfig create mode 100755 drivers/mg_driver/mgdrv/Makefile create mode 100755 drivers/mg_driver/mgdrv/mg_drv.c diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi index 7b12a7074b9..e8ea1797d2b 100755 --- a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi @@ -12,10 +12,6 @@ #include "msm8909-qrd.dtsi" //#include "msm8909-camera-sensor-skua.dtsi" -#include "dsi-panel-hx8394f-zzw500hah-720p-video.dtsi" -#include "dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi" -//#include "dsi-panel-ortustech-video.dtsi" -#include "dsi-panel-ortustech32-video.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909 QRD SKUA"; compatible = "qcom,msm8909-qrd", "qcom,msm8909", "qcom,qrd"; @@ -237,7 +233,7 @@ vio-supply = <&pm8909_l6>; akm,layout = <0x3>; akm,poll_interval = <200>; - akm,gpio_rstn = <&msm_gpio 65 0x0>; + akm,gpio_rstn = <&msm_gpio 16 0x0>; akm,auto-report; }; diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index fa1c46ebf5c..a34502456b9 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -291,21 +291,21 @@ CONFIG_KEYBOARD_GPIO=y CONFIG_INPUT_JOYSTICK=y CONFIG_JOYSTICK_XPAD=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y -CONFIG_TOUCHSCREEN_ATMEL_MXT=y -CONFIG_TOUCHSCREEN_FT5X06_GESTURE=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +# CONFIG_TOUCHSCREEN_ATMEL_MXT=y +# CONFIG_TOUCHSCREEN_FT5X06_GESTURE=y CONFIG_SECURE_TOUCH=y -CONFIG_TOUCHSCREEN_GEN_VKEYS=y -CONFIG_TOUCHSCREEN_FT5X06=y -CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y -CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y +# CONFIG_TOUCHSCREEN_GEN_VKEYS=y +# CONFIG_TOUCHSCREEN_FT5X06=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y CONFIG_INPUT_MISC=y -CONFIG_SENSORS_MPU6050=y -CONFIG_SENSORS_AKM8963=y +# CONFIG_SENSORS_MPU6050=y +# CONFIG_SENSORS_AKM8963=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m -CONFIG_SENSORS_LTR553=y +# CONFIG_SENSORS_LTR553=y # CONFIG_SENSORS_AKM09911=y CONFIG_SENSORS_BMA2X2=y # CONFIG_VT is not set @@ -313,6 +313,8 @@ CONFIG_SENSORS_BMA2X2=y # CONFIG_DEVMEM is not set # CONFIG_DEVKMEM is not set CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_HSL=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y @@ -331,8 +333,8 @@ CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y CONFIG_POWER_SUPPLY=y CONFIG_SMB135X_CHARGER=y -CONFIG_SMB1360_CHARGER_FG=y -CONFIG_SMB358_CHARGER=y +# CONFIG_SMB1360_CHARGER_FG=y +# CONFIG_SMB358_CHARGER=y CONFIG_BATTERY_BCL=y CONFIG_QPNP_VM_BMS=y CONFIG_QPNP_LINEAR_CHARGER=y @@ -534,7 +536,7 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_FUSE_FS=y CONFIG_CMA_SIZE_MBYTES=8 # add by liangdi -CONFIG_TOUCHSCREEN_GT1XX=y +#CONFIG_TOUCHSCREEN_GT1XX=y CONFIG_SENSORS_AKM09911=y # add by liangdi 20190821 CONFIG_SENSORS_BMI160=y @@ -545,7 +547,6 @@ CONFIG_SENSORS_BMI160_ENABLE_INT1=y CONFIG_SENSORS_BMP280=y CONFIG_SENSORS_BMP280_I2C=y CONFIG_TOUCHSCREEN_GT9XX=y -CONFIG_GT9XX_TOUCHPANEL_DRIVER=yCONFIG_TOUCHSCREEN_GT9XX=y CONFIG_GT9XX_TOUCHPANEL_DRIVER=y CONFIG_GT9XX_TOUCHPANEL_UPDATE=y CONFIG_GT9XX_TOUCHPANEL_DEBUG=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index fa4f6a8c503..38e0f3fead1 100755 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -599,7 +599,7 @@ CONFIG_QMI_ENCDEC=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y # add by liangdi -CONFIG_TOUCHSCREEN_GT1XX=y +#CONFIG_TOUCHSCREEN_GT1XX=y CONFIG_SENSORS_AKM09911=y # add by liangdi 20190821 CONFIG_SENSORS_BMI160=y diff --git a/drivers/Kconfig b/drivers/Kconfig index 386d76e620b..1b6458991a1 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -196,4 +196,6 @@ source "drivers/firmware/Kconfig" source "drivers/bif/Kconfig" +#add by huangshifang 20191123 +source "drivers/mg_driver/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index f5306e9584c..c59fd50cd5f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -171,3 +171,6 @@ obj-$(CONFIG_BIF) += bif/ obj-$(CONFIG_SENSORS) += sensors/ obj-$(CONFIG_SENSORS_SSC) += sensors/ + +#add by huangshifang for mg driver 20191123 +obj-$(CONFIG_MG_DRIVER_CONTROL) += mg_driver/ \ No newline at end of file diff --git a/drivers/mg_driver/Kconfig b/drivers/mg_driver/Kconfig new file mode 100755 index 00000000000..4494a9d2436 --- /dev/null +++ b/drivers/mg_driver/Kconfig @@ -0,0 +1,16 @@ +#**************************************************************** +# +# mg Product configuration +# +#**************************************************************** + +#Main menu +menu "mg Product Drivers Support" + +config MG_DRIVER_CONTROL + tristate + default y + +source "drivers/mg_driver/mgdrv/Kconfig" + +endmenu #mg Drivers menu end diff --git a/drivers/mg_driver/Makefile b/drivers/mg_driver/Makefile new file mode 100755 index 00000000000..027147e730d --- /dev/null +++ b/drivers/mg_driver/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the uc drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_MG_DRIVER_CONTROL) += mgdrv/ + diff --git a/drivers/mg_driver/mgdrv/Kconfig b/drivers/mg_driver/mgdrv/Kconfig new file mode 100755 index 00000000000..7be90dee554 --- /dev/null +++ b/drivers/mg_driver/mgdrv/Kconfig @@ -0,0 +1,9 @@ +menu "mg drivers Control Select" + +config MG_DRIVER_CONTROL + bool "mg driver control" + default n + help + if you want to use mg driver control, say Y, else say N + +endmenu diff --git a/drivers/mg_driver/mgdrv/Makefile b/drivers/mg_driver/mgdrv/Makefile new file mode 100755 index 00000000000..ea87d21f7ab --- /dev/null +++ b/drivers/mg_driver/mgdrv/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MG_DRIVER_CONTROL) += mg_drv.o diff --git a/drivers/mg_driver/mgdrv/mg_drv.c b/drivers/mg_driver/mgdrv/mg_drv.c new file mode 100755 index 00000000000..72173803c9c --- /dev/null +++ b/drivers/mg_driver/mgdrv/mg_drv.c @@ -0,0 +1,292 @@ +/*! + * addb by liangdi for mg drivers 20190521 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + INPUT_LOW = 0, + INPUT_HIGHT, +}; + +#define GPIO_PWM_DELAY_TIME (250000)//(500000000) +#define GPIO_PWM_OUT_TIME (800) //100 ms pwm out time +#define GPIO_PWM_STOP_TIME (800) //100 ms pwm stop time +#define GPIO_PWM_LONG_STOP_TIME (4800) //600 ms pwm long stop time +#define GPIO_PWM_BEEPER_TIMES (2) //beeper speak times + +static struct platform_driver mg_drv_driver; + +static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer); + +struct mg_drv { + struct platform_device *pdev; + int pwm_gpio; + int gpio_pwm_value; + unsigned long time; + struct hrtimer mytimer; + ktime_t kt; + int pwm_level; //0 : low ,1:high + int pwm_count; //pwm out time + int pwm_count2;//pwm stop time + bool pwm_stop; +}; + +struct mg_drv *glmg_driver = NULL; + +int mg_parse_dt(void) +{ + + struct device_node *node = glmg_driver->pdev->dev.of_node; + glmg_driver->pwm_gpio = of_get_named_gpio(node, "qcom,pwm_gpio", 0); + if (gpio_is_valid(glmg_driver->pwm_gpio)) + { + gpio_direction_output(glmg_driver->pwm_gpio, 1); + pr_err("relay gpio power on\n"); + } + return 0; +} + +static void gpio_pwm_start(void) +{ + pr_info("-----------gpio pwm start------------"); + + glmg_driver->time = (unsigned long)((50 * GPIO_PWM_DELAY_TIME)/100); + glmg_driver->pwm_level = 0; + glmg_driver->pwm_count = GPIO_PWM_OUT_TIME; + glmg_driver->pwm_count2 = 0; + glmg_driver->pwm_stop = false; + + hrtimer_init(&glmg_driver->mytimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); + glmg_driver->mytimer.function = hrtimer_handler; + glmg_driver->kt = ktime_set(0, GPIO_PWM_DELAY_TIME); + hrtimer_start(&glmg_driver->mytimer,glmg_driver->kt,HRTIMER_MODE_REL); +} + +static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer) +{ + if(glmg_driver->gpio_pwm_value == 0) + { + gpio_direction_output(glmg_driver->pwm_gpio, 0); + glmg_driver->pwm_level = 1; + return HRTIMER_NORESTART; + } + + glmg_driver->pwm_count--; + if(glmg_driver->pwm_count <= 0) + { + if(!glmg_driver->pwm_stop) + { + gpio_direction_output(glmg_driver->pwm_gpio, 0); + glmg_driver->pwm_stop = true; + glmg_driver->pwm_count2++; + if(glmg_driver->pwm_count2 == GPIO_PWM_BEEPER_TIMES) + { + glmg_driver->pwm_count = GPIO_PWM_LONG_STOP_TIME; + glmg_driver->pwm_count2 = 0; + } + else + glmg_driver->pwm_count = GPIO_PWM_OUT_TIME; + } + else + { + glmg_driver->pwm_stop = false; + glmg_driver->pwm_count = GPIO_PWM_STOP_TIME; + } + } + + if(!glmg_driver->pwm_level) { + + if(!glmg_driver->pwm_stop) + gpio_direction_output(glmg_driver->pwm_gpio, 0); + + glmg_driver->pwm_level = 1; + glmg_driver->kt = ktime_set(0, glmg_driver->time); + hrtimer_forward_now(&glmg_driver->mytimer, glmg_driver->kt); + //pr_err("--->low\n"); + + } else { + if(!glmg_driver->pwm_stop) + gpio_direction_output(glmg_driver->pwm_gpio, 1); + + glmg_driver->pwm_level =0; + glmg_driver->kt = ktime_set(0, glmg_driver->time); + hrtimer_forward_now(&glmg_driver->mytimer, glmg_driver->kt); + //pr_err("--->hight\n"); + } + return HRTIMER_RESTART; +} +/* +static ssize_t show_driver_attr_board_id(struct device_driver *dev, char *buf) +{ + + return snprintf(buf, 20, "%d\n", glmg_driver->board_id_value); +} + +static ssize_t store_driver_attr_board_id(struct device_driver *dev, const char *buf, size_t count) +{ + pr_err("store_driver_attr_board_id\n"); + return count; +} +*/ +static ssize_t show_driver_attr_gpio_pwm(struct device_driver *ddri, char *buf) +{ + + return snprintf(buf, 20, "%d\n", glmg_driver->gpio_pwm_value); +} + +static ssize_t store_driver_attr_gpio_pwm(struct device_driver *ddri, const char *buf, size_t count) +{ + ssize_t ret = -EINVAL; + unsigned long temp = 0; + + ret = kstrtoul(buf, 10, &temp); + if (ret) + return ret; + + if(temp >= 1) + temp = 1; + + if(temp <= 0) + temp = 0; + + pr_err("store_driver_attr_gpio_pwm value old %d, new %lu\n", glmg_driver->gpio_pwm_value,temp); + + if(temp) + { + glmg_driver->gpio_pwm_value = (int)temp; + gpio_pwm_start(); + pr_err("gpio pwm start\n"); + } + else + { + glmg_driver->gpio_pwm_value = (int)temp; + pr_err("gpio pwm change\n"); + } + pr_err("store_driver_attr_gpio_pwm %lu\n",temp); + return count; +} + +//static DRIVER_ATTR(board_id, S_IWUSR | S_IRUGO, show_driver_attr_board_id, store_driver_attr_board_id); +static DRIVER_ATTR(gpio_pwm, S_IWUSR | S_IRUGO, show_driver_attr_gpio_pwm, store_driver_attr_gpio_pwm); + +static int mg_drv_probe(struct platform_device *pdev) +{ + int ret = 0; + + glmg_driver = devm_kzalloc(&pdev->dev, sizeof(struct mg_drv), GFP_KERNEL); + + if (!glmg_driver) { + pr_err("unable to allocate platform data\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, glmg_driver); + glmg_driver->pdev = pdev; + + glmg_driver->gpio_pwm_value = 0; + + mg_parse_dt(); + + glmg_driver->pwm_level = 0; + + ret = gpio_request(glmg_driver->pwm_gpio, "pwm_gpio"); + if (ret < 0) { + pr_err("gpio req failed for id\n"); + ret = -ENODEV; + } + + if(driver_create_file(&mg_drv_driver.driver, &driver_attr_gpio_pwm)) + { + pr_err("mg_drv_probe driver_create_file ERROR \n"); + goto exit; + } + + pr_info("mg_drv_probe successfully probe\n"); + + return ret; + +exit: + pr_err("%s: probing chr failed, check hardware\n", + __func__); + + return ret; +} + +static int mg_drv_remove(struct platform_device *pdev) +{ + pr_err("mg_drv_remove\n"); + //driver_remove_file(&mg_drv_driver.driver,&driver_attr_board_id); + driver_remove_file(&mg_drv_driver.driver,&driver_attr_gpio_pwm); + return 0; +} + +static int mg_drv_suspend(struct device *dev) +{ + pr_err("mg_drv_suspend\n"); + return 0; +} + +static int mg_drv_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops mg_drv_pm_ops = { + .suspend = mg_drv_suspend, + .resume = mg_drv_resume, +}; + +static const struct of_device_id mg_drv_of_match[] = { + { .compatible = "qcom,mg_drv", }, + { } +}; +MODULE_DEVICE_TABLE(of, mg_drv_of_match); + +static struct platform_driver mg_drv_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "mg_drv", + .of_match_table = mg_drv_of_match, + .pm = &mg_drv_pm_ops, + }, + .probe = mg_drv_probe, + .remove = mg_drv_remove, +}; + +static int __init mg_drv_init(void) +{ + return platform_driver_register(&mg_drv_driver); +} + +static void __exit mg_drv_exit(void) +{ + platform_driver_unregister(&mg_drv_driver); +} + +MODULE_AUTHOR("mg Corporation"); +MODULE_DESCRIPTION("driver for mg "); +MODULE_LICENSE("GPL v2"); + +module_init(mg_drv_init); +module_exit(mg_drv_exit); + -- 2.25.1 From 0c29bd745aac710d853aff0a5e3850967a9d6f9c Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Jan 2020 18:14:29 -0500 Subject: [PATCH 06/76] MeiG Patch 20191204 huangshifang:BEEPER added to vibrator Change-Id: I1f997ded8859c33186bee36b36df4244f25dbf7c --- drivers/platform/msm/qpnp-vibrator.c | 99 ++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index a4a33b96837..4b1a4ac0edb 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -23,6 +23,17 @@ #include "../../staging/android/timed_output.h" #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define QPNP_VIB_VTG_CTL(base) (base + 0x41) #define QPNP_VIB_EN_CTL(base) (base + 0x46) @@ -44,6 +55,16 @@ enum qpnp_vib_mode { QPNP_VIB_DTEST3, }; +#define GPIO_PWM_DELAY_TIME (250000) + +static unsigned long gpio_pwm_delay_times[] = {1000000,1000000, 500000,500000, 333333,333333, 250000,250000,200000,200000,166666,166666,142857,142857,125000, 125000, \ + 111111,111111,100000,100000}; + +static unsigned long gpio_pwm_delay_index = 0; + + +static struct qpnp_vib *gl_vib = NULL; + struct qpnp_pwm_info { struct pwm_device *pwm_dev; u32 pwm_channel; @@ -70,10 +91,19 @@ struct qpnp_vib { //add by liangdi int vib_gpio; u32 vib_gpio_flags; + u32 pwm_gpio_flags; //add end + int pwm_gpio; + struct hrtimer mytimer; + ktime_t kt; + unsigned long time; + int pwm_level; //0: low ,1:high + int gpio_pwm_value; }; +static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer); + static int qpnp_vib_read_u8(struct qpnp_vib *vib, u8 *data, u16 reg) { int rc; @@ -148,6 +178,51 @@ static int qpnp_vibrator_config(struct qpnp_vib *vib) return rc; } +static void gpio_pwm_start(void) +{ + unsigned long delay_time = gpio_pwm_delay_times[gpio_pwm_delay_index++]; + + if (gpio_pwm_delay_index == 20) + gpio_pwm_delay_index = 0; + + pr_info("--------------gpio pwm start---------------"); + gl_vib->time = (unsigned long)((50 * delay_time)/100); + gl_vib->pwm_level = 0; + + hrtimer_init(&gl_vib->mytimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); + gl_vib->mytimer.function = hrtimer_handler; + gl_vib->kt = ktime_set(0, delay_time); + hrtimer_start(&gl_vib->mytimer,gl_vib->kt,HRTIMER_MODE_REL); +} + +static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer) +{ + if(gl_vib->gpio_pwm_value == 0) + { + gpio_direction_output(gl_vib->pwm_gpio, 0); + gl_vib->pwm_level = 1; + return HRTIMER_NORESTART; + } + + if(!gl_vib->pwm_level){ + + gpio_direction_output(gl_vib->pwm_gpio, 0); + + gl_vib->pwm_level = 1; + gl_vib->kt = ktime_set(0, gl_vib->time); + hrtimer_forward_now(&gl_vib->mytimer, gl_vib->kt); + + } else { + + gpio_direction_output(gl_vib->pwm_gpio, 1); + + gl_vib->pwm_level = 0; + gl_vib->kt = ktime_set(0, gl_vib->time); + hrtimer_forward_now(&gl_vib->mytimer, gl_vib->kt); + } + return HRTIMER_RESTART; +} + static int qpnp_vib_set(struct qpnp_vib *vib, int on) { int rc; @@ -171,6 +246,9 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(vib->vib_gpio, 0); } //add end + + vib->gpio_pwm_value = 1; + gpio_pwm_start(); } } else { if (vib->mode != QPNP_VIB_MANUAL) { @@ -190,6 +268,8 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(vib->vib_gpio, 1); } //add end + + vib->gpio_pwm_value = 0; } } @@ -276,6 +356,14 @@ static int qpnp_vib_parse_dt(struct qpnp_vib *vib) /* vibrator */ vib->vib_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "vib-gpios", 0, &vib->vib_gpio_flags); + vib->pwm_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "pwm-gpios", + 0, &vib->pwm_gpio_flags); + + if (gpio_is_valid(vib->pwm_gpio)) + { + gpio_direction_output(vib->pwm_gpio, 1); + pr_err("pwm gpio power on\n"); + } //add end vib->timeout = QPNP_VIB_DEFAULT_TIMEOUT; rc = of_property_read_u32(spmi->dev.of_node, @@ -357,6 +445,7 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) struct qpnp_vib *vib; struct resource *vib_resource; int rc; + int ret = 0; vib = devm_kzalloc(&spmi->dev, sizeof(*vib), GFP_KERNEL); if (!vib) @@ -370,12 +459,20 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) return -EINVAL; } vib->base = vib_resource->start; + vib->gpio_pwm_value = 0; rc = qpnp_vib_parse_dt(vib); if (rc) { dev_err(&spmi->dev, "DT parsing failed\n"); return rc; } + + ret = gpio_request(vib->pwm_gpio, "pwm_gpio"); + if(ret < 0) + { + pr_err("gpio req failed for id\n"); + ret = -ENODEV; + } rc = qpnp_vibrator_config(vib); if (rc) { @@ -398,6 +495,8 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) rc = timed_output_dev_register(&vib->timed_dev); if (rc < 0) return rc; + + gl_vib = vib; return rc; } -- 2.25.1 From e66dea8dbdb9f97b30dca345fc61c9b8e41950fb Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Jan 2020 19:00:13 -0500 Subject: [PATCH 07/76] MeiG Patch 20200113 huangshifang:Modify compass not available Change-Id: Id0ba7e2c223b34679dcc5eab38fdcc7ea9660e9d --- arch/arm/boot/dts/qcom/msm8909-qrd.dtsi | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi index d0c00183fa0..d9c6ac94d36 100755 --- a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi @@ -67,7 +67,7 @@ label = "volume_up"; gpios = <&msm_gpio 90 0x1>; linux,input-type = <1>; - linux,code = <0x19c>;/* KEY_PREVIOUS <115>;*/ + linux,code = <115>;/* KEY_PREVIOUS <115>;*/ gpio-key,wakeup; debounce-interval = <15>; }; @@ -75,17 +75,18 @@ label = "volume_down"; gpios = <&msm_gpio 11 0x1>; linux,input-type = <1>; - linux,code = <0x197>;/* KEY_NEXT <114>;*/ + linux,code = <114>;/* KEY_NEXT <114>;*/ gpio-key,wakeup; debounce-interval = <15>; }; - + /* home_key { label = "home_key"; gpios = <&msm_gpio 98 0x1>; linux,input-type = <1>; - linux,code = <28>; /* KEY_ENTER <102>*/ + linux,code = <28>; //KEY_ENTER <102> }; + */ }; }; @@ -143,7 +144,8 @@ status = "okay"; qcom,vib-timeout-ms = <15000>; qcom,vib-vtg-level-mV = <3100>; - vib-gpios = <&msm_gpio 16 0x1>; + //vib-gpios = <&msm_gpio 16 0x1>; + pwm-gpios = <&msm_gpio 98 0x1>; }; }; }; -- 2.25.1 From 9d38a138b1f4120bacf2b1397a16dac9ccf46c18 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Jan 2020 19:44:15 -0500 Subject: [PATCH 08/76] MeiG Patch 20200115 liangdi:change to mtp Change-Id: I1cb225b7d6f34c62dc291f124690db7b3d7a88b1 --- .../boot/dts/qcom/msm8909-mdss-panels.dtsi | 3 + arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 297 ++++++++++++------ arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 12 +- 3 files changed, 212 insertions(+), 100 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi index bce3922040c..714e4dc1667 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi @@ -23,6 +23,9 @@ #include "dsi-panel-auo-qvga-cmd.dtsi" #include "dsi-panel-auo-cx-qvga-cmd.dtsi" #include "dsi-panel-390p-auo-cmd.dtsi" +#include "dsi-panel-hx8394f-zzw500hah-720p-video.dtsi" +#include "dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi" +#include "dsi-panel-ortustech32-video.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index e1620532654..2b9cd9c59ce 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -11,9 +11,10 @@ */ #include "msm8909.dtsi" +#include "msm8909-pm8909.dtsi" #include "msm8909-pinctrl.dtsi" #include "msm8909-regulator.dtsi" -#include "msm8909-camera-sensor-mtp.dtsi" +//#include "msm8909-camera-sensor-mtp.dtsi" &soc { @@ -31,13 +32,13 @@ pinctrl-0 = <&smb_int_default>; qcom,bmd-algo-disabled; - qcom,float-voltage-mv = <4200>; + qcom,float-voltage-mv = <4350>; qcom,charging-timeout = <1536>; qcom,recharge-thresh-mv = <100>; regulator-name = "smb1357_otg_vreg"; qcom,soft-vfloat-comp-disabled; - qcom,thermal-mitigation = <1500 700 600 0>; - + qcom,thermal-mitigation = <2000 1500 1000 0>; + qcom,fastchg-ma = <2000>; qcom,bms-psy-name = "bms"; /* @@ -60,7 +61,7 @@ * set status = "ok" and * add 'qcom,use-external-charger' to pm8909_chg node */ - status = "disabled"; + status = "ok"; }; }; @@ -134,7 +135,63 @@ synaptics,disable-gpios; synaptics,display-coords = <0 0 719 1279>; synaptics,panel-coords = <0 0 719 1405>; + status = "disabled"; }; + + goodix@5d { + compatible = "goodix,gt9xx"; + reg = <0x5d>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x00>; + reset-gpios = <&msm_gpio 12 0x00>; + interrupt-gpios = <&msm_gpio 13 0x2002>; + vdd-supply = <&pm8909_l17>; + vcc_i2c-supply = <&pm8909_l6>; + // pins used by touchscreen + pinctrl-names = "pmx_ts_active", + "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + goodix,i2c-pull-up; + goodix,no-force-update; + goodix,panel-coords = <0 0 480 800>; + goodix,display-coords = <0 0 480 800>; + goodix,button-map= <139 172 158>; + goodix,product-id0 = "917S"; + goodix,product-id1 = "917S"; + //goodix,fw_name = "gtp_fw.bin";if open, there is a null pointer in sysfs_remove_group + goodix,enable-power-off; + goodix,cfg-data0 = [ + 01 E0 01 20 03 05 0D 00 00 40 + 00 0F 78 64 53 11 01 00 00 00 + 14 17 19 1D 0F 04 00 00 00 00 + 00 00 04 51 14 00 00 00 00 00 + 32 00 00 50 54 28 85 25 10 37 + 39 A2 07 38 6D 62 93 02 24 00 + 00 28 50 C0 02 02 00 00 53 B1 + 2E 9E 35 8D 3B 80 42 76 49 6D + 00 00 00 00 00 00 00 F0 4C 3C + FF FF 07 14 14 00 00 00 00 00 + 00 00 00 00 00 00 00 00 50 73 + 50 32 FF FF 00 00 00 00 00 00 + 00 00 00 28 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 0D 0E 0F 10 12 13 14 15 1F 1D + 1B 1A 19 18 17 16 FF FF FF FF + FF FF FF FF FF FF FF FF FF FF + FF FF 06 08 0C 12 13 14 15 17 + 18 19 FF FF FF FF FF FF FF FF + FF FF FF FF 00 00 05 00 00 0F + 00 00 00 80 46 08 96 50 32 0A + 0A 64 32 00 00 00 00 00 00 70 + 22 03 0C 08 23 00 14 23 00 28 + 46 30 3C D0 07 50 30 02 01]; + goodix,cfg-data1 = []; + goodix,have-touch-key; + goodix,driver-send-cfg; + }; }; i2c@78b6000 { /* BLSP1 QUP2 */ @@ -153,9 +210,16 @@ pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; clocks = <&clock_rpm clk_bb_clk2_pin>; clock-names = "ref_clk"; + status = "disabled"; }; }; + mg_drv{ + compatible = "qcom,mg_drv"; + status = "ok"; + qcom,pwm_gpio = <&msm_gpio 98 0x0>; + }; + gen-vkeys { compatible = "qcom,gen-vkeys"; label = "synaptics_dsx"; @@ -173,29 +237,20 @@ pinctrl-0 = <&gpio_key_active>; pinctrl-1 = <&gpio_key_suspend>; - camera_focus { - label = "camera_focus"; - gpios = <&msm_gpio 91 0x1>; - linux,input-type = <1>; - linux,code = <0x210>; - gpio-key,wakeup; - debounce-interval = <15>; - }; - - camera_snapshot { - label = "camera_snapshot"; - gpios = <&msm_gpio 92 0x1>; + key_previous { + label = "volume_up"; + gpios = <&msm_gpio 90 0x1>; linux,input-type = <1>; - linux,code = <0x2fe>; + linux,code = <0x19c>;/* KEY_PREVIOUS <0x19c>;*/ gpio-key,wakeup; debounce-interval = <15>; }; - vol_up { - label = "volume_up"; - gpios = <&msm_gpio 90 0x1>; + key_next { + label = "volume_down"; + gpios = <&msm_gpio 91 0x1>; linux,input-type = <1>; - linux,code = <115>; + linux,code = <0x197>;/* KEY_NEXT <0x197>;*/ gpio-key,wakeup; debounce-interval = <15>; }; @@ -298,10 +353,15 @@ qcom,rpull-up-kohm = <100>; qcom,vref-batt-therm = <1800000>; - #include "batterydata-palladium.dtsi" + //#include "batterydata-palladium.dtsi" + #include "batterydata-qrd-skua-4v35-2000mah.dtsi" }; }; +&pm8909_vib { + status = "okay"; +}; + &qcom_rng { status = "okay"; }; @@ -350,14 +410,15 @@ &sdhc_2 { #address-cells = <0>; interrupt-parent = <&sdhc_2>; - interrupts = <0 1 2>; + //interrupts = <0 1 2>; + interrupts = <0 1>; #interrupt-cells = <1>; interrupt-map-mask = <0xffffffff>; interrupt-map = <0 &intc 0 125 0 - 1 &intc 0 221 0 - 2 &msm_gpio 38 0>; - interrupt-names = "hc_irq", "pwr_irq", "status_irq"; - cd-gpios = <&msm_gpio 38 0x1>; + 1 &intc 0 221 0>; + // 2 &msm_gpio 38 0>; + interrupt-names = "hc_irq", "pwr_irq";//, "status_irq"; + //cd-gpios = <&msm_gpio 38 0x1>; vdd-supply = <&pm8909_l11>; qcom,vdd-voltage-level = <1800000 2950000>; @@ -370,59 +431,79 @@ pinctrl-names = "active", "sleep"; pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + qcom,nonremovable; status = "ok"; }; &i2c_1 { /* BLSP1 QUP1 */ - mpu6050@68 { /* Gyroscope and accelerometer sensor combo */ - compatible = "invn,mpu6050"; - reg = <0x68>; - pinctrl-names = "mpu_default","mpu_sleep"; - pinctrl-0 = <&mpu6050_default>; - pinctrl-1 = <&mpu6050_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <96 0x1>; - vdd-supply = <&pm8909_l17>; - vlogic-supply = <&pm8909_l6>; - invn,gpio-int = <&msm_gpio 96 0x1>; - invn,place = "Portrait Down Back Side"; - }; - - avago@39 { /* Ambient light and proximity sensor */ - compatible = "avago,apds9900"; - reg = <0x39>; + //light and proximity sensor +/* + liteon@23 { + compatible = "liteon,ltr553"; + reg = <0x23>; pinctrl-names = "default","sleep"; - pinctrl-0 = <&apds99xx_default>; - pinctrl-1 = <&apds99xx_sleep>; + pinctrl-0 = <<r553_default>; + pinctrl-1 = <<r553_sleep>; interrupt-parent = <&msm_gpio>; - interrupts = <94 0x2002>; + interrupts = <94 0x2>; vdd-supply = <&pm8909_l17>; vio-supply = <&pm8909_l6>; - avago,irq-gpio = <&msm_gpio 94 0x2002>; - avago,ps-threshold = <600>; - avago,ps-hysteresis-threshold = <500>; - avago,ps-pulse = <8>; - avago,ps-pgain = <0>; - avago,als-B = <186>; - avago,als-C = <75>; - avago,als-D = <129>; - avago,ga-value = <256>; + liteon,intr = <&msm_gpio 94 0x2>; + liteon,highthr = <800>; + liteon,lowthr = <300>; }; - - akm@c { /* Magnetic field sensor */ - compatible = "ak,ak8963"; +*/ + akm@c { + compatible = "ak,ak09911"; reg = <0x0c>; - pinctrl-names = "ak8963_default", "ak8963_sleep"; - pinctrl-0 = <&ak8963_default>; - pinctrl-1 = <&ak8963_sleep>; + pinctrl-names = "default","sleep"; + pinctrl-0 = <&akm_default>; + pinctrl-1 = <&akm_sleep>; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + akm,layout = <0x3>; + akm,poll_interval = <200>; + akm,gpio_rstn = <&msm_gpio 16 0x0>; + akm,auto-report; + }; + + bosch@18 { //Accelerometer sensor + compatible = "bosch,bma2x2"; + status = "disabled"; + reg = <0x18>; + pinctrl-names = "default"; + pinctrl-0 = <&bma2x2_int1_default &bma2x2_int2_default>; interrupt-parent = <&msm_gpio>; - interrupts = <65 0x2>; + interrupts = <96 0x2002>; vdd-supply = <&pm8909_l17>; vio-supply = <&pm8909_l6>; - ak,layout = <0x6>; - ak,auto-report; + bosch,init-interval = <200>; + bosch,place = <2>; + bosch,gpio-int1 = <&msm_gpio 96 0x2002>; + bosch,gpio-int2 = <&msm_gpio 31 0x2002>; }; + + bmp@76 { + compatible = "bmp280"; + reg = <0x76>; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + }; + + bosch@68 { /* Accelerometer and gyroscope sensor */ + compatible = "bosch,bmi160"; + //status = "disabled"; + reg = <0x68>; + pinctrl-names = "default"; + pinctrl-0 = <&bmi160_int1_default>; + interrupt-parent = <&msm_gpio>; + interrupts = <95 0x2002>; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + bosch,place = <5>; + bosch,gpio-int1 = <&msm_gpio 95 0x2002>; + }; }; &mdss_mdp { @@ -473,18 +554,18 @@ pmx_mdss { mdss_dsi_active: mdss_dsi_active { mux { - pins = "gpio25", "gpio37"; + pins = "gpio25", "gpio17"; }; config { - pins = "gpio25", "gpio37"; + pins = "gpio25", "gpio17"; }; }; mdss_dsi_suspend: mdss_dsi_suspend { mux { - pins = "gpio25", "gpio37"; + pins = "gpio25", "gpio17"; }; config { - pins = "gpio25", "gpio37"; + pins = "gpio25", "gpio17"; }; }; }; @@ -506,8 +587,8 @@ }; }; }; - mpu6050_int_pin { - mpu6050_default: mpu6050_default { + bma2x2_int1_pin { + bma2x2_int1_default: int1_default { mux { pins = "gpio96"; function = "gpio"; @@ -515,34 +596,51 @@ config { pins = "gpio96"; drive-dtrength = <6>; - bias-pull-down; + bias-pull-up; }; }; - mpu6050_sleep: mpu6050_sleep { + }; + bma2x2_int2_pin { + bma2x2_int2_default: int2_default { mux { - pins = "gpio96"; + pins = "gpio65"; function = "gpio"; }; config { - pins = "gpio96"; - drive-dtrength = <2>; - bias-pull-down; + pins = "gpio65"; + drive-dtrength = <6>; + bias-pull-up; }; }; }; - apds99xx_int_pin { - apds99xx_default: apds99xx_default { + + bmi160_int1_pin { + bmi160_int1_default: int1_default { + mux { + pins = "gpio95"; + function = "gpio"; + }; + config { + pins = "gpio95"; + drive-dtrength = <6>; + bias-pull-up; + }; + }; + }; + + ltr553_int_pin { + ltr553_default: ltr553_default { mux { pins = "gpio94"; function = "gpio"; }; config { pins = "gpio94"; - drive-strength = <6>; - bias-pull-up; + drive-dtrength = <6>; + bias-pull-up; }; }; - apds99xx_sleep: apds99xx_sleep { + ltr553_sleep: ltr553_sleep { mux { pins = "gpio94"; function = "gpio"; @@ -550,23 +648,24 @@ config { pins = "gpio94"; drive-strength = <2>; - bias-pull-down; + bias-pull-down; }; }; - }; - ak8963_int_pin { - ak8963_default: ak8963_default { + }; + + akm_reset_pin { + akm_default: akm_default { mux { pins = "gpio65"; function = "gpio"; }; config { pins = "gpio65"; - drive-strength = <6>; - bias-pull-up; + drive-dtrength = <6>; + bias-pull-up; }; }; - ak8963_sleep: ak8963_sleep { + akm_sleep: akm_sleep { mux { pins = "gpio65"; function = "gpio"; @@ -574,20 +673,30 @@ config { pins = "gpio65"; drive-strength = <2>; - bias-pull-down; + bias-pull-down; }; }; - }; + }; + }; +&dsi_ortustech32_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8909_mpps 2 0>; + qcom,cont-splash-enabled; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; &mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + //qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; + qcom,dsi-pref-prim-pan = <&dsi_ortustech32_video>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; qcom,platform-reset-gpio = <&msm_gpio 25 0>; - qcom,platform-bklight-en-gpio = <&msm_gpio 37 0>; + qcom,platform-bklight-en-gpio = <&msm_gpio 17 0>; }; /* CoreSight */ diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index 2e968b72912..3dd3b9b7bbe 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -266,7 +266,7 @@ pmx_mdss { mdss_dsi_active: mdss_dsi_active { mux { - pins = "gpio25", "gpio37"; + pins = "gpio25", "gpio17"; function = "gpio"; }; @@ -279,7 +279,7 @@ mdss_dsi_suspend: mdss_dsi_suspend { mux { - pins = "gpio25", "gpio37"; + pins = "gpio25", "gpio17"; function = "gpio"; }; @@ -909,20 +909,20 @@ tlmm_gpio_key { gpio_key_active: gpio_key_active { mux { - pins = "gpio90", "gpio92", "gpio11"; + pins = "gpio90", "gpio91", "gpio92"; function = "gpio"; }; config { - pins = "gpio90", "gpio92", "gpio11"; - drive-strength = <2>; + pins = "gpio90", "gpio91", "gpio92"; + drive-strength = <10>; bias-pull-up; }; }; gpio_key_suspend: gpio_key_suspend { mux { - pins = "gpio91", "gpio91", "gpio92"; + pins = "gpio90", "gpio91", "gpio92"; function = "gpio"; }; -- 2.25.1 From 3ad99729504fbd5267d16400d5366a6c75a7bf6c Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Jan 2020 20:15:55 -0500 Subject: [PATCH 09/76] MeiG 20200116 Patch liangdi:limit charging max current 2000mA Change-Id: Ic6c49ed1638ec4127aa618a4f2d2d13bf5d7896f --- drivers/power/smb135x-charger.c | 48 ++++++++++++++++++++++++++++++--- include/linux/usb/msm_hsusb.h | 4 +-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 69eeecb75aa..65450132143 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -179,6 +179,7 @@ #define USB_AC_VAL 0x01 #define CMD_CHG_REG 0x42 +#define THERM_MONI_EN BIT(4) #define CMD_CHG_EN BIT(1) #define OTG_EN BIT(0) @@ -1181,7 +1182,7 @@ static int smb135x_set_fastchg_current(struct smb135x_chg *chip, rc = smb135x_masked_write(chip, CFG_1C_REG, FCC_MASK, reg); if (rc < 0) dev_err(chip->dev, "cannot write to config c rc = %d\n", rc); - pr_debug("fastchg current set to %dma\n", + pr_err("fastchg current set to %dma\n", chip->fastchg_current_table[i]); return rc; } @@ -1226,6 +1227,7 @@ static int smb135x_set_high_usb_chg_current(struct smb135x_chg *chip, dev_err(chip->dev, "Couldn't write cfg 5 rc = %d\n", rc); else chip->real_usb_psy_ma = chip->usb_current_table[i]; + pr_err("usb real current_ma %d\n",chip->usb_current_table[i]); return rc; } @@ -1243,7 +1245,7 @@ static int smb135x_set_usb_chg_current(struct smb135x_chg *chip, { int rc; - pr_debug("USB current_ma = %d\n", current_ma); + pr_err("USB current_ma = %d\n", current_ma); if (chip->workaround_flags & WRKARND_USB100_BIT) { pr_info("USB requested = %dmA using %dmA\n", current_ma, @@ -1393,6 +1395,17 @@ static int smb135x_charging_enable(struct smb135x_chg *chip, int enable) enable, rc); return rc; } +/* + rc = smb135x_masked_write(chip, CMD_CHG_REG, + THERM_MONI_EN, THERM_MONI_EN); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set CHG_ENABLE_BIT enable = %d rc = %d\n", + enable, rc); + return rc; + } +*/ + pr_err("charging enable = %d\n", enable); return 0; } @@ -2077,7 +2090,7 @@ static void smb135x_external_power_changed(struct power_supply *psy) else current_limit = prop.intval / 1000; - pr_debug("current_limit = %d\n", current_limit); + pr_err("current_limit = %d\n", current_limit); if (chip->usb_psy_ma != current_limit) { mutex_lock(&chip->current_change_lock); @@ -2823,7 +2836,7 @@ static int handle_usb_insertion(struct smb135x_chg *chip) } usb_type_name = usb_type_str[usb_type_index]; usb_supply_type = usb_type_enum[usb_type_index]; - pr_debug("inserted %s, usb psy type = %d stat_5 = 0x%02x apsd_rerun = %d\n", + pr_err("inserted %s, usb psy type = %d stat_5 = 0x%02x apsd_rerun = %d\n", usb_type_name, usb_supply_type, reg, chip->apsd_rerun); if (chip->batt_present && !chip->apsd_rerun && chip->usb_psy) { @@ -4247,6 +4260,7 @@ static int smb135x_main_charger_probe(struct i2c_client *client, struct smb135x_chg *chip; struct power_supply *usb_psy; u8 reg = 0; + u8 product_id = 0; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) { @@ -4285,6 +4299,32 @@ static int smb135x_main_charger_probe(struct i2c_client *client, mutex_init(&chip->otg_oc_count_lock); device_init_wakeup(chip->dev, true); wakeup_source_init(&chip->wake_source.source, "smb_wake_source"); + + //add by liangdi for check smb135x 20191115 + rc = read_version2(chip, &product_id);//check smb1358 05-0-06 + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read product id rc = %d,addr 0x%x\n", rc,chip->client->addr); + + chip->client->addr = 0x1C;//check smb1358 05-0-05 + rc = read_version2(chip, &product_id); + + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read product id rc = %d,addr 0x%x\n", rc,chip->client->addr); + //goto read_version_fail; + } + else + { + pr_info("smb1358 05-0-05 read product id 0x%x",product_id); + } + } + else + { + pr_info("smb1358 05-0-06 read product id 0x%x",product_id); + } + //add end + /* probe the device to check if its actually connected */ rc = smb135x_read(chip, CFG_4_REG, ®); if (rc) { diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 7414d398456..6cf3473ef41 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -120,9 +120,9 @@ enum msm_usb_phy_type { QUSB_ULPI_PHY, }; -#define IDEV_CHG_MAX 1500 +#define IDEV_CHG_MAX 2000 //1500 //modify by liangdi for 2A current 20200115 #define IUNIT 100 -#define IDEV_HVDCP_CHG_MAX 1800 +#define IDEV_HVDCP_CHG_MAX 2000 //1800 //modify by liangdi for 2A current 20200115 /** * Different states involved in USB charger detection. -- 2.25.1 From ff86774e744b7ddbeb09d2d5a2083e1a60b056da Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 4 Feb 2020 09:08:48 -0500 Subject: [PATCH 10/76] kernel/msm-3.18: Fixed issue where Keyboard would crash when used. Issue caused by vibrator engine being triggered for beeping but not configured in PM8909 dtsi. Change-Id: I27426835b2e5126b88eb4a0bc9f030498b598712 --- arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi | 3 ++- drivers/platform/msm/qpnp-vibrator.c | 15 ++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi index 4f210806a64..94f557a34f3 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi @@ -13,7 +13,7 @@ &pm8909_chg { status = "ok"; - qcom,charging-disabled; + qcom,use-external-charger; }; &pm8909_bms { @@ -46,6 +46,7 @@ status = "okay"; qcom,vib-timeout-ms = <15000>; qcom,vib-vtg-level-mV = <3100>; + pwm-gpios = <&msm_gpio 98 0x1>; }; }; }; diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index 4b1a4ac0edb..fa890ac8394 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -57,12 +57,6 @@ enum qpnp_vib_mode { #define GPIO_PWM_DELAY_TIME (250000) -static unsigned long gpio_pwm_delay_times[] = {1000000,1000000, 500000,500000, 333333,333333, 250000,250000,200000,200000,166666,166666,142857,142857,125000, 125000, \ - 111111,111111,100000,100000}; - -static unsigned long gpio_pwm_delay_index = 0; - - static struct qpnp_vib *gl_vib = NULL; struct qpnp_pwm_info { @@ -180,18 +174,13 @@ static int qpnp_vibrator_config(struct qpnp_vib *vib) static void gpio_pwm_start(void) { - unsigned long delay_time = gpio_pwm_delay_times[gpio_pwm_delay_index++]; - - if (gpio_pwm_delay_index == 20) - gpio_pwm_delay_index = 0; - pr_info("--------------gpio pwm start---------------"); - gl_vib->time = (unsigned long)((50 * delay_time)/100); + gl_vib->time = (unsigned long)((50 * GPIO_PWM_DELAY_TIME)/100); gl_vib->pwm_level = 0; hrtimer_init(&gl_vib->mytimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); gl_vib->mytimer.function = hrtimer_handler; - gl_vib->kt = ktime_set(0, delay_time); + gl_vib->kt = ktime_set(0, GPIO_PWM_DELAY_TIME); hrtimer_start(&gl_vib->mytimer,gl_vib->kt,HRTIMER_MODE_REL); } -- 2.25.1 From 2f3643c3fcb38c8a287736eddcf6873a4ff09112 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 19 Feb 2020 07:41:27 -0500 Subject: [PATCH 11/76] MeiG liangdi: modify accelerometer direction Change-Id: I139a65994b8ca10ca18b1e78def3862493bea9fe --- drivers/input/misc/bmi160_driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/input/misc/bmi160_driver.c b/drivers/input/misc/bmi160_driver.c index 627440c160a..bd18a537394 100755 --- a/drivers/input/misc/bmi160_driver.c +++ b/drivers/input/misc/bmi160_driver.c @@ -884,6 +884,10 @@ static void bmi_work_func(struct work_struct *work) bmi160_udata.z = data.z; bmi_remap_sensor_data(&bmi160_udata, client_data); + //add by liangdi 20200211 + bmi160_udata.x = -bmi160_udata.x; + bmi160_udata.y = -bmi160_udata.y; + //add end /*report current frame via input event*/ input_event(client_data->input_accel, EV_ABS, ABS_X, bmi160_udata.x); input_event(client_data->input_accel, EV_ABS, ABS_Y, bmi160_udata.y); -- 2.25.1 From e90878e0aca9d08838d08efbe7f0d51d1ad6e37c Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 19 Feb 2020 07:43:48 -0500 Subject: [PATCH 12/76] MeiG: Liangdi: allowreading of battery voltage and temperature Change-Id: Ic8358c5ac97c2e3fd9f40b509e2bc5c705550e99 --- drivers/power/qpnp-vm-bms.c | 24 +++++++++++ drivers/power/smb135x-charger.c | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/drivers/power/qpnp-vm-bms.c b/drivers/power/qpnp-vm-bms.c index fc685f1e9f0..75c305925d8 100644 --- a/drivers/power/qpnp-vm-bms.c +++ b/drivers/power/qpnp-vm-bms.c @@ -2187,6 +2187,24 @@ static int get_prop_bms_current_now(struct qpnp_bms_chip *chip) return chip->current_now; } +//add by liangdi for read voltage and temperature 20200212 +static int get_prop_battery_voltage_now(struct qpnp_bms_chip *chip) +{ + int rc; + struct qpnp_vadc_result adc_result; + + rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &adc_result); + if (rc) { + pr_err("error reading adc channel = %d, rc = %d\n", + VBAT_SNS, rc); + return rc; + } + pr_debug("mvolts phy=%lld meas=0x%llx\n", adc_result.physical, + adc_result.measurement); + return (int)adc_result.physical; +} +//add end + static int get_current_cc(struct qpnp_bms_chip *chip) { int soc, cc_full; @@ -2225,6 +2243,7 @@ static enum power_supply_property bms_power_props[] = { POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_VOLTAGE_NOW, }; static int @@ -2306,6 +2325,11 @@ static int qpnp_vm_bms_power_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: val->intval = get_current_cc(chip); break; + //add by liangdi for read voltage and temperature 20200212 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = get_prop_battery_voltage_now(chip); + break; + //add end default: return -EINVAL; } diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 65450132143..80c20b7b2a5 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -729,6 +729,10 @@ static enum power_supply_property smb135x_battery_properties[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_OCV, + POWER_SUPPLY_PROP_CURRENT_NOW, }; static int smb135x_get_prop_batt_status(struct smb135x_chg *chip) @@ -822,6 +826,60 @@ static int smb135x_get_prop_batt_capacity(struct smb135x_chg *chip) return DEFAULT_BATT_CAPACITY; } +//add by liangdi for read voltage and temperature 20200212 +static int smb135x_get_prop_batt_temp(struct smb135x_chg *chip) +{ + union power_supply_propval ret = {0, }; + + if (chip->bms_psy) { + chip->bms_psy->get_property(chip->bms_psy, + POWER_SUPPLY_PROP_TEMP, &ret); + return ret.intval; + } + + return 0; +} + +static int smb135x_get_prop_batt_voltage(struct smb135x_chg *chip) +{ + union power_supply_propval ret = {0, }; + + if (chip->bms_psy) { + chip->bms_psy->get_property(chip->bms_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret); + return ret.intval; + } + + return 0; +} + +static int smb135x_get_prop_batt_voltage_ocv(struct smb135x_chg *chip) +{ + union power_supply_propval ret = {0, }; + + if (chip->bms_psy) { + chip->bms_psy->get_property(chip->bms_psy, + POWER_SUPPLY_PROP_VOLTAGE_OCV, &ret); + return ret.intval; + } + + return 0; +} + +static int smb135x_get_prop_batt_current(struct smb135x_chg *chip) +{ + union power_supply_propval ret = {0, }; + + if (chip->bms_psy) { + chip->bms_psy->get_property(chip->bms_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &ret); + return ret.intval; + } + + return 0; +} +//add end + static int smb135x_get_prop_batt_health(struct smb135x_chg *chip) { union power_supply_propval ret = {0, }; @@ -1665,6 +1723,20 @@ static int smb135x_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: val->intval = chip->therm_lvl_sel; break; + //add by liangdi for read voltage and temperature 20200212 + case POWER_SUPPLY_PROP_TEMP: + val->intval = smb135x_get_prop_batt_temp(chip); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = smb135x_get_prop_batt_voltage(chip); + break; + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + val->intval = smb135x_get_prop_batt_voltage_ocv(chip); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = smb135x_get_prop_batt_current(chip); + break; + //add end default: return -EINVAL; } -- 2.25.1 From 57862f00a8f7edf1b50fbf960b02d814bb5c6d6f Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 19 Feb 2020 07:48:34 -0500 Subject: [PATCH 13/76] MeiG liangdi: modify magnetometer direction Change-Id: Ieb666ed1ad9e04191c8c9a0a8c14040fdfdd6ccd --- drivers/input/misc/akm09911m.c | 176 ++++++++------------------------- 1 file changed, 40 insertions(+), 136 deletions(-) diff --git a/drivers/input/misc/akm09911m.c b/drivers/input/misc/akm09911m.c index 87c3bbc5e46..f78a8bd800f 100755 --- a/drivers/input/misc/akm09911m.c +++ b/drivers/input/misc/akm09911m.c @@ -1878,21 +1878,12 @@ static int akm_pinctrl_init(struct akm_compass_data *akm) return 0; } #define CALIBRATION_BY_OURSELF 1 -//static int calibrate_xyz[3] = {-13,-28,-80}; -//static int calibrate_xyz[3] = {5,-31,24}; -//static int calibrate_xyz[3] = {12,-23,25}; -//static int calibrate_xyz[3] = {54,40,41}; -//static int calibrate_xyz[3] = {58,78,35}; -//static int calibrate_xyz[3] = {52,39,35}; -//static int calibrate_xyz[3] = {53,67,31}; #if CALIBRATION_BY_OURSELF static int calibrate_xyz[3] = {70,7,-8}; -static int max_xyz[3] = {126,64,50}; -static int min_xyz[3] = {14,-50,-66}; -//static int max_xyz1[3] = {0,0,0}; -//static int min_xyz1[3] = {0,0,0}; -static int range_xyz[3] = {112,114,116}; +static int max_xyz[3] = {60,60,60}; +static int min_xyz[3] = {-60,-60,-60}; +static int range_xyz[3] = {120,120,120}; static void akm_calibrate_xyz(int *data) { //static bool first_data = 1; @@ -1900,104 +1891,35 @@ static void akm_calibrate_xyz(int *data) int i = 0; /* if(first_data) - { - max_xyz1[0] = min_xyz1[0] = data[0]; - max_xyz1[1] = min_xyz1[1] = data[1]; - max_xyz1[2] = min_xyz1[2] = data[2]; + { + max_xyz[0] = min_xyz[0] = data[0]; + max_xyz[1] = min_xyz[1] = data[1]; + max_xyz[2] = min_xyz[2] = data[2]; first_data = 0; - //return; - } + return; + } */ + for(i = 0;i < 3;i ++) { - /* - if(max_xyz1[i] < data[i] || min_xyz1[i] > data[i]) + if(max_xyz[i] < data[i] || min_xyz[i] > data[i]) { - if(max_xyz1[i] < data[i]) max_xyz1[i] = data[i]; - else min_xyz1[i] = data[i]; - if(!calibrate_use_defult[i]) - { - if(max_xyz1[i] - min_xyz1[i] - range_xyz[i] > -50) - { - first_data = 0; - calibrate_use_defult[0] = 1; - calibrate_use_defult[1] = 1; - calibrate_use_defult[2] = 1; - return; - } - calibrate_xyz[i] = (max_xyz1[i] + min_xyz1[i]) / 2; - } - } - */ - //if(calibrate_use_defult[i]) - //{ - if(max_xyz[i] < data[i] || min_xyz[i] > data[i]) + if(max_xyz[i] < data[i]) { - if(max_xyz[i] < data[i]) - { - max_xyz[i] = data[i]; - min_xyz[i] = max_xyz[i] - range_xyz[i]; - } - else - { - min_xyz[i] = data[i]; - max_xyz[i] = min_xyz[i] + range_xyz[i]; - } - calibrate_xyz[i] = (max_xyz[i] + min_xyz[i]) / 2; + max_xyz[i] = data[i]; + min_xyz[i] = max_xyz[i] - range_xyz[i]; } - /* - if(max_xyz1[i] - min_xyz1[i] - range_xyz[i] > -80) + else { - calibrate_xyz[i] = (max_xyz1[i] + min_xyz1[i]) / 2; - calibrate_use_defult[i] = 0; + min_xyz[i] = data[i]; + max_xyz[i] = min_xyz[i] + range_xyz[i]; } - */ - //} - } - /* - if(max_xyz[0] < data[0] || min_xyz[0] > data[0]) - { - if(max_xyz[0] < data[0]) - { - max_xyz[0] = data[0]; - min_xyz[0] = max_xyz[0] - range_xyz[0]; - } - else - { - min_xyz[0] = data[0]; - max_xyz[0] = min_xyz[0] + range_xyz[0]; - } - calibrate_xyz[0] = (max_xyz[0] + min_xyz[0])/2; + calibrate_xyz[i] = (max_xyz[i] + min_xyz[i]) / 2; + //pr_err("max_x %d:max_y %d:max_z %d\n",max_xyz[0],max_xyz[1],max_xyz[2]); + //pr_err("min_x %d:min_y %d:min_z %d\n",min_xyz[0],min_xyz[1],min_xyz[2]); + //pr_err("range_x %d:range_y %d:range_z %d\n",max_xyz[0]-min_xyz[0],max_xyz[1]-min_xyz[1],max_xyz[2]-min_xyz[2]); } - if(max_xyz[1] < data[1] || min_xyz[1] > data[1]) - { - if(max_xyz[1] < data[1]) - { - max_xyz[1] = data[1]; - min_xyz[1] = max_xyz[1] - range_xyz[1]; - } - else - { - min_xyz[1] = data[1]; - max_xyz[1] = min_xyz[1] + range_xyz[1]; - } - calibrate_xyz[1] = (max_xyz[1] + min_xyz[1])/2; - } - if(max_xyz[2] < data[2] || min_xyz[2] > data[2]) - { - if(max_xyz[2] < data[2]) - { - max_xyz[2] = data[2]; - min_xyz[2] = max_xyz[2] - range_xyz[2]; - } - else - { - min_xyz[2] = data[2]; - max_xyz[2] = min_xyz[2] + range_xyz[2]; - } - calibrate_xyz[2] = (max_xyz[2] + min_xyz[2])/2; - } - */ + } return; } #endif @@ -2011,9 +1933,6 @@ static int akm_report_data(struct akm_compass_data *akm) ktime_t timestamp; #if CALIBRATION_BY_OURSELF int data[3] = {0}; - int i,j,temp_max,temp_min; - static int pre_data[5][3] = {{0}}; - static int cnt = 0; #endif do { @@ -2038,40 +1957,25 @@ static int akm_report_data(struct akm_compass_data *akm) timestamp = ktime_get_boottime(); ///////////////////////////////////////////////////////////////////////////// #if CALIBRATION_BY_OURSELF - //data[0] = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); - //data[1] = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); - //data[2] = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); - //mag_x = data[0] - calibrate_xyz[0]; - //mag_y = data[1] - calibrate_xyz[1]; - //mag_z = data[2] - calibrate_xyz[2]; - //akm_calibrate_xyz(data); - data[0] = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); - data[1] = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); - data[2] = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); + tmp = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); + tmp = tmp * akm->sense_conf[0] / 128 + tmp; + data[0] = tmp; + + tmp = (int)((int16_t)(dat_buf[4]<<8)+((int16_t)dat_buf[3])); + tmp = tmp * akm->sense_conf[1] / 128 + tmp; + data[1] = tmp; + + tmp = (int)((int16_t)(dat_buf[6]<<8)+((int16_t)dat_buf[5])); + tmp = tmp * akm->sense_conf[2] / 128 + tmp; + data[2] = tmp; + + //pr_err("data0 %d:data1 %d:data2 %d\n",data[0],data[1],data[2]); akm_calibrate_xyz(data); - pre_data[cnt][0] = data[0] - calibrate_xyz[0]; - pre_data[cnt][1] = data[1] - calibrate_xyz[1]; - pre_data[cnt][2] = data[2] - calibrate_xyz[2]; - cnt ++; - cnt %= 5; - for(j = 0;j < 3;j ++) - { - temp_max = temp_min = pre_data[0][j]; - for(i = 1;i < 5;i ++) - { - if(pre_data[i][j] > temp_max) temp_max = pre_data[i][j]; - else if(pre_data[i][j] < temp_min) temp_min = pre_data[i][j]; - } - //data[j] = pre_data[0][j] + pre_data[1][j] + pre_data[2][j] + pre_data[3][j] + pre_data[4][j] - temp_max - temp_min; - } - //akm_calibrate_xyz(data); - mag_x = data[0]; - mag_y = data[1]; - mag_z = -data[2]; - //pr_err("%d:%d:%d\n",mag_x,mag_y,mag_y); - //orientation[0] = (float) Math.atan2((mGeomagnetic[0]*mGravity[1] - mGeomagnetic[1]*mGravity[0]) , (mGeomagnetic[2]*mGravity[1] - mGeomagnetic[1]*mGravity[2])); - //pr_err("%d,%d,%d %d,%d,%d %d,%d,%d\n",calibrate_xyz[0],calibrate_xyz[1],calibrate_xyz[2],max_xyz[0],max_xyz[1],max_xyz[2],min_xyz[0],min_xyz[1],min_xyz[2]); - //pr_err("%d:%s:===mag_x = %d,mag_y = %d,mag_z = %d\n\n",__LINE__,__func__,mag_x,mag_y,mag_y); + mag_x = data[0] - calibrate_xyz[0]; + mag_y = data[1] - calibrate_xyz[1]; + mag_z = data[2] - calibrate_xyz[2]; + + //pr_err("mag_x %d:mag_y %d:mag_z %d\n",mag_x,mag_y,mag_z); #else tmp = (int)((int16_t)(dat_buf[2]<<8)+((int16_t)dat_buf[1])); tmp = tmp * akm->sense_conf[0] / 128 + tmp; -- 2.25.1 From 7c52ac5f1559180358a30aa83160e72e9c38660d Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 5 Mar 2020 08:09:58 -0500 Subject: [PATCH 14/76] Restore console to ttyHSL0 Enable ANT UART at ttyHSL1 Change-Id: I3723d64d0616905cbb020788c8813225c5e29122 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 7 ++++++ arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 24 +++++++++++++++++++++ arch/arm/boot/dts/qcom/msm8909-qrd.dtsi | 12 +++++------ arch/arm/boot/dts/qcom/msm8909.dtsi | 1 - 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 2b9cd9c59ce..ff3ba762c2f 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -348,6 +348,13 @@ pinctrl-0 = <&uart_console_sleep>; }; +&blsp1_uart2 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&nrf52_sleep>; +}; + + / { mtp_batterydata: qcom,battery-data { qcom,rpull-up-kohm = <100>; diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index 3dd3b9b7bbe..59b3579d92d 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -184,6 +184,30 @@ bias-pull-down; }; }; + + nrf52_active: nrf52_active { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; + nrf52_sleep: nrf52_sleep { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-pull-down; + }; + }; + blsp1_uart2_tx_active: blsp1_uart2_tx_active { mux { diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi index d9c6ac94d36..ae5cb2ebcd4 100755 --- a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi @@ -25,15 +25,15 @@ status = "okay"; }; &blsp1_uart1 { - status = "ok"; + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart_console_sleep>; }; -//&blsp1_uart2 { -// status = "ok"; -// pinctrl-names = "default"; -// pinctrl-0 = <&hsuart_active>; -//}; +&blsp1_uart2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&nrf52_sleep>; +}; &qcom_rng { status = "okay"; diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index a00b887f70a..474cca4bf28 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -409,7 +409,6 @@ < 1267200 >; }; - blsp1_uart1: serial@78af000 { compatible = "qcom,msm-lsuart-v14"; reg = <0x78af000 0x200>; -- 2.25.1 From feb46df2232dc7d3200649b2cf97be252dd96d71 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 19 Mar 2020 14:33:32 -0400 Subject: [PATCH 15/76] - Updating dtsi for 2-wire UART1 usage with proper drain-strength - Adding hh_serial_test as a package to be included Change-Id: I2919cb4e1d87eeea0f85dee608c223955415dd36 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index ff3ba762c2f..b0dd6d89743 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -351,7 +351,7 @@ &blsp1_uart2 { status = "ok"; pinctrl-names = "default"; - pinctrl-0 = <&nrf52_sleep>; + pinctrl-0 = <&nrf52_active>; }; -- 2.25.1 From 9593b5c21bdd71d5b636106237b072bfe5dc3cba Mon Sep 17 00:00:00 2001 From: vipinbb Date: Mon, 30 Mar 2020 18:41:45 -0400 Subject: [PATCH 16/76] liangdo: enable USB OTG - checkin pwmcontroller app Change-Id: Iff835c8c27efc3ff6899570cf23d2aa51a7e3d4d --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 5 +- .../arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi | 10 + drivers/power/smb135x-charger.c | 13 +- pwmcontroller/Android.mk | 7 + pwmcontroller/pwmctrl.c | 183 ++++++++++++++++++ 5 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 pwmcontroller/Android.mk create mode 100644 pwmcontroller/pwmctrl.c diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index b0dd6d89743..b9ae45141ce 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -348,13 +348,10 @@ pinctrl-0 = <&uart_console_sleep>; }; -&blsp1_uart2 { +&blsp1_uart2_hs{ status = "ok"; - pinctrl-names = "default"; - pinctrl-0 = <&nrf52_active>; }; - / { mtp_batterydata: qcom,battery-data { qcom,rpull-up-kohm = <100>; diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi index 94f557a34f3..74517fbf4a4 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi @@ -22,6 +22,16 @@ qcom,batt-aging-comp; }; +&usb_otg { + interrupts = <0 134 0>,<0 140 0>,<0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; + + qcom,hsusb-otg-mode = <3>; + //qcom,hsusb-otg-otg-control = <1>; + qcom,hsusb-otg-delay-lpm; + vbus_otg-supply = <&smb1357_otg_vreg>; +}; + &spmi_bus { qcom,pm8909@0 { qcom,leds@a300 { diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 80c20b7b2a5..f07f51be9fc 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -1535,6 +1535,7 @@ static int smb135x_system_temp_level_set(struct smb135x_chg *chip, { int rc = 0; int prev_therm_lvl; + pr_err("smb135x_system_temp_level_set %d now %d\n", lvl_sel,chip->therm_lvl_sel); if (!chip->thermal_mitigation) { pr_err("Thermal mitigation not supported\n"); @@ -1555,6 +1556,8 @@ static int smb135x_system_temp_level_set(struct smb135x_chg *chip, if (lvl_sel == chip->therm_lvl_sel) return 0; + pr_err("smb135x_system_temp_level_set %d\n", lvl_sel); + mutex_lock(&chip->current_change_lock); prev_therm_lvl = chip->therm_lvl_sel; chip->therm_lvl_sel = lvl_sel; @@ -2211,6 +2214,8 @@ static int smb135x_chg_otg_enable(struct smb135x_chg *chip) int restart_count = 0; struct timeval time_a, time_b, time_c, time_d; u8 reg; + + pr_err("smb135x_chg_otg_enable\n"); if (chip->revision == REV_2) { /* @@ -2319,6 +2324,7 @@ static int smb135x_chg_otg_regulator_enable(struct regulator_dev *rdev) int rc = 0; struct smb135x_chg *chip = rdev_get_drvdata(rdev); + pr_err("enable otg regulator\n"); chip->otg_oc_count = 0; rc = smb135x_chg_otg_enable(chip); if (rc) @@ -2332,6 +2338,7 @@ static int smb135x_chg_otg_regulator_disable(struct regulator_dev *rdev) int rc = 0; struct smb135x_chg *chip = rdev_get_drvdata(rdev); + pr_err("diable otg regulator\n"); mutex_lock(&chip->otg_oc_count_lock); cancel_delayed_work_sync(&chip->reset_otg_oc_count_work); mutex_unlock(&chip->otg_oc_count_lock); @@ -2679,7 +2686,7 @@ static int rid_handler(struct smb135x_chg *chip, u8 rt_stat) if (chip->usb_slave_present ^ usb_slave_present) { chip->usb_slave_present = usb_slave_present; if (chip->usb_psy) { - pr_debug("setting usb psy usb_otg = %d\n", + pr_err("setting usb psy usb_otg = %d\n", chip->usb_slave_present); power_supply_set_usb_otg(chip->usb_psy, chip->usb_slave_present); @@ -2720,7 +2727,7 @@ static int otg_oc_handler(struct smb135x_chg *chip, u8 rt_stat) chip->otg_oc_count); } - pr_debug("rt_stat = 0x%02x\n", rt_stat); + pr_err("rt_stat = 0x%02x\n", rt_stat); schedule_delayed_work(&chip->reset_otg_oc_count_work, msecs_to_jiffies(RESET_OTG_OC_COUNT_MS)); mutex_unlock(&chip->otg_oc_count_lock); @@ -3674,7 +3681,7 @@ static int determine_initial_status(struct smb135x_chg *chip) chip->usb_slave_present = is_usb_slave_present(chip); if (chip->usb_psy && !chip->id_line_not_connected) { - pr_debug("setting usb psy usb_otg = %d\n", + pr_err("setting usb psy usb_otg = %d\n", chip->usb_slave_present); power_supply_set_usb_otg(chip->usb_psy, chip->usb_slave_present); diff --git a/pwmcontroller/Android.mk b/pwmcontroller/Android.mk new file mode 100644 index 00000000000..032136d4026 --- /dev/null +++ b/pwmcontroller/Android.mk @@ -0,0 +1,7 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := pwmctrl +LOCAL_SRC_FILES := pwmctrl.c +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) + +include $(BUILD_EXECUTABLE) diff --git a/pwmcontroller/pwmctrl.c b/pwmcontroller/pwmctrl.c new file mode 100644 index 00000000000..2928e8786da --- /dev/null +++ b/pwmcontroller/pwmctrl.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include +#include +#include + + +#define IN 0 +#define OUT 1 + +#define LOW 0 +#define HIGH 1 + +#define POUT 98 + +static int +GPIOExport(int pin) +{ +#define BUFFER_MAX 3 + char buffer[BUFFER_MAX]; + ssize_t bytes_written; + int fd; + + fd = open("/sys/class/gpio/export", O_WRONLY); + if (-1 == fd) { + fprintf(stderr, "Failed to open export for writing!\n"); + return(-1); + } + + bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin); + write(fd, buffer, bytes_written); + close(fd); + return(0); +} + +static int +GPIOUnexport(int pin) +{ + char buffer[BUFFER_MAX]; + ssize_t bytes_written; + int fd; + + fd = open("/sys/class/gpio/unexport", O_WRONLY); + if (-1 == fd) { + fprintf(stderr, "Failed to open unexport for writing!\n"); + return(-1); + } + + bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin); + write(fd, buffer, bytes_written); + close(fd); + return(0); +} + +static int +GPIODirection(int pin, int dir) +{ + static const char s_directions_str[] = "in\0out"; + +#define DIRECTION_MAX 35 + char path[DIRECTION_MAX]; + int fd; + + snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin); + fd = open(path, O_WRONLY); + if (-1 == fd) { + fprintf(stderr, "Failed to open gpio direction for writing!\n"); + return(-1); + } + + if (-1 == write(fd, &s_directions_str[IN == dir ? 0 : 3], IN == dir ? 2 : 3)) { + fprintf(stderr, "Failed to set direction!\n"); + return(-1); + } + + close(fd); + return(0); +} + +static int +GPIORead(int pin) +{ +#define VALUE_MAX 30 + char path[VALUE_MAX]; + char value_str[3]; + int fd; + + snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", pin); + fd = open(path, O_RDONLY); + if (-1 == fd) { + fprintf(stderr, "Failed to open gpio value for reading!\n"); + return(-1); + } + + if (-1 == read(fd, value_str, 3)) { + fprintf(stderr, "Failed to read value!\n"); + return(-1); + } + + close(fd); + + return(atoi(value_str)); +} + +//static int +//GPIOWrite(int pin, int value) +//{ +// int fd; +// +// if (-1 == fd) { +// fprintf(stderr, "Failed to open gpio value for writing!\n"); +// return(-1); +// } +// +// if (1 != ) { +// fprintf(stderr, "Failed to write value!\n"); +// return(-1); +// } +// +// return(0); +//} + + +int +main(int argc, const char* argv[]) +{ + if (argc < 2) + { + printf("Usage: ./pwmctrl \n"); + return -1; + } + + int freq = atoi(argv[1]); + printf("Buzzer freq: %d Hz\n", freq); + + long freq_to_ns_period = 1000000000 / freq; + printf("Buzzer period: %ld ns\n", freq_to_ns_period); + + + int fd; + char path[VALUE_MAX]; + snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", POUT); + fd = open(path, O_WRONLY); + static const char s_values_str[] = "01"; + struct timespec end_time; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); + struct timespec start_time; + long diffInNanos = 0; + uint8_t toggle = 0; + + if (-1 == GPIOExport(POUT)) + return(1); + + + if (-1 == GPIODirection(POUT, OUT)) + return(2); + + do + { + toggle ^= 0x01; + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time); + + while(diffInNanos < ((freq_to_ns_period * 50) / 100)) + { + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); + diffInNanos = (end_time.tv_sec - start_time.tv_sec) * (long)1e9 + (end_time.tv_nsec - start_time.tv_nsec); + } + + write(fd, &s_values_str[LOW == toggle ? 0 : 1], 1); + diffInNanos = 0; + } + while (1); + + if (-1 == GPIOUnexport(POUT)) + return(4); + + close(fd); + + return(0); +} -- 2.25.1 From 42db5cc76029e9063484769f2565d69608adf960 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Mon, 30 Mar 2020 20:33:57 -0400 Subject: [PATCH 17/76] MEIG: liangdi: enable usb storage Change-Id: I7596e74a95c10507662a0a2b10e9fb4158b01d6f --- arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi | 8 ++++---- arch/arm/configs/msm8909-perf_defconfig | 18 ++++++++++++++++++ arch/arm/configs/msm8909_defconfig | 7 +++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi index 74517fbf4a4..6480959078c 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi @@ -23,12 +23,12 @@ }; &usb_otg { - interrupts = <0 134 0>,<0 140 0>,<0 136 0>; - interrupt-names = "core_irq", "async_irq", "phy_irq"; + //interrupts = <0 134 0>,<0 140 0>,<0 136 0>; + //interrupt-names = "core_irq", "async_irq", "phy_irq"; qcom,hsusb-otg-mode = <3>; - //qcom,hsusb-otg-otg-control = <1>; - qcom,hsusb-otg-delay-lpm; + qcom,hsusb-otg-otg-control = <2>; + //qcom,hsusb-otg-delay-lpm; vbus_otg-supply = <&smb1357_otg_vreg>; }; diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index a34502456b9..07259a2379f 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -247,11 +247,17 @@ CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=y # CONFIG_SCSI_PROC_FS is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -396,6 +402,17 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_ACM=y CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_ISD200=y +CONFIG_USB_STORAGE_USBAT=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_STORAGE_ALAUDA=y +CONFIG_USB_STORAGE_ONETOUCH=y +CONFIG_USB_STORAGE_KARMA=y +CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_GADGET=y @@ -527,6 +544,7 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_QMI_ENCDEC=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 38e0f3fead1..433fa0884b8 100755 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -252,11 +252,18 @@ CONFIG_UID_STAT=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y -- 2.25.1 From c3e34676ab6b411b96512a92a70a8957886982af Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 31 Mar 2020 00:37:45 -0400 Subject: [PATCH 18/76] MEIG: liangdi: optimized TP driver Change-Id: Ibb976ab2eca625297e230aa7289fd5a6d528b3ee --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 14 +++++------ drivers/input/touchscreen/gt9xx_2/gt9xx.c | 30 +++++++++++++++++------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index b9ae45141ce..57067523706 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -148,12 +148,12 @@ vdd-supply = <&pm8909_l17>; vcc_i2c-supply = <&pm8909_l6>; // pins used by touchscreen - pinctrl-names = "pmx_ts_active", - "pmx_ts_suspend", - "pmx_ts_release"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - pinctrl-2 = <&ts_release>; + //pinctrl-names = "pmx_ts_active", + // "pmx_ts_suspend", + // "pmx_ts_release"; + //pinctrl-0 = <&ts_int_active &ts_reset_active>; + //pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + //pinctrl-2 = <&ts_release>; goodix,i2c-pull-up; goodix,no-force-update; goodix,panel-coords = <0 0 480 800>; @@ -190,7 +190,7 @@ 46 30 3C D0 07 50 30 02 01]; goodix,cfg-data1 = []; goodix,have-touch-key; - goodix,driver-send-cfg; + //goodix,driver-send-cfg; }; }; diff --git a/drivers/input/touchscreen/gt9xx_2/gt9xx.c b/drivers/input/touchscreen/gt9xx_2/gt9xx.c index ced035fc6a5..86b609bb54e 100644 --- a/drivers/input/touchscreen/gt9xx_2/gt9xx.c +++ b/drivers/input/touchscreen/gt9xx_2/gt9xx.c @@ -81,6 +81,8 @@ #define GTP_MAX_TOUCH 5 #define GTP_ESD_CHECK_CIRCLE_MS 2000 +#define USE_PINCTRL 0 //add by liangdi for nopinctrl 20200229 + static void gtp_int_sync(struct goodix_ts_data *ts, int ms); static int gtp_i2c_test(struct i2c_client *client); static int goodix_power_off(struct goodix_ts_data *ts); @@ -420,6 +422,10 @@ static void goodix_ts_work_func(struct work_struct *work) if (ts->enter_update) return; #endif + + if (ts->gtp_is_suspend) + return; + if (ts->pdata->slide_wakeup) { if (DOZE_ENABLED == doze_status) { ret = gtp_i2c_read(ts->client, doze_buf, 3); @@ -801,7 +807,7 @@ static s8 gtp_wakeup_sleep(struct goodix_ts_data *ts) gtp_reset_guitar(ts, 20); ret = gtp_send_cfg(ts); - if (ret <= 0) { + if (ret < 0) { dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n"); return ret; @@ -976,6 +982,7 @@ static int gtp_init_panel(struct goodix_ts_data *ts) } else { /* DRIVER NOT SEND CONFIG */ +/* ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH; ret = gtp_i2c_read(ts->client, config_data, ts->gtp_cfg_len + GTP_ADDR_LENGTH); @@ -986,8 +993,9 @@ static int gtp_init_panel(struct goodix_ts_data *ts) ts->abs_y_max = GTP_MAX_HEIGHT; ts->int_trigger_type = GTP_INT_TRIGGER; } +*/ } /* !DRIVER NOT SEND CONFIG */ - +/* if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) { ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8) + config_data[RESOLUTION_LOC]; @@ -998,7 +1006,7 @@ static int gtp_init_panel(struct goodix_ts_data *ts) ret = gtp_send_cfg(ts); if (ret < 0) dev_err(&client->dev, "%s: Send config error.\n", __func__); - +*/ msleep(20); return ret; } @@ -1965,7 +1973,7 @@ static int goodix_parse_dt(struct device *dev, return 0; } -#if 1 +#if(USE_PINCTRL != 0) static int goodix_ts_pinctrl_init(struct goodix_ts_data *ts) { int retval; @@ -2101,7 +2109,7 @@ static int goodix_ts_probe(struct i2c_client *client, goto exit_deinit_power; } -#if 1 +#if(USE_PINCTRL != 0) if(strcmp(client->name,"gt9xx")==0) { printk(KERN_ERR "2222goodix_ts_probe name = %s\n",client->name); @@ -2123,6 +2131,8 @@ static int goodix_ts_probe(struct i2c_client *client, printk(KERN_ERR "1111goodix_ts_probe name = %s\n",client->name); ts->ts_pinctrl = NULL ; } +#else + ts->ts_pinctrl = NULL ; #endif gtp_reset_guitar(ts, 20); @@ -2228,6 +2238,7 @@ static int goodix_ts_probe(struct i2c_client *client, } init_done = true; + pr_info("goodix init OK\n"); return 0; exit_free_irq: mutex_destroy(&ts->lock); @@ -2343,12 +2354,15 @@ static int goodix_ts_suspend(struct device *dev) { struct goodix_ts_data *ts = dev_get_drvdata(dev); int ret = 0, i; + pr_err("goodix_ts_suspend++\n"); if (ts->gtp_is_suspend) { dev_dbg(&ts->client->dev, "Already in suspend state.\n"); return 0; } + ts->gtp_is_suspend = 1; + mutex_lock(&ts->lock); if (ts->fw_loading) { @@ -2387,7 +2401,7 @@ static int goodix_ts_suspend(struct device *dev) */ msleep(58); mutex_unlock(&ts->lock); - ts->gtp_is_suspend = 1; + pr_err("goodix_ts_suspend--\n"); return ret; } @@ -2404,6 +2418,7 @@ static int goodix_ts_resume(struct device *dev) { struct goodix_ts_data *ts = dev_get_drvdata(dev); int ret = 0; + pr_err("goodix_ts_resume++\n"); if (!ts->gtp_is_suspend) { dev_dbg(&ts->client->dev, "Already in awake state.\n"); @@ -2415,7 +2430,7 @@ static int goodix_ts_resume(struct device *dev) if (ts->pdata->slide_wakeup) doze_status = DOZE_DISABLED; - if (ret <= 0) + if (ret < 0) dev_err(&ts->client->dev, "GTP resume failed.\n"); if (ts->use_irq) @@ -2433,6 +2448,7 @@ static int goodix_ts_resume(struct device *dev) #endif mutex_unlock(&ts->lock); ts->gtp_is_suspend = 0; + pr_err("goodix_ts_resume--\n"); return ret; } -- 2.25.1 From 7b75127b05ce7217f2bf766585d671cc98e73010 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 31 Mar 2020 01:00:28 -0400 Subject: [PATCH 19/76] MEIG: liangdi: add nrf spi driver Change-Id: I2335ef7a79425a520146f6298651d713d288a852 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 20 + arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 129 +++- arch/arm/configs/msm8909-perf_defconfig | 3 +- arch/arm/configs/msm8909_defconfig | 3 +- drivers/mg_driver/Kconfig | 6 + drivers/mg_driver/Makefile | 1 + drivers/mg_driver/nrf/Kconfig | 9 + drivers/mg_driver/nrf/Makefile | 1 + drivers/mg_driver/nrf/nrf.c | 630 ++++++++++++++++++++ 9 files changed, 776 insertions(+), 26 deletions(-) create mode 100755 drivers/mg_driver/nrf/Kconfig create mode 100755 drivers/mg_driver/nrf/Makefile create mode 100755 drivers/mg_driver/nrf/nrf.c diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 57067523706..5d98d7d7daf 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -352,6 +352,26 @@ status = "ok"; }; +&spi_0 { + nrf_spi@0 { + compatible = "qcom,nrf"; + reg = <0>; + spi-max-frequency = <9600000>; + interrupt-parent = <&msm_gpio>; + interrupts = <28 0x00>; + qcom,chip_wakeup = <&msm_gpio 28 0x2002>; + qcom,chip_status = <&msm_gpio 30 0x0>; + qcom,ant_reset = <&msm_gpio 29 0x0>; + pinctrl-names = "nrf_active", + "nrf_suspend", + "nrf_release"; + pinctrl-0 = <&nrf_int_active &nrf_status_active &nrf_ant_reset_active>; + pinctrl-1 = <&nrf_int_suspend &nrf_status_suspend &nrf_ant_reset_suspend>; + pinctrl-2 = <&nrf_release>; + status = "ok"; + }; +}; + / { mtp_batterydata: qcom,battery-data { qcom,rpull-up-kohm = <100>; diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index 59b3579d92d..3d594e48fa2 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -184,30 +184,6 @@ bias-pull-down; }; }; - - nrf52_active: nrf52_active { - mux { - pins = "gpio20", "gpio21"; - function = "blsp_uart2"; - }; - config { - pins = "gpio20", "gpio21"; - drive-strength = <2>; - bias-disable; - }; - }; - nrf52_sleep: nrf52_sleep { - mux { - pins = "gpio20", "gpio21"; - function = "blsp_uart2"; - }; - config { - pins = "gpio20", "gpio21"; - drive-strength = <2>; - bias-pull-down; - }; - }; - blsp1_uart2_tx_active: blsp1_uart2_tx_active { mux { @@ -930,6 +906,111 @@ }; }; + nrf_int_active { + nrf_int_active: nrf_int_active { + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + nrf_int_suspend { + nrf_int_suspend: nrf_int_suspend { + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + nrf_status_active { + nrf_status_active: nrf_status_active { + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + nrf_status_suspend { + nrf_status_suspend: nrf_status_suspend { + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + nrf_ant_reset_active { + nrf_ant_reset_active: nrf_ant_reset_active { + mux { + pins = "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio29"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + nrf_ant_reset_suspend { + nrf_ant_reset_suspend: nrf_ant_reset_suspend { + mux { + pins = "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio29"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + nrf_release { + nrf_release: nrf_release { + mux { + pins = "gpio28", "gpio29", "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio28", "gpio29", "gpio30"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + tlmm_gpio_key { gpio_key_active: gpio_key_active { mux { diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 07259a2379f..8af68dafb1e 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -568,4 +568,5 @@ CONFIG_TOUCHSCREEN_GT9XX=y CONFIG_GT9XX_TOUCHPANEL_DRIVER=y CONFIG_GT9XX_TOUCHPANEL_UPDATE=y CONFIG_GT9XX_TOUCHPANEL_DEBUG=y -CONFIG_MG_DRIVER_CONTROL=y \ No newline at end of file +CONFIG_MG_DRIVER_CONTROL=y +CONFIG_NRF_DRIVER=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 433fa0884b8..03721995008 100755 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -621,4 +621,5 @@ CONFIG_GT9XX_TOUCHPANEL_DRIVER=y CONFIG_GT9XX_TOUCHPANEL_UPDATE=y CONFIG_GT9XX_TOUCHPANEL_DEBUG=y CONFIG_MG_DRIVER_CONTROL=y -CONFIG_LOG_BUF_SHIFT=20 \ No newline at end of file +CONFIG_LOG_BUF_SHIFT=20 +CONFIG_NRF_DRIVER=y \ No newline at end of file diff --git a/drivers/mg_driver/Kconfig b/drivers/mg_driver/Kconfig index 4494a9d2436..ad96f616ef1 100755 --- a/drivers/mg_driver/Kconfig +++ b/drivers/mg_driver/Kconfig @@ -12,5 +12,11 @@ config MG_DRIVER_CONTROL default y source "drivers/mg_driver/mgdrv/Kconfig" + +config NRF_DRIVER + tristate + default y + +source "drivers/mg_driver/nrf/Kconfig" endmenu #mg Drivers menu end diff --git a/drivers/mg_driver/Makefile b/drivers/mg_driver/Makefile index 027147e730d..b7c6e169683 100755 --- a/drivers/mg_driver/Makefile +++ b/drivers/mg_driver/Makefile @@ -5,4 +5,5 @@ # Each configuration option enables a list of files. obj-$(CONFIG_MG_DRIVER_CONTROL) += mgdrv/ +obj-$(CONFIG_NRF_DRIVER) += nrf/ diff --git a/drivers/mg_driver/nrf/Kconfig b/drivers/mg_driver/nrf/Kconfig new file mode 100755 index 00000000000..d033dcd1785 --- /dev/null +++ b/drivers/mg_driver/nrf/Kconfig @@ -0,0 +1,9 @@ +menu "nrf drivers Control Select" + +config NRF_DRIVER + bool "nrf drivers" + default n + help + if you want to use mg driver control, say Y, else say N + +endmenu diff --git a/drivers/mg_driver/nrf/Makefile b/drivers/mg_driver/nrf/Makefile new file mode 100755 index 00000000000..b7c98958833 --- /dev/null +++ b/drivers/mg_driver/nrf/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NRF_DRIVER) += nrf.o diff --git a/drivers/mg_driver/nrf/nrf.c b/drivers/mg_driver/nrf/nrf.c new file mode 100755 index 00000000000..5b3b210085b --- /dev/null +++ b/drivers/mg_driver/nrf/nrf.c @@ -0,0 +1,630 @@ +/*! + * addb by liangdi for nrf drivers 20200302 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEFAULT_SPI_SPEED (9600000) +#define BUF_LEN (1024) + +#define NRF_CHR_FILE_NAME "nrf0" //do not neeed modify usually +#define NRF_CHR_DEV_NAME "nrf" //do not neeed modify usually + +#define PINCTRL_STATE_ACTIVE "nrf_active" +#define PINCTRL_STATE_SUSPEND "nrf_suspend" +#define PINCTRL_STATE_RELEASE "nrf_release" + +static DEFINE_MUTEX(dev_lock); + +enum { + INPUT_LOW = 0, + INPUT_HIGHT, +}; + + +struct nrf_drv { + //struct platform_device *pdev; + struct spi_device *spi; + int chip_wakeup;//nrf wakeup msm8909 + unsigned int chip_wakeup_flags; + unsigned int wakeup_irq; + int chip_status;//msm8909 status 0:power off or sleep; 1: power on + int ant_reset; + unsigned char *stxb; + unsigned char *srxb; + + bool use_irq; + spinlock_t irq_lock; + struct workqueue_struct *nrf_wq; + struct work_struct work; + int irq_is_disabled; + struct wakeup_source wakesource; + int waketimeout; + + dev_t idd; + struct cdev *chd; + struct class *cls; + struct device *dev; + + struct pinctrl *nrf_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; +}; + +struct nrf_drv *gl_nrf_driver = NULL; +static struct spi_driver nrf_drv_driver; + +static int nrf_pinctrl_init(struct nrf_drv *nrf_drv) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + nrf_drv->nrf_pinctrl = devm_pinctrl_get(&(nrf_drv->spi->dev)); + if (IS_ERR_OR_NULL(nrf_drv->nrf_pinctrl)) { + retval = PTR_ERR(nrf_drv->nrf_pinctrl); + pr_err("Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + nrf_drv->pinctrl_state_active + = pinctrl_lookup_state(nrf_drv->nrf_pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(nrf_drv->pinctrl_state_active)) { + retval = PTR_ERR(nrf_drv->pinctrl_state_active); + pr_err("Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + nrf_drv->pinctrl_state_suspend + = pinctrl_lookup_state(nrf_drv->nrf_pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(nrf_drv->pinctrl_state_suspend)) { + retval = PTR_ERR(nrf_drv->pinctrl_state_suspend); + pr_err("Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + nrf_drv->pinctrl_state_release + = pinctrl_lookup_state(nrf_drv->nrf_pinctrl, + PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(nrf_drv->pinctrl_state_release)) { + retval = PTR_ERR(nrf_drv->pinctrl_state_release); + pr_err("Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(nrf_drv->nrf_pinctrl); +err_pinctrl_get: + nrf_drv->nrf_pinctrl = NULL; + return retval; +} + +int nrf_parse_dt(struct device *dev) +{ + int ret =0; + struct spi_device *spi = to_spi_device(dev); + struct nrf_drv *nrf_driver = spi_get_drvdata(spi); + struct device_node *node = dev->of_node; +/* + nrf_driver->chip_wakeup = of_get_named_gpio(node, "qcom,chip_wakeup", 0); + if (nrf_driver->chip_wakeup < 0) { + pr_err("chip_wakeup is missing\n"); + return -1; + } +*/ + nrf_driver->chip_wakeup = of_get_named_gpio_flags(node, "qcom,chip_wakeup", + 0, &nrf_driver->chip_wakeup_flags); + + if (nrf_driver->chip_wakeup < 0) + return nrf_driver->chip_wakeup; + + ret = gpio_request(nrf_driver->chip_wakeup, "chip_wakeup"); + if (ret < 0) { + pr_err("chip_wakeup failed\n"); + return -ENODEV; + } + + ret = gpio_direction_input(nrf_driver->chip_wakeup); + nrf_driver->wakeup_irq = gpio_to_irq(nrf_driver->chip_wakeup); + + nrf_driver->chip_status = of_get_named_gpio(node, "qcom,chip_status", 0); + if (nrf_driver->chip_status < 0) { + pr_err("chip_status is missing\n"); + return -1; + } + + if (nrf_driver->chip_status < 0) + return nrf_driver->chip_status; + + ret = gpio_request(nrf_driver->chip_status, "chip_status"); + if (ret < 0) { + pr_err("chip_status failed\n"); + return -ENODEV; + } + + nrf_driver->ant_reset = of_get_named_gpio(node, "qcom,ant_reset", 0); + if (nrf_driver->ant_reset < 0) { + pr_err("ant_reset is missing\n"); + return -1; + } + + if (nrf_driver->ant_reset < 0) + return nrf_driver->ant_reset; + + ret = gpio_request(nrf_driver->ant_reset, "ant_reset"); + if (ret < 0) { + pr_err("ant_reset failed\n"); + return -ENODEV; + } + + gpio_direction_output(nrf_driver->chip_status, 1); + gpio_direction_output(nrf_driver->ant_reset, 1); + dev_info(dev, "end nrf_parse_dt\n"); + + return 0; +} + +static ssize_t show_driver_attr_ant_reset(struct device_driver *dev, char *buf) +{ + + return snprintf(buf, 20, "%d\n", gl_nrf_driver->ant_reset); +} + +static ssize_t store_driver_attr_ant_reset(struct device_driver *dev, const char *buf, size_t count) +{ + pr_err("nrf ant_reset\n"); + gpio_direction_output(gl_nrf_driver->ant_reset, 0); + msleep(500); + gpio_direction_output(gl_nrf_driver->ant_reset, 1); + return count; +} + +static ssize_t show_driver_attr_wake_timeout(struct device_driver *dev, char *buf) +{ + + return snprintf(buf, 20, "%d\n", gl_nrf_driver->waketimeout); +} + +static ssize_t store_driver_attr_wake_timeout(struct device_driver *dev, const char *buf, size_t count) +{ + ssize_t ret = -EINVAL; + unsigned long time = 0; + + ret = kstrtoul(buf, 10, &time); + if (ret) + return ret; + + gl_nrf_driver->waketimeout = (int)time; + pr_err("nrf wake timeout new %lu\n",time); + + return count; +} + +static DRIVER_ATTR(ant_reset, S_IWUSR | S_IRUGO, show_driver_attr_ant_reset, store_driver_attr_ant_reset); +static DRIVER_ATTR(wake_timeout, S_IWUSR | S_IRUGO, show_driver_attr_wake_timeout, store_driver_attr_wake_timeout); + + +int nrf_sync(u8 *txb, u8 *rxb, int len) { + int ret = 0; +struct spi_message m; +struct spi_transfer t = { + .tx_buf = txb, + .rx_buf = rxb, + .len = len, + .delay_usecs = 1, + .bits_per_word = 8, + .speed_hz = gl_nrf_driver->spi->max_speed_hz, + }; + mutex_lock(&dev_lock); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + ret = spi_sync(gl_nrf_driver->spi, &m); + mutex_unlock(&dev_lock); + return ret; +} + +static ssize_t nrf_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { + int val, ret = 0; + pr_err("nrf_read %d\n",count); + + ret = nrf_sync(gl_nrf_driver->stxb, gl_nrf_driver->srxb, count); + if(ret) { + pr_err("nrf_sync failed\n"); + return -2; + } + + ret = copy_to_user(buf, gl_nrf_driver->srxb, count); + if(!ret) val = count; + else { + val = -3; + pr_err("copy_to_user failed\n"); + } + + pr_err("nrf_write size %d,%d,%d,%d,%d,%d\n",count, + gl_nrf_driver->srxb[0], + gl_nrf_driver->srxb[1], + gl_nrf_driver->srxb[2], + gl_nrf_driver->srxb[3], + gl_nrf_driver->srxb[4]); + + return val; +} + +static ssize_t nrf_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { + int val, ret = 0; + + memset(gl_nrf_driver->stxb, 0, BUF_LEN); + ret = copy_from_user(gl_nrf_driver->stxb, buf, count); + if(ret) { + pr_err("copy form user failed\n"); + val = -2; + } else { + val = count; + } + pr_err("nrf_write size %d,%d,%d,%d,%d,%d\n",count, + gl_nrf_driver->stxb[0], + gl_nrf_driver->stxb[1], + gl_nrf_driver->stxb[2], + gl_nrf_driver->stxb[3], + gl_nrf_driver->stxb[4]); + return val; +} + +static long nrf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + int ret = 0; + + pr_err("nrf_ioctl: cmd=0x%x\n",cmd); + switch(cmd){ + default: + ret = -EINVAL; + pr_err("nrf_ioctl no such cmd\n"); + } + pr_err("nrf_ioctl: end.\n"); + return ret; +} + +static const struct file_operations sfops = { + .owner = THIS_MODULE, + .write = nrf_write, + .read = nrf_read, + .unlocked_ioctl = nrf_ioctl, + //.mmap = mas_mmap, +}; + +static int init_file_node(struct device *dev) +{ + int ret; + struct spi_device *spi = to_spi_device(dev); + struct nrf_drv *nrf_driver = spi_get_drvdata(spi); + + ret = alloc_chrdev_region(&nrf_driver->idd, 0, 1, NRF_CHR_DEV_NAME); + if(ret < 0) + { + pr_err("alloc_chrdev_region error!\n"); + return -1; + } + nrf_driver->chd = cdev_alloc(); + if (!nrf_driver->chd) + { + pr_err("cdev_alloc error!\n"); + return -1; + } + nrf_driver->chd->owner = THIS_MODULE; + nrf_driver->chd->ops = &sfops; + cdev_add(nrf_driver->chd, nrf_driver->idd, 1); + nrf_driver->cls = class_create(THIS_MODULE, NRF_CHR_DEV_NAME); + if (IS_ERR(nrf_driver->cls)) { + pr_err("class_create err\n"); + return -1; + } + nrf_driver->dev = device_create(nrf_driver->cls, NULL, nrf_driver->idd, NULL, NRF_CHR_FILE_NAME); + ret = IS_ERR(nrf_driver->dev) ? PTR_ERR(nrf_driver->dev) : 0; + if(ret){ + pr_err("device_create err\n"); + } + return 0; +} + +static int deinit_file_node(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct nrf_drv *nrf_driver = spi_get_drvdata(spi); + + cdev_del(nrf_driver->chd); + nrf_driver->chd = NULL; + kfree(nrf_driver->chd); + device_destroy(nrf_driver->cls, nrf_driver->idd); + unregister_chrdev_region(nrf_driver->idd, 1); + class_destroy(nrf_driver->cls); + return 0; +} + +void nrf_wakeup_irq_disable(struct nrf_drv *nrf_drv) +{ + unsigned long irqflags; + + spin_lock_irqsave(&nrf_drv->irq_lock, irqflags); + if (!nrf_drv->irq_is_disabled) { + nrf_drv->irq_is_disabled = true; + disable_irq_nosync(nrf_drv->wakeup_irq); + } + spin_unlock_irqrestore(&nrf_drv->irq_lock, irqflags); +} + +void nrf_wakeup_irq_enable(struct nrf_drv *nrf_drv) +{ + unsigned long irqflags = 0; + + spin_lock_irqsave(&nrf_drv->irq_lock, irqflags); + if (nrf_drv->irq_is_disabled) { + enable_irq(nrf_drv->wakeup_irq); + nrf_drv->irq_is_disabled = false; + } + spin_unlock_irqrestore(&nrf_drv->irq_lock, irqflags); +} + +static void nrf_wakeup_work_func(struct work_struct *work) +{ + struct nrf_drv *nrf_drv = NULL; + + nrf_drv = container_of(work, struct nrf_drv, work); + + pr_err("nrf wakeup work func"); + if (nrf_drv->use_irq) + nrf_wakeup_irq_enable(nrf_drv); + return; +} + +static irqreturn_t nrf_wakeup_irq_handler(int irq, void *dev_id) +{ + struct nrf_drv *nrf_drv = dev_id; + //printk(KERN_ERR"..........nrf_wakeup_irq_handler..........\n"); + nrf_wakeup_irq_disable(nrf_drv); + + __pm_wakeup_event(&nrf_drv->wakesource, nrf_drv->waketimeout); + queue_work(nrf_drv->nrf_wq, &nrf_drv->work); + + return IRQ_HANDLED; +} + +static int nrf_drv_probe(struct spi_device *spi) +{ + int ret = 0; + struct nrf_drv *nrf_drv; + pr_err("nrf_drv_probe probe\n"); + + nrf_drv = devm_kzalloc(&spi->dev, sizeof(struct nrf_drv), GFP_KERNEL); + + if (!nrf_drv) { + pr_err("unable to allocate platform data\n"); + return -ENOMEM; + } + gl_nrf_driver = nrf_drv; + + nrf_drv->spi = spi; + nrf_drv->spi->max_speed_hz = DEFAULT_SPI_SPEED; + nrf_drv->spi->mode = SPI_MODE_0; //CPOL=CPHA=0 + nrf_drv->spi->bits_per_word = 8; + ret = spi_setup(nrf_drv->spi); + if (ret) + return ret; + + //allocate memory for DMA transfer + nrf_drv->stxb = kmalloc(BUF_LEN, GFP_ATOMIC); + if(nrf_drv->stxb == NULL){ + pr_err("mem alloc failed\n"); + return -ENOMEM; + } + + nrf_drv->srxb = kmalloc(BUF_LEN, GFP_ATOMIC); + if(nrf_drv->srxb == NULL){ + pr_err("mem alloc failed\n"); + return -ENOMEM; + } + + spi_set_drvdata(nrf_drv->spi, nrf_drv); + + ret = nrf_parse_dt(&nrf_drv->spi->dev); + + ret = nrf_pinctrl_init(nrf_drv); + + if (!ret && nrf_drv->nrf_pinctrl) { + ret = pinctrl_select_state(nrf_drv->nrf_pinctrl, + nrf_drv->pinctrl_state_active); + if (ret < 0) { + pr_err("failed to select pin to active state"); + return -ENODEV; + } + } else { + return -ENODEV; + } + + ret = init_file_node(&nrf_drv->spi->dev); + if(ret){ + goto exit; + } + + if(driver_create_file(&nrf_drv_driver.driver, &driver_attr_ant_reset)) + { + pr_err("driver_create_file ant_reset ERROR \n"); + goto exit; + } + + + if(driver_create_file(&nrf_drv_driver.driver, &driver_attr_wake_timeout)) + { + pr_err("driver_create_file wake_timeout ERROR \n"); + goto exit; + } + + nrf_drv->nrf_wq = create_singlethread_workqueue("nrf_wq"); + INIT_WORK(&nrf_drv->work, nrf_wakeup_work_func); + + ret = request_threaded_irq(nrf_drv->wakeup_irq, NULL, + nrf_wakeup_irq_handler, + nrf_drv->chip_wakeup_flags, + "chip_wakeup", nrf_drv); + + if (ret) + { + nrf_drv->use_irq = false; + return ret; + } + else + { + nrf_wakeup_irq_enable(nrf_drv); + nrf_drv->use_irq = true; + } + + device_init_wakeup(&nrf_drv->spi->dev, 1); + + wakeup_source_init(&nrf_drv->wakesource,"nrf_wakelock"); + nrf_drv->waketimeout = 5000;///5 seconds + + pr_info("nrf_drv_probe successfully probe\n"); + + return ret; + +exit: + deinit_file_node(&nrf_drv->spi->dev); + + if (nrf_drv->use_irq) + free_irq(nrf_drv->wakeup_irq, nrf_drv); + + cancel_work_sync(&nrf_drv->work); + flush_workqueue(nrf_drv->nrf_wq); + destroy_workqueue(nrf_drv->nrf_wq); + + wakeup_source_trash(&nrf_drv->wakesource); + pr_err("%s: probing chr failed, check hardware\n", + __func__); + + return ret; +} + +static int nrf_drv_remove(struct spi_device *spi) +{ + pr_err("nrf_drv_remove\n"); + return 0; +} + +static int nrf_drv_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct nrf_drv *nrf_driver = spi_get_drvdata(spi); + int ret = 0; + + if(gpio_is_valid(nrf_driver->chip_status)) + gpio_direction_output(nrf_driver->chip_status, 0); + + if (device_may_wakeup(&nrf_driver->spi->dev)) + enable_irq_wake(nrf_driver->wakeup_irq); + + if (nrf_driver->nrf_pinctrl) { + ret = pinctrl_select_state(nrf_driver->nrf_pinctrl, + nrf_driver->pinctrl_state_suspend); + if (ret < 0) + pr_err("failed to select pin to suspend state\n"); + } + pr_err("nrf_drv_suspend\n"); + return 0; +} + +static int nrf_drv_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct nrf_drv *nrf_driver = spi_get_drvdata(spi); + int ret = 0; + + if (nrf_driver->nrf_pinctrl) { + ret = pinctrl_select_state(nrf_driver->nrf_pinctrl, + nrf_driver->pinctrl_state_active); + if (ret < 0) + pr_err("failed to select pin to active state\n"); + } + + if(gpio_is_valid(nrf_driver->chip_status)) + gpio_direction_output(nrf_driver->chip_status, 1); + + if (device_may_wakeup(&nrf_driver->spi->dev)) + disable_irq_wake(nrf_driver->wakeup_irq); + + + pr_err("nrf_drv_resume\n"); + return 0; +} + +static const struct dev_pm_ops nrf_drv_pm_ops = { + .suspend = nrf_drv_suspend, + .resume = nrf_drv_resume, +}; + +static const struct of_device_id nrf_drv_of_match[] = { + { .compatible = "qcom,nrf", }, + { } +}; + +MODULE_DEVICE_TABLE(of, nrf_drv_of_match); + +static const struct spi_device_id nrf_spi_ids[] = { + { "nrf", 0 }, +}; + +static struct spi_driver nrf_drv_driver = { + .driver = { + .name = "nrf", + .owner = THIS_MODULE, + .of_match_table = nrf_drv_of_match, + .pm = &nrf_drv_pm_ops, + }, + .id_table = nrf_spi_ids, + .probe = nrf_drv_probe, + .remove = nrf_drv_remove, +}; + +static int __init nrf_drv_init(void) +{ + return spi_register_driver(&nrf_drv_driver); +} + +static void __exit nrf_drv_exit(void) +{ + spi_unregister_driver(&nrf_drv_driver); +} + +MODULE_AUTHOR("nrf Corporation"); +MODULE_DESCRIPTION("driver for nrf "); +MODULE_LICENSE("GPL v2"); + +module_init(nrf_drv_init); +module_exit(nrf_drv_exit); + -- 2.25.1 From 7acf0ab145ef3e0568c3f4c29543deb6e722c355 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 31 Mar 2020 01:19:02 -0400 Subject: [PATCH 20/76] MEIG: liangdi: Max fastchg current 1250mA Change-Id: I0a01cdb0e53360f13fb8ad4d34ec26d35b6232f2 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 5d98d7d7daf..610169be47d 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -37,8 +37,8 @@ qcom,recharge-thresh-mv = <100>; regulator-name = "smb1357_otg_vreg"; qcom,soft-vfloat-comp-disabled; - qcom,thermal-mitigation = <2000 1500 1000 0>; - qcom,fastchg-ma = <2000>; + qcom,thermal-mitigation = <1250 1250 1000 0>; + qcom,fastchg-ma = <1250>; qcom,bms-psy-name = "bms"; /* -- 2.25.1 From 1b163f303534f51ac90cbf24764ca23bd3ed0394 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 31 Mar 2020 13:56:14 -0400 Subject: [PATCH 21/76] Disable SPI driver and DTS since it is causing issues with UART driver and booting. !!TO FIX!! Change-Id: I5a9381803e6ee494c364e7379e343a08e5ba7ce5 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 11 +++++++++ arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 26 +++++++++++++++++++++ arch/arm/configs/msm8909-perf_defconfig | 20 ++++++++-------- arch/arm/configs/msm8909_defconfig | 18 +++++++------- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 610169be47d..cf3b1f32651 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -348,10 +348,20 @@ pinctrl-0 = <&uart_console_sleep>; }; +&blsp1_uart2 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&nrf52_active>; +}; + + +/* &blsp1_uart2_hs{ status = "ok"; }; +*/ +/* &spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; @@ -371,6 +381,7 @@ status = "ok"; }; }; +*/ / { mtp_batterydata: qcom,battery-data { diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index 3d594e48fa2..c2157f73090 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -185,6 +185,30 @@ }; }; + nrf52_active: nrf52_active { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; + + nrf52_sleep: nrf52_sleep { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-pull-down; + }; + }; + blsp1_uart2_tx_active: blsp1_uart2_tx_active { mux { pins = "gpio20"; @@ -906,6 +930,7 @@ }; }; +/* nrf_int_active { nrf_int_active: nrf_int_active { mux { @@ -1010,6 +1035,7 @@ }; }; }; +*/ tlmm_gpio_key { gpio_key_active: gpio_key_active { diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 8af68dafb1e..29717973bd8 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -247,17 +247,17 @@ CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=y # CONFIG_SCSI_PROC_FS is not set -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y +#CONFIG_SCSI=y +#CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y +#CONFIG_SCSI_CONSTANTS=y +#CONFIG_SCSI_LOGGING=y +#CONFIG_SCSI_SCAN_ASYNC=y +#CONFIG_SCSI_UFSHCD=y +#CONFIG_SCSI_UFSHCD_PLATFORM=y +#CONFIG_SCSI_UFS_QCOM=y +#CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -569,4 +569,4 @@ CONFIG_GT9XX_TOUCHPANEL_DRIVER=y CONFIG_GT9XX_TOUCHPANEL_UPDATE=y CONFIG_GT9XX_TOUCHPANEL_DEBUG=y CONFIG_MG_DRIVER_CONTROL=y -CONFIG_NRF_DRIVER=y +#CONFIG_NRF_DRIVER=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 03721995008..3731856a059 100755 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -253,17 +253,17 @@ CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=y # CONFIG_SCSI_PROC_FS is not set -CONFIG_SCSI=y +#CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SCAN_ASYNC=y -CONFIG_SCSI_UFSHCD=y -CONFIG_SCSI_UFSHCD_PLATFORM=y -CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y +#CONFIG_SCSI_CONSTANTS=y +#CONFIG_SCSI_LOGGING=y +#CONFIG_SCSI_SCAN_ASYNC=y +#CONFIG_SCSI_UFSHCD=y +#CONFIG_SCSI_UFSHCD_PLATFORM=y +#CONFIG_SCSI_UFS_QCOM=y +#CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -622,4 +622,4 @@ CONFIG_GT9XX_TOUCHPANEL_UPDATE=y CONFIG_GT9XX_TOUCHPANEL_DEBUG=y CONFIG_MG_DRIVER_CONTROL=y CONFIG_LOG_BUF_SHIFT=20 -CONFIG_NRF_DRIVER=y \ No newline at end of file +#CONFIG_NRF_DRIVER=y \ No newline at end of file -- 2.25.1 From 2c6e72b456aea4836cb3aef5989c14537bb33b87 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 22 Apr 2020 23:41:43 -0600 Subject: [PATCH 22/76] kernel/msm-3.18 - MeiG: liangdi: fix dumpsys battery issu Change-Id: Id1c12a4ca59bee9d61c12122edeec75aca1ec319 --- drivers/power/power_supply_sysfs.c | 1 + drivers/power/smb135x-charger.c | 51 +++++++++++++++++++++++++++++- drivers/usb/phy/phy-msm-usb.c | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 0fd9357b0ce..d92aea3c14b 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -314,6 +314,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(manufacturer), POWER_SUPPLY_ATTR(serial_number), POWER_SUPPLY_ATTR(battery_type), + POWER_SUPPLY_ATTR(bms_suspend),//add by liangdi }; static struct attribute * diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index f07f51be9fc..47a0b51a780 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -733,6 +733,10 @@ static enum power_supply_property smb135x_battery_properties[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CURRENT_MAX, + //POWER_SUPPLY_PROP_BMS_SUSPEND,//add by liangdi for device suspend 20200417 }; static int smb135x_get_prop_batt_status(struct smb135x_chg *chip) @@ -831,6 +835,9 @@ static int smb135x_get_prop_batt_temp(struct smb135x_chg *chip) { union power_supply_propval ret = {0, }; + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + if (chip->bms_psy) { chip->bms_psy->get_property(chip->bms_psy, POWER_SUPPLY_PROP_TEMP, &ret); @@ -844,6 +851,9 @@ static int smb135x_get_prop_batt_voltage(struct smb135x_chg *chip) { union power_supply_propval ret = {0, }; + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + if (chip->bms_psy) { chip->bms_psy->get_property(chip->bms_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret); @@ -857,6 +867,9 @@ static int smb135x_get_prop_batt_voltage_ocv(struct smb135x_chg *chip) { union power_supply_propval ret = {0, }; + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + if (chip->bms_psy) { chip->bms_psy->get_property(chip->bms_psy, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ret); @@ -870,6 +883,9 @@ static int smb135x_get_prop_batt_current(struct smb135x_chg *chip) { union power_supply_propval ret = {0, }; + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + if (chip->bms_psy) { chip->bms_psy->get_property(chip->bms_psy, POWER_SUPPLY_PROP_CURRENT_NOW, &ret); @@ -878,6 +894,23 @@ static int smb135x_get_prop_batt_current(struct smb135x_chg *chip) return 0; } + +static int smb135x_get_prop_charge_count(struct smb135x_chg *chip) +{ + union power_supply_propval ret = {0,}; + + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + + if (chip->bms_psy) { + chip->bms_psy->get_property(chip->bms_psy, + POWER_SUPPLY_PROP_CHARGE_COUNTER, &ret); + } else { + pr_debug("No BMS supply registered return 0\n"); + } + + return ret.intval; +} //add end static int smb135x_get_prop_batt_health(struct smb135x_chg *chip) @@ -1667,6 +1700,10 @@ static int smb135x_battery_set_property(struct power_supply *psy, case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: smb135x_system_temp_level_set(chip, val->intval); break; + case POWER_SUPPLY_PROP_BMS_SUSPEND: + chip->device_suspended = true; + pr_err("bms go to suspended\n"); + break; default: rc = -EINVAL; } @@ -1738,7 +1775,16 @@ static int smb135x_battery_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = smb135x_get_prop_batt_current(chip); - break; + break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + val->intval = smb135x_get_prop_charge_count(chip); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + val->intval = chip->vfloat_mv * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = chip->fastchg_ma * 1000; + break; //add end default: return -EINVAL; @@ -4652,6 +4698,8 @@ static int smb135x_suspend(struct device *dev) struct smb135x_chg *chip = i2c_get_clientdata(client); int i, rc; + pr_err("smb135x_suspend\n"); + /* no suspend resume activities for parallel charger */ if (chip->parallel_charger) return 0; @@ -4733,6 +4781,7 @@ static int smb135x_resume(struct device *dev) } chip->device_suspended = false; + pr_err("smb135x_resume\n"); return 0; } diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 20280e8b0ea..29cc240ec3f 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -3514,6 +3514,7 @@ static int otg_power_get_property_usb(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CURRENT_MAX: val->intval = motg->current_max; + motg->voltage_max = MICRO_5V;//add by liangdi for dumpsys battery 20200421 break; case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: val->intval = motg->typec_current_max; -- 2.25.1 From 5f937799d2fd84d932edd770103bbbf8b5a977dd Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 23 Apr 2020 09:03:13 -0600 Subject: [PATCH 23/76] kernel/msm-3.18: - MeiG - liangdi: fix suspend problem Change-Id: I55af6f74df984802de31b40e0dcda0e7f8780c2b --- arch/arm/boot/dts/qcom/msm-pm8909.dtsi | 2 +- drivers/base/power/wakeup.c | 7 ++-- drivers/power/qpnp-vm-bms.c | 46 +++++++++++++++++++++++--- include/linux/power_supply.h | 1 + 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm-pm8909.dtsi b/arch/arm/boot/dts/qcom/msm-pm8909.dtsi index c840c742195..c7ab055a400 100755 --- a/arch/arm/boot/dts/qcom/msm-pm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm8909.dtsi @@ -280,7 +280,7 @@ status = "disabled"; qcom,v-cutoff-uv = <3400000>; - qcom,max-voltage-uv = <4200000>; + qcom,max-voltage-uv = <4350000>; qcom,r-conn-mohm = <0>; qcom,shutdown-soc-valid-limit = <100>; qcom,low-soc-calculate-soc-threshold = <15>; diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 7dbfe1a35a6..eb4ff19963d 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -144,7 +144,6 @@ void wakeup_source_add(struct wakeup_source *ws) if (WARN_ON(!ws)) return; - spin_lock_init(&ws->lock); setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws); ws->active = false; @@ -738,7 +737,7 @@ void pm_print_active_wakeup_sources(void) rcu_read_lock(); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->active) { - pr_info("active wakeup source: %s\n", ws->name); + pr_err("active wakeup source: %s\n", ws->name); active = 1; } else if (!active && (!last_activity_ws || @@ -749,7 +748,7 @@ void pm_print_active_wakeup_sources(void) } if (!active && last_activity_ws) - pr_info("last active wakeup source: %s\n", + pr_err("last active wakeup source: %s\n", last_activity_ws->name); rcu_read_unlock(); } @@ -779,7 +778,7 @@ bool pm_wakeup_pending(void) spin_unlock_irqrestore(&events_lock, flags); if (ret) { - pr_info("PM: Wakeup pending, aborting suspend\n"); + pr_err("PM: Wakeup pending, aborting suspend\n"); pm_print_active_wakeup_sources(); } diff --git a/drivers/power/qpnp-vm-bms.c b/drivers/power/qpnp-vm-bms.c index 75c305925d8..c74e4a5b5ef 100644 --- a/drivers/power/qpnp-vm-bms.c +++ b/drivers/power/qpnp-vm-bms.c @@ -509,6 +509,32 @@ static bool is_battery_charging(struct qpnp_bms_chip *chip) return false; } +//add by liangdi for device suspend 20200417 +static bool set_device_suspend(struct qpnp_bms_chip *chip) +{ + union power_supply_propval ret = {0,}; + int rc; + + if (chip->batt_psy == NULL) + chip->batt_psy = power_supply_get_by_name("battery"); + if (chip->batt_psy) { + /* if battery has been registered, use the type property */ + rc = chip->batt_psy->set_property(chip->batt_psy, + POWER_SUPPLY_PROP_BMS_SUSPEND, &ret); + + if (rc) { + pr_err("Unable to set POWER_SUPPLY_PROP_BMS_SUSPEND rc=%d\n", rc); + return false; + } + return true; + } + + /* Default to false if the battery power supply is not registered. */ + pr_debug("battery power supply is not registered\n"); + return false; +} +//add end + #define BAT_PRES_BIT BIT(7) static bool is_battery_present(struct qpnp_bms_chip *chip) { @@ -4127,11 +4153,23 @@ static void process_resume_data(struct qpnp_bms_chip *chip) static int bms_suspend(struct device *dev) { struct qpnp_bms_chip *chip = dev_get_drvdata(dev); - bool battery_charging = is_battery_charging(chip); - bool hi_power_state = is_hi_power_state_requested(chip); - bool charger_present = is_charger_present(chip); + bool device_suspend;//add by liangdi for device suspend 20200417 + bool battery_charging; + bool hi_power_state; + bool charger_present; bool bms_suspend_config; + pr_err("bms_suspend\n"); + device_suspend = set_device_suspend(chip);//add by liangdi for device suspend 20200417 + battery_charging = is_battery_charging(chip); + hi_power_state = is_hi_power_state_requested(chip); + charger_present = is_charger_present(chip); + + if(!device_suspend) + { + pr_err("set bms suspend failed\n"); + } + /* * Keep BMS FSM active if 'cfg_force_bms_active_on_charger' property * is present and charger inserted. This ensures that recharge @@ -4213,7 +4251,7 @@ static int bms_resume(struct device *dev) monitor_soc_delay / 1000, tm_now_sec, chip->tm_sec); schedule_delayed_work(&chip->monitor_soc_work, msecs_to_jiffies(monitor_soc_delay)); - + pr_err("bms_resume\n"); return 0; } diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 7d3c3df6588..606f931aa99 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -267,6 +267,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, POWER_SUPPLY_PROP_BATTERY_TYPE, + POWER_SUPPLY_PROP_BMS_SUSPEND,//add by liangdi for device suspend 20200417 }; enum power_supply_type { -- 2.25.1 From 5694c9253cc97caf30ce9b5040135a765619057d Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Apr 2020 17:15:49 -0400 Subject: [PATCH 24/76] MeiG Liangdi: optimize beeper Change-Id: I7d43a3c1dc41f179aff59a47f8c67c79c8cf29bf --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 17 +++----- drivers/mg_driver/mgdrv/mg_drv.c | 2 +- drivers/platform/msm/qpnp-vibrator.c | 58 ++++++++++++++++--------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index cf3b1f32651..545c73a3ced 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -216,8 +216,8 @@ mg_drv{ compatible = "qcom,mg_drv"; - status = "ok"; - qcom,pwm_gpio = <&msm_gpio 98 0x0>; + status = "disabled"; + //qcom,pwm_gpio = <&msm_gpio 98 0x0>; }; gen-vkeys { @@ -349,17 +349,10 @@ }; &blsp1_uart2 { - status = "ok"; - pinctrl-names = "default"; - pinctrl-0 = <&nrf52_active>; -}; - - -/* -&blsp1_uart2_hs{ - status = "ok"; + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&nrf52_active>; }; -*/ /* &spi_0 { diff --git a/drivers/mg_driver/mgdrv/mg_drv.c b/drivers/mg_driver/mgdrv/mg_drv.c index 72173803c9c..bc2533fb37f 100755 --- a/drivers/mg_driver/mgdrv/mg_drv.c +++ b/drivers/mg_driver/mgdrv/mg_drv.c @@ -60,7 +60,7 @@ int mg_parse_dt(void) glmg_driver->pwm_gpio = of_get_named_gpio(node, "qcom,pwm_gpio", 0); if (gpio_is_valid(glmg_driver->pwm_gpio)) { - gpio_direction_output(glmg_driver->pwm_gpio, 1); + gpio_direction_output(glmg_driver->pwm_gpio, 0); pr_err("relay gpio power on\n"); } return 0; diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index fa890ac8394..94aa9e4f1a5 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -174,12 +174,10 @@ static int qpnp_vibrator_config(struct qpnp_vib *vib) static void gpio_pwm_start(void) { - pr_info("--------------gpio pwm start---------------"); + //pr_err("gpio pwm start\n"); gl_vib->time = (unsigned long)((50 * GPIO_PWM_DELAY_TIME)/100); gl_vib->pwm_level = 0; - - hrtimer_init(&gl_vib->mytimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); - gl_vib->mytimer.function = hrtimer_handler; + gl_vib->kt = ktime_set(0, GPIO_PWM_DELAY_TIME); hrtimer_start(&gl_vib->mytimer,gl_vib->kt,HRTIMER_MODE_REL); } @@ -188,6 +186,7 @@ static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer) { if(gl_vib->gpio_pwm_value == 0) { + //pr_err("gpio pwm stop\n"); gpio_direction_output(gl_vib->pwm_gpio, 0); gl_vib->pwm_level = 1; return HRTIMER_NORESTART; @@ -216,6 +215,8 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) { int rc; u8 val; + + //pr_err("value on is :%d\n", on); if (on) { if (vib->mode != QPNP_VIB_MANUAL) { @@ -228,6 +229,7 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) if (rc < 0) return rc; vib->reg_en_ctl = val; + //add by liangdi if (gpio_is_valid(vib->vib_gpio)) { @@ -235,9 +237,13 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(vib->vib_gpio, 0); } //add end + + if (gpio_is_valid(vib->pwm_gpio)) + { + vib->gpio_pwm_value = 1; + gpio_pwm_start(); + } - vib->gpio_pwm_value = 1; - gpio_pwm_start(); } } else { if (vib->mode != QPNP_VIB_MANUAL) { @@ -250,6 +256,7 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) if (rc < 0) return rc; vib->reg_en_ctl = val; + //add by liangdi if (gpio_is_valid(vib->vib_gpio)) { @@ -257,8 +264,9 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(vib->vib_gpio, 1); } //add end - - vib->gpio_pwm_value = 0; + + if (gpio_is_valid(vib->pwm_gpio)) + vib->gpio_pwm_value = 0; } } @@ -273,15 +281,19 @@ static void qpnp_vib_enable(struct timed_output_dev *dev, int value) mutex_lock(&vib->lock); hrtimer_cancel(&vib->vib_timer); - if (value == 0) { - vib->state = 0; - } else { - value = (value > vib->timeout ? - vib->timeout : value); - vib->state = 1; - hrtimer_start(&vib->vib_timer, - ktime_set(value / 1000, (value % 1000) * 1000000), - HRTIMER_MODE_REL); + //pr_err("qpnp_vib_enable %d",value); + if(value != 10) + { + if (value == 0) { + vib->state = 0; + } else { + value = (value > vib->timeout ? + vib->timeout : value); + vib->state = 1; + hrtimer_start(&vib->vib_timer, + ktime_set(value / 1000, (value % 1000) * 1000000), + HRTIMER_MODE_REL); + } } mutex_unlock(&vib->lock); schedule_work(&vib->work); @@ -292,6 +304,7 @@ static void qpnp_vib_update(struct work_struct *work) struct qpnp_vib *vib = container_of(work, struct qpnp_vib, work); qpnp_vib_set(vib, vib->state); + //pr_info("state is :%d\n", vib->state); } static int qpnp_vib_get_time(struct timed_output_dev *dev) @@ -345,14 +358,16 @@ static int qpnp_vib_parse_dt(struct qpnp_vib *vib) /* vibrator */ vib->vib_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "vib-gpios", 0, &vib->vib_gpio_flags); + vib->pwm_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "pwm-gpios", 0, &vib->pwm_gpio_flags); if (gpio_is_valid(vib->pwm_gpio)) { - gpio_direction_output(vib->pwm_gpio, 1); + gpio_direction_output(vib->pwm_gpio, 0); pr_err("pwm gpio power on\n"); } + //add end vib->timeout = QPNP_VIB_DEFAULT_TIMEOUT; rc = of_property_read_u32(spmi->dev.of_node, @@ -449,6 +464,8 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) } vib->base = vib_resource->start; vib->gpio_pwm_value = 0; + hrtimer_init(&vib->mytimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); + vib->mytimer.function = hrtimer_handler; rc = qpnp_vib_parse_dt(vib); if (rc) { @@ -462,7 +479,7 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) pr_err("gpio req failed for id\n"); ret = -ENODEV; } - + rc = qpnp_vibrator_config(vib); if (rc) { dev_err(&spmi->dev, "vib config failed\n"); @@ -484,7 +501,7 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) rc = timed_output_dev_register(&vib->timed_dev); if (rc < 0) return rc; - + gl_vib = vib; return rc; @@ -496,6 +513,7 @@ static int qpnp_vibrator_remove(struct spmi_device *spmi) cancel_work_sync(&vib->work); hrtimer_cancel(&vib->vib_timer); + hrtimer_cancel(&vib->mytimer); timed_output_dev_unregister(&vib->timed_dev); mutex_destroy(&vib->lock); -- 2.25.1 From bd9fa1ad5602e175d5669153b016e79fd170b09e Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Apr 2020 17:36:24 -0400 Subject: [PATCH 25/76] MeiG liangi: optimize drivers Change-Id: Ie873cd04d38e7c5b4892a561cc930832d81f0900 --- arch/arm/boot/dts/qcom/Makefile | 56 +----- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 210 +++++++++++----------- arch/arm/boot/dts/qcom/msm8909.dtsi | 7 +- arch/arm/configs/msm8909-perf_defconfig | 44 ++--- drivers/input/touchscreen/gt9xx_2/gt9xx.c | 31 ++-- 5 files changed, 149 insertions(+), 199 deletions(-) diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 222dbd27229..0bceda44a2e 100755 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -292,61 +292,7 @@ dtb-$(CONFIG_ARCH_MSM8916) += msm8952-qrd-skum.dtb \ msm8952-ext-codec-cdp.dtb \ msm8952-mtp.dtb -dtb-$(CONFIG_ARCH_MSM8909) += msm8909-pm8916-mtp.dtb \ - msm8909-cdp.dtb \ - msm8909-1gb-qrd-skua.dtb\ - msm8909-1gb-qrd-skuc.dtb \ - msm8909-1gb-qrd-skue.dtb \ - msm8909-qrd-skue.dtb \ - msm8909w-wtp.dtb \ - apq8009w-wtp.dtb \ - apq8009w-cdp.dtb \ - msm8909w-swoctp.dtb \ - msm8909w-swoctp-circpanel.dtb \ - apq8009w-swoctp.dtb \ - apq8009w-swoctp-circpanel.dtb \ - apq8009w-nowgr-swoctp.dtb \ - apq8009w-nowgr-swoctp-circpanel.dtb \ - msm8909-pm8916-cdp.dtb \ - msm8909w-cdp.dtb \ - msm8909w-1gb-wtp.dtb \ - apq8009w-1gb-wtp.dtb \ - msm8909w-1gb-cdp.dtb \ - apq8009w-1gb-cdp.dtb \ - msm8909w-1gb-swoctp.dtb \ - msm8909w-1gb-swoctp-circpanel.dtb \ - apq8009w-1gb-swoctp.dtb \ - apq8009w-1gb-swoctp-circpanel.dtb \ - apq8009w-1gb-nowgr-swoctp.dtb \ - apq8009w-1gb-nowgr-swoctp-circpanel.dtb \ - msm8909w-bg-wtp-v1.dtb \ - msm8909w-bg-wtp-v2.dtb \ - apq8009w-bg-wtp-v1.dtb \ - apq8009w-bg-wtp-v2.dtb \ - apq8009-mtp-wcd9326.dtb \ - msm8909-mtp-wcd9326.dtb \ - msm8909-mtp-wcd9326-refboard.dtb \ - msm8909-512mb-mtp-wcd9326-refboard.dtb \ - msm8909-512mb-cdp-wcd9326-refboard.dtb \ - msm8909-512mb-rcm-wcd9326-refboard.dtb \ - msm8909-cdp-wcd9326-refboard.dtb \ - msm8909-rcm-wcd9326-refboard.dtb \ - apq8009-mtp-wcd9326-refboard.dtb \ - apq8009-512mb-mtp-wcd9326-refboard.dtb \ - apq8009-512mb-cdp-wcd9326-refboard.dtb \ - apq8009-512mb-rcm-wcd9326-refboard.dtb \ - apq8009-cdp-wcd9326-refboard.dtb \ - apq8009-rcm-wcd9326-refboard.dtb \ - apq8009-robot-refboard.dtb \ - apq8009-robot-rome.dtb \ - apq8009-mtp-drone.dtb \ - msm8909-mtp.dtb \ - msm8909-1gb-mtp.dtb \ - msm8909-1gb-rcm.dtb \ - msm8909-pm8916-1gb-rcm.dtb \ - msm8909-1gb-cdp.dtb \ - apq8009-ext-codec-dragon.dtb \ - apq8009-dragon.dtb +dtb-$(CONFIG_ARCH_MSM8909) += msm8909-1gb-mtp.dtb ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 545c73a3ced..165a4e4d627 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -354,7 +354,6 @@ pinctrl-0 = <&nrf52_active>; }; -/* &spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; @@ -374,7 +373,6 @@ status = "ok"; }; }; -*/ / { mtp_batterydata: qcom,battery-data { @@ -466,22 +464,22 @@ &i2c_1 { /* BLSP1 QUP1 */ //light and proximity sensor -/* - liteon@23 { - compatible = "liteon,ltr553"; - reg = <0x23>; - pinctrl-names = "default","sleep"; - pinctrl-0 = <<r553_default>; - pinctrl-1 = <<r553_sleep>; - interrupt-parent = <&msm_gpio>; - interrupts = <94 0x2>; - vdd-supply = <&pm8909_l17>; - vio-supply = <&pm8909_l6>; - liteon,intr = <&msm_gpio 94 0x2>; - liteon,highthr = <800>; - liteon,lowthr = <300>; - }; -*/ + +// liteon@23 { +// compatible = "liteon,ltr553"; +// reg = <0x23>; +// pinctrl-names = "default","sleep"; +// pinctrl-0 = <<r553_default>; +// pinctrl-1 = <<r553_sleep>; +// interrupt-parent = <&msm_gpio>; +// interrupts = <94 0x2>; +// vdd-supply = <&pm8909_l17>; +// vio-supply = <&pm8909_l6>; +// liteon,intr = <&msm_gpio 94 0x2>; +// liteon,highthr = <800>; +// liteon,lowthr = <300>; +// }; + akm@c { compatible = "ak,ak09911"; reg = <0x0c>; @@ -496,21 +494,21 @@ akm,auto-report; }; - bosch@18 { //Accelerometer sensor - compatible = "bosch,bma2x2"; - status = "disabled"; - reg = <0x18>; - pinctrl-names = "default"; - pinctrl-0 = <&bma2x2_int1_default &bma2x2_int2_default>; - interrupt-parent = <&msm_gpio>; - interrupts = <96 0x2002>; - vdd-supply = <&pm8909_l17>; - vio-supply = <&pm8909_l6>; - bosch,init-interval = <200>; - bosch,place = <2>; - bosch,gpio-int1 = <&msm_gpio 96 0x2002>; - bosch,gpio-int2 = <&msm_gpio 31 0x2002>; - }; +// bosch@18 { //Accelerometer sensor +// compatible = "bosch,bma2x2"; +// status = "disabled"; +// reg = <0x18>; +// pinctrl-names = "default"; +// pinctrl-0 = <&bma2x2_int1_default &bma2x2_int2_default>; +// interrupt-parent = <&msm_gpio>; +// interrupts = <96 0x2002>; +// vdd-supply = <&pm8909_l17>; +// vio-supply = <&pm8909_l6>; +// bosch,init-interval = <200>; +// bosch,place = <2>; +// bosch,gpio-int1 = <&msm_gpio 96 0x2002>; +// bosch,gpio-int2 = <&msm_gpio 31 0x2002>; +// }; bmp@76 { compatible = "bmp280"; @@ -523,14 +521,14 @@ compatible = "bosch,bmi160"; //status = "disabled"; reg = <0x68>; - pinctrl-names = "default"; - pinctrl-0 = <&bmi160_int1_default>; + //pinctrl-names = "default"; + //pinctrl-0 = <&bmi160_int1_default>; interrupt-parent = <&msm_gpio>; - interrupts = <95 0x2002>; + interrupts = <96 0x2002>; vdd-supply = <&pm8909_l17>; vio-supply = <&pm8909_l6>; bosch,place = <5>; - bosch,gpio-int1 = <&msm_gpio 95 0x2002>; + bosch,gpio-int1 = <&msm_gpio 96 0x2002>; }; }; @@ -615,91 +613,91 @@ }; }; }; - bma2x2_int1_pin { - bma2x2_int1_default: int1_default { - mux { - pins = "gpio96"; - function = "gpio"; - }; - config { - pins = "gpio96"; - drive-dtrength = <6>; - bias-pull-up; - }; - }; - }; - bma2x2_int2_pin { - bma2x2_int2_default: int2_default { - mux { - pins = "gpio65"; - function = "gpio"; - }; - config { - pins = "gpio65"; - drive-dtrength = <6>; - bias-pull-up; - }; - }; - }; - - bmi160_int1_pin { - bmi160_int1_default: int1_default { - mux { - pins = "gpio95"; - function = "gpio"; - }; - config { - pins = "gpio95"; - drive-dtrength = <6>; - bias-pull-up; - }; - }; - }; - - ltr553_int_pin { - ltr553_default: ltr553_default { - mux { - pins = "gpio94"; - function = "gpio"; - }; - config { - pins = "gpio94"; - drive-dtrength = <6>; - bias-pull-up; - }; - }; - ltr553_sleep: ltr553_sleep { - mux { - pins = "gpio94"; - function = "gpio"; - }; - config { - pins = "gpio94"; - drive-strength = <2>; - bias-pull-down; - }; - }; - }; +// bma2x2_int1_pin { +// bma2x2_int1_default: int1_default { +// mux { +// pins = "gpio96"; +// function = "gpio"; +// }; +// config { +// pins = "gpio96"; +// drive-dtrength = <6>; +// bias-pull-up; +// }; +// }; +// }; +// bma2x2_int2_pin { +// bma2x2_int2_default: int2_default { +// mux { +// pins = "gpio65"; +// function = "gpio"; +// }; +// config { +// pins = "gpio65"; +// drive-dtrength = <6>; +// bias-pull-up; +// }; +// }; +// }; + +// bmi160_int1_pin { +// bmi160_int1_default: int1_default { +// mux { +// pins = "gpio96"; +// function = "gpio"; +// }; +// config { +// pins = "gpio96"; +// drive-dtrength = <6>; +// bias-pull-up; +// }; +// }; +// }; + +// ltr553_int_pin { +// ltr553_default: ltr553_default { +// mux { +// pins = "gpio94"; +// function = "gpio"; +// }; +// config { +// pins = "gpio94"; +// drive-dtrength = <6>; +// bias-pull-up; +// }; +// }; +// ltr553_sleep: ltr553_sleep { +// mux { +// pins = "gpio94"; +// function = "gpio"; +// }; +// config { +// pins = "gpio94"; +// drive-strength = <2>; +// bias-pull-down; +// }; +// }; +// }; akm_reset_pin { akm_default: akm_default { mux { - pins = "gpio65"; + pins = "gpio16"; function = "gpio"; }; config { - pins = "gpio65"; + pins = "gpio16"; drive-dtrength = <6>; bias-pull-up; }; }; akm_sleep: akm_sleep { mux { - pins = "gpio65"; + pins = "gpio16"; function = "gpio"; }; config { - pins = "gpio65"; + pins = "gpio16"; drive-strength = <2>; bias-pull-down; }; diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index 474cca4bf28..498642ce762 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -207,7 +207,7 @@ #include "msm8909-bus.dtsi" #include "msm8909-mdss.dtsi" #include "msm8909-mdss-pll.dtsi" -#include "msm8909-camera.dtsi" +//#include "msm8909-camera.dtsi" &soc { #address-cells = <1>; @@ -409,6 +409,7 @@ < 1267200 >; }; + blsp1_uart1: serial@78af000 { compatible = "qcom,msm-lsuart-v14"; reg = <0x78af000 0x200>; @@ -1406,6 +1407,7 @@ <&dma_blsp1 7 32 0x20000020 0x20>; dma-names = "tx", "rx"; qcom,master-id = <86>; + status = "disabled"; }; i2c_4: i2c@78b8000 { /* BLSP1 QUP4 */ @@ -1443,7 +1445,7 @@ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, <&clock_gcc clk_gcc_blsp1_qup5_i2c_apps_clk>; clock-names = "iface_clk", "core_clk"; - qcom,clk-freq-out = <100000>; + qcom,clk-freq-out = <400000>; qcom,clk-freq-in = <19200000>; pinctrl-names = "i2c_active", "i2c_sleep"; pinctrl-0 = <&i2c_5_active>; @@ -1478,6 +1480,7 @@ <&dma_blsp1 9 32 0x20000020 0x20>; dma-names = "tx", "rx"; qcom,master-id = <86>; + status = "disabled"; }; i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */ diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 29717973bd8..5efe39e1fa4 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -10,7 +10,7 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=16 +CONFIG_LOG_BUF_SHIFT=20 CONFIG_CGROUPS=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y @@ -247,17 +247,17 @@ CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=y # CONFIG_SCSI_PROC_FS is not set -#CONFIG_SCSI=y -#CONFIG_BLK_DEV_SD=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y -#CONFIG_SCSI_CONSTANTS=y -#CONFIG_SCSI_LOGGING=y -#CONFIG_SCSI_SCAN_ASYNC=y -#CONFIG_SCSI_UFSHCD=y -#CONFIG_SCSI_UFSHCD_PLATFORM=y -#CONFIG_SCSI_UFS_QCOM=y -#CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -368,16 +368,16 @@ CONFIG_MEDIA_RADIO_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_SOC_CAMERA=y +# CONFIG_SOC_CAMERA=y CONFIG_MSM_VIDC_V4L2=y -CONFIG_MSMB_CAMERA=y -CONFIG_MSM_CAMERA_SENSOR=y -CONFIG_MSM_CSI30_HEADER=y -CONFIG_MSM_CSIPHY=y -CONFIG_MSM_CSID=y -CONFIG_MSM_EEPROM=y -CONFIG_MSM_ISP_V1=y -CONFIG_MSM_ISPIF=y +# CONFIG_MSMB_CAMERA=y +# CONFIG_MSM_CAMERA_SENSOR=y +# CONFIG_MSM_CSI30_HEADER=y +# CONFIG_MSM_CSIPHY=y +# CONFIG_MSM_CSID=y +# CONFIG_MSM_EEPROM=y +# CONFIG_MSM_ISP_V1=y +# CONFIG_MSM_ISPIF=y CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_MSM_KGSL=y @@ -566,7 +566,7 @@ CONFIG_SENSORS_BMP280=y CONFIG_SENSORS_BMP280_I2C=y CONFIG_TOUCHSCREEN_GT9XX=y CONFIG_GT9XX_TOUCHPANEL_DRIVER=y -CONFIG_GT9XX_TOUCHPANEL_UPDATE=y -CONFIG_GT9XX_TOUCHPANEL_DEBUG=y +# CONFIG_GT9XX_TOUCHPANEL_UPDATE=y +# CONFIG_GT9XX_TOUCHPANEL_DEBUG=y CONFIG_MG_DRIVER_CONTROL=y -#CONFIG_NRF_DRIVER=y +CONFIG_NRF_DRIVER=y diff --git a/drivers/input/touchscreen/gt9xx_2/gt9xx.c b/drivers/input/touchscreen/gt9xx_2/gt9xx.c index 86b609bb54e..e1192bf7627 100644 --- a/drivers/input/touchscreen/gt9xx_2/gt9xx.c +++ b/drivers/input/touchscreen/gt9xx_2/gt9xx.c @@ -207,7 +207,7 @@ int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len) break; dev_err(&client->dev, "I2C retry: %d\n", retries + 1); } - if ((retries == GTP_I2C_RETRY_5)) { + if (retries == GTP_I2C_RETRY_5) { if (ts->pdata->slide_wakeup) if (DOZE_ENABLED == doze_status) return ret; @@ -424,7 +424,11 @@ static void goodix_ts_work_func(struct work_struct *work) #endif if (ts->gtp_is_suspend) + { + if(ts->use_irq) + gtp_irq_enable(ts); return; + } if (ts->pdata->slide_wakeup) { if (DOZE_ENABLED == doze_status) { @@ -523,7 +527,7 @@ static void goodix_ts_work_func(struct work_struct *work) if (ts->pdata->with_pen) { if (pre_pen && (touch_num == 0)) { - dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!"); + //dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!"); input_report_key(ts->input_dev, BTN_TOOL_PEN, 0); input_mt_slot(ts->input_dev, 5); input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1); @@ -541,8 +545,8 @@ static void goodix_ts_work_func(struct work_struct *work) if (ts->pdata->with_pen) { id = coor_data[pos]; if (id == 128) { - dev_dbg(&ts->client->dev, - "Pen touch DOWN(Slot)!"); + //dev_dbg(&ts->client->dev, + // "Pen touch DOWN(Slot)!"); input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8); input_y = coor_data[pos + 3] @@ -561,9 +565,9 @@ static void goodix_ts_work_func(struct work_struct *work) ABS_MT_POSITION_Y, input_y); input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w); - dev_dbg(&ts->client->dev, - "Pen/Stylus: (%d, %d)[%d]", - input_x, input_y, input_w); + //dev_dbg(&ts->client->dev, + // "Pen/Stylus: (%d, %d)[%d]", + // input_x, input_y, input_w); pre_pen = 1; pre_touch = 0; } @@ -2145,14 +2149,8 @@ static int goodix_ts_probe(struct i2c_client *client, if (pdata->force_update) ts->force_update = true; - - ret = gtp_check_product_id(client); - if (ret != 0) { - dev_err(&client->dev, "GTP Product id doesn't match.\n"); - goto exit_free_irq; - } -#if 0//modified by lidan for shutdown charging +#if 0//modified by liangdi for shutdown charging if (pdata->fw_name) strlcpy(ts->fw_name, pdata->fw_name, strlen(pdata->fw_name) + 1); @@ -2209,6 +2207,11 @@ static int goodix_ts_probe(struct i2c_client *client, if (ret != 2) dev_err(&client->dev, "GTP firmware version read failed.\n"); + ret = gtp_check_product_id(client); + if (ret != 0) { + dev_err(&client->dev, "GTP Product id doesn't match.\n"); + goto exit_free_irq; + } if (ts->use_irq) gtp_irq_enable(ts); -- 2.25.1 From 3dbfb38aeaf75d1795039f54ee0af9e18cdf76bf Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 29 Apr 2020 18:06:16 -0400 Subject: [PATCH 26/76] MeiG Liangdi: update gt9xx.2.8 Change-Id: Iac2085b4b110e84ce70c7deefa4aaff42c975296 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 66 +- arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 101 +- arch/arm/configs/msm8909-perf_defconfig | 2 +- drivers/input/touchscreen/Kconfig | 2 +- drivers/input/touchscreen/Makefile | 2 +- drivers/input/touchscreen/gt9xx_2.8/Kconfig | 35 + drivers/input/touchscreen/gt9xx_2.8/Makefile | 7 + .../input/touchscreen/gt9xx_2.8/goodix_tool.c | 530 ++++ drivers/input/touchscreen/gt9xx_2.8/gt9xx.c | 2565 +++++++++++++++++ drivers/input/touchscreen/gt9xx_2.8/gt9xx.h | 384 +++ .../touchscreen/gt9xx_2.8/gt9xx_update.c | 2092 ++++++++++++++ 11 files changed, 5735 insertions(+), 51 deletions(-) create mode 100755 drivers/input/touchscreen/gt9xx_2.8/Kconfig create mode 100755 drivers/input/touchscreen/gt9xx_2.8/Makefile create mode 100755 drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c create mode 100755 drivers/input/touchscreen/gt9xx_2.8/gt9xx.c create mode 100755 drivers/input/touchscreen/gt9xx_2.8/gt9xx.h create mode 100755 drivers/input/touchscreen/gt9xx_2.8/gt9xx_update.c diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 165a4e4d627..f83068fa56f 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -118,26 +118,7 @@ }; i2c@78b9000 { /* BLSP1 QUP5 */ - synaptics@20 { - compatible = "synaptics,dsx"; - reg = <0x20>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x2008>; - avdd-supply = <&pm8909_l17>; - vdd-supply = <&pm8909_l6>; - /* pins used by touchscreen */ - pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - pinctrl-2 = <&ts_release>; - synaptics,irq-gpio = <&msm_gpio 13 0x2008>; - synaptics,reset-gpio = <&msm_gpio 12 0x0>; - synaptics,disable-gpios; - synaptics,display-coords = <0 0 719 1279>; - synaptics,panel-coords = <0 0 719 1405>; - status = "disabled"; - }; - +/* goodix@5d { compatible = "goodix,gt9xx"; reg = <0x5d>; @@ -192,6 +173,47 @@ goodix,have-touch-key; //goodix,driver-send-cfg; }; +*/ + gt9xx@5d { + compatible = "goodix,gt9xx"; + reg = <0x5d>; + status = "okay"; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2800>; + vdd_ana-supply = <&pm8909_l17>; + vcc_i2c-supply = <&pm8909_l6>; + + pinctrl-names = "default", "int-output-low","int-output-high", "int-input"; + pinctrl-0 = <&ts_int_default>; + pinctrl-1 = <&ts_int_output_low>; + pinctrl-2 = <&ts_int_output_high>; + pinctrl-3 = <&ts_int_input>; + + reset-gpios = <&msm_gpio 12 0x0>; + irq-gpios = <&msm_gpio 13 0x2800>; + irq-flags = <2>; + + touchscreen-max-id = <11>; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; + touchscreen-max-w = <512>; + touchscreen-max-p = <512>; + touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158��KEY_MENU=139*/ + + goodix,slide-wakeup = <0>; + goodix,type-a-report = <0>; + goodix,driver-send-cfg = <0>; + goodix,resume-in-workqueue = <0>; + goodix,int-sync = <1>; + goodix,swap-x2y = <0>; + goodix,esd-protect = <1>; + goodix,auto-update-cfg = <0>; + goodix,power-off-sleep = <1>; + goodix,pen-suppress-finger = <0>; + goodix,cfg-group0 = [ + 53 D0 02 00 05 05 F5 D5 21 48 2D 0F 5A 41 0E 05 00 00 32 32 20 00 05 14 14 1A 14 8B 2B 00 + ]; + }; }; i2c@78b6000 { /* BLSP1 QUP2 */ @@ -354,7 +376,7 @@ pinctrl-0 = <&nrf52_active>; }; -&spi_0 { +/*&spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; reg = <0>; @@ -372,7 +394,7 @@ pinctrl-2 = <&nrf_release>; status = "ok"; }; -}; +};*/ / { mtp_batterydata: qcom,battery-data { diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index c2157f73090..0b134c9a9fa 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -185,30 +185,6 @@ }; }; - nrf52_active: nrf52_active { - mux { - pins = "gpio20", "gpio21"; - function = "blsp_uart2"; - }; - config { - pins = "gpio20", "gpio21"; - drive-strength = <2>; - bias-disable; - }; - }; - - nrf52_sleep: nrf52_sleep { - mux { - pins = "gpio20", "gpio21"; - function = "blsp_uart2"; - }; - config { - pins = "gpio20", "gpio21"; - drive-strength = <2>; - bias-pull-down; - }; - }; - blsp1_uart2_tx_active: blsp1_uart2_tx_active { mux { pins = "gpio20"; @@ -930,7 +906,55 @@ }; }; -/* + /* add pingrp for touchscreen */ + ts_int_default: ts_int_defalut { + mux { + pins = "gpio13"; + function = "gpio"; + }; + config { + pins = "gpio13"; + drive-strength = <16>; + /*bias-pull-up;*/ + input-enable; + bias-disable; + }; + }; + + ts_int_output_high: ts_int_output_high { + mux { + pins = "gpio13"; + function = "gpio"; + }; + config { + pins = "gpio13"; + output-high; + }; + }; + + ts_int_output_low: ts_int_output_low { + mux { + pins = "gpio13"; + function = "gpio"; + }; + config { + pins = "gpio13"; + output-low; + }; + }; + + ts_int_input: ts_int_input { + mux { + pins = "gpio13"; + function = "gpio"; + }; + config { + pins = "gpio13"; + input-enable; + bias-disable; + }; + }; + nrf_int_active { nrf_int_active: nrf_int_active { mux { @@ -1035,7 +1059,32 @@ }; }; }; -*/ + + nrf52_active: nrf52_active { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; + + nrf52_sleep: nrf52_sleep { + mux { + pins = "gpio20", "gpio21"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-pull-down; + }; + }; tlmm_gpio_key { gpio_key_active: gpio_key_active { diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 5efe39e1fa4..7394dd5d0e2 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -565,7 +565,7 @@ CONFIG_SENSORS_BMI160_ENABLE_INT1=y CONFIG_SENSORS_BMP280=y CONFIG_SENSORS_BMP280_I2C=y CONFIG_TOUCHSCREEN_GT9XX=y -CONFIG_GT9XX_TOUCHPANEL_DRIVER=y +#CONFIG_GT9XX_TOUCHPANEL_DRIVER=y # CONFIG_GT9XX_TOUCHPANEL_UPDATE=y # CONFIG_GT9XX_TOUCHPANEL_DEBUG=y CONFIG_MG_DRIVER_CONTROL=y diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index d903feec011..537384144bf 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1135,7 +1135,7 @@ config TOUCHSCREEN_MAXIM_STI To compile this driver as a module, choose M here: the module will be called maxim_sti. -source "drivers/input/touchscreen/gt9xx/Kconfig" +source "drivers/input/touchscreen/gt9xx_2.8/Kconfig" config TOUCHSCREEN_GT1XX bool "Goodix touchpanel GT1xx series" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index d5508c103f9..1635943d44a 100755 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -90,5 +90,5 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o #obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ -obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_2/ +obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_2.8/ obj-$(CONFIG_TOUCHSCREEN_GT1XX) += gt1xx/ diff --git a/drivers/input/touchscreen/gt9xx_2.8/Kconfig b/drivers/input/touchscreen/gt9xx_2.8/Kconfig new file mode 100755 index 00000000000..f0eff1979b7 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2.8/Kconfig @@ -0,0 +1,35 @@ +# +# Goodix GT9xx Touchscreen driver +# +config TOUCHSCREEN_GT9XX + bool "Goodix touchpanel GT9xx series" + depends on I2C + help + Say Y here if you have a Goodix GT9xx touchscreen + controller. + + If unsure, say N. + +config TOUCHSCREEN_GT9XX_UPDATE + tristate "Goodix GT9xx touch controller auto update support" + depends on TOUCHSCREEN_GT9XX + default y + help + Enable this for support firmware update. + + Say Y here if you want update touch controller firmware. + + If unsure, say N. + +config TOUCHSCREEN_GT9XX_TOOL + tristate "Goodix GT9xx Tools for debuging" + depends on TOUCHSCREEN_GT9XX + default y + help + This implement interface support for Goodix GT9xx + touchscreen debug. + + Say Y here if you want to have a Android app debug interface + to your system. + + If unsure, say N. diff --git a/drivers/input/touchscreen/gt9xx_2.8/Makefile b/drivers/input/touchscreen/gt9xx_2.8/Makefile new file mode 100755 index 00000000000..73ed2e91bf7 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2.8/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Goodix gt9xx touchscreen driver. +# +#subdir-ccflags-y += -DDEBUG +obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx.o +obj-$(CONFIG_TOUCHSCREEN_GT9XX_UPDATE) += gt9xx_update.o +obj-$(CONFIG_TOUCHSCREEN_GT9XX_TOOL) += goodix_tool.o diff --git a/drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c b/drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c new file mode 100755 index 00000000000..04d1f1b8f00 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c @@ -0,0 +1,530 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 2.8.0.1 + * Release Date: 2017/11/24 + */ + +#include "gt9xx.h" + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *)) +static char procname[20] = {0}; + +#pragma pack(1) +struct st_cmd_head { + u8 wr; /*write read flag 0:R 1:W 2:PID 3:*/ + u8 flag; /*0:no need flag/int 1: need flag 2:need int*/ + u8 flag_addr[2]; /*flag address*/ + u8 flag_val; /*flag val*/ + u8 flag_relation; /*flag_val:flag 0:not equal 1:equal 2:> 3:<*/ + u16 circle; /*polling cycle*/ + u8 times; /*plling times*/ + u8 retry; /*I2C retry times*/ + u16 delay; /*delay before read or after write*/ + u16 data_len; /*data length*/ + u8 addr_len; /*address length*/ + u8 addr[2]; /*address*/ + u8 res[3]; /*reserved*/ + u8 *data; }; /*data pointer*/ +#pragma pack() +struct st_cmd_head cmd_head; + +static struct i2c_client *gt_client; +static struct proc_dir_entry *goodix_proc_entry; + +static ssize_t goodix_tool_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t goodix_tool_write(struct file *, const char __user *, size_t, loff_t *); +static const struct file_operations gtp_proc_ops = { + .owner = THIS_MODULE, + .read = goodix_tool_read, + .write = goodix_tool_write, +}; + +/* static s32 goodix_tool_write(struct file *filp, + * const char __user *buff, unsigned long len, void *data); + */ +/*static s32 goodix_tool_read( char *page, char + **start, off_t off, int count, int *eof, void *data ); + */ +static s32 (*tool_i2c_read)(u8 *, u16); +static s32 (*tool_i2c_write)(u8 *, u16); + +static s32 DATA_LENGTH = (s32)0; +static s8 IC_TYPE[16] = "GT9XX"; + +static void tool_set_proc_name(char *procname) +{ + snprintf(procname, 20, "gmnode"); /* modify for moto */ +} + +static s32 tool_i2c_read_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + for (i = 0; i < cmd_head.retry; i++) { + ret = gtp_i2c_read(ts->client, buf, len + GTP_ADDR_LENGTH); + if (ret > 0) + break; + } + return ret; +} + +static s32 tool_i2c_write_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + for (i = 0; i < cmd_head.retry; i++) { + ret = gtp_i2c_write(ts->client, buf, len); + if (ret > 0) + break; + } + + return ret; +} + +static s32 tool_i2c_read_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_read_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static s32 tool_i2c_write_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_write_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static void register_i2c_func(void) +{ + /* if (!strncmp(IC_TYPE, "GT818", 5) + * || !strncmp(IC_TYPE, "GT816", 5) + * || !strncmp(IC_TYPE, "GT811", 5) + * || !strncmp(IC_TYPE, "GT818F", 6) + * || !strncmp(IC_TYPE, "GT827", 5) + * || !strncmp(IC_TYPE,"GT828", 5) + * || !strncmp(IC_TYPE, "GT813", 5)) + */ + if (strncmp(IC_TYPE, "GT8110", 6) && + strncmp(IC_TYPE, "GT8105", 6) && + strncmp(IC_TYPE, "GT801", 5) && + strncmp(IC_TYPE, "GT800", 5) && + strncmp(IC_TYPE, "GT801PLUS", 9) && + strncmp(IC_TYPE, "GT811", 5) && + strncmp(IC_TYPE, "GTxxx", 5) && + strncmp(IC_TYPE, "GT9XX", 5)) { + tool_i2c_read = tool_i2c_read_with_extra; + tool_i2c_write = tool_i2c_write_with_extra; + dev_dbg(>_client->dev, "I2C function: with pre and end cmd!"); + } else { + tool_i2c_read = tool_i2c_read_no_extra; + tool_i2c_write = tool_i2c_write_no_extra; + dev_info(>_client->dev, "I2C function: without pre and end cmd!"); + } +} + +static void unregister_i2c_func(void) +{ + tool_i2c_read = NULL; + tool_i2c_write = NULL; + dev_info(>_client->dev, "I2C function: unregister i2c transfer function!"); +} + +s32 init_wr_node(struct i2c_client *client) +{ + s32 i; + + gt_client = client; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 6; + while ((!cmd_head.data) && i) { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (cmd_head.data) + break; + i--; + } + if (i) { + DATA_LENGTH = i * DATA_LENGTH_UINT - GTP_ADDR_LENGTH; + dev_info(>_client->dev, + "Alloc memory size:%d.", DATA_LENGTH); + } else { + dev_err(>_client->dev, "Apply for memory failed."); + return FAIL; + } + + cmd_head.addr_len = 2; + cmd_head.retry = 5; + + register_i2c_func(); + + tool_set_proc_name(procname); + goodix_proc_entry = proc_create(procname, 0666, NULL, >p_proc_ops); + if (!goodix_proc_entry) { + dev_err(>_client->dev, "Couldn't create proc entry!"); + return FAIL; + } + + dev_info(>_client->dev, "Create proc entry success!"); + return SUCCESS; +} + +void uninit_wr_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + unregister_i2c_func(); + remove_proc_entry(procname, NULL); +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + dev_dbg(>_client->dev, + "equal:src:0x%02x dst:0x%02x ret:%d.", + src, dst, (s32)ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* + * Function: + * Comfirm function. + * Input: + * None. + * Output: + * Return write length. + ********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + + memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); + + for (i = 0; i < cmd_head.times; i++) { + if (tool_i2c_read(buf, 1) <= 0) { + dev_err(>_client->dev, "Read flag data failed!"); + return FAIL; + } + if (true == relation(buf[GTP_ADDR_LENGTH], + cmd_head.flag_val, cmd_head.flag_relation)) { + dev_dbg(>_client->dev, "value at flag addr:0x%02x.", + buf[GTP_ADDR_LENGTH]); + dev_dbg(>_client->dev, "flag value:0x%02x.", + cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) { + dev_err(>_client->dev, "Can't get the continue flag!"); + return FAIL; + } + + return SUCCESS; +} + +ssize_t goodix_tool_write(struct file *filp, const char __user *buff, + size_t len, loff_t *off) +{ + s32 ret = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(gt_client); + + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + + dev_dbg(>_client->dev, "[Operation]wr: %02X", cmd_head.wr); + dev_dbg(>_client->dev, + "[Flag]flag: %02X,addr: %02X%02X,value: %02X,relation: %02X", + cmd_head.flag, cmd_head.flag_addr[0], + cmd_head.flag_addr[1], cmd_head.flag_val, + cmd_head.flag_relation); + dev_dbg(>_client->dev, + "[Retry]circle: %d,times: %d,retry: %d, delay: %d", + (s32)cmd_head.circle, + (s32)cmd_head.times, (s32)cmd_head.retry, + (s32)cmd_head.delay); + + if (1 == cmd_head.wr) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], + cmd_head.addr, cmd_head.addr_len); + + GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + + cmd_head.addr_len); + + if (1 == cmd_head.flag) { + if (FAIL == comfirm()) { + dev_err(>_client->dev, + "[WRITE]Comfirm fail!"); + return -EPERM; + } + } else if (2 == cmd_head.flag) { + /*Need interrupt!*/ + } + if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - + cmd_head.addr_len], cmd_head.data_len + + cmd_head.addr_len) <= 0) { + dev_err(>_client->dev, "[WRITE]Write data failed!"); + return -EPERM; + } + + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - + cmd_head.addr_len], + cmd_head.data_len + cmd_head.addr_len); + if (cmd_head.delay) + msleep(cmd_head.delay); + } else if (3 == cmd_head.wr) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + + register_i2c_func(); + } else if (5 == cmd_head.wr) { + /*memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);*/ + } else if (7 == cmd_head.wr) {/*disable irq!*/ + gtp_work_control_enable(i2c_get_clientdata(gt_client), false); + + if (ts->pdata->esd_protect) + gtp_esd_off(ts); + } else if (9 == cmd_head.wr) {/*enable irq!*/ + gtp_work_control_enable(i2c_get_clientdata(gt_client), true); + + if (ts->pdata->esd_protect) + gtp_esd_on(ts); + } else if (17 == cmd_head.wr) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_dbg(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + if (cmd_head.data[GTP_ADDR_LENGTH]) { + dev_info(>_client->dev, "gtp enter rawdiff."); + set_bit(RAW_DATA_MODE, &ts->flags); + } else { + clear_bit(RAW_DATA_MODE, &ts->flags); + dev_info(>_client->dev, "gtp leave rawdiff."); + } + } else if (19 == cmd_head.wr) { + /* add new command: reset guitar */ + gtp_reset_guitar(gt_client, 20); + } +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + else if (11 == cmd_head.wr) {/*Enter update mode!*/ + if (FAIL == gup_enter_update_mode(gt_client)) + return -EPERM; + } else if (13 == cmd_head.wr) {/*Leave update mode!*/ + gup_leave_update_mode(gt_client); + } else if (15 == cmd_head.wr) {/*Update firmware!*/ + show_len = 0; + total_len = 0; + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + memset(cmd_head.data, 0, DATA_LENGTH); + ret = copy_from_user(cmd_head.data, + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_dbg(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + + if (FAIL == gup_update_proc((void *)cmd_head.data)) + return -EPERM; + } +#endif + + return len; +} + +/******************************************************* + * Function: + * Goodix tool read function. + * Input: + * standard proc read function param. + * Output: + * Return read length. + ********************************************************/ +ssize_t goodix_tool_read(struct file *file, char __user *page, + size_t size, loff_t *ppos) +{ + s32 ret = 0; + + if (*ppos) { + /* ADB call again + * dev_dbg(>_client->dev, "[HEAD]wr: %d", cmd_head.wr); + * dev_dbg(>_client->dev, + * "[PARAM]size: %d, *ppos: %d", size, (int)*ppos); + * dev_dbg(>_client->dev, + * "[TOOL_READ]ADB call again, return it."); + */ + *ppos = 0; + return 0; + } + + if (cmd_head.wr % 2) { + return -EPERM; + } else if (!cmd_head.wr) { + u16 len, data_len, loc, addr; + + if (1 == cmd_head.flag) { + if (FAIL == comfirm()) { + dev_err(>_client->dev, "[READ]Comfirm fail!"); + return -EPERM; + } + } else if (2 == cmd_head.flag) { + /*Need interrupt!*/ + } + + if (cmd_head.delay) + msleep(cmd_head.delay); + + data_len = cmd_head.data_len; + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + loc = 0; + + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + cmd_head.data[0] = (addr >> 8) & 0xFF; + cmd_head.data[1] = (addr & 0xFF); + if (tool_i2c_read(cmd_head.data, len) <= 0) { + dev_err(>_client->dev, "[READ]Read data failed!"); + return -EPERM; + } + ret = simple_read_from_buffer(&page[loc], size, ppos, + &cmd_head.data[GTP_ADDR_LENGTH], len); + if (ret < 0) + return ret; + loc += len; + addr += len; + data_len -= len; + } + return cmd_head.data_len; + } else if (2 == cmd_head.wr) { + ret = simple_read_from_buffer(page, size, ppos, + IC_TYPE, sizeof(IC_TYPE)); + return ret; + } +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + else if (4 == cmd_head.wr) { + u8 progress_buf[4]; + + progress_buf[0] = show_len >> 8; + progress_buf[1] = show_len & 0xff; + progress_buf[2] = total_len >> 8; + progress_buf[3] = total_len & 0xff; + + ret = simple_read_from_buffer(page, size, ppos, + progress_buf, 4); + return ret; + } +#endif + else if (6 == cmd_head.wr) { + /*Read error code!*/ + } else if (8 == cmd_head.wr) { /*Read driver version*/ + ret = simple_read_from_buffer(page, size, ppos, + GTP_DRIVER_VERSION, + strlen(GTP_DRIVER_VERSION)); + return ret; + } + + return -EPERM; +} diff --git a/drivers/input/touchscreen/gt9xx_2.8/gt9xx.c b/drivers/input/touchscreen/gt9xx_2.8/gt9xx.c new file mode 100755 index 00000000000..e9aa69f46d0 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2.8/gt9xx.c @@ -0,0 +1,2565 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 2.8.0.1 + * Release Date: 2017/11/24 + */ + +#include +#include +#include +#include +#include "gt9xx.h" + +#define GOODIX_COORDS_ARR_SIZE 4 +#define PROP_NAME_SIZE 24 +#define I2C_MAX_TRANSFER_SIZE 255 +#define GTP_PEN_BUTTON1 BTN_STYLUS +#define GTP_PEN_BUTTON2 BTN_STYLUS2 + +static const char *goodix_ts_name = "goodix-ts"; +static const char *goodix_input_phys = "input/ts"; +struct i2c_client *i2c_connect_client; +static struct proc_dir_entry *gtp_config_proc; + +enum doze { + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +}; + +static enum doze doze_status = DOZE_DISABLED; + +static int gtp_i2c_test(struct i2c_client *client); +static int gtp_enter_doze(struct goodix_ts_data *ts); + +static int gtp_unregister_powermanager(struct goodix_ts_data *ts); +static int gtp_register_powermanager(struct goodix_ts_data *ts); + +static int gtp_esd_init(struct goodix_ts_data *ts); +static void gtp_esd_check_func(struct work_struct *); +static int gtp_init_ext_watchdog(struct i2c_client *client); + +/* + * return: 2 - ok, < 0 - i2c transfer error + */ +int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len) +{ + unsigned int transfer_length = 0; + unsigned int pos = 0, address = (buf[0] << 8) + buf[1]; + unsigned char get_buf[64], addr_buf[2]; + int retry, r = 2; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = !I2C_M_RD, + .buf = &addr_buf[0], + .len = GTP_ADDR_LENGTH, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + } + }; + + len -= GTP_ADDR_LENGTH; + if (likely(len < sizeof(get_buf))) { + /* code optimize, use stack memory */ + msgs[1].buf = &get_buf[0]; + } else { + msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE + ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); + if (!msgs[1].buf) + return -ENOMEM; + } + + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE)) + transfer_length = I2C_MAX_TRANSFER_SIZE; + else + transfer_length = len - pos; + msgs[0].buf[0] = (address >> 8) & 0xFF; + msgs[0].buf[1] = address & 0xFF; + msgs[1].len = transfer_length; + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, msgs, 2) == 2)) { + memcpy(&buf[2 + pos], msgs[1].buf, transfer_length); + pos += transfer_length; + address += transfer_length; + break; + } + dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n", + retry + 1, address); + usleep_range(2000, 2100); + } + if (unlikely(retry == RETRY_MAX_TIMES)) { + dev_err(&client->dev, + "I2c read failed,dev:%02x,reg:%04x,size:%u\n", + client->addr, address, len); + r = -EAGAIN; + goto read_exit; + } + } +read_exit: + if (len >= sizeof(get_buf)) + kfree(msgs[1].buf); + return r; +} + +/******************************************************* + * Function: + * Write data to the i2c slave device. + * Input: + * client: i2c device. + * buf[0~1]: write start address. + * buf[2~len-1]: data buffer + * len: GTP_ADDR_LENGTH + write bytes count + * Output: + * numbers of i2c_msgs to transfer: + * 1: succeed, otherwise: failed + *********************************************************/ +int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len) + +{ + unsigned int pos = 0, transfer_length = 0; + unsigned int address = (buf[0] << 8) + buf[1]; + unsigned char put_buf[64]; + int retry, r = 1; + struct i2c_msg msg = { + .addr = client->addr, + .flags = !I2C_M_RD, + }; + + if (likely(len < sizeof(put_buf))) { + /* code optimize,use stack memory*/ + msg.buf = &put_buf[0]; + } else { + msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE + ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); + if (!msg.buf) + return -ENOMEM; + } + + len -= GTP_ADDR_LENGTH; + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH)) + transfer_length = I2C_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH; + else + transfer_length = len - pos; + msg.buf[0] = (unsigned char)((address >> 8) & 0xFF); + msg.buf[1] = (unsigned char)(address & 0xFF); + msg.len = transfer_length + 2; + memcpy(&msg.buf[2], &buf[2 + pos], transfer_length); + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, &msg, 1) == 1)) { + pos += transfer_length; + address += transfer_length; + break; + } + dev_dbg(&client->dev, "I2C write retry[%d]\n", retry + 1); + usleep_range(2000, 2100); + } + if (unlikely(retry == RETRY_MAX_TIMES)) { + dev_err(&client->dev, + "I2c write failed,dev:%02x,reg:%04x,size:%u\n", + client->addr, address, len); + r = -EAGAIN; + goto write_exit; + } + } +write_exit: + if (len + GTP_ADDR_LENGTH >= sizeof(put_buf)) + kfree(msg.buf); + return r; +} + +/******************************************************* + * Function: + * i2c read twice, compare the results + * Input: + * client: i2c device + * addr: operate address + * rxbuf: read data to store, if compare successful + * len: bytes to read + * Output: + * FAIL: read failed + * SUCCESS: read successful + *********************************************************/ +s32 gtp_i2c_read_dbl_check(struct i2c_client *client, + u16 addr, u8 *rxbuf, int len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + u8 retry = 0; + + if (len + 2 > sizeof(buf)) { + dev_warn(&client->dev, + "%s, only support length less then %zu\n", + __func__, sizeof(buf) - 2); + return FAIL; + } + while (retry++ < 3) { + memset(buf, 0xAA, 16); + buf[0] = (u8)(addr >> 8); + buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, buf, len + 2); + + memset(confirm_buf, 0xAB, 16); + confirm_buf[0] = (u8)(addr >> 8); + confirm_buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, confirm_buf, len + 2); + + if (!memcmp(buf, confirm_buf, len + 2)) { + memcpy(rxbuf, confirm_buf + 2, len); + return SUCCESS; + } + } + dev_err(&client->dev, + "I2C read 0x%04X, %d bytes, double check failed!\n", + addr, len); + + return FAIL; +} + +/******************************************************* + * Function: + * Send config. + * Input: + * client: i2c device. + * Output: + * result of i2c write operation. + * 1: succeed, otherwise + * 0: Not executed + * < 0: failed + *********************************************************/ +s32 gtp_send_cfg(struct i2c_client *client) +{ + s32 ret, i; + u8 check_sum; + s32 retry = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + struct goodix_config_data *cfg = &ts->pdata->config; + + if (!cfg->length || !ts->pdata->driver_send_cfg) { + dev_info(&ts->client->dev, + "No config data or error occurred in panel_init\n"); + return 0; + } + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < cfg->length; i++) + check_sum += cfg->data[i]; + cfg->data[cfg->length] = (~check_sum) + 1; + + dev_info(&ts->client->dev, "Driver send config\n"); + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + ret = gtp_i2c_write(client, cfg->data, + GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); + if (ret > 0) + break; + } + + return ret; +} + +/******************************************************* + * Function: + * Control enable or disable of work thread. + * Input: + * ts: goodix i2c_client private data + * enable: enable var. + *********************************************************/ +void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable) +{ + if (enable) { + set_bit(WORK_THREAD_ENABLED, &ts->flags); + dev_dbg(&ts->client->dev, "Input report thread enabled!\n"); + } else { + clear_bit(WORK_THREAD_ENABLED, &ts->flags); + dev_dbg(&ts->client->dev, "Input report thread disabled!\n"); + } +} + +static int gtp_gesture_handler(struct goodix_ts_data *ts) +{ + u8 doze_buf[3] = {GTP_REG_DOZE_BUF >> 8, GTP_REG_DOZE_BUF & 0xFF}; + int ret; + + ret = gtp_i2c_read(ts->client, doze_buf, 3); + if (ret < 0) { + dev_err(&ts->client->dev, "Failed read doze buf"); + return -EINVAL; + } + + dev_dbg(&ts->client->dev, "0x814B = 0x%02X", doze_buf[2]); + if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') || + (doze_buf[2] == 'c') || (doze_buf[2] == 'd') || + (doze_buf[2] == 'e') || (doze_buf[2] == 'g') || + (doze_buf[2] == 'h') || (doze_buf[2] == 'm') || + (doze_buf[2] == 'o') || (doze_buf[2] == 'q') || + (doze_buf[2] == 's') || (doze_buf[2] == 'v') || + (doze_buf[2] == 'w') || (doze_buf[2] == 'y') || + (doze_buf[2] == 'z') || (doze_buf[2] == 0x5E) || + (doze_buf[2] == 0xAA) || (doze_buf[2] == 0xAB) || + (doze_buf[2] == 0xBA) || (doze_buf[2] == 0xBB) || + (doze_buf[2] == 0xCC)) { + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + } else { + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + gtp_enter_doze(ts); + } + return 0; +} + +/* + * return touch state register value + * pen event id fixed with 9 and set tool type TOOL_PEN + * + */ +static u8 gtp_get_points(struct goodix_ts_data *ts, + struct goodix_point_t *points, + u8 *key_value) +{ + int ret; + int i; + u8 *coor_data = NULL; + u8 finger_state = 0; + u8 touch_num = 0; + u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, + GTP_READ_COOR_ADDR & 0xFF, 0 }; + u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH_ID + 1] = { + GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF }; + + ret = gtp_i2c_read(ts->client, point_data, 12); + if (ret < 0) { + dev_err(&ts->client->dev, + "I2C transfer error. errno:%d\n ", ret); + return 0; + } + finger_state = point_data[GTP_ADDR_LENGTH]; + if (finger_state == 0x00) + return 0; + + touch_num = finger_state & 0x0f; + if ((finger_state & MASK_BIT_8) == 0 || + touch_num > ts->pdata->max_touch_id) { + dev_err(&ts->client->dev, + "Invalid touch state: 0x%x", finger_state); + finger_state = 0; + goto exit_get_point; + } + + if (touch_num > 1) { + u8 buf[8 * GTP_MAX_TOUCH_ID] = { + (GTP_READ_COOR_ADDR + 10) >> 8, + (GTP_READ_COOR_ADDR + 10) & 0xff }; + + ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); + if (ret < 0) { + dev_err(&ts->client->dev, "I2C error. %d\n", ret); + finger_state = 0; + goto exit_get_point; + } + memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); + } + + /* panel have touch key */ + /* 0x20_UPKEY 0X10_DOWNKEY 0X40_ALLKEYDOWN */ + *key_value = point_data[3 + 8 * touch_num]; + + memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID); + for (i = 0; i < touch_num; i++) { + coor_data = &point_data[i * 8 + 3]; + points[i].id = coor_data[0]; + points[i].x = coor_data[1] | (coor_data[2] << 8); + points[i].y = coor_data[3] | (coor_data[4] << 8); + points[i].w = coor_data[5] | (coor_data[6] << 8); + /* if pen hover points[].p must set to zero */ + points[i].p = coor_data[5] | (coor_data[6] << 8); + + if (ts->pdata->swap_x2y) + GTP_SWAP(points[i].x, points[i].y); + + dev_dbg(&ts->client->dev, "[%d][%d %d %d]\n", + points[i].id, points[i].x, points[i].y, points[i].p); + + /* pen device coordinate */ + if (points[i].id & 0x80) { + points[i].tool_type = GTP_TOOL_PEN; + points[i].id = 10; + if (ts->pdata->pen_suppress_finger) { + points[0] = points[i]; + memset(++points, 0, sizeof(*points) * (GTP_MAX_TOUCH_ID - 1)); + finger_state &= 0xf0; + finger_state |= 0x01; + break; + } + } else { + points[i].tool_type = GTP_TOOL_FINGER; + } + } + +exit_get_point: + if (!test_bit(RAW_DATA_MODE, &ts->flags)) { + ret = gtp_i2c_write(ts->client, end_cmd, 3); + if (ret < 0) + dev_info(&ts->client->dev, "I2C write end_cmd error!"); + } + return finger_state; +} + +static void gtp_type_a_report(struct goodix_ts_data *ts, u8 touch_num, + struct goodix_point_t *points) +{ + int i; + u16 cur_touch = 0; + static u16 pre_touch; + static u8 pre_pen_id; + + if (touch_num) + input_report_key(ts->input_dev, BTN_TOUCH, 1); + + for (i = 0; i < ts->pdata->max_touch_id; i++) { + if (touch_num && i == points->id) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, points->id); + + if (points->tool_type == GTP_TOOL_PEN) { + input_report_key(ts->input_dev, BTN_TOOL_PEN, true); + pre_pen_id = points->id; + } else { + input_report_key(ts->input_dev, BTN_TOOL_FINGER, true); + } + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + points->x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + points->y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + points->w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + points->p); + input_mt_sync(ts->input_dev); + + cur_touch |= 0x01 << points->id; + points++; + } else if (pre_touch & 0x01 << i) { + if (pre_pen_id == i) { + input_report_key(ts->input_dev, BTN_TOOL_PEN, false); + /* valid id will < 10, so id to 0xff to indicate a invalid state */ + pre_pen_id = 0xff; + } else { + input_report_key(ts->input_dev, BTN_TOOL_FINGER, false); + } + } + } + + pre_touch = cur_touch; + if (!pre_touch) { + input_mt_sync(ts->input_dev); + input_report_key(ts->input_dev, BTN_TOUCH, 0); + } + input_sync(ts->input_dev); +} + +static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num, + struct goodix_point_t *points) +{ + int i; + u16 cur_touch = 0; + static u16 pre_touch; + static u8 pre_pen_id; + + for (i = 0; i < ts->pdata->max_touch_id; i++) { + if (touch_num && i == points->id) { + input_mt_slot(ts->input_dev, points->id); + + if (points->tool_type == GTP_TOOL_PEN) { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_PEN, true); + pre_pen_id = points->id; + } else { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, true); + } + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + points->x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + points->y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + points->w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + points->p); + + cur_touch |= 0x01 << points->id; + points++; + } else if (pre_touch & 0x01 << i) { + input_mt_slot(ts->input_dev, i); + if (pre_pen_id == i) { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_PEN, false); + /* valid id will < 10, so set id to 0xff to + * indicate a invalid state + */ + pre_pen_id = 0xff; + } else { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, false); + } + } + } + + pre_touch = cur_touch; + /* report BTN_TOUCH event */ + input_mt_sync_frame(ts->input_dev); + input_sync(ts->input_dev); +} + +/******************************************************* + * Function: + * Goodix touchscreen sensor report function + * Input: + * ts: goodix tp private data + * Output: + * None. + *********************************************************/ +static void gtp_work_func(struct goodix_ts_data *ts) +{ + u8 point_state = 0; + u8 key_value = 0; + s32 i = 0; + s32 ret = -1; + static u8 pre_key; + struct goodix_point_t points[GTP_MAX_TOUCH_ID]; + + if (test_bit(PANEL_RESETTING, &ts->flags)) + return; + if (!test_bit(WORK_THREAD_ENABLED, &ts->flags)) + return; + + /* gesture event */ + if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { + ret = gtp_gesture_handler(ts); + if (ret) + dev_err(&ts->client->dev, + "Failed handler gesture event %d\n", ret); + return; + } + + point_state = gtp_get_points(ts, points, &key_value); + if (!point_state) { + dev_dbg(&ts->client->dev, "Invalid finger points\n"); + return; + } + + /* touch key event */ + if (key_value & 0xf0 || pre_key & 0xf0) { + /* pen button */ + switch (key_value) { + case 0x40: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); + break; + case 0x10: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); + dev_dbg(&ts->client->dev, "pen button1 down\n"); + break; + case 0x20: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); + break; + default: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); + dev_dbg(&ts->client->dev, "button1 up\n"); + break; + } + input_sync(ts->input_dev); + pre_key = key_value; + } else if (key_value & 0x0f || pre_key & 0x0f) { + /* panel key */ + for (i = 0; i < ts->pdata->key_nums; i++) { + if ((pre_key | key_value) & (0x01 << i)) + input_report_key(ts->input_dev, + ts->pdata->key_map[i], + key_value & (0x01 << i)); + } + input_sync(ts->input_dev); + pre_key = key_value; + } + + if (!ts->pdata->type_a_report) + gtp_mt_slot_report(ts, point_state & 0x0f, points); + else + gtp_type_a_report(ts, point_state & 0x0f, points); +} + +/******************************************************* + * Function: + * Timer interrupt service routine for polling mode. + * Input: + * timer: timer struct pointer + * Output: + * Timer work mode. + * HRTIMER_NORESTART: + * no restart mode + *********************************************************/ +static enum hrtimer_restart gtp_timer_handler(struct hrtimer *timer) +{ + struct goodix_ts_data *ts = + container_of(timer, struct goodix_ts_data, timer); + + gtp_work_func(ts); + hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), + HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} + +static irqreturn_t gtp_irq_handler(int irq, void *dev_id) +{ + struct goodix_ts_data *ts = dev_id; + + gtp_work_func(ts); + return IRQ_HANDLED; +} + +void gtp_int_output(struct goodix_ts_data *ts, int level) +{ + if (!ts->pdata->int_sync) + return; + + if (level == 0) { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_out_low); + else if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_output(ts->pdata->irq_gpio, 0); + else + dev_err(&ts->client->dev, + "Failed set int pin output low\n"); + } else { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_out_high); + else if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_output(ts->pdata->irq_gpio, 1); + else + dev_err(&ts->client->dev, + "Failed set int pin output high\n"); + } +} + +void gtp_int_sync(struct goodix_ts_data *ts, s32 ms) +{ + if (!ts->pdata->int_sync) + return; + + if (ts->pinctrl.pinctrl) { + gtp_int_output(ts, 0); + msleep(ms); + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_input); + } else if (gpio_is_valid(ts->pdata->irq_gpio)) { + gpio_direction_output(ts->pdata->irq_gpio, 0); + msleep(ms); + gpio_direction_input(ts->pdata->irq_gpio); + } else { + dev_err(&ts->client->dev, "Failed sync int pin\n"); + } +} + +/******************************************************* + * Function: + * Reset chip. Control the reset pin and int-pin(if + * defined), + * Input: + * client: i2c device. + * ms: reset time in millisecond + * Output: + * None. + *******************************************************/ +void gtp_reset_guitar(struct i2c_client *client, s32 ms) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + dev_info(&client->dev, "Guitar reset"); + set_bit(PANEL_RESETTING, &ts->flags); + if (!gpio_is_valid(ts->pdata->rst_gpio)) { + dev_warn(&client->dev, "reset failed no valid reset gpio"); + return; + } + + gpio_direction_output(ts->pdata->rst_gpio, 0); + usleep_range(ms * 1000, ms * 1000 + 100); /* T2: > 10ms */ + + gtp_int_output(ts, client->addr == 0x14); + + usleep_range(2000, 3000); /* T3: > 100us (2ms)*/ + gpio_direction_output(ts->pdata->rst_gpio, 1); + + usleep_range(6000, 7000); /* T4: > 5ms */ + gpio_direction_input(ts->pdata->rst_gpio); + + gtp_int_sync(ts, 50); + if (ts->pdata->esd_protect) + gtp_init_ext_watchdog(client); + + clear_bit(PANEL_RESETTING, &ts->flags); +} + +/******************************************************* + * Function: + * Enter doze mode for sliding wakeup. + * Input: + * ts: goodix tp private data + * Output: + * 1: succeed, otherwise failed + *******************************************************/ +static int gtp_enter_doze(struct goodix_ts_data *ts) +{ + int ret = -1; + int retry = 0; + u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), + (u8)GTP_REG_COMMAND, 8 }; + + /* resend doze command + * if (test_and_set_bit(DOZE_MODE, &ts->flags)) { + * dev_info(&ts->client->dev, "Already in doze mode\n"); + * return SUCCESS; + * } + */ + set_bit(DOZE_MODE, &ts->flags); + dev_dbg(&ts->client->dev, "Entering gesture mode."); + while (retry++ < 5) { + i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8); + i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret < 0) { + dev_dbg(&ts->client->dev, + "failed to set doze flag into 0x8046, %d\n", + retry); + continue; + } + i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8); + i2c_control_buf[1] = (u8)GTP_REG_COMMAND; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) { + dev_dbg(&ts->client->dev, "Gesture mode enabled\n"); + return ret; + } + usleep_range(10000, 11000); + } + + dev_err(&ts->client->dev, "Failed enter doze mode\n"); + clear_bit(DOZE_MODE, &ts->flags); + return ret; +} + +static s8 gtp_enter_sleep(struct goodix_ts_data *ts) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), + (u8)GTP_REG_COMMAND, 5 }; + + gtp_int_output(ts, 0); + usleep_range(5000, 6000); + + while (retry++ < 5) { + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) { + dev_info(&ts->client->dev, "Enter sleep mode\n"); + + return ret; + } + usleep_range(10000, 11000); + } + dev_err(&ts->client->dev, "Failed send sleep cmd\n"); + + return ret; +} + +static int gtp_wakeup_sleep(struct goodix_ts_data *ts) +{ + u8 retry = 0; + int ret = -1; + + while (retry++ < 10) { + gtp_int_output(ts, 1); + usleep_range(5000, 6000); + + ret = gtp_i2c_test(ts->client); + if (!ret) { + dev_dbg(&ts->client->dev, "Success wakeup sleep\n"); + + gtp_int_sync(ts, 25); + if (ts->pdata->esd_protect) + gtp_init_ext_watchdog(ts->client); + + return ret; + } + gtp_reset_guitar(ts->client, 20); + } + + dev_err(&ts->client->dev, "Failed wakeup from sleep mode\n"); + return -EINVAL; +} + +static int gtp_find_valid_cfg_data(struct goodix_ts_data *ts) +{ + int ret = -1; + u8 sensor_id = 0; + struct goodix_config_data *cfg = &ts->pdata->config; + + /* if defined CONFIG_OF, parse config data from dtsi + * else parse config data form header file. + */ + cfg->length = 0; + +#ifndef CONFIG_OF + u8 cfg_info_group0[] = CTP_CFG_GROUP0; + u8 cfg_info_group1[] = CTP_CFG_GROUP1; + u8 cfg_info_group2[] = CTP_CFG_GROUP2; + u8 cfg_info_group3[] = CTP_CFG_GROUP3; + u8 cfg_info_group4[] = CTP_CFG_GROUP4; + u8 cfg_info_group5[] = CTP_CFG_GROUP5; + + u8 *send_cfg_buf[] = { cfg_info_group0, cfg_info_group1, + cfg_info_group2, cfg_info_group3, + cfg_info_group4, cfg_info_group5 }; + u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0), + CFG_GROUP_LEN(cfg_info_group1), + CFG_GROUP_LEN(cfg_info_group2), + CFG_GROUP_LEN(cfg_info_group3), + CFG_GROUP_LEN(cfg_info_group4), + CFG_GROUP_LEN(cfg_info_group5)}; + + dev_dbg(&ts->client->dev, + "Config Groups\' Lengths: %d, %d, %d, %d, %d, %d", + cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], + cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]); +#endif + + /* read sensor id */ + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, + &sensor_id, 1); + if (SUCCESS != ret || sensor_id >= 0x06) { + dev_err(&ts->client->dev, + "Failed get valid sensor_id(0x%02X), No Config Sent\n", + sensor_id); + return -EINVAL; + } + + dev_dbg(&ts->client->dev, "Sensor_ID: %d", sensor_id); + /* parse config data */ +#ifdef CONFIG_OF + dev_dbg(&ts->client->dev, "Get config data from device tree\n"); + ret = gtp_parse_dt_cfg(&ts->client->dev, + &cfg->data[GTP_ADDR_LENGTH], + &cfg->length, sensor_id); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to parse config data form device tree\n"); + cfg->length = 0; + return -EPERM; + } +#else + dev_dbg(&ts->client->dev, "Get config data from header file\n"); + if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && + (!cfg_info_len[3]) && (!cfg_info_len[4]) && + (!cfg_info_len[5])) { + sensor_id = 0; + } + cfg->length = cfg_info_len[sensor_id]; + memset(&cfg->data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&cfg->data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], + cfg->length); +#endif + + if (cfg->length < GTP_CONFIG_MIN_LENGTH) { + dev_err(&ts->client->dev, + "Failed get valid config data with sensor id %d\n", + sensor_id); + cfg->length = 0; + return -EPERM; + } + + dev_info(&ts->client->dev, "Config group%d used,length: %d\n", + sensor_id, cfg->length); + + return 0; +} + +/******************************************************* + * Function: + * Get valid config data from dts or .h file. + * Read firmware version info and judge firmware + * working state + * Input: + * ts: goodix private data + * Output: + * Executive outcomes. + * 0: succeed, otherwise: failed + *******************************************************/ +static s32 gtp_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = -1; + u8 opr_buf[16] = {0}; + u8 drv_cfg_version = 0; + u8 flash_cfg_version = 0; + struct goodix_config_data *cfg = &ts->pdata->config; + + if (!ts->pdata->driver_send_cfg) { + dev_info(&ts->client->dev, "Driver set not send config\n"); + cfg->length = GTP_CONFIG_MAX_LENGTH; + ret = gtp_i2c_read(ts->client, + cfg->data, cfg->length + + GTP_ADDR_LENGTH); + if (ret < 0) + dev_err(&ts->client->dev, "Read origin Config Failed\n"); + + return 0; + } + + gtp_find_valid_cfg_data(ts); + + /* check firmware */ + ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); + if (SUCCESS == ret) { + if (opr_buf[0] != 0xBE) { + set_bit(FW_ERROR, &ts->flags); + dev_err(&ts->client->dev, + "Firmware error, no config sent!\n"); + return -EINVAL; + } + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + dev_dbg(&ts->client->dev, + "Config Version: %d; IC Config Version: %d\n", + cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); + flash_cfg_version = opr_buf[0]; + drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; + + if (flash_cfg_version < 90 && + flash_cfg_version > drv_cfg_version) + cfg->data[GTP_ADDR_LENGTH] = 0x00; + } else { + dev_err(&ts->client->dev, + "Failed to get ic config version!No config sent\n"); + return -EPERM; + } + + ret = gtp_send_cfg(ts->client); + if (ret < 0) + dev_err(&ts->client->dev, "Send config error\n"); + else + usleep_range(10000, 11000); /* 10 ms */ + + /* restore config version */ + cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; + + return 0; +} + +static ssize_t gtp_config_read_proc(struct file *file, char __user *page, + size_t size, loff_t *ppos) +{ + int i, ret; + char *ptr; + size_t data_len = 0; + char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = { + (u8)(GTP_REG_CONFIG_DATA >> 8), + (u8)GTP_REG_CONFIG_DATA }; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + struct goodix_config_data *cfg = &ts->pdata->config; + + ptr = kzalloc(4096, GFP_KERNEL); + if (!ptr) { + dev_err(&ts->client->dev, "Failed alloc memory for config\n"); + return -ENOMEM; + } + + data_len += snprintf(ptr + data_len, 4096 - data_len, + "====init value====\n"); + for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "0x%02X ", cfg->data[i + 2]); + + if (i % 8 == 7) + data_len += snprintf(ptr + data_len, + 4096 - data_len, "\n"); + } + data_len += snprintf(ptr + data_len, 4096 - data_len, "\n"); + + data_len += snprintf(ptr + data_len, 4096 - data_len, + "====real value====\n"); + ret = gtp_i2c_read(i2c_connect_client, temp_data, + GTP_CONFIG_MAX_LENGTH + 2); + if (ret < 0) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "Failed read real config data\n"); + } else { + for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "0x%02X ", temp_data[i + 2]); + + if (i % 8 == 7) + data_len += snprintf(ptr + data_len, + 4096 - data_len, "\n"); + } + } + + data_len = simple_read_from_buffer(page, size, ppos, ptr, data_len); + kfree(ptr); + ptr = NULL; + return data_len; +} + +static u8 ascii2hex(u8 a) +{ + s8 value = 0; + + if (a >= '0' && a <= '9') + value = a - '0'; + else if (a >= 'A' && a <= 'F') + value = a - 'A' + 0x0A; + else if (a >= 'a' && a <= 'f') + value = a - 'a' + 0x0A; + else + value = 0xff; + + return value; +} + +int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf) +{ + int i, ret; + int cfg_len = 0; + u8 high, low; + + for (i = 0; i < src_len;) { + if (src_buf[i] == ' ' || src_buf[i] == '\r' || + src_buf[i] == '\n') { + i++; + continue; + } + + if ((src_buf[i] == '0') && ((src_buf[i + 1] == 'x') || + (src_buf[i + 1] == 'X'))) { + high = ascii2hex(src_buf[i + 2]); + low = ascii2hex(src_buf[i + 3]); + + if ((high == 0xFF) || (low == 0xFF)) { + ret = -1; + goto convert_failed; + } + + if (cfg_len < GTP_CONFIG_MAX_LENGTH) { + dst_buf[cfg_len++] = (high << 4) + low; + i += 5; + } else { + ret = -2; + goto convert_failed; + } + } else { + ret = -3; + goto convert_failed; + } + } + return cfg_len; + +convert_failed: + return ret; +} + +static ssize_t gtp_config_write_proc(struct file *filp, + const char __user *buffer, + size_t count, loff_t *off) +{ + u8 *temp_buf; + u8 *file_config; + int file_cfg_len; + s32 ret = 0, i; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + dev_dbg(&ts->client->dev, "write count %zu\n", count); + + if (count > PAGE_SIZE) { + dev_err(&ts->client->dev, "config to long %zu\n", count); + return -EFAULT; + } + + temp_buf = kzalloc(count, GFP_KERNEL); + if (!temp_buf) { + dev_err(&ts->client->dev, "failed alloc temp memory"); + return -ENOMEM; + } + + file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!file_config) { + dev_err(&ts->client->dev, "failed alloc config memory"); + kfree(temp_buf); + return -ENOMEM; + } + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + + if (copy_from_user(temp_buf, buffer, count)) { + dev_err(&ts->client->dev, "Failed copy from user\n"); + ret = -EFAULT; + goto send_cfg_err; + } + + file_cfg_len = gtp_ascii_to_array(temp_buf, (int)count, + &file_config[GTP_ADDR_LENGTH]); + if (file_cfg_len < 0) { + dev_err(&ts->client->dev, "failed covert ascii to hex"); + ret = -EFAULT; + goto send_cfg_err; + } + + GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); + + i = 0; + while (i++ < 5) { + ret = gtp_i2c_write(ts->client, file_config, file_cfg_len + 2); + if (ret > 0) { + dev_info(&ts->client->dev, "Send config SUCCESS."); + break; + } + dev_err(&ts->client->dev, "Send config i2c error."); + ret = -EFAULT; + goto send_cfg_err; + } + + ret = count; +send_cfg_err: + kfree(temp_buf); + kfree(file_config); + return ret; +} + +static const struct file_operations config_proc_ops = { + .owner = THIS_MODULE, + .read = gtp_config_read_proc, + .write = gtp_config_write_proc, +}; + +static ssize_t gtp_workmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t data_len = 0; + struct goodix_ts_data *data = dev_get_drvdata(dev); + + if (test_bit(DOZE_MODE, &data->flags)) + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "doze_mode"); + else if (test_bit(SLEEP_MODE, &data->flags)) + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "sleep_mode"); + else + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "normal_mode"); + + return data_len; +} +static DEVICE_ATTR(workmode, 0444, gtp_workmode_show, NULL); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE +#define FW_NAME_MAX_LEN 80 +static ssize_t gtp_dofwupdate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + char update_file_name[FW_NAME_MAX_LEN]; + int retval; + + if (count > FW_NAME_MAX_LEN) { + dev_info(&ts->client->dev, "FW filename is too long\n"); + retval = -EINVAL; + goto exit; + } + + strlcpy(update_file_name, buf, count); + + ts->force_update = true; + retval = gup_update_proc(update_file_name); + if (retval == FAIL) + dev_err(&ts->client->dev, "Fail to update GTP firmware.\n"); + else + dev_info(&ts->client->dev, "Update success\n"); + + return count; + +exit: + return retval; +} +static DEVICE_ATTR(dofwupdate, 0664, NULL, gtp_dofwupdate_store); +#endif + +static ssize_t gtp_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + struct goodix_fw_info *fw_info = &data->fw_info; + + return scnprintf(buf, PAGE_SIZE, "GT%s_%x_%d\n", + fw_info->pid, fw_info->version, fw_info->sensor_id); +} +static DEVICE_ATTR(productinfo, 0444, gtp_productinfo_show, NULL); + +static ssize_t gtp_drv_irq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long value = 0; + int err = 0; + struct goodix_ts_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &value); + if (err < 0) { + dev_err(dev, "Failed to convert value\n"); + return -EINVAL; + } + + switch (value) { + case 0: + /* Disable irq */ + gtp_work_control_enable(data, false); + break; + case 1: + /* Enable irq */ + gtp_work_control_enable(data, true); + break; + default: + dev_err(dev, "Invalid value\n"); + return -EINVAL; + } + + return count; +} + +static ssize_t gtp_drv_irq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + test_bit(WORK_THREAD_ENABLED, &data->flags) + ? "enabled" : "disabled"); +} +static DEVICE_ATTR(drv_irq, 0664, gtp_drv_irq_show, gtp_drv_irq_store); + +static ssize_t gtp_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + + if ('1' != buf[0]) { + dev_err(dev, "Invalid argument for reset\n"); + return -EINVAL; + } + + gtp_reset_guitar(data->client, 20); + + return count; +} +static DEVICE_ATTR(reset, 0220, NULL, gtp_reset_store); + +static struct attribute *gtp_attrs[] = { + &dev_attr_workmode.attr, + &dev_attr_productinfo.attr, + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + &dev_attr_dofwupdate.attr, +#endif + + &dev_attr_drv_irq.attr, + &dev_attr_reset.attr, + NULL +}; + +static const struct attribute_group gtp_attr_group = { + .attrs = gtp_attrs, +}; + +static int gtp_create_file(struct goodix_ts_data *ts) +{ + int ret; + struct i2c_client *client = ts->client; + + /* Create proc file system */ + gtp_config_proc = NULL; + gtp_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0664, + NULL, &config_proc_ops); + if (!gtp_config_proc) + dev_err(&client->dev, "create_proc_entry %s failed\n", + GT91XX_CONFIG_PROC_FILE); + else + dev_info(&client->dev, "create proc entry %s success\n", + GT91XX_CONFIG_PROC_FILE); + + ret = sysfs_create_group(&client->dev.kobj, >p_attr_group); + if (ret) { + dev_err(&client->dev, "Failure create sysfs group %d\n", ret); + /*TODO: debug change */ + goto exit_free_config_proc; + } + return 0; + +exit_free_config_proc: + remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); + return -ENODEV; +} + +s32 gtp_get_fw_info(struct i2c_client *client, struct goodix_fw_info *fw_info) +{ + s32 ret = -1; + u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; + + ret = gtp_i2c_read(client, buf, sizeof(buf)); + if (ret < 0) { + dev_err(&client->dev, "Failed read fw_info\n"); + return ret; + } + + /* product id */ + memset(fw_info, 0, sizeof(*fw_info)); + + if (buf[5] == 0x00) { + memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 3); + dev_info(&client->dev, "IC Version: %c%c%c_%02X%02X\n", + buf[2], buf[3], buf[4], buf[7], buf[6]); + } else { + memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 4); + dev_info(&client->dev, "IC Version: %c%c%c%c_%02X%02X\n", + buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); + } + + /* current firmware version */ + fw_info->version = (buf[7] << 8) | buf[6]; + + /* read sensor id */ + fw_info->sensor_id = 0xff; + ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID, + &fw_info->sensor_id, 1); + if (SUCCESS != ret || fw_info->sensor_id >= 0x06) { + dev_err(&client->dev, + "Failed get valid sensor_id(0x%02X), No Config Sent\n", + fw_info->sensor_id); + + fw_info->sensor_id = 0xff; + } + + return ret; +} + +static int gtp_i2c_test(struct i2c_client *client) +{ + u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + u8 retry = 0; + int ret = -1; + + while (retry++ < 3) { + ret = gtp_i2c_read(client, test, 3); + if (ret == 2) + return 0; + + dev_err(&client->dev, "GTP i2c test failed time %d\n", retry); + usleep_range(10000, 11000); /* 10 ms */ + } + + return -EAGAIN; +} + +static int gtp_pinctrl_init(struct goodix_ts_data *ts) +{ + struct goodix_pinctrl *pinctrl = &ts->pinctrl; + + pinctrl->pinctrl = devm_pinctrl_get(&ts->client->dev); + if (IS_ERR_OR_NULL(pinctrl->pinctrl)) { + dev_info(&ts->client->dev, "No pinctrl found\n"); + pinctrl->pinctrl = NULL; + return 0; + } + + pinctrl->default_sta = pinctrl_lookup_state(pinctrl->pinctrl, + "default"); + if (IS_ERR_OR_NULL(pinctrl->default_sta)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:default state\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl, + "int-output-high"); + if (IS_ERR_OR_NULL(pinctrl->int_out_high)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:output_high\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl, + "int-output-low"); + if (IS_ERR_OR_NULL(pinctrl->int_out_low)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:output_low\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_input = pinctrl_lookup_state(pinctrl->pinctrl, + "int-input"); + if (IS_ERR_OR_NULL(pinctrl->int_input)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:int-input\n"); + goto exit_pinctrl_init; + } + dev_info(&ts->client->dev, "Success init pinctrl\n"); + return 0; +exit_pinctrl_init: + devm_pinctrl_put(pinctrl->pinctrl); + pinctrl->pinctrl = NULL; + pinctrl->int_out_high = NULL; + pinctrl->int_out_low = NULL; + pinctrl->int_input = NULL; + return 0; +} + +static void gtp_pinctrl_deinit(struct goodix_ts_data *ts) +{ + if (ts->pinctrl.pinctrl) + devm_pinctrl_put(ts->pinctrl.pinctrl); +} + +static int gtp_request_io_port(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (gpio_is_valid(ts->pdata->irq_gpio)) { + ret = gpio_request(ts->pdata->irq_gpio, "goodix_ts_int"); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request GPIO:%d, ERRNO:%d\n", + (s32)ts->pdata->irq_gpio, ret); + return -ENODEV; + } + + gpio_direction_input(ts->pdata->irq_gpio); + dev_info(&ts->client->dev, "Success request irq-gpio\n"); + } + + if (gpio_is_valid(ts->pdata->rst_gpio)) { + ret = gpio_request(ts->pdata->rst_gpio, "goodix_ts_rst"); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request GPIO:%d, ERRNO:%d\n", + (s32)ts->pdata->rst_gpio, ret); + + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); + + return -ENODEV; + } + + gpio_direction_input(ts->pdata->rst_gpio); + dev_info(&ts->client->dev, "Success request rst-gpio\n"); + } + + return 0; +} + +/******************************************************* + * Function: + * Request interrupt if define irq pin, else use hrtimer + * as interrupt source + * Input: + * ts: private data. + * Output: + * Executive outcomes. + * 0: succeed, -1: failed. + *******************************************************/ +static int gtp_request_irq(struct goodix_ts_data *ts) +{ + int ret = -1; + + /* use irq */ + if (gpio_is_valid(ts->pdata->irq_gpio) || ts->client->irq > 0) { + if (gpio_is_valid(ts->pdata->irq_gpio)) + ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio); + + dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n", + ts->client->irq, ts->pdata->irq_flags); + ret = request_threaded_irq(ts->client->irq, NULL, + gtp_irq_handler, + ts->pdata->irq_flags | IRQF_ONESHOT, + ts->client->name, + ts); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request irq %d\n", ts->client->irq); + return ret; + } + } else { /* use hrtimer */ + dev_info(&ts->client->dev, "No hardware irq, use hrtimer\n"); + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = gtp_timer_handler; + hrtimer_start(&ts->timer, + ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), + HRTIMER_MODE_REL); + set_bit(HRTIMER_USED, &ts->flags); + ret = 0; + } + return ret; +} + +static s8 gtp_request_input_dev(struct goodix_ts_data *ts) +{ + s8 ret = -1; + u8 index = 0; + + ts->input_dev = input_allocate_device(); + if (!ts->input_dev) { + dev_err(&ts->client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) + | BIT_MASK(EV_ABS); + if (!ts->pdata->type_a_report) { + input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT); + dev_info(&ts->client->dev, "Use slot report protocol\n"); + } else { + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + __set_bit(BTN_TOUCH, ts->input_dev->keybit); + dev_info(&ts->client->dev, "Use type A report protocol\n"); + } + + input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1); + input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2); + + /* touch key register */ + for (index = 0; index < ts->pdata->key_nums; index++) + input_set_capability(ts->input_dev, EV_KEY, + ts->pdata->key_map[index]); + + if (ts->pdata->slide_wakeup) + input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); + + if (ts->pdata->swap_x2y) + GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, + ts->pdata->abs_size_x, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, + ts->pdata->abs_size_y, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, + ts->pdata->max_touch_width, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, + ts->pdata->max_touch_pressure, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, + ts->pdata->max_touch_id, 0, 0); + if (!ts->pdata->type_a_report) { + input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); + } else { + __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); + } + + ts->input_dev->name = goodix_ts_name; + ts->input_dev->phys = goodix_input_phys; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0xDEAD; + ts->input_dev->id.product = 0xBEEF; + ts->input_dev->id.version = 10427; + + ret = input_register_device(ts->input_dev); + if (ret) { + dev_err(&ts->client->dev, "Register %s input device failed\n", + ts->input_dev->name); + input_free_device(ts->input_dev); + return -ENODEV; + } + + return 0; +} + +/* + * Devices Tree support + */ +#ifdef CONFIG_OF +static void gtp_parse_dt_coords(struct device *dev, + struct goodix_ts_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + int ret; + + ret = of_property_read_u32(np, "touchscreen-max-id", + &pdata->max_touch_id); + if (ret || pdata->max_touch_id > GTP_MAX_TOUCH_ID) { + dev_info(dev, "Unset touchscreen-max-id, use default\n"); + pdata->max_touch_id = GTP_MAX_TOUCH_ID; + } + + ret = of_property_read_u32(np, "touchscreen-size-x", + &pdata->abs_size_x); + if (ret) { + dev_info(dev, "Unset touchscreen-size-x, use default\n"); + pdata->abs_size_x = GTP_DEFAULT_MAX_X; + } + + ret = of_property_read_u32(np, "touchscreen-size-y", + &pdata->abs_size_y); + if (ret) { + dev_info(dev, "Unset touchscreen-size-y, use default\n"); + pdata->abs_size_y = GTP_DEFAULT_MAX_Y; + } + + ret = of_property_read_u32(np, "touchscreen-max-w", + &pdata->max_touch_width); + if (ret) { + dev_info(dev, "Unset touchscreen-max-w, use default\n"); + pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; + } + + ret = of_property_read_u32(np, "touchscreen-max-p", + &pdata->max_touch_pressure); + if (ret) { + dev_info(dev, "Unset touchscreen-max-p, use default\n"); + pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; + } + dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n", + pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y, + pdata->max_touch_width, pdata->max_touch_pressure); +} + +static int gtp_parse_dt(struct device *dev, + struct goodix_ts_platform_data *pdata) +{ + int ret; + u32 key_nums; + struct property *prop; + u32 key_map[MAX_KEY_NUMS]; + struct device_node *np = dev->of_node; + + gtp_parse_dt_coords(dev, pdata); + + ret = of_property_read_u32(np, "irq-flags", + &pdata->irq_flags); + if (ret) { + dev_info(dev, + "Failed get int-trigger-type from dts,set default\n"); + pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER; + } + of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync); + if (pdata->int_sync) + dev_info(dev, "int-sync enabled\n"); + + of_property_read_u32(np, "goodix,driver-send-cfg", + &pdata->driver_send_cfg); + if (pdata->driver_send_cfg) + dev_info(dev, "driver-send-cfg enabled\n"); + + of_property_read_u32(np, "goodix,swap-x2y", &pdata->swap_x2y); + if (pdata->swap_x2y) + dev_info(dev, "swap-x2y enabled\n"); + + of_property_read_u32(np, "goodix,slide-wakeup", &pdata->slide_wakeup); + if (pdata->slide_wakeup) + dev_info(dev, "slide-wakeup enabled\n"); + + of_property_read_u32(np, "goodix,auto-update", &pdata->auto_update); + if (pdata->auto_update) + dev_info(dev, "auto-update enabled\n"); + + of_property_read_u32(np, "goodix,auto-update-cfg", + &pdata->auto_update_cfg); + if (pdata->auto_update_cfg) + dev_info(dev, "auto-update-cfg enabled\n"); + + of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect); + if (pdata->esd_protect) + dev_info(dev, "esd-protect enabled\n"); + + of_property_read_u32(np, "goodix,type-a-report", + &pdata->type_a_report); + if (pdata->type_a_report) + dev_info(dev, "type-a-report enabled\n"); + + of_property_read_u32(np, "goodix,resume-in-workqueue", + &pdata->resume_in_workqueue); + if (pdata->resume_in_workqueue) + dev_info(dev, "resume-in-workqueue enabled\n"); + + of_property_read_u32(np, "goodix,power-off-sleep", + &pdata->power_off_sleep); + if (pdata->power_off_sleep) + dev_info(dev, "power-off-sleep enabled\n"); + + of_property_read_u32(np, "goodix,pen-suppress-finger", + &pdata->pen_suppress_finger); + if (pdata->pen_suppress_finger) + dev_info(dev, "pen-suppress-finger enabled\n"); + + prop = of_find_property(np, "touchscreen-key-map", NULL); + if (prop) { + key_nums = prop->length / sizeof(key_map[0]); + key_nums = key_nums > MAX_KEY_NUMS ? MAX_KEY_NUMS : key_nums; + + dev_dbg(dev, "key nums %d\n", key_nums); + ret = of_property_read_u32_array(np, + "touchscreen-key-map", key_map, + key_nums); + if (ret) { + dev_err(dev, "Unable to read key codes\n"); + pdata->key_nums = 0; + memset(pdata->key_map, 0, + MAX_KEY_NUMS * sizeof(pdata->key_map[0])); + } + pdata->key_nums = key_nums; + memcpy(pdata->key_map, key_map, + key_nums * sizeof(pdata->key_map[0])); + dev_info(dev, "key-map is [%x %x %x %x]\n", + pdata->key_map[0], pdata->key_map[1], + pdata->key_map[2], pdata->key_map[3]); + } + + pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0); + if (!gpio_is_valid(pdata->irq_gpio)) + dev_err(dev, "No valid irq gpio"); + + pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0); + if (!gpio_is_valid(pdata->rst_gpio)) + dev_err(dev, "No valid rst gpio"); + + return 0; +} + +/******************************************************* + * Function: + * parse config data from devices tree. + * Input: + * dev: device that this driver attached. + * cfg: pointer of the config array. + * cfg_len: pointer of the config length. + * sid: sensor id. + * Output: + * Executive outcomes. + * 0-succeed, -1-faileds. + *******************************************************/ +int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid) +{ + struct device_node *np = dev->of_node; + struct property *prop; + char cfg_name[18]; + int ret; + + snprintf(cfg_name, sizeof(cfg_name), "goodix,cfg-group%d", sid); + prop = of_find_property(np, cfg_name, cfg_len); + if (!prop || !prop->value || *cfg_len == 0 || + *cfg_len > GTP_CONFIG_MAX_LENGTH) { + *cfg_len = 0; + ret = -EPERM;/* failed */ + } else { + memcpy(cfg, prop->value, *cfg_len); + ret = 0; + } + + return ret; +} + +#endif + +static int gtp_power_on(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (ts->vdd_ana) { + ret = regulator_enable(ts->vdd_ana); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vdd enable failed ret=%d\n", + ret); + goto err_enable_vdd_ana; + } + } + + if (ts->vcc_i2c) { + ret = regulator_enable(ts->vcc_i2c); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c enable failed ret=%d\n", + ret); + goto err_enable_vcc_i2c; + } + } + clear_bit(POWER_OFF_MODE, &ts->flags); + return 0; + +err_enable_vcc_i2c: + if (ts->vdd_ana) + regulator_disable(ts->vdd_ana); +err_enable_vdd_ana: + set_bit(POWER_OFF_MODE, &ts->flags); + return ret; +} + +static int gtp_power_off(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (ts->vcc_i2c) { + set_bit(POWER_OFF_MODE, &ts->flags); + ret = regulator_disable(ts->vcc_i2c); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c disable failed ret=%d\n", + ret); + goto err_disable_vcc_i2c; + } + dev_info(&ts->client->dev, + "Regulator vcc_i2c disabled\n"); + } + + if (ts->vdd_ana) { + set_bit(POWER_OFF_MODE, &ts->flags); + ret = regulator_disable(ts->vdd_ana); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vdd disable failed ret=%d\n", + ret); + goto err_disable_vdd_ana; + } + dev_info(&ts->client->dev, + "Regulator vdd_ana disabled\n"); + } + return ret; + +err_disable_vdd_ana: + if (ts->vcc_i2c) + ret = regulator_enable(ts->vcc_i2c); +err_disable_vcc_i2c: + clear_bit(POWER_OFF_MODE, &ts->flags); + return ret; +} + +static int gtp_power_init(struct goodix_ts_data *ts) +{ + int ret; + + ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana"); + if (IS_ERR(ts->vdd_ana)) { + ts->vdd_ana = NULL; + ret = PTR_ERR(ts->vdd_ana); + dev_info(&ts->client->dev, + "Regulator get failed vdd ret=%d\n", ret); + } + + ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c"); + if (IS_ERR(ts->vcc_i2c)) { + ts->vcc_i2c = NULL; + ret = PTR_ERR(ts->vcc_i2c); + dev_info(&ts->client->dev, + "Regulator get failed vcc_i2c ret=%d\n", ret); + } + return 0; +} + +static int gtp_power_deinit(struct goodix_ts_data *ts) +{ + if (ts->vdd_ana) + regulator_put(ts->vdd_ana); + if (ts->vcc_i2c) + regulator_put(ts->vcc_i2c); + + return 0; +} + +static void gtp_shutdown(struct i2c_client *client) +{ + struct goodix_ts_data *data = i2c_get_clientdata(client); + + if (!data->init_done) + return; + + gtp_work_control_enable(data, false); + gtp_power_off(data); + + return; +} + +static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = -1; + struct goodix_ts_data *ts; + struct goodix_ts_platform_data *pdata; + + /* do NOT remove these logs */ + dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION); + dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); + + i2c_connect_client = client; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "Failed check I2C functionality"); + return -ENODEV; + } + + ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) { + dev_err(&client->dev, "Failed alloc ts memory"); + return -ENOMEM; + } + + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed alloc pdata memory\n"); + devm_kfree(&client->dev, ts); + return -EINVAL; + } + + ts->init_done = false; + +#ifdef CONFIG_OF + if (client->dev.of_node) { + ret = gtp_parse_dt(&client->dev, pdata); + if (ret) { + dev_err(&client->dev, "Failed parse dts\n"); + goto exit_free_client_data; + } + } +#else + /* set parameters at here if you platform doesn't DTS */ + pdata->rst_gpio = GTP_RST_PORT; + pdata->irq_gpio = GTP_INT_PORT; + pdata->slide_wakeup = false; + pdata->auto_update = true; + pdata->auto_update_cfg = false; + pdata->type_a_report = false; + pdata->esd_protect = false; + pdata->max_touch_id = GTP_MAX_TOUCH_ID; + pdata->abs_size_x = GTP_DEFAULT_MAX_X; + pdata->abs_size_y = GTP_DEFAULT_MAX_Y; + pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; + pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; +#endif + + ts->client = client; + ts->pdata = pdata; + + i2c_set_clientdata(client, ts); + + ret = gtp_power_init(ts); + if (ret) { + dev_err(&client->dev, "Failed get regulator\n"); + ret = -EINVAL; + goto exit_free_client_data; + } + + ret = gtp_power_on(ts); + if (ret) { + dev_err(&client->dev, "Failed power on device\n"); + ret = -EINVAL; + goto exit_deinit_power; + } + + ret = gtp_pinctrl_init(ts); + if (ret < 0) { + /* if define pinctrl must define the following state + * to let int-pin work normally: default, int_output_high, + * int_output_low, int_input + */ + dev_err(&client->dev, "Failed get wanted pinctrl state\n"); + goto exit_deinit_power; + } + + ret = gtp_request_io_port(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed request IO port\n"); + goto exit_power_off; + } + + gtp_reset_guitar(ts->client, 20); + + ret = gtp_i2c_test(client); + if (ret) { + dev_err(&client->dev, "Failed communicate with IC use I2C\n"); + goto exit_free_io_port; + } + + dev_info(&client->dev, "I2C Addr is %x\n", client->addr); + + ret = gtp_get_fw_info(client, &ts->fw_info); + if (ret < 0) { + dev_err(&client->dev, "Failed read FW version\n"); + goto exit_free_io_port; + } + + pdata->config.data[0] = GTP_REG_CONFIG_DATA >> 8; + pdata->config.data[1] = GTP_REG_CONFIG_DATA & 0xff; + ret = gtp_init_panel(ts); + if (ret < 0) + dev_info(&client->dev, "Panel un-initialize\n"); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + if (ts->pdata->auto_update) { + ret = gup_init_update_proc(ts); + if (ret < 0) + dev_err(&client->dev, "Failed create update thread\n"); + } +#endif + + ret = gtp_request_input_dev(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed request input device\n"); + goto exit_free_io_port; + } + + mutex_init(&ts->lock); + + ret = gtp_request_irq(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed create work thread"); + goto exit_unreg_input_dev; + } + gtp_work_control_enable(ts, false); + if (ts->pdata->slide_wakeup) { + dev_info(&client->dev, "slide wakeup enabled\n"); + ret = enable_irq_wake(client->irq); + if (ret < 0) + dev_err(&client->dev, "Failed set irq wake\n"); + } + + gtp_register_powermanager(ts); + + ret = gtp_create_file(ts); + if (ret) { + dev_info(&client->dev, "Failed create attributes file"); + goto exit_powermanager; + } + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL + init_wr_node(client);/*TODO judge return value */ +#endif + + gtp_esd_init(ts); + gtp_esd_on(ts); + /* probe init finished */ + ts->init_done = true; + gtp_work_control_enable(ts, true); + + return 0; + +exit_powermanager: + gtp_unregister_powermanager(ts); +exit_unreg_input_dev: + input_unregister_device(ts->input_dev); +exit_free_io_port: + if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_free(ts->pdata->rst_gpio); + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); +exit_power_off: + gtp_power_off(ts); + gtp_pinctrl_deinit(ts); +exit_deinit_power: + gtp_power_deinit(ts); +exit_free_client_data: + devm_kfree(&client->dev, pdata); + devm_kfree(&client->dev, ts); + i2c_set_clientdata(client, NULL); + + return ret; +} + +static int gtp_drv_remove(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + gtp_work_control_enable(ts, false); + gtp_unregister_powermanager(ts); + + remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); + + sysfs_remove_group(&client->dev.kobj, >p_attr_group); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL + uninit_wr_node(); +#endif + + if (ts->pdata->esd_protect) + gtp_esd_off(ts); + + /* TODO: how to judge a irq numbers validity */ + if (ts->client->irq) + free_irq(client->irq, ts); + else + hrtimer_cancel(&ts->timer); + + if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_free(ts->pdata->rst_gpio); + + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); + + gtp_power_off(ts); + gtp_power_deinit(ts); + gtp_pinctrl_deinit(ts); + dev_info(&client->dev, "goodix ts driver removed"); + i2c_set_clientdata(client, NULL); + input_unregister_device(ts->input_dev); + mutex_destroy(&ts->lock); + + devm_kfree(&client->dev, ts->pdata); + devm_kfree(&client->dev, ts); + + return 0; +} + +static void gtp_suspend(struct goodix_ts_data *ts) +{ + int ret = -1; + + if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_warn(&ts->client->dev, + "Fw upgrade in progress, can't go to suspend\n"); + return; + } + + if (test_and_set_bit(SLEEP_MODE, &ts->flags)) { + dev_info(&ts->client->dev, "Already in suspend state\n"); + return; + } + + dev_dbg(&ts->client->dev, "Try enter suspend mode\n"); + + gtp_esd_off(ts); + gtp_work_control_enable(ts, false); + if (ts->pdata->slide_wakeup) { + ret = gtp_enter_doze(ts); + gtp_work_control_enable(ts, true); + } else if (ts->pdata->power_off_sleep) { + /*TODO: power off routine */ + gtp_power_off(ts); + ret = SUCCESS; + } else { + ret = gtp_enter_sleep(ts); + } + + if (ret < 0) + dev_err(&ts->client->dev, "Failed enter suspend\n"); + + /* to avoid waking up while not sleeping */ + /* delay 48 + 10ms to ensure reliability */ + msleep(GTP_58_DLY_MS); +} + +static int gtp_gesture_wakeup(struct goodix_ts_data *ts) +{ + int ret; + int retry = 10; + + do { + gtp_reset_guitar(ts->client, 10); + ret = gtp_i2c_test(ts->client); + if (!ret) + break; + } while (--retry); + + if (!retry) + ret = -EIO; + + clear_bit(DOZE_MODE, &ts->flags); + return ret; +} + +static void gtp_resume(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_info(&ts->client->dev, + "Fw upgrade in progress, can't do resume\n"); + return; + } + + if (!test_bit(SLEEP_MODE, &ts->flags)) { + dev_dbg(&ts->client->dev, "Already in awake state\n"); + return; + } + + dev_info(&ts->client->dev, "Try resume from sleep mode\n"); + + gtp_work_control_enable(ts, false); + + if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { + ret = gtp_gesture_wakeup(ts); + if (ret) + dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); + } else if (ts->pdata->power_off_sleep) { + ret = gtp_power_on(ts); + if (ret) { + dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); + } else { + gtp_reset_guitar(ts->client, 20); + ret = gtp_i2c_test(ts->client); + if (ret) + dev_warn(&ts->client->dev, + "I2C communicate failed after power on\n"); + } + } else { + ret = gtp_wakeup_sleep(ts); + if (ret) + dev_warn(&ts->client->dev, + "Failed wakeup from sleep mode\n"); + } + + if (ret) + dev_warn(&ts->client->dev, "Later resume failed\n"); + else + gtp_esd_on(ts); + + clear_bit(SLEEP_MODE, &ts->flags); + gtp_work_control_enable(ts, true); +} + +#if defined(CONFIG_FB) +static void fb_notify_resume_work(struct work_struct *work) +{ + struct goodix_ts_data *ts = + container_of(work, struct goodix_ts_data, fb_notify_work); + dev_info(&ts->client->dev, "try resume in workqueue\n"); + gtp_resume(ts); +} + +/* frame buffer notifier block control the suspend/resume procedure */ +static int gtp_fb_notifier_callback(struct notifier_block *noti, + unsigned long event, void *data) +{ + struct fb_event *ev_data = data; + struct goodix_ts_data *ts = container_of(noti, + struct goodix_ts_data, notifier); + int *blank; + + if (ev_data && ev_data->data && event == FB_EVENT_BLANK && ts) { + blank = ev_data->data; + if (*blank == FB_BLANK_UNBLANK || + *blank == FB_BLANK_NORMAL) { + dev_dbg(&ts->client->dev, "ts_resume"); + if (ts->pdata->resume_in_workqueue) + schedule_work(&ts->fb_notify_work); + else + gtp_resume(ts); + } else if (*blank == FB_BLANK_POWERDOWN) { + dev_dbg(&ts->client->dev, "ts_suspend"); + if (ts->pdata->resume_in_workqueue) + flush_work(&ts->fb_notify_work); + gtp_suspend(ts); + } + } + + return 0; +} + +#elif defined(CONFIG_PM) +static int gtp_pm_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts) { + dev_dbg(&ts->client->dev, "Suspend by i2c pm."); + gtp_suspend(ts); + } + + return 0; +} + +static int gtp_pm_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts) { + dev_dbg(&ts->client->dev, "Resume by i2c pm."); + gtp_resume(ts); + } + + return 0; +} + +static const struct dev_pm_ops gtp_pm_ops = { + .suspend = gtp_pm_suspend, + .resume = gtp_pm_resume, +}; + +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void gtp_early_suspend(struct early_suspend *h) +{ + struct goodix_ts_data *ts = container_of(h, + struct goodix_ts_data, early_suspend); + + if (ts) { + dev_dbg(&ts->client->dev, "Suspend by earlysuspend module."); + gtp_suspend(ts); + } +} + +static void gtp_late_resume(struct early_suspend *h) +{ + struct goodix_ts_data *ts = container_of(h, + struct goodix_ts_data, early_suspend); + + if (ts) { + dev_dbg(&ts->client->dev, "Resume by earlysuspend module."); + gtp_resume(ts); + } +} +#endif + +static int gtp_register_powermanager(struct goodix_ts_data *ts) +{ + int ret; +#if defined(CONFIG_FB) + INIT_WORK(&ts->fb_notify_work, fb_notify_resume_work); + ts->notifier.notifier_call = gtp_fb_notifier_callback; + ret = fb_register_client(&ts->notifier); + if (ret) + dev_err(&ts->client->dev, + "Unable to register fb_notifier: %d\n", ret); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = goodix_ts_early_suspend; + ts->early_suspend.resume = goodix_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + return ret; +} + +static int gtp_unregister_powermanager(struct goodix_ts_data *ts) +{ +#if defined(CONFIG_FB) + fb_unregister_client(&ts->notifier); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + + return 0; +} + +/******************************************************* + * Function: + * Initialize external watchdog for esd protect + * Input: + * client: i2c device. + * Output: + * result of i2c write operation. + * 0: succeed, otherwise: failed + ********************************************************/ +static int gtp_init_ext_watchdog(struct i2c_client *client) +{ + int ret; + u8 opr_buffer[3] = { (u8)(GTP_REG_ESD_CHECK >> 8), + (u8)GTP_REG_ESD_CHECK, + (u8)GTP_ESD_CHECK_VALUE }; + + dev_dbg(&client->dev, "[Esd]Init external watchdog\n"); + ret = gtp_i2c_write(client, opr_buffer, 3); + if (ret == 1) + return 0; + + dev_err(&client->dev, "Failed init ext watchdog\n"); + return -EINVAL; +} + +static void gtp_esd_check_func(struct work_struct *work) +{ + s32 i; + s32 ret = -1; + u8 esd_buf[5] = { (u8)(GTP_REG_COMMAND >> 8), (u8)GTP_REG_COMMAND }; + struct delayed_work *dwork = to_delayed_work(work); + struct goodix_ts_esd *ts_esd = container_of(dwork, struct goodix_ts_esd, + delayed_work); + struct goodix_ts_data *ts = container_of(ts_esd, struct goodix_ts_data, + ts_esd); + + if (test_bit(SLEEP_MODE, &ts->flags) || + test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_dbg(&ts->client->dev, + "Esd cancled by power_suspend or fw_update!"); + return; + } + + if (ts_esd->esd_on == false) + return; + + for (i = 0; i < 3; i++) { + ret = gtp_i2c_read(ts->client, esd_buf, 4); + if (ret < 0) + continue; + + dev_dbg(&ts->client->dev, + "[Esd]0x8040 = 0x%02X, 0x8041 = 0x%02X", + esd_buf[2], esd_buf[3]); + if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || + esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { + gtp_i2c_read(ts->client, esd_buf, 4); + if (ret < 0) + continue; + + if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || + esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { + i = 3; + break; + } + } else { + /* IC works normally, Write 0x8040 0xAA, feed the dog */ + esd_buf[2] = (u8)GTP_ESD_CHECK_VALUE; + gtp_i2c_write(ts->client, esd_buf, 3); + break; + } + } + if (i >= 3) { + dev_err(&ts->client->dev, "IC working abnormally! Reset IC\n"); + esd_buf[0] = 0x42; + esd_buf[1] = 0x26; + esd_buf[2] = 0x01; + esd_buf[3] = 0x01; + esd_buf[4] = 0x01; + gtp_i2c_write(ts->client, esd_buf, 5); + /* TODO: Is power off really need? */ + msleep(GTP_50_DLY_MS); + gtp_power_off(ts); + msleep(GTP_20_DLY_MS); + gtp_power_on(ts); + msleep(GTP_20_DLY_MS); + + gtp_reset_guitar(ts->client, 50); + msleep(GTP_50_DLY_MS); + gtp_send_cfg(ts->client); + } + + if (ts_esd->esd_on == true && !test_bit(SLEEP_MODE, &ts->flags)) { + schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); + dev_dbg(&ts->client->dev, "ESD work rescheduled\n"); + } +} + +static int gtp_esd_init(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + INIT_DELAYED_WORK(&ts_esd->delayed_work, gtp_esd_check_func); + mutex_init(&ts_esd->mutex); + ts_esd->esd_on = false; + + return 0; +} + +void gtp_esd_on(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + if (!ts->pdata->esd_protect) + return; + mutex_lock(&ts_esd->mutex); + if (ts_esd->esd_on == false) { + ts_esd->esd_on = true; + schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); + dev_info(&ts->client->dev, "ESD on"); + } + mutex_unlock(&ts_esd->mutex); +} + +void gtp_esd_off(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + if (!ts->pdata->esd_protect) + return; + mutex_lock(&ts_esd->mutex); + if (ts_esd->esd_on == true) { + ts_esd->esd_on = false; + cancel_delayed_work_sync(&ts_esd->delayed_work); + dev_info(&ts->client->dev, "ESD off"); + } + mutex_unlock(&ts_esd->mutex); +} + +#ifdef CONFIG_OF +static const struct of_device_id gtp_match_table[] = { + {.compatible = "goodix,gt9xx",}, + { }, +}; +#endif + +static const struct i2c_device_id gtp_device_id[] = { + { GTP_I2C_NAME, 0 }, + { } +}; + +static struct i2c_driver goodix_ts_driver = { + .probe = gtp_probe, + .remove = gtp_drv_remove, + .id_table = gtp_device_id, + .shutdown = gtp_shutdown, + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = gtp_match_table, +#endif +#if !defined(CONFIG_FB) && defined(CONFIG_PM) + .pm = >p_pm_ops, +#endif + }, +}; + +static int __init gtp_init(void) +{ + s32 ret; + + pr_info("Gt9xx driver installing..\n"); + ret = i2c_add_driver(&goodix_ts_driver); + + return ret; +} + +static void __exit gtp_exit(void) +{ + pr_info("Gt9xx driver exited\n"); + i2c_del_driver(&goodix_ts_driver); +} + +module_init(gtp_init); +module_exit(gtp_exit); + +MODULE_DESCRIPTION("GT9 serials touch controller Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/input/touchscreen/gt9xx_2.8/gt9xx.h b/drivers/input/touchscreen/gt9xx_2.8/gt9xx.h new file mode 100755 index 00000000000..2e1c6658787 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2.8/gt9xx.h @@ -0,0 +1,384 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 2.8.0.2 + * Release Date: 2017/12/14 + */ + +#ifndef _GOODIX_GT9XX_H_ +#define _GOODIX_GT9XX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#ifdef CONFIG_FB +#include +#include +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#define GTP_TOOL_PEN 1 +#define GTP_TOOL_FINGER 2 + +#define MAX_KEY_NUMS 4 +#define GTP_CONFIG_MAX_LENGTH 240 +#define GTP_ADDR_LENGTH 2 + +/***************************PART1:ON/OFF define*******************************/ +#define GTP_DEBUG_ON 1 +#define GTP_DEBUG_ARRAY_ON 0 +#define GTP_DEBUG_FUNC_ON 0 + +struct goodix_point_t { + int id; + int x; + int y; + int w; + int p; + int tool_type; +}; + +struct goodix_config_data { + int length; + u8 data[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]; +}; + +struct goodix_ts_platform_data { + int irq_gpio; + int rst_gpio; + u32 irq_flags; + u32 abs_size_x; + u32 abs_size_y; + u32 max_touch_id; + u32 max_touch_width; + u32 max_touch_pressure; + u32 key_map[MAX_KEY_NUMS]; + u32 key_nums; + u32 int_sync; + u32 driver_send_cfg; + u32 swap_x2y; + u32 slide_wakeup; + u32 auto_update; + u32 auto_update_cfg; + u32 esd_protect; + u32 type_a_report; + u32 power_off_sleep; + u32 resume_in_workqueue; + u32 pen_suppress_finger; + struct goodix_config_data config; +}; + +struct goodix_ts_esd { + struct delayed_work delayed_work; + struct mutex mutex; + bool esd_on; +}; + +enum { + WORK_THREAD_ENABLED = 0, + HRTIMER_USED, + FW_ERROR, + + DOZE_MODE, + SLEEP_MODE, + POWER_OFF_MODE, + RAW_DATA_MODE, + + FW_UPDATE_RUNNING, + PANEL_RESETTING +}; + +struct goodix_pinctrl { + struct pinctrl *pinctrl; + struct pinctrl_state *default_sta; + struct pinctrl_state *int_out_high; + struct pinctrl_state *int_out_low; + struct pinctrl_state *int_input; +}; + +struct goodix_fw_info { + u8 pid[6]; + u16 version; + u8 sensor_id; +}; + +struct goodix_ts_data { + unsigned long flags; /* This member record the device status */ + + struct goodix_ts_esd ts_esd; + struct i2c_client *client; + struct input_dev *input_dev; + struct input_dev *pen_dev; + struct goodix_ts_platform_data *pdata; + /* use pinctrl control int-pin output low or high */ + struct goodix_pinctrl pinctrl; + struct hrtimer timer; + struct mutex lock; + struct notifier_block ps_notif; + struct regulator *vdd_ana; + struct regulator *vcc_i2c; +#if defined(CONFIG_FB) + struct notifier_block notifier; + struct work_struct fb_notify_work; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + struct goodix_fw_info fw_info; + bool force_update; + bool init_done; +}; + +/************************* PART2:TODO define *******************************/ +/* STEP_1(REQUIRED): Define Configuration Information Group(s) + Sensor_ID Map: + sensor_opt1 sensor_opt2 Sensor_ID + GND GND 0 + VDDIO GND 1 + NC GND 2 + GND NC/300K 3 + VDDIO NC/300K 4 + NC NC/300K 5 +*/ +/* TODO: define your own default or for Sensor_ID == 0 config here. + The predefined one is just a sample config, + which is not suitable for your tp in most cases. */ +#define CTP_CFG_GROUP0 {\ + 0x41, 0xD0, 0x02, 0x00, 0x05, 0x0A, 0x34, \ + 0x00, 0x01, 0x08, 0x28, 0x05, 0x50, 0x32, \ + 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x17, 0x19, 0x1E, 0x14, 0x8C, \ + 0x2D, 0x0E, 0x3C, 0x3E, 0x82, 0x0A, 0x82, \ + 0x0A, 0x00, 0x99, 0x33, 0x1D, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x2B, 0x19, 0x64, 0x94, 0xC0, 0x02, \ + 0x08, 0x00, 0x00, 0x04, 0xF2, 0x1C, 0x00, \ + 0xB9, 0x26, 0x00, 0x93, 0x32, 0x00, 0x77, \ + 0x42, 0x00, 0x62, 0x57, 0x00, 0x62, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0xFF, 0x65, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x19, 0x46, 0x00, 0x00, 0x00, 0x00, 0x32, \ + 0x1C, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, \ + 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x08, \ + 0x0A, 0x0C, 0x0F, 0x10, 0x12, 0x13, 0x14, \ + 0x18, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, \ + 0x22, 0x24, 0x26, 0x28, 0x29, 0x2A, 0xFF, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0xB8, 0x01\ +} + +/* TODO: define your config for Sensor_ID == 1 here, if needed */ +#define CTP_CFG_GROUP1 {\ +} + +/* TODO: define your config for Sensor_ID == 2 here, if needed */ +#define CTP_CFG_GROUP2 {\ +} + +/* TODO: define your config for Sensor_ID == 3 here, if needed */ +#define CTP_CFG_GROUP3 {\ +} +/* TODO: define your config for Sensor_ID == 4 here, if needed */ +#define CTP_CFG_GROUP4 {\ + 0x53,0xD0,0x02,0x00,0x05,0x05,0xF5,0xD5,0x21,0x48,0x2D,0x0F,\ + 0x5A,0x41,0x0E,0x05,0x00,0x00,0x32,0x32,0x20,0x00,0x05,0x14,\ + 0x14,0x1A,0x14,0x8B,0x2B,0x0C,0xB5,0xB7,0xEB,0x04,0xFF,0xFE,\ + 0x00,0x22,0x33,0x10,0x3C,0x80,0x00,0x00,0x00,0x1E,0x12,0x41,\ + 0x23,0x12,0x5A,0xAA,0xBE,0x4A,0x55,0x04,0x00,0x14,0x19,0x04,\ + 0x80,0xAB,0x00,0x7F,0xAF,0x64,0x7E,0xB3,0x00,0x7E,0xB7,0x00,\ + 0x7B,0xBB,0x3C,0x7B,0x08,0x30,0x00,0x00,0xF8,0x70,0x50,0xFF,\ + 0xFF,0x17,0x00,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,\ + 0x08,0x46,0x80,0x08,0x0A,0x00,0xA0,0x00,0x3C,0x28,0x19,0x19,\ + 0x80,0x11,0x00,0x00,0x18,0x16,0x14,0x12,0x10,0x0E,0x0C,0x0A,\ + 0x08,0x06,0x04,0x02,0xFF,0xFF,0x28,0x00,0x32,0x20,0x00,0x06,\ + 0x00,0x00,0x0A,0x06,0x10,0x08,0x0A,0x22,0xEB,0x04,0x26,0x24,\ + 0x22,0x21,0x20,0x1F,0x1E,0x1D,0x1C,0x18,0x16,0x12,0x10,0x0F,\ + 0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0x13,0xFF,0xFF,0xFF,0xFF,\ + 0x00,0x00,0x00,0x02,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x28,0x0B,0x0B,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE6,0x10,0xEF,0x01\ +} + +/* TODO: define your config for Sensor_ID == 5 here, if needed */ +#define CTP_CFG_GROUP5 {\ +} + +/* STEP_2(REQUIRED): Customize your I/O ports & I/O operations */ +#define GTP_RST_PORT 64 /* EXYNOS4_GPX2(0) */ +#define GTP_INT_PORT 65 /* EXYNOS4_GPX2(1) */ + +#define GTP_GPIO_AS_INPUT(pin) (gpio_direction_input(pin)) +#define GTP_GPIO_AS_INT(pin) (GTP_GPIO_AS_INPUT(pin)) +#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin) +#define GTP_GPIO_OUTPUT(pin, level) gpio_direction_output(pin, level) +#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label) +#define GTP_GPIO_FREE(pin) gpio_free(pin) + +/* STEP_3(optional): Specify your special config info if needed */ +#define GTP_DEFAULT_MAX_X 720 /* default coordinate max values */ +#define GTP_DEFAULT_MAX_Y 1080 +#define GTP_DEFAULT_MAX_WIDTH 1024 +#define GTP_DEFAULT_MAX_PRESSURE 1024 +#define GTP_DEFAULT_INT_TRIGGER 1 /* 1 rising, 2 falling */ +#define GTP_MAX_TOUCH_ID 16 + +/* STEP_4(optional): If keys are available and reported as keys, +config your key info here */ +#define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_HOMEPAGE, \ + KEY_F1, KEY_F2, KEY_F3} + +/**************************PART3:OTHER define*******************************/ +#define GTP_DRIVER_VERSION "V2.8.0.2<2017/12/14>" +#define GTP_I2C_NAME "goodix-ts" +#define GT91XX_CONFIG_PROC_FILE "gt9xx_config" +#define GTP_POLL_TIME 10 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_ESD_CHECK_VALUE 0xAA +#define RETRY_MAX_TIMES 5 +#define PEN_TRACK_ID 9 +#define MASK_BIT_8 0x80 +#define FAIL 0 +#define SUCCESS 1 + +/* Registers define */ +#define GTP_REG_COMMAND 0x8040 +#define GTP_REG_ESD_CHECK 0x8041 +#define GTP_REG_COMMAND_CHECK 0x8046 +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_VERSION 0x8140 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_DOZE_BUF 0x814B +#define GTP_READ_COOR_ADDR 0x814E + +/* Sleep time define */ +#define GTP_1_DLY_MS 1 +#define GTP_2_DLY_MS 2 +#define GTP_10_DLY_MS 10 +#define GTP_20_DLY_MS 20 +#define GTP_50_DLY_MS 50 +#define GTP_58_DLY_MS 58 +#define GTP_100_DLY_MS 100 +#define GTP_500_DLY_MS 500 +#define GTP_1000_DLY_MS 1000 +#define GTP_3000_DLY_MS 3000 + +#define RESOLUTION_LOC 3 +#define TRIGGER_LOC 8 + +#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0])) +/* Log define */ +#define GTP_DEBUG(fmt, arg...) \ +do { \ + if (GTP_DEBUG_ON) {\ + pr_info("<<-GTP-DEBUG->> [%d]"fmt"\n", __LINE__, ##arg);\ + } \ +} while (0) +#define GTP_DEBUG_ARRAY(array, num) \ +do { \ + s32 i;\ + u8 *a = array;\ + if (GTP_DEBUG_ARRAY_ON) {\ + pr_warn("<<-GTP-DEBUG-ARRAY->>\n");\ + for (i = 0; i < (num); i++) {\ + pr_warn("%02x ", (a)[i]);\ + if ((i + 1) % 10 == 0) {\ + pr_warn("\n");\ + } \ + } \ + pr_warn("\n");\ + } \ +} while (0) +#define GTP_DEBUG_FUNC() \ +do {\ + if (GTP_DEBUG_FUNC_ON) {\ + pr_warn("<<-GTP-FUNC->> Func:%s@Line:%d\n", \ + __func__, __LINE__);\ + } \ +} while (0) +#define GTP_SWAP(x, y) \ +do {\ + typeof(x) z = x;\ + x = y;\ + y = z;\ +} while (0) + +/******************************End of Part III********************************/ +#ifdef CONFIG_OF +extern int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid); +#endif + +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern void gtp_int_sync(struct goodix_ts_data *ts, s32 ms); +extern void gtp_esd_on(struct goodix_ts_data *ts); +extern void gtp_esd_off(struct goodix_ts_data *ts); +extern void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE +extern u16 show_len; +extern u16 total_len; +extern u8 gup_init_update_proc(struct goodix_ts_data *); +extern s32 gup_update_proc(void *dir); +extern s32 gup_enter_update_mode(struct i2c_client *client); +extern void gup_leave_update_mode(struct i2c_client *client); +#endif + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL +extern s32 init_wr_node(struct i2c_client *); +extern void uninit_wr_node(void); +#endif + +/*********** For gt9xx_update Start *********/ +extern struct i2c_client *i2c_connect_client; +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern void gtp_int_output(struct goodix_ts_data *ts, int level); +extern s32 gtp_send_cfg(struct i2c_client *client); +extern s32 gtp_get_fw_info(struct i2c_client *, struct goodix_fw_info *fw_info); +extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int); +extern int gtp_i2c_read(struct i2c_client *, u8 *, int); +extern int gtp_i2c_write(struct i2c_client *, u8 *, int); +extern s32 gtp_fw_startup(struct i2c_client *client); +extern int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf); +/*********** For gt9xx_update End *********/ + +#endif /* _GOODIX_GT9XX_H_ */ diff --git a/drivers/input/touchscreen/gt9xx_2.8/gt9xx_update.c b/drivers/input/touchscreen/gt9xx_2.8/gt9xx_update.c new file mode 100755 index 00000000000..499599af30d --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_2.8/gt9xx_update.c @@ -0,0 +1,2092 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 2.8.0.1 + * Release Date: 2017/11/24 + */ + +#include +#include "gt9xx.h" + +#include +#include +#include +#include + +#define GUP_REG_HW_INFO 0x4220 +#define GUP_REG_FW_MSG 0x41E4 +#define GUP_REG_PID_VID 0x8140 + +#define FIRMWARE_NAME_LEN_MAX 256 +#define GOODIX_FIRMWARE_FILE_NAME "goodix_firmware.bin" +#define GOODIX_CONFIG_FILE_NAME "goodix_config.cfg" + +#define FW_HEAD_LENGTH 14 +#define FW_SECTION_LENGTH 0x2000 /* 8K */ +#define FW_DSP_ISP_LENGTH 0x1000 /* 4K */ +#define FW_DSP_LENGTH 0x1000 /* 4K */ +#define FW_BOOT_LENGTH 0x800 /* 2K */ +#define FW_SS51_LENGTH (4 * FW_SECTION_LENGTH) /* 32K */ +#define FW_BOOT_ISP_LENGTH 0x800 /* 2k */ +#define FW_GLINK_LENGTH 0x3000 /* 12k */ +#define FW_GWAKE_LENGTH (4 * FW_SECTION_LENGTH) /* 32k */ + +#define PACK_SIZE 256 +#define MAX_FRAME_CHECK_TIME 5 + + +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 + +#pragma pack(1) +struct st_fw_head { + u8 hw_info[4]; /* hardware info */ + u8 pid[8]; /* product id */ + u16 vid; /* version id */ +}; +#pragma pack() + +struct st_update_msg { + u8 fw_damaged; + u8 fw_flag; + const u8 *fw_data; + struct file *cfg_file; + struct st_fw_head ic_fw_msg; + u32 fw_total_len; + u32 fw_burned_len; + const struct firmware *fw; +} update_msg; + +struct st_update_msg update_msg; + +u16 show_len; +u16 total_len; + +static u8 gup_burn_fw_gwake_section(struct i2c_client *client, + u8 *fw_section, u16 start_addr, + u32 len, u8 bank_cmd); + +static s32 gup_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + u8 drv_cfg_version; + u8 flash_cfg_version; + struct goodix_config_data *cfg = &ts->pdata->config; + + if (cfg->length < GTP_CONFIG_MIN_LENGTH) { + dev_err(&ts->client->dev, + "No valid config with sensor_ID(%d) ", + sensor_id); + + return -EPERM; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + dev_dbg(&ts->client->dev, + "CFG_GROUP%d Config Version: %d, IC Config Version: %d", + sensor_id, cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); + + flash_cfg_version = opr_buf[0]; + drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; + + if (flash_cfg_version < 90 && + flash_cfg_version > drv_cfg_version) + cfg->data[GTP_ADDR_LENGTH] = 0x00; + } else { + dev_err(&ts->client->dev, + "Failed to get ic config version!No config sent!"); + return -EPERM; + } + + ret = gtp_send_cfg(ts->client); + if (ret < 0) + dev_err(&ts->client->dev, "Send config error."); + else + usleep_range(10000, 11000); + + /* restore config vrsion */ + cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; + + return 0; +} + + +static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len) +{ + s32 i = 0; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + + for (i = 0; i < 5; i++) { + if (gtp_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) + break; + } + + if (i >= 5) { + dev_err(&client->dev, + "Read data from 0x%02x%02x failed!", + msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) +{ + s32 i = 0; + u8 msg[3]; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + msg[2] = val; + + for (i = 0; i < 5; i++) { + if (gtp_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) + break; + } + + if (i >= 5) { + dev_err(&client->dev, + "Set data to 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_get_ic_fw_msg(struct i2c_client *client) +{ + s32 ret = -1; + u8 retry = 0; + u8 buf[16]; + u8 i; + + /* step1:get hardware info */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, + &buf[GTP_ADDR_LENGTH], 4); + if (FAIL == ret) { + dev_err(&client->dev, "[get_ic_fw_msg]get hw_info failed,exit"); + return FAIL; + } + + /* buf[2~5]: 00 06 90 00 + * hw_info: 00 90 06 00 + */ + for (i = 0; i < 4; i++) + update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; + dev_dbg(&client->dev, + "IC Hardware info:%02x%02x%02x%02x", + update_msg.ic_fw_msg.hw_info[0], + update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], + update_msg.ic_fw_msg.hw_info[3]); + /* step2:get firmware message */ + for (retry = 0; retry < 2; retry++) { + ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); + if (FAIL == ret) { + dev_err(&client->dev, "Read firmware message fail."); + return ret; + } + + update_msg.fw_damaged = buf[GTP_ADDR_LENGTH]; + if ((0xBE != update_msg.fw_damaged) && (!retry)) { + dev_info(&client->dev, "The check sum in ic is error."); + dev_info(&client->dev, "The IC will be updated by force."); + continue; + } + break; + } + dev_dbg(&client->dev, + "IC force update flag:0x%x", update_msg.fw_damaged); + + /* step3:get pid & vid */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, + &buf[GTP_ADDR_LENGTH], 6); + if (FAIL == ret) { + dev_err(&client->dev, "[get_ic_fw_msg]get pid & vid failed,exit"); + return FAIL; + } + + memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); + memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); + dev_dbg(&client->dev, "IC Product id:%s", update_msg.ic_fw_msg.pid); + + /* GT9XX PID MAPPING */ + /*|-----FLASH-----RAM-----| + *|------918------918-----| + *|------968------968-----| + *|------913------913-----| + *|------913P-----913P----| + *|------927------927-----| + *|------927P-----927P----| + *|------9110-----9110----| + *|------9110P----9111----|*/ + if (update_msg.ic_fw_msg.pid[0] != 0) { + if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) { + dev_dbg(&client->dev, "IC Mapping Product id:%s", + update_msg.ic_fw_msg.pid); + memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); + } + } + + update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] + + (buf[GTP_ADDR_LENGTH + 5] << 8); + dev_dbg(&client->dev, "IC version id:%04x", update_msg.ic_fw_msg.vid); + + return SUCCESS; +} + +s32 gup_enter_update_mode(struct i2c_client *client) +{ + s32 ret = -1; + s32 retry = 0; + u8 rd_buf[3]; + + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + /* step1:RST output low last at least 2ms */ + if (!gpio_is_valid(ts->pdata->rst_gpio)) { + dev_err(&ts->client->dev, "update failed, no rst pin\n"); + return FAIL; + } + gpio_direction_output(ts->pdata->rst_gpio, 0); + usleep_range(2000, 3000); + + /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */ + gtp_int_output(ts, client->addr == 0x14); + usleep_range(2000, 3000); + + /* step3:RST output high reset guitar */ + gpio_direction_output(ts->pdata->rst_gpio, 1); + + /* 20121211 modify start */ + usleep_range(5000, 6000); + while (retry++ < 200) { + /* step4:Hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_dbg(&client->dev, + "Hold ss51 & dsp I2C error,retry:%d", + retry); + continue; + } + + /* step5:Confirm hold */ + ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); + if (ret <= 0) { + dev_dbg(&client->dev, + "Hold ss51 & dsp I2C error,retry:%d", + retry); + continue; + } + if (0x0C == rd_buf[GTP_ADDR_LENGTH]) { + dev_dbg(&client->dev, "Hold ss51 & dsp confirm SUCCESS"); + break; + } + dev_dbg(&client->dev, + "Hold ss51 & dsp confirm 0x4180 failed,value:%d", + rd_buf[GTP_ADDR_LENGTH]); + } + if (retry >= 200) { + dev_err(&client->dev, "Enter update Hold ss51 failed."); + return FAIL; + } + + /* step6:DSP_CK and DSP_ALU_CK PowerOn */ + ret = gup_set_ic_msg(client, 0x4010, 0x00); + + /* 20121211 modify end */ + return ret; +} + +void gup_leave_update_mode(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts->pdata->int_sync && ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_input); + else if (ts->pdata->int_sync && gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_input(ts->pdata->irq_gpio); + dev_dbg(&client->dev, "[leave_update_mode]reset chip."); + gtp_reset_guitar(i2c_connect_client, 20); +} + +static u8 gup_enter_update_judge(struct i2c_client *client, + struct st_fw_head *fw_head) +{ + u16 u16_tmp; + s32 i = 0; + u32 fw_len = 0; + s32 pid_cmp_len = 0; + + u16_tmp = fw_head->vid; + fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); + + dev_info(&client->dev, "FILE HARDWARE INFO:%*ph\n", 4, + &fw_head->hw_info[0]); + dev_info(&client->dev, "FILE PID:%s\n", fw_head->pid); + dev_info(&client->dev, "FILE VID:%04x\n", fw_head->vid); + + dev_info(&client->dev, "IC HARDWARE INFO:%*ph\n", 4, + &update_msg.ic_fw_msg.hw_info[0]); + dev_info(&client->dev, "IC PID:%s\n", update_msg.ic_fw_msg.pid); + dev_info(&client->dev, "IC VID:%04x\n", update_msg.ic_fw_msg.vid); + + if (!memcmp(fw_head->pid, "9158", 4) && + !memcmp(update_msg.ic_fw_msg.pid, "915S", 4)) { + dev_info(&client->dev, "Update GT915S to GT9158 directly!"); + return SUCCESS; + } + /* First two conditions */ + if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, + sizeof(update_msg.ic_fw_msg.hw_info))) { + fw_len = 42 * 1024; + } else { + fw_len = fw_head->hw_info[3]; + fw_len += (((u32)fw_head->hw_info[2]) << 8); + fw_len += (((u32)fw_head->hw_info[1]) << 16); + fw_len += (((u32)fw_head->hw_info[0]) << 24); + } + if (update_msg.fw_total_len != fw_len) { + dev_err(&client->dev, + "Inconsistent firmware size, Update aborted!"); + dev_err(&client->dev, + " Default size: %d(%dK), actual size: %d(%dK)", + fw_len, fw_len/1024, update_msg.fw_total_len, + update_msg.fw_total_len/1024); + return FAIL; + } + dev_info(&client->dev, "Firmware length:%d(%dK)", + update_msg.fw_total_len, + update_msg.fw_total_len/1024); + + if (update_msg.fw_damaged != 0xBE) { + dev_info(&client->dev, "FW chksum error,need enter update."); + return SUCCESS; + } + + /* 20130523 start */ + if (strlen(update_msg.ic_fw_msg.pid) < 3) { + dev_info(&client->dev, "Illegal IC pid, need enter update"); + return SUCCESS; + } + + /* check pid legality */ + for (i = 0; i < 3; i++) { + if (!isdigit(update_msg.ic_fw_msg.pid[i])) { + dev_info(&client->dev, + "Illegal IC pid, need enter update"); + return SUCCESS; + } + } + /* 20130523 end */ + + pid_cmp_len = strlen(fw_head->pid); + if (pid_cmp_len < strlen(update_msg.ic_fw_msg.pid)) + pid_cmp_len = strlen(update_msg.ic_fw_msg.pid); + + if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, pid_cmp_len)) || + (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) || + (!memcmp(fw_head->pid, "91XX", 4))) { + if (!memcmp(fw_head->pid, "91XX", 4)) + dev_dbg(&client->dev, + "Force none same pid update mode."); + else + dev_dbg(&client->dev, "Get the same pid."); + + /* The third condition */ + if (fw_head->vid != update_msg.ic_fw_msg.vid) { + dev_info(&client->dev, "Need enter update."); + return SUCCESS; + } + dev_err(&client->dev, "File VID == Ic VID, update aborted!"); + } else { + dev_err(&client->dev, "File PID != Ic PID, update aborted!"); + } + + return FAIL; +} + +static int gup_update_config(struct i2c_client *client) +{ + s32 ret = 0; + s32 i = 0; + s32 file_cfg_len = 0; + u8 *file_config; + const struct firmware *fw_cfg; + + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + ret = request_firmware(&fw_cfg, GOODIX_CONFIG_FILE_NAME, + &client->dev); + if (ret < 0) { + dev_err(&client->dev, + "Cannot get config file - %s (%d)\n", + GOODIX_CONFIG_FILE_NAME, ret); + return -EFAULT; + } + if (!fw_cfg || !fw_cfg->data || fw_cfg->size > PAGE_SIZE) { + dev_err(&client->dev, "config file illegal"); + ret = -EFAULT; + goto cfg_fw_err; + } + + dev_dbg(&client->dev, "config firmware file len:%zu", fw_cfg->size); + + file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!file_config) { + dev_err(&ts->client->dev, "failed alloc memory"); + ret = -ENOMEM; + goto cfg_fw_err; + } + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + file_cfg_len = gtp_ascii_to_array(fw_cfg->data, fw_cfg->size, + &file_config[GTP_ADDR_LENGTH]); + if (file_cfg_len < 0) { + dev_err(&client->dev, "failed covert ascii to hex"); + ret = -EFAULT; + goto update_cfg_file_failed; + } + + GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); + + i = 0; + while (i++ < 5) { + ret = gtp_i2c_write(client, file_config, file_cfg_len + 2); + if (ret > 0) { + dev_info(&client->dev, "Send config SUCCESS."); + msleep(500); + break; + } + dev_err(&ts->client->dev, "Send config i2c error."); + } + +update_cfg_file_failed: + kfree(file_config); +cfg_fw_err: + release_firmware(fw_cfg); + return ret; +} + +static u8 gup_check_firmware_name(struct i2c_client *client, + u8 **path_p) +{ + u8 len; + u8 *fname; + + if (!(*path_p)) { + *path_p = GOODIX_FIRMWARE_FILE_NAME; + return 0; + } + + len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX); + if (len >= FIRMWARE_NAME_LEN_MAX) { + dev_err(&client->dev, "firmware name too long!"); + return -EINVAL; + } + + fname = strrchr(*path_p, '/'); + if (fname) { + fname = fname + 1; + *path_p = fname; + } + + return 0; +} + +static u8 gup_get_update_file(struct i2c_client *client, + struct st_fw_head *fw_head, u8 *path) +{ + s32 ret = 0; + s32 i = 0; + s32 fw_checksum = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts->pdata->auto_update_cfg) { + ret = gup_update_config(client); + if (ret <= 0) + dev_err(&client->dev, "Update config failed."); + } + + ret = gup_check_firmware_name(client, &path); + if (ret < 0) + return FAIL; + + ret = request_firmware(&update_msg.fw, path, &client->dev); + if (ret < 0) { + dev_err(&client->dev, "Failed get firmware:%d\n", ret); + return FAIL; + } + + dev_info(&client->dev, "FW File: %s size=%zu", + path, update_msg.fw->size); + update_msg.fw_data = update_msg.fw->data; + update_msg.fw_total_len = update_msg.fw->size; + + if (update_msg.fw_total_len < + FW_HEAD_LENGTH + FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH) { + dev_err(&client->dev, + "INVALID bin file(size: %d), update aborted.", + update_msg.fw_total_len); + goto invalied_fw; + } + + update_msg.fw_total_len -= FW_HEAD_LENGTH; + + dev_dbg(&client->dev, "Bin firmware actual size: %d(%dK)", + update_msg.fw_total_len, update_msg.fw_total_len/1024); + + memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH); + + /* check firmware legality */ + fw_checksum = 0; + for (i = 0; i < update_msg.fw_total_len; i += 2) { + u16 temp; + + temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) + + update_msg.fw_data[FW_HEAD_LENGTH + i + 1]; + fw_checksum += temp; + } + + dev_dbg(&client->dev, "firmware checksum:%x", fw_checksum&0xFFFF); + if (fw_checksum & 0xFFFF) { + dev_err(&client->dev, "Illegal firmware file."); + goto invalied_fw; + } + + return SUCCESS; + +invalied_fw: + update_msg.fw_data = NULL; + update_msg.fw_total_len = 0; + release_firmware(update_msg.fw); + return FAIL; +} + +static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, + u16 start_addr, u16 total_length) +{ + s32 ret = 0; + u16 burn_addr = start_addr; + u16 frame_length = 0; + u16 burn_length = 0; + u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 retry = 0; + + dev_dbg(&client->dev, "Begin burn %dk data to addr 0x%x", + total_length / 1024, start_addr); + while (burn_length < total_length) { + dev_dbg(&client->dev, + "B/T:%04d/%04d", burn_length, total_length); + frame_length = ((total_length - burn_length) + > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length); + wr_buf[0] = (u8)(burn_addr>>8); + rd_buf[0] = wr_buf[0]; + wr_buf[1] = (u8)burn_addr; + rd_buf[1] = wr_buf[1]; + memcpy(&wr_buf[GTP_ADDR_LENGTH], + &burn_buf[burn_length], frame_length); + + for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) { + ret = gtp_i2c_write(client, + wr_buf, GTP_ADDR_LENGTH + frame_length); + if (ret <= 0) { + dev_err(&client->dev, + "Write frame data i2c error."); + continue; + } + ret = gtp_i2c_read(client, rd_buf, + GTP_ADDR_LENGTH + frame_length); + if (ret <= 0) { + dev_err(&client->dev, + "Read back frame data i2c error."); + continue; + } + if (memcmp(&wr_buf[GTP_ADDR_LENGTH], + &rd_buf[GTP_ADDR_LENGTH], frame_length)) { + dev_err(&client->dev, + "Check frame data fail,not equal."); + dev_dbg(&client->dev, "write array:"); + GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], + frame_length); + dev_dbg(&client->dev, "read array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], + frame_length); + continue; + } else { + /* dev_dbg(&client->dev, + * "Check frame data success."); + */ + break; + } + } + if (retry >= MAX_FRAME_CHECK_TIME) { + dev_err(&client->dev, + "Burn frame data time out,exit."); + return FAIL; + } + burn_length += frame_length; + burn_addr += frame_length; + } + + return SUCCESS; +} + +static u8 gup_load_section_file(u8 *buf, u32 offset, u16 length, u8 set_or_end) +{ + if (!update_msg.fw_data || + update_msg.fw_total_len < offset + length) { + dev_err(&i2c_connect_client->dev, + "cannot load section data. fw_len=%d read end=%d\n", + update_msg.fw_total_len, + FW_HEAD_LENGTH + offset + length); + return FAIL; + } + + if (SEEK_SET == set_or_end) { + memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset], + length); + } else { + /* seek end */ + memcpy(buf, &update_msg.fw_data[update_msg.fw_total_len + + FW_HEAD_LENGTH - offset], length); + } + + return SUCCESS; +} + +static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src, + u16 start_rd_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + s32 ret = 0; + u16 recall_addr = start_rd_addr; + u16 recall_length = 0; + u16 frame_length = 0; + + while (recall_length < chk_length) { + frame_length = ((chk_length - recall_length) + > PACK_SIZE) ? PACK_SIZE : + (chk_length - recall_length); + ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); + if (ret <= 0) { + dev_err(&client->dev, "recall i2c error,exit"); + return FAIL; + } + + if (memcmp(&rd_buf[GTP_ADDR_LENGTH], + &chk_src[recall_length], frame_length)) { + dev_err(&client->dev, "Recall frame data fail,not equal."); + dev_dbg(&client->dev, "chk_src array:"); + GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length); + dev_dbg(&client->dev, "recall array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); + return FAIL; + } + + recall_length += frame_length; + recall_addr += frame_length; + } + dev_dbg(&client->dev, + "Recall check %dk firmware success.", + (chk_length/1024)); + + return SUCCESS; +} + +static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, + u16 start_addr, u8 bank_cmd) +{ + s32 ret = 0; + u8 rd_buf[5]; + + /* step1:hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]hold ss51 & dsp fail."); + return FAIL; + } + + /* step2:set scramble */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]set scramble fail."); + return FAIL; + } + + /* step3:select bank */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, + (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step4:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + /* step5:burn 8k fw section */ + ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_section]burn fw_section fail."); + return FAIL; + } + + /* step6:hold ss51 & release dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]hold ss51 & release dsp fail."); + return FAIL; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step7:send burn cmd to move data to flash from sram */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]send burn cmd fail."); + return FAIL; + } + dev_dbg(&client->dev, + "[burn_fw_section]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]Get burn state fail"); + return FAIL; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_section]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:select bank */ + ret = gup_set_ic_msg(client, + _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4) & 0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step9:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + /* step10:recall 8k fw section */ + ret = gup_recall_check(client, + fw_section, start_addr, FW_SECTION_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_section]recall check %dk firmware fail.", + FW_SECTION_LENGTH / 1024); + return FAIL; + } + + /* step11:disable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]disable accessing code fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_dsp_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp_isp = NULL; + u8 retry = 0; + + dev_info(&client->dev, "[burn_dsp_isp]Begin burn dsp isp---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_dsp_isp]step1:alloc memory"); + while (retry++ < 5) { + fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL); + if (fw_dsp_isp == NULL) { + continue; + } else { + dev_info(&client->dev, + "[burn_dsp_isp]Alloc %dk byte memory success.", + FW_DSP_ISP_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_dsp_isp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load dsp isp file data */ + dev_dbg(&client->dev, "[burn_dsp_isp]step2:load dsp isp file data"); + ret = gup_load_section_file(fw_dsp_isp, FW_DSP_ISP_LENGTH, + FW_DSP_ISP_LENGTH, SEEK_END); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_dsp_isp]load firmware dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + /* step3:disable wdt,clear cache enable */ + dev_dbg(&client->dev, + "[burn_dsp_isp]step3:disable wdt,clear cache enable"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]disable wdt fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_dsp_isp]clear cache enable fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step4:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_dsp_isp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step5:set boot from sram */ + dev_dbg(&client->dev, "[burn_dsp_isp]step5:set boot from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]set boot from sram fail"); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step6:software reboot */ + dev_dbg(&client->dev, "[burn_dsp_isp]step6:software reboot"); + ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]software reboot fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step7:select bank2 */ + dev_dbg(&client->dev, "[burn_dsp_isp]step7:select bank2"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]select bank2 fail"); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step8:enable accessing code */ + dev_dbg(&client->dev, "[burn_dsp_isp]step8:enable accessing code"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_dsp_isp]enable accessing code fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step9:burn 4k dsp_isp */ + dev_dbg(&client->dev, "[burn_dsp_isp]step9:burn 4k dsp_isp"); + ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, "[burn_dsp_isp]burn dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + /* step10:set scramble */ + dev_dbg(&client->dev, "[burn_dsp_isp]step10:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + update_msg.fw_burned_len += FW_DSP_ISP_LENGTH; + dev_dbg(&client->dev, "[burn_dsp_isp]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_dsp_isp: + kfree(fw_dsp_isp); + + return ret; +} + +static u8 gup_burn_fw_ss51(struct i2c_client *client) +{ + u8 *fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + dev_info(&client->dev, "[burn_fw_ss51]Begin burn ss51 firmware---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_ss51]step1:alloc memory"); + while (retry++ < 5) { + fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_ss51 == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_ss51]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH / 1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_ss51]Alloc memory fail,exit."); + return FAIL; + } + + dev_info(&client->dev, "[burn_fw_ss51]Reset first 8K of ss51 to 0xFF."); + dev_dbg(&client->dev, "[burn_fw_ss51]step2: reset bank0 0xC000~0xD000"); + memset(fw_ss51, 0xFF, FW_SECTION_LENGTH); + + /* step3:clear control flag */ + dev_dbg(&client->dev, "[burn_fw_ss51]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_ss51]clear control flag fail."); + ret = FAIL; + goto exit_burn_fw_ss51; + } + + /* step4:burn ss51 firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_ss51; + } + + /* step5:load ss51 firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step5:load ss51 firmware section 2 file data"); + ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + /* step6:burn ss51 firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step6:burn ss51 firmware section 2"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + /* step7:load ss51 firmware section 3 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step7:load ss51 firmware section 3 file data"); + ret = gup_load_section_file(fw_ss51, 2 * FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + /* step8:burn ss51 firmware section 3 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step8:burn ss51 firmware section 3"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + /* step9:load ss51 firmware section 4 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step9:load ss51 firmware section 4 file data"); + ret = gup_load_section_file(fw_ss51, 3 * FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + /* step10:burn ss51 firmware section 4 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step10:burn ss51 firmware section 4"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + update_msg.fw_burned_len += (FW_SECTION_LENGTH*4); + dev_dbg(&client->dev, "[burn_fw_ss51]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_ss51: + kfree(fw_ss51); + return ret; +} + +static u8 gup_burn_fw_dsp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + dev_info(&client->dev, "[burn_fw_dsp]Begin burn dsp firmware---->>"); + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_dsp]step1:alloc memory"); + while (retry++ < 5) { + fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL); + if (fw_dsp == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_dsp]Alloc %dk byte memory success.", + FW_SECTION_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_dsp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step2:load firmware dsp"); + ret = gup_load_section_file(fw_dsp, 4 * FW_SECTION_LENGTH, + FW_DSP_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, "[burn_fw_dsp]load firmware dsp fail."); + goto exit_burn_fw_dsp; + } + + /* step3:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_dsp]step3:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step4:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step5:set scramble */ + dev_dbg(&client->dev, "[burn_fw_dsp]step5:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step6:release ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step6:release ss51 & dsp"); + ret = gup_set_ic_msg( + client, _rRW_MISCTL__SWRST_B0_, 0x04);/* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + /* must delay */ + usleep_range(1000, 1100); + + /* step7:burn 4k dsp firmware */ + dev_dbg(&client->dev, "[burn_fw_dsp]step7:burn 4k dsp firmware"); + ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, "[burn_fw_dsp]burn fw_section fail."); + goto exit_burn_fw_dsp; + } + + /* step8:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_dsp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]send burn cmd fail."); + goto exit_burn_fw_dsp; + } + dev_dbg(&client->dev, "[burn_fw_dsp]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]Get burn state fail"); + goto exit_burn_fw_dsp; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_dsp]Get burn state:%d.", + rd_buf[GTP_ADDR_LENGTH]); */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step9:recall check 4k dsp firmware */ + dev_dbg(&client->dev, + "[burn_fw_dsp]step9:recall check 4k dsp firmware"); + ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_dsp]recall check 4k dsp firmware fail."); + goto exit_burn_fw_dsp; + } + + update_msg.fw_burned_len += FW_DSP_LENGTH; + dev_dbg(&client->dev, "[burn_fw_dsp]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_dsp: + kfree(fw_dsp); + + return ret; +} + +static u8 gup_burn_fw_boot(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_boot = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + dev_info(&client->dev, + "[burn_fw_boot]Begin burn bootloader firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_boot]step1:Alloc memory"); + while (retry++ < 5) { + fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL); + if (fw_boot == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_boot]Alloc %dk byte memory success.", + FW_BOOT_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_boot]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware bootloader */ + dev_dbg(&client->dev, "[burn_fw_boot]step2:load firmware bootloader"); + ret = gup_load_section_file(fw_boot, + 4 * FW_SECTION_LENGTH + FW_DSP_LENGTH, + FW_BOOT_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_boot]load firmware bootcode fail."); + goto exit_burn_fw_boot; + } + + /* step3:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_boot]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step4:set scramble */ + dev_dbg(&client->dev, "[burn_fw_boot]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step5:hold ss51 & release dsp */ + dev_dbg(&client->dev, "[burn_fw_boot]step5:hold ss51 & release dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + /* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]release ss51 & dsp fail"); + ret = FAIL; + goto exit_burn_fw_boot; + } + /* must delay */ + usleep_range(1000, 1100); + + /* step6:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_boot]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step6:burn 2k bootloader firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot]step6:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, "[burn_fw_boot]burn fw_boot fail."); + goto exit_burn_fw_boot; + } + + /* step7:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_boot]step7:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]send burn cmd fail."); + goto exit_burn_fw_boot; + } + dev_dbg(&client->dev, + "[burn_fw_boot]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot]Get burn state fail"); + goto exit_burn_fw_boot; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_boot]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:recall check 2k bootloader firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot]step8:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_boot]recall check 2k bootcode firmware fail"); + goto exit_burn_fw_boot; + } + + update_msg.fw_burned_len += FW_BOOT_LENGTH; + dev_dbg(&client->dev, "[burn_fw_boot]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_boot: + kfree(fw_boot); + + return ret; +} +static u8 gup_burn_fw_boot_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_boot_isp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + if (update_msg.fw_burned_len >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the boot_isp code!"); + return SUCCESS; + } + dev_info(&client->dev, + "[burn_fw_boot_isp]Begin burn boot_isp firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step1:Alloc memory"); + while (retry++ < 5) { + fw_boot_isp = kzalloc(FW_BOOT_ISP_LENGTH, GFP_KERNEL); + if (fw_boot_isp == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Alloc %dk byte memory success.", + (FW_BOOT_ISP_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, + "[burn_fw_boot_isp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware bootloader */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step2:load firmware bootloader isp"); + /* ret = gup_load_section_file(fw_boot_isp, + * (4*FW_SECTION_LENGTH+FW_DSP_LENGTH + + * FW_BOOT_LENGTH+FW_DSP_ISP_LENGTH), FW_BOOT_ISP_LENGTH, SEEK_SET); + */ + ret = gup_load_section_file(fw_boot_isp, (update_msg.fw_burned_len - FW_DSP_ISP_LENGTH), + FW_BOOT_ISP_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_boot_isp]load firmware boot_isp fail."); + goto exit_burn_fw_boot_isp; + } + + /* step3:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]hold ss51 & dsp fail"); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + /* step4:set scramble */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + + /* step5:hold ss51 & release dsp */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step5:hold ss51 & release dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + /* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot_isp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step6:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + /* step7:burn 2k bootload_isp firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step7:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_boot_isp]burn fw_section fail."); + goto exit_burn_fw_boot_isp; + } + + /* step7:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x07); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]send burn cmd fail."); + goto exit_burn_fw_boot_isp; + } + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot_isp]Get burn state fail"); + goto exit_burn_fw_boot_isp; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_boot_isp]Get + * burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:recall check 2k bootload_isp firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step9:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_boot_isp]recall check 2k bootcode_isp firmware fail."); + goto exit_burn_fw_boot_isp; + } + + update_msg.fw_burned_len += FW_BOOT_ISP_LENGTH; + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_boot_isp: + kfree(fw_boot_isp); + + return ret; +} + +static u8 gup_burn_fw_link(struct i2c_client *client) +{ + u8 *fw_link = NULL; + u8 retry = 0; + s32 ret = 0; + u32 offset; + + if (update_msg.fw_burned_len >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the link code!"); + return SUCCESS; + } + dev_info(&client->dev, "[burn_fw_link]Begin burn link firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_link]step1:Alloc memory"); + while (retry++ < 5) { + fw_link = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_link == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_link]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_link]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware link section 1 */ + dev_dbg(&client->dev, + "[burn_fw_link]step2:load firmware link section 1"); + offset = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; + ret = gup_load_section_file(fw_link, offset, FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_link]load firmware link section 1 fail."); + goto exit_burn_fw_link; + } + + /* step3:burn link firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_link]step3:burn link firmware section 1"); + ret = gup_burn_fw_gwake_section( + client, fw_link, 0x9000, FW_SECTION_LENGTH, 0x38); + + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_link]burn link firmware section 1 fail."); + goto exit_burn_fw_link; + } + + /* step4:load link firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_link]step4:load link firmware section 2 file data"); + offset += FW_SECTION_LENGTH; + ret = gup_load_section_file(fw_link, offset, + FW_GLINK_LENGTH - FW_SECTION_LENGTH, SEEK_SET); + + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_link]load link firmware section 2 fail."); + goto exit_burn_fw_link; + } + + /* step5:burn link firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_link]step4:burn link firmware section 2"); + ret = gup_burn_fw_gwake_section(client, + fw_link, 0x9000, FW_GLINK_LENGTH - FW_SECTION_LENGTH, 0x39); + + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_link]burn link firmware section 2 fail."); + goto exit_burn_fw_link; + } + + update_msg.fw_burned_len += FW_GLINK_LENGTH; + dev_dbg(&client->dev, + "[burn_fw_link]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_link: + kfree(fw_link); + + return ret; +} + +static u8 gup_burn_fw_gwake_section(struct i2c_client *client, + u8 *fw_section, u16 start_addr, u32 len, u8 bank_cmd) +{ + s32 ret = 0; + u8 rd_buf[5]; + + /* step1:hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]hold ss51 & dsp fail."); + return FAIL; + } + + /* step2:set scramble */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]set scramble fail."); + return FAIL; + } + + /* step3:hold ss51 & release dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]hold ss51 & release dsp fail."); + return FAIL; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step4:select bank */ + ret = gup_set_ic_msg( + client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step5:burn fw section */ + ret = gup_burn_proc(client, fw_section, start_addr, len); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_app_section]burn fw_section fail."); + return FAIL; + } + + /* step6:send burn cmd to move data to flash from sram */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]send burn cmd fail."); + return FAIL; + } + dev_dbg(&client->dev, + "[burn_fw_section]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]Get burn state fail"); + return FAIL; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_app_section]Get burn state:%d." + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step7:recall fw section */ + ret = gup_recall_check(client, fw_section, start_addr, len); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_app_section]recall check %dk firmware fail.", + len/1024); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_fw_gwake(struct i2c_client *client) +{ + u8 *fw_gwake = NULL; + u8 retry = 0; + s32 ret = 0; + u16 start_index = 4*FW_SECTION_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH + + FW_BOOT_ISP_LENGTH + FW_GLINK_LENGTH;/* 32 + 4 + 2 + 4 = 42K */ + /* u16 start_index; */ + + if (start_index >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the gwake code!"); + return SUCCESS; + } + /* start_index = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; */ + dev_info(&client->dev, + "[burn_fw_gwake]Begin burn gwake firmware---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_gwake]step1:alloc memory"); + while (retry++ < 5) { + fw_gwake = + kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_gwake == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_gwake]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_gwake]Alloc memory fail,exit."); + return FAIL; + } + + /* clear control flag */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]clear control flag fail."); + goto exit_burn_fw_gwake; + } + + /* step2:load app_code firmware section 1 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step2:load app_code firmware section 1 file data"); + ret = gup_load_section_file(fw_gwake, start_index, + FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 1 fail."); + goto exit_burn_fw_gwake; + } + + /* step3:burn app_code firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step3:burn app_code firmware section 1"); + ret = gup_burn_fw_gwake_section(client, + fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3A); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 1 fail."); + goto exit_burn_fw_gwake; + } + + /* step5:load app_code firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step5:load app_code firmware section 2 file data"); + ret = gup_load_section_file(fw_gwake, start_index+FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 2 fail."); + goto exit_burn_fw_gwake; + } + + /* step6:burn app_code firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step6:burn app_code firmware section 2"); + ret = gup_burn_fw_gwake_section(client, + fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3B); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 2 fail."); + goto exit_burn_fw_gwake; + } + + /* step7:load app_code firmware section 3 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step7:load app_code firmware section 3 file data"); + ret = gup_load_section_file(fw_gwake, + start_index + 2 * FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 3 fail."); + goto exit_burn_fw_gwake; + } + + /* step8:burn app_code firmware section 3 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step8:burn app_code firmware section 3"); + ret = gup_burn_fw_gwake_section( + client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3C); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 3 fail."); + goto exit_burn_fw_gwake; + } + + /* step9:load app_code firmware section 4 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step9:load app_code firmware section 4 file data"); + ret = gup_load_section_file(fw_gwake, + start_index + 3 * FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 4 fail."); + goto exit_burn_fw_gwake; + } + + /* step10:burn app_code firmware section 4 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step10:burn app_code firmware section 4"); + ret = gup_burn_fw_gwake_section( + client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3D); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 4 fail."); + goto exit_burn_fw_gwake; + } + + /* update_msg.fw_burned_len += FW_GWAKE_LENGTH; */ + dev_dbg(&client->dev, + "[burn_fw_gwake]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_gwake: + kfree(fw_gwake); + + return ret; +} + +static u8 gup_burn_fw_finish(struct i2c_client *client) +{ + u8 *fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + dev_info(&client->dev, + "[burn_fw_finish]burn first 8K of ss51 and finish update."); + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_finish]step1:alloc memory"); + while (retry++ < 5) { + fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_ss51 == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_finish]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, + "[burn_fw_finish]Alloc memory fail,exit."); + return FAIL; + } + + dev_dbg(&client->dev, "[burn_fw_finish]step2: burn ss51 first 8K."); + ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH, SEEK_SET); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_finish]load ss51 firmware section 1 fail."); + goto exit_burn_fw_finish; + } + + dev_dbg(&client->dev, "[burn_fw_finish]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]clear control flag fail."); + goto exit_burn_fw_finish; + } + + dev_dbg(&client->dev, + "[burn_fw_finish]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if (FAIL == ret) { + dev_err(&client->dev, + "[burn_fw_finish]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_finish; + } + + /* step11:enable download DSP code */ + dev_dbg(&client->dev, + "[burn_fw_finish]step5:enable download DSP code "); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]enable download DSP code fail."); + goto exit_burn_fw_finish; + } + + /* step12:release ss51 & hold dsp */ + dev_dbg(&client->dev, "[burn_fw_finish]step6:release ss51 & hold dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]release ss51 & hold dsp fail."); + goto exit_burn_fw_finish; + } + + if (fw_ss51 != NULL) + kfree(fw_ss51); + return SUCCESS; + +exit_burn_fw_finish: + if (fw_ss51 != NULL) + kfree(fw_ss51); + + return FAIL; +} + +/* return 0 can update, else no update condition */ +static int gup_update_condition_check(struct goodix_ts_data *ts) +{ + if (test_bit(SLEEP_MODE, &ts->flags)) { + dev_info(&ts->client->dev, "Update abort, tp in sleep mode\n"); + return -EINVAL; + } + + return 0; +} +s32 gup_update_proc(void *dir) +{ + s32 ret = 0; + s32 update_ret = FAIL; + u8 retry = 0; + struct st_fw_head fw_head; + struct goodix_ts_data *ts = NULL; + + ts = i2c_get_clientdata(i2c_connect_client); + + dev_dbg(&ts->client->dev, "[update_proc]Begin update ......\n"); + + show_len = 1; + total_len = 100; + + ret = gup_update_condition_check(ts); + if (ret) { + dev_warn(&ts->client->dev, "Update start failed\n"); + return FAIL; + } + + if (test_and_set_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_warn(&ts->client->dev, "FW update may already running\n"); + return FAIL; + } + + ret = gup_get_update_file(i2c_connect_client, &fw_head, (u8 *)dir); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "Failed get valied firmware data\n"); + clear_bit(FW_UPDATE_RUNNING, &ts->flags); + return FAIL; + } + + gtp_work_control_enable(ts, false); + gtp_esd_off(ts); + + ret = gup_get_ic_fw_msg(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, "[update_proc]get ic message fail."); + goto file_fail; + } + + if (ts->force_update || dir) { + dev_dbg(&ts->client->dev, "Enter force update."); + } else { + ret = gup_enter_update_judge(i2c_connect_client, &fw_head); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]Doesn't meet update condition\n"); + goto file_fail; + } + } + + ret = gup_enter_update_mode(ts->client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]enter update mode fail."); + goto update_fail; + } + + while (retry++ < 5) { + show_len = 10; + total_len = 100; + update_msg.fw_burned_len = 0; + ret = gup_burn_dsp_isp(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn dsp isp fail."); + continue; + } + + show_len = 20; + ret = gup_burn_fw_gwake(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn app_code firmware fail."); + continue; + } + + show_len = 30; + ret = gup_burn_fw_ss51(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn ss51 firmware fail."); + continue; + } + + show_len = 40; + ret = gup_burn_fw_dsp(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn dsp firmware fail."); + continue; + } + + show_len = 50; + ret = gup_burn_fw_boot(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn bootloader firmware fail."); + continue; + } + show_len = 60; + + ret = gup_burn_fw_boot_isp(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn boot_isp firmware fail."); + continue; + } + + show_len = 70; + ret = gup_burn_fw_link(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn link firmware fail."); + continue; + } + + show_len = 80; + ret = gup_burn_fw_finish(i2c_connect_client); + if (FAIL == ret) { + dev_err(&ts->client->dev, + "[update_proc]burn finish fail."); + continue; + } + show_len = 90; + dev_info(&ts->client->dev, "[update_proc]UPDATE SUCCESS."); + retry = 0; + break; + } + + if (retry >= 5) { + dev_err(&ts->client->dev, + "[update_proc]retry timeout,UPDATE FAIL."); + update_ret = FAIL; + } else { + update_ret = SUCCESS; + } + +update_fail: + dev_dbg(&ts->client->dev, "[update_proc]leave update mode."); + gup_leave_update_mode(i2c_connect_client); + + msleep(GTP_100_DLY_MS); + + if (SUCCESS == update_ret) { + dev_info(&ts->client->dev, + "firmware error auto update, resent config!\n"); + gup_init_panel(ts); + } + gtp_get_fw_info(ts->client, &ts->fw_info); + +file_fail: + + update_msg.fw_data = NULL; + update_msg.fw_total_len = 0; + release_firmware(update_msg.fw); + + clear_bit(FW_UPDATE_RUNNING, &ts->flags); + gtp_work_control_enable(ts, true); + gtp_esd_on(ts); + total_len = 100; + ts->force_update = false; + if (SUCCESS == update_ret) { + show_len = 100; + clear_bit(FW_ERROR, &ts->flags); + return SUCCESS; + } else { + show_len = 200; + return FAIL; + } +} + +u8 gup_init_update_proc(struct goodix_ts_data *ts) +{ + struct task_struct *thread = NULL; + + dev_info(&ts->client->dev, "Ready to run update thread."); + + thread = kthread_run(gup_update_proc, + (void *)NULL, "guitar_update"); + + if (IS_ERR(thread)) { + dev_err(&ts->client->dev, + "Failed to create update thread.\n"); + return -EPERM; + } + + return 0; +} -- 2.25.1 From 0ba5de3d5c02aed8e20c8ceb8f2e647a52645a56 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 30 Apr 2020 09:01:18 -0400 Subject: [PATCH 27/76] MeiG Liangdi: modify batterydata to 2500mAH Change-Id: I6a94abe7b024b907caa87e5c4dc862db836eee60 --- arch/arm/boot/dts/qcom/batterydata-qrd-skua-4v35-2000mah.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/batterydata-qrd-skua-4v35-2000mah.dtsi b/arch/arm/boot/dts/qcom/batterydata-qrd-skua-4v35-2000mah.dtsi index 6013efec43f..9231f4b4c2a 100644 --- a/arch/arm/boot/dts/qcom/batterydata-qrd-skua-4v35-2000mah.dtsi +++ b/arch/arm/boot/dts/qcom/batterydata-qrd-skua-4v35-2000mah.dtsi @@ -15,7 +15,7 @@ qcom,qrd-skua-4v35-2000mAh-data { qcom,batt-id-kohm = <200>; qcom,chg-term-ua = <100000>; qcom,default-rbatt-mohm = <146>; - qcom,fcc-mah = <2000>; + qcom,fcc-mah = <2500>; qcom,max-voltage-uv = <4350000>; qcom,rbatt-capacitive-mohm = <50>; qcom,v-cutoff-uv = <3400000>; -- 2.25.1 From a80c8ff6d7be075882c662a64b242762de54e764 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 30 Apr 2020 09:06:23 -0400 Subject: [PATCH 28/76] MeiG Liangdi: Add new battery drain curve data file Change-Id: I941af9291d875f251100576478fc0dbb14c1b53b --- .../qcom/batterydata-mtp-4v35-2500mah.dtsi | 118 ++++++++++++++++++ arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 9 +- include/linux/batterydata-lib.h | 2 +- 3 files changed, 124 insertions(+), 5 deletions(-) create mode 100755 arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi diff --git a/arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi b/arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi new file mode 100755 index 00000000000..6f6e58ec0e0 --- /dev/null +++ b/arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi @@ -0,0 +1,118 @@ +/* Copyright (c) 2014, 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. + */ +qcom,mtp-4v35-2500mAh { + qcom,battery-type = "mtp_4v35_2500mAh"; + qcom,batt-id-kohm = <100>; + qcom,chg-term-ua = <75000>; + qcom,default-rbatt-mohm = <212>; + qcom,fcc-mah = <2500>; + qcom,max-voltage-uv = <4350000>; + qcom,rbatt-capacitive-mohm = <50>; + qcom,v-cutoff-uv = <3400000>; + + qcom,fcc-temp-lut { + qcom,lut-col-legend = <(-20) 0 25 40 60>; + qcom,lut-data = <2552 2561 2564 2563 2554>; + }; + + qcom,ibat-acc-lut { + qcom,lut-col-legend = <(-20) 0 25>; + qcom,lut-row-legend = <0 500 1000 1500 2000>; + qcom,lut-data = <2514 2534 2537>, + <12 1942 2536>, + <6 976 2413>, + <9 333 2033>, + <11 84 1490>; + }; + + qcom,pc-temp-ocv-lut { + qcom,lut-col-legend = <(-20) 0 25 40 60>; + qcom,lut-row-legend = <100 95 90 85 80>, + <75 70 65 60 55>, + <50 45 40 35 30>, + <25 20 16 13 11>, + <10 9 8 7 6>, + <5 4 3 2 1>, + <0>; + qcom,lut-data = <4324 4325 4322 4319 4314>, + <4200 4242 4254 4254 4250>, + <4118 4179 4198 4198 4196>, + <4026 4120 4144 4144 4142>, + <3963 4071 4093 4093 4091>, + <3915 3999 4048 4044 4042>, + <3879 3945 3984 3996 3998>, + <3852 3908 3946 3956 3956>, + <3830 3872 3902 3912 3914>, + <3810 3840 3864 3865 3866>, + <3792 3814 3834 3836 3837>, + <3774 3794 3810 3812 3814>, + <3756 3779 3790 3792 3794>, + <3740 3766 3773 3774 3776>, + <3722 3753 3760 3758 3756>, + <3702 3739 3748 3742 3732>, + <3682 3724 3732 3725 3713>, + <3663 3712 3713 3706 3693>, + <3648 3701 3694 3686 3674>, + <3640 3692 3686 3678 3667>, + <3632 3686 3684 3676 3666>, + <3624 3681 3682 3675 3664>, + <3614 3674 3680 3673 3662>, + <3602 3666 3676 3670 3660>, + <3588 3654 3670 3664 3652>, + <3570 3637 3654 3648 3634>, + <3544 3608 3622 3612 3596>, + <3508 3563 3570 3560 3543>, + <3449 3496 3498 3490 3474>, + <3356 3394 3394 3386 3373>, + <3200 3200 3200 3200 3200>; + }; + + qcom,rbatt-sf-lut { + qcom,lut-col-legend = <(-20) 0 25 40 60>; + qcom,lut-row-legend = <100 95 90 85 80>, + <75 70 65 60 55>, + <50 45 40 35 30>, + <25 20 16 13 11>, + <10 9 8 7 6>, + <5 4 3 2 1>; + qcom,lut-data = <1009 295 100 82 75>, + <1008 295 100 81 75>, + <953 293 101 83 76>, + <888 288 105 86 78>, + <854 290 108 89 80>, + <834 272 114 92 82>, + <837 262 110 93 84>, + <850 260 110 96 86>, + <883 258 101 92 85>, + <928 254 97 81 75>, + <988 254 96 80 75>, + <1058 256 97 82 77>, + <1138 262 98 83 80>, + <1243 271 98 84 80>, + <1373 284 99 83 78>, + <1544 306 101 82 74>, + <1771 337 102 83 76>, + <2033 371 103 85 77>, + <2277 393 101 83 76>, + <2384 386 101 82 76>, + <2539 401 102 83 77>, + <2722 419 105 86 78>, + <2931 439 108 89 81>, + <3191 464 111 92 83>, + <3497 491 115 93 84>, + <3868 523 116 92 82>, + <4310 564 112 89 79>, + <4918 635 112 89 80>, + <5762 744 116 90 81>, + <6982 925 124 94 83>; + }; +}; \ No newline at end of file diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index f83068fa56f..5e175a3e692 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -198,7 +198,7 @@ touchscreen-size-y = <800>; touchscreen-max-w = <512>; touchscreen-max-p = <512>; - touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158��KEY_MENU=139*/ + touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158£¬KEY_MENU=139*/ goodix,slide-wakeup = <0>; goodix,type-a-report = <0>; @@ -376,7 +376,7 @@ pinctrl-0 = <&nrf52_active>; }; -/*&spi_0 { +&spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; reg = <0>; @@ -394,7 +394,7 @@ pinctrl-2 = <&nrf_release>; status = "ok"; }; -};*/ +}; / { mtp_batterydata: qcom,battery-data { @@ -402,7 +402,8 @@ qcom,vref-batt-therm = <1800000>; //#include "batterydata-palladium.dtsi" - #include "batterydata-qrd-skua-4v35-2000mah.dtsi" + //#include "batterydata-qrd-skua-4v35-2000mah.dtsi" + #include "batterydata-mtp-4v35-2500mah.dtsi" }; }; diff --git a/include/linux/batterydata-lib.h b/include/linux/batterydata-lib.h index 39517f83c87..b3d485f30e7 100644 --- a/include/linux/batterydata-lib.h +++ b/include/linux/batterydata-lib.h @@ -24,7 +24,7 @@ #define PC_TEMP_ROWS 31 #define PC_TEMP_COLS 8 -#define ACC_IBAT_ROWS 4 +#define ACC_IBAT_ROWS 5 //4 //modify by liangdi for new batterydata file 20200428 #define ACC_TEMP_COLS 3 #define MAX_SINGLE_LUT_COLS 20 -- 2.25.1 From cd51fa25dce5acddad2e83c6c59da635afbfbe14 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 1 May 2020 15:28:19 -0400 Subject: [PATCH 29/76] kernel/msm-3.18: Disable ANT SPI Change-Id: Iaef9f51cd6b002c1d27ceca3da56d1da7677c974 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 5e175a3e692..9ff3474ce41 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -198,7 +198,7 @@ touchscreen-size-y = <800>; touchscreen-max-w = <512>; touchscreen-max-p = <512>; - touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158£¬KEY_MENU=139*/ + touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158��KEY_MENU=139*/ goodix,slide-wakeup = <0>; goodix,type-a-report = <0>; @@ -376,7 +376,7 @@ pinctrl-0 = <&nrf52_active>; }; -&spi_0 { +/*&spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; reg = <0>; @@ -394,7 +394,7 @@ pinctrl-2 = <&nrf_release>; status = "ok"; }; -}; +};*/ / { mtp_batterydata: qcom,battery-data { -- 2.25.1 From 62021ed7419930932534bd2ffa11b7614c49de3e Mon Sep 17 00:00:00 2001 From: vipinbb Date: Sun, 14 Jun 2020 20:32:02 -0400 Subject: [PATCH 30/76] MeiG: huangshifang:Add sound level to beeper Change-Id: I48f4e38e3ef2b45d9a0e346c5b0387e81726b4fc --- .../arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi | 4 + drivers/platform/msm/qpnp-vibrator.c | 178 +++++++++++++++++- 2 files changed, 179 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi index 6480959078c..c8d3f45e4c9 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi @@ -57,6 +57,10 @@ qcom,vib-timeout-ms = <15000>; qcom,vib-vtg-level-mV = <3100>; pwm-gpios = <&msm_gpio 98 0x1>; + medium-gpios = <&msm_gpio 95 0x1>; + pwr-gpios = <&msm_gpio 2 0x1>; + loud-gpios = <&msm_gpio 110 0x1>; + quiet-gpios = <&msm_gpio 23 0x1>; }; }; }; diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index 94aa9e4f1a5..43cacdc6565 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -54,11 +54,21 @@ enum qpnp_vib_mode { QPNP_VIB_DTEST2, QPNP_VIB_DTEST3, }; +//add by huangshifang for beeper sound control 20200516 +enum sound_mode { + SOUND_NONE, + SOUND_QUIET, + SOUND_MEDIUM, + SOUND_LOUD, + SOUND_MAX, +}; +//add end #define GPIO_PWM_DELAY_TIME (250000) - static struct qpnp_vib *gl_vib = NULL; - +//add by huangshifang for beeper sound control 20200516 +static struct spmi_driver qpnp_vibrator_driver; +//add end struct qpnp_pwm_info { struct pwm_device *pwm_dev; u32 pwm_channel; @@ -87,6 +97,17 @@ struct qpnp_vib { u32 vib_gpio_flags; u32 pwm_gpio_flags; //add end + //add by huangshifang for beeper sound control 20200516 + int pwr_gpio; + int quiet_gpio; + int medium_gpio; + int loud_gpio; + u32 pwr_gpio_flags; + u32 quiet_gpio_flags; + u32 medium_gpio_flags; + u32 loud_gpio_flags; + int sound_mode; + //add end int pwm_gpio; struct hrtimer mytimer; ktime_t kt; @@ -238,12 +259,47 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) } //add end + //add by huangshifang for beeper sound control 20200516 + switch(vib->sound_mode) + { + case SOUND_NONE: + gpio_direction_output(gl_vib->pwr_gpio, 0); + gpio_direction_output(gl_vib->quiet_gpio, 0); + gpio_direction_output(gl_vib->loud_gpio, 0); + gpio_direction_output(gl_vib->medium_gpio, 0); + pr_err("sound_none start \n"); + break; + case SOUND_QUIET: + gpio_direction_output(gl_vib->quiet_gpio, 1); + gpio_direction_output(gl_vib->medium_gpio, 0); + gpio_direction_output(gl_vib->loud_gpio, 0); + gpio_direction_output(gl_vib->pwr_gpio, 1); + pr_err("sound_quiet start \n"); + break; + case SOUND_MEDIUM: + gpio_direction_output(gl_vib->quiet_gpio, 0); + gpio_direction_output(gl_vib->medium_gpio, 1); + gpio_direction_output(gl_vib->loud_gpio, 0); + gpio_direction_output(gl_vib->pwr_gpio, 1); + pr_err("sound_medium start \n"); + break; + case SOUND_LOUD: + gpio_direction_output(gl_vib->quiet_gpio, 0); + gpio_direction_output(gl_vib->medium_gpio, 0); + gpio_direction_output(gl_vib->loud_gpio, 1); + gpio_direction_output(gl_vib->pwr_gpio, 1); + pr_err("sound_loud start \n"); + break; + default: + break; + } + //add end + if (gpio_is_valid(vib->pwm_gpio)) { vib->gpio_pwm_value = 1; gpio_pwm_start(); } - } } else { if (vib->mode != QPNP_VIB_MANUAL) { @@ -267,6 +323,13 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) if (gpio_is_valid(vib->pwm_gpio)) vib->gpio_pwm_value = 0; + + //add by huangshifang for beeper sound control 20200516 + gpio_direction_output(gl_vib->pwr_gpio, 0); + gpio_direction_output(gl_vib->quiet_gpio, 0); + gpio_direction_output(gl_vib->loud_gpio, 0); + gpio_direction_output(gl_vib->medium_gpio, 0); + //add end } } @@ -367,8 +430,46 @@ static int qpnp_vib_parse_dt(struct qpnp_vib *vib) gpio_direction_output(vib->pwm_gpio, 0); pr_err("pwm gpio power on\n"); } + //add end + + //add by huangshifang for beeper sound control 20200516 + vib->medium_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "medium-gpios", + 0, &vib->medium_gpio_flags); + + vib->pwr_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "pwr-gpios", + 0, &vib->pwr_gpio_flags); + + vib->loud_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "loud-gpios", + 0, &vib->loud_gpio_flags); + + vib->quiet_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "quiet-gpios", + 0, &vib->quiet_gpio_flags); + + if (gpio_is_valid(vib->medium_gpio)) + { + gpio_direction_output(vib->medium_gpio, 0); + pr_err("medium gpio power on\n"); + } + + if (gpio_is_valid(vib->pwr_gpio)) + { + gpio_direction_output(vib->pwr_gpio, 0); + pr_err("pwr gpio power on\n"); + } + if (gpio_is_valid(vib->loud_gpio)) + { + gpio_direction_output(vib->loud_gpio, 0); + pr_err("loud gpio power on\n"); + } + + if (gpio_is_valid(vib->quiet_gpio)) + { + gpio_direction_output(vib->quiet_gpio, 0); + pr_err("quiet gpio power on\n"); + } //add end + vib->timeout = QPNP_VIB_DEFAULT_TIMEOUT; rc = of_property_read_u32(spmi->dev.of_node, "qcom,vib-timeout-ms", &temp_val); @@ -444,6 +545,37 @@ static int qpnp_vib_parse_dt(struct qpnp_vib *vib) return 0; } +//add by huangshifang for beeper sound control 20200516 +static ssize_t show_driver_attr_beeper(struct device_driver *dev, char *buf) +{ + return snprintf(buf, 20, "%d\n", gl_vib->sound_mode); +} + +static ssize_t store_driver_attr_beeper(struct device_driver *dev, const char *buf, size_t count) +{ + ssize_t ret = -EINVAL; + unsigned long gpioval = 0; + + ret = kstrtoul(buf, 10, &gpioval); + if (ret) + { + return ret; + } + + if(gpioval >= 3) + gpioval = 3; + + if(gpioval <= 0) + gpioval = 0; + + gl_vib->sound_mode = gpioval; + + return count; +} + +static DRIVER_ATTR(beeper, S_IWUSR | S_IRUGO, show_driver_attr_beeper, store_driver_attr_beeper); +//add end + static int qpnp_vibrator_probe(struct spmi_device *spmi) { struct qpnp_vib *vib; @@ -480,11 +612,51 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) ret = -ENODEV; } + //add by huangshifang for beeper sound control 20200516 + ret = gpio_request(vib->medium_gpio, "medium_gpio"); + if(ret < 0) + { + pr_err("medium_gpio req failed for id\n"); + ret = -ENODEV; + } + + ret = gpio_request(vib->pwr_gpio, "pwr_gpio"); + if(ret < 0) + { + pr_err("pwr_gpio req failed for id\n"); + ret = -ENODEV; + } + + ret = gpio_request(vib->quiet_gpio, "quiet_gpio"); + if(ret < 0) + { + pr_err("quiet_gpio req failed for id\n"); + ret = -ENODEV; + } + + ret = gpio_request(vib->loud_gpio, "loud_gpio"); + if(ret < 0) + { + pr_err("loud_gpio req failed for id\n"); + ret = -ENODEV; + } + + vib->sound_mode = SOUND_MEDIUM; + //add end + rc = qpnp_vibrator_config(vib); if (rc) { dev_err(&spmi->dev, "vib config failed\n"); return rc; } + + //add by huangshifang for beeper sound control 20200516 + if(driver_create_file(&qpnp_vibrator_driver.driver, &driver_attr_beeper)) + { + pr_err("mg_drv_probe driver_creat_file ERROR \n"); + return ret; + } + //add end mutex_init(&vib->lock); INIT_WORK(&vib->work, qpnp_vib_update); -- 2.25.1 From 09f80d12b7e6e17bd2d05ab5d33723fe82c5b5da Mon Sep 17 00:00:00 2001 From: vipinbb Date: Sun, 14 Jun 2020 20:47:13 -0400 Subject: [PATCH 31/76] MeiG: liangdi:fix suspend issue Change-Id: I42e41d8380fd4aac94e0eddc4dd7c19d4b9b63ff --- arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 8 ++++---- arch/arm/boot/dts/qcom/msm8909-regulator.dtsi | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index 0b134c9a9fa..55175b7d8d4 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -1951,22 +1951,22 @@ vdd_spkdrv { vdd_spkdrv_act: vdd_spkdrv_on { mux { - pins = "gpio4"; + pins = "gpio36"; function = "gpio"; }; config { - pins = "gpio4"; + pins = "gpio36"; drive-strength = <8>; }; }; vdd_spkdrv_sus: vdd_spkdrv_off { mux { - pins = "gpio4"; + pins = "gpio36"; function = "gpio"; }; config { - pins = "gpio4"; + pins = "gpio36"; drive-strength = <2>; bias-disable; }; diff --git a/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi index 24acaf8e92e..53ad975d3b6 100644 --- a/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi @@ -275,6 +275,6 @@ regulator-name = "spk_vreg"; startup-delay-us = <0>; enable-active-high; - gpio = <&msm_gpio 4 0>; + gpio = <&msm_gpio 36 0>; }; }; -- 2.25.1 From 2cf36cc092a91a90009110b963bde2a89088f077 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Sun, 14 Jun 2020 21:00:53 -0400 Subject: [PATCH 32/76] MeiG: liangdi:dump auto reboot Change-Id: I5df7fa73cb4ef0cb81bb946571cecd2615c2d994 --- drivers/reset/msm-poweroff.c | 614 +++++++++++++++++++++++++++++++++++ 1 file changed, 614 insertions(+) create mode 100755 drivers/reset/msm-poweroff.c diff --git a/drivers/reset/msm-poweroff.c b/drivers/reset/msm-poweroff.c new file mode 100755 index 00000000000..27711ad7e19 --- /dev/null +++ b/drivers/reset/msm-poweroff.c @@ -0,0 +1,614 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define EMERGENCY_DLOAD_MAGIC1 0x322A4F99 +#define EMERGENCY_DLOAD_MAGIC2 0xC67E4350 +#define EMERGENCY_DLOAD_MAGIC3 0x77777777 +#define EMMC_DLOAD_TYPE 0x2 + +#define SCM_IO_DISABLE_PMIC_ARBITER 1 +#define SCM_IO_DEASSERT_PS_HOLD 2 +#define SCM_WDOG_DEBUG_BOOT_PART 0x9 +#define SCM_DLOAD_MODE 0X10 +#define SCM_EDLOAD_MODE 0X01 +#define SCM_DLOAD_CMD 0x10 + + +static int restart_mode; +static void *restart_reason; +static bool scm_pmic_arbiter_disable_supported; +static bool scm_deassert_ps_hold_supported; +/* Download mode master kill-switch */ +static void __iomem *msm_ps_hold; +static phys_addr_t tcsr_boot_misc_detect; +static void scm_disable_sdi(void); + +#ifdef CONFIG_MSM_DLOAD_MODE +/* Runtime could be only changed value once. +* There is no API from TZ to re-enable the registers. +* So the SDI cannot be re-enabled when it already by-passed. +*/ +static int download_mode = 0;//1;//modify by liangdi for dump auto reboot 20200523 +#else +static const int download_mode; +#endif + +#ifdef CONFIG_MSM_DLOAD_MODE +#define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode" +#define DL_MODE_PROP "qcom,msm-imem-download_mode" + +static int in_panic; +static void *dload_mode_addr; +static bool dload_mode_enabled; +static void *emergency_dload_mode_addr; +static bool scm_dload_supported; +static struct kobject dload_kobj; +static void *dload_type_addr; + +static int dload_set(const char *val, struct kernel_param *kp); +/* interface for exporting attributes */ +struct reset_attribute { + struct attribute attr; + ssize_t (*show)(struct kobject *kobj, struct attribute *attr, + char *buf); + size_t (*store)(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count); +}; +#define to_reset_attr(_attr) \ + container_of(_attr, struct reset_attribute, attr) +#define RESET_ATTR(_name, _mode, _show, _store) \ + static struct reset_attribute reset_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +module_param_call(download_mode, dload_set, param_get_int, + &download_mode, 0644); + +static int panic_prep_restart(struct notifier_block *this, + unsigned long event, void *ptr) +{ + in_panic = 1; + return NOTIFY_DONE; +} + +static struct notifier_block panic_blk = { + .notifier_call = panic_prep_restart, +}; + +int scm_set_dload_mode(int arg1, int arg2) +{ + struct scm_desc desc = { + .args[0] = arg1, + .args[1] = arg2, + .arginfo = SCM_ARGS(2), + }; + + if (!scm_dload_supported) { + if (tcsr_boot_misc_detect) + return scm_io_write(tcsr_boot_misc_detect, arg1); + + return 0; + } + + if (!is_scm_armv8()) + return scm_call_atomic2(SCM_SVC_BOOT, SCM_DLOAD_CMD, arg1, + arg2); + + return scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, SCM_DLOAD_CMD), + &desc); +} + +static void set_dload_mode(int on) +{ + int ret; + + if (dload_mode_addr) { + __raw_writel(on ? 0xE47B337D : 0, dload_mode_addr); + __raw_writel(on ? 0xCE14091A : 0, + dload_mode_addr + sizeof(unsigned int)); + mb(); + } + + ret = scm_set_dload_mode(on ? SCM_DLOAD_MODE : 0, 0); + if (ret) + pr_err("Failed to set secure DLOAD mode: %d\n", ret); + + dload_mode_enabled = on; +} + +static bool get_dload_mode(void) +{ + return dload_mode_enabled; +} + +static void enable_emergency_dload_mode(void) +{ + int ret; + + if (emergency_dload_mode_addr) { + __raw_writel(EMERGENCY_DLOAD_MAGIC1, + emergency_dload_mode_addr); + __raw_writel(EMERGENCY_DLOAD_MAGIC2, + emergency_dload_mode_addr + + sizeof(unsigned int)); + __raw_writel(EMERGENCY_DLOAD_MAGIC3, + emergency_dload_mode_addr + + (2 * sizeof(unsigned int))); + + /* Need disable the pmic wdt, then the emergency dload mode + * will not auto reset. */ + qpnp_pon_wd_config(0); + mb(); + } + + ret = scm_set_dload_mode(SCM_EDLOAD_MODE, 0); + if (ret) + pr_err("Failed to set secure EDLOAD mode: %d\n", ret); +} + +static int dload_set(const char *val, struct kernel_param *kp) +{ + int ret; + int old_val = download_mode; + + ret = param_set_int(val, kp); + + if (ret) + return ret; + + /* If download_mode is not zero or one, ignore. */ + if (download_mode >> 1) { + download_mode = old_val; + return -EINVAL; + } + + set_dload_mode(download_mode); + + return 0; +} +#else +static void set_dload_mode(int on) +{ + return; +} + +static void enable_emergency_dload_mode(void) +{ + pr_err("dload mode is not enabled on target\n"); +} + +static bool get_dload_mode(void) +{ + return false; +} +#endif + +static void scm_disable_sdi(void) +{ + int ret; + struct scm_desc desc = { + .args[0] = 1, + .args[1] = 0, + .arginfo = SCM_ARGS(2), + }; + + /* Needed to bypass debug image on some chips */ + if (!is_scm_armv8()) + ret = scm_call_atomic2(SCM_SVC_BOOT, + SCM_WDOG_DEBUG_BOOT_PART, 1, 0); + else + ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, + SCM_WDOG_DEBUG_BOOT_PART), &desc); + if (ret) + pr_err("Failed to disable secure wdog debug: %d\n", ret); +} + +void msm_set_restart_mode(int mode) +{ + restart_mode = mode; +} +EXPORT_SYMBOL(msm_set_restart_mode); + +/* + * Force the SPMI PMIC arbiter to shutdown so that no more SPMI transactions + * are sent from the MSM to the PMIC. This is required in order to avoid an + * SPMI lockup on certain PMIC chips if PS_HOLD is lowered in the middle of + * an SPMI transaction. + */ +static void halt_spmi_pmic_arbiter(void) +{ + struct scm_desc desc = { + .args[0] = 0, + .arginfo = SCM_ARGS(1), + }; + + if (scm_pmic_arbiter_disable_supported) { + pr_crit("Calling SCM to disable SPMI PMIC arbiter\n"); + if (!is_scm_armv8()) + scm_call_atomic1(SCM_SVC_PWR, + SCM_IO_DISABLE_PMIC_ARBITER, 0); + else + scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_PWR, + SCM_IO_DISABLE_PMIC_ARBITER), &desc); + } +} + +static void msm_restart_prepare(const char *cmd) +{ + bool need_warm_reset = false; + +#ifdef CONFIG_MSM_DLOAD_MODE + + /* Write download mode flags if we're panic'ing + * Write download mode flags if restart_mode says so + * Kill download mode if master-kill switch is set + */ + + set_dload_mode(download_mode && + (in_panic || restart_mode == RESTART_DLOAD)); +#endif + + if (qpnp_pon_check_hard_reset_stored()) { + /* Set warm reset as true when device is in dload mode */ + if (get_dload_mode() || + ((cmd != NULL && cmd[0] != '\0') && + !strcmp(cmd, "edl"))) + need_warm_reset = true; + } else { + need_warm_reset = (get_dload_mode() || + ((cmd != NULL && cmd[0] != '\0') && + strcmp(cmd, "userrequested"))); + } + + /* Hard reset the PMIC unless memory contents must be maintained. */ + if (need_warm_reset) { + qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET); + } else { + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + } + + if (cmd != NULL) { + if (!strncmp(cmd, "bootloader", 10)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_BOOTLOADER); + __raw_writel(0x77665500, restart_reason); + } else if (!strncmp(cmd, "recovery", 8)) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_RECOVERY); + __raw_writel(0x77665502, restart_reason); + } else if (!strcmp(cmd, "rtc")) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_RTC); + __raw_writel(0x77665503, restart_reason); + } else if (!strcmp(cmd, "dm-verity device corrupted")) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_DMVERITY_CORRUPTED); + __raw_writel(0x77665508, restart_reason); + } else if (!strcmp(cmd, "dm-verity enforcing")) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_DMVERITY_ENFORCE); + __raw_writel(0x77665509, restart_reason); + } else if (!strcmp(cmd, "keys clear")) { + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_KEYS_CLEAR); + __raw_writel(0x7766550a, restart_reason); + } else if (!strncmp(cmd, "oem-", 4)) { + unsigned long code; + int ret; + ret = kstrtoul(cmd + 4, 16, &code); + if (!ret) + __raw_writel(0x6f656d00 | (code & 0xff), + restart_reason); + } else if (!strncmp(cmd, "edl", 3)) { + enable_emergency_dload_mode(); + } else { + __raw_writel(0x77665501, restart_reason); + } + } + + flush_cache_all(); + + /*outer_flush_all is not supported by 64bit kernel*/ +#ifndef CONFIG_ARM64 + outer_flush_all(); +#endif + +} + +/* + * Deassert PS_HOLD to signal the PMIC that we are ready to power down or reset. + * Do this by calling into the secure environment, if available, or by directly + * writing to a hardware register. + * + * This function should never return. + */ +static void deassert_ps_hold(void) +{ + struct scm_desc desc = { + .args[0] = 0, + .arginfo = SCM_ARGS(1), + }; + + if (scm_deassert_ps_hold_supported) { + /* This call will be available on ARMv8 only */ + scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_PWR, + SCM_IO_DEASSERT_PS_HOLD), &desc); + } + + /* Fall-through to the direct write in case the scm_call "returns" */ + __raw_writel(0, msm_ps_hold); +} + +static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) +{ + pr_notice("Going down for restart now\n"); + + msm_restart_prepare(cmd); + +#ifdef CONFIG_MSM_DLOAD_MODE + /* + * Trigger a watchdog bite here and if this fails, + * device will take the usual restart path. + */ + + if (WDOG_BITE_ON_PANIC && in_panic) + msm_trigger_wdog_bite(); +#endif + + scm_disable_sdi(); + halt_spmi_pmic_arbiter(); + deassert_ps_hold(); + + mdelay(10000); +} + +static void do_msm_poweroff(void) +{ + pr_notice("Powering off the SoC\n"); + + set_dload_mode(0); + scm_disable_sdi(); + qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN); + + halt_spmi_pmic_arbiter(); + deassert_ps_hold(); + + mdelay(10000); + pr_err("Powering off has failed\n"); + return; +} + +#ifdef CONFIG_MSM_DLOAD_MODE +static ssize_t attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct reset_attribute *reset_attr = to_reset_attr(attr); + ssize_t ret = -EIO; + + if (reset_attr->show) + ret = reset_attr->show(kobj, attr, buf); + + return ret; +} + +static ssize_t attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + struct reset_attribute *reset_attr = to_reset_attr(attr); + ssize_t ret = -EIO; + + if (reset_attr->store) + ret = reset_attr->store(kobj, attr, buf, count); + + return ret; +} + +static const struct sysfs_ops reset_sysfs_ops = { + .show = attr_show, + .store = attr_store, +}; + +static struct kobj_type reset_ktype = { + .sysfs_ops = &reset_sysfs_ops, +}; + +static ssize_t show_emmc_dload(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + uint32_t read_val, show_val; + + read_val = __raw_readl(dload_type_addr); + if (read_val == EMMC_DLOAD_TYPE) + show_val = 1; + else + show_val = 0; + + return snprintf(buf, sizeof(show_val), "%u\n", show_val); +} + +static size_t store_emmc_dload(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + uint32_t enabled; + int ret; + + ret = kstrtouint(buf, 0, &enabled); + if (ret < 0) + return ret; + + if (!((enabled == 0) || (enabled == 1))) + return -EINVAL; + + if (enabled == 1) + __raw_writel(EMMC_DLOAD_TYPE, dload_type_addr); + else + __raw_writel(0, dload_type_addr); + + return count; +} +RESET_ATTR(emmc_dload, 0644, show_emmc_dload, store_emmc_dload); + +static struct attribute *reset_attrs[] = { + &reset_attr_emmc_dload.attr, + NULL +}; + +static struct attribute_group reset_attr_group = { + .attrs = reset_attrs, +}; +#endif + +static int msm_restart_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *mem; + struct device_node *np; + int ret = 0; + +#ifdef CONFIG_MSM_DLOAD_MODE + if (scm_is_call_available(SCM_SVC_BOOT, SCM_DLOAD_CMD) > 0) + scm_dload_supported = true; + + atomic_notifier_chain_register(&panic_notifier_list, &panic_blk); + np = of_find_compatible_node(NULL, NULL, DL_MODE_PROP); + if (!np) { + pr_err("unable to find DT imem DLOAD mode node\n"); + } else { + dload_mode_addr = of_iomap(np, 0); + if (!dload_mode_addr) + pr_err("unable to map imem DLOAD offset\n"); + } + + np = of_find_compatible_node(NULL, NULL, EDL_MODE_PROP); + if (!np) { + pr_err("unable to find DT imem EDLOAD mode node\n"); + } else { + emergency_dload_mode_addr = of_iomap(np, 0); + if (!emergency_dload_mode_addr) + pr_err("unable to map imem EDLOAD mode offset\n"); + } + + np = of_find_compatible_node(NULL, NULL, + "qcom,msm-imem-dload-type"); + if (!np) { + pr_err("unable to find DT imem dload-type node\n"); + goto skip_sysfs_create; + } else { + dload_type_addr = of_iomap(np, 0); + if (!dload_type_addr) { + pr_err("unable to map imem dload-type offset\n"); + goto skip_sysfs_create; + } + } + + ret = kobject_init_and_add(&dload_kobj, &reset_ktype, + kernel_kobj, "%s", "dload"); + if (ret) { + pr_err("%s:Error in creation kobject_add\n", __func__); + kobject_put(&dload_kobj); + goto skip_sysfs_create; + } + + ret = sysfs_create_group(&dload_kobj, &reset_attr_group); + if (ret) { + pr_err("%s:Error in creation sysfs_create_group\n", __func__); + kobject_del(&dload_kobj); + } +skip_sysfs_create: +#endif + np = of_find_compatible_node(NULL, NULL, + "qcom,msm-imem-restart_reason"); + if (!np) { + pr_err("unable to find DT imem restart reason node\n"); + } else { + restart_reason = of_iomap(np, 0); + if (!restart_reason) { + pr_err("unable to map imem restart reason offset\n"); + ret = -ENOMEM; + goto err_restart_reason; + } + } + + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pshold-base"); + msm_ps_hold = devm_ioremap_resource(dev, mem); + if (IS_ERR(msm_ps_hold)) + return PTR_ERR(msm_ps_hold); + + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "tcsr-boot-misc-detect"); + if (mem) + tcsr_boot_misc_detect = mem->start; + + pm_power_off = do_msm_poweroff; + arm_pm_restart = do_msm_restart; + + if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DISABLE_PMIC_ARBITER) > 0) + scm_pmic_arbiter_disable_supported = true; + + if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DEASSERT_PS_HOLD) > 0) + scm_deassert_ps_hold_supported = true; + + set_dload_mode(download_mode); + if (!download_mode) + scm_disable_sdi(); + + return 0; + +err_restart_reason: +#ifdef CONFIG_MSM_DLOAD_MODE + iounmap(emergency_dload_mode_addr); + iounmap(dload_mode_addr); +#endif + return ret; +} + +static const struct of_device_id of_msm_restart_match[] = { + { .compatible = "qcom,pshold", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_msm_restart_match); + +static struct platform_driver msm_restart_driver = { + .probe = msm_restart_probe, + .driver = { + .name = "msm-restart", + .of_match_table = of_match_ptr(of_msm_restart_match), + }, +}; + +static int __init msm_restart_init(void) +{ + return platform_driver_register(&msm_restart_driver); +} +device_initcall(msm_restart_init); -- 2.25.1 From 1466cc259734e7747327f9c1cc7623349fdf7501 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Sun, 14 Jun 2020 21:10:50 -0400 Subject: [PATCH 33/76] MeiG: liangdi:power on SUB_VBUS_EN pin Change-Id: Ib250b0307369402c68e0107c500a5d6891dddc74 --- .../arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi | 1 + drivers/platform/msm/qpnp-vibrator.c | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi index c8d3f45e4c9..bcbd4619e7e 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi @@ -61,6 +61,7 @@ pwr-gpios = <&msm_gpio 2 0x1>; loud-gpios = <&msm_gpio 110 0x1>; quiet-gpios = <&msm_gpio 23 0x1>; + sub-vbus-en = <&msm_gpio 33 0x0>; }; }; }; diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index 43cacdc6565..527c21a350a 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -95,7 +95,17 @@ struct qpnp_vib { //add by liangdi int vib_gpio; u32 vib_gpio_flags; + int pwm_gpio; u32 pwm_gpio_flags; + struct hrtimer mytimer; + ktime_t kt; + unsigned long time; + int pwm_level; //0: low ,1:high + int gpio_pwm_value; + + // add for sub vbus en + int sub_vbus_en_gpio; + u32 sub_vbus_en_gpio_flags; //add end //add by huangshifang for beeper sound control 20200516 int pwr_gpio; @@ -108,13 +118,6 @@ struct qpnp_vib { u32 loud_gpio_flags; int sound_mode; //add end - int pwm_gpio; - struct hrtimer mytimer; - ktime_t kt; - unsigned long time; - int pwm_level; //0: low ,1:high - int gpio_pwm_value; - }; static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer); @@ -428,8 +431,17 @@ static int qpnp_vib_parse_dt(struct qpnp_vib *vib) if (gpio_is_valid(vib->pwm_gpio)) { gpio_direction_output(vib->pwm_gpio, 0); - pr_err("pwm gpio power on\n"); + pr_err("pwm gpio power off\n"); } + + vib->sub_vbus_en_gpio = of_get_named_gpio_flags(spmi->dev.of_node, "sub-vbus-en", + 0, &vib->sub_vbus_en_gpio_flags); + + if (gpio_is_valid(vib->sub_vbus_en_gpio)) + { + gpio_direction_output(vib->sub_vbus_en_gpio, 1); + pr_err("sub-vbus-en power on\n"); + } //add end //add by huangshifang for beeper sound control 20200516 @@ -448,25 +460,25 @@ static int qpnp_vib_parse_dt(struct qpnp_vib *vib) if (gpio_is_valid(vib->medium_gpio)) { gpio_direction_output(vib->medium_gpio, 0); - pr_err("medium gpio power on\n"); + pr_err("medium gpio power off\n"); } if (gpio_is_valid(vib->pwr_gpio)) { gpio_direction_output(vib->pwr_gpio, 0); - pr_err("pwr gpio power on\n"); + pr_err("pwr gpio power off\n"); } if (gpio_is_valid(vib->loud_gpio)) { gpio_direction_output(vib->loud_gpio, 0); - pr_err("loud gpio power on\n"); + pr_err("loud gpio power off\n"); } if (gpio_is_valid(vib->quiet_gpio)) { gpio_direction_output(vib->quiet_gpio, 0); - pr_err("quiet gpio power on\n"); + pr_err("quiet gpio power off\n"); } //add end -- 2.25.1 From 3152d5fff1c5afbbbc3c8f496505c7d6f01a19eb Mon Sep 17 00:00:00 2001 From: vipinbb Date: Sun, 14 Jun 2020 21:20:18 -0400 Subject: [PATCH 34/76] MeiG: liangdi:modify capacity 0%-15%,max charging current 2500mA Change-Id: I1fe31d0a3f34626aae90c8e83e1b3bd6bd2e0718 --- drivers/power/smb135x-charger.c | 51 ++- include/linux/msm_hsusb.h | 732 ++++++++++++++++++++++++++++++++ 2 files changed, 782 insertions(+), 1 deletion(-) create mode 100755 include/linux/msm_hsusb.h diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 47a0b51a780..507ce5e3965 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -423,7 +423,11 @@ struct smb135x_chg { struct regulator *usb_pullup_vreg; struct delayed_work wireless_insertion_work; struct delayed_work src_detect_low_work; - + //add by liangdi for detect soc and limit max charging current 20200527 + struct delayed_work bat_detect_soc_work; + int fastchg_ma_now; + //add end + unsigned int thermal_levels; unsigned int therm_lvl_sel; unsigned int *thermal_mitigation; @@ -3033,6 +3037,43 @@ static void src_detect_check_work(struct work_struct *work) } } +//add by liangdi for detect soc and limit max charging current 20200527 +#define MAX_FAST_CHARG_CURRENT 2500 +static void battery_detect_soc_work(struct work_struct *work) +{ + struct smb135x_chg *chip = container_of(work, + struct smb135x_chg, bat_detect_soc_work.work); + int rc = 0; + int soc = 0; + soc = smb135x_get_prop_batt_capacity(chip); + +// pr_err("detect soc usb_present=%d, soc %d, fastchg_ma_now %d\n", +// chip->usb_present,soc,chip->fastchg_ma_now); + + if((soc <= 15) && (chip->fastchg_ma_now != MAX_FAST_CHARG_CURRENT)) + { + chip->fastchg_ma_now = MAX_FAST_CHARG_CURRENT; + rc = smb135x_set_fastchg_current(chip, MAX_FAST_CHARG_CURRENT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); + return; + } + } + else if((soc > 15) && (chip->fastchg_ma_now != chip->fastchg_ma)) + { + chip->fastchg_ma_now = chip->fastchg_ma; + rc = smb135x_set_fastchg_current(chip, chip->fastchg_ma); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); + return; + } + } + + schedule_delayed_work(&chip->bat_detect_soc_work, msecs_to_jiffies(20000)); + return ; +} +//add end + /** * usbin_uv_handler() * @chip: pointer to smb135x_chg chip @@ -3938,6 +3979,8 @@ static int smb135x_hw_init(struct smb135x_chg *chip) /* set maximum fastchg current */ if (chip->fastchg_ma != -EINVAL) { + + chip->fastchg_ma_now = chip->fastchg_ma;//add by liangdi for detect soc and limit max charging current 20200527 rc = smb135x_set_fastchg_current(chip, chip->fastchg_ma); if (rc < 0) { dev_err(chip->dev, "Couldn't set fastchg current = %d\n", @@ -4544,6 +4587,12 @@ static int smb135x_main_charger_probe(struct i2c_client *client, } create_debugfs_entries(chip); + + //add by liangdi for detect soc and limit max charging current 20200527 + INIT_DELAYED_WORK(&chip->bat_detect_soc_work, battery_detect_soc_work); + schedule_delayed_work(&chip->bat_detect_soc_work, msecs_to_jiffies(200)); + //add end + dev_info(chip->dev, "SMB135X version = %s revision = %s successfully probed batt=%d dc = %d usb = %d\n", version_str[chip->version], revision_str[chip->revision], diff --git a/include/linux/msm_hsusb.h b/include/linux/msm_hsusb.h new file mode 100755 index 00000000000..64caf2e7033 --- /dev/null +++ b/include/linux/msm_hsusb.h @@ -0,0 +1,732 @@ +/* include/linux/usb/msm_hsusb.h + * + * Copyright (C) 2008 Google, Inc. + * Author: Brian Swetland + * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __ASM_ARCH_MSM_HSUSB_H +#define __ASM_ARCH_MSM_HSUSB_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * The following are bit fields describing the usb_request.udc_priv word. + * These bit fields are set by function drivers that wish to queue + * usb_requests with sps/bam parameters. + */ +#define MSM_PIPE_ID_MASK (0x1F) +#define MSM_TX_PIPE_ID_OFS (16) +#define MSM_SPS_MODE BIT(5) +#define MSM_IS_FINITE_TRANSFER BIT(6) +#define MSM_PRODUCER BIT(7) +#define MSM_DISABLE_WB BIT(8) +#define MSM_ETD_IOC BIT(9) +#define MSM_INTERNAL_MEM BIT(10) +#define MSM_VENDOR_ID BIT(16) + +/** + * Requested USB votes for BUS bandwidth + * + * USB_NO_PERF_VOTE BUS Vote for inactive USB session or disconnect + * USB_MAX_PERF_VOTE Maximum BUS bandwidth vote + * USB_MIN_PERF_VOTE Minimum BUS bandwidth vote (for some hw same as NO_PERF) + * + */ +enum usb_bus_vote { + USB_NO_PERF_VOTE = 0, + USB_MAX_PERF_VOTE, + USB_MIN_PERF_VOTE, +}; + +/** + * Requested USB votes for NOC frequency + * + * USB_NOC_NOM_VOTE Vote for NOM set of NOC frequencies + * USB_NOC_SVS_VOTE Vote for SVS set of NOC frequencies + * + */ +enum usb_noc_mode { + USB_NOC_NOM_VOTE = 0, + USB_NOC_SVS_VOTE, + USB_NOC_NUM_VOTE, +}; + +/** + * Supported USB modes + * + * USB_PERIPHERAL Only peripheral mode is supported. + * USB_HOST Only host mode is supported. + * USB_OTG OTG mode is supported. + * + */ +enum usb_mode_type { + USB_NONE = 0, + USB_PERIPHERAL, + USB_HOST, + USB_OTG, +}; + +/** + * OTG control + * + * OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host + * only configuration. + * OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY. + * OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware. + * OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs. + * + */ +enum otg_control_type { + OTG_NO_CONTROL = 0, + OTG_PHY_CONTROL, + OTG_PMIC_CONTROL, + OTG_USER_CONTROL, +}; + +/** + * PHY used in + * + * INVALID_PHY Unsupported PHY + * CI_PHY Chipidea PHY + * SNPS_PICO_PHY Synopsis Pico PHY + * SNPS_FEMTO_PHY Synopsis Femto PHY + * QUSB_ULPI_PHY + * + */ +enum msm_usb_phy_type { + INVALID_PHY = 0, + CI_PHY, /* not supported */ + SNPS_PICO_PHY, + SNPS_FEMTO_PHY, + QUSB_ULPI_PHY, +}; + +#define IDEV_CHG_MAX 3000 //1500 //modify by liangdi for 2A current 20200115 +#define IUNIT 100 +#define IDEV_HVDCP_CHG_MAX 3000 //1800 //modify by liangdi for 2A current 20200115 + +/** + * Different states involved in USB charger detection. + * + * USB_CHG_STATE_UNDEFINED USB charger is not connected or detection + * process is not yet started. + * USB_CHG_STATE_IN_PROGRESS Charger detection in progress + * USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact. + * USB_CHG_STATE_DCD_DONE Data pin contact is detected. + * USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects + * between SDP and DCP/CDP). + * USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects + * between DCP and CDP). + * USB_CHG_STATE_DETECTED USB charger type is determined. + * + */ +enum usb_chg_state { + USB_CHG_STATE_UNDEFINED = 0, + USB_CHG_STATE_IN_PROGRESS, + USB_CHG_STATE_WAIT_FOR_DCD, + USB_CHG_STATE_DCD_DONE, + USB_CHG_STATE_PRIMARY_DONE, + USB_CHG_STATE_SECONDARY_DONE, + USB_CHG_STATE_DETECTED, +}; + +/** + * USB charger types + * + * USB_INVALID_CHARGER Invalid USB charger. + * USB_SDP_CHARGER Standard downstream port. Refers to a downstream port + * on USB2.0 compliant host/hub. + * USB_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger). + * USB_CDP_CHARGER Charging downstream port. Enumeration can happen and + * IDEV_CHG_MAX can be drawn irrespective of USB state. + * USB_PROPRIETARY_CHARGER A proprietary charger pull DP and DM to specific + * voltages between 2.0-3.3v for identification. + * + */ +enum usb_chg_type { + USB_INVALID_CHARGER = 0, + USB_SDP_CHARGER, + USB_DCP_CHARGER, + USB_CDP_CHARGER, + USB_PROPRIETARY_CHARGER, + USB_FLOATED_CHARGER, +}; + +/** + * Used different VDDCX voltage voting mechnism + * VDDCX_CORNER Vote for VDDCX Corner voltage + * VDDCX Vote for VDDCX Absolute voltage + */ +enum usb_vdd_type { + VDDCX_CORNER = 0, + VDDCX, + VDD_TYPE_MAX, +}; + +/** + * Used different VDDCX voltage values + */ +enum usb_vdd_value { + VDD_NONE = 0, + VDD_MIN, + VDD_MAX, + VDD_VAL_MAX, +}; + +/** + * Maintain state for hvdcp external charger status + * DEFAULT This is used when DCP is detected + * ACTIVE This is used when ioctl is called to block LPM + * INACTIVE This is used when ioctl is called to unblock LPM + */ + +enum usb_ext_chg_status { + DEFAULT = 1, + ACTIVE, + INACTIVE, +}; + +/** + * Supported USB controllers + */ +enum usb_ctrl { + DWC3_CTRL = 0, /* DWC3 controller */ + CI_CTRL, /* ChipIdea controller */ + HSIC_CTRL, /* HSIC controller */ + NUM_CTRL, +}; + +/** + * USB ID state + */ +enum usb_id_state { + USB_ID_GROUND = 0, + USB_ID_FLOAT, +}; + +/** + * struct msm_otg_platform_data - platform device data + * for msm_otg driver. + * @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as + * "do not overwrite default vaule at this address". + * @phy_init_sz: PHY configuration sequence size. + * @vbus_power: VBUS power on/off routine.It should return result + * as success(zero value) or failure(non-zero value). + * @power_budget: VBUS power budget in mA (0 will be treated as 500mA). + * @mode: Supported mode (OTG/peripheral/host). + * @otg_control: OTG switch controlled by user/Id pin + * @default_mode: Default operational mode. Applicable only if + * OTG switch is controller by user. + * @pmic_id_irq: IRQ number assigned for PMIC USB ID line. + * @mpm_otgsessvld_int: MPM wakeup pin assigned for OTG SESSVLD + * interrupt. Used when .otg_control == OTG_PHY_CONTROL. + * @mpm_dpshv_int: MPM wakeup pin assigned for DP SHV interrupt. + * Used during host bus suspend. + * @mpm_dmshv_int: MPM wakeup pin assigned for DM SHV interrupt. + * Used during host bus suspend. + * @mhl_enable: indicates MHL connector or not. + * @disable_reset_on_disconnect: perform USB PHY and LINK reset + * on USB cable disconnection. + * @pnoc_errata_fix: workaround needed for PNOC hardware bug that + * affects USB performance. + * @enable_lpm_on_suspend: Enable the USB core to go into Low + * Power Mode, when USB bus is suspended but cable + * is connected. + * @core_clk_always_on_workaround: Don't disable core_clk when + * USB enters LPM. + * @delay_lpm_on_disconnect: Use a delay before entering LPM + * upon USB cable disconnection. + * @enable_sec_phy: Use second HSPHY with USB2 core + * @bus_scale_table: parameters for bus bandwidth requirements + * @mhl_dev_name: MHL device name used to register with MHL driver. + * @log2_itc: value of 2^(log2_itc-1) will be used as the + * interrupt threshold (ITC), when log2_itc is + * between 1 to 7. + * @l1_supported: enable link power management support. + * @dpdm_pulldown_added: Indicates whether pull down resistors are + * connected on data lines or not. + * @vddmin_gpio: dedictaed gpio in the platform that is used for + * pullup the D+ line in case of bus suspend with + * phy retention. + * @enable_ahb2ahb_bypass: Indicates whether enable AHB2AHB BYPASS + * mode with controller in device mode. + * @bool disable_retention_with_vdd_min: Indicates whether to enable + allowing VDDmin without putting PHY into retention. + * @bool enable_phy_id_pullup: Indicates whether phy id pullup is + enabled or not. + * @usb_id_gpio: Gpio used for USB ID detection. + * @hub_reset_gpio: Gpio used for hub reset. + * @switch_sel_gpio: Gpio used for controlling switch that + routing D+/D- from the USB HUB to the USB jack type B + for peripheral mode. + * @bool phy_dvdd_always_on: PHY DVDD is supplied by always on PMIC LDO. + * @bool emulation: Indicates whether we are running on emulation platform. + * @bool enable_streaming: Indicates whether streaming to be enabled by default. + * @bool enable_axi_prefetch: Indicates whether AXI Prefetch interface is used + for improving data performance. + * @bool enable_sdp_typec_current_limit: Indicates whether type-c current for + sdp charger to be limited. + * @usbeth_reset_gpio: Gpio used for external usb-to-eth reset. + */ +struct msm_otg_platform_data { + int *phy_init_seq; + int phy_init_sz; + int (*vbus_power)(bool on); + unsigned power_budget; + enum usb_mode_type mode; + enum otg_control_type otg_control; + enum usb_mode_type default_mode; + enum msm_usb_phy_type phy_type; + void (*setup_gpio)(enum usb_otg_state state); + int (*link_clk_reset)(struct clk *link_clk, bool assert); + int (*phy_clk_reset)(struct clk *phy_clk); + int pmic_id_irq; + unsigned int mpm_otgsessvld_int; + unsigned int mpm_dpshv_int; + unsigned int mpm_dmshv_int; + bool mhl_enable; + bool disable_reset_on_disconnect; + bool pnoc_errata_fix; + bool enable_lpm_on_dev_suspend; + bool core_clk_always_on_workaround; + bool delay_lpm_on_disconnect; + bool dp_manual_pullup; + bool enable_sec_phy; + struct msm_bus_scale_pdata *bus_scale_table; + const char *mhl_dev_name; + int log2_itc; + bool l1_supported; + bool dpdm_pulldown_added; + int vddmin_gpio; + bool enable_ahb2ahb_bypass; + bool disable_retention_with_vdd_min; + bool enable_phy_id_pullup; + int usb_id_gpio; + int hub_reset_gpio; + int usbeth_reset_gpio; + int switch_sel_gpio; + bool phy_dvdd_always_on; + bool emulation; + bool enable_streaming; + bool enable_axi_prefetch; + bool enable_sdp_typec_current_limit; + bool vbus_low_as_hostmode; +}; + +/* phy related flags */ +#define ENABLE_DP_MANUAL_PULLUP BIT(0) +#define ENABLE_SECONDARY_PHY BIT(1) +#define PHY_HOST_MODE BIT(2) +#define PHY_CHARGER_CONNECTED BIT(3) +#define PHY_VBUS_VALID_OVERRIDE BIT(4) +#define DEVICE_IN_SS_MODE BIT(5) +#define PHY_LANE_A BIT(6) +#define PHY_LANE_B BIT(7) +#define PHY_HSFS_MODE BIT(8) +#define PHY_LS_MODE BIT(9) + +#define USB_NUM_BUS_CLOCKS 3 + +/** + * struct msm_otg: OTG driver data. Shared by HCD and DCD. + * @otg: USB OTG Transceiver structure. + * @pdata: otg device platform data. + * @irq: IRQ number assigned for HSUSB controller. + * @async_irq: IRQ number used by some controllers during low power state + * @phy_irq: IRQ number assigned for PHY to notify events like id and line + state changes. + * @clk: clock struct of usb_hs_clk. + * @pclk: clock struct of iface_clk. + * @core_clk: clock struct of core_bus_clk. + * @sleep_clk: clock struct of sleep_clk for USB PHY. + * @phy_reset_clk: clock struct of phy_reset_clk for USB PHY. This clock is + a reset only clock and resets the PHY, ULPI bridge and + CSR wrapper. + * @phy_por_clk: clock struct of phy_por_clk for USB PHY. This clock is + a reset only clock and resets only the PHY (POR). + * @phy_csr_clk: clock struct of phy_csr_clk for USB PHY. This clock is + required to access PHY CSR registers via AHB2PHY interface. + * @bus_clks: bimc/snoc/pcnoc clock struct. + * @default_noc_mode: default frequency for NOC clocks - SVS or NOM + * @core_clk_rate: core clk max frequency + * @regs: ioremapped register base address. + * @usb_phy_ctrl_reg: relevant PHY_CTRL_REG register base address. + * @inputs: OTG state machine inputs(Id, SessValid etc). + * @sm_work: OTG state machine work. + * @sm_work_pending: OTG state machine work is pending, queued post pm_resume + * @resume_pending: USB h/w lpm_exit pending. Done on next sm_work run + * @pm_suspended: OTG device is system(PM) suspended. + * @pm_notify: Notifier to receive system wide PM transition events. + It is used to defer wakeup events processing until + system is RESUMED. + * @in_lpm: indicates low power mode (LPM) state. + * @async_int: IRQ line on which ASYNC interrupt arrived in LPM. + * @cur_power: The amount of mA available from downstream port. + * @otg_wq: Strict order otg workqueue for OTG works (SM/ID/SUSPEND). + * @chg_work: Charger detection work. + * @chg_state: The state of charger detection process. + * @chg_type: The type of charger attached. + * @dcd_retires: The retry count used to track Data contact + * detection process. + * @wlock: Wake lock struct to prevent system suspend when + * USB is active. + * @xo_handle: TCXO buffer handle + * @bus_perf_client: Bus performance client handle to request BUS bandwidth + * @mhl_enabled: MHL driver registration successful and MHL enabled. + * @host_bus_suspend: indicates host bus suspend or not. + * @device_bus_suspend: indicates device bus suspend or not. + * @bus_clks_enabled: indicates pcnoc/snoc/bimc clocks are on or not. + * @chg_check_timer: The timer used to implement the workaround to detect + * very slow plug in of wall charger. + * @bc1p2_current_max: Max charging current allowed as per bc1.2 chg detection + * @typec_current_max: Max charging current allowed as per type-c chg detection + * @is_ext_chg_dcp: To indicate whether charger detected by external entity + SMB hardware is DCP charger or not. + * @ext_id_irq: IRQ for ID interrupt. + * @phy_irq_pending: Gets set when PHY IRQ arrives in LPM. + * @id_state: Indicates USBID line status. + * @rm_pulldown: Indicates pulldown status on D+ and D- data lines. + * @dbg_idx: Dynamic debug buffer Index. + * @dbg_lock: Dynamic debug buffer Lock. + * @buf: Dynamic Debug Buffer. + * @max_nominal_system_clk_rate: max freq at which system clock can run in + nominal mode. + */ +struct msm_otg { + struct usb_phy phy; + struct msm_otg_platform_data *pdata; + struct platform_device *pdev; + int irq; + int async_irq; + int phy_irq; + struct clk *clk; + struct clk *xo_clk; + struct clk *pclk; + struct clk *core_clk; + struct clk *sleep_clk; + struct clk *phy_reset_clk; + struct clk *phy_por_clk; + struct clk *phy_csr_clk; + struct clk *bus_clks[USB_NUM_BUS_CLOCKS]; + struct clk *phy_ref_clk; + long core_clk_rate; + long core_clk_svs_rate; + long core_clk_nominal_rate; + enum usb_noc_mode default_noc_mode; + struct resource *io_res; + void __iomem *regs; + void __iomem *phy_csr_regs; + void __iomem *usb_phy_ctrl_reg; +#define ID 0 +#define B_SESS_VLD 1 +#define A_BUS_SUSPEND 14 +#define MHL 17 +#define B_FALSE_SDP 18 + unsigned long inputs; + struct work_struct sm_work; + bool sm_work_pending; + bool resume_pending; + atomic_t pm_suspended; + struct notifier_block pm_notify; + atomic_t in_lpm; + bool err_event_seen; + int async_int; + unsigned cur_power; + int phy_number; + struct workqueue_struct *otg_wq; + struct delayed_work chg_work; + struct delayed_work id_status_work; + enum usb_chg_state chg_state; + enum usb_chg_type chg_type; + u8 dcd_retries; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vddcx; + struct reset_control *phy_rst; + struct reset_control *link_rst; + int vdd_levels[3]; + unsigned dcd_time; + struct wake_lock wlock; + unsigned long caps; + struct msm_xo_voter *xo_handle; + uint32_t bus_perf_client; + bool mhl_enabled; + bool host_bus_suspend; + bool device_bus_suspend; + bool bus_clks_enabled; + struct timer_list chg_check_timer; + /* + * Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v + * analog regulators while going to low power mode. + * Currently only 28nm PHY has the support to allowing PHY + * power collapse since it doesn't have leakage currents while + * turning off the power rails. + */ +#define ALLOW_PHY_POWER_COLLAPSE BIT(0) + /* + * Allow PHY RETENTION mode before turning off the digital + * voltage regulator(VDDCX). + */ +#define ALLOW_PHY_RETENTION BIT(1) + /* + * Allow putting the core in Low Power mode, when + * USB bus is suspended but cable is connected. + */ +#define ALLOW_LPM_ON_DEV_SUSPEND BIT(2) + /* + * Allowing PHY regulators LPM puts the HSUSB 3.3v and 1.8v + * analog regulators into LPM while going to USB low power mode. + */ +#define ALLOW_PHY_REGULATORS_LPM BIT(3) + /* + * Allow PHY RETENTION mode before turning off the digital + * voltage regulator(VDDCX) during host mode. + */ +#define ALLOW_HOST_PHY_RETENTION BIT(4) + /* + * Allow VDD minimization without putting PHY into retention + * for fixing PHY current leakage issue when LDOs ar turned off. + */ +#define ALLOW_VDD_MIN_WITH_RETENTION_DISABLED BIT(5) + + /* + * PHY can keep D+ pull-up during peripheral bus suspend and + * D+/D- pull-down during host bus suspend without any + * re-work. This is possible only when PHY DVDD is supplied + * by a PMIC LDO (unlike VDDCX/VDDMX). + */ +#define ALLOW_BUS_SUSPEND_WITHOUT_REWORK BIT(6) + unsigned long lpm_flags; +#define PHY_PWR_COLLAPSED BIT(0) +#define PHY_RETENTIONED BIT(1) +#define XO_SHUTDOWN BIT(2) +#define CLOCKS_DOWN BIT(3) +#define PHY_REGULATORS_LPM BIT(4) + int reset_counter; + struct power_supply usb_psy; + enum power_supply_type usb_supply_type; + unsigned int online; + unsigned int host_mode; + unsigned int voltage_max; + unsigned int current_max; + unsigned int bc1p2_current_max; + unsigned int typec_current_max; + unsigned int usbin_health; + + dev_t ext_chg_dev; + struct cdev ext_chg_cdev; + struct class *ext_chg_class; + struct device *ext_chg_device; + bool ext_chg_opened; + enum usb_ext_chg_status ext_chg_active; + struct completion ext_chg_wait; + struct pinctrl *phy_pinctrl; + bool is_ext_chg_dcp; + struct qpnp_vadc_chip *vadc_dev; + int ext_id_irq; + bool phy_irq_pending; + enum usb_id_state id_state; + bool rm_pulldown; +/* Maximum debug message length */ +#define DEBUG_MSG_LEN 128UL +/* Maximum number of messages */ +#define DEBUG_MAX_MSG 256UL + unsigned int dbg_idx; + rwlock_t dbg_lock; + + char (buf[DEBUG_MAX_MSG])[DEBUG_MSG_LEN]; /* buffer */ + unsigned int vbus_state; + unsigned int usb_irq_count; + int pm_qos_latency; + struct pm_qos_request pm_qos_req_dma; + struct delayed_work perf_vote_work; +}; + +struct ci13xxx_platform_data { + u8 usb_core_id; + int *tlmm_init_seq; + int tlmm_seq_count; + /* + * value of 2^(log2_itc-1) will be used as the interrupt threshold + * (ITC), when log2_itc is between 1 to 7. + */ + int log2_itc; + void *prv_data; + bool l1_supported; + bool enable_ahb2ahb_bypass; + bool enable_streaming; + bool enable_axi_prefetch; +}; + +/** + * struct msm_hsic_host_platform_data - platform device data + * for msm_hsic_host driver. + * @phy_sof_workaround: Enable ALL PHY SOF bug related workarounds for + SUSPEND, RESET and RESUME. + * @phy_susp_sof_workaround: Enable PHY SOF workaround for + * SUSPEND. + * @phy_reset_sof_workaround: Enable PHY SOF workaround for + * RESET. + * @dis_internal_clk_gating: If set, internal clock gating in controller + * is disabled. + * + */ +struct msm_hsic_host_platform_data { + unsigned strobe; + unsigned data; + bool ignore_cal_pad_config; + bool phy_sof_workaround; + bool dis_internal_clk_gating; + bool phy_susp_sof_workaround; + bool phy_reset_sof_workaround; + u32 reset_delay; + int strobe_pad_offset; + int data_pad_offset; + + struct msm_bus_scale_pdata *bus_scale_table; + unsigned log2_irq_thresh; + + /* gpio used to resume peripheral */ + unsigned resume_gpio; + int *tlmm_init_seq; + int tlmm_seq_count; + + /*swfi latency is required while driving resume on to the bus */ + u32 swfi_latency; + + /*standalone latency is required when HSCI is active*/ + u32 standalone_latency; + bool pool_64_bit_align; + bool enable_hbm; + bool disable_park_mode; + bool consider_ipa_handshake; + bool ahb_async_bridge_bypass; + bool disable_cerr; +}; + +struct msm_usb_host_platform_data { + unsigned int power_budget; + int pmic_gpio_dp_irq; + unsigned int dock_connect_irq; + bool use_sec_phy; + bool no_selective_suspend; + int resume_gpio; + int ext_hub_reset_gpio; + bool is_uicc; + int pm_qos_latency; +}; + +#ifdef CONFIG_USB_BAM +void msm_bam_set_usb_host_dev(struct device *dev); +void msm_bam_set_hsic_host_dev(struct device *dev); +void msm_bam_wait_for_usb_host_prod_granted(void); +void msm_bam_wait_for_hsic_host_prod_granted(void); +bool msm_bam_hsic_lpm_ok(void); +void msm_bam_usb_host_notify_on_resume(void); +void msm_bam_hsic_host_notify_on_resume(void); +bool msm_bam_hsic_host_pipe_empty(void); +bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable); +int msm_do_bam_disable_enable(enum usb_ctrl ctrl); +#else +static inline void msm_bam_set_usb_host_dev(struct device *dev) {} +static inline void msm_bam_set_hsic_host_dev(struct device *dev) {} +static inline void msm_bam_wait_for_usb_host_prod_granted(void) {} +static inline void msm_bam_wait_for_hsic_host_prod_granted(void) {} +static inline bool msm_bam_hsic_lpm_ok(void) { return true; } +static inline void msm_bam_hsic_host_notify_on_resume(void) {} +static inline void msm_bam_usb_host_notify_on_resume(void) {} +static inline bool msm_bam_hsic_host_pipe_empty(void) { return true; } +static inline bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable) +{ + return true; +} +int msm_do_bam_disable_enable(enum usb_ctrl ctrl) { return true; } +#endif +#ifdef CONFIG_USB_CI13XXX_MSM +void msm_hw_soft_reset(void); +void msm_hw_bam_disable(bool bam_disable); +void msm_usb_irq_disable(bool disable); +#else +static inline void msm_hw_soft_reset(void) +{ +} +static inline void msm_hw_bam_disable(bool bam_disable) +{ +} +static inline void msm_usb_irq_disable(bool disable) +{ +} +#endif + +/* CONFIG_PM_RUNTIME */ +#ifdef CONFIG_PM_RUNTIME +static inline int get_pm_runtime_counter(struct device *dev) +{ + return atomic_read(&dev->power.usage_count); +} +#else /* !CONFIG_PM_RUNTIME */ +static inline int get_pm_runtime_counter(struct device *dev) { return -ENOSYS; } +#endif + +#ifdef CONFIG_USB_DWC3_MSM +int msm_ep_config(struct usb_ep *ep, struct usb_request *request); +int msm_ep_unconfig(struct usb_ep *ep); +void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable); +int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr, u32 size, + u8 dst_pipe_idx); +bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget); +int msm_dwc3_reset_dbm_ep(struct usb_ep *ep); + +#else +static inline int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr, + u32 size, u8 dst_pipe_idx) +{ + return -ENODEV; +} + +static inline int msm_ep_config(struct usb_ep *ep, struct usb_request *request) +{ + return -ENODEV; +} + +static inline int msm_ep_unconfig(struct usb_ep *ep) +{ + return -ENODEV; +} + +static inline void dwc3_tx_fifo_resize_request( + struct usb_ep *ep, bool qdss_enable) +{ +} + +static inline bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget) +{ + return false; +} + +static inline int msm_dwc3_reset_dbm_ep(struct usb_ep *ep) +{ + return -ENODEV; +} + +#endif +#endif -- 2.25.1 From fb88e5b4de8f8dce87e8c5c34fc2bca9f5d58dac Mon Sep 17 00:00:00 2001 From: vipinbb Date: Sun, 14 Jun 2020 23:58:08 -0400 Subject: [PATCH 35/76] MeiG: liangdi:add ptn5150 drivers Change-Id: I4c53fb3587d3d48db043379455b6df2603cf6bdd --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 24 +- arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 15 + arch/arm/configs/msm8909-perf_defconfig | 4 +- drivers/extcon/Kconfig | 8 + drivers/extcon/Makefile | 1 + drivers/extcon/extcon-ptn5150.c | 389 ++++++++++++++++++++ drivers/input/misc/bmi160_driver.c | 10 +- 7 files changed, 439 insertions(+), 12 deletions(-) create mode 100755 drivers/extcon/extcon-ptn5150.c diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 9ff3474ce41..f2b9733907d 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -37,7 +37,7 @@ qcom,recharge-thresh-mv = <100>; regulator-name = "smb1357_otg_vreg"; qcom,soft-vfloat-comp-disabled; - qcom,thermal-mitigation = <1250 1250 1000 0>; + qcom,thermal-mitigation = <2500 2500 1000 0>; qcom,fastchg-ma = <1250>; qcom,bms-psy-name = "bms"; @@ -198,7 +198,7 @@ touchscreen-size-y = <800>; touchscreen-max-w = <512>; touchscreen-max-p = <512>; - touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158��KEY_MENU=139*/ + touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158£¬KEY_MENU=139*/ goodix,slide-wakeup = <0>; goodix,type-a-report = <0>; @@ -367,7 +367,8 @@ &blsp1_uart1 { status = "ok"; pinctrl-names = "default"; - pinctrl-0 = <&uart_console_sleep>; + //pinctrl-0 = <&uart_console_sleep>; + pinctrl-0 = <&uart_console_active>; }; &blsp1_uart2 { @@ -376,7 +377,7 @@ pinctrl-0 = <&nrf52_active>; }; -/*&spi_0 { +&spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; reg = <0>; @@ -394,7 +395,7 @@ pinctrl-2 = <&nrf_release>; status = "ok"; }; -};*/ +}; / { mtp_batterydata: qcom,battery-data { @@ -552,7 +553,18 @@ vio-supply = <&pm8909_l6>; bosch,place = <5>; bosch,gpio-int1 = <&msm_gpio 96 0x2002>; - }; + }; + + ptn5150@1d { + compatible = "nxp,ptn5150"; + reg = <0x1d>; + int-gpio = <&msm_gpio 31 0x2004>; + port-gpio = <&msm_gpio 3 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&ptn5150_default>; + status = "disabled"; + }; + }; &mdss_mdp { diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index 55175b7d8d4..f794c6849b1 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -1086,6 +1086,21 @@ }; }; + ptn5150_default { + ptn5150_default: ptn5150_default { + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + tlmm_gpio_key { gpio_key_active: gpio_key_active { mux { diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 7394dd5d0e2..af499987261 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -320,7 +320,7 @@ CONFIG_SENSORS_BMA2X2=y # CONFIG_DEVKMEM is not set CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y +# CONFIG_SERIAL_MSM_HSL_CONSOLE=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y @@ -570,3 +570,5 @@ CONFIG_TOUCHSCREEN_GT9XX=y # CONFIG_GT9XX_TOUCHPANEL_DEBUG=y CONFIG_MG_DRIVER_CONTROL=y CONFIG_NRF_DRIVER=y +CONFIG_EXTCON=y +CONFIG_EXTCON_PTN5150=y diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 6a1f7de6fa5..fd70eaad3b0 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -93,4 +93,12 @@ config EXTCON_SM5502 Silicon Mitus SM5502. The SM5502 is a USB port accessory detector and switch. +config EXTCON_PTN5150 + tristate "PTN5150 CC (Configuration Channel) LOGIC USB EXTCON support" + depends on I2C + select REGMAP_I2C + help + Say Y here to enable support for USB peripheral and USB host + detection by ptn5150 CC (Configuration Channel) logic chip. + endif # MULTISTATE_SWITCH diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 0370b42e5a2..017c87d3343 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o +obj-$(CONFIG_EXTCON_PTN5150) += extcon-ptn5150.o diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c new file mode 100755 index 00000000000..bb19ab6e10d --- /dev/null +++ b/drivers/extcon/extcon-ptn5150.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// extcon-ptn5150.c - PTN5150 CC logic extcon driver to support USB detection +// +// Based on extcon-sm5502.c driver +// Copyright (c) 2018-2019 by Vijai Kumar K +// Author: Vijai Kumar K + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PTN5150 registers */ +enum ptn5150_reg { + PTN5150_REG_DEVICE_ID = 0x01, + PTN5150_REG_CONTROL, + PTN5150_REG_INT_STATUS, + PTN5150_REG_CC_STATUS, + PTN5150_REG_CON_DET = 0x09, + PTN5150_REG_VCONN_STATUS, + PTN5150_REG_RESET, + PTN5150_REG_INT_MASK = 0x18, + PTN5150_REG_INT_REG_STATUS, + PTN5150_REG_END, +}; + +#define PTN5150_DFP_ATTACHED 0x1 +#define PTN5150_UFP_ATTACHED 0x2 + +/* Define PTN5150 MASK/SHIFT constant */ +#define PTN5150_REG_DEVICE_ID_VENDOR_SHIFT 0 +#define PTN5150_REG_DEVICE_ID_VENDOR_MASK \ + (0x3 << PTN5150_REG_DEVICE_ID_VENDOR_SHIFT) + +#define PTN5150_REG_DEVICE_ID_VERSION_SHIFT 3 +#define PTN5150_REG_DEVICE_ID_VERSION_MASK \ + (0x1f << PTN5150_REG_DEVICE_ID_VERSION_SHIFT) + +#define PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT 2 +#define PTN5150_REG_CC_PORT_ATTACHMENT_MASK \ + (0x7 << PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT) + +#define PTN5150_REG_CC_VBUS_DETECTION_SHIFT 7 +#define PTN5150_REG_CC_VBUS_DETECTION_MASK \ + (0x1 << PTN5150_REG_CC_VBUS_DETECTION_SHIFT) + +#define PTN5150_REG_INT_CABLE_ATTACH_SHIFT 0 +#define PTN5150_REG_INT_CABLE_ATTACH_MASK \ + (0x1 << PTN5150_REG_INT_CABLE_ATTACH_SHIFT) + +#define PTN5150_REG_INT_CABLE_DETACH_SHIFT 1 +#define PTN5150_REG_INT_CABLE_DETACH_MASK \ + (0x1 << PTN5150_REG_INT_CABLE_DETACH_SHIFT) + +struct ptn5150_info { + struct device *dev; + struct extcon_dev *edev; + struct i2c_client *i2c; + struct regmap *regmap; + struct gpio_desc *int_gpiod; + //struct gpio_desc *vbus_gpiod; + struct gpio_desc *port_gpiod; + int irq; + struct work_struct irq_work; + struct mutex mutex; +}; +#if 0 +/* List of detectable cables */ +static const unsigned int ptn5150_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, +// EXTCON_NONE, +}; +#else +enum { + EXTCON_CABLE_USB = 0, + EXTCON_CABLE_USB_HOST, + EXTCON_CABLE_TA, + EXTCON_CABLE_FAST_CHARGER, + EXTCON_CABLE_SLOW_CHARGER, + EXTCON_CABLE_CHARGE_DOWNSTREAM, + EXTCON_CABLE_MHL, + EXTCON_CABLE_MHL_TA, + EXTCON_CABLE_JIG_USB_ON, + EXTCON_CABLE_JIG_USB_OFF, + EXTCON_CABLE_JIG_UART_OFF, + EXTCON_CABLE_JIG_UART_ON, + EXTCON_CABLE_DOCK_SMART, + EXTCON_CABLE_DOCK_DESK, + EXTCON_CABLE_DOCK_AUDIO, + + _EXTCON_CABLE_NUM, +}; + +static const char *ptn5150_extcon_cable[] = { + [EXTCON_CABLE_USB] = "USB", + [EXTCON_CABLE_USB_HOST] = "USB-Host", + NULL, +}; + +#endif +static const struct regmap_config ptn5150_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PTN5150_REG_END, +}; + +static void ptn5150_irq_work(struct work_struct *work) +{ + struct ptn5150_info *info = container_of(work, + struct ptn5150_info, irq_work); + int ret = 0; + unsigned int reg_data; + unsigned int int_status; + + if (!info->edev) + return; + + mutex_lock(&info->mutex); + + ret = regmap_read(info->regmap, PTN5150_REG_CC_STATUS, ®_data); + if (ret) { + dev_err(info->dev, "failed to read CC STATUS %d\n", ret); + mutex_unlock(&info->mutex); + return; + } + + /* Clear interrupt. Read would clear the register */ + ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, &int_status); + if (ret) { + dev_err(info->dev, "failed to read INT STATUS %d\n", ret); + mutex_unlock(&info->mutex); + return; + } + + if (int_status) { + unsigned int cable_attach; + + cable_attach = int_status & PTN5150_REG_INT_CABLE_ATTACH_MASK; + if (cable_attach) { + unsigned int port_status; +// unsigned int vbus; + + port_status = ((reg_data & + PTN5150_REG_CC_PORT_ATTACHMENT_MASK) >> + PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT); + + switch (port_status) { + case PTN5150_DFP_ATTACHED: +/* + extcon_set_state_sync(info->edev, + EXTCON_USB_HOST, false); + gpiod_set_value(info->vbus_gpiod, 0); + extcon_set_state_sync(info->edev, EXTCON_USB, + true); +*/ + extcon_set_cable_state(info->edev, "USB-Host", false); + extcon_set_cable_state(info->edev, "USB", true); + break; + case PTN5150_UFP_ATTACHED: +/* + extcon_set_state_sync(info->edev, EXTCON_USB, + false); + vbus = ((reg_data & + PTN5150_REG_CC_VBUS_DETECTION_MASK) >> + PTN5150_REG_CC_VBUS_DETECTION_SHIFT); + if (vbus) + gpiod_set_value(info->vbus_gpiod, 0); + else + gpiod_set_value(info->vbus_gpiod, 1); + + extcon_set_state_sync(info->edev, + EXTCON_USB_HOST, true); +*/ + extcon_set_cable_state(info->edev, "USB", false); + extcon_set_cable_state(info->edev, "USB-Host", true); + break; + default: + dev_err(info->dev, + "Unknown Port status : %x\n", + port_status); + break; + } + } else { +/* + extcon_set_state_sync(info->edev, + EXTCON_USB_HOST, false); + extcon_set_state_sync(info->edev, + EXTCON_USB, false); + gpiod_set_value(info->vbus_gpiod, 0); +*/ + extcon_set_cable_state(info->edev, "USB-Host", false); + extcon_set_cable_state(info->edev, "USB", true); + } + } + + /* Clear interrupt. Read would clear the register */ + ret = regmap_read(info->regmap, PTN5150_REG_INT_REG_STATUS, + &int_status); + if (ret) { + dev_err(info->dev, + "failed to read INT REG STATUS %d\n", ret); + mutex_unlock(&info->mutex); + return; + } + + mutex_unlock(&info->mutex); +} + + +static irqreturn_t ptn5150_irq_handler(int irq, void *data) +{ + struct ptn5150_info *info = data; + + schedule_work(&info->irq_work); + + return IRQ_HANDLED; +} + +static int ptn5150_init_dev_type(struct ptn5150_info *info) +{ + unsigned int reg_data, vendor_id, version_id; + int ret; + + ret = regmap_read(info->regmap, PTN5150_REG_DEVICE_ID, ®_data); + if (ret) { + dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); + return -EINVAL; + } + + vendor_id = ((reg_data & PTN5150_REG_DEVICE_ID_VENDOR_MASK) >> + PTN5150_REG_DEVICE_ID_VENDOR_SHIFT); + version_id = ((reg_data & PTN5150_REG_DEVICE_ID_VERSION_MASK) >> + PTN5150_REG_DEVICE_ID_VERSION_SHIFT); + + dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n", + version_id, vendor_id); + + /* Clear any existing interrupts */ + ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, ®_data); + if (ret) { + dev_err(info->dev, + "failed to read PTN5150_REG_INT_STATUS %d\n", + ret); + return -EINVAL; + } + + ret = regmap_read(info->regmap, PTN5150_REG_INT_REG_STATUS, ®_data); + if (ret) { + dev_err(info->dev, + "failed to read PTN5150_REG_INT_REG_STATUS %d\n", ret); + return -EINVAL; + } + + return 0; +} + +static int ptn5150_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct device_node *np = i2c->dev.of_node; + struct ptn5150_info *info; + int ret; + + if (!np) + return -EINVAL; + + info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + i2c_set_clientdata(i2c, info); + + info->dev = &i2c->dev; + info->i2c = i2c; + info->int_gpiod = devm_gpiod_get(&i2c->dev, "int", GPIOD_IN); + if (IS_ERR(info->int_gpiod)) { + dev_err(dev, "failed to get INT GPIO\n"); + return PTR_ERR(info->int_gpiod); + } + + info->port_gpiod = devm_gpiod_get(&i2c->dev, "port", GPIOD_IN); + if (IS_ERR(info->port_gpiod)) { + dev_err(dev, "failed to get port GPIO\n"); + return PTR_ERR(info->port_gpiod); + } + ret = gpiod_direction_output(info->port_gpiod, 0);//set to UFP + if (ret) { + dev_err(dev, "failed to set port GPIO direction\n"); + return -EINVAL; + } + + pr_info("int gpio %d, port gpio %d\n",desc_to_gpio(info->int_gpiod),desc_to_gpio(info->port_gpiod)); +/* + info->vbus_gpiod = devm_gpiod_get(&i2c->dev, "vbus", GPIOD_IN); + if (IS_ERR(info->vbus_gpiod)) { + dev_err(dev, "failed to get VBUS GPIO\n"); + return -EINVAL; + } + ret = gpiod_direction_output(info->vbus_gpiod, 0); + if (ret) { + dev_err(dev, "failed to set VBUS GPIO direction\n"); + return (info->vbus_gpiod); + } +*/ + mutex_init(&info->mutex); + + INIT_WORK(&info->irq_work, ptn5150_irq_work); + + info->regmap = devm_regmap_init_i2c(i2c, &ptn5150_regmap_config); + if (IS_ERR(info->regmap)) { + ret = PTR_ERR(info->regmap); + dev_err(info->dev, "failed to allocate register map: %d\n", + ret); + return ret; + } + + if (info->int_gpiod) { + info->irq = gpiod_to_irq(info->int_gpiod); + if (info->irq < 0) { + dev_err(dev, "failed to get INTB IRQ\n"); + return info->irq; + } + + ret = devm_request_threaded_irq(dev, info->irq, NULL, + ptn5150_irq_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + i2c->name, info); + if (ret < 0) { + dev_err(dev, "failed to request handler for INTB IRQ\n"); + return ret; + } + } + + /* Allocate extcon device */ + info->edev = devm_extcon_dev_allocate(info->dev, ptn5150_extcon_cable); + if (IS_ERR(info->edev)) { + dev_err(info->dev, "failed to allocate memory for extcon\n"); + return -ENOMEM; + } + + /* Register extcon device */ + ret = devm_extcon_dev_register(info->dev, info->edev); + if (ret) { + dev_err(info->dev, "failed to register extcon device\n"); + return ret; + } + + /* Initialize PTN5150 device and print vendor id and version id */ + ret = ptn5150_init_dev_type(info); + if (ret) + return -EINVAL; + + return 0; +} + +static const struct of_device_id ptn5150_dt_match[] = { + { .compatible = "nxp,ptn5150" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ptn5150_dt_match); + +static const struct i2c_device_id ptn5150_i2c_id[] = { + { "ptn5150", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ptn5150_i2c_id); + +static struct i2c_driver ptn5150_i2c_driver = { + .driver = { + .name = "ptn5150", + .of_match_table = ptn5150_dt_match, + }, + .probe = ptn5150_i2c_probe, + .id_table = ptn5150_i2c_id, +}; + +static int __init ptn5150_i2c_init(void) +{ + return i2c_add_driver(&ptn5150_i2c_driver); +} +subsys_initcall(ptn5150_i2c_init); diff --git a/drivers/input/misc/bmi160_driver.c b/drivers/input/misc/bmi160_driver.c index bd18a537394..fc3fe650459 100755 --- a/drivers/input/misc/bmi160_driver.c +++ b/drivers/input/misc/bmi160_driver.c @@ -4719,9 +4719,9 @@ static void bmi160_set_acc_enable(struct device *dev, unsigned int enable) mutex_exit: mutex_unlock(&client_data->mutex_enable); - dev_notice(dev, - "acc_enable en_state=%d\n", - atomic_read(&client_data->wkqueue_en)); +// dev_notice(dev, +// "acc_enable en_state=%d\n", +// atomic_read(&client_data->wkqueue_en)); } @@ -4763,8 +4763,8 @@ static void bmi160_set_gyro_enable(struct device *dev, unsigned int enable) mutex_exit: mutex_unlock(&client_data->mutex_enable); - dev_notice(&client->dev, "gyro_enable en_state=%d\n", - atomic_read(&client_data->gyro_en)); +// dev_notice(&client->dev, "gyro_enable en_state=%d\n", +// atomic_read(&client_data->gyro_en)); } -- 2.25.1 From e90eb3dc8a15320d5ebd8a0ce3334f5e2e74ecbf Mon Sep 17 00:00:00 2001 From: vipinbb Date: Mon, 15 Jun 2020 08:13:06 -0400 Subject: [PATCH 36/76] MeiG: liangdi:fix read nv issue Change-Id: I08d8e2e0e54908ba37f1c84d981e341eb22224fb --- drivers/char/diag/diagchar_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 2c235bce013..439ec0f905f 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -2639,6 +2639,10 @@ static int diag_user_process_raw_data(const char __user *buf, int len) if (!user_space_data) return -ENOMEM; + //add by liangdi for read nv cause the process consume CPU 20200602 + usleep_range(10000, 10100); + //add end + err = copy_from_user(user_space_data, buf, len); if (err) { pr_err("diag: copy failed for user space data\n"); -- 2.25.1 From 3bb0cfadaca5a40273be6cb97d56ff1da23aa521 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 17 Jun 2020 10:35:59 -0400 Subject: [PATCH 37/76] kernel/msm-3.18: disable SPI drver Change-Id: I0df03a701f9b5ca9bf6c26553cbffea0d9177dc7 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index f2b9733907d..8620039f937 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -377,6 +377,7 @@ pinctrl-0 = <&nrf52_active>; }; +/* &spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; @@ -396,7 +397,7 @@ status = "ok"; }; }; - +*/ / { mtp_batterydata: qcom,battery-data { qcom,rpull-up-kohm = <100>; -- 2.25.1 From 0d87b363c593917e9c04317dc7a656c230cfa05e Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 30 Jun 2020 12:46:54 -0400 Subject: [PATCH 38/76] MeiG liangdi enable ptn5150 for typeC Change-Id: I26cbef049638469ac55bb300a8ce911474893c6f --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 7 +++-- drivers/extcon/extcon-ptn5150.c | 35 ++++++++++++++++++++++++- drivers/power/smb135x-charger.c | 10 +++++-- drivers/usb/phy/phy-msm-usb.c | 6 +++-- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 8620039f937..2b3c132444c 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -198,7 +198,7 @@ touchscreen-size-y = <800>; touchscreen-max-w = <512>; touchscreen-max-p = <512>; - touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158£¬KEY_MENU=139*/ + touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158��KEY_MENU=139*/ goodix,slide-wakeup = <0>; goodix,type-a-report = <0>; @@ -377,7 +377,6 @@ pinctrl-0 = <&nrf52_active>; }; -/* &spi_0 { nrf_spi@0 { compatible = "qcom,nrf"; @@ -397,7 +396,7 @@ status = "ok"; }; }; -*/ + / { mtp_batterydata: qcom,battery-data { qcom,rpull-up-kohm = <100>; @@ -563,7 +562,7 @@ port-gpio = <&msm_gpio 3 0x0>; pinctrl-names = "default"; pinctrl-0 = <&ptn5150_default>; - status = "disabled"; + //status = "disabled"; }; }; diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c index bb19ab6e10d..82ec180c72e 100755 --- a/drivers/extcon/extcon-ptn5150.c +++ b/drivers/extcon/extcon-ptn5150.c @@ -30,6 +30,11 @@ enum ptn5150_reg { PTN5150_REG_END, }; +enum mode_select { + UFP_MODE = 0x00, + DFP_MODE, + DRP_MODE, +}; #define PTN5150_DFP_ATTACHED 0x1 #define PTN5150_UFP_ATTACHED 0x2 @@ -145,7 +150,7 @@ static void ptn5150_irq_work(struct work_struct *work) cable_attach = int_status & PTN5150_REG_INT_CABLE_ATTACH_MASK; if (cable_attach) { unsigned int port_status; -// unsigned int vbus; + unsigned int vbus; port_status = ((reg_data & PTN5150_REG_CC_PORT_ATTACHMENT_MASK) >> @@ -160,6 +165,7 @@ static void ptn5150_irq_work(struct work_struct *work) extcon_set_state_sync(info->edev, EXTCON_USB, true); */ + pr_err("DFP attached\n"); extcon_set_cable_state(info->edev, "USB-Host", false); extcon_set_cable_state(info->edev, "USB", true); break; @@ -178,6 +184,16 @@ static void ptn5150_irq_work(struct work_struct *work) extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true); */ + + pr_err("UFP attached\n"); + vbus = ((reg_data & + PTN5150_REG_CC_VBUS_DETECTION_MASK) >> + PTN5150_REG_CC_VBUS_DETECTION_SHIFT); + if (vbus) + pr_err("VBUS detected\n"); + else + pr_err("VBUS not detected\n"); + extcon_set_cable_state(info->edev, "USB", false); extcon_set_cable_state(info->edev, "USB-Host", true); break; @@ -195,6 +211,7 @@ static void ptn5150_irq_work(struct work_struct *work) EXTCON_USB, false); gpiod_set_value(info->vbus_gpiod, 0); */ + pr_err("Cable Detached\n"); extcon_set_cable_state(info->edev, "USB-Host", false); extcon_set_cable_state(info->edev, "USB", true); } @@ -242,6 +259,22 @@ static int ptn5150_init_dev_type(struct ptn5150_info *info) dev_info(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n", version_id, vendor_id); + //add by liangdi for set DRP mode + ret = regmap_read(info->regmap, PTN5150_REG_CONTROL, ®_data); + if (ret) { + dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); + return -EINVAL; + } + dev_info(info->dev, "1ptn5150 reg control 0x%x\n",reg_data); + reg_data = (reg_data & (~(0x3 << 1))) | (DRP_MODE << 1); + + ret = regmap_write(info->regmap, PTN5150_REG_CONTROL, reg_data); + if (ret) { + dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); + return -EINVAL; + } + //add end + /* Clear any existing interrupts */ ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, ®_data); if (ret) { diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 507ce5e3965..baa7e4bdc0e 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -3045,10 +3045,12 @@ static void battery_detect_soc_work(struct work_struct *work) struct smb135x_chg, bat_detect_soc_work.work); int rc = 0; int soc = 0; + int vol_now = 0; soc = smb135x_get_prop_batt_capacity(chip); + vol_now = smb135x_get_prop_batt_voltage(chip);; -// pr_err("detect soc usb_present=%d, soc %d, fastchg_ma_now %d\n", -// chip->usb_present,soc,chip->fastchg_ma_now); + pr_err("detect soc usb_present=%d, soc %d, fastchg_ma_now %d,vol_now %d\n", + chip->usb_present,soc,chip->fastchg_ma_now,vol_now); if((soc <= 15) && (chip->fastchg_ma_now != MAX_FAST_CHARG_CURRENT)) { @@ -4588,6 +4590,10 @@ static int smb135x_main_charger_probe(struct i2c_client *client, create_debugfs_entries(chip); + //add by liangdi for charging issue 20200619 + smb135x_chg_stat_handler(client->irq, chip); + //add end + //add by liangdi for detect soc and limit max charging current 20200527 INIT_DELAYED_WORK(&chip->bat_detect_soc_work, battery_detect_soc_work); schedule_delayed_work(&chip->bat_detect_soc_work, msecs_to_jiffies(200)); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 29cc240ec3f..c306a628e1f 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -104,7 +104,7 @@ module_param(lpm_disconnect_thresh , uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(lpm_disconnect_thresh, "Delay before entering LPM on USB disconnect"); -static bool floated_charger_enable; +static bool floated_charger_enable = 1;//add by liangdi for charging issue 20200619 module_param(floated_charger_enable , bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(floated_charger_enable, "Whether to enable floated charger"); @@ -2855,9 +2855,11 @@ static void msm_otg_sm_work(struct work_struct *w) break; case USB_CDP_CHARGER: msm_otg_notify_charger(motg, - IDEV_CHG_MAX); + 900);//add by liangdi for reduce CDP current 20200619 /* fall through */ case USB_SDP_CHARGER: + msm_otg_notify_charger(motg, + 500);//add by liangdi for charging issue 20200619 pm_runtime_get_sync(otg->phy->dev); msm_otg_start_peripheral(otg, 1); otg->phy->state = -- 2.25.1 From ad736b3270df42765537d9c76d1f90fa5be89dfe Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 7 Jul 2020 10:46:12 -0400 Subject: [PATCH 39/76] MeiG: liangdi: add beeper freq control Change-Id: I16bcf9b36aaf4fbd1b2fd29840ba9ce862000aab --- drivers/platform/msm/qpnp-vibrator.c | 59 ++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index 527c21a350a..43cfe1a9811 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -64,7 +64,8 @@ enum sound_mode { }; //add end -#define GPIO_PWM_DELAY_TIME (250000) +#define DEFAULT_PWM_FREQ_HZ (4000)///4K HZ +#define GPIO_PWM_DELAY_TIME (10000000)//100 HZ (250000) static struct qpnp_vib *gl_vib = NULL; //add by huangshifang for beeper sound control 20200516 static struct spmi_driver qpnp_vibrator_driver; @@ -118,6 +119,8 @@ struct qpnp_vib { u32 loud_gpio_flags; int sound_mode; //add end + int pwm_freq_hz; + int pwm_timer_value; }; static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer); @@ -199,10 +202,10 @@ static int qpnp_vibrator_config(struct qpnp_vib *vib) static void gpio_pwm_start(void) { //pr_err("gpio pwm start\n"); - gl_vib->time = (unsigned long)((50 * GPIO_PWM_DELAY_TIME)/100); + gl_vib->time = (unsigned long)((50 * gl_vib->pwm_timer_value)/100); gl_vib->pwm_level = 0; - gl_vib->kt = ktime_set(0, GPIO_PWM_DELAY_TIME); + gl_vib->kt = ktime_set(0, gl_vib->pwm_timer_value); hrtimer_start(&gl_vib->mytimer,gl_vib->kt,HRTIMER_MODE_REL); } @@ -270,28 +273,28 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(gl_vib->quiet_gpio, 0); gpio_direction_output(gl_vib->loud_gpio, 0); gpio_direction_output(gl_vib->medium_gpio, 0); - pr_err("sound_none start \n"); + //pr_err("sound_none start \n"); break; case SOUND_QUIET: gpio_direction_output(gl_vib->quiet_gpio, 1); gpio_direction_output(gl_vib->medium_gpio, 0); gpio_direction_output(gl_vib->loud_gpio, 0); gpio_direction_output(gl_vib->pwr_gpio, 1); - pr_err("sound_quiet start \n"); + //pr_err("sound_quiet start \n"); break; case SOUND_MEDIUM: gpio_direction_output(gl_vib->quiet_gpio, 0); gpio_direction_output(gl_vib->medium_gpio, 1); gpio_direction_output(gl_vib->loud_gpio, 0); gpio_direction_output(gl_vib->pwr_gpio, 1); - pr_err("sound_medium start \n"); + //pr_err("sound_medium start \n"); break; case SOUND_LOUD: gpio_direction_output(gl_vib->quiet_gpio, 0); gpio_direction_output(gl_vib->medium_gpio, 0); gpio_direction_output(gl_vib->loud_gpio, 1); gpio_direction_output(gl_vib->pwr_gpio, 1); - pr_err("sound_loud start \n"); + //pr_err("sound_loud start \n"); break; default: break; @@ -586,6 +589,37 @@ static ssize_t store_driver_attr_beeper(struct device_driver *dev, const char *b } static DRIVER_ATTR(beeper, S_IWUSR | S_IRUGO, show_driver_attr_beeper, store_driver_attr_beeper); + +static ssize_t store_driver_attr_beeper_freq(struct device_driver *dev, const char *buf, size_t count) +{ + ssize_t ret = -EINVAL; + unsigned long freq = 0; + unsigned long timerper100hz = 0; + + ret = kstrtoul(buf, 10, &freq); + if (ret) + return ret; + + if(freq <= 100)///100 Hz + freq = 100; + + if(freq >= 100000)///100K Hz + freq = 100000; + + timerper100hz = GPIO_PWM_DELAY_TIME; + + gl_vib->pwm_timer_value = timerper100hz / (freq / 100); + + gl_vib->pwm_freq_hz = freq; + return count; +} + +static ssize_t show_driver_attr_beeper_freq(struct device_driver *dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", gl_vib->pwm_freq_hz); +} + +static DRIVER_ATTR(beeper_freq, S_IWUSR | S_IRUGO, show_driver_attr_beeper_freq, store_driver_attr_beeper_freq); //add end static int qpnp_vibrator_probe(struct spmi_device *spmi) @@ -654,6 +688,9 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) } vib->sound_mode = SOUND_MEDIUM; + + vib->pwm_freq_hz = DEFAULT_PWM_FREQ_HZ;///4 Khz + vib->pwm_timer_value = GPIO_PWM_DELAY_TIME / (vib->pwm_freq_hz / 100); //add end rc = qpnp_vibrator_config(vib); @@ -665,7 +702,13 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) //add by huangshifang for beeper sound control 20200516 if(driver_create_file(&qpnp_vibrator_driver.driver, &driver_attr_beeper)) { - pr_err("mg_drv_probe driver_creat_file ERROR \n"); + pr_err("beeper driver_creat_file ERROR \n"); + return ret; + } + + if(driver_create_file(&qpnp_vibrator_driver.driver, &driver_attr_beeper_freq)) + { + pr_err("beeper driver_creat_file ERROR \n"); return ret; } //add end -- 2.25.1 From 51b1653bca286faf38d28347179c5ed9721845f6 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 10 Jul 2020 08:35:48 -0400 Subject: [PATCH 40/76] MeiG: liangdi: fix kernel warning Change-Id: Iae474e9c348a4cf71b3882130098e94a2b81db09 --- drivers/extcon/extcon-class.c | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c index 4c2f2c543bb..0b60d694be5 100644 --- a/drivers/extcon/extcon-class.c +++ b/drivers/extcon/extcon-class.c @@ -66,9 +66,9 @@ const char extcon_cable_name[][CABLE_NAME_MAX + 1] = { }; static struct class *extcon_class; -#if defined(CONFIG_ANDROID) -static struct class_compat *switch_class; -#endif /* CONFIG_ANDROID */ +//#if defined(CONFIG_ANDROID) +//static struct class_compat *switch_class; +//#endif /* CONFIG_ANDROID */ static LIST_HEAD(extcon_dev_list); static DEFINE_MUTEX(extcon_dev_list_lock); @@ -546,11 +546,11 @@ static int create_extcon_class(void) return PTR_ERR(extcon_class); extcon_class->dev_groups = extcon_groups; -#if defined(CONFIG_ANDROID) - switch_class = class_compat_register("switch"); - if (WARN(!switch_class, "cannot allocate")) - return -ENOMEM; -#endif /* CONFIG_ANDROID */ +//#if defined(CONFIG_ANDROID) +// switch_class = class_compat_register("switch"); +/// if (WARN(!switch_class, "cannot allocate")) +// return -ENOMEM; +//#endif /* CONFIG_ANDROID */ } return 0; @@ -829,10 +829,10 @@ int extcon_dev_register(struct extcon_dev *edev) put_device(&edev->dev); goto err_dev; } -#if defined(CONFIG_ANDROID) - if (switch_class) - ret = class_compat_create_link(switch_class, &edev->dev, NULL); -#endif /* CONFIG_ANDROID */ +//#if defined(CONFIG_ANDROID) +// if (switch_class) +// ret = class_compat_create_link(switch_class, &edev->dev, NULL); +//#endif /* CONFIG_ANDROID */ spin_lock_init(&edev->lock); @@ -907,10 +907,10 @@ void extcon_dev_unregister(struct extcon_dev *edev) kfree(edev->cables); } -#if defined(CONFIG_ANDROID) - if (switch_class) - class_compat_remove_link(switch_class, &edev->dev, NULL); -#endif +//#if defined(CONFIG_ANDROID) +// if (switch_class) +// class_compat_remove_link(switch_class, &edev->dev, NULL); +//#endif put_device(&edev->dev); } EXPORT_SYMBOL_GPL(extcon_dev_unregister); @@ -1021,9 +1021,9 @@ module_init(extcon_class_init); static void __exit extcon_class_exit(void) { -#if defined(CONFIG_ANDROID) - class_compat_unregister(switch_class); -#endif +//#if defined(CONFIG_ANDROID) +// class_compat_unregister(switch_class); +//#endif class_destroy(extcon_class); } module_exit(extcon_class_exit); -- 2.25.1 From dbbaa809d8cb51d1d758340cff43066cee41e3af Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 10 Jul 2020 08:42:23 -0400 Subject: [PATCH 41/76] MeiG: liangdi: optimize drivers Change-Id: I9b18095a19f9e134aed86a89a9c9708092a09b4f --- arch/arm/boot/dts/qcom/Makefile | 293 ------------------ .../arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi | 4 +- arch/arm/boot/dts/qcom/msm8909.dtsi | 4 +- arch/arm/configs/msm8909-perf_defconfig | 33 +- 4 files changed, 19 insertions(+), 315 deletions(-) diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 0bceda44a2e..edcdcccf3f8 100755 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -1,296 +1,3 @@ -dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-mtp.dtb \ - msm8996-v2-pmi8994-pmk8001-mtp.dtb \ - msm8996-v2-pmi8994-pm8004-mtp.dtb \ - msm8996-v2-pmi8994-pm8004-pmk8001-mtp.dtb \ - msm8996-v2-fluid.dtb \ - msm8996-v2-liquid.dtb \ - msm8996-v2-dtp.dtb \ - msm8996-v3-auto-cdp.dtb \ - msm8996-v3-auto-adp.dtb \ - msm8996-v3-pmi8994-cdp.dtb \ - msm8996-v3-pmi8994-mtp.dtb \ - msm8996-v3-pmi8994-pmk8001-cdp.dtb \ - msm8996-v3-pmi8994-pmk8001-mtp.dtb \ - msm8996-v3-pmi8994-pm8004-cdp.dtb \ - msm8996-v3-pmi8994-pm8004-mtp.dtb \ - msm8996-v3-pmi8994-pm8004-pmk8001-cdp.dtb \ - msm8996-v3-pmi8994-pm8004-pmk8001-mtp.dtb \ - msm8996-v3-pmi8996-cdp.dtb \ - msm8996-v3-pmi8996-mtp.dtb \ - msm8996-v3-pmi8996-pmk8001-cdp.dtb \ - msm8996-v3-pmi8996-pmk8001-mtp.dtb \ - msm8996-v3-fluid.dtb \ - msm8996-v3-liquid.dtb \ - msm8996-v3-dtp.dtb \ - msm8996-v3-pm8004-mmxf-adp.dtb \ - msm8996-v3-pm8004-agave-adp.dtb \ - msm8996-v3-pm8004-agave-adp-lite.dtb \ - msm8996pro-auto-adp.dtb \ - msm8996pro-auto-adp-lite.dtb \ - msm8996pro-auto-cdp.dtb \ - msm8996pro-pmi8994-cdp.dtb \ - msm8996pro-pmi8994-mtp.dtb \ - msm8996pro-pmi8994-pmk8001-cdp.dtb \ - msm8996pro-pmi8994-pmk8001-mtp.dtb \ - msm8996pro-pmi8994-pm8004-cdp.dtb \ - msm8996pro-pmi8994-pm8004-mtp.dtb \ - msm8996pro-pmi8994-pm8004-pmk8001-cdp.dtb \ - msm8996pro-pmi8994-pm8004-pmk8001-mtp.dtb \ - msm8996pro-pmi8996-cdp.dtb \ - msm8996pro-pmi8996-mtp.dtb \ - msm8996pro-pmi8996-pmk8001-cdp.dtb \ - msm8996pro-pmi8996-pmk8001-mtp.dtb \ - msm8996pro-v1.1-auto-cdp.dtb \ - msm8996pro-v1.1-pmi8994-cdp.dtb \ - msm8996pro-v1.1-pmi8994-mtp.dtb \ - msm8996pro-v1.1-pmi8994-pmk8001-cdp.dtb \ - msm8996pro-v1.1-pmi8994-pmk8001-mtp.dtb \ - msm8996pro-v1.1-pmi8994-pm8004-cdp.dtb \ - msm8996pro-v1.1-pmi8994-pm8004-mtp.dtb \ - msm8996pro-v1.1-pmi8994-pm8004-pmk8001-cdp.dtb \ - msm8996pro-v1.1-pmi8994-pm8004-pmk8001-mtp.dtb \ - msm8996pro-v1.1-pmi8996-cdp.dtb \ - msm8996pro-v1.1-pmi8996-mtp.dtb \ - msm8996pro-v1.1-pmi8996-pmk8001-cdp.dtb \ - msm8996pro-v1.1-pmi8996-pmk8001-mtp.dtb \ - apq8096pro-auto-cdp.dtb \ - apq8096pro-v1.1-auto-adp.dtb \ - apq8096pro-v1.1-auto-adp-lite.dtb \ - apq8096pro-liquid.dtb \ - apq8096pro-v1.1-auto-cdp.dtb \ - apq8096pro-v1.1-pmi8994-cdp.dtb \ - apq8096pro-v1.1-pmi8994-mtp.dtb \ - apq8096pro-v1.1-pmi8994-pmk8001-cdp.dtb \ - apq8096pro-v1.1-pmi8994-pmk8001-mtp.dtb \ - apq8096pro-v1.1-pmi8994-pm8004-cdp.dtb \ - apq8096pro-v1.1-pmi8994-pm8004-mtp.dtb \ - apq8096pro-v1.1-pmi8994-pm8004-pmk8001-cdp.dtb \ - apq8096pro-v1.1-pmi8994-pm8004-pmk8001-mtp.dtb \ - apq8096pro-v1.1-pmi8996-cdp.dtb \ - apq8096pro-v1.1-pmi8996-mtp.dtb \ - apq8096pro-v1.1-pmi8996-pmk8001-cdp.dtb \ - apq8096pro-v1.1-pmi8996-pmk8001-mtp.dtb \ - msm8996-v3.0-pmi8994-cdp.dtb \ - msm8996-v3.0-pmi8994-mtp.dtb \ - msm8996-v3.0-pmi8994-pm8004-cdp.dtb \ - msm8996-v3.0-pmi8994-pm8004-mtp.dtb \ - msm8996-v3.0-pmi8994-pm8004-pmk8001-cdp.dtb \ - msm8996-v3.0-pmi8994-pmk8001-cdp.dtb \ - msm8996-v3.0-pmi8996-cdp.dtb \ - msm8996-v3.0-pmi8996-mtp.dtb \ - msm8996-v3.0-fluid.dtb \ - msm8996-v3.0-liquid.dtb \ - msm8996-v3.0-dtp.dtb \ - apq8096-v2-pmi8994-mtp.dtb \ - apq8096-v2-liquid.dtb \ - apq8096-v2-dragonboard.dtb \ - apq8096-v2-auto-dragonboard.dtb \ - apq8096-v3-pmi8994-cdp.dtb \ - apq8096-v3-pmi8994-mtp.dtb \ - apq8096-v3-pmi8994-pmk8001-cdp.dtb \ - apq8096-v3-pmi8994-pm8004-cdp.dtb \ - apq8096-v3-pmi8994-pm8004-pmk8001-cdp.dtb \ - apq8096-v3-pmi8996-cdp.dtb \ - apq8096-v3-pmi8996-mtp.dtb \ - apq8096-v3-liquid.dtb \ - apq8096-v3-dragonboard.dtb \ - apq8096-v3-mediabox.dtb \ - apq8096-v3-sbc.dtb \ - apq8096-v3-auto-dragonboard.dtb \ - apq8096-v3-auto-adp.dtb \ - apq8096-v3-auto-cdp.dtb \ - apq8096-v3-drone.dtb \ - apq8096-v3.0-pmi8994-cdp.dtb \ - apq8096-v3.0-pmi8994-mtp.dtb \ - apq8096-v3.0-pmi8994-pm8004-cdp.dtb \ - apq8096-v3.0-pmi8994-pm8004-pmk8001-cdp.dtb \ - apq8096-v3.0-pmi8994-pmk8001-cdp.dtb \ - apq8096-v3.0-pmi8996-cdp.dtb \ - apq8096-v3.0-pmi8996-mtp.dtb \ - apq8096-v3.0-liquid.dtb \ - apq8096-v3.0-dragonboard.dtb \ - apq8096-v3-pmi8994-mdm9x55-i2s-cdp.dtb \ - apq8096-v3-pmi8994-pm8004-mdm9x55-i2s-cdp.dtb \ - apq8096-v3-pmi8994-pm8004-pmk8001-mdm9x55-i2s-cdp.dtb \ - apq8096-v3-pmi8994-pmk8001-mdm9x55-i2s-cdp.dtb \ - apq8096-v3-pmi8996-mdm9x55-i2s-cdp.dtb \ - apq8096-v3-pmi8994-mdm9x55-i2s-mtp.dtb \ - apq8096-v3-pmi8994-mdm9x55-slimbus-mtp.dtb \ - apq8096-v3-pmi8996-mdm9x55-i2s-mtp.dtb \ - apq8096-v3-pmi8996-mdm9x55-slimbus-mtp.dtb \ - apq8096-v3-pmi8996-dragonboard.dtb - -dtb-$(CONFIG_MSM_GVM_QUIN) += vplatform-lfv-msm8996.dtb - -dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ - msmcobalt-rumi.dtb \ - msmcobalt-cdp.dtb \ - msmcobalt-mtp.dtb \ - msmcobalt-v2-sim.dtb \ - msmcobalt-v2-rumi.dtb \ - msmcobalt-v2-mtp.dtb \ - msmcobalt-v2-cdp.dtb - -dtb-$(CONFIG_ARCH_MDM9640) += mdm9640-sim.dtb \ - mdm9640-rumi.dtb \ - mdm9640-emmc-cdp.dtb \ - mdm9640-nand-cdp.dtb \ - mdm9640-mtp.dtb \ - mdm9640-v1-mtp.dtb \ - mdm9640-v1-pmk8001-mtp.dtb \ - mdm9640-v2-mtp.dtb \ - mdm9640-v2-pmk8001-mtp.dtb \ - - -dtb-$(CONFIG_ARCH_MDM9650) += mdm9650-ttp.dtb \ - mdm9650-pcie-ep-ttp.dtb \ - mdm9650-nand-dualwifi-mtp.dtb \ - mdm9650-v1.1-emmc-cdp.dtb \ - mdm9650-v1.1-nand-cdp.dtb \ - mdm9650-v1.1-emmc-mtp.dtb \ - mdm9650-v1.1-nand-mtp.dtb \ - mdm9650-v1.1-nand-ccard-v2.dtb \ - mdm9650-v1.1-emmc-pcie-ep-mtp.dtb \ - mdm9650-v1.1-nand-pcie-ep-mtp.dtb \ - mdm9650-v1.1-nand-cv2x.dtb \ - mdm9650-v1.1-nand-rome-sdio-mtp.dtb - -dtb-$(CONFIG_ARCH_SDX20) += sdx20-emmc-cdp.dtb \ - sdx20-emmc-mtp.dtb \ - sdx20-nand-cdp.dtb \ - sdx20-nand-mtp.dtb \ - sdx20-nand-dualwifi-mtp.dtb \ - sdx20-nand-dualwifi-cdp.dtb \ - sdx20-v2-emmc-cdp.dtb \ - sdx20-v2-emmc-mtp.dtb \ - sdx20-v2-nand-cdp.dtb \ - sdx20-v2-nand-mtp.dtb \ - sdx20-v2-nand-dualwifi-mtp.dtb \ - sdx20-v2-nand-dualwifi-cdp.dtb \ - sdx20-v2-nand-singlewifi-dualwificonf-mtp.dtb \ - sdx20-emmc-pcie-ep-mtp.dtb \ - sdx20-nand-pcie-ep-mtp.dtb \ - sdx20-v2-emmc-pcie-ep-mtp.dtb \ - sdx20-v2-nand-pcie-ep-mtp.dtb - -dtb-$(CONFIG_ARCH_MSM8937) += msm8937-rumi.dtb \ - msm8937-pmi8950-cdp.dtb \ - msm8937-pmi8937-cdp.dtb \ - msm8937-pmi8940-cdp.dtb \ - msm8937-pmi8950-ext-codec-cdp.dtb \ - msm8937-pmi8950-mtp.dtb \ - msm8937-pmi8937-mtp.dtb \ - msm8937-pmi8940-mtp.dtb \ - msm8937-pmi8950-rcm.dtb \ - msm8937-pmi8937-rcm.dtb \ - msm8937-pmi8940-rcm.dtb \ - msm8937-pmi8950-qrd-sku1.dtb \ - msm8937-pmi8937-qrd-sku2.dtb \ - msm8937-pmi8950-qrd-sku1-dvt1.dtb \ - msm8937-pmi8937-qrd-sku2-dvt1.dtb \ - apq8037-pmi8950-cdp.dtb \ - apq8037-pmi8937-cdp.dtb \ - apq8037-pmi8950-mtp.dtb \ - apq8037-pmi8937-mtp.dtb - -dtb-$(CONFIG_ARCH_MSM8917) += msm8917-rumi.dtb \ - apq8017-pmi8937-cdp.dtb \ - apq8017-pmi8937-mtp.dtb \ - apq8017-pmi8950-cdp.dtb \ - apq8017-pmi8950-mtp.dtb \ - msm8917-pmi8937-cdp.dtb \ - msm8917-pmi8937-mtp.dtb \ - msm8917-pmi8940-cdp.dtb \ - msm8917-pmi8940-mtp.dtb \ - msm8917-pmi8950-cdp.dtb \ - msm8917-pmi8950-cdp-mirror-lake-touch.dtb \ - msm8917-pmi8950-ext-codec-cdp.dtb \ - msm8917-pmi8950-mtp.dtb \ - msm8917-pmi8937-rcm.dtb \ - msm8917-pmi8940-rcm.dtb \ - msm8917-pmi8950-rcm.dtb \ - msm8917-qgp-tmo.dtb \ - msm8917-pmi8937-qrd-sku5.dtb \ - apq8017-pmi8937-cdp-wcd-rome.dtb \ - apq8017-pmi8950-cdp-wcd-rome.dtb \ - apq8017-no-pmi-wcd-rome-cdp.dtb - -dtb-$(CONFIG_ARCH_MSM8920) += msm8920-pmi8937-cdp.dtb \ - msm8920-pmi8937-mtp.dtb \ - msm8920-pmi8950-cdp.dtb \ - msm8920-pmi8950-mtp.dtb \ - msm8920-pmi8937-rcm.dtb \ - msm8920-pmi8950-rcm.dtb \ - msm8920-pmi8940-qrd-sku7.dtb \ - msm8920-pmi8950-ext-codec-cdp.dtb - -dtb-$(CONFIG_ARCH_MSM8940) += msm8940-pmi8937-cdp.dtb \ - msm8940-pmi8937-mtp.dtb \ - msm8940-pmi8950-cdp.dtb \ - msm8940-pmi8950-mtp.dtb \ - msm8940-pmi8937-rcm.dtb \ - msm8940-pmi8950-rcm.dtb \ - msm8940-pmi8950-qrd-sku6.dtb \ - msm8940-pmi8950-qrd-sku7.dtb \ - msm8940-pmi8950-ext-codec-cdp.dtb \ - msm8940-pmi8940-mtp.dtb \ - msm8940-pmi8940-cdp.dtb \ - msm8940-pmi8940-rcm.dtb \ - msm8940-pmi8940-qrd-sku7.dtb - -dtb-$(CONFIG_ARCH_MSM8953) += msm8953-sim.dtb \ - msm8953-rumi.dtb \ - msm8953-cdp.dtb \ - msm8953-mtp.dtb \ - msm8953-ext-codec-mtp.dtb \ - msm8953-qrd-sku3.dtb \ - msm8953-rcm.dtb \ - apq8053-rcm.dtb \ - msm8953-ext-codec-rcm.dtb \ - apq8053-cdp.dtb \ - apq8053-ipc.dtb \ - msm8953-ipc.dtb \ - apq8053-mtp.dtb \ - apq8053-ext-audio-mtp.dtb \ - apq8053-ext-codec-rcm.dtb \ - apq8053-lite-dragon-v1.0.dtb \ - apq8053-lite-dragon-v2.0.dtb \ - apq8053-lite-ext-codec-dragon-v2.0.dtb \ - msm8953-cdp-1200p.dtb \ - msm8953-iot-mtp.dtb \ - apq8053-iot-mtp.dtb \ - msm8953-pmi8940-cdp.dtb \ - msm8953-pmi8940-mtp.dtb \ - msm8953-pmi8937-cdp.dtb \ - msm8953-pmi8937-mtp.dtb \ - msm8953-pmi8940-ext-codec-mtp.dtb \ - msm8953-pmi8937-ext-codec-mtp.dtb - -dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \ - sdm450-cdp.dtb \ - sdm450-mtp.dtb \ - sdm450-qrd.dtb \ - sdm450-pmi8940-mtp.dtb \ - sdm450-pmi8937-mtp.dtb \ - sdm450-iot-mtp.dtb \ - sda450-cdp.dtb \ - sda450-mtp.dtb - -dtb-$(CONFIG_ARCH_MDM9607) += mdm9607-rumi.dtb \ - mdm9607-cdp.dtb \ - mdm9607-mtp.dtb \ - mdm9607-rcm.dtb \ - mdm9607-mtp-sdcard.dtb \ - mdm9607-ttp.dtb \ - mdm9206-mtp.dtb \ - mdm9206-cdp.dtb \ - mdm9206-mtp-sdcard.dtb \ - mdm9206-rcm.dtb - -dtb-$(CONFIG_ARCH_MSM8916) += msm8952-qrd-skum.dtb \ - msm8952-cdp.dtb \ - msm8952-ext-codec-cdp.dtb \ - msm8952-mtp.dtb dtb-$(CONFIG_ARCH_MSM8909) += msm8909-1gb-mtp.dtb diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi index bcbd4619e7e..3d5a4e0905f 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pm8909-mtp.dtsi @@ -12,7 +12,7 @@ */ &pm8909_chg { - status = "ok"; + status = "disabled"; qcom,use-external-charger; }; @@ -35,7 +35,7 @@ &spmi_bus { qcom,pm8909@0 { qcom,leds@a300 { - status = "okay"; + status = "disabled"; qcom,led_mpp_4 { label = "mpp"; linux,name = "button-backlight"; diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index 498642ce762..9e92e2c749b 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -562,10 +562,10 @@ compatible = "qcom,msm-thermal"; qcom,sensor-id = <3>; qcom,poll-ms = <250>; - qcom,limit-temp = <60>; + qcom,limit-temp = <70>; qcom,temp-hysteresis = <10>; qcom,freq-step = <2>; - qcom,core-limit-temp = <80>; + qcom,core-limit-temp = <90>; qcom,core-temp-hysteresis = <10>; qcom,hotplug-temp = <97>; qcom,hotplug-temp-hysteresis = <12>; diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index af499987261..76ec04e212d 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -41,7 +41,6 @@ CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_MSM=y CONFIG_ARCH_MSM8909=y -CONFIG_LEDS_MSM_GPIO_FLASH=y CONFIG_ARM_KERNMEM_PERMS=y CONFIG_SMP=y CONFIG_SCHED_MC=y @@ -234,8 +233,8 @@ CONFIG_MTD=y CONFIG_MTD_TESTS=m CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_MSM_QPIC_NAND=y -CONFIG_MTD_NAND=y +#CONFIG_MTD_MSM_QPIC_NAND=y +#CONFIG_MTD_NAND=y CONFIG_MTD_UBI=y CONFIG_ZRAM=y CONFIG_ZRAM_LZ4_COMPRESS=y @@ -313,12 +312,12 @@ CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m # CONFIG_SENSORS_LTR553=y # CONFIG_SENSORS_AKM09911=y -CONFIG_SENSORS_BMA2X2=y +# CONFIG_SENSORS_BMA2X2=y # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set # CONFIG_DEVKMEM is not set -CONFIG_SERIAL_MSM_HS=y +#CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_HSL=y # CONFIG_SERIAL_MSM_HSL_CONSOLE=y CONFIG_SERIAL_MSM_SMD=y @@ -326,7 +325,7 @@ CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y -CONFIG_MSM_ADSPRPC=y +#CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y CONFIG_SLIMBUS=y @@ -343,7 +342,7 @@ CONFIG_SMB135X_CHARGER=y # CONFIG_SMB358_CHARGER=y CONFIG_BATTERY_BCL=y CONFIG_QPNP_VM_BMS=y -CONFIG_QPNP_LINEAR_CHARGER=y +#CONFIG_QPNP_LINEAR_CHARGER=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_MSM=y CONFIG_MSM_DLOAD_MODE=y @@ -429,14 +428,12 @@ CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_MSM_GPIO_FLASH=y -CONFIG_LEDS_AW2013=y -CONFIG_LEDS_TRIGGERS=y +#CONFIG_LEDS_GPIO=y +#CONFIG_LEDS_MSM_GPIO_FLASH=y +#CONFIG_LEDS_AW2013=y +#CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_CLASS=y -CONFIG_LEDS_QPNP=y -CONFIG_LEDS_AW2013=y +#CONFIG_LEDS_QPNP=y CONFIG_NEW_LEDS=y CONFIG_SWITCH=y CONFIG_RTC_CLASS=y @@ -472,14 +469,14 @@ CONFIG_MSM_MEMORY_DUMP_V2=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_COMMON_LOG=y CONFIG_MSM_WATCHDOG_V2=y -CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +#CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_SCM=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_SMEM=y CONFIG_MSM_SMD=y -CONFIG_MSM_SMD_DEBUG=y +#CONFIG_MSM_SMD_DEBUG=y CONFIG_MSM_SMEM_LOGGING=y CONFIG_MSM_SMP2P=y CONFIG_MSM_SMP2P_TEST=y @@ -504,7 +501,7 @@ CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_SENSORS=y CONFIG_SENSORS_SSC=y -CONFIG_MSM_TZ_LOG=y +#CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y @@ -568,7 +565,7 @@ CONFIG_TOUCHSCREEN_GT9XX=y #CONFIG_GT9XX_TOUCHPANEL_DRIVER=y # CONFIG_GT9XX_TOUCHPANEL_UPDATE=y # CONFIG_GT9XX_TOUCHPANEL_DEBUG=y -CONFIG_MG_DRIVER_CONTROL=y +#CONFIG_MG_DRIVER_CONTROL=y CONFIG_NRF_DRIVER=y CONFIG_EXTCON=y CONFIG_EXTCON_PTN5150=y -- 2.25.1 From bfad8928310e02c9b7c0d1613dccbada2998806f Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 10 Jul 2020 08:44:13 -0400 Subject: [PATCH 42/76] MeiG: remove some driver logs Change-Id: I89321753f3ad705cbe80ad38c7800ad20eeafc09 --- drivers/input/misc/akm09911m.c | 6 +-- drivers/input/misc/bmi160_driver.c | 30 ++++++------ drivers/input/misc/bmi160_i2c.c | 2 +- .../input/touchscreen/gt9xx_2.8/goodix_tool.c | 8 ++-- drivers/input/touchscreen/gt9xx_2.8/gt9xx.c | 48 +++++++++---------- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/input/misc/akm09911m.c b/drivers/input/misc/akm09911m.c index f78a8bd800f..81ea103527e 100755 --- a/drivers/input/misc/akm09911m.c +++ b/drivers/input/misc/akm09911m.c @@ -2289,7 +2289,7 @@ static int akm_compass_probe(struct i2c_client *client, const struct i2c_device_ struct akm09911_platform_data *pdata; int err = 0; int i; - printk(KERN_ERR"=====================ak,akm09911=================\n"); + //printk(KERN_ERR"=====================ak,akm09911=================\n"); dev_dbg(&client->dev, "start probing."); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { @@ -2375,7 +2375,7 @@ static int akm_compass_probe(struct i2c_client *client, const struct i2c_device_ /* Pull up the reset pin */ AKECS_Reset(s_akm, 1); - dev_err(&client->dev, "AKECS_Reset@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); + //dev_err(&client->dev, "AKECS_Reset@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); /* check connection */ err = akm_compass_power_init(s_akm, 1); @@ -2547,7 +2547,7 @@ static struct i2c_driver akm_compass_driver = { static int __init akm_compass_init(void) { - pr_info("AKM compass driver: initialize1111111."); + //pr_info("AKM compass driver: initialize1111111."); return i2c_add_driver(&akm_compass_driver); } diff --git a/drivers/input/misc/bmi160_driver.c b/drivers/input/misc/bmi160_driver.c index fc3fe650459..4ac87c332d8 100755 --- a/drivers/input/misc/bmi160_driver.c +++ b/drivers/input/misc/bmi160_driver.c @@ -695,9 +695,9 @@ static int bmi_input_init(struct bmi_client_data *client_data) return err; } client_data->input_accel = dev; - dev_notice(client_data->dev, - "bmi160 accel input register successfully, %s!\n", - client_data->input_accel->name); +// dev_notice(client_data->dev, +// "bmi160 accel input register successfully, %s!\n", +// client_data->input_accel->name); dev = devm_input_allocate_device(&client_data->i2c->dev); if (NULL == dev) @@ -720,9 +720,9 @@ static int bmi_input_init(struct bmi_client_data *client_data) return err; } client_data->input_gyro = dev; - dev_notice(client_data->dev, - "bmi160 gyro input register successfully, %s!\n", - client_data->input_gyro->name); +// dev_notice(client_data->dev, +// "bmi160 gyro input register successfully, %s!\n", +// client_data->input_gyro->name); return err; } @@ -761,9 +761,9 @@ static int bmi_check_chip_id(struct bmi_client_data *client_data) for (i = 0; i < bmi_sensor_cnt; i++) { if (sensor_type_map[i].chip_id == chip_id) { client_data->chip_id = chip_id; - dev_notice(client_data->dev, - "Bosch Sensortec Device detected, " - "HW IC name: %s\n", sensor_type_map[i].sensor_name); + //dev_notice(client_data->dev, + //"Bosch Sensortec Device detected, " + //"HW IC name: %s\n", sensor_type_map[i].sensor_name); break; } } @@ -4968,7 +4968,7 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) client_data->is_timer_running = 0; client_data->time_odr = 500000; /*200Hz*/ - bmi_dump_reg(client_data); + //bmi_dump_reg(client_data); /*power on detected*/ /*or softrest(cmd 0xB6) */ @@ -5017,8 +5017,8 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) #ifdef BMI160_ENABLE_INT1 client_data->gpio_pin = of_get_named_gpio_flags(dev->of_node, "bosch,gpio-int1", 0, NULL); - dev_info(client_data->dev, "BMI160 qpio number:%d\n", - client_data->gpio_pin); + //dev_info(client_data->dev, "BMI160 qpio number:%d\n", + // client_data->gpio_pin); err += gpio_request_one(client_data->gpio_pin, GPIOF_IN, "bmi160_int"); err += gpio_direction_input(client_data->gpio_pin); @@ -5104,9 +5104,9 @@ int bmi_probe(struct bmi_client_data *client_data, struct device *dev) bmi160_power_ctl(client_data, false); - dev_notice(dev, "sensor_time:%d, %d", - sensortime_duration_tbl[0].ts_delat, - sensortime_duration_tbl[0].ts_duration_lsb); +// dev_notice(dev, "sensor_time:%d, %d", +// sensortime_duration_tbl[0].ts_delat, +// sensortime_duration_tbl[0].ts_duration_lsb); dev_notice(dev, "sensor %s probed successfully", SENSOR_NAME); return 0; diff --git a/drivers/input/misc/bmi160_i2c.c b/drivers/input/misc/bmi160_i2c.c index 64648529ce5..b72291fc963 100755 --- a/drivers/input/misc/bmi160_i2c.c +++ b/drivers/input/misc/bmi160_i2c.c @@ -252,7 +252,7 @@ static int bmi_i2c_probe(struct i2c_client *client, int err = 0; struct bmi_client_data *client_data = NULL; - dev_info(&client->dev, "BMI160 i2c function probe entrance"); + //dev_info(&client->dev, "BMI160 i2c function probe entrance"); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "i2c_check_functionality error!"); diff --git a/drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c b/drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c index 04d1f1b8f00..05a7636c650 100755 --- a/drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c +++ b/drivers/input/touchscreen/gt9xx_2.8/goodix_tool.c @@ -150,7 +150,7 @@ static void register_i2c_func(void) } else { tool_i2c_read = tool_i2c_read_no_extra; tool_i2c_write = tool_i2c_write_no_extra; - dev_info(>_client->dev, "I2C function: without pre and end cmd!"); + //dev_info(>_client->dev, "I2C function: without pre and end cmd!"); } } @@ -178,8 +178,8 @@ s32 init_wr_node(struct i2c_client *client) } if (i) { DATA_LENGTH = i * DATA_LENGTH_UINT - GTP_ADDR_LENGTH; - dev_info(>_client->dev, - "Alloc memory size:%d.", DATA_LENGTH); + //dev_info(>_client->dev, + // "Alloc memory size:%d.", DATA_LENGTH); } else { dev_err(>_client->dev, "Apply for memory failed."); return FAIL; @@ -197,7 +197,7 @@ s32 init_wr_node(struct i2c_client *client) return FAIL; } - dev_info(>_client->dev, "Create proc entry success!"); + //dev_info(>_client->dev, "Create proc entry success!"); return SUCCESS; } diff --git a/drivers/input/touchscreen/gt9xx_2.8/gt9xx.c b/drivers/input/touchscreen/gt9xx_2.8/gt9xx.c index e9aa69f46d0..69081b38671 100755 --- a/drivers/input/touchscreen/gt9xx_2.8/gt9xx.c +++ b/drivers/input/touchscreen/gt9xx_2.8/gt9xx.c @@ -703,7 +703,7 @@ void gtp_reset_guitar(struct i2c_client *client, s32 ms) { struct goodix_ts_data *ts = i2c_get_clientdata(client); - dev_info(&client->dev, "Guitar reset"); + //dev_info(&client->dev, "Guitar reset"); set_bit(PANEL_RESETTING, &ts->flags); if (!gpio_is_valid(ts->pdata->rst_gpio)) { dev_warn(&client->dev, "reset failed no valid reset gpio"); @@ -931,7 +931,7 @@ static s32 gtp_init_panel(struct goodix_ts_data *ts) struct goodix_config_data *cfg = &ts->pdata->config; if (!ts->pdata->driver_send_cfg) { - dev_info(&ts->client->dev, "Driver set not send config\n"); + //dev_info(&ts->client->dev, "Driver set not send config\n"); cfg->length = GTP_CONFIG_MAX_LENGTH; ret = gtp_i2c_read(ts->client, cfg->data, cfg->length + @@ -1440,7 +1440,7 @@ static int gtp_pinctrl_init(struct goodix_ts_data *ts) "Failed get pinctrl state:int-input\n"); goto exit_pinctrl_init; } - dev_info(&ts->client->dev, "Success init pinctrl\n"); + //dev_info(&ts->client->dev, "Success init pinctrl\n"); return 0; exit_pinctrl_init: devm_pinctrl_put(pinctrl->pinctrl); @@ -1471,7 +1471,7 @@ static int gtp_request_io_port(struct goodix_ts_data *ts) } gpio_direction_input(ts->pdata->irq_gpio); - dev_info(&ts->client->dev, "Success request irq-gpio\n"); + //dev_info(&ts->client->dev, "Success request irq-gpio\n"); } if (gpio_is_valid(ts->pdata->rst_gpio)) { @@ -1488,7 +1488,7 @@ static int gtp_request_io_port(struct goodix_ts_data *ts) } gpio_direction_input(ts->pdata->rst_gpio); - dev_info(&ts->client->dev, "Success request rst-gpio\n"); + //dev_info(&ts->client->dev, "Success request rst-gpio\n"); } return 0; @@ -1513,8 +1513,8 @@ static int gtp_request_irq(struct goodix_ts_data *ts) if (gpio_is_valid(ts->pdata->irq_gpio)) ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio); - dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n", - ts->client->irq, ts->pdata->irq_flags); + //dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n", + // ts->client->irq, ts->pdata->irq_flags); ret = request_threaded_irq(ts->client->irq, NULL, gtp_irq_handler, ts->pdata->irq_flags | IRQF_ONESHOT, @@ -1553,7 +1553,7 @@ static s8 gtp_request_input_dev(struct goodix_ts_data *ts) | BIT_MASK(EV_ABS); if (!ts->pdata->type_a_report) { input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT); - dev_info(&ts->client->dev, "Use slot report protocol\n"); + //dev_info(&ts->client->dev, "Use slot report protocol\n"); } else { __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); __set_bit(BTN_TOUCH, ts->input_dev->keybit); @@ -1654,9 +1654,9 @@ static void gtp_parse_dt_coords(struct device *dev, dev_info(dev, "Unset touchscreen-max-p, use default\n"); pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; } - dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n", - pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y, - pdata->max_touch_width, pdata->max_touch_pressure); +// dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n", +// pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y, +// pdata->max_touch_width, pdata->max_touch_pressure); } static int gtp_parse_dt(struct device *dev, @@ -1678,8 +1678,8 @@ static int gtp_parse_dt(struct device *dev, pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER; } of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync); - if (pdata->int_sync) - dev_info(dev, "int-sync enabled\n"); + //if (pdata->int_sync) + // dev_info(dev, "int-sync enabled\n"); of_property_read_u32(np, "goodix,driver-send-cfg", &pdata->driver_send_cfg); @@ -1704,8 +1704,8 @@ static int gtp_parse_dt(struct device *dev, dev_info(dev, "auto-update-cfg enabled\n"); of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect); - if (pdata->esd_protect) - dev_info(dev, "esd-protect enabled\n"); + //if (pdata->esd_protect) + // dev_info(dev, "esd-protect enabled\n"); of_property_read_u32(np, "goodix,type-a-report", &pdata->type_a_report); @@ -1719,8 +1719,8 @@ static int gtp_parse_dt(struct device *dev, of_property_read_u32(np, "goodix,power-off-sleep", &pdata->power_off_sleep); - if (pdata->power_off_sleep) - dev_info(dev, "power-off-sleep enabled\n"); + //if (pdata->power_off_sleep) + // dev_info(dev, "power-off-sleep enabled\n"); of_property_read_u32(np, "goodix,pen-suppress-finger", &pdata->pen_suppress_finger); @@ -1745,9 +1745,9 @@ static int gtp_parse_dt(struct device *dev, pdata->key_nums = key_nums; memcpy(pdata->key_map, key_map, key_nums * sizeof(pdata->key_map[0])); - dev_info(dev, "key-map is [%x %x %x %x]\n", - pdata->key_map[0], pdata->key_map[1], - pdata->key_map[2], pdata->key_map[3]); + //dev_info(dev, "key-map is [%x %x %x %x]\n", + // pdata->key_map[0], pdata->key_map[1], + // pdata->key_map[2], pdata->key_map[3]); } pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0); @@ -1921,8 +1921,8 @@ static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id) struct goodix_ts_platform_data *pdata; /* do NOT remove these logs */ - dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION); - dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); + //dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION); + //dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); i2c_connect_client = client; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { @@ -2012,7 +2012,7 @@ static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id) goto exit_free_io_port; } - dev_info(&client->dev, "I2C Addr is %x\n", client->addr); + //dev_info(&client->dev, "I2C Addr is %x\n", client->addr); ret = gtp_get_fw_info(client, &ts->fw_info); if (ret < 0) { @@ -2492,7 +2492,7 @@ void gtp_esd_on(struct goodix_ts_data *ts) if (ts_esd->esd_on == false) { ts_esd->esd_on = true; schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); - dev_info(&ts->client->dev, "ESD on"); + //dev_info(&ts->client->dev, "ESD on"); } mutex_unlock(&ts_esd->mutex); } -- 2.25.1 From 333928bf8c44d0245646c9adedfc81e056c1b210 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 10 Jul 2020 08:47:19 -0400 Subject: [PATCH 43/76] MeiG: liangdi: set kernel loglevel Change-Id: I6fd57ba65fa5da839c2d06bb1b822e7524cfe3d5 --- kernel/printk/printk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 0f4c0848490..9cfc9150c98 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -60,10 +60,10 @@ extern void printascii(char *); #endif int console_printk[4] = { - CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */ + CONSOLE_LOGLEVEL_QUIET, /* console_loglevel *///CONSOLE_LOGLEVEL_DEFAULT MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */ CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */ - CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */ + CONSOLE_LOGLEVEL_QUIET, /* default_console_loglevel *///CONSOLE_LOGLEVEL_DEFAULT }; /* Deferred messaged from sched code are marked by this special level */ -- 2.25.1 From 7bb4188f52067ab2ad31d0179d9fc9e2d9ed5fbf Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 10 Jul 2020 09:17:53 -0400 Subject: [PATCH 44/76] MeiG: liangdi: optimize ptn5150 Change-Id: I39ba6ca67b25104acc42d46e9b87e9b679e57e1b --- drivers/extcon/extcon-ptn5150.c | 190 +++++++++++++++++++++++++++++--- drivers/power/smb135x-charger.c | 4 + 2 files changed, 180 insertions(+), 14 deletions(-) diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c index 82ec180c72e..490872bbf8b 100755 --- a/drivers/extcon/extcon-ptn5150.c +++ b/drivers/extcon/extcon-ptn5150.c @@ -15,6 +15,7 @@ #include #include #include +#include /* PTN5150 registers */ enum ptn5150_reg { @@ -34,6 +35,13 @@ enum mode_select { UFP_MODE = 0x00, DFP_MODE, DRP_MODE, + NONE_MODE, +}; + +enum RP_UA { + RP_80UA = 0x00, + RP_180UA, + RP_330UA, }; #define PTN5150_DFP_ATTACHED 0x1 #define PTN5150_UFP_ATTACHED 0x2 @@ -74,7 +82,19 @@ struct ptn5150_info { int irq; struct work_struct irq_work; struct mutex mutex; + unsigned int usb_insert; + unsigned int current_mode; + char mode_name[10]; + struct power_supply *batt_psy; + struct delayed_work cable_detached_detect_work; }; + +/* current mode */ +static char *mode_text[] = { + "ufp", "dfp", "drp", "none" +}; + + #if 0 /* List of detectable cables */ static const unsigned int ptn5150_extcon_cable[] = { @@ -116,6 +136,74 @@ static const struct regmap_config ptn5150_regmap_config = { .max_register = PTN5150_REG_END, }; +static int ptnusb_i2c_enable(struct ptn5150_info *info, u8 port_mode) +{ + int ret = 0; + unsigned int reg_data = 0; + + if(info->current_mode != port_mode) + { + ret = regmap_read(info->regmap, PTN5150_REG_CONTROL, ®_data); + if (ret) { + dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); + return -EINVAL; + } + dev_info(info->dev, "1ptn5150 reg control 0x%x\n",reg_data); + reg_data = (reg_data & (~(0x3 << 1))) | (port_mode << 1); + + ret = regmap_write(info->regmap, PTN5150_REG_CONTROL, reg_data); + if (ret) { + dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); + return -EINVAL; + } + + info->current_mode = port_mode; + strlcpy(info->mode_name, mode_text[port_mode], strlen(mode_text[port_mode])+1); + dev_err(info->dev, "mode set to - %s\n", info->mode_name); + } + else + { + dev_err(info->dev, "mode already set to - %s\n", info->mode_name); + } + + return 0; +} + +#if 0 +static bool is_usb_otg_present(struct ptn5150_info *info) +{ + union power_supply_propval ret = {0,}; + + if (info->batt_psy == NULL) + info->batt_psy = power_supply_get_by_name("battery"); + if (info->batt_psy) { + /* if battery has been registered, use the type property */ + info->batt_psy->get_property(info->batt_psy, POWER_SUPPLY_PROP_USB_OTG, &ret); + + return ret.intval; + } + + /* Default to false if the battery power supply is not registered. */ + pr_err("battery power supply is not registered\n"); + return false; +} +#endif + +static void cable_detached_detect_work(struct work_struct *work) +{ + struct ptn5150_info *info = container_of(work, + struct ptn5150_info, cable_detached_detect_work.work); + + pr_err("usb insert %s\n",mode_text[info->usb_insert]); + //if UFP attached, and is not the USB otg device. set ufp + if(info->usb_insert == NONE_MODE) + { + ptnusb_i2c_enable(info, DRP_MODE); + return; + } + return ; +} + static void ptn5150_irq_work(struct work_struct *work) { struct ptn5150_info *info = container_of(work, @@ -168,6 +256,7 @@ static void ptn5150_irq_work(struct work_struct *work) pr_err("DFP attached\n"); extcon_set_cable_state(info->edev, "USB-Host", false); extcon_set_cable_state(info->edev, "USB", true); + info->usb_insert = DFP_MODE; break; case PTN5150_UFP_ATTACHED: /* @@ -196,6 +285,7 @@ static void ptn5150_irq_work(struct work_struct *work) extcon_set_cable_state(info->edev, "USB", false); extcon_set_cable_state(info->edev, "USB-Host", true); + info->usb_insert = UFP_MODE; break; default: dev_err(info->dev, @@ -213,7 +303,11 @@ static void ptn5150_irq_work(struct work_struct *work) */ pr_err("Cable Detached\n"); extcon_set_cable_state(info->edev, "USB-Host", false); - extcon_set_cable_state(info->edev, "USB", true); + extcon_set_cable_state(info->edev, "USB", true); + + info->usb_insert = NONE_MODE; + + schedule_delayed_work(&info->cable_detached_detect_work, msecs_to_jiffies(1000)); } } @@ -240,6 +334,70 @@ static irqreturn_t ptn5150_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static ssize_t ptn_usbmode_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ptn5150_info *info = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%s\n", info->mode_name); +} + +static ssize_t ptn_usbmode_name_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct ptn5150_info *info= dev_get_drvdata(dev); + + if (size > 10) + return -EINVAL; + + strlcpy(info->mode_name, buf, size); +// if (info->mode_name[size-1] == '\n') +// info->mode_name[size-1] = 0; + + pr_err("set usb mode %s\n",info->mode_name); + + if(!strcmp(info->mode_name, "ufp")) + { + ptnusb_i2c_enable(info, UFP_MODE); + } + else if(!strcmp(info->mode_name, "dfp")) + { + ptnusb_i2c_enable(info, DFP_MODE); + } + else if(!strcmp(info->mode_name, "drp")) + { + ptnusb_i2c_enable(info, DRP_MODE); + } + else if(!strcmp(info->mode_name, "none")) + { + ptnusb_i2c_enable(info, DRP_MODE); + } + + return size; +} + +static DEVICE_ATTR(usbmode, 0664, ptn_usbmode_name_show, ptn_usbmode_name_store); + +static ssize_t ptn_usbinsert_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ptn5150_info *info = dev_get_drvdata(dev); + + return snprintf(buf, strlen(mode_text[info->usb_insert])+1, "%s\n", mode_text[info->usb_insert]); +} + +static ssize_t ptn_usbinsert_name_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + //struct ptn5150_info *info= dev_get_drvdata(dev); + + return size; +} + +static DEVICE_ATTR(usbinsert, 0664, ptn_usbinsert_name_show, ptn_usbinsert_name_store); + static int ptn5150_init_dev_type(struct ptn5150_info *info) { unsigned int reg_data, vendor_id, version_id; @@ -260,19 +418,8 @@ static int ptn5150_init_dev_type(struct ptn5150_info *info) version_id, vendor_id); //add by liangdi for set DRP mode - ret = regmap_read(info->regmap, PTN5150_REG_CONTROL, ®_data); - if (ret) { - dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); - return -EINVAL; - } - dev_info(info->dev, "1ptn5150 reg control 0x%x\n",reg_data); - reg_data = (reg_data & (~(0x3 << 1))) | (DRP_MODE << 1); - - ret = regmap_write(info->regmap, PTN5150_REG_CONTROL, reg_data); - if (ret) { - dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); - return -EINVAL; - } + info->current_mode = NONE_MODE; + ptnusb_i2c_enable(info, DRP_MODE); //add end /* Clear any existing interrupts */ @@ -342,6 +489,7 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c, return (info->vbus_gpiod); } */ + dev_set_drvdata(&i2c->dev, info); mutex_init(&info->mutex); INIT_WORK(&info->irq_work, ptn5150_irq_work); @@ -391,6 +539,20 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c, if (ret) return -EINVAL; + ret = device_create_file(info->dev, &dev_attr_usbmode); + if (ret) { + dev_err(info->dev, "sys file creation failed\n"); + return ret; + } + + ret = device_create_file(info->dev, &dev_attr_usbinsert); + if (ret) { + dev_err(info->dev, "sys file creation failed\n"); + return ret; + } + + INIT_DELAYED_WORK(&info->cable_detached_detect_work, cable_detached_detect_work); + return 0; } diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index baa7e4bdc0e..2cb4c04d0a5 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -740,6 +740,7 @@ static enum power_supply_property smb135x_battery_properties[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_USB_OTG, //POWER_SUPPLY_PROP_BMS_SUSPEND,//add by liangdi for device suspend 20200417 }; @@ -1789,6 +1790,9 @@ static int smb135x_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_MAX: val->intval = chip->fastchg_ma * 1000; break; + case POWER_SUPPLY_PROP_USB_OTG: + val->intval = chip->usb_slave_present; + break; //add end default: return -EINVAL; -- 2.25.1 From 753f8111d0944934ce2ab7137ef1644fece35875 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 17 Jul 2020 16:36:20 -0400 Subject: [PATCH 45/76] kernel/msm-3.18: expose chip_status pin as device driver for backup FWOTA mechanism Change-Id: Ibc920acc763068c2da720a75f6c38c11fba6574b --- drivers/mg_driver/nrf/nrf.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/mg_driver/nrf/nrf.c b/drivers/mg_driver/nrf/nrf.c index 5b3b210085b..669b7cb6ab8 100755 --- a/drivers/mg_driver/nrf/nrf.c +++ b/drivers/mg_driver/nrf/nrf.c @@ -208,6 +208,20 @@ static ssize_t store_driver_attr_ant_reset(struct device_driver *dev, const char return count; } +static ssize_t show_driver_attr_chip_status(struct device_driver *dev, char *buf) +{ + + return snprintf(buf, 20, "%d\n", gl_nrf_driver->chip_status); +} + +static ssize_t store_driver_attr_chip_status(struct device_driver *dev, const char *buf, size_t count) +{ + pr_err("nrf chip_statust\n"); + gpio_direction_output(gl_nrf_driver->chip_status, 0); + return count; +} + + static ssize_t show_driver_attr_wake_timeout(struct device_driver *dev, char *buf) { @@ -231,6 +245,7 @@ static ssize_t store_driver_attr_wake_timeout(struct device_driver *dev, const c static DRIVER_ATTR(ant_reset, S_IWUSR | S_IRUGO, show_driver_attr_ant_reset, store_driver_attr_ant_reset); static DRIVER_ATTR(wake_timeout, S_IWUSR | S_IRUGO, show_driver_attr_wake_timeout, store_driver_attr_wake_timeout); +static DRIVER_ATTR(chip_status, S_IWUSR | S_IRUGO, show_driver_attr_chip_status, store_driver_attr_chip_status); int nrf_sync(u8 *txb, u8 *rxb, int len) { @@ -479,6 +494,13 @@ static int nrf_drv_probe(struct spi_device *spi) goto exit; } + if(driver_create_file(&nrf_drv_driver.driver, &driver_attr_chip_status)) + { + pr_err("driver_create_file chip_status ERROR \n"); + goto exit; + } + + if(driver_create_file(&nrf_drv_driver.driver, &driver_attr_wake_timeout)) { -- 2.25.1 From beffd095b0c3f83f0dda447c2979f068eeea4623 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 24 Jul 2020 00:41:38 -0400 Subject: [PATCH 46/76] kernel/msm-3.18: Re-enable Kernel console logging over UART0 Change-Id: I5d10b58bb56fcc1142d4e476000a0c920e580a80 --- arch/arm/configs/msm8909-perf_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 76ec04e212d..bab0c9f536a 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -319,7 +319,7 @@ CONFIG_INPUT_GPIO=m # CONFIG_DEVKMEM is not set #CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_HSL=y -# CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y -- 2.25.1 From 6a18bede3d46d1e4c344f9b47e5e514fba53f4b7 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Mon, 3 Aug 2020 16:24:41 -0400 Subject: [PATCH 47/76] MeiG: liangdi: typeC set the default as UFP Change-Id: I143c278b1acbd805c732b69fa8c4b0dacea03544 --- drivers/extcon/extcon-ptn5150.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c index 490872bbf8b..bfcf432ebd7 100755 --- a/drivers/extcon/extcon-ptn5150.c +++ b/drivers/extcon/extcon-ptn5150.c @@ -198,7 +198,7 @@ static void cable_detached_detect_work(struct work_struct *work) //if UFP attached, and is not the USB otg device. set ufp if(info->usb_insert == NONE_MODE) { - ptnusb_i2c_enable(info, DRP_MODE); + ptnusb_i2c_enable(info, UFP_MODE);//DRP_MODE); return; } return ; @@ -419,7 +419,7 @@ static int ptn5150_init_dev_type(struct ptn5150_info *info) //add by liangdi for set DRP mode info->current_mode = NONE_MODE; - ptnusb_i2c_enable(info, DRP_MODE); + ptnusb_i2c_enable(info, UFP_MODE);//DRP_MODE); //add end /* Clear any existing interrupts */ -- 2.25.1 From 87ab66197c540225d1cc533d4a70fd9f00db2056 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 6 Aug 2020 13:59:16 -0400 Subject: [PATCH 48/76] kernel/msm-3.18: liangdi: fix problem 180% drain rate Change-Id: If5f39330c57b9e17d8905c48069916f0292c5b1d --- arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi | 2 +- drivers/power/qpnp-vm-bms.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi b/arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi index 6f6e58ec0e0..c4f9638dbde 100755 --- a/arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi +++ b/arch/arm/boot/dts/qcom/batterydata-mtp-4v35-2500mah.dtsi @@ -43,7 +43,7 @@ qcom,mtp-4v35-2500mAh { <10 9 8 7 6>, <5 4 3 2 1>, <0>; - qcom,lut-data = <4324 4325 4322 4319 4314>, + qcom,lut-data = <4304 4304 4304 4304 4304>, <4200 4242 4254 4254 4250>, <4118 4179 4198 4198 4196>, <4026 4120 4144 4144 4142>, diff --git a/drivers/power/qpnp-vm-bms.c b/drivers/power/qpnp-vm-bms.c index c74e4a5b5ef..1afc1d86a39 100644 --- a/drivers/power/qpnp-vm-bms.c +++ b/drivers/power/qpnp-vm-bms.c @@ -1013,9 +1013,10 @@ static int lookup_soc_ocv(struct qpnp_bms_chip *chip, int ocv_uv, int batt_temp) if (batt_temp > chip->dt.cfg_low_temp_threshold) soc_uuc = adjust_uuc(chip, soc_uuc); - soc_acc = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_uuc), - (100 - soc_uuc)); +// soc_acc = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_uuc), +// (100 - soc_uuc)); + soc_acc = (100 * (soc_ocv - soc_uuc) / (100 - soc_uuc));//modify by liangdi for fix the problem 180% drain rate pr_debug("fcc=%d acc=%d soc_final=%d soc_uuc=%d soc_acc=%d current_now=%d iavg_ma=%d\n", fcc, acc, soc_final, soc_uuc, soc_acc, chip->current_now / 1000, iavg_ma); -- 2.25.1 From 3e26c8a3ec80f1d2e200f24d256d26b1247ffe78 Mon Sep 17 00:00:00 2001 From: Brent Dimmig Date: Wed, 2 Sep 2020 11:47:49 -0400 Subject: [PATCH 49/76] kernel/msm-1.8/drivers/input/misc: log temperature value to dmesg Change-Id: Ie6ecf9de99b9a389090485022180e10ce8797ff3 --- drivers/input/misc/bmp280_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/bmp280_core.c b/drivers/input/misc/bmp280_core.c index bf81e981dbf..fc3c1b3db52 100755 --- a/drivers/input/misc/bmp280_core.c +++ b/drivers/input/misc/bmp280_core.c @@ -1538,7 +1538,7 @@ static void bmp_temp_work_func(struct work_struct *work) status = bmp_get_temperature(client_data, &temperature); mutex_unlock(&client_data->lock); if (status == 0) { - //pr_err("bmp280 temperature value :%d Pa\n", temperature); + pr_info("bmp280 temperature value :%d /100 C\n", temperature); input_event(client_data->input_temp, EV_ABS, MSC_RAW, temperature); input_sync(client_data->input_temp); } -- 2.25.1 From 87f2d4df6d9bf8f25a0d1903c04ff6ecede55fd5 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 4 Sep 2020 12:10:43 -0600 Subject: [PATCH 50/76] kernel/msm-3.18 MEIG: liangdi: optimize vendor Change-Id: Icc66acbbcc3bd972d895ce17c8f2f9c69d4c06c7 --- arch/arm/configs/msm8909-perf_defconfig | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index bab0c9f536a..560ff7c6ea3 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -213,7 +213,7 @@ CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y -CONFIG_RMNET_DATA_DEBUG_PKT=y +#CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_BT_RFCOMM=y @@ -319,7 +319,7 @@ CONFIG_INPUT_GPIO=m # CONFIG_DEVKMEM is not set #CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_HSL=y -CONFIG_SERIAL_MSM_HSL_CONSOLE=y +# CONFIG_SERIAL_MSM_HSL_CONSOLE=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y @@ -469,7 +469,7 @@ CONFIG_MSM_MEMORY_DUMP_V2=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_COMMON_LOG=y CONFIG_MSM_WATCHDOG_V2=y -#CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_SCM=y @@ -543,10 +543,6 @@ CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_QMI_ENCDEC=y -CONFIG_MEMCG=y -CONFIG_MEMCG_SWAP=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_SECURITY=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_FUSE_FS=y CONFIG_CMA_SIZE_MBYTES=8 @@ -569,3 +565,4 @@ CONFIG_TOUCHSCREEN_GT9XX=y CONFIG_NRF_DRIVER=y CONFIG_EXTCON=y CONFIG_EXTCON_PTN5150=y + -- 2.25.1 From c2645bab9967a80c2420eb6d2cf024dc3c4a5a99 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Mon, 7 Sep 2020 18:44:14 -0600 Subject: [PATCH 51/76] kernal/msm-3.18: MeiG: huangshifang: 1ms output PWM Change-Id: I880e55b658800fa0a034edc62e1bb449f54d3e20 --- drivers/platform/msm/qpnp-vibrator.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index 43cfe1a9811..c505c74a1bb 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -280,6 +280,7 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(gl_vib->medium_gpio, 0); gpio_direction_output(gl_vib->loud_gpio, 0); gpio_direction_output(gl_vib->pwr_gpio, 1); + msleep(1); //pr_err("sound_quiet start \n"); break; case SOUND_MEDIUM: @@ -287,6 +288,7 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(gl_vib->medium_gpio, 1); gpio_direction_output(gl_vib->loud_gpio, 0); gpio_direction_output(gl_vib->pwr_gpio, 1); + msleep(1); //pr_err("sound_medium start \n"); break; case SOUND_LOUD: @@ -294,6 +296,7 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) gpio_direction_output(gl_vib->medium_gpio, 0); gpio_direction_output(gl_vib->loud_gpio, 1); gpio_direction_output(gl_vib->pwr_gpio, 1); + msleep(1); //pr_err("sound_loud start \n"); break; default: -- 2.25.1 From ca08b5be872f6624f2bea38b58d3338b50a1985e Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 8 Sep 2020 15:02:37 -0600 Subject: [PATCH 52/76] kernel/msm-3.18: MeiG: liangdi: disable QC2.0 charger Change-Id: Ie0433a302ec75fb3225e44e85aa1d6dcbf2df781 --- drivers/power/smb135x-charger.c | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 2cb4c04d0a5..c95c16e9efc 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -2203,6 +2203,12 @@ static void smb135x_external_power_changed(struct power_supply *psy) struct smb135x_chg, batt_psy); union power_supply_propval prop = {0,}; int rc, current_limit = 0; + //add by liangdi fixed charging issue 20200818 + u8 reg; + int usb_type_index; + char *usb_type_name = "null"; + enum power_supply_type usb_supply_type; + //add end if (!chip->usb_psy) return; @@ -2219,6 +2225,38 @@ static void smb135x_external_power_changed(struct power_supply *psy) else current_limit = prop.intval / 1000; + //add by liangdi fixed charging issue 20200818 + rc = smb135x_read(chip, STATUS_5_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read status 5 rc = %d\n", rc); + return; + } + /* + * Report the charger type as UNKNOWN if the + * apsd-fail flag is set. This nofifies the USB driver + * to initiate a s/w based charger type detection. + */ + if (chip->workaround_flags & WRKARND_APSD_FAIL) + reg = 0; + + rc = get_usb_type_index(chip, reg, &usb_type_index); + if (rc < 0) { + dev_err(chip->dev, + "Error getting usb_type_index rc = %d\n", rc); + return; + } + usb_type_name = usb_type_str[usb_type_index]; + usb_supply_type = usb_type_enum[usb_type_index]; + pr_err("inserted %s, usb psy type = %d stat_5 = 0x%02x apsd_rerun = %d\n", + usb_type_name, usb_supply_type, reg, chip->apsd_rerun); + + if((current_limit == 500) && (usb_supply_type == POWER_SUPPLY_TYPE_USB_DCP)) + { + pr_err("need change current\n"); + current_limit = 3000; + } + //add end + pr_err("current_limit = %d\n", current_limit); if (chip->usb_psy_ma != current_limit) { @@ -3787,6 +3825,7 @@ static int smb135x_hw_init(struct smb135x_chg *chip) int rc; int i; u8 reg, mask; + u8 cfg_e; if (chip->pinctrl_state_name) { chip->smb_pinctrl = pinctrl_get_select(chip->dev, @@ -3996,6 +4035,7 @@ static int smb135x_hw_init(struct smb135x_chg *chip) } if (chip->usb_pullup_vreg) { + pr_err("enable 9V HVDCP adapter support\n"); /* enable 9V HVDCP adapter support */ rc = smb135x_masked_write(chip, CFG_E_REG, HVDCP_5_9_BIT, HVDCP_5_9_BIT); @@ -4006,6 +4046,20 @@ static int smb135x_hw_init(struct smb135x_chg *chip) } } + //add by liangdi for disable HVDCP 20200818 + rc = smb135x_masked_write(chip, CFG_E_REG, HVDCP_5_9_BIT | HVDCP_EN_BIT, 0); + if (rc < 0) + dev_err(chip->dev, + "Couldn't request for 5V rc=%d\n", rc); + + rc = smb135x_read(chip, CFG_E_REG, &cfg_e); + if (rc < 0) { + pr_err("Couldn't read cfg_e_reg rc = %d\n", rc); + return rc; + } + pr_err("read CFG_E_REG 0x%x\n", cfg_e); + //add end + if (chip->gamma_setting) { rc = smb135x_masked_write(chip, CFG_1B_REG, COLD_HARD_MASK, chip->gamma_setting[0] << COLD_HARD_SHIFT); -- 2.25.1 From 09310dd17208f4c292defe8d466a93c07ea5f2ae Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 8 Sep 2020 15:12:03 -0600 Subject: [PATCH 53/76] kernel/msm-3.18: MeiG: liangdi:add battery charging jeita Change-Id: I81509493068ea3225c799171a538a4af4b654bab --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 15 +- drivers/power/smb135x-charger.c | 455 ++++++++++++++++++++++-- 2 files changed, 440 insertions(+), 30 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 2b3c132444c..32335431be2 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -37,10 +37,23 @@ qcom,recharge-thresh-mv = <100>; regulator-name = "smb1357_otg_vreg"; qcom,soft-vfloat-comp-disabled; - qcom,thermal-mitigation = <2500 2500 1000 0>; + //qcom,soft-current-comp-disabled; + qcom,thermal-mitigation = <2500 2500 2500 0>; + qcom,fastchg-ma = <1250>; qcom,bms-psy-name = "bms"; + qcom,hot-bat-decidegc= <550>; + qcom,warm-bat-decidegc= <450>; + qcom,cool-bat-decidegc= <150>; + qcom,cold-bat-decidegc= <0>; + qcom,warm-bat-ma= <1250>; + qcom,cool-bat-ma= <500>; + qcom,warm-bat-mv = <4100>; + qcom,cool-bat-mv = <4350>; + qcom,chg-vadc = <&pm8909_vadc>; + qcom,chg-adc_tm = <&pm8909_adc_tm>; + /* * Disable SMB1357 based charging termination as BMS * controls charging. diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index c95c16e9efc..483906151d4 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -28,6 +28,7 @@ #include #include #include +#include #define SMB135X_BITS_PER_REG 8 @@ -441,8 +442,27 @@ struct smb135x_chg { bool apsd_rerun; bool id_line_not_connected; struct smb135x_wakeup_source wake_source; + //add by liangdi for battery charging jeita 20200819 + bool jeita_supported; + struct qpnp_vadc_chip *vadc_dev; + struct qpnp_adc_tm_chip *adc_tm_dev; + struct qpnp_adc_tm_btm_param adc_param; + int cold_bat_decidegc; + int hot_bat_decidegc; + int cool_bat_decidegc; + int warm_bat_decidegc; + unsigned int cool_bat_ma; + unsigned int warm_bat_ma; + unsigned int cool_bat_mv; + unsigned int warm_bat_mv; + + int bat_present_decidegc; + int jeita_current_limit; + //add end }; +#define MAX_FAST_CHARG_CURRENT 2500 + #define RETRY_COUNT 5 int retry_sleep_ms[RETRY_COUNT] = { 10, 20, 30, 40, 50 @@ -1280,6 +1300,7 @@ static int smb135x_set_fastchg_current(struct smb135x_chg *chip, dev_err(chip->dev, "cannot write to config c rc = %d\n", rc); pr_err("fastchg current set to %dma\n", chip->fastchg_current_table[i]); + chip->fastchg_ma_now = current_ma; return rc; } @@ -2668,31 +2689,31 @@ static void wireless_insertion_work(struct work_struct *work) static int hot_hard_handler(struct smb135x_chg *chip, u8 rt_stat) { - pr_debug("rt_stat = 0x%02x\n", rt_stat); - chip->batt_hot = !!rt_stat; + pr_err("rt_stat = 0x%02x\n", rt_stat); + //chip->batt_hot = !!rt_stat; return 0; } static int cold_hard_handler(struct smb135x_chg *chip, u8 rt_stat) { - pr_debug("rt_stat = 0x%02x\n", rt_stat); - chip->batt_cold = !!rt_stat; + pr_err("rt_stat = 0x%02x\n", rt_stat); + //chip->batt_cold = !!rt_stat; return 0; } static int hot_soft_handler(struct smb135x_chg *chip, u8 rt_stat) { - pr_debug("rt_stat = 0x%02x\n", rt_stat); - chip->batt_warm = !!rt_stat; + pr_err("rt_stat = 0x%02x\n", rt_stat); + //chip->batt_warm = !!rt_stat; return 0; } static int cold_soft_handler(struct smb135x_chg *chip, u8 rt_stat) { - pr_debug("rt_stat = 0x%02x\n", rt_stat); - chip->batt_cool = !!rt_stat; + pr_err("rt_stat = 0x%02x\n", rt_stat); + //chip->batt_cool = !!rt_stat; return 0; } static int battery_missing_handler(struct smb135x_chg *chip, u8 rt_stat) { - pr_debug("rt_stat = 0x%02x\n", rt_stat); + pr_err("rt_stat = 0x%02x\n", rt_stat); chip->batt_present = !rt_stat; return 0; } @@ -3079,8 +3100,277 @@ static void src_detect_check_work(struct work_struct *work) } } +//add by liangdi for battery charging jeita 20200819 +static void smb135x_chg_set_appropriate_battery_current( + struct smb135x_chg *chip) +{ + int rc; + int soc = 0; + unsigned int current_max = 0; + + soc = smb135x_get_prop_batt_capacity(chip); + + if(soc <= 15) + current_max = MAX_FAST_CHARG_CURRENT; + else + current_max = chip->fastchg_ma; + + + chip->jeita_current_limit = 0; + + if (chip->batt_cool) + { + current_max = min(current_max, chip->cool_bat_ma); + chip->jeita_current_limit = chip->cool_bat_ma; + } + + if (chip->batt_warm) + { + current_max = min(current_max, chip->warm_bat_ma); + chip->jeita_current_limit = chip->warm_bat_ma; + } + + pr_err("jeita soc %d current_max %d current_limit %d\n",soc, current_max, chip->jeita_current_limit); + + rc = smb135x_set_fastchg_current(chip, current_max); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); + return; + } +} + +static void smb135x_chg_set_appropriate_vddmax( + struct smb135x_chg *chip) +{ + int rc; + unsigned int vddmax = chip->vfloat_mv; + + if (chip->batt_cool) + vddmax = min(vddmax, chip->cool_bat_mv); + if (chip->batt_warm) + vddmax = min(vddmax, chip->warm_bat_mv); + + pr_err("jeita voltage limit %dmV\n",vddmax); + rc = smb135x_float_voltage_set(chip, vddmax); + if (rc) + dev_err(chip->dev, + "Couldn't set float voltage rc = %d\n", rc); +} + +#define HYSTERESIS_DECIDEGC 20 +static void smb_chg_adc_notification(enum qpnp_tm_state state, void *ctx) +{ + int rc = 0; + struct smb135x_chg *chip = ctx; + bool bat_hot = 0, bat_cold = 0, bat_present = 0, bat_warm = 0, + bat_cool = 0; + int temp; + + if (state >= ADC_TM_STATE_NUM) { + pr_err("invallid state parameter %d\n", state); + return; + } + + temp = smb135x_get_prop_batt_temp(chip); + + pr_err("temp = %d state = %s\n", temp, + state == ADC_TM_WARM_STATE ? "hot" : "cold"); + + if (state == ADC_TM_WARM_STATE) { + if (temp >= chip->hot_bat_decidegc) { + bat_hot = true; + bat_warm = false; + bat_cold = false; + bat_cool = false; + bat_present = true; + + chip->adc_param.low_temp = + chip->hot_bat_decidegc - HYSTERESIS_DECIDEGC; + chip->adc_param.state_request = + ADC_TM_COOL_THR_ENABLE; + } else if (temp >= + chip->warm_bat_decidegc && chip->jeita_supported) { + bat_hot = false; + bat_warm = true; + bat_cold = false; + bat_cool = false; + bat_present = true; + + chip->adc_param.low_temp = + chip->warm_bat_decidegc - HYSTERESIS_DECIDEGC; + chip->adc_param.high_temp = + chip->hot_bat_decidegc; + } else if (temp >= + chip->cool_bat_decidegc && chip->jeita_supported) { + bat_hot = false; + bat_warm = false; + bat_cold = false; + bat_cool = false; + bat_present = true; + + chip->adc_param.low_temp = + chip->cool_bat_decidegc - HYSTERESIS_DECIDEGC; + chip->adc_param.high_temp = + chip->warm_bat_decidegc; + } else if (temp >= + chip->cold_bat_decidegc) { + bat_hot = false; + bat_warm = false; + bat_cold = false; + bat_cool = true; + bat_present = true; + + chip->adc_param.low_temp = + chip->cold_bat_decidegc - HYSTERESIS_DECIDEGC; + if (chip->jeita_supported) + chip->adc_param.high_temp = + chip->cool_bat_decidegc; + else + chip->adc_param.high_temp = + chip->hot_bat_decidegc; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } else if (temp >= chip->bat_present_decidegc) { + bat_hot = false; + bat_warm = false; + bat_cold = true; + bat_cool = false; + bat_present = true; + + chip->adc_param.high_temp = chip->cold_bat_decidegc; + chip->adc_param.low_temp = chip->bat_present_decidegc + - HYSTERESIS_DECIDEGC; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } + } else { + if (temp <= chip->bat_present_decidegc) { + bat_cold = true; + bat_cool = false; + bat_hot = false; + bat_warm = false; + bat_present = false; + chip->adc_param.high_temp = chip->bat_present_decidegc + + HYSTERESIS_DECIDEGC; + chip->adc_param.state_request = + ADC_TM_WARM_THR_ENABLE; + } else if (temp <= chip->cold_bat_decidegc) { + bat_hot = false; + bat_warm = false; + bat_cold = true; + bat_cool = false; + bat_present = true; + chip->adc_param.high_temp = + chip->cold_bat_decidegc + HYSTERESIS_DECIDEGC; + /* add low_temp to enable batt present check */ + chip->adc_param.low_temp = + chip->bat_present_decidegc; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } else if (temp <= chip->cool_bat_decidegc && + chip->jeita_supported) { + bat_hot = false; + bat_warm = false; + bat_cold = false; + bat_cool = true; + bat_present = true; + chip->adc_param.high_temp = + chip->cool_bat_decidegc + HYSTERESIS_DECIDEGC; + chip->adc_param.low_temp = + chip->cold_bat_decidegc; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } else if (temp <= chip->warm_bat_decidegc && + chip->jeita_supported) { + bat_hot = false; + bat_warm = false; + bat_cold = false; + bat_cool = false; + bat_present = true; + chip->adc_param.high_temp = + chip->warm_bat_decidegc + HYSTERESIS_DECIDEGC; + chip->adc_param.low_temp = + chip->cool_bat_decidegc; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } else if (temp <= chip->hot_bat_decidegc) { + bat_hot = false; + bat_warm = true; + bat_cold = false; + bat_cool = false; + bat_present = true; + if (chip->jeita_supported) + chip->adc_param.low_temp = + chip->warm_bat_decidegc; + else + chip->adc_param.low_temp = + chip->cold_bat_decidegc; + chip->adc_param.high_temp = + chip->hot_bat_decidegc + HYSTERESIS_DECIDEGC; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } + } + + if (bat_present) + chip->batt_present = true; + else + chip->batt_present = false; + + if (bat_hot ^ chip->batt_hot || bat_cold ^ chip->batt_cold) { + chip->batt_hot = bat_hot; + chip->batt_cold = bat_cold; + /* stop charging explicitly since we use PMIC thermal pin*/ + if (bat_hot || bat_cold || !chip->batt_present) + { + pr_err("stop to charging\n"); + rc = smb135x_path_suspend(chip, DC, THERMAL, true); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set dc suspend rc %d\n", rc); + return; + } + rc = smb135x_path_suspend(chip, USB, THERMAL, true); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set usb suspend rc %d\n", rc); + return; + } + } + else + { + pr_err("start to charging\n"); + rc = smb135x_path_suspend(chip, DC, THERMAL, false); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set dc suspend rc %d\n", rc); + return; + } + rc = smb135x_path_suspend(chip, USB, THERMAL, false); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set usb suspend rc %d\n", rc); + return; + } + } + } + + if ((chip->batt_warm ^ bat_warm || chip->batt_cool ^ bat_cool) + && chip->jeita_supported) { + chip->batt_warm = bat_warm; + chip->batt_cool = bat_cool; + + smb135x_chg_set_appropriate_battery_current(chip); + smb135x_chg_set_appropriate_vddmax(chip); + } + + pr_err("hot %d, cold %d, warm %d, cool %d, jeita supported %d, missing %d, low = %d deciDegC, high = %d deciDegC\n", + chip->batt_hot, chip->batt_cold, chip->batt_warm, + chip->batt_cool, chip->jeita_supported, chip->batt_present, + chip->adc_param.low_temp, chip->adc_param.high_temp); + if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param)) + pr_err("request ADC error\n"); +} +//add end + //add by liangdi for detect soc and limit max charging current 20200527 -#define MAX_FAST_CHARG_CURRENT 2500 + static void battery_detect_soc_work(struct work_struct *work) { struct smb135x_chg *chip = container_of(work, @@ -3088,28 +3378,43 @@ static void battery_detect_soc_work(struct work_struct *work) int rc = 0; int soc = 0; int vol_now = 0; + int temp; + soc = smb135x_get_prop_batt_capacity(chip); vol_now = smb135x_get_prop_batt_voltage(chip);; + temp = smb135x_get_prop_batt_temp(chip); - pr_err("detect soc usb_present=%d, soc %d, fastchg_ma_now %d,vol_now %d\n", - chip->usb_present,soc,chip->fastchg_ma_now,vol_now); + pr_err("detect soc usb_present=%d, soc %d, fastchg_ma_now %d,vol_now %d, temp %d, jeita_current_limit %d\n", + chip->usb_present,soc,chip->fastchg_ma_now,vol_now,temp,chip->jeita_current_limit); - if((soc <= 15) && (chip->fastchg_ma_now != MAX_FAST_CHARG_CURRENT)) + if(chip->jeita_current_limit != 0) { - chip->fastchg_ma_now = MAX_FAST_CHARG_CURRENT; - rc = smb135x_set_fastchg_current(chip, MAX_FAST_CHARG_CURRENT); - if (rc < 0) { - dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); - return; - } + if(chip->fastchg_ma_now != chip->jeita_current_limit) + { + rc = smb135x_set_fastchg_current(chip, chip->jeita_current_limit); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); + return; + } + } } - else if((soc > 15) && (chip->fastchg_ma_now != chip->fastchg_ma)) + else { - chip->fastchg_ma_now = chip->fastchg_ma; - rc = smb135x_set_fastchg_current(chip, chip->fastchg_ma); - if (rc < 0) { - dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); - return; + if((soc <= 15) && (chip->fastchg_ma_now != MAX_FAST_CHARG_CURRENT)) + { + rc = smb135x_set_fastchg_current(chip, MAX_FAST_CHARG_CURRENT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); + return; + } + } + else if((soc > 15) && (chip->fastchg_ma_now != chip->fastchg_ma)) + { + rc = smb135x_set_fastchg_current(chip, chip->fastchg_ma); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set fastchg current = %d\n",rc); + return; + } } } @@ -3765,7 +4070,7 @@ static int determine_initial_status(struct smb135x_chg *chip) dev_err(chip->dev, "Couldn't read irq A rc = %d\n", rc); return rc; } - +/* if (reg & IRQ_A_HOT_HARD_BIT) chip->batt_hot = true; if (reg & IRQ_A_COLD_HARD_BIT) @@ -3774,7 +4079,7 @@ static int determine_initial_status(struct smb135x_chg *chip) chip->batt_warm = true; if (reg & IRQ_A_COLD_SOFT_BIT) chip->batt_cool = true; - +*/ rc = smb135x_read(chip, IRQ_C_REG, ®); if (rc < 0) { dev_err(chip->dev, "Couldn't read irq A rc = %d\n", rc); @@ -4024,8 +4329,6 @@ static int smb135x_hw_init(struct smb135x_chg *chip) /* set maximum fastchg current */ if (chip->fastchg_ma != -EINVAL) { - - chip->fastchg_ma_now = chip->fastchg_ma;//add by liangdi for detect soc and limit max charging current 20200527 rc = smb135x_set_fastchg_current(chip, chip->fastchg_ma); if (rc < 0) { dev_err(chip->dev, "Couldn't set fastchg current = %d\n", @@ -4369,6 +4672,53 @@ static int smb_parse_dt(struct smb135x_chg *chip) chip->id_line_not_connected = of_property_read_bool(node, "qcom,id-line-not-connected"); + + //add by liangdi for battery charging jeita 20200819 + rc = of_property_read_u32(node, "qcom,cold-bat-decidegc", + &chip->cold_bat_decidegc); + if (rc < 0) + chip->cold_bat_decidegc = 0; + + rc = of_property_read_u32(node, "qcom,hot-bat-decidegc", + &chip->hot_bat_decidegc); + if (rc < 0) + chip->hot_bat_decidegc = 550; + + rc = of_property_read_u32(node, "qcom,warm-bat-decidegc", + &chip->warm_bat_decidegc); + if (rc < 0) + chip->warm_bat_decidegc = 450; + + rc = of_property_read_u32(node, "qcom,cool-bat-decidegc", + &chip->cool_bat_decidegc); + if (rc < 0) + chip->cool_bat_decidegc = 150; + + rc = of_property_read_u32(node, "qcom,cool-bat-ma", + &chip->cool_bat_ma); + if (rc < 0) + chip->cool_bat_ma = 500; + + rc = of_property_read_u32(node, "qcom,warm-bat-ma", + &chip->warm_bat_ma); + if (rc < 0) + chip->warm_bat_ma = 500; + + rc = of_property_read_u32(node, "qcom,cool-bat-mv", + &chip->cool_bat_mv); + if (rc < 0) + chip->cool_bat_mv = 4100; + + rc = of_property_read_u32(node, "qcom,warm-bat-mv", + &chip->warm_bat_mv); + if (rc < 0) + chip->warm_bat_mv = 4100; + + pr_err("hot dec %d, warm dec %d, cool dec %d, cold dec %d, cool ma %d, warm ma %d\n", + chip->hot_bat_decidegc,chip->warm_bat_decidegc,chip->cool_bat_decidegc,chip->cold_bat_decidegc, + chip->cool_bat_ma,chip->warm_bat_ma); + + //add end return 0; } @@ -4505,6 +4855,24 @@ static int smb135x_main_charger_probe(struct i2c_client *client, return rc; } +//add by liangdi for battery charging jeita 20200819 + chip->vadc_dev = qpnp_get_vadc(chip->dev, "chg"); + if (IS_ERR(chip->vadc_dev)) { + rc = PTR_ERR(chip->vadc_dev); + if (rc != -EPROBE_DEFER) + pr_err("vadc property configured incorrectly\n"); + return rc; + } + + chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg"); + if (IS_ERR(chip->adc_tm_dev)) { + rc = PTR_ERR(chip->adc_tm_dev); + if (rc != -EPROBE_DEFER) + pr_err("adc_tm property missing\n"); + return rc; + } +//add end + usb_psy = power_supply_get_by_name("usb"); if (!usb_psy && chip->chg_enabled) { dev_dbg(&client->dev, "USB supply not found; defer probe\n"); @@ -4657,6 +5025,35 @@ static int smb135x_main_charger_probe(struct i2c_client *client, schedule_delayed_work(&chip->bat_detect_soc_work, msecs_to_jiffies(200)); //add end + //add by liangdi for battery charging jeita 20200819 + chip->jeita_supported = true; + + chip->bat_present_decidegc = -200; + + if(chip->jeita_supported ) + { + chip->adc_param.low_temp = chip->cool_bat_decidegc; + chip->adc_param.high_temp = chip->warm_bat_decidegc; + } + else + { + chip->adc_param.low_temp = chip->cold_bat_decidegc; + chip->adc_param.high_temp = chip->hot_bat_decidegc; + } + chip->adc_param.timer_interval = ADC_MEAS2_INTERVAL_1S; + chip->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE; + chip->adc_param.btm_ctx = chip; + chip->adc_param.threshold_notification = + smb_chg_adc_notification; + chip->adc_param.channel = LR_MUX1_BATT_THERM; + + /* update battery missing info in tm_channel_measure*/ + rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev, + &chip->adc_param); + if (rc) + pr_err("requesting ADC error %d\n", rc); + //add end + dev_info(chip->dev, "SMB135X version = %s revision = %s successfully probed batt=%d dc = %d usb = %d\n", version_str[chip->version], revision_str[chip->revision], -- 2.25.1 From 87b6c3bd318687c26cd0ef5254c4cee4f0531e95 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 9 Sep 2020 15:34:20 -0600 Subject: [PATCH 54/76] kernel/msm-3.18: MeiG liangdi:add serial console and disable console Rx MeiG: liangdi:Brightness Control by Pulse Dimming MeiG liangdi optimize led drivers Change-Id: I7fa68a03c3a2431929bf307c3cb10390dc98af9d --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 1 + arch/arm/boot/dts/qcom/msm8909-regulator.dtsi | 2 +- arch/arm/configs/msm8909-perf_defconfig | 3 +- drivers/tty/serial/Kconfig | 8 + drivers/tty/serial/msm_serial_hs_lite.c | 9 +- drivers/video/msm/mdss/mdss_dsi.c | 7 + drivers/video/msm/mdss/mdss_dsi.h | 2 + drivers/video/msm/mdss/mdss_dsi_panel.c | 144 ++++++++++++++++++ 8 files changed, 172 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 32335431be2..bb8b45b7722 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -771,6 +771,7 @@ qcom,platform-reset-gpio = <&msm_gpio 25 0>; qcom,platform-bklight-en-gpio = <&msm_gpio 17 0>; + qcom,bklight-pulse-gpio = <&msm_gpio 36 0>; }; /* CoreSight */ diff --git a/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi index 53ad975d3b6..8e99aac980d 100644 --- a/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-regulator.dtsi @@ -275,6 +275,6 @@ regulator-name = "spk_vreg"; startup-delay-us = <0>; enable-active-high; - gpio = <&msm_gpio 36 0>; + gpio = <&msm_gpio 93 0>; }; }; diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 560ff7c6ea3..d5b2b92eda6 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -319,7 +319,8 @@ CONFIG_INPUT_GPIO=m # CONFIG_DEVKMEM is not set #CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_HSL=y -# CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL_CONSOLE=y +CONFIG_SERIAL_MSM_HSL_CONSOLE_RX_DISABLE=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 3bac01181ab..624b60d109f 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1092,6 +1092,14 @@ config SERIAL_MSM_HSL help Select this module to enable MSM high speed UART driver. +config SERIAL_MSM_HSL_CONSOLE_RX_DISABLE + tristate "MSM UART :disable console rx" + depends on (ARM || ARM64) && ARCH_MSM + select SERIAL_CORE + default n + help + Select this module to disable console rx. + config SERIAL_MSM_HSL_CONSOLE bool "MSM High speed serial legacy mode console support" depends on SERIAL_MSM_HSL=y diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c index f4e87c7cd87..5d74bad4801 100644 --- a/drivers/tty/serial/msm_serial_hs_lite.c +++ b/drivers/tty/serial/msm_serial_hs_lite.c @@ -610,8 +610,13 @@ static void handle_rx(struct uart_port *port, unsigned int misr) /* TODO: handle sysrq */ /* if (!uart_handle_sysrq_char(port, c)) */ - copied = tty_insert_flip_string(tty->port, (char *) &c, - (count > 4) ? 4 : count); +#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE_RX_DISABLE + if(strcmp(msm_hsl_port->name,"msm_serial_hsl0"))//add by liangdi for disable console RX 20200901 +#endif + { + copied = tty_insert_flip_string(tty->port, (char *) &c, + (count > 4) ? 4 : count); + } count -= copied; } diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c index 6813c756970..c11002eaac5 100644 --- a/drivers/video/msm/mdss/mdss_dsi.c +++ b/drivers/video/msm/mdss/mdss_dsi.c @@ -4097,6 +4097,13 @@ static int mdss_dsi_parse_gpio_params(struct platform_device *ctrl_pdev, if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) pr_info("%s: bklt_en gpio not specified\n", __func__); + //add by liangdi for Brightness Control by Pulse Dimming 20200821 + ctrl_pdata->bklt_pulse_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, + "qcom,bklight-pulse-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->bklt_pulse_gpio)) + pr_info("%s: bklt_pulse gpio not specified\n", __func__); + //add end + ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-reset-gpio", 0); if (!gpio_is_valid(ctrl_pdata->rst_gpio)) diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h index 6d6757ff592..321ebd395d4 100644 --- a/drivers/video/msm/mdss/mdss_dsi.h +++ b/drivers/video/msm/mdss/mdss_dsi.h @@ -432,6 +432,8 @@ struct mdss_dsi_ctrl_pdata { int rst_gpio; int disp_en_gpio; int bklt_en_gpio; + int bklt_pulse_gpio;//add by liangdi for Brightness Control by Pulse Dimming 20200821 + spinlock_t pulse_lock; int mode_gpio; int intf_mux_gpio; int bklt_ctrl; /* backlight ctrl */ diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c index 37a4f20cc2a..9aff9da775a 100644 --- a/drivers/video/msm/mdss/mdss_dsi_panel.c +++ b/drivers/video/msm/mdss/mdss_dsi_panel.c @@ -65,6 +65,129 @@ end: return status; } +//add by liangdi for Brightness Control by Pulse Dimming 20200821 +#define MAX_BRIGHT_LEVEL 3212 +#define MAX_PULSE_COUNT 16 +#define T_SHUTDOWN 5 //5ms //3ms < tSHDN +#define T_READY 50 //50us //30us < tREADY +#define T_HIGH 2 //2us //0.5us < tHI +#define T_LOW 2 //2us //0.5us < tLO < 500us +//#define MAX_PULSE_STEP 5 //set brightness step manually +void mdss_brightness_control_by_pulse(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int level) +{ + int pulse = 0, count =0; + int i = 0; + static int pre_pulse = -1; + unsigned long irqflags = 0; +#ifdef MAX_PULSE_STEP + int pulse_step[MAX_PULSE_STEP]={1,5,9,13,16}; +#endif + + if (!gpio_is_valid(ctrl_pdata->bklt_pulse_gpio)) + { + pr_err("bklt_pulse_gpio is not valid\n"); + return; + } + + if(level == 0) + { + //LCD off + gpio_direction_output(ctrl_pdata->bklt_pulse_gpio, 0); + pre_pulse = -1; + return; + } + + //max level is 3212, 214=3212/15 + pulse = level/(MAX_BRIGHT_LEVEL/15);//level/214;//0~15 + if((pulse < 0) || (pulse > 15)) + { + pr_err("brightness set error pulse %d, level %d\n", pulse, level); + return ; + } + + //how many pulse need to send + pulse = MAX_PULSE_COUNT - pulse;///1~16 + if(pre_pulse == pulse) + { + return; + } + + if(pre_pulse < 0) + { + //need tSHDN and tREADY + spin_lock_irqsave(&ctrl_pdata->pulse_lock, irqflags); + for(i=0; ibklt_pulse_gpio, 0);//showndown backlight + mdelay(T_SHUTDOWN);//3ms < tSHDN + gpio_direction_output(ctrl_pdata->bklt_pulse_gpio, 1); + udelay(T_READY);//30us < tREADY + } + else + { + gpio_direction_output(ctrl_pdata->bklt_pulse_gpio, 0); + udelay(T_LOW);//0.5us < tLO < 500us + gpio_direction_output(ctrl_pdata->bklt_pulse_gpio, 1); + udelay(T_HIGH);//0.5us < tHI + } + } + + pre_pulse = pulse; + spin_unlock_irqrestore(&ctrl_pdata->pulse_lock, irqflags); + pr_err("brightness reset\n"); + return; + } + +#ifdef MAX_PULSE_STEP + for(i=0; i= MAX_PULSE_STEP) + { + //pr_err("brightness skip pulse %d\n",pulse); + return; + } +#endif + + //pr_err("brightness pre_pulse %d pulse %d,level %d\n",pre_pulse,pulse,level); + + spin_lock_irqsave(&ctrl_pdata->pulse_lock, irqflags); + if(pulse < pre_pulse) + { + count = MAX_PULSE_COUNT - pre_pulse;//need to send in a loop + count = count + pulse;//total pulse need to send + + for(i=0; ibklt_pulse_gpio, 0); + udelay(T_LOW);//0.5us < tLO < 500us + gpio_direction_output(ctrl_pdata->bklt_pulse_gpio, 1); + udelay(T_HIGH);//0.5us < tHI + } + //pr_err("brightness -- %d\n",count); + } + else + { + count = pulse-pre_pulse; + for(i=0; ibklt_pulse_gpio, 0); + udelay(T_LOW);//0.5us < tLO < 500us + gpio_direction_output(ctrl_pdata->bklt_pulse_gpio, 1); + udelay(T_HIGH);//0.5us < tHI + } + //pr_err("brightness ++ %d\n",count); + } + pre_pulse = pulse; + spin_unlock_irqrestore(&ctrl_pdata->pulse_lock, irqflags); +} +//add end + static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level) { int ret; @@ -76,6 +199,8 @@ static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level) return; } + mdss_brightness_control_by_pulse(ctrl, level);//add by liangdi for Brightness Control by Pulse Dimming 20200821 + if (level == 0) { if (ctrl->pwm_enabled) { ret = pwm_config_us(ctrl->pwm_bl, level, @@ -317,6 +442,21 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) goto bklt_en_gpio_err; } } + + //add by liangdi for Brightness Control by Pulse Dimming 20200821 +/* + if (gpio_is_valid(ctrl_pdata->bklt_pulse_gpio)) { + rc = gpio_request(ctrl_pdata->bklt_pulse_gpio, + "bright_pulse"); + if (rc) { + pr_err("request bright_pulse failed, rc=%d\n", + rc); + goto bklt_pulse_gpio_err; + } + } +*/ + //add end + if (gpio_is_valid(ctrl_pdata->mode_gpio)) { rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode"); if (rc) { @@ -328,6 +468,9 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata) return rc; mode_gpio_err: +// if (gpio_is_valid(ctrl_pdata->bklt_pulse_gpio)) +// gpio_free(ctrl_pdata->bklt_pulse_gpio); +//bklt_pulse_gpio_err: if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) gpio_free(ctrl_pdata->bklt_en_gpio); bklt_en_gpio_err: @@ -2878,5 +3021,6 @@ int mdss_dsi_panel_init(struct device_node *node, mdss_dsi_panel_apply_display_setting; ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; ctrl_pdata->panel_data.get_idle = mdss_dsi_panel_get_idle_mode; + spin_lock_init(&ctrl_pdata->pulse_lock);//add by liangdi for Brightness Control by Pulse Dimming 20200821 return 0; } -- 2.25.1 From 8d88195a946caeb9093a9041042fa1a8838c1e7b Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 1 Oct 2020 09:57:34 -0600 Subject: [PATCH 55/76] kernel/msm-3.18: MEIG: liangdi:disable smb1358 jeita Change-Id: I6940d2b3d7fefb2a986c3390cb0661b12b1b1b8e --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 3 ++- drivers/power/smb135x-charger.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index bb8b45b7722..0f5f897aa50 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -37,7 +37,7 @@ qcom,recharge-thresh-mv = <100>; regulator-name = "smb1357_otg_vreg"; qcom,soft-vfloat-comp-disabled; - //qcom,soft-current-comp-disabled; + qcom,soft-current-comp-disabled; qcom,thermal-mitigation = <2500 2500 2500 0>; qcom,fastchg-ma = <1250>; @@ -53,6 +53,7 @@ qcom,cool-bat-mv = <4350>; qcom,chg-vadc = <&pm8909_vadc>; qcom,chg-adc_tm = <&pm8909_adc_tm>; + qcom,gamma-setting = <3 3 3 3>; /* * Disable SMB1357 based charging termination as BMS diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 483906151d4..98140e1f5e1 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -114,6 +114,7 @@ #define CFG_1A_REG 0x1A #define TEMP_MONITOR_EN_BIT BIT(6) +#define JEITA_TEMP_LIMIT_EN_BIT BIT(5) #define HOT_SOFT_VFLOAT_COMP_EN_BIT BIT(3) #define COLD_SOFT_VFLOAT_COMP_EN_BIT BIT(2) #define HOT_SOFT_CURRENT_COMP_EN_BIT BIT(1) @@ -4454,7 +4455,7 @@ static int smb135x_hw_init(struct smb135x_chg *chip) if (chip->soft_current_comp_disabled) { mask = HOT_SOFT_CURRENT_COMP_EN_BIT - | COLD_SOFT_CURRENT_COMP_EN_BIT; + | COLD_SOFT_CURRENT_COMP_EN_BIT | JEITA_TEMP_LIMIT_EN_BIT; rc = smb135x_masked_write(chip, CFG_1A_REG, mask, 0); if (rc < 0) { dev_err(chip->dev, "Couldn't disable soft current rc = %d\n", -- 2.25.1 From e40c10723d0e74bb73d28257b56e4f0974c015e5 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 1 Oct 2020 10:00:29 -0600 Subject: [PATCH 56/76] kernel/msm-3.18: MeiG: zhouxinghua modify the y direction for gyro Change-Id: Ia8edaab9f340c452506b10772c974f32c510eec5 --- drivers/input/misc/bmi160_driver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/input/misc/bmi160_driver.c b/drivers/input/misc/bmi160_driver.c index 4ac87c332d8..1d761d252d4 100755 --- a/drivers/input/misc/bmi160_driver.c +++ b/drivers/input/misc/bmi160_driver.c @@ -915,7 +915,9 @@ static void bmi_gyro_work_func(struct work_struct *work) bmi160_udata.x = data.x; bmi160_udata.y = data.y; bmi160_udata.z = data.z; - + //add by zhouxinghua 20200925 + bmi160_udata.y = -bmi160_udata.y; + //add end bmi_remap_sensor_data(&bmi160_udata, client_data); /*report current frame via input event*/ input_event(client_data->input_gyro, EV_ABS, ABS_RX, bmi160_udata.x); -- 2.25.1 From 7b4efc2a75fdecf8df3cacf88e8bf276d805d686 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 1 Oct 2020 10:32:21 -0600 Subject: [PATCH 57/76] kernel/msm-3.18: - added missing patches for charging updates. Change-Id: Ib22b249e1d1aabe0a9edd142183eba3b46484197 --- arch/arm/configs/msm8909_defconfig | 2 +- drivers/power/reset/msm-poweroff.c | 2 +- include/linux/usb/msm_hsusb.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 3731856a059..0587cd29f0c 100755 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -253,7 +253,7 @@ CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MSM_MCU_TIME_SYNC=y # CONFIG_SCSI_PROC_FS is not set -#CONFIG_SCSI=y +CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index b10dc24730a..27711ad7e19 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -60,7 +60,7 @@ static void scm_disable_sdi(void); * There is no API from TZ to re-enable the registers. * So the SDI cannot be re-enabled when it already by-passed. */ -static int download_mode = 1; +static int download_mode = 0;//1;//modify by liangdi for dump auto reboot 20200523 #else static const int download_mode; #endif diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 6cf3473ef41..64caf2e7033 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -120,9 +120,9 @@ enum msm_usb_phy_type { QUSB_ULPI_PHY, }; -#define IDEV_CHG_MAX 2000 //1500 //modify by liangdi for 2A current 20200115 +#define IDEV_CHG_MAX 3000 //1500 //modify by liangdi for 2A current 20200115 #define IUNIT 100 -#define IDEV_HVDCP_CHG_MAX 2000 //1800 //modify by liangdi for 2A current 20200115 +#define IDEV_HVDCP_CHG_MAX 3000 //1800 //modify by liangdi for 2A current 20200115 /** * Different states involved in USB charger detection. -- 2.25.1 From f1265b9041f22e6cfa83231415f035966fe8886f Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 23 Oct 2020 13:36:16 -0600 Subject: [PATCH 58/76] kernel/msm-3.18: - update kernel UART fifo to 256 from 64 to prevent buffer overruns. Change-Id: I4e00f79a1d54e53cabc427c78b2a4efed2933ac2 --- drivers/tty/serial/msm_serial_hs_lite.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c index 5d74bad4801..c61d8934eb7 100644 --- a/drivers/tty/serial/msm_serial_hs_lite.c +++ b/drivers/tty/serial/msm_serial_hs_lite.c @@ -1328,7 +1328,7 @@ static struct msm_hsl_port msm_hsl_uart_ports[] = { .iotype = UPIO_MEM, .ops = &msm_hsl_uart_pops, .flags = UPF_BOOT_AUTOCONF, - .fifosize = 64, + .fifosize = 256, // VIP: Increase FIFO size. (prev 64) .line = 0, }, }, @@ -1337,7 +1337,7 @@ static struct msm_hsl_port msm_hsl_uart_ports[] = { .iotype = UPIO_MEM, .ops = &msm_hsl_uart_pops, .flags = UPF_BOOT_AUTOCONF, - .fifosize = 64, + .fifosize = 256, // VIP: Increase FIFO size. (prev 64) .line = 1, }, }, @@ -1346,7 +1346,7 @@ static struct msm_hsl_port msm_hsl_uart_ports[] = { .iotype = UPIO_MEM, .ops = &msm_hsl_uart_pops, .flags = UPF_BOOT_AUTOCONF, - .fifosize = 64, + .fifosize = 256, // VIP: Increase FIFO size. (prev 64) .line = 2, }, }, -- 2.25.1 From 84e1ec5b442120484acf99ed50d12d503da65f01 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 27 Oct 2020 11:58:37 -0600 Subject: [PATCH 59/76] kernel/msm-3.18: - fix bug causing hard-poll of temperature sensor causing high CPU usage. - fixed to poll @0.5Hz. (from 14Hz) Change-Id: I0ee88e4b95da1dd9a7c7d1339cc217bf4c1ae893 --- drivers/input/misc/bmp280_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/input/misc/bmp280_core.c b/drivers/input/misc/bmp280_core.c index fc3c1b3db52..b2e77013fc8 100755 --- a/drivers/input/misc/bmp280_core.c +++ b/drivers/input/misc/bmp280_core.c @@ -1529,8 +1529,6 @@ static void bmp_temp_work_func(struct work_struct *work) struct bmp_client_data *client_data = container_of((struct delayed_work *)work, struct bmp_client_data, temp_work); - uint32_t delay = msecs_to_jiffies(client_data->delay); - uint32_t j1 = jiffies; uint32_t temperature; int status; @@ -1543,7 +1541,7 @@ static void bmp_temp_work_func(struct work_struct *work) input_sync(client_data->input_temp); } - schedule_delayed_work(&client_data->temp_work, delay-(jiffies-j1)); + schedule_delayed_work(&client_data->temp_work, msecs_to_jiffies(2000)); } //add end /*! -- 2.25.1 From 079e897e7efac4181bbf0026f084bca950534d38 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 5 Nov 2020 15:42:25 -0700 Subject: [PATCH 60/76] kernel/msm-3.18: - liangdi:optimize beeper drivers Change-Id: If47f5475673b10cde54f190337a4bbd679f97f67 --- drivers/platform/msm/qpnp-vibrator.c | 50 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/platform/msm/qpnp-vibrator.c b/drivers/platform/msm/qpnp-vibrator.c index c505c74a1bb..e50f9460f90 100755 --- a/drivers/platform/msm/qpnp-vibrator.c +++ b/drivers/platform/msm/qpnp-vibrator.c @@ -102,7 +102,7 @@ struct qpnp_vib { ktime_t kt; unsigned long time; int pwm_level; //0: low ,1:high - int gpio_pwm_value; + int pwm_start; // add for sub vbus en int sub_vbus_en_gpio; @@ -205,37 +205,33 @@ static void gpio_pwm_start(void) gl_vib->time = (unsigned long)((50 * gl_vib->pwm_timer_value)/100); gl_vib->pwm_level = 0; - gl_vib->kt = ktime_set(0, gl_vib->pwm_timer_value); - hrtimer_start(&gl_vib->mytimer,gl_vib->kt,HRTIMER_MODE_REL); + gl_vib->kt = ktime_set(0, gl_vib->time); + hrtimer_start(&gl_vib->mytimer,gl_vib->kt,HRTIMER_MODE_REL_PINNED); } static enum hrtimer_restart hrtimer_handler(struct hrtimer *timer) { - if(gl_vib->gpio_pwm_value == 0) + if(gl_vib->pwm_start == 0) { //pr_err("gpio pwm stop\n"); gpio_direction_output(gl_vib->pwm_gpio, 0); - gl_vib->pwm_level = 1; + gl_vib->pwm_level = 0; return HRTIMER_NORESTART; } - if(!gl_vib->pwm_level){ - - gpio_direction_output(gl_vib->pwm_gpio, 0); - - gl_vib->pwm_level = 1; - gl_vib->kt = ktime_set(0, gl_vib->time); - hrtimer_forward_now(&gl_vib->mytimer, gl_vib->kt); - - } else { - + if(!gl_vib->pwm_level) + { gpio_direction_output(gl_vib->pwm_gpio, 1); - + gl_vib->pwm_level = 1; + } + else + { + gpio_direction_output(gl_vib->pwm_gpio, 0); gl_vib->pwm_level = 0; - gl_vib->kt = ktime_set(0, gl_vib->time); - hrtimer_forward_now(&gl_vib->mytimer, gl_vib->kt); } - return HRTIMER_RESTART; + + hrtimer_forward_now(&gl_vib->mytimer, gl_vib->kt); + return HRTIMER_RESTART; } static int qpnp_vib_set(struct qpnp_vib *vib, int on) @@ -293,7 +289,7 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) break; case SOUND_LOUD: gpio_direction_output(gl_vib->quiet_gpio, 0); - gpio_direction_output(gl_vib->medium_gpio, 0); + gpio_direction_output(gl_vib->medium_gpio, 1); gpio_direction_output(gl_vib->loud_gpio, 1); gpio_direction_output(gl_vib->pwr_gpio, 1); msleep(1); @@ -306,7 +302,7 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) if (gpio_is_valid(vib->pwm_gpio)) { - vib->gpio_pwm_value = 1; + vib->pwm_start = 1; gpio_pwm_start(); } } @@ -331,13 +327,17 @@ static int qpnp_vib_set(struct qpnp_vib *vib, int on) //add end if (gpio_is_valid(vib->pwm_gpio)) - vib->gpio_pwm_value = 0; + { + vib->pwm_start = 0; + hrtimer_cancel(&vib->mytimer); + } //add by huangshifang for beeper sound control 20200516 gpio_direction_output(gl_vib->pwr_gpio, 0); gpio_direction_output(gl_vib->quiet_gpio, 0); gpio_direction_output(gl_vib->loud_gpio, 0); gpio_direction_output(gl_vib->medium_gpio, 0); + gpio_direction_output(gl_vib->pwm_gpio, 0); //add end } } @@ -353,7 +353,7 @@ static void qpnp_vib_enable(struct timed_output_dev *dev, int value) mutex_lock(&vib->lock); hrtimer_cancel(&vib->vib_timer); - //pr_err("qpnp_vib_enable %d",value); + //pr_err("qpnp_vib_enable %d\n",value); if(value != 10) { if (value == 0) { @@ -644,8 +644,8 @@ static int qpnp_vibrator_probe(struct spmi_device *spmi) return -EINVAL; } vib->base = vib_resource->start; - vib->gpio_pwm_value = 0; - hrtimer_init(&vib->mytimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); + vib->pwm_start = 0; + hrtimer_init(&vib->mytimer,CLOCK_MONOTONIC,HRTIMER_MODE_REL_PINNED); vib->mytimer.function = hrtimer_handler; rc = qpnp_vib_parse_dt(vib); -- 2.25.1 From 58a64b158896618b22f0f006514c2f7c6f311658 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 5 Nov 2020 16:27:30 -0700 Subject: [PATCH 61/76] kernel/msm-3.18: - liangdi:Compatible with the new TP Change-Id: Ica3e0179196844c55d3d2ad6dfbf3bc0c9e1ba37 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 113 +- arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 75 + arch/arm/configs/msm8909-perf_defconfig | 7 +- drivers/input/touchscreen/Kconfig | 10 +- drivers/input/touchscreen/Makefile | 2 +- drivers/input/touchscreen/gt1x/Kconfig | 221 ++ drivers/input/touchscreen/gt1x/Makefile | 5 + ...ting_Guide_for_Android_20150710_Rev.02.pdf | Bin 0 -> 355764 bytes .../gt1x/docs/GT1x-dts-bindings.txt | 74 + ...for-Goodix-TP-in-pinctrl-dts-reference.txt | 129 + .../touchscreen/gt1x/docs/RevisionLog.txt | 44 + drivers/input/touchscreen/gt1x/gt1x.c | 884 ++++++ drivers/input/touchscreen/gt1x/gt1x_extents.c | 1004 +++++++ drivers/input/touchscreen/gt1x/gt1x_generic.c | 2607 +++++++++++++++++ drivers/input/touchscreen/gt1x/gt1x_generic.h | 517 ++++ drivers/input/touchscreen/gt1x/gt1x_tools.c | 468 +++ drivers/input/touchscreen/gt1x/gt1x_update.c | 1494 ++++++++++ 17 files changed, 7590 insertions(+), 64 deletions(-) create mode 100755 drivers/input/touchscreen/gt1x/Kconfig create mode 100755 drivers/input/touchscreen/gt1x/Makefile create mode 100755 drivers/input/touchscreen/gt1x/docs/GT1X_Driver_Porting_Guide_for_Android_20150710_Rev.02.pdf create mode 100755 drivers/input/touchscreen/gt1x/docs/GT1x-dts-bindings.txt create mode 100755 drivers/input/touchscreen/gt1x/docs/Pingroup-for-Goodix-TP-in-pinctrl-dts-reference.txt create mode 100755 drivers/input/touchscreen/gt1x/docs/RevisionLog.txt create mode 100755 drivers/input/touchscreen/gt1x/gt1x.c create mode 100755 drivers/input/touchscreen/gt1x/gt1x_extents.c create mode 100755 drivers/input/touchscreen/gt1x/gt1x_generic.c create mode 100755 drivers/input/touchscreen/gt1x/gt1x_generic.h create mode 100755 drivers/input/touchscreen/gt1x/gt1x_tools.c create mode 100755 drivers/input/touchscreen/gt1x/gt1x_update.c diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 0f5f897aa50..dd961f507ee 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -133,61 +133,6 @@ i2c@78b9000 { /* BLSP1 QUP5 */ /* - goodix@5d { - compatible = "goodix,gt9xx"; - reg = <0x5d>; - interrupt-parent = <&msm_gpio>; - interrupts = <13 0x00>; - reset-gpios = <&msm_gpio 12 0x00>; - interrupt-gpios = <&msm_gpio 13 0x2002>; - vdd-supply = <&pm8909_l17>; - vcc_i2c-supply = <&pm8909_l6>; - // pins used by touchscreen - //pinctrl-names = "pmx_ts_active", - // "pmx_ts_suspend", - // "pmx_ts_release"; - //pinctrl-0 = <&ts_int_active &ts_reset_active>; - //pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - //pinctrl-2 = <&ts_release>; - goodix,i2c-pull-up; - goodix,no-force-update; - goodix,panel-coords = <0 0 480 800>; - goodix,display-coords = <0 0 480 800>; - goodix,button-map= <139 172 158>; - goodix,product-id0 = "917S"; - goodix,product-id1 = "917S"; - //goodix,fw_name = "gtp_fw.bin";if open, there is a null pointer in sysfs_remove_group - goodix,enable-power-off; - goodix,cfg-data0 = [ - 01 E0 01 20 03 05 0D 00 00 40 - 00 0F 78 64 53 11 01 00 00 00 - 14 17 19 1D 0F 04 00 00 00 00 - 00 00 04 51 14 00 00 00 00 00 - 32 00 00 50 54 28 85 25 10 37 - 39 A2 07 38 6D 62 93 02 24 00 - 00 28 50 C0 02 02 00 00 53 B1 - 2E 9E 35 8D 3B 80 42 76 49 6D - 00 00 00 00 00 00 00 F0 4C 3C - FF FF 07 14 14 00 00 00 00 00 - 00 00 00 00 00 00 00 00 50 73 - 50 32 FF FF 00 00 00 00 00 00 - 00 00 00 28 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 00 00 - 0D 0E 0F 10 12 13 14 15 1F 1D - 1B 1A 19 18 17 16 FF FF FF FF - FF FF FF FF FF FF FF FF FF FF - FF FF 06 08 0C 12 13 14 15 17 - 18 19 FF FF FF FF FF FF FF FF - FF FF FF FF 00 00 05 00 00 0F - 00 00 00 80 46 08 96 50 32 0A - 0A 64 32 00 00 00 00 00 00 70 - 22 03 0C 08 23 00 14 23 00 28 - 46 30 3C D0 07 50 30 02 01]; - goodix,cfg-data1 = []; - goodix,have-touch-key; - //goodix,driver-send-cfg; - }; -*/ gt9xx@5d { compatible = "goodix,gt9xx"; reg = <0x5d>; @@ -212,7 +157,7 @@ touchscreen-size-y = <800>; touchscreen-max-w = <512>; touchscreen-max-p = <512>; - touchscreen-key-map = <172>, <158>; /*KEY_HOMEPAGE=172, KEY_BACK=158��KEY_MENU=139*/ + touchscreen-key-map = <172>, <158>; goodix,slide-wakeup = <0>; goodix,type-a-report = <0>; @@ -228,8 +173,64 @@ 53 D0 02 00 05 05 F5 D5 21 48 2D 0F 5A 41 0E 05 00 00 32 32 20 00 05 14 14 1A 14 8B 2B 00 ]; }; +*/ + goodix_ts@14 { + compatible = "goodix,gt1x"; + reg = <0x14>; + status = "okay"; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2800>; + goodix,reset-gpio = <&msm_gpio 12 0x0>; + goodix,irq-gpio = <&msm_gpio 13 0x2800>; + goodix,default-config2 = [ + 01 E0 01 20 03 05 3D 15 A0 00 + 42 0C 6E 50 35 01 00 08 04 20 + 00 00 00 00 00 00 00 28 00 00 + 3C 08 32 28 28 64 00 00 8C A0 + C8 00 00 00 00 00 00 00 00 00 + 50 BE 00 00 85 05 0E 37 39 7C + 05 00 3D 33 24 F8 1E 18 32 C7 + 30 A9 38 82 41 7F 49 00 00 00 + 00 3C 00 00 00 00 57 50 32 FF + FF 77 00 00 00 00 00 00 00 00 + 00 00 00 00 28 5A C0 94 52 28 + 00 04 B6 30 9F 38 8D 41 80 49 + 75 51 6D 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 1F 1D 1B 1A 19 + 18 17 0F 10 12 13 14 15 16 FF + FF FF FF FF FF FF FF FF FF FF + FF FF FF FF FF FF FF 06 08 0C + 12 13 14 15 17 18 19 FF FF FF + FF FF FF FF FF FF FF FF FF FF + FF FF FF FF FF FF FF FF FF 00 + C4 09 23 23 50 5D 54 50 3C 14 + 32 FF FF 06 51 00 8A 02 40 00 + AA 00 22 22 00 40 9A 46 01 01 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 FF 00 + ]; + pinctrl-names = "pmx_ts_wakeup","pmx_ts_normal","pmx_ts_poweroff","pmx_ts_sleep"; + pinctrl-0 = <&ts_int_pullup &ts_reset_pullup>; + pinctrl-1 = <&ts_int_nopull &ts_reset_pullup>; + pinctrl-2 = <&ts_int_pulldown &ts_reset_pulldown>; + pinctrl-3 = <&ts_int_pulldown &ts_reset_pullup>; + }; }; + + i2c@78b6000 { /* BLSP1 QUP2 */ nq@28 { compatible = "qcom,nq-nci"; diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index f794c6849b1..a998a6a3f81 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -955,6 +955,81 @@ }; }; + pmx_ts_int_pullup { + ts_int_pullup: ts_int_pullup { + mux { + pins = "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_nopull { + ts_int_nopull: ts_int_nopull { + mux { + pins = "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + pmx_ts_int_pulldown { + ts_int_pulldown: ts_int_pulldown { + mux { + pins = "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_pullup { + ts_reset_pullup: ts_reset_pullup { + mux { + pins = "gpio12"; + function = "gpio"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_pulldown { + ts_reset_pulldown: ts_reset_pulldown { + mux { + pins = "gpio12"; + function = "gpio"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + nrf_int_active { nrf_int_active: nrf_int_active { mux { diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index d5b2b92eda6..89041e625f9 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -558,10 +558,13 @@ CONFIG_SENSORS_BMI160_ENABLE_INT1=y # CONFIG_SENSORS_BMI160_ENABLE_INT2=y CONFIG_SENSORS_BMP280=y CONFIG_SENSORS_BMP280_I2C=y -CONFIG_TOUCHSCREEN_GT9XX=y -#CONFIG_GT9XX_TOUCHPANEL_DRIVER=y +# CONFIG_TOUCHSCREEN_GT9XX=y +# CONFIG_GT9XX_TOUCHPANEL_DRIVER=y # CONFIG_GT9XX_TOUCHPANEL_UPDATE=y # CONFIG_GT9XX_TOUCHPANEL_DEBUG=y +CONFIG_TOUCHSCREEN_GOODIX_GT1X=y +CONFIG_GTP_POWER_CTRL_SLEEP=y +# CONFIG_GTP_DEBUG_ON=y #CONFIG_MG_DRIVER_CONTROL=y CONFIG_NRF_DRIVER=y CONFIG_EXTCON=y diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 537384144bf..99baf47fef8 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1136,17 +1136,17 @@ config TOUCHSCREEN_MAXIM_STI module will be called maxim_sti. source "drivers/input/touchscreen/gt9xx_2.8/Kconfig" -config TOUCHSCREEN_GT1XX - bool "Goodix touchpanel GT1xx series" +config TOUCHSCREEN_GOODIX_GT1X + bool "Goodix touchpanel GT1x series" depends on I2C help - Say Y here if you have a Goodix GT1xx touchscreen. - GT1xx controllers are multi touch controllers which can + Say Y here if you have a Goodix GT1x touchscreen. + GT1x controllers are multi touch controllers which can report 5 touches at a time. If unsure, say N. -source "drivers/input/touchscreen/gt1xx/Kconfig" +source "drivers/input/touchscreen/gt1x/Kconfig" config TOUCHSCREEN_HIMAX_CHIPSET bool "Himax touchpanel CHIPSET" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 1635943d44a..abcfe47bcf1 100755 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -91,4 +91,4 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o #obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx_2.8/ -obj-$(CONFIG_TOUCHSCREEN_GT1XX) += gt1xx/ +obj-$(CONFIG_TOUCHSCREEN_GOODIX_GT1X) += gt1x/ diff --git a/drivers/input/touchscreen/gt1x/Kconfig b/drivers/input/touchscreen/gt1x/Kconfig new file mode 100755 index 00000000000..ce2ca1be728 --- /dev/null +++ b/drivers/input/touchscreen/gt1x/Kconfig @@ -0,0 +1,221 @@ +# +# Touchscreen driver configuration +# +menuconfig TOUCHSCREEN_GOODIX_GT1X + bool "GOODIX GT1X Touchscreen" + default y + help + Say Y here if you have GOODIX GT1X Touchscreen. + + If unsure, say N. + +config GTP_INCELL_PANEL + bool "GTP_INCELL_PANEL" + default n + help + Say Y here if you have GT1152 incell panel.. + + If unsure, say N. + +config GTP_DRIVER_SEND_CFG + bool "GTP_DRIVER_SEND_CONFIG" + default n + help + Say Y here if you want touch driver send chip config + data to hardware. + + If unsure, say N. + +config GTP_CUSTOM_CFG + bool "GTP_CUSTOM_CONFIG" + default n + help + Say Y here if you want to customize the resolution and + INT trigger type. + + If unsure, say N. + +config GTP_CHANGE_X2Y + bool "GTP_CHANGE_X2Y" + default n + help + Say Y here if you want to change x/y coordinate. + + If unsure, say N. + +config GTP_WARP_X_ON + bool "GTP_WARP_X_ON" + default n + help + Say Y here if you want to mirror x. + + If unsure, say N. + +config GTP_WARP_Y_ON + bool "GTP_WARP_Y_ON" + default n + help + Say Y here if you want to mirror y. + + If unsure, say N. + +config GTP_GESTURE_WAKEUP + bool "GTP_GESTURE_WAKEUP Feature" + default n + help + Say Y here if you want to enable gesture feature. + + If unsure, say N. + +config GTP_HOTKNOT + bool "GTP_HOTKNOT Feature" + default n + help + Say Y here if you want to enable hotknot feature. + + If unsure, say N. + +config HOTKNOT_BLOCK_RW + bool "HOTKNOT_BLOCK_RW" + default n + help + Say Y here if you have want to enable blocking rw + feature when using hotknot. + + If unsure, say N. + +config GTP_FW_UPDATE_VERIFY + bool "GTP_FW_UPDATE_VERIFY" + default n + help + Say Y here if you want verify firmware in chip flash + during firmware update, it's unnecessary to enable + verification if you use the latest firmwrae. + + If unsure, say N. + +config GTP_HAVE_TOUCH_KEY + bool "GTP_HAVE_TOUCH_KEY" + default n + help + Say Y here if you have touch key. + + If unsure, say N. + +config GTP_PROXIMITY + bool "GTP_PROXIMITY Feature" + default n + help + Say Y here if you want enable proximity feature. + + If unsure, say N. + +config GTP_WITH_STYLUS + bool "GTP_WITH_STYLUS" + default n + help + Say Y here if you have pen. + + If unsure, say N. + +config GTP_HAVE_STYLUS_KEY + bool "GTP_HAVE_STYLUS_KEY" + default n + help + Say Y here if you have GTP_HAVE_STYLUS_KEY. + + If unsure, say N. + +config GTP_AUTO_UPDATE + bool "GTP_AUTO_UPDATE" + default n + help + Say Y here if you want to check and update firmware + during kernel booting. + + If unsure, say N. + +config GTP_CREATE_WR_NODE + bool "GTP_CREATE_WR_NODE DebugTools Node" + default y + help + Say Y here if you want to use Goodix debug tools.. + + If unsure, say N. + +config GTP_ESD_PROTECT + bool "GTP_ESD_PROTECT" + default n + help + Say Y here if you want ESD protection. + + If unsure, say N. + +config GTP_CHARGER_SWITCH + bool "GTP_CHARGER_SWITCH" + default n + help + Say Y here if you want ot turn on charger detector. + + If unsure, say N. + +config GTP_POWER_CTRL_SLEEP + bool "GTP_POWER_CTRL_SLEEP" + default n + help + Say Y here if you want ot power off touch panel + after suspend. + + If unsure, say N. + +config GTP_TYPE_B_PROTOCOL + bool "GTP_TYPE_B_PROTOCOL" + default y + help + Say Y here if you want to use input type B protocol. + + If unsure, say N. + +config GTP_SMART_COVER + bool "GTP_SMART_COVER" + default n + help + Say Y here if you want to use smart cover feature. + + If unsure, say N. + +config GTP_DEBUG_ON + bool "GTP_DEBUG_ON" + default n + help + Say Y here if you want to keep debug logs. + + If unsure, say N. + +config GTP_DEBUG_ARRAY_ON + bool "GTP_DEBUG_ARRAY_ON" + depends on GTP_DEBUG_ON + default n + help + Say Y here if you have GTP_DEBUG_ARRAY_ON. + + If unsure, say N. + +config GTP_DEBUG_FUNC_ON + bool "GTP_DEBUG_FUNC_ON" + depends on GTP_DEBUG_ON + default n + help + Say Y here if you have GTP_DEBUG_FUNC_ON. + + If unsure, say N. + +config TPD_HAVE_BUTTON + bool "TPD_HAVE_BUTTON" + depends on MTK_PLATFORM + default n + help + Say Y here if you have tpd button. + + If unsure, say N. + diff --git a/drivers/input/touchscreen/gt1x/Makefile b/drivers/input/touchscreen/gt1x/Makefile new file mode 100755 index 00000000000..fdc1bda9fad --- /dev/null +++ b/drivers/input/touchscreen/gt1x/Makefile @@ -0,0 +1,5 @@ +# Goodix GT1x Touch Driver + +obj-$(CONFIG_TOUCHSCREEN_GOODIX_GT1X) += gt1.o +gt1-objs += gt1x.o gt1x_generic.o gt1x_extents.o gt1x_update.o gt1x_tools.o + diff --git a/drivers/input/touchscreen/gt1x/docs/GT1X_Driver_Porting_Guide_for_Android_20150710_Rev.02.pdf b/drivers/input/touchscreen/gt1x/docs/GT1X_Driver_Porting_Guide_for_Android_20150710_Rev.02.pdf new file mode 100755 index 0000000000000000000000000000000000000000..d4ad4026bbce3f2c89d062f1e0aefc37e89e4df0 GIT binary patch literal 355764 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�q{ORhkWR&2ULp%Q?Vsc4Qv&FlLayC{d_=sYioj zS!mW2Y&7^JP}6$VKNW4Ya}GsJb`=7a;aFM0Hw zI(|;iK~sN)NNBowgc-7cHLc4uqIlBJf2EC^5Zcx(6wGX-<)K}NoYy_zIjO-+{T}>I zH%UiiMF@2~qWb4Kpc6@|n{^DDXsX8xru@Fg&zF?=VEnuwW|fh%Px7rE^@DQX0W%k> z$z5ROjyx8pE+t}+-(cpTKTO3~j+TlkzenxQT(ik)ems|A=#!vk5xXj zs#I=J4%n97tbUhf@>A4aIpjVTlL@M1shVv`mtyF!d&GYxn*ita>8s>4asG^9>=Mty zu8=CMR-DCSRj9P02xzm}M01{L7#)Ymd|aPAy_lhmf8w|>P5&idM4uiUwo)sRf5QpB zwhnlN7A7ct(E|V*hk~|F1th*qY+z9JT8irjkX=01zMC)KrA4sxx0>muQK;Qrfjna| z8TQvNO)Tgxk)7QVwMo;W^y{4z5Ir^b46qSlb~IGOd>MIy7JI!|LLob#a)SY%u;!1p zV9)9OQ=sZW&NDb6$U}VFgwloZ-6F>q9pXNG4lHkU_oiirwnKn@hy6}iqfu9Ju4Ep4 zHRZNZr`JS0VG&_&qY3nUm#-x8I@Gj7kJKkI_g;)ucg^~l<&>~#DM+cBvZj@q@QJI| z?8v@≧̸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 * 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∓caQ8G@co#plH!IFdC!k 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 literal 0 HcmV?d00001 diff --git a/drivers/input/touchscreen/gt1x/docs/GT1x-dts-bindings.txt b/drivers/input/touchscreen/gt1x/docs/GT1x-dts-bindings.txt new file mode 100755 index 00000000000..316c3709092 --- /dev/null +++ b/drivers/input/touchscreen/gt1x/docs/GT1x-dts-bindings.txt @@ -0,0 +1,74 @@ +Goodix GT1x-series Touch Driver Bindings +======================================== + +Required properties +------------------- + + - compatible: Should be "goodix,gt1x", compatible with the of_match_table + defined in driver. + - reg: I2C slave address of the device. + - interrupt-parent: Parent of interrupt. + - interrupts: Configuration of touch panel controller interrupt GPIO. + - vdd_ana-suppy: Power supply needed to power on the device, when use + external regulator, do not add this property. + - goodix,irq-gpio: Interrupt gpio which is to provide interrupts to + host, same as "interrupts" node. + - goodix,reset-gpio: Reset gpio to control the reset of chip. + - goodix,default-configx: chip default configuration data, x stands for + sensor ID. See example below for reference. + +*NOTE*: +Becausse kenel3.13 or later version does not support output of GPIO tied to IRQ line, +we add pinctrl method to set pins' states, you should add pinctrl-names, pinctrl-x +to dts as below. +- pinctrl-names = "pmx_ts_wakeup","pmx_ts_normal","pmx_ts_poweroff","pmx_ts_sleep"; +- pinctrl-0 = <&ts_int_pullup &ts_reset_pullup>; +- pinctrl-1 = <&ts_int_nopull &ts_reset_pullup>; +- pinctrl-2 = <&ts_int_pulldown &ts_reset_pulldown>; +- pinctrl-3 = <&ts_int_pulldown &ts_reset_pullup>; + + +Optional properties +------------------- + - goodix,charger-configx: chip configuration data used in charger mode, if you + hava enabled CONFIG_GTP_CHAGER_SWITCH, you need to add this property. + x stands for sendor ID. + - goodix,smartcover-configx: chip configuration data used in smartcover mode, if + you have enabled CONFIG_GTP_SMARTCOVER, you need to add this property. + +Example +------- +``` + i2c@f9927000 { /*Goodix BLSP1 QUP5 */ + goodix_ts@5d { + compatible = "goodix,gt1x"; + reg = <0x5d>; + interrupt-parent = <&msmgpio>; + interrupts = <17 0x2008>; + vdd_ana-supply = <&pm8226_l19>; + pinctrl-names = "pmx_ts_wakeup","pmx_ts_normal","pmx_ts_poweroff","pmx_ts_sleep"; + pinctrl-0 = <&ts_int_pullup &ts_reset_pullup>; + pinctrl-1 = <&ts_int_nopull &ts_reset_pullup>; + pinctrl-2 = <&ts_int_pulldown &ts_reset_pulldown>; + pinctrl-3 = <&ts_int_pulldown &ts_reset_pullup>; + goodix,reset-gpio = <&msmgpio 16 0x00>; + goodix,irq-gpio = <&msmgpio 17 0x00>; + goodix,default-config0 = [ + 5c 00 12 11 10 11 5f 00 cc bb + 22 00 11 00 00 00 00 00 00 00 + ... + ]; + goodix,charger-config2 = [ + 5f 00 12 11 10 11 5f 00 cc bb + 23 00 11 00 00 00 00 00 00 00 + ... + ]; + /* if you have disable CONFIG_GTP_INT_SEL_SYNC, + * please add properties below. + * You should config goodix_int_pull_up node in + * the pinctrl dtsi file */ + pinctrl-names = "default"; + pinctrl-0 = <&goodix_int_pull_up>; + +}; +``` diff --git a/drivers/input/touchscreen/gt1x/docs/Pingroup-for-Goodix-TP-in-pinctrl-dts-reference.txt b/drivers/input/touchscreen/gt1x/docs/Pingroup-for-Goodix-TP-in-pinctrl-dts-reference.txt new file mode 100755 index 00000000000..329b575bd7b --- /dev/null +++ b/drivers/input/touchscreen/gt1x/docs/Pingroup-for-Goodix-TP-in-pinctrl-dts-reference.txt @@ -0,0 +1,129 @@ + Drive Goodix TPIC without INT GPIO Output +======================================================== + +1.Background +------------ + +Goodix touch IC has a special mechanism that INT GPIO is used for I2C address +selection and GPIO synchronization during the hardware reset process. +The reason for designing this mechanism is to prevent i2c address conflict. +The main flow of this mechanism is as follows: + + reset pin output 0 -> INT pin output 1 if i2c address is 0x14, or output 0 if + i2c address is 0x5D -> reset pin output 1 -> delay and wait until hardware + address selection circuit initialization completes. -> INT pin output 0 to inform the + firmware that it can safely output INT pulse. + +But in kernal3.13 or later versions, the GPIO subsystem has restricted the output +of GPIO which had been tied to IRQ line. Therefore, we add pinctrl method to set pins' states. + +2.How-to +--------- + +If your kernel has the restriction on the output of GPIO tied to IRQ line, + follow the steps below: + + - Add pinctrl-names, pinctrl-x to TP dts as described at GT1x-dts-bindings.txt + - Add pingroup for Goodix touch as suggested below. + See below for example: + + ``` + i2c@f9927000 { /*Goodix BLSP1 QUP5 */ + goodix_ts@14 { + compatible = "goodix,gt1x"; + reg = <0x14>; + goodix,reset-gpio = <&msmgpio 16 0x00>; + goodix,irq-gpio = <&msmgpio 17 0x00>; + pinctrl-names = "pmx_ts_wakeup","pmx_ts_normal","pmx_ts_poweroff","pmx_ts_sleep"; + pinctrl-0 = <&ts_int_pullup &ts_reset_pullup>; + pinctrl-1 = <&ts_int_nopull &ts_reset_pullup>; + pinctrl-2 = <&ts_int_pulldown &ts_reset_pulldown>; + pinctrl-3 = <&ts_int_pulldown &ts_reset_pullup>; + + }; + + //e.g. in msm8937-pinctrl.dtsi + /* add pingrp for touchscreen */ + pmx_ts_int_pullup { + ts_int_pullup: ts_int_pullup { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_nopull { + ts_int_nopull: ts_int_nopull { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + pmx_ts_int_pulldown { + ts_int_pulldown: ts_int_pulldown { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_pullup { + ts_reset_pullup: ts_reset_pullup { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_pulldown { + ts_reset_pulldown: ts_reset_pulldown { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + ``` + + + + + + + diff --git a/drivers/input/touchscreen/gt1x/docs/RevisionLog.txt b/drivers/input/touchscreen/gt1x/docs/RevisionLog.txt new file mode 100755 index 00000000000..665a62ca420 --- /dev/null +++ b/drivers/input/touchscreen/gt1x/docs/RevisionLog.txt @@ -0,0 +1,44 @@ +Goodix GT1x series Driver - Android platform +============================================ + +Revision Information +-------------------- +v1.6+ 2017/12/12 + -Add pinctrl method to set the pins' states. + -Modify the risk whitch read or write user point directly. + +V1.6 2016/11/02 + - Move macros to Kconfig + - Support extended configuration data. + - Using request_firmware to obtain chip firmware and hotknot auth-firmwrae. + - Add fallback flow to probe function. + - Move configuration data to devictreee node. + - Using threaded IRQ to do the bottom half work. + - Fix issue of coordinates report when using Input typeB protocol. + +v1.4 2015/07/10 + - Free resource of gpio and regulator when module removed. + - Add gesture debug command to proc/gt1x_debug + - Modify chip reset function to support GT2x + - Make wake-up process simplified. + - Adjustment for gt1x_init. + - Calculate checksum of gesture package. + - Fixed bugs in hotknot ioctl function. + - Support incell touch ic + - Double check firmware update status ret + +v1.2 2015/3/28 + - Add device tree support. + - Add mutex lock for gt1x_send_cfg + - Calculate checksum of coordinates package + - Add P-sensor module for non-mtk platform + - Add Smartcover module + - Move suspend/resume functions into gt1x_generic.c + - Fixed some bugs + - New rules for firmware patch id + - Add a thread to run GTP Tools firmware upgrade function. + - Add LCD notify callback. + - 64bit kernel compatibility + +v1.0 2014/11/28 + - First Release. diff --git a/drivers/input/touchscreen/gt1x/gt1x.c b/drivers/input/touchscreen/gt1x/gt1x.c new file mode 100755 index 00000000000..e781490536e --- /dev/null +++ b/drivers/input/touchscreen/gt1x/gt1x.c @@ -0,0 +1,884 @@ +/* drivers/input/touchscreen/gt1x.c + * + * 2010 - 2017 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.6 + */ + +#include "gt1x_generic.h" +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL +#include +#endif + +static struct input_dev *input_dev; +static spinlock_t irq_lock; +static int irq_disabled; + +struct goodix_pinctrl gt_pinctrl; + +#ifdef CONFIG_OF +//static struct regulator *vdd_ana; +int gt1x_rst_gpio; +int gt1x_int_gpio; +#endif + +static int gt1x_register_powermanger(void); +static int gt1x_unregister_powermanger(void); + +/** + * gt1x_i2c_write - i2c write. + * @addr: register address. + * @buffer: data buffer. + * @len: the bytes of data to write. + *Return: 0: success, otherwise: failed + */ +s32 gt1x_i2c_write(u16 addr, u8 * buffer, s32 len) +{ + struct i2c_msg msg = { + .flags = 0, + .addr = gt1x_i2c_client->addr, + }; + return _do_i2c_write(&msg, addr, buffer, len); +} + +/** + * gt1x_i2c_read - i2c read. + * @addr: register address. + * @buffer: data buffer. + * @len: the bytes of data to write. + *Return: 0: success, otherwise: failed + */ +s32 gt1x_i2c_read(u16 addr, u8 * buffer, s32 len) +{ + u8 addr_buf[GTP_ADDR_LENGTH] = { (addr >> 8) & 0xFF, addr & 0xFF }; + struct i2c_msg msgs[2] = { + { + .addr = gt1x_i2c_client->addr, + .flags = 0, + .buf = addr_buf, + .len = GTP_ADDR_LENGTH}, + { + .addr = gt1x_i2c_client->addr, + .flags = I2C_M_RD} + }; + return _do_i2c_read(msgs, addr, buffer, len); +} + +/** + * gt1x_irq_enable - enable irq function. + * + */ +void gt1x_irq_enable(void) +{ + unsigned long irqflags = 0; + + spin_lock_irqsave(&irq_lock, irqflags); + if (irq_disabled) { + irq_disabled = 0; + spin_unlock_irqrestore(&irq_lock, irqflags); + enable_irq(gt1x_i2c_client->irq); + } else { + spin_unlock_irqrestore(&irq_lock, irqflags); + } +} + +/** + * gt1x_irq_enable - disable irq function. + * disable irq and wait bottom half + * thread(gt1x_ts_work_thread) + */ +void gt1x_irq_disable(void) +{ + unsigned long irqflags; + + /* because there is an irq enable action in + * the bottom half thread, we need to wait until + * bottom half thread finished. + */ + synchronize_irq(gt1x_i2c_client->irq); + spin_lock_irqsave(&irq_lock, irqflags); + if (!irq_disabled) { + irq_disabled = 1; + spin_unlock_irqrestore(&irq_lock, irqflags); + disable_irq(gt1x_i2c_client->irq); + } else { + spin_unlock_irqrestore(&irq_lock, irqflags); + } +} + +#ifndef CONFIG_OF +int gt1x_power_switch(s32 state) +{ + return 0; +} +#endif + +int gt1x_debug_proc(u8 * buf, int count) +{ + return -1; +} + +#ifdef CONFIG_GTP_CHARGER_SWITCH +u32 gt1x_get_charger_status(void) +{ + /* + * Need to get charger status of + * your platform. + */ + return 0; +} +#endif + +/** + * gt1x_ts_irq_handler - External interrupt service routine + * for interrupt mode. + * @irq: interrupt number. + * @dev_id: private data pointer. + * Return: Handle Result. + * IRQ_WAKE_THREAD: top half work finished, + * wake up bottom half thread to continue the rest work. + */ +static irqreturn_t gt1x_ts_irq_handler(int irq, void *dev_id) +{ + unsigned long irqflags; + + /* irq top half, use nosync irq api to + * disable irq line, if irq is enabled, + * then wake up bottom half thread */ + spin_lock_irqsave(&irq_lock, irqflags); + if (!irq_disabled) { + irq_disabled = 1; + spin_unlock_irqrestore(&irq_lock, irqflags); + disable_irq_nosync(gt1x_i2c_client->irq); + return IRQ_WAKE_THREAD; + } else { + spin_unlock_irqrestore(&irq_lock, irqflags); + return IRQ_HANDLED; + } +} + +/** + * gt1x_touch_down - Report touch point event . + * @id: trackId + * @x: input x coordinate + * @y: input y coordinate + * @w: input pressure + * Return: none. + */ +void gt1x_touch_down(s32 x, s32 y, s32 size, s32 id) +{ +#ifdef CONFIG_GTP_CHANGE_X2Y + GTP_SWAP(x, y); +#endif + + input_report_key(input_dev, BTN_TOUCH, 1); +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL + input_mt_slot(input_dev, id); + input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true); +#else + input_report_abs(input_dev, ABS_MT_TRACKING_ID, id); +#endif + + input_report_abs(input_dev, ABS_MT_POSITION_X, x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(input_dev, ABS_MT_PRESSURE, size); + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, size); + +#ifndef CONFIG_GTP_TYPE_B_PROTOCOL + input_mt_sync(input_dev); +#endif +} + +/** + * gt1x_touch_up - Report touch release event. + * @id: trackId + * Return: none. + */ +void gt1x_touch_up(s32 id) +{ +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL + input_mt_slot(input_dev, id); + input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false); +#else + input_mt_sync(input_dev); +#endif +} + +/** + * gt1x_ts_work_thread - Goodix touchscreen work function. + * @iwork: work struct of gt1x_workqueue. + * Return: none. + */ +static irqreturn_t gt1x_ts_work_thread(int irq, void *data) +{ + u8 point_data[11] = { 0 }; + u8 end_cmd = 0; + u8 finger = 0; + s32 ret = 0; + + if (update_info.status) { + GTP_DEBUG("Ignore interrupts during fw update."); + return IRQ_HANDLED; + } + +#ifdef CONFIG_GTP_GESTURE_WAKEUP + ret = gesture_event_handler(input_dev); + if (ret >= 0) + goto exit_work_func; +#endif + + if (gt1x_halt) { + GTP_DEBUG("Ignore interrupts after suspend"); + return IRQ_HANDLED; + } + + ret = gt1x_i2c_read(GTP_READ_COOR_ADDR, point_data, sizeof(point_data)); + if (ret < 0) { + GTP_ERROR("I2C transfer error!"); +#ifndef CONFIG_GTP_ESD_PROTECT + gt1x_power_reset(); +#endif + goto exit_work_func; + } + + finger = point_data[0]; + if (finger == 0x00) + gt1x_request_event_handler(); + + if ((finger & 0x80) == 0) { +#ifdef CONFIG_HOTKNOT_BLOCK_RW + if (!hotknot_paired_flag) +#endif + { + goto exit_eint; + } + } + +#ifdef CONFIG_HOTKNOT_BLOCK_RW + ret = hotknot_event_handler(point_data); + if (!ret) + goto exit_work_func; +#endif + +#ifdef CONFIG_GTP_PROXIMITY + ret = gt1x_prox_event_handler(point_data); + if (ret > 0) + goto exit_work_func; +#endif + +#ifdef CONFIG_GTP_WITH_STYLUS + ret = gt1x_touch_event_handler(point_data, input_dev, pen_dev); +#else + ret = gt1x_touch_event_handler(point_data, input_dev, NULL); +#endif + +exit_work_func: + if (!gt1x_rawdiff_mode && (ret >= 0 || ret == ERROR_VALUE)) { + ret = gt1x_i2c_write(GTP_READ_COOR_ADDR, &end_cmd, 1); + if (ret < 0) + GTP_ERROR("I2C write end_cmd error!"); + } +exit_eint: + gt1x_irq_enable(); + return IRQ_HANDLED; +} + +/* + * Devices Tree support, +*/ +#ifdef CONFIG_OF +/** + * gt1x_parse_dt - parse platform infomation form devices tree. + */ +static int gt1x_parse_dt(struct device *dev) +{ + struct device_node *np; + //int ret = 0; + + if (!dev) + return -ENODEV; + + np = dev->of_node; + gt1x_int_gpio = of_get_named_gpio(np, "goodix,irq-gpio", 0); + gt1x_rst_gpio = of_get_named_gpio(np, "goodix,reset-gpio", 0); + + if (!gpio_is_valid(gt1x_int_gpio) || !gpio_is_valid(gt1x_rst_gpio)) { + GTP_ERROR("Invalid GPIO, irq-gpio:%d, rst-gpio:%d", + gt1x_int_gpio, gt1x_rst_gpio); + return -EINVAL; + } +/* + vdd_ana = regulator_get(dev, "vdd_ana"); + if (IS_ERR(vdd_ana)) { + GTP_ERROR("regulator get of vdd_ana failed"); + ret = PTR_ERR(vdd_ana); + vdd_ana = NULL; + return ret; + } +*/ + return 0; +} + +/** + * goodix_pinctrl_init - pinctrl init + */ +static int goodix_pinctrl_init(struct i2c_client *client) +{ + int ret = 0; + + gt_pinctrl.ts_pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR_OR_NULL(gt_pinctrl.ts_pinctrl)) { + GTP_ERROR("Failed to get pinctrl"); + ret = PTR_ERR(gt_pinctrl.ts_pinctrl); + gt_pinctrl.ts_pinctrl= NULL; + return ret; + } + + gt_pinctrl.pinctrl_wakeup = pinctrl_lookup_state(gt_pinctrl.ts_pinctrl, "pmx_ts_wakeup"); + if (IS_ERR_OR_NULL(gt_pinctrl.pinctrl_wakeup)) { + GTP_ERROR("Pin state[wakeup] not found"); + ret = PTR_ERR(gt_pinctrl.pinctrl_wakeup); + goto exit_put; + } + + gt_pinctrl.pinctrl_normal = pinctrl_lookup_state(gt_pinctrl.ts_pinctrl, "pmx_ts_normal"); + if (IS_ERR_OR_NULL(gt_pinctrl.pinctrl_normal)) { + GTP_ERROR("Pin state[normal] not found"); + ret = PTR_ERR(gt_pinctrl.pinctrl_normal); + } + + gt_pinctrl.pinctrl_poweroff = pinctrl_lookup_state(gt_pinctrl.ts_pinctrl, "pmx_ts_poweroff"); + if (IS_ERR_OR_NULL(gt_pinctrl.pinctrl_poweroff)) { + GTP_ERROR("Pin state[poweroff] not found"); + ret = PTR_ERR(gt_pinctrl.pinctrl_poweroff); + goto exit_put; + } + + gt_pinctrl.pinctrl_sleep = pinctrl_lookup_state(gt_pinctrl.ts_pinctrl, "pmx_ts_sleep"); + if (IS_ERR_OR_NULL(gt_pinctrl.pinctrl_sleep)) { + GTP_ERROR("Pin state[sleep] not found"); + ret = PTR_ERR(gt_pinctrl.pinctrl_sleep); + goto exit_put; + } + + return 0; +exit_put: + devm_pinctrl_put(gt_pinctrl.ts_pinctrl); + gt_pinctrl.ts_pinctrl = NULL; + gt_pinctrl.pinctrl_wakeup = NULL; + gt_pinctrl.pinctrl_normal = NULL; + gt_pinctrl.pinctrl_poweroff = NULL; + gt_pinctrl.pinctrl_sleep = NULL; + return ret; +} + + +/** + * gt1x_power_switch - power switch . + * @on: 1-switch on, 0-switch off. + * return: 0-succeed, -1-faileds + */ +int gt1x_power_switch(int on) +{ + + int ret = 0; + struct i2c_client *client = gt1x_i2c_client; + + if (!client/* || !vdd_ana*/) + return -1; +/* + if (on) { + GTP_DEBUG("GTP power on."); + ret = regulator_enable(vdd_ana); + } else { + GTP_DEBUG("GTP power off."); + ret = regulator_disable(vdd_ana); + } + + usleep_range(10000, 10000);//usleep(10000); +*/ + return ret; + +} +#endif + +static void gt1x_release_resource(void) +{ + if (gpio_is_valid(GTP_INT_PORT)) { + gpio_direction_input(GTP_INT_PORT); + gpio_free(GTP_INT_PORT); + } + + if (gpio_is_valid(GTP_RST_PORT)) { + gpio_direction_output(GTP_RST_PORT, 0); + gpio_free(GTP_RST_PORT); + } + +#ifdef CONFIG_OF +/* + if (vdd_ana) { + gt1x_power_switch(SWITCH_OFF); + regulator_put(vdd_ana); + vdd_ana = NULL; + } +*/ +#endif + + if (gt_pinctrl.ts_pinctrl) + devm_pinctrl_put(gt_pinctrl.ts_pinctrl); + gt_pinctrl.ts_pinctrl = NULL; + gt_pinctrl.pinctrl_wakeup = NULL; + gt_pinctrl.pinctrl_normal = NULL; + gt_pinctrl.pinctrl_poweroff = NULL; + gt_pinctrl.pinctrl_sleep = NULL; + + if (input_dev) { + input_unregister_device(input_dev); + input_dev = NULL; + } +} + +/** + * gt1x_request_gpio - Request gpio(INT & RST) ports. + */ +static s32 gt1x_request_gpio(void) +{ + s32 ret = 0; + + ret = gpio_request(GTP_INT_PORT, "GTP_INT_IRQ"); + if (ret < 0) { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32) GTP_INT_PORT, ret); + ret = -ENODEV; + } else { + GTP_GPIO_AS_INT(GTP_INT_PORT); + gt1x_i2c_client->irq = gpio_to_irq(GTP_INT_PORT); + } + + ret = gpio_request(GTP_RST_PORT, "GTP_RST_PORT"); + if (ret < 0) { + GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32) GTP_RST_PORT, ret); + ret = -ENODEV; + } + + GTP_GPIO_AS_INPUT(GTP_RST_PORT); + return ret; +} + +/** + * gt1x_request_irq - Request interrupt. + * Return + * 0: succeed, -1: failed. + */ +static s32 gt1x_request_irq(void) +{ + s32 ret = -1; + const u8 irq_table[] = GTP_IRQ_TAB; + + GTP_DEBUG("INT trigger type:%x", gt1x_int_type); + ret = devm_request_threaded_irq(>1x_i2c_client->dev, + gt1x_i2c_client->irq, + gt1x_ts_irq_handler, + gt1x_ts_work_thread, + irq_table[gt1x_int_type], + gt1x_i2c_client->name, + gt1x_i2c_client); + if (ret) { + GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret); + return -1; + } else { + gt1x_irq_disable(); + return 0; + } +} + +/** + * gt1x_request_input_dev - Request input device Function. + * Return + * 0: succeed, -1: failed. + */ +static s8 gt1x_request_input_dev(void) +{ + s8 ret = -1; +#ifdef CONFIG_GTP_HAVE_TOUCH_KEY + u8 index = 0; +#endif + + input_dev = input_allocate_device(); + if (input_dev == NULL) { + GTP_ERROR("Failed to allocate input device."); + return -ENOMEM; + } + + input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0)) + input_mt_init_slots(input_dev, GTP_MAX_TOUCH, INPUT_MT_DIRECT); +#else + input_mt_init_slots(input_dev, GTP_MAX_TOUCH); +#endif +#endif + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + +#ifdef CONFIG_GTP_HAVE_TOUCH_KEY + for (index = 0; index < GTP_MAX_KEY_NUM; index++) + input_set_capability(input_dev, EV_KEY, gt1x_touch_key_array[index]); +#endif + +#ifdef CONFIG_GTP_GESTURE_WAKEUP + input_set_capability(input_dev, EV_KEY, KEY_GES_REGULAR); + input_set_capability(input_dev, EV_KEY, KEY_GES_CUSTOM); +#endif + +#ifdef CONFIG_GTP_CHANGE_X2Y + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, gt1x_abs_y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, gt1x_abs_x_max, 0, 0); +#else + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, gt1x_abs_x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, gt1x_abs_y_max, 0, 0); +#endif + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + input_dev->name = "goodix-ts"; + input_dev->phys = "input/ts"; + input_dev->id.bustype = BUS_I2C; + input_dev->id.vendor = 0xDEAD; + input_dev->id.product = 0xBEEF; + input_dev->id.version = 10427; + + ret = input_register_device(input_dev); + if (ret) { + GTP_ERROR("Register %s input device failed", input_dev->name); + return -ENODEV; + } + + return 0; +} + +/** + * gt1x_ts_probe - I2c probe. + * @client: i2c device struct. + * @id: device id. + * Return 0: succeed, <0: failed. + */ +static int gt1x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = -1; + + /* do NOT remove these logs */ + GTP_INFO("GTP Driver Version: %s,slave addr:%02xh", + GTP_DRIVER_VERSION, client->addr); + + gt1x_i2c_client = client; + spin_lock_init(&irq_lock); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + GTP_ERROR("I2C check functionality failed."); + return -ENODEV; + } + +#ifdef CONFIG_OF /* device tree support */ + if (client->dev.of_node) { + ret = gt1x_parse_dt(&client->dev); + if (ret < 0) + return -EINVAL; + } +#else +#error [GOODIX]only support devicetree platform +#endif + + /* init pinctrl states */ + ret = goodix_pinctrl_init(client); + if (ret < 0) { + GTP_ERROR("Init pinctrl states failed."); + goto exit_clean; + } + + /* Set pin state as poweroff */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_poweroff) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_poweroff); + if (ret < 0) { + GTP_ERROR("Set pin state as poweroff error: %d", ret); + goto exit_clean; + } + + /* gpio resource */ + ret = gt1x_request_gpio(); + if (ret < 0) { + GTP_ERROR("GTP request IO port failed."); + goto exit_clean; + } + + /* power on */ + ret = gt1x_power_switch(SWITCH_ON); + if (ret < 0) { + GTP_ERROR("Power on failed"); + goto exit_clean; + } + + /* reset ic & do i2c test */ + ret = gt1x_reset_guitar(); + if (ret != 0) { + ret = gt1x_power_switch(SWITCH_OFF); + if (ret < 0) + goto exit_clean; + ret = gt1x_power_switch(SWITCH_ON); + if (ret < 0) + goto exit_clean; + ret = gt1x_reset_guitar(); /* retry */ + if (ret != 0) { + //add by liangdi for Compatible with TP917S 20201020 + GTP_ERROR("Gt init failed,change I2C addr"); + gt1x_i2c_client->addr = 0x5d; + ret = gt1x_power_switch(SWITCH_OFF); + if (ret < 0) + goto exit_clean; + ret = gt1x_power_switch(SWITCH_ON); + if (ret < 0) + goto exit_clean; + ret = gt1x_reset_guitar(); /* retry */ + if (ret != 0) + { + GTP_ERROR("Reset guitar failed!"); + goto exit_clean; + } + //add end + } + } + + /* check firmware, initialize and send + * chip configuration data, initialize nodes */ + gt1x_init(); + + ret = gt1x_request_input_dev(); + if (ret < 0) + goto err_input; + + ret = gt1x_request_irq(); + if (ret < 0) + goto err_irq; + +#ifdef CONFIG_GTP_ESD_PROTECT + /* must before auto update */ + gt1x_init_esd_protect(); + gt1x_esd_switch(SWITCH_ON); +#endif + +#ifdef CONFIG_GTP_AUTO_UPDATE + do { + struct task_struct *thread = NULL; + thread = kthread_run(gt1x_auto_update_proc, + (void *)NULL, + "gt1x_auto_update"); + if (IS_ERR(thread)) + GTP_ERROR("Failed to create auto-update thread: %d.", ret); + } while (0); +#endif + + gt1x_register_powermanger(); + gt1x_irq_enable(); + return 0; + +err_irq: +err_input: + gt1x_deinit(); +exit_clean: + gt1x_release_resource(); + GTP_ERROR("GTP probe failed:%d", ret); + return -ENODEV; +} + +/** + * gt1x_ts_remove - Goodix touchscreen driver release function. + * @client: i2c device struct. + * Return 0: succeed, -1: failed. + */ +static int gt1x_ts_remove(struct i2c_client *client) +{ + GTP_INFO("GTP driver removing..."); + gt1x_unregister_powermanger(); + + gt1x_deinit(); + gt1x_release_resource(); + + return 0; +} + +#if defined(CONFIG_FB) +/* frame buffer notifier block control the suspend/resume procedure */ +static struct notifier_block gt1x_fb_notifier; + +static int gtp_fb_notifier_callback(struct notifier_block *noti, unsigned long event, void *data) +{ + struct fb_event *ev_data = data; + int *blank; + +#ifdef CONFIG_GTP_INCELL_PANEL +#ifndef FB_EARLY_EVENT_BLANK + #error Need add FB_EARLY_EVENT_BLANK to fbmem.c +#endif + + if (ev_data && ev_data->data && event == FB_EARLY_EVENT_BLANK) { + blank = ev_data->data; + if (*blank == FB_BLANK_UNBLANK) { + GTP_DEBUG("Resume by fb notifier."); + gt1x_resume(); + } + } +#else + if (ev_data && ev_data->data && event == FB_EVENT_BLANK) { + blank = ev_data->data; + if (*blank == FB_BLANK_UNBLANK) { + GTP_DEBUG("Resume by fb notifier."); + gt1x_resume(); + } + } +#endif + + if (ev_data && ev_data->data && event == FB_EVENT_BLANK) { + blank = ev_data->data; + if (*blank == FB_BLANK_POWERDOWN) { + GTP_DEBUG("Suspend by fb notifier."); + gt1x_suspend(); + } + } + + return 0; +} +#elif defined(CONFIG_PM) +/** + * gt1x_ts_suspend - i2c suspend callback function. + * @dev: i2c device. + * Return 0: succeed, -1: failed. + */ +static int gt1x_pm_suspend(struct device *dev) +{ + return gt1x_suspend(); +} + +/** + * gt1x_ts_resume - i2c resume callback function. + * @dev: i2c device. + * Return 0: succeed, -1: failed. + */ +static int gt1x_pm_resume(struct device *dev) +{ + return gt1x_resume(); +} + +/* bus control the suspend/resume procedure */ +static const struct dev_pm_ops gt1x_ts_pm_ops = { + .suspend = gt1x_pm_suspend, + .resume = gt1x_pm_resume, +}; + +#elif defined(CONFIG_HAS_EARLYSUSPEND) +/* earlysuspend module the suspend/resume procedure */ +static void gt1x_ts_early_suspend(struct early_suspend *h) +{ + gt1x_suspend(); +} + +static void gt1x_ts_late_resume(struct early_suspend *h) +{ + gt1x_resume(); +} + +static struct early_suspend gt1x_early_suspend = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1, + .suspend = gt1x_ts_early_suspend, + .resume = gt1x_ts_late_resume, +}; +#endif + + +static int gt1x_register_powermanger(void) +{ +#if defined(CONFIG_FB) + gt1x_fb_notifier.notifier_call = gtp_fb_notifier_callback; + fb_register_client(>1x_fb_notifier); + +#elif defined(CONFIG_HAS_EARLYSUSPEND) + register_early_suspend(>1x_early_suspend); +#endif + return 0; +} + +static int gt1x_unregister_powermanger(void) +{ +#if defined(CONFIG_FB) + fb_unregister_client(>1x_fb_notifier); + +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(>1x_early_suspend); +#endif + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id gt1x_match_table[] = { + {.compatible = "goodix,gt1x",}, + { }, +}; +#endif + +static const struct i2c_device_id gt1x_ts_id[] = { + {GTP_I2C_NAME, 0}, + {} +}; + +static struct i2c_driver gt1x_ts_driver = { + .probe = gt1x_ts_probe, + .remove = gt1x_ts_remove, + .id_table = gt1x_ts_id, + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = gt1x_match_table, +#endif +#if !defined(CONFIG_FB) && defined(CONFIG_PM) + .pm = >1x_ts_pm_ops, +#endif + }, +}; + +/** + * gt1x_ts_init - Driver Install function. + * Return 0---succeed. + */ +static int __init gt1x_ts_init(void) +{ + GTP_INFO("GTP driver installing..."); + return i2c_add_driver(>1x_ts_driver); +} + +/** + * gt1x_ts_exit - Driver uninstall function. + * Return 0---succeed. + */ +static void __exit gt1x_ts_exit(void) +{ + GTP_DEBUG_FUNC(); + GTP_INFO("GTP driver exited."); + i2c_del_driver(>1x_ts_driver); +} + +module_init(gt1x_ts_init); +module_exit(gt1x_ts_exit); + +MODULE_DESCRIPTION("GTP Series Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/gt1x/gt1x_extents.c b/drivers/input/touchscreen/gt1x/gt1x_extents.c new file mode 100755 index 00000000000..173b4880e76 --- /dev/null +++ b/drivers/input/touchscreen/gt1x/gt1x_extents.c @@ -0,0 +1,1004 @@ +/* drivers/input/touchscreen/gt1x_extents.c + * + * 2010 - 2017 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.6 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /*proc */ + +#include +#include "gt1x_generic.h" + +#ifdef CONFIG_GTP_GESTURE_WAKEUP + +#define GESTURE_NODE "goodix_gesture" +#define GESTURE_MAX_POINT_COUNT 64 + +#pragma pack(1) +typedef struct { + u8 ic_msg[6]; /*from the first byte */ + u8 gestures[4]; + u8 data[3 + GESTURE_MAX_POINT_COUNT * 4 + 80]; /*80 bytes for extra data */ +} st_gesture_data; +#pragma pack() + +#define SETBIT(longlong, bit) (longlong[bit/8] |= (1 << bit%8)) +#define CLEARBIT(longlong, bit) (longlong[bit/8] &=(~(1 << bit%8))) +#define QUERYBIT(longlong, bit) (!!(longlong[bit/8] & (1 << bit%8))) + +#define CHKBITS_32 32 +#define CHKBITS_16 16 +#define CHKBITS_8 8 + +int gesture_enabled = 0; /* module switch */ +DOZE_T gesture_doze_status = DOZE_DISABLED; /* doze status */ + +static u8 gestures_flag[32]; /* gesture flag, every bit stands for a gesture */ +static st_gesture_data gesture_data; /* gesture data buffer */ +static struct mutex gesture_data_mutex; /* lock for gesture data */ + +static ssize_t gt1x_gesture_data_read(struct file *file, char __user * page, size_t size, loff_t * ppos) +{ + s32 ret = -1; + GTP_DEBUG("visit gt1x_gesture_data_read. ppos:%d", (int)*ppos); + if (*ppos) { + return 0; + } + if (size == 4) { + ret = copy_to_user(((u8 __user *) page), "GT1X", 4); + return 4; + } + ret = simple_read_from_buffer(page, size, ppos, &gesture_data, sizeof(gesture_data)); + + GTP_DEBUG("Got the gesture data."); + return ret; +} + +static ssize_t gt1x_gesture_data_write(struct file *filp, const char __user * buff, size_t len, loff_t * off) +{ + s32 ret = 0; + + GTP_DEBUG_FUNC(); + + ret = copy_from_user(&gesture_enabled, buff, 1); + if (ret) { + GTP_ERROR("copy_from_user failed."); + return -EPERM; + } + + GTP_DEBUG("gesture enabled:%x, ret:%d", gesture_enabled, ret); + + return len; +} + +/** + * calc_checksum - Calc checksum. + * @buf: data to be calc + * @len: length of buf. + * @bits: checkbits + * Return true-pass, false:not pass. + */ +static bool calc_checksum(u8 *buf, int len, int bits) +{ + int i; + + if (bits == CHKBITS_16) { + u16 chksum, *b = (u16 *)buf; + + if (len % 2) { + return false; + } + + len /= 2; + for (i = 0, chksum = 0; i < len; i++) { + if (i == len - 1) + chksum += le16_to_cpu(b[i]); + else + chksum += be16_to_cpu(b[i]); + } + return chksum == 0 ? true : false; + } else if (bits == CHKBITS_8) { + u8 chksum; + + for (i = 0, chksum =0; i < len; i++) { + chksum += buf[i]; + } + return chksum == 0 ? true : false; + } + + return false; +} + +int gesture_enter_doze(void) +{ + int retry = 0; + + GTP_DEBUG_FUNC(); + GTP_DEBUG("Entering doze mode..."); + while (retry++ < 5) { + if (!gt1x_send_cmd(0x08, 0)) { + gesture_doze_status = DOZE_ENABLED; + GTP_DEBUG("Working in doze mode!"); + return 0; + } + msleep(10); + } + GTP_ERROR("Send doze cmd failed."); + return -1; +} + +s32 gesture_event_handler(struct input_dev * dev) +{ + u8 doze_buf[4] = { 0 }, ges_type; + static int err_flag1 = 0, err_flag2 = 0; + int len, extra_len, need_chk; + unsigned int key_code; + s32 ret = 0; + + if (DOZE_ENABLED != gesture_doze_status) { + return -1; + } + + /** package: -head 4B + track points + extra info- + * - head - + * doze_buf[0]: gesture type, + * doze_buf[1]: number of gesture points , + * doze_buf[2]: protocol type, + * doze_buf[3]: gesture extra data length. + */ + ret = gt1x_i2c_read(GTP_REG_WAKEUP_GESTURE, doze_buf, 4); + if (ret < 0) { + return 0; + } + + ges_type = doze_buf[0]; + len = doze_buf[1]; + need_chk = doze_buf[2] & 0x80; + extra_len = doze_buf[3]; + + GTP_DEBUG("0x%x = 0x%02X,0x%02X,0x%02X,0x%02X", GTP_REG_WAKEUP_GESTURE, + doze_buf[0], doze_buf[1], doze_buf[2], doze_buf[3]); + + if (len > GESTURE_MAX_POINT_COUNT) { + GTP_ERROR("Gesture contain too many points!(%d)", len); + len = GESTURE_MAX_POINT_COUNT; + } + + if (extra_len > 32) { + GTP_ERROR("Gesture contain too many extra data!(%d)", extra_len); + extra_len = 32; + } + + /* get gesture extra info */ + if (extra_len >= 0) { + u8 ges_data[extra_len + 1]; + + /* head 4 + extra data * 4 + chksum 1 */ + ret = gt1x_i2c_read(GTP_REG_WAKEUP_GESTURE + 4, + ges_data, extra_len + 1); + if (ret < 0) { + GTP_ERROR("Read extra gesture data failed."); + return 0; + } + + if (likely(need_chk)) { /* calc checksum */ + bool val; + + ges_data[extra_len] += doze_buf[0] + doze_buf[1] + + doze_buf[2] + doze_buf[3]; + + val = calc_checksum(ges_data, extra_len + 1, CHKBITS_8); + if (unlikely(!val)) { /* check failed */ + GTP_ERROR("Gesture checksum error."); + if (err_flag1) { + err_flag1 = 0; + ret = 0; + goto clear_reg; + } else { + /* just return 0 without clear reg, + this will receive another int, we + check the data in the next frame */ + err_flag1 = 1; + return 0; + } + } + + err_flag1 = 0; + } + + mutex_lock(&gesture_data_mutex); + memcpy(&gesture_data.data[4 + len * 4], ges_data, extra_len); + mutex_unlock(&gesture_data_mutex); + } + + /* check gesture type (if available?) */ + if (ges_type == 0 || !QUERYBIT(gestures_flag, ges_type)) { + GTP_INFO("Gesture[0x%02X] has been disabled.", doze_buf[0]); + doze_buf[0] = 0x00; + gt1x_i2c_write(GTP_REG_WAKEUP_GESTURE, doze_buf, 1); + gesture_enter_doze(); + return 0; + } + + /* get gesture point data */ + if (len > 0) { /* coor num * 4 + chksum 2*/ + u8 ges_data[len * 4 + 2]; + + ret = gt1x_i2c_read(GES_BUFFER_ADDR, ges_data, len * 4); + if (ret < 0) { + GTP_ERROR("Read gesture data failed."); + return 0; + } + + /* checksum reg for gesture point data */ + ret = gt1x_i2c_read(0x819F, &ges_data[len * 4], 2); + if (ret < 0) { + GTP_ERROR("Read gesture data failed."); + return 0; + } + + if (likely(need_chk)) { + bool val = calc_checksum(ges_data, + len * 4 + 2, CHKBITS_16); + if (unlikely(!val)) { /* check failed */ + GTP_ERROR("Gesture checksum error."); + if (err_flag2) { + err_flag2 = 0; + ret = 0; + goto clear_reg; + } else { + err_flag2 = 1; + return 0; + } + } + + err_flag2 = 0; + } + + mutex_lock(&gesture_data_mutex); + memcpy(&gesture_data.data[4], ges_data, len * 4); + mutex_unlock(&gesture_data_mutex); + } + + mutex_lock(&gesture_data_mutex); + gesture_data.data[0] = ges_type; // gesture type + gesture_data.data[1] = len; // gesture points number + gesture_data.data[2] = doze_buf[2] & 0x7F; // protocol type + gesture_data.data[3] = extra_len; // gesture date length + mutex_unlock(&gesture_data_mutex); + + /* get key code */ + key_code = ges_type < 16? KEY_GES_CUSTOM : KEY_GES_REGULAR; + GTP_DEBUG("Gesture: 0x%02X, points: %d", doze_buf[0], doze_buf[1]); + + input_report_key(dev, key_code, 1); + input_sync(dev); + input_report_key(dev, key_code, 0); + input_sync(dev); + +clear_reg: + doze_buf[0] = 0; // clear ges flag + gt1x_i2c_write(GTP_REG_WAKEUP_GESTURE, doze_buf, 1); + return ret; +} + +void gesture_clear_wakeup_data(void) +{ + mutex_lock(&gesture_data_mutex); + memset(gesture_data.data, 0, 4); + mutex_unlock(&gesture_data_mutex); +} + +void gt1x_gesture_debug(int on) +{ + if (on) { + gesture_enabled = 1; + memset(gestures_flag, 0xFF, sizeof(gestures_flag)); + } else { + gesture_enabled = 0; + memset(gestures_flag, 0x00, sizeof(gestures_flag)); + gesture_doze_status = DOZE_DISABLED; + } + GTP_DEBUG("Gesture debug %s", on ? "on":"off"); +} + +#endif // GTP_GESTURE_WAKEUP + +//HotKnot module +#ifdef CONFIG_GTP_HOTKNOT +#include +#define HOTKNOT_NODE "hotknot" +#define HOTKNOT_VERSION "GOODIX,GT1X" +#define HN_AUTH_HEADER 14 +#define GT1X_HN_JUMP_FW "gt1x_hotknot_jump_fw.bin" +#define GT1X_HN_AUTH_FW "gt1x_hotknot_auth_fw.bin" +#define GT2X_HN_AUTH_FW "gt2x_hotknot_auth_fw.bin" + +u8 hotknot_enabled = 0; +u8 hotknot_transfer_mode = 0; + +static int hotknot_open(struct inode *node, struct file *flip) +{ + GTP_DEBUG("Hotknot is enabled."); + hotknot_enabled = 1; + return 0; +} + +static int hotknot_release(struct inode *node, struct file *filp) +{ + GTP_DEBUG("Hotknot is disabled."); + hotknot_enabled = 0; + return 0; +} + +static s32 hotknot_enter_transfer_mode(void) +{ + int ret = 0; + u8 buffer[5] = { 0 }; + + hotknot_transfer_mode = 1; +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + + gt1x_irq_disable(); + gt1x_send_cmd(GTP_CMD_HN_TRANSFER, 0); + msleep(100); + gt1x_irq_enable(); + + ret = gt1x_i2c_read(0x8140, buffer, sizeof(buffer)); + if (ret) { + hotknot_transfer_mode = 0; + return ret; + } + + buffer[4] = 0; + GTP_DEBUG("enter transfer mode: %s ", buffer); + if (strcmp(buffer, "GHot")) { + hotknot_transfer_mode = 0; + return ERROR_HN_VER; + } + + return 0; +} + +static s32 hotknot_load_hotknot_subsystem(void) +{ + return hotknot_enter_transfer_mode(); +} + +static int gt1x_load_auth_subsystem(void) +{ + const struct firmware *jump_fw, *auth_fw; + int ret; + + GTP_INFO("Request %s", GT1X_HN_JUMP_FW); + ret = request_firmware(&jump_fw, GT1X_HN_JUMP_FW, + >1x_i2c_client->dev); + if (ret < 0) { + GTP_ERROR("Failed to get %s", GT1X_HN_JUMP_FW); + return ret; + } else if (jump_fw->size != SZ_4K) { + ret = -EINVAL; + GTP_ERROR("Firmware size not match"); + goto out1; + } + + GTP_INFO("Request %s", GT1X_HN_AUTH_FW); + ret = request_firmware(&auth_fw, GT1X_HN_AUTH_FW, + >1x_i2c_client->dev); + if (ret < 0) { + GTP_ERROR("Failed to get %s", GT1X_HN_AUTH_FW); + goto out1; + } else if (auth_fw->size != SZ_4K + HN_AUTH_HEADER) { + ret = -EINVAL; + GTP_ERROR("Firmware size not match"); + goto out0; + } + + GTP_INFO("hotknot load jump code."); + ret = gt1x_load_patch((u8 *)jump_fw->data, SZ_4K, 0, SZ_8K); + if (ret < 0) { + GTP_ERROR("Load jump code fail!"); + goto out0; + } + + GTP_INFO("hotknot load auth code."); + ret = gt1x_load_patch((u8 *)&auth_fw->data[HN_AUTH_HEADER], + SZ_4K, 4096, SZ_8K); + if (ret < 0) { + GTP_ERROR("Load auth system fail!"); + goto out0; + } + +out0: + release_firmware(auth_fw); +out1: + release_firmware(jump_fw); + return ret; +} + +static int gt2x_load_auth_subsystem(void) +{ + const struct firmware *auth_fw; + int ret; + + GTP_INFO("Request %s", GT2X_HN_AUTH_FW); + ret = request_firmware(&auth_fw, GT2X_HN_AUTH_FW, + >1x_i2c_client->dev); + if (ret < 0) { + GTP_ERROR("Failed to get %s", GT2X_HN_AUTH_FW); + return ret; + } else if (auth_fw->size != SZ_4K + HN_AUTH_HEADER) { + ret = -EINVAL; + GTP_ERROR("Firmware size not match"); + goto out0; + } + + GTP_INFO("hotknot load auth code."); + ret = gt1x_load_patch((u8 *)&auth_fw->data[HN_AUTH_HEADER], + SZ_4K, 0, SZ_1K * 6); + if (ret < 0) + GTP_ERROR("Load auth system fail!"); + +out0: + release_firmware(auth_fw); + return ret; +} + +static s32 hotknot_load_authentication_subsystem(void) +{ + s32 ret = 0; + u8 buffer[5] = { 0 }; + + ret = gt1x_hold_ss51_dsp_no_reset(); + if (ret < 0) { + GTP_ERROR("Hold ss51 fail!"); + return ERROR; + } + + if (gt1x_chip_type == CHIP_TYPE_GT1X) + ret = gt1x_load_auth_subsystem(); + else /* GT2X */ + ret = gt2x_load_auth_subsystem(); + + if (ret < 0) + return ret; + + ret = gt1x_startup_patch(); + if (ret < 0) { + GTP_ERROR("Startup auth system fail!"); + return ret; + } + + ret = gt1x_i2c_read(GTP_REG_VERSION, buffer, 4); + if (ret < 0) { + GTP_ERROR("i2c read error!"); + return ERROR_IIC; + } + buffer[4] = 0; + GTP_INFO("Current System version: %s", buffer); + return 0; +} + +static s32 hotknot_recovery_main_system(void) +{ + gt1x_irq_disable(); + gt1x_reset_guitar(); + gt1x_irq_enable(); +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + hotknot_transfer_mode = 0; + return 0; +} + +#ifdef CONFIG_HOTKNOT_BLOCK_RW +DECLARE_WAIT_QUEUE_HEAD(bp_waiter); +static u8 got_hotknot_state = 0; +static u8 got_hotknot_extra_state = 0; +static u8 wait_hotknot_state = 0; +static u8 force_wake_flag = 0; +static u8 block_enable = 0; +s32 hotknot_paired_flag = 0; + +static s32 hotknot_block_rw(u8 rqst_hotknot_state, s32 wait_hotknot_timeout) +{ + s32 ret = 0; + + wait_hotknot_state |= rqst_hotknot_state; + GTP_DEBUG("Goodix tool received wait polling state:0x%x,timeout:%d, all wait state:0x%x", rqst_hotknot_state, wait_hotknot_timeout, wait_hotknot_state); + got_hotknot_state &= (~rqst_hotknot_state); + + set_current_state(TASK_INTERRUPTIBLE); + if (wait_hotknot_timeout <= 0) { + wait_event_interruptible(bp_waiter, force_wake_flag || rqst_hotknot_state == (got_hotknot_state & rqst_hotknot_state)); + } else { + wait_event_interruptible_timeout(bp_waiter, force_wake_flag || rqst_hotknot_state == (got_hotknot_state & rqst_hotknot_state), wait_hotknot_timeout); + } + + wait_hotknot_state &= (~rqst_hotknot_state); + + if (rqst_hotknot_state != (got_hotknot_state & rqst_hotknot_state)) { + GTP_ERROR("Wait 0x%x block polling waiter failed.", rqst_hotknot_state); + ret = -1; + } + if(force_wake_flag) { + got_hotknot_extra_state = 0x07; // force wakeup report as departed + } + force_wake_flag = 0; + return ret; +} + +void hotknot_wakeup_block(void) +{ + GTP_DEBUG("Manual wakeup all block polling waiter!"); + got_hotknot_state = 0; + wait_hotknot_state = 0; + force_wake_flag = 1; + wake_up_interruptible(&bp_waiter); +} + +s32 hotknot_event_handler(u8 * data) +{ + u8 hn_pxy_state = 0; + u8 hn_pxy_state_bak = 0; + static u8 hn_paired_cnt = 0; + u8 hn_state_buf[10] = { 0 }; + u8 finger = data[0]; + u8 id = 0; + + if (block_enable && !hotknot_paired_flag && (finger & 0x0F)) { + id = data[1]; + hn_pxy_state = data[2] & 0x80; + hn_pxy_state_bak = data[3] & 0x80; + if ((32 == id) && (0x80 == hn_pxy_state) && (0x80 == hn_pxy_state_bak)) { +#ifdef HN_DBLCFM_PAIRED + if (hn_paired_cnt++ < 2) { + return 0; + } +#endif + GTP_DEBUG("HotKnot paired!"); + if (wait_hotknot_state & HN_DEVICE_PAIRED) { + GTP_DEBUG("INT wakeup HN_DEVICE_PAIRED block polling waiter"); + got_hotknot_state |= HN_DEVICE_PAIRED; + wake_up_interruptible(&bp_waiter); + } + block_enable = 0; + hotknot_paired_flag = 1; + return 0; + } else { + got_hotknot_state &= (~HN_DEVICE_PAIRED); + hn_paired_cnt = 0; + } + } + + if (hotknot_paired_flag) { + s32 ret = -1; + ret = gt1x_i2c_read(GTP_REG_HN_STATE, hn_state_buf, 6); + if (ret < 0) { + GTP_ERROR("I2C transfer error. errno:%d\n ", ret); + return 0; + } + + got_hotknot_state = 0; + + GTP_DEBUG("wait_hotknot_state:%x", wait_hotknot_state); + GTP_DEBUG("[0x8800~0x8803]=0x%x,0x%x,0x%x,0x%x", hn_state_buf[0], hn_state_buf[1], hn_state_buf[2], hn_state_buf[3]); + + if (wait_hotknot_state & HN_MASTER_SEND) { + if ((0x03 == hn_state_buf[0]) || (0x04 == hn_state_buf[0]) + || (0x07 == hn_state_buf[0])) { + GTP_DEBUG("Wakeup HN_MASTER_SEND block polling waiter"); + got_hotknot_state |= HN_MASTER_SEND; + got_hotknot_extra_state = hn_state_buf[0]; + wake_up_interruptible(&bp_waiter); + } + } else if (wait_hotknot_state & HN_SLAVE_RECEIVED) { + if ((0x03 == hn_state_buf[1]) || (0x04 == hn_state_buf[1]) + || (0x07 == hn_state_buf[1])) { + GTP_DEBUG("Wakeup HN_SLAVE_RECEIVED block polling waiter:0x%x", hn_state_buf[1]); + got_hotknot_state |= HN_SLAVE_RECEIVED; + got_hotknot_extra_state = hn_state_buf[1]; + wake_up_interruptible(&bp_waiter); + } + } else if (wait_hotknot_state & HN_MASTER_DEPARTED) { + if (0x07 == hn_state_buf[0]) { + GTP_DEBUG("Wakeup HN_MASTER_DEPARTED block polling waiter"); + got_hotknot_state |= HN_MASTER_DEPARTED; + wake_up_interruptible(&bp_waiter); + } + } else if (wait_hotknot_state & HN_SLAVE_DEPARTED) { + if (0x07 == hn_state_buf[1]) { + GTP_DEBUG("Wakeup HN_SLAVE_DEPARTED block polling waiter"); + got_hotknot_state |= HN_SLAVE_DEPARTED; + wake_up_interruptible(&bp_waiter); + } + } + return 0; + } + + return -1; +} +#endif //HOTKNOT_BLOCK_RW +#endif //GTP_HOTKNOT + +#define GOODIX_MAGIC_NUMBER 'G' +#define NEGLECT_SIZE_MASK (~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) + +#define GESTURE_ENABLE _IO(GOODIX_MAGIC_NUMBER, 1) // 1 +#define GESTURE_DISABLE _IO(GOODIX_MAGIC_NUMBER, 2) +#define GESTURE_FLAG_SET _IO(GOODIX_MAGIC_NUMBER, 3) +#define GESTURE_FLAG_CLEAR _IO(GOODIX_MAGIC_NUMBER, 4) +//#define SET_ENABLED_GESTURE (_IOW(GOODIX_MAGIC_NUMBER, 5, u8) & NEGLECT_SIZE_MASK) +#define GESTURE_DATA_OBTAIN (_IOR(GOODIX_MAGIC_NUMBER, 6, u8) & NEGLECT_SIZE_MASK) +#define GESTURE_DATA_ERASE _IO(GOODIX_MAGIC_NUMBER, 7) + +//#define HOTKNOT_LOAD_SUBSYSTEM (_IOW(GOODIX_MAGIC_NUMBER, 6, u8) & NEGLECT_SIZE_MASK) +#define HOTKNOT_LOAD_HOTKNOT _IO(GOODIX_MAGIC_NUMBER, 20) +#define HOTKNOT_LOAD_AUTHENTICATION _IO(GOODIX_MAGIC_NUMBER, 21) +#define HOTKNOT_RECOVERY_MAIN _IO(GOODIX_MAGIC_NUMBER, 22) +//#define HOTKNOT_BLOCK_RW (_IOW(GOODIX_MAGIC_NUMBER, 6, u8) & NEGLECT_SIZE_MASK) +#define HOTKNOT_DEVICES_PAIRED _IO(GOODIX_MAGIC_NUMBER, 23) +#define HOTKNOT_MASTER_SEND _IO(GOODIX_MAGIC_NUMBER, 24) +#define HOTKNOT_SLAVE_RECEIVE _IO(GOODIX_MAGIC_NUMBER, 25) +//#define HOTKNOT_DEVICES_COMMUNICATION +#define HOTKNOT_MASTER_DEPARTED _IO(GOODIX_MAGIC_NUMBER, 26) +#define HOTKNOT_SLAVE_DEPARTED _IO(GOODIX_MAGIC_NUMBER, 27) +#define HOTKNOT_VENDOR_VERSION (_IOR(GOODIX_MAGIC_NUMBER, 28, u8) & NEGLECT_SIZE_MASK) +#define HOTKNOT_WAKEUP_BLOCK _IO(GOODIX_MAGIC_NUMBER, 29) + +#define IO_IIC_READ (_IOR(GOODIX_MAGIC_NUMBER, 100, u8) & NEGLECT_SIZE_MASK) +#define IO_IIC_WRITE (_IOW(GOODIX_MAGIC_NUMBER, 101, u8) & NEGLECT_SIZE_MASK) +#define IO_RESET_GUITAR _IO(GOODIX_MAGIC_NUMBER, 102) +#define IO_DISABLE_IRQ _IO(GOODIX_MAGIC_NUMBER, 103) +#define IO_ENABLE_IRQ _IO(GOODIX_MAGIC_NUMBER, 104) +#define IO_GET_VERISON (_IOR(GOODIX_MAGIC_NUMBER, 110, u8) & NEGLECT_SIZE_MASK) +#define IO_PRINT (_IOW(GOODIX_MAGIC_NUMBER, 111, u8) & NEGLECT_SIZE_MASK) +#define IO_VERSION "V1.3-20150420" + +#define CMD_HEAD_LENGTH 20 +static s32 io_iic_read(u8 * data, void __user * arg) +{ + s32 err = ERROR; + s32 data_length = 0; + u16 addr = 0; + + err = copy_from_user(data, arg, CMD_HEAD_LENGTH); + if (err) { + GTP_ERROR("Can't access the memory."); + return ERROR_MEM; + } + + addr = data[0] << 8 | data[1]; + data_length = data[2] << 8 | data[3]; + + err = gt1x_i2c_read(addr, &data[CMD_HEAD_LENGTH], data_length); + if (!err) { + err = copy_to_user(&((u8 __user *) arg)[CMD_HEAD_LENGTH], &data[CMD_HEAD_LENGTH], data_length); + if (err) { + GTP_ERROR("ERROR when copy to user.[addr: %04x], [read length:%d]", addr, data_length); + return ERROR_MEM; + } + err = CMD_HEAD_LENGTH + data_length; + } + //GTP_DEBUG("IIC_READ.addr:0x%4x, length:%d, ret:%d", addr, data_length, err); + //GTP_DEBUG_ARRAY((&data[CMD_HEAD_LENGTH]), data_length); + + return err; +} + +static s32 io_iic_write(u8 * data) +{ + s32 err = ERROR; + s32 data_length = 0; + u16 addr = 0; + + addr = data[0] << 8 | data[1]; + data_length = data[2] << 8 | data[3]; + + err = gt1x_i2c_write(addr, &data[CMD_HEAD_LENGTH], data_length); + if (!err) { + err = CMD_HEAD_LENGTH + data_length; + } + + //GTP_DEBUG("IIC_WRITE.addr:0x%4x, length:%d, ret:%d", addr, data_length, err); + //GTP_DEBUG_ARRAY((&data[CMD_HEAD_LENGTH]), data_length); + return err; +} + +//@return, 0:operate successfully +// > 0: the length of memory size ioctl has accessed, +// error otherwise. +static long gt1x_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + u32 value = 0; + s32 ret = 0; //the initial value must be 0 + u8 *data = NULL; + int cnt = 30; + + /* Blocking when firmwaer updating */ + while (cnt-- && update_info.status) { + ssleep(1); + } + + //GTP_DEBUG("IOCTL CMD:%x", cmd); + /* GTP_DEBUG("command:%d, length:%d, rw:%s", + _IOC_NR(cmd), + _IOC_SIZE(cmd), + (_IOC_DIR(cmd) & _IOC_READ) ? "read" : (_IOC_DIR(cmd) & _IOC_WRITE) ? "write" : "-"); + */ + + if (_IOC_DIR(cmd)) { + s32 err = -1; + s32 data_length = _IOC_SIZE(cmd); + data = (u8 *) kzalloc(data_length, GFP_KERNEL); + memset(data, 0, data_length); + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + err = copy_from_user(data, (void __user *)arg, data_length); + if (err) { + GTP_ERROR("Can't access the memory."); + kfree(data); + return -1; + } + } + } else { + value = (u32) arg; + } + + switch (cmd & NEGLECT_SIZE_MASK) { + case IO_GET_VERISON: + if ((u8 __user *) arg) { + ret = copy_to_user(((u8 __user *) arg), IO_VERSION, sizeof(IO_VERSION)); + if (!ret) { + ret = sizeof(IO_VERSION); + } + GTP_INFO("%s", IO_VERSION); + } + break; + case IO_IIC_READ: + ret = io_iic_read(data, (void __user *)arg); + break; + + case IO_IIC_WRITE: + ret = io_iic_write(data); + break; + + case IO_RESET_GUITAR: + gt1x_irq_disable(); + gt1x_reset_guitar(); + gt1x_irq_enable(); + break; + + case IO_DISABLE_IRQ: + gt1x_irq_disable(); +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + break; + + case IO_ENABLE_IRQ: + gt1x_irq_enable(); +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + break; + + //print a string to syc log messages between application and kernel. + case IO_PRINT: + if (data) + GTP_INFO("%s", (char *)data); + break; + +#ifdef CONFIG_GTP_GESTURE_WAKEUP + case GESTURE_ENABLE: + GTP_DEBUG("Gesture switch ON."); + gesture_enabled = 1; + break; + + case GESTURE_DISABLE: + GTP_DEBUG("Gesture switch OFF."); + gesture_enabled = 0; + break; + + case GESTURE_FLAG_SET: + SETBIT(gestures_flag, (u8) value); + GTP_DEBUG("Gesture flag: 0x%02X enabled.", value); + break; + + case GESTURE_FLAG_CLEAR: + CLEARBIT(gestures_flag, (u8) value); + GTP_DEBUG("Gesture flag: 0x%02X disabled.", value); + break; + + case GESTURE_DATA_OBTAIN: + GTP_DEBUG("Obtain gesture data."); + mutex_lock(&gesture_data_mutex); + ret = copy_to_user(((u8 __user *) arg), &gesture_data.data, 4 + gesture_data.data[1] * 4 + gesture_data.data[3]); + if (ret) { + GTP_ERROR("ERROR when copy gesture data to user."); + ret = ERROR_MEM; + } else { + ret = 4 + gesture_data.data[1] * 4 + gesture_data.data[3]; + } + mutex_unlock(&gesture_data_mutex); + break; + + case GESTURE_DATA_ERASE: + GTP_DEBUG("ERASE_GESTURE_DATA"); + gesture_clear_wakeup_data(); + break; +#endif // GTP_GESTURE_WAKEUP + +#ifdef CONFIG_GTP_HOTKNOT + case HOTKNOT_VENDOR_VERSION: + ret = copy_to_user(((u8 __user *) arg), HOTKNOT_VERSION, sizeof(HOTKNOT_VERSION)); + if (!ret) { + ret = sizeof(HOTKNOT_VERSION); + } + break; + case HOTKNOT_LOAD_HOTKNOT: + ret = hotknot_load_hotknot_subsystem(); + break; + + case HOTKNOT_LOAD_AUTHENTICATION: +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + ret = hotknot_load_authentication_subsystem(); + break; + + case HOTKNOT_RECOVERY_MAIN: + ret = hotknot_recovery_main_system(); + break; +#ifdef CONFIG_HOTKNOT_BLOCK_RW + case HOTKNOT_DEVICES_PAIRED: + hotknot_paired_flag = 0; + force_wake_flag = 0; + block_enable = 1; + ret = hotknot_block_rw(HN_DEVICE_PAIRED, (s32) value); + break; + + case HOTKNOT_MASTER_SEND: + ret = hotknot_block_rw(HN_MASTER_SEND, (s32) value); + if (!ret) + ret = got_hotknot_extra_state; + break; + + case HOTKNOT_SLAVE_RECEIVE: + ret = hotknot_block_rw(HN_SLAVE_RECEIVED, (s32) value); + if (!ret) + ret = got_hotknot_extra_state; + break; + + case HOTKNOT_MASTER_DEPARTED: + ret = hotknot_block_rw(HN_MASTER_DEPARTED, (s32) value); + break; + + case HOTKNOT_SLAVE_DEPARTED: + ret = hotknot_block_rw(HN_SLAVE_DEPARTED, (s32) value); + break; + + case HOTKNOT_WAKEUP_BLOCK: + hotknot_wakeup_block(); + break; +#endif //HOTKNOT_BLOCK_RW +#endif //GTP_HOTKNOT + + default: + GTP_INFO("Unknown cmd."); + ret = -1; + break; + } + + if (data != NULL) { + kfree(data); + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long gt1x_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *arg32 = compat_ptr(arg); + + if (!file->f_op || !file->f_op->unlocked_ioctl) + return -ENOTTY; + + return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); +} +#endif + +static const struct file_operations gt1x_fops = { + .owner = THIS_MODULE, +#ifdef CONFIG_GTP_GESTURE_WAKEUP + .read = gt1x_gesture_data_read, + .write = gt1x_gesture_data_write, +#endif + .unlocked_ioctl = gt1x_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gt1x_compat_ioctl, +#endif +}; + +#ifdef CONFIG_GTP_HOTKNOT +static const struct file_operations hotknot_fops = { + .open = hotknot_open, + .release = hotknot_release, + .unlocked_ioctl = gt1x_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gt1x_compat_ioctl, +#endif +}; + +static struct miscdevice hotknot_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = HOTKNOT_NODE, + .fops = &hotknot_fops, +}; +#endif + +s32 gt1x_init_node(void) +{ +#ifdef CONFIG_GTP_GESTURE_WAKEUP + struct proc_dir_entry *proc_entry = NULL; + mutex_init(&gesture_data_mutex); + memset(gestures_flag, 0, sizeof(gestures_flag)); + memset((u8 *) & gesture_data, 0, sizeof(st_gesture_data)); + + proc_entry = proc_create(GESTURE_NODE, 0666, NULL, >1x_fops); + if (proc_entry == NULL) { + GTP_ERROR("CAN't create proc entry /proc/%s.", GESTURE_NODE); + return -1; + } else { + GTP_INFO("Created proc entry /proc/%s.", GESTURE_NODE); + } +#endif + +#ifdef CONFIG_GTP_HOTKNOT + if (misc_register(&hotknot_misc_device)) { + GTP_ERROR("CAN't create misc device in /dev/hotknot."); + return -1; + } else { + GTP_INFO("Created misc device in /dev/hotknot."); + } +#endif + return 0; +} + +void gt1x_deinit_node(void) +{ +#ifdef CONFIG_GTP_GESTURE_WAKEUP + remove_proc_entry(GESTURE_NODE, NULL); +#endif + +#ifdef CONFIG_GTP_HOTKNOT + misc_deregister(&hotknot_misc_device); +#endif +} diff --git a/drivers/input/touchscreen/gt1x/gt1x_generic.c b/drivers/input/touchscreen/gt1x/gt1x_generic.c new file mode 100755 index 00000000000..401a71206eb --- /dev/null +++ b/drivers/input/touchscreen/gt1x/gt1x_generic.c @@ -0,0 +1,2607 @@ +/* drivers/input/touchscreen/gt1x_generic.c + * + * 2010 - 2017 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.6 + */ + +#include "gt1x_generic.h" +#if defined(CONFIG_GTP_PROXIMITY) && defined(PLATFORM_MTK) +#include +#include +#include +#endif +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL +#include +#endif + +static struct workqueue_struct *gt1x_workqueue; +struct i2c_client *gt1x_i2c_client; +static u8 gt1x_config[GTP_CONFIG_ORG_LENGTH + GTP_CONFIG_EXT_LENGTH]; +static u32 gt1x_cfg_length = GTP_CONFIG_MAX_LENGTH; +gt1x_chip_type_t gt1x_chip_type = CHIP_TYPE_NONE; +struct gt1x_version_info gt1x_version = {{0}}; +#ifdef CONFIG_GTP_HAVE_TOUCH_KEY +static const u16 gt1x_touch_key_array[] = GTP_KEY_TAB; +#endif +#if defined(CONFIG_GTP_WITH_STYLUS) && defined(CONFIG_GTP_HAVE_STYLUS_KEY) +static const u16 gt1x_stylus_key_array[] = GTP_STYLUS_KEY_TAB; +#endif +#define GOODIX_SYSFS_DIR "goodix" +static struct kobject *sysfs_rootdir = NULL; + +volatile int gt1x_rawdiff_mode = 0; +static u8 gt1x_wakeup_level = 0; +u8 gt1x_init_failed = 0; +u8 gt1x_int_type = 0; +u32 gt1x_abs_x_max = 0; +u32 gt1x_abs_y_max = 0; +int gt1x_halt = 0; +bool send_cfg_need = false;//add by liangdi for Compatible with TP917S 20201020 + +static ssize_t gt1x_debug_read_proc(struct file *, char __user *, size_t,loff_t *); +static ssize_t gt1x_debug_write_proc(struct file *, const char __user *, size_t, loff_t *); + +static struct proc_dir_entry *gt1x_debug_proc_entry = NULL; +static const struct file_operations gt1x_debug_fops = { + .owner = THIS_MODULE, + .read = gt1x_debug_read_proc, + .write = gt1x_debug_write_proc, +}; + +static s32 gt1x_init_debug_node(void) +{ + gt1x_debug_proc_entry = proc_create(GT1X_DEBUG_PROC_FILE, + 0660, NULL, >1x_debug_fops); + if (gt1x_debug_proc_entry == NULL) { + GTP_ERROR("Create proc entry /proc/%s FAILED!", + GT1X_DEBUG_PROC_FILE); + return -1; + } + GTP_INFO("Created proc entry /proc/%s.", GT1X_DEBUG_PROC_FILE); + return 0; +} + +static void gt1x_deinit_debug_node(void) +{ + if (gt1x_debug_proc_entry != NULL) { + remove_proc_entry(GT1X_DEBUG_PROC_FILE, NULL); + } +} + +static ssize_t gt1x_debug_read_proc(struct file *file, char __user * page, + size_t size, loff_t * ppos) +{ + char *ptr = page; + char *temp_buff = NULL; + char temp_data[gt1x_cfg_length]; + struct irq_desc *irq_desc = NULL; + int i; + + if (*ppos) { + return 0; + } + temp_buff = (char *)kmalloc(GTP_CONFIG_MAX_LENGTH * 2 + GTP_CONFIG_EXT_LENGTH * 2 + 350, GFP_KERNEL); + if (!temp_buff) { + GTP_ERROR("error when alloc mem."); + return -ENOMEM; + } + + ptr = temp_buff; + ptr += sprintf(ptr, "==== GT1X default config setting in driver====\n"); //47 bytes + + for (i = 0; i < gt1x_cfg_length; i++) { + ptr += sprintf(ptr, "0x%02X,", gt1x_config[i]); + if (i % 10 == 9 && i != GTP_CONFIG_ORG_LENGTH) + ptr += sprintf(ptr, "\n"); //24 bytes + + if (i == GTP_CONFIG_ORG_LENGTH - 1) + ptr += sprintf(ptr, "\n-------------\n"); //15 bytes + } + + ptr += sprintf(ptr, "\n"); //one bytes + + ptr += sprintf(ptr, "==== GT1X config read from chip====\n"); //36 bytes + i = gt1x_i2c_read(GTP_REG_CONFIG_DATA, temp_data, + GTP_CONFIG_ORG_LENGTH); + if (i == 0 && gt1x_cfg_length == GTP_CONFIG_ORG_LENGTH + + GTP_CONFIG_EXT_LENGTH) { + i = gt1x_i2c_read(GTP_REG_EXT_CONFIG, + &temp_data[GTP_CONFIG_ORG_LENGTH], + GTP_CONFIG_EXT_LENGTH); + } + + for (i = 0; i < gt1x_cfg_length; i++) { + ptr += sprintf(ptr, "0x%02X,", temp_data[i]); + if (i % 10 == 9 && i != GTP_CONFIG_ORG_LENGTH) + ptr += sprintf(ptr, "\n"); //37 bytes + + if (i == GTP_CONFIG_ORG_LENGTH - 1) + ptr += sprintf(ptr, "\n-------------\n"); //15 bytes + } + + ptr += sprintf(ptr, "\n"); //one bytes + /* Touch PID & VID */ + ptr += sprintf(ptr, "==== GT1X Version Info ====\n"); //28 bytes + + gt1x_i2c_read(GTP_REG_VERSION, temp_data, 12); + ptr += sprintf(ptr, "ProductID: GT%c%c%c%c\n", temp_data[0], //18 bytes + temp_data[1], temp_data[2], temp_data[3]); + ptr += sprintf(ptr, "PatchID: %02X%02X\n", temp_data[4], temp_data[5]); //14 bytes + ptr += sprintf(ptr, "MaskID: %02X%02X\n", temp_data[7], temp_data[8]); //13 bytes + ptr += sprintf(ptr, "SensorID: %02X\n", temp_data[10] & 0x0F); //13 bytes + + irq_desc = irq_to_desc(gt1x_i2c_client->irq); + if (irq_desc) { + ptr += sprintf(ptr, "IRQ: %d, irq_desc->disable-depth:%d\n", //36 bytes + gt1x_i2c_client->irq, irq_desc->depth); + } + + i = ptr-temp_buff; + if (copy_to_user(page, temp_buff, i)) + { + GTP_ERROR("[READ]copy_to_user failed."); + return -1; + } + *ppos += i; + kfree(temp_buff); + + return i; +} + +static ssize_t gt1x_debug_write_proc(struct file *file, + const char __user *buffer, size_t count, loff_t * ppos) +{ + s32 ret = 0; + u8 buf[gt1x_cfg_length]; + char mode_str[50] = { 0 }; + int mode; + int cfg_len; + char arg1[50] = { 0 }; + u8 temp_config[gt1x_cfg_length]; + + GTP_DEBUG("write count %ld\n", (unsigned long)count); + + if (count > gt1x_cfg_length) { + GTP_ERROR("Too much data, buffer size: %d, data:%ld", + gt1x_cfg_length, (unsigned long)count); + return -EFAULT; + } + + if (copy_from_user(buf, buffer, count)) { + GTP_ERROR("copy from user fail!"); + return -EFAULT; + } + // send config + if (count == gt1x_cfg_length) { + memcpy(gt1x_config, buf, count); + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + if (ret < 0) { + GTP_ERROR("send gt1x_config failed."); + return -EFAULT; + } + gt1x_abs_x_max = (gt1x_config[RESOLUTION_LOC + 1] << 8) + + gt1x_config[RESOLUTION_LOC]; + gt1x_abs_y_max = (gt1x_config[RESOLUTION_LOC + 3] << 8) + + gt1x_config[RESOLUTION_LOC + 2]; + + return count; + } + + sscanf(buf, "%s %d", (char *)&mode_str, &mode); + + //force clear gt1x_config + if (strcmp(mode_str, "clear_config") == 0) { + GTP_INFO("Force clear gt1x_config"); + gt1x_send_cmd(GTP_CMD_CLEAR_CFG, 0); + return count; + } + if (strcmp(mode_str, "init") == 0) { + GTP_INFO("Init panel"); + gt1x_init_panel(); + return count; + } + if (strcmp(mode_str, "chip") == 0) { + GTP_INFO("Get chip type:"); + gt1x_get_chip_type(); + return count; + } + if (strcmp(mode_str, "int") == 0) { + if (mode == 0) { + GTP_INFO("Disable irq."); + gt1x_irq_disable(); + } else { + GTP_INFO("Enable irq."); + gt1x_irq_enable(); + } + return count; + } + + if (strcmp(mode_str, "poweron") == 0) { + gt1x_power_switch(1); + return count; + } + + if (strcmp(mode_str, "poweroff") == 0) { + gt1x_power_switch(0); + return count; + } + + if (strcmp(mode_str, "version") == 0) { + gt1x_read_version(NULL); + return count; + } + + if (strcmp(mode_str, "reset") == 0) { + gt1x_irq_disable(); + gt1x_reset_guitar(); + gt1x_irq_enable(); + return count; + } +#ifdef CONFIG_GTP_CHARGER_SWITCH + if (strcmp(mode_str, "charger") == 0) { + gt1x_charger_config(mode); + return count; + } +#endif + sscanf(buf, "%s %s", (char *)&mode_str, (char *)&arg1); + if (strcmp(mode_str, "update") == 0) { + if(strcmp(arg1, "request") == 0){ + GTP_INFO("Update firmware from request!"); + gt1x_update_firmware(NULL); + }else{ + gt1x_update_firmware(arg1); + } + return count; + } + + if (strcmp(mode_str, "sendconfig") == 0) { + cfg_len = gt1x_parse_config(arg1, temp_config); + if (cfg_len < 0) { + return -1; + } + gt1x_send_cfg(temp_config, gt1x_cfg_length); + return count; + } + + if (strcmp(mode_str, "debug_gesture") == 0) { +#ifdef CONFIG_GTP_GESTURE_WAKEUP + gt1x_gesture_debug(!!mode); +#endif + } + + if (strcmp(mode_str, "force_update") == 0) { + update_info.force_update = !!mode; + } + return gt1x_debug_proc(buf, count); +} + +static u8 ascii2hex(u8 a) +{ + s8 value = 0; + if (a >= '0' && a <= '9') { + value = a - '0'; + } else if (a >= 'A' && a <= 'F') { + value = a - 'A' + 0x0A; + } else if (a >= 'a' && a <= 'f') { + value = a - 'a' + 0x0A; + } else { + value = 0xff; + } + return value; +} + +int gt1x_parse_config(char *filename, u8 * config) +{ + mm_segment_t old_fs; + struct file *fp = NULL; + u8 *buf; + int i; + int len; + int cur_len = -1; + u8 high, low; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(filename, O_RDONLY, 0); + if (IS_ERR(fp)) { + GTP_ERROR("Open config file error!(file: %s)", filename); + goto parse_cfg_fail1; + } + len = fp->f_op->llseek(fp, 0, SEEK_END); + if (len > gt1x_cfg_length * 6 || len < gt1x_cfg_length) { + GTP_ERROR("Config is invalid!(length: %d)", len); + goto parse_cfg_fail2; + } + buf = (u8 *) kzalloc(len, GFP_KERNEL); + if (buf == NULL) { + GTP_ERROR("Allocate memory failed!(size: %d)", len); + goto parse_cfg_fail2; + } + fp->f_op->llseek(fp, 0, SEEK_SET); + if (fp->f_op->read(fp, (char *)buf, len, &fp->f_pos) != len) { + GTP_ERROR("Read %d bytes from file failed!", len); + } + + GTP_INFO("Parse config file: %s (%d bytes)", filename, len); + + for (i = 0, cur_len = 0; i < len && cur_len < gt1x_cfg_length;) { + if (buf[i] == ' ' || buf[i] == '\r' || buf[i] == '\n' || buf[i] == ',') { + i++; + continue; + } + if (buf[i] == '0' && (buf[i + 1] == 'x' || buf[i + 1] == 'X')) { + + high = ascii2hex(buf[i + 2]); + low = ascii2hex(buf[i + 3]); + + if (high != 0xFF && low != 0xFF) { + config[cur_len++] = (high << 4) + low; + i += 4; + continue; + } + } + GTP_ERROR("Illegal config file!"); + cur_len = -1; + break; + } + + if (cur_len < GTP_CONFIG_MIN_LENGTH || config[cur_len - 1] != 0x01) { + cur_len = -1; + } else { + for (i = 0; i < cur_len; i++) { + if (i % 10 == 0) { + printk("\n<>:"); + } + printk("0x%02x,", config[i]); + } + printk("\n"); + } + + kfree(buf); +parse_cfg_fail2: + filp_close(fp, NULL); +parse_cfg_fail1: + set_fs(old_fs); + + return cur_len; +} + +s32 _do_i2c_read(struct i2c_msg * msgs, u16 addr, u8 * buffer, s32 len) +{ + s32 ret = -1; + s32 pos = 0; + s32 data_length = len; + s32 transfer_length = 0; + u8 *data = NULL; + u16 address = addr; + + data = (u8 *) kmalloc(IIC_MAX_TRANSFER_SIZE < + (len + GTP_ADDR_LENGTH) ? + IIC_MAX_TRANSFER_SIZE : + (len + GTP_ADDR_LENGTH), GFP_KERNEL); + if (data == NULL) { + return ERROR_MEM; + } + msgs[1].buf = data; + + while (pos != data_length) { + if ((data_length - pos) > IIC_MAX_TRANSFER_SIZE) { + transfer_length = IIC_MAX_TRANSFER_SIZE; + } else { + transfer_length = data_length - pos; + } + msgs[0].buf[0] = (address >> 8) & 0xFF; + msgs[0].buf[1] = address & 0xFF; + msgs[1].len = transfer_length; + + ret = i2c_transfer(gt1x_i2c_client->adapter, msgs, 2); + if (ret != 2) { + GTP_ERROR("I2c Transfer error! (%d)", ret); + kfree(data); + return ERROR_IIC; + } + memcpy(&buffer[pos], msgs[1].buf, transfer_length); + pos += transfer_length; + address += transfer_length; + } + + kfree(data); + return 0; +} + +s32 _do_i2c_write(struct i2c_msg * msg, u16 addr, u8 * buffer, s32 len) +{ + s32 ret = -1; + s32 pos = 0; + s32 data_length = len; + s32 transfer_length = 0; + u8 *data = NULL; + u16 address = addr; + + data = (u8 *) kmalloc(IIC_MAX_TRANSFER_SIZE < + (len + GTP_ADDR_LENGTH) ? IIC_MAX_TRANSFER_SIZE : + (len + GTP_ADDR_LENGTH), GFP_KERNEL); + if (data == NULL) { + return ERROR_MEM; + } + msg->buf = data; + + while (pos != data_length) { + if ((data_length - pos) > (IIC_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH)) { + transfer_length = IIC_MAX_TRANSFER_SIZE - GTP_ADDR_LENGTH; + } else { + transfer_length = data_length - pos; + } + + msg->buf[0] = (address >> 8) & 0xFF; + msg->buf[1] = address & 0xFF; + msg->len = transfer_length + GTP_ADDR_LENGTH; + memcpy(&msg->buf[GTP_ADDR_LENGTH], &buffer[pos], transfer_length); + + ret = i2c_transfer(gt1x_i2c_client->adapter, msg, 1); + if (ret != 1) { + GTP_ERROR("I2c transfer error! (%d)", ret); + kfree(data); + return ERROR_IIC; + } + pos += transfer_length; + address += transfer_length; + } + + kfree(data); + return 0; +} + +/** + * gt1x_i2c_read_dbl_check - read twice and double check + * @addr: register address + * @buffer: data buffer + * @len: bytes to read + * Return <0: i2c error, 0: ok, 1:fail + */ +s32 gt1x_i2c_read_dbl_check(u16 addr, u8 * buffer, s32 len) +{ + u8 buf[16] = { 0 }; + u8 confirm_buf[16] = { 0 }; + int ret; + + if (len > 16) { + GTP_ERROR("i2c_read_dbl_check length %d is too long, exceed %zu", + len, sizeof(buf)); + return ERROR; + } + + memset(buf, 0xAA, sizeof(buf)); + ret = gt1x_i2c_read(addr, buf, len); + if (ret < 0) { + return ret; + } + + msleep(5); + memset(confirm_buf, 0, sizeof(confirm_buf)); + ret = gt1x_i2c_read(addr, confirm_buf, len); + if (ret < 0) { + return ret; + } + + if (!memcmp(buf, confirm_buf, len)) { + memcpy(buffer, confirm_buf, len); + return 0; + } + GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len); + return 1; +} + +/** + * gt1x_get_info - Get information from ic, such as resolution and + * int trigger type + * Return <0: i2c failed, 0: i2c ok + */ +s32 gt1x_get_info(void) +{ + u8 opr_buf[4] = { 0 }; + s32 ret = 0; + + ret = gt1x_i2c_read(GTP_REG_CONFIG_DATA + 1, opr_buf, 4); + if (ret < 0) { + return ret; + } + + gt1x_abs_x_max = (opr_buf[1] << 8) + opr_buf[0]; + gt1x_abs_y_max = (opr_buf[3] << 8) + opr_buf[2]; + + ret = gt1x_i2c_read(GTP_REG_CONFIG_DATA + 6, opr_buf, 1); + if (ret < 0) { + return ret; + } + gt1x_int_type = opr_buf[0] & 0x03; + + GTP_INFO("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x", + gt1x_abs_x_max, gt1x_abs_y_max, gt1x_int_type); + + return 0; +} + +/** + * gt1x_send_cfg - Send gt1x_config Function. + * @config: pointer of the configuration array. + * @cfg_len: length of configuration array. + * Return 0--success,non-0--fail. + */ +s32 gt1x_send_cfg(u8 * config, int cfg_len) +{ +//#ifdef CONFIG_GTP_DRIVER_SEND_CFG + static DEFINE_MUTEX(mutex_cfg); + int i; + s32 ret = 0; + s32 retry = 0; + u16 checksum = 0; + +if(send_cfg_need) +{ + if (update_info.status) { + GTP_DEBUG("Ignore cfg during fw update."); + return -1; + } + + mutex_lock(&mutex_cfg); + GTP_DEBUG("Driver send config, length:%d", cfg_len); + + if (cfg_len != GTP_CONFIG_ORG_LENGTH + && cfg_len != GTP_CONFIG_ORG_LENGTH + GTP_CONFIG_EXT_LENGTH) { + GTP_ERROR("Invalid config length"); + mutex_unlock(&mutex_cfg); + return -1; + } + + /* Extends config */ + if (config[GTP_REG_EXT_CFG_FLAG - GTP_REG_CONFIG_DATA] & 0x40) { + int total_len = GTP_CONFIG_EXT_LENGTH + GTP_CONFIG_ORG_LENGTH; + + /* bit0 of first byte of extended config + * must be set to 1, otherwise the firmware + * will not accept the extended config data + */ + config[GTP_CONFIG_ORG_LENGTH] |= 0x01; + GTP_DEBUG("ext_cfg, debug info:%X", config[GTP_CONFIG_ORG_LENGTH]); + + for (i = GTP_CONFIG_ORG_LENGTH; i < total_len - 2; i+=2) + checksum += (config[i] << 8) + + config[i + 1]; + + if (!checksum){ + GTP_ERROR("Invalid config, all of the bytes is zero!"); + mutex_unlock(&mutex_cfg); + return -1; + } + checksum = 0 - checksum; + config[total_len - 2] = (checksum >> 8) & 0xFF; + config[total_len - 1] = checksum & 0xFF; + + do { + ret = gt1x_i2c_write(GTP_REG_EXT_CONFIG, + &config[GTP_CONFIG_ORG_LENGTH], GTP_CONFIG_EXT_LENGTH); + } while (ret < 0 && retry++ < 3) ; + + if (ret < 0) { + GTP_ERROR("Send ext_config failed!"); + mutex_unlock(&mutex_cfg); + return -1; + } else { + GTP_DEBUG("Send ext_config successfully"); + } + } + + /* Original Config */ + cfg_len = GTP_CONFIG_ORG_LENGTH; + for (i = 0, checksum = 0; i < cfg_len - 3; i += 2) + checksum += (config[i] << 8) + config[i + 1]; + + if (!checksum) { + GTP_ERROR("Invalid config, all of the bytes is zero!"); + mutex_unlock(&mutex_cfg); + return -1; + } + + checksum = 0 - checksum; + GTP_DEBUG("Config checksum: 0x%04X", checksum); + config[cfg_len - 3] = (checksum >> 8) & 0xFF; + config[cfg_len - 2] = checksum & 0xFF; + config[cfg_len - 1] = 0x01; + retry = 0; + while (retry++ < 3) { + ret = gt1x_i2c_write(GTP_REG_CONFIG_DATA, config, cfg_len); + if (!ret) { + /* at least 200ms, wait for storing config into flash. */ + msleep(200); + mutex_unlock(&mutex_cfg); + GTP_DEBUG("Send config successfully!"); + return 0; + } + } + GTP_ERROR("Send config failed!"); + mutex_unlock(&mutex_cfg); + return ret; +} +else //#endif +{ + GTP_DEBUG("Do not send config"); + return 0; +} +} + +#ifdef CONFIG_OF +/** + * gt1x_parse_tp_config - get config data of touch panel + * @of_node: device node + * @cfg_name: config name prefix, e.g. "default-config" + * @sensor_id: config group ID + * @config: config data buffer + * return: > 0 size of config data, <0 error + */ +int gt1x_find_tp_config(struct device *dev, + char *cfg_name, u8 sensor_id, u8 *config) +{ + struct property *prop; + char name[32]; + u8 extcfg_flag; + int size, requ_size; + + if (!dev || !dev->of_node || !cfg_name || + !config || sensor_id > 6) + return -EINVAL; + + snprintf(name, sizeof(name), "goodix,%s%d", cfg_name, sensor_id); + prop = of_find_property(dev->of_node, name, &size); + if (!prop || !prop->value || size < GTP_CONFIG_ORG_LENGTH) { + GTP_ERROR("Property %s not found", name); + return -ENOENT; + } + + extcfg_flag = ((u8 *)prop->value)[GTP_REG_EXT_CFG_FLAG - + GTP_REG_CONFIG_DATA]; + if (extcfg_flag & 0x40) /* has extended config data*/ + requ_size = GTP_CONFIG_ORG_LENGTH + GTP_CONFIG_EXT_LENGTH; + else + requ_size = GTP_CONFIG_ORG_LENGTH; + + if (size != requ_size) { + GTP_ERROR("Invalid config size:%d", size); + return -EINVAL; + } + + memcpy(config, prop->value, size); + GTP_INFO("Find %s, size:%d, ver:%02xh ", + name, size, config[0]); + return size; +} +#else +int gt1x_find_tp_config(struct device *dev, + char *cfg_name, u8 sensor_id, u8 *config) +{ + return -ENOENT; +} +#endif + +/** + * gt1x_init_panel - Prepare config data for touch ic, + * don't call this function after initialization. + * + * Return 0--success,<0 --fail. + */ +s32 gt1x_init_panel(void) +{ + u16 cfg_len = 0; + s32 ret = 0; +#ifdef CONFIG_MTK_PLATFORM + struct device *dev = tpd->tpd_dev; +#else + struct device *dev = >1x_i2c_client->dev; +#endif + +//#ifdef CONFIG_GTP_DRIVER_SEND_CFG +if(send_cfg_need) +{ + cfg_len = gt1x_find_tp_config(dev, "default-config", + gt1x_version.sensor_id, gt1x_config); + if (cfg_len < 0) { + GTP_ERROR("Failed to obtain config data:%d", cfg_len); + return -EINVAL; + } + + /* clear the flag, avoid failure when send + * the_config of driver. */ + gt1x_config[0] &= 0x7F; + +#ifdef CONFIG_GTP_CUSTOM_CFG + gt1x_config[RESOLUTION_LOC] = (u8) GTP_MAX_WIDTH; + gt1x_config[RESOLUTION_LOC + 1] = (u8) (GTP_MAX_WIDTH >> 8); + gt1x_config[RESOLUTION_LOC + 2] = (u8) GTP_MAX_HEIGHT; + gt1x_config[RESOLUTION_LOC + 3] = (u8) (GTP_MAX_HEIGHT >> 8); + + if (GTP_INT_TRIGGER == 0) { /* RISING */ + gt1x_config[TRIGGER_LOC] &= 0xfe; + } else if (GTP_INT_TRIGGER == 1) { /* FALLING */ + gt1x_config[TRIGGER_LOC] |= 0x01; + } + set_reg_bit(gt1x_config[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); +#endif /* END GTP_CUSTOM_CFG */ +} +else //#else /* DRIVER NOT SEND CONFIG */ +{ + cfg_len = GTP_CONFIG_ORG_LENGTH; + ret = gt1x_i2c_read(GTP_REG_CONFIG_DATA, gt1x_config, cfg_len); + if (ret < 0) + return ret; + + if (gt1x_config[GTP_REG_EXT_CFG_FLAG - GTP_REG_CONFIG_DATA] & 0x40) { + ret = gt1x_i2c_read(GTP_REG_EXT_CONFIG, + >1x_config[cfg_len], GTP_CONFIG_EXT_LENGTH); + if (ret < 0) + return ret; + + cfg_len += GTP_CONFIG_EXT_LENGTH; + } +} +//#endif /* END GTP_DRIVER_SEND_CFG */ + + /* match resolution when gt1x_abs_x_max & gt1x_abs_y_max + * have been set already */ + if ((gt1x_abs_x_max == 0) && (gt1x_abs_y_max == 0)) { + gt1x_abs_x_max = (gt1x_config[RESOLUTION_LOC + 1] << 8) + + gt1x_config[RESOLUTION_LOC]; + gt1x_abs_y_max = (gt1x_config[RESOLUTION_LOC + 3] << 8) + + gt1x_config[RESOLUTION_LOC + 2]; + gt1x_int_type = (gt1x_config[TRIGGER_LOC]) & 0x03; + gt1x_wakeup_level = !(gt1x_config[MODULE_SWITCH3_LOC] & 0x20); + } else { + gt1x_config[RESOLUTION_LOC] = (u8) gt1x_abs_x_max; + gt1x_config[RESOLUTION_LOC + 1] = (u8) (gt1x_abs_x_max >> 8); + gt1x_config[RESOLUTION_LOC + 2] = (u8) gt1x_abs_y_max; + gt1x_config[RESOLUTION_LOC + 3] = (u8) (gt1x_abs_y_max >> 8); + set_reg_bit(gt1x_config[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); + gt1x_config[TRIGGER_LOC] = (gt1x_config[TRIGGER_LOC] & 0xFC) | gt1x_int_type; + } + + GTP_INFO("X_MAX=%d,Y_MAX=%d,TRIGGER=0x%02x,WAKEUP_LEVEL=%d", + gt1x_abs_x_max, gt1x_abs_y_max, gt1x_int_type, gt1x_wakeup_level); + + gt1x_cfg_length = cfg_len; + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + return ret; +} + +void gt1x_select_addr(void) +{ + int ret = 0; + /* Set pinctrl state as wakeup */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_wakeup) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_wakeup); + if (ret < 0) + GTP_ERROR("Set pinctrl state as wakeup error: %d", ret); + + GTP_GPIO_OUTPUT(GTP_RST_PORT, 0); + usleep_range(1000, 1030); + GTP_GPIO_OUTPUT(GTP_INT_PORT, gt1x_i2c_client->addr == 0x14); + usleep_range(3000, 3030); + GTP_GPIO_OUTPUT(GTP_RST_PORT, 1); + usleep_range(2000, 2030); +} + +static s32 gt1x_set_reset_status(void) +{ + /* 0x8040 ~ 0x8043 */ + u8 value[] = {0xAA, 0x00, 0x56, 0xAA}; + int ret; + + ret = gt1x_i2c_write(GTP_REG_CMD + 1, &value[1], 3); + if (ret < 0) + return ret; + + return gt1x_i2c_write(GTP_REG_CMD, value, 1); +} + +#ifdef CONFIG_GTP_INCELL_PANEL +int gt1x_write_and_readback(u16 addr, u8 * buffer, s32 len) +{ + int ret; + u8 d[len]; + + ret = gt1x_i2c_write(addr, buffer, len); + if (ret < 0) + return -1; + + ret = gt1x_i2c_read(addr, d, len); + if (ret < 0 || memcmp(buffer, d, len)) + return -1; + + return 0; +} + +int gt1x_incell_reset(void) +{ +#define RST_RETRY 5 + int ret, retry = RST_RETRY; + u8 d[2]; + + do { + /* select i2c address */ + gt1x_select_addr(); + + /* test i2c */ + ret = gt1x_i2c_read(0x4220, d, 1); + + } while (--retry && ret < 0); + + if (ret < 0) { + return -1; + } + + /* Important! */ + usleep_range(10000, 11000); /* delay 10ms */ + + /* Stop cpu of the touch ic */ + retry = RST_RETRY; + do { + d[0] = 0x0C; + ret = gt1x_write_and_readback(0x4180, d, 1); + } while (--retry && ret < 0); + + if (ret < 0) { + GTP_ERROR("Hold error."); + return -1; + } + + /* skip sensor id check. [start] */ + retry = RST_RETRY; + do { + d[0] = 0x00; + ret = gt1x_write_and_readback(0x4305, d, 1); + if (ret < 0) + continue; + + d[0] = 0x2B; + d[1] = 0x24; + ret = gt1x_write_and_readback(0x42c4, d, 2); + if (ret < 0) + continue; + + d[0] = 0xE1; + d[1] = 0xD3; + ret = gt1x_write_and_readback(0x42e4, d, 2); + if (ret < 0) + continue; + + d[0] = 0x01; + ret = gt1x_write_and_readback(0x4305, d, 1); + if (ret < 0) + continue; + else + break; + } while (--retry ); + + if (!retry) + return -1; + /* skip sensor id check. [end] */ + + /* release hold of cpu */ + retry = RST_RETRY; + do { + d[0] = 0x00; + ret = gt1x_write_and_readback(0x4180, d, 1); + + } while (--retry && ret < 0); + + if (ret < 0) + return -1; + + return 0; + +} +#endif + +s32 gt1x_reset_guitar(void) +{ + int ret; + + GTP_INFO("GTP RESET!"); + +#ifdef CONFIG_GTP_INCELL_PANEL + ret = gt1x_incell_reset(); + if (ret < 0) + return ret; +#else + gt1x_select_addr(); + usleep_range(8000, 8000); //must >= 6ms +#endif + + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + msleep(50); + /* Set pinctrl state as normal */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_normal) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_normal); + if (ret < 0) + GTP_ERROR("Set pinctrl state as normal error: %d", ret); + GTP_GPIO_AS_INT(GTP_INT_PORT); + + ret = gt1x_set_reset_status(); + return ret; +} + +/** + * gt1x_read_version - Read gt1x version info. + * @ver_info: address to store version info + * Return 0-succeed. + */ +s32 gt1x_read_version(struct gt1x_version_info * ver_info) +{ + s32 ret = -1; + u8 buf[12] = { 0 }; + u32 mask_id = 0; + u32 patch_id = 0; + u8 product_id[5] = { 0 }; + u8 sensor_id = 0; + u8 match_opt = 0; + int i, retry = 3; + u8 checksum = 0; + + GTP_DEBUG_FUNC(); + + while (retry--) { + ret = gt1x_i2c_read_dbl_check(GTP_REG_VERSION, buf, sizeof(buf)); + if (!ret) { + checksum = 0; + + for (i = 0; i < sizeof(buf); i++) { + checksum += buf[i]; + } + + if (checksum == 0 && /* first 3 bytes must be number or char */ + IS_NUM_OR_CHAR(buf[0]) && IS_NUM_OR_CHAR(buf[1]) && + IS_NUM_OR_CHAR(buf[2]) && buf[10] != 0xFF) { + /*sensor id == 0xFF, retry */ + break; + } else { + GTP_ERROR("Read version failed!(checksum error)"); + } + } else { + GTP_ERROR("Read version failed!"); + } + GTP_DEBUG("Read version : %d", retry); + msleep(100); + } + + if (retry <= 0) { + if (ver_info) + ver_info->sensor_id = 0; + return -1; + } + + mask_id = (u32) ((buf[7] << 16) | (buf[8] << 8) | buf[9]); + patch_id = (u32) ((buf[4] << 16) | (buf[5] << 8) | buf[6]); + memcpy(product_id, buf, 4); + sensor_id = buf[10] & 0x0F; + match_opt = (buf[10] >> 4) & 0x0F; + + GTP_INFO("IC VERSION:GT%s_%06X(Patch)_%04X(Mask)_%02X(SensorID)", + product_id, patch_id, mask_id >> 8, sensor_id); + //add by liangdi for Compatible with TP917S 20201020 + if(!strcmp(product_id,"1158") && (sensor_id == 2)) + { + pr_err("GT%s sensorid %d is detected,need send cfg\n",product_id,sensor_id); + send_cfg_need = true; + } + else + { + pr_err("GT%s sensorid %d is detected\n",product_id,sensor_id); + } + //add end + if (ver_info != NULL) { + ver_info->mask_id = mask_id; + ver_info->patch_id = patch_id; + memcpy(ver_info->product_id, product_id, 5); + ver_info->sensor_id = sensor_id; + ver_info->match_opt = match_opt; + } + return 0; +} + +/** + * gt1x_get_chip_type - get chip type . + * + * different chip synchronize in different way, + */ +s32 gt1x_get_chip_type(void) +{ + u8 opr_buf[4] = { 0x00 }; + u8 gt1x_data[] = { 0x02, 0x08, 0x90, 0x00 }; + u8 gt9l_data[] = { 0x03, 0x10, 0x90, 0x00 }; + s32 ret = -1; + + /* chip type already exist */ + if (gt1x_chip_type != CHIP_TYPE_NONE) { + return 0; + } + + /* read hardware */ + ret = gt1x_i2c_read_dbl_check(GTP_REG_HW_INFO, opr_buf, sizeof(opr_buf)); + if (ret) { + GTP_ERROR("I2c communication error."); + return -1; + } + + /* find chip type */ + if (!memcmp(opr_buf, gt1x_data, sizeof(gt1x_data))) { + gt1x_chip_type = CHIP_TYPE_GT1X; + } else if (!memcmp(opr_buf, gt9l_data, sizeof(gt9l_data))) { + gt1x_chip_type = CHIP_TYPE_GT2X; + } + + if (gt1x_chip_type != CHIP_TYPE_NONE) { + GTP_INFO("Chip Type: %s", + (gt1x_chip_type == CHIP_TYPE_GT1X) ? + "GT1X" : "GT2X"); + return 0; + } else { + return -1; + } +} + +/** + * gt1x_enter_sleep - Eter sleep function. + * + * Returns 0--success,non-0--fail. + */ +static s32 gt1x_enter_sleep(void) +{ + int ret; + +#ifdef CONFIG_GTP_POWER_CTRL_SLEEP + /* Set pin state as poweroff */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_poweroff) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_poweroff); + if (ret < 0) + GTP_ERROR("Set pin state as poweroff error: %d", ret); + gt1x_power_switch(SWITCH_OFF); + return 0; +#else + { + s32 retry = 0; + + if (gt1x_wakeup_level == 1) { + /* Set pin state as sleep */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_sleep) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_sleep); + if (ret < 0) + GTP_ERROR("Set pin state as sleep error: %d", ret); + /* high level wakeup */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + } else { + /* Set pinctrl state as wakeup */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_wakeup) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_wakeup); + if (ret < 0) + GTP_ERROR("Set pinctrl state as wakeup error: %d", ret); + /* low level wakeup */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, 1); + } + msleep(5); + + while (retry++ < 3) { + if (!gt1x_send_cmd(GTP_CMD_SLEEP, 0)) { + GTP_INFO("Enter sleep mode!"); + return 0; + } + msleep(10); + } + + GTP_ERROR("Enter sleep mode failed."); + return -1; + } +#endif +} + +/** + * gt1x_wakeup_sleep - wakeup from sleep mode Function. + * + * Return: 0--success,non-0--fail. + */ +static s32 gt1x_wakeup_sleep(void) +{ +#ifndef CONFIG_GTP_POWER_CTRL_SLEEP + u8 retry = 0; + s32 ret = -1; + int flag = 0; +#endif + + GTP_DEBUG("Wake up begin."); + gt1x_irq_disable(); + +#ifdef CONFIG_GTP_POWER_CTRL_SLEEP + /* power manager unit control the procedure */ + gt1x_power_reset(); + GTP_INFO("Wakeup by poweron"); + return 0; +#else + /* gesture wakeup & int port wakeup */ + while (retry++ < 2) { +#ifdef CONFIG_GTP_GESTURE_WAKEUP + if (gesture_enabled) { +#ifndef CONFIG_MTK_PLATFORM + disable_irq_wake(gt1x_i2c_client->irq); +#endif + gesture_doze_status = DOZE_DISABLED; + ret = gt1x_reset_guitar(); + if(!ret) + break; + } else +#endif + { + if (1 == gt1x_wakeup_level) { + /* Set pinctrl state as wakeup */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_wakeup) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_wakeup); + if (ret < 0) + GTP_ERROR("Set pinctrl state as wakeup error: %d", ret); + } + + /* wake up through int port */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, gt1x_wakeup_level); + msleep(5); + /* Synchronize int IO */ + GTP_GPIO_OUTPUT(GTP_INT_PORT, 0); + msleep(50); + + /* Set pinctrl state as normal */ + if ( gt_pinctrl.ts_pinctrl && gt_pinctrl.pinctrl_normal) + ret = pinctrl_select_state(gt_pinctrl.ts_pinctrl, gt_pinctrl.pinctrl_normal); + if (ret < 0) + GTP_ERROR("Set pinctrl state as normal error: %d", ret); + GTP_GPIO_AS_INT(GTP_INT_PORT); + flag = 1; + + ret = gt1x_set_reset_status(); + if (!ret) + break; +#if 0 + /* wakeup throuth hw reset */ + ret = gt1x_reset_guitar(); + if (!ret) + break; +#endif + } /* end int wakeup */ + } + + if (ret < 0 && flag) { + /* int wakeup failed , try waking + * up by reset */ + while (retry--) { + ret = gt1x_reset_guitar(); + if(!ret) + break; + } + } + + if (ret) { + GTP_ERROR("Wake up sleep failed."); + return -1; + } else { + GTP_INFO("Wake up end."); + return 0; + } +#endif /* END GTP_POWER_CTRL_SLEEP */ +} + +/** + * gt1x_send_cmd - seng cmd + * must write data & checksum first + * byte content + * 0 cmd + * 1 data + * 2 checksum + * Returns 0 - succeed,non-0 - failed + */ +s32 gt1x_send_cmd(u8 cmd, u8 data) +{ + s32 ret; + static DEFINE_MUTEX(cmd_mutex); + u8 buffer[3] = { cmd, data, 0 }; + + mutex_lock(&cmd_mutex); + buffer[2] = (u8) ((0 - cmd - data) & 0xFF); + ret = gt1x_i2c_write(GTP_REG_CMD + 1, &buffer[1], 2); + ret |= gt1x_i2c_write(GTP_REG_CMD, &buffer[0], 1); + msleep(50); + mutex_unlock(&cmd_mutex); + + return ret; +} + +void gt1x_power_reset(void) +{ + static int rst_flag; + s32 i = 0; + + if (rst_flag || update_info.status) { + return; + } + GTP_INFO("force_reset_guitar"); + rst_flag = 1; + gt1x_irq_disable(); + gt1x_power_switch(SWITCH_OFF); + msleep(30); + gt1x_power_switch(SWITCH_ON); + + for (i = 0; i < 5; i++) { + if(gt1x_reset_guitar()) { + continue; + } + if(gt1x_send_cfg(gt1x_config, gt1x_cfg_length)) { + msleep(500); + continue; + } + break; + } + gt1x_irq_enable(); + rst_flag = 0; +} + +s32 gt1x_request_event_handler(void) +{ + s32 ret = -1; + u8 rqst_data = 0; + + ret = gt1x_i2c_read(GTP_REG_RQST, &rqst_data, 1); + if (ret) { + GTP_ERROR("I2C transfer error. errno:%d", ret); + return -1; + } + GTP_DEBUG("Request state:0x%02x.", rqst_data); + switch (rqst_data & 0x0F) { + case GTP_RQST_CONFIG: + GTP_INFO("Request Config."); + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + if (ret) { + GTP_ERROR("Send gt1x_config error."); + } else { + GTP_INFO("Send gt1x_config success."); + rqst_data = GTP_RQST_RESPONDED; + gt1x_i2c_write(GTP_REG_RQST, &rqst_data, 1); + } + break; + case GTP_RQST_RESET: + GTP_INFO("Request Reset."); + gt1x_reset_guitar(); + rqst_data = GTP_RQST_RESPONDED; + gt1x_i2c_write(GTP_REG_RQST, &rqst_data, 1); + break; + case GTP_RQST_BAK_REF: + GTP_INFO("Request Ref."); + break; + case GTP_RQST_MAIN_CLOCK: + GTP_INFO("Request main clock."); + break; +#ifdef CONFIG_GTP_HOTKNOT + case GTP_RQST_HOTKNOT_CODE: + GTP_INFO("Request HotKnot Code."); + break; +#endif + default: + break; + } + return 0; +} + +/** + * gt1x_touch_event_handler - handle touch event + * (pen event, key event, finger touch envent) + * @data: + * Return <0: failed, 0: succeed + */ +s32 gt1x_touch_event_handler(u8 * data, struct input_dev * dev, + struct input_dev * pen_dev) +{ + u8 touch_data[1 + 8 * GTP_MAX_TOUCH + 2] = { 0 }; + static u16 pre_event = 0; + static u16 pre_index = 0; + u8 touch_num = 0; + u8 key_value = 0; + u16 cur_event = 0; + u8 *coor_data = NULL; + u8 check_sum = 0; + s32 input_x = 0; + s32 input_y = 0; + s32 input_w = 0; + s32 id = 0; + s32 i = 0; + s32 ret = -1; + + GTP_DEBUG_FUNC(); + touch_num = data[0] & 0x0f; + if (touch_num > GTP_MAX_TOUCH) { + GTP_ERROR("Illegal finger number!"); + return ERROR_VALUE; + } + + memcpy(touch_data, data, 11); + + /* read the remaining coor data + * 0x814E(touch status) + 8(every coordinate + * consist of 8 bytes data) * touch num + + * keycode + checksum + */ + if (touch_num > 1) { + ret = gt1x_i2c_read((GTP_READ_COOR_ADDR + 11), + &touch_data[11], 1 + 8 * touch_num + 2 - 11); + if (ret) { + return ret; + } + } + + /* cacl checksum */ + for (i = 0; i < 1 + 8 * touch_num + 2; i++) { + check_sum += touch_data[i]; + } + if (check_sum) { /* checksum error*/ + ret = gt1x_i2c_read(GTP_READ_COOR_ADDR, + touch_data, 3 + 8 * touch_num); + if (ret) { + return ret; + } + + for (i = 0, check_sum = 0; i < 3 + 8 * touch_num; i++) { + check_sum += touch_data[i]; + GTP_ERROR("touch_data[%d]=%x",i,touch_data[i]); + } + if (check_sum) { + GTP_ERROR("Checksum error[%x]",check_sum); + return ERROR_VALUE; + } + } +/* + * cur_event , pre_event bit defination + * bits: bit4 bit3 bit2 bit1 bit0 + * event: hover stylus_key stylus key touch + */ + key_value = touch_data[1 + 8 * touch_num]; +/* start check current event */ + if ((touch_data[0] & 0x10) && key_value) { +#if defined(CONFIG_GTP_HAVE_STYLUS_KEY) || defined(CONFIG_GTP_HAVE_TOUCH_KEY) || defined(CONFIG_TPD_HAVE_BUTTON) + /* get current key states */ + if (key_value & 0xF0) { + SET_BIT(cur_event, BIT_STYLUS_KEY); + } else if (key_value & 0x0F) { + SET_BIT(cur_event, BIT_TOUCH_KEY); + } +#endif + } +#ifdef CONFIG_GTP_WITH_STYLUS + else if (touch_data[1] & 0x80) { + SET_BIT(cur_event, BIT_STYLUS); + } +#endif + else if (touch_num) { + SET_BIT(cur_event, BIT_TOUCH); + } + +/* start handle current event and pre-event */ +#ifdef CONFIG_GTP_HAVE_STYLUS_KEY + if (CHK_BIT(cur_event, BIT_STYLUS_KEY) || CHK_BIT(pre_event, BIT_STYLUS_KEY)) { + /* + * 0x10 -- stylus key0 down + * 0x20 -- stylus key1 down + * 0x40 -- stylus key0 & stylus key1 both down + */ + u8 temp = (key_value & 0x40) ? 0x30 : key_value; + for (i = 4; i < 6; i++) { + input_report_key(pen_dev, gt1x_stylus_key_array[i - 4], + temp & (0x01 << i)); + } + GTP_DEBUG("Stulus key event."); + } +#endif + +#ifdef CONFIG_GTP_WITH_STYLUS + if (CHK_BIT(cur_event, BIT_STYLUS)) { + coor_data = &touch_data[1]; + id = coor_data[0] & 0x7F; + input_x = coor_data[1] | (coor_data[2] << 8); + input_y = coor_data[3] | (coor_data[4] << 8); + input_w = coor_data[5] | (coor_data[6] << 8); + + input_x = GTP_WARP_X(gt1x_abs_x_max, input_x); + input_y = GTP_WARP_Y(gt1x_abs_y_max, input_y); + + GTP_DEBUG("Pen touch DOWN."); + gt1x_pen_down(input_x, input_y, input_w, 0); + } else if (CHK_BIT(pre_event, BIT_STYLUS)) { + GTP_DEBUG("Pen touch UP."); + gt1x_pen_up(0); + } +#endif + +#ifdef CONFIG_GTP_HAVE_TOUCH_KEY + if (CHK_BIT(cur_event, BIT_TOUCH_KEY) || CHK_BIT(pre_event, BIT_TOUCH_KEY)) { + for (i = 0; i < GTP_MAX_KEY_NUM; i++) { + input_report_key(dev, gt1x_touch_key_array[i], + key_value & (0x01 << i)); + } + if (CHK_BIT(cur_event, BIT_TOUCH_KEY)) { + GTP_DEBUG("Key Down."); + } else { + GTP_DEBUG("Key Up."); + } + } +#elif defined(CONFIG_TPD_HAVE_BUTTON) + if (tpd_dts_data.use_tpd_button) { + if (CHK_BIT(cur_event, BIT_TOUCH_KEY) || CHK_BIT(pre_event, BIT_TOUCH_KEY)) { + for (i = 0; i < tpd_dts_data.tpd_key_num; i++) + input_report_key(dev, tpd_dts_data.tpd_key_local[i], + key_value & (0x01 << i)); + if (CHK_BIT(cur_event, BIT_TOUCH_KEY)) + GTP_DEBUG("Key Down."); + else + GTP_DEBUG("Key Up."); + } + } +#endif + +/* finger touch event*/ + if (CHK_BIT(cur_event, BIT_TOUCH)) { + u8 report_num = 0; + coor_data = &touch_data[1]; + id = coor_data[0] & 0x0F; + for (i = 0; i < GTP_MAX_TOUCH; i++) { + if (i == id) { + input_x = coor_data[1] | (coor_data[2] << 8); + input_y = coor_data[3] | (coor_data[4] << 8); + input_w = coor_data[5] | (coor_data[6] << 8); + + input_x = GTP_WARP_X(gt1x_abs_x_max, input_x); + input_y = GTP_WARP_Y(gt1x_abs_y_max, input_y); + + GTP_DEBUG("(%d)(%d,%d)[%d]", id, input_x, input_y, input_w); + gt1x_touch_down(input_x, input_y, input_w, i); + if (report_num++ < touch_num) { + coor_data += 8; + id = coor_data[0] & 0x0F; + } + pre_index |= 0x01 << i; + } else if (pre_index & (0x01 << i)) { +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL + gt1x_touch_up(i); +#endif + pre_index &= ~(0x01 << i); + } + } + } else if (CHK_BIT(pre_event, BIT_TOUCH)) { +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL + int cycles = pre_index < 3 ? 3 : GTP_MAX_TOUCH; + input_report_key(dev, BTN_TOUCH, 0); + for (i = 0; i < cycles; i++) { + if (pre_index >> i & 0x01) { + gt1x_touch_up(i); + } + } +#else + input_report_key(dev, BTN_TOUCH, 0); + gt1x_touch_up(0); +#endif + GTP_DEBUG("Released Touch."); + pre_index = 0; + } + + /* start sync input report */ + if (CHK_BIT(cur_event, BIT_STYLUS_KEY | BIT_STYLUS) + || CHK_BIT(pre_event, BIT_STYLUS_KEY | BIT_STYLUS)) { + input_sync(pen_dev); + } + + if (CHK_BIT(cur_event, BIT_TOUCH_KEY | BIT_TOUCH) + || CHK_BIT(pre_event, BIT_TOUCH_KEY | BIT_TOUCH)) { + input_sync(dev); + } + + if (unlikely(!pre_event && !cur_event)) { + GTP_DEBUG("Additional Int Pulse."); + } else { + pre_event = cur_event; + } + + return 0; +} + +#ifdef CONFIG_GTP_WITH_STYLUS +struct input_dev *pen_dev; + +static void gt1x_pen_init(void) +{ + s32 ret = 0; + + pen_dev = input_allocate_device(); + if (pen_dev == NULL) { + GTP_ERROR("Failed to allocate input device for pen/stylus."); + return; + } + + pen_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + pen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + set_bit(BTN_TOOL_PEN, pen_dev->keybit); + set_bit(INPUT_PROP_DIRECT, pen_dev->propbit); + +#ifdef CONFIG_GTP_HAVE_STYLUS_KEY + input_set_capability(pen_dev, EV_KEY, BTN_STYLUS); + input_set_capability(pen_dev, EV_KEY, BTN_STYLUS2); +#endif + + input_set_abs_params(pen_dev, ABS_MT_POSITION_X, 0, gt1x_abs_x_max, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_POSITION_Y, 0, gt1x_abs_y_max, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(pen_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0); + + pen_dev->name = "goodix-pen"; + pen_dev->phys = "input/ts"; + pen_dev->id.bustype = BUS_I2C; + + ret = input_register_device(pen_dev); + if (ret) { + GTP_ERROR("Register %s input device failed", pen_dev->name); + return; + } +} + +void gt1x_pen_down(s32 x, s32 y, s32 size, s32 id) +{ + input_report_key(pen_dev, BTN_TOOL_PEN, 1); +#ifdef CONFIG_GTP_CHANGE_X2Y + GTP_SWAP(x, y); +#endif + +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL + input_mt_slot(pen_dev, id); + input_report_abs(pen_dev, ABS_MT_PRESSURE, size); + input_report_abs(pen_dev, ABS_MT_TOUCH_MAJOR, size); + input_report_abs(pen_dev, ABS_MT_TRACKING_ID, id); + input_report_abs(pen_dev, ABS_MT_POSITION_X, x); + input_report_abs(pen_dev, ABS_MT_POSITION_Y, y); +#else + input_report_key(pen_dev, BTN_TOUCH, 1); + if ((!size) && (!id)) { + /* for virtual button */ + input_report_abs(pen_dev, ABS_MT_PRESSURE, 100); + input_report_abs(pen_dev, ABS_MT_TOUCH_MAJOR, 100); + } else { + input_report_abs(pen_dev, ABS_MT_PRESSURE, size); + input_report_abs(pen_dev, ABS_MT_TOUCH_MAJOR, size); + input_report_abs(pen_dev, ABS_MT_TRACKING_ID, id); + } + input_report_abs(pen_dev, ABS_MT_POSITION_X, x); + input_report_abs(pen_dev, ABS_MT_POSITION_Y, y); + input_mt_sync(pen_dev); +#endif +} + +void gt1x_pen_up(s32 id) +{ + input_report_key(pen_dev, BTN_TOOL_PEN, 0); +#ifdef CONFIG_GTP_TYPE_B_PROTOCOL + input_mt_slot(pen_dev, id); + input_report_abs(pen_dev, ABS_MT_TRACKING_ID, -1); +#else + input_report_key(pen_dev, BTN_TOUCH, 0); + input_mt_sync(pen_dev); +#endif +} +#endif + +/** + * Proximity Module + */ +#ifdef CONFIG_GTP_PROXIMITY +#define GTP_PS_DEV_NAME "goodix_proximity" +#define GTP_REG_PROXIMITY_ENABLE 0x8049 +#define PS_FARAWAY 1 +#define PS_NEAR 0 +struct gt1x_ps_device{ + int enabled; // module enabled/disabled + int state; // Faraway or Near +#ifdef PLATFORM_MTK + struct hwmsen_object obj_ps; +#else + struct input_dev *input_dev; + struct kobject *kobj; +#endif +}; +static struct gt1x_ps_device *gt1x_ps_dev; + +void gt1x_ps_report(int state) +{ +#ifdef PLATFORM_MTK + s32 ret = -1; + + struct hwm_sensor_data sensor_data; + //map and store data to hwm_sensor_data + sensor_data.values[0] = !!state; + sensor_data.value_divide = 1; + sensor_data.status = SENSOR_STATUS_ACCURACY_MEDIUM; + //report to the up-layer + ret = hwmsen_get_interrupt_data(ID_PROXIMITY, &sensor_data); + if (ret) { + GTP_ERROR("Call hwmsen_get_interrupt_data fail = %d\n", ret); + } +#else + input_report_abs(gt1x_ps_dev->input_dev, ABS_DISTANCE, !!state); + input_sync(gt1x_ps_dev->input_dev); +#endif /* End PLATFROM_MTK */ + + GTP_INFO("Report proximity state: %s", + state == PS_FARAWAY? "FARAWAY":"NEAR"); +} + +static s32 gt1x_ps_enable(s32 enable) +{ + u8 state; + s32 ret = -1; + + GTP_INFO("Proximity function to be %s.", enable ? "on" : "off"); + state = enable ? 1 : 0; + if (gt1x_chip_type == CHIP_TYPE_GT1X) + ret = gt1x_i2c_write(GTP_REG_PROXIMITY_ENABLE, &state, 1); + else if (gt1x_chip_type == CHIP_TYPE_GT2X) + ret = gt1x_send_cmd(state ? 0x12 : 0x13, 0); + if (ret) { + GTP_ERROR("GTP %s proximity cmd failed.", + state ? "enable" : "disable"); + } + + if (!ret && enable) { + gt1x_ps_dev->enabled = 1; + } else { + gt1x_ps_dev->enabled = 0; + } + gt1x_ps_dev->state = PS_FARAWAY; + GTP_INFO("Proximity function %s %s.", + state ? "enable" : "disable", ret ? "fail" : "success"); + return ret; +} + +int gt1x_prox_event_handler(u8 * data) +{ + u8 ps = 0; + + if (gt1x_ps_dev && gt1x_ps_dev->enabled) { + ps = (data[0] & 0x60) ? 0 : 1; + if (ps != gt1x_ps_dev->state) { + gt1x_ps_report(ps); + gt1x_ps_dev->state = ps; + GTP_DEBUG("REG INDEX[0x814E]:0x%02X\n", data[0]); + } + + return (ps == PS_NEAR? 1 : 0); + } + return -1; +} + +#ifdef PLATFORM_MTK +static inline s32 gt1x_get_ps_value(void) +{ + return gt1x_ps_dev->state; +} + +static s32 gt1x_ps_operate(void *self, u32 command, void *buff_in, + s32 size_in, void *buff_out, s32 size_out, s32 * actualout) +{ + s32 err = 0; + s32 value; + struct hwm_sensor_data *sensor_data; + struct hwm_sensor_data sensor_size; + + GTP_INFO("psensor operator cmd:%d", command); + switch (command) { + case SENSOR_DELAY: + if ((buff_in == NULL) || (size_in < sizeof(int))) { + GTP_ERROR("Set delay parameter error!"); + err = -EINVAL; + } + // Do nothing + break; + + case SENSOR_ENABLE: + if ((buff_in == NULL) || (size_in < sizeof(int))) { + GTP_ERROR("Enable sensor parameter error!"); + err = -EINVAL; + } else { + value = *(int *)buff_in; + err = gt1x_ps_enable(value); + } + + break; + + case SENSOR_GET_DATA: + if ((buff_out == NULL) || (size_out < sizeof(sensor_size))) { + GTP_ERROR("Get sensor data parameter error!"); + err = -EINVAL; + } else { + sensor_data = (struct hwm_sensor_data *) buff_out; + sensor_data->values[0] = gt1x_get_ps_value(); + sensor_data->value_divide = 1; + sensor_data->status = SENSOR_STATUS_ACCURACY_MEDIUM; + } + + break; + + default: + GTP_ERROR("proxmy sensor operate function no this parameter %d!\n", + command); + err = -1; + break; + } + + return err; +} +#endif + +#ifndef PLATFORM_MTK +static ssize_t gt1x_ps_enable_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d", + gt1x_ps_dev->enabled); +} + +static ssize_t gt1x_ps_enable_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + if(sscanf(buf, "%u", &input) != 1) { + return -EINVAL; + } + if(input == 1) { + gt1x_ps_enable(1); + gt1x_ps_report(PS_FARAWAY); + } else if(input == 0) { + gt1x_ps_report(PS_FARAWAY); + gt1x_ps_enable(0); + } else { + return -EINVAL; + } + return count; +} + +static ssize_t gt1x_ps_state_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d", gt1x_ps_dev->state); +} + +static ssize_t gt1x_ps_state_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + if(sscanf(buf, "%u", &input) != 1) { + return -EINVAL; + } + + if (!gt1x_ps_dev->enabled) { + return -EINVAL; + } + + if(input == 1) { + gt1x_ps_dev->state = PS_FARAWAY; + } else if(input == 0) { + gt1x_ps_dev->state = PS_NEAR; + } else { + return -EINVAL; + } + + gt1x_ps_report(gt1x_ps_dev->state); + return count; +} + +static struct kobj_attribute ps_attrs[] = { + __ATTR(enable, S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + gt1x_ps_enable_show, gt1x_ps_enable_store), + __ATTR(state, S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + gt1x_ps_state_show, gt1x_ps_state_store) +}; + +#endif /* End PLATFORM_MTK */ + +static int gt1x_ps_init(void) +{ + int err; + + gt1x_ps_dev = kzalloc(sizeof(struct gt1x_ps_device), GFP_KERNEL); + if (!gt1x_ps_dev) { + return -ENOMEM; + } + + gt1x_ps_dev->state = PS_FARAWAY; + +#ifdef PLATFORM_MTK + gt1x_ps_dev->obj_ps.polling = 0; + gt1x_ps_dev->obj_ps.sensor_operate = gt1x_ps_operate; + + if ((err = hwmsen_attach(ID_PROXIMITY, >1x_ps_dev->obj_ps))) { + GTP_ERROR("hwmsen attach fail, return:%d.", err); + goto err_exit; + } + + GTP_INFO("hwmsen attach OK."); + return 0; +#else + gt1x_ps_dev->input_dev = input_allocate_device(); + if(!gt1x_ps_dev->input_dev) { + GTP_ERROR("Failed to alloc inpput device for proximity!"); + err = -ENOMEM; + goto err_exit; + } + + gt1x_ps_dev->input_dev->name = GTP_PS_DEV_NAME; + gt1x_ps_dev->input_dev->phys = "goodix/proximity"; + gt1x_ps_dev->input_dev->id.bustype = BUS_I2C; + gt1x_ps_dev->input_dev->id.vendor = 0xDEED; + gt1x_ps_dev->input_dev->id.product = 0xBEEF; + gt1x_ps_dev->input_dev->id.version = 1; + set_bit(EV_ABS, gt1x_ps_dev->input_dev->evbit); + input_set_abs_params(gt1x_ps_dev->input_dev, ABS_DISTANCE, 0, 1, 0, 0); + + err = input_register_device(gt1x_ps_dev->input_dev); + if(err) { + GTP_ERROR("Failed to register proximity input device: %s!", + gt1x_ps_dev->input_dev->name); + goto err_register_dev; + } + /* register sysfs interface */ + if (!sysfs_rootdir) { + sysfs_rootdir = kobject_create_and_add("goodix", NULL); + if(!sysfs_rootdir){ + GTP_ERROR("Failed to create and add sysfs interface: goodix."); + err = -ENOMEM; + goto err_register_dev; + } + } + + gt1x_ps_dev->kobj = kobject_create_and_add("proximity", sysfs_rootdir); + if(!gt1x_ps_dev->kobj){ + GTP_ERROR("Failed to create and add sysfs interface: proximity."); + err = -ENOMEM; + goto err_register_dev; + } + // create sysfs files + { + int i; + for(i = 0; i < sizeof(ps_attrs)/sizeof(ps_attrs[0]); i++) { + if((err = sysfs_create_file(gt1x_ps_dev->kobj, &ps_attrs[i].attr))) { + goto err_create_file; + } + } + } + + GTP_INFO("Proximity sensor init OK."); + return 0; +err_create_file: + kobject_put(gt1x_ps_dev->kobj); +err_register_dev: + input_free_device(gt1x_ps_dev->input_dev); +#endif /* End PLATFROM_MTK */ + +err_exit: + kfree(gt1x_ps_dev); + gt1x_ps_dev = NULL; + return err; +} + +static void gt1x_ps_deinit(void) +{ + if(gt1x_ps_dev) { +#ifndef PLATFORM_MTK + int i = 0; + for(; i < sizeof(ps_attrs) / sizeof(ps_attrs[0]); i++) { + sysfs_remove_file(gt1x_ps_dev->kobj, &ps_attrs[i].attr); + } + kobject_del(gt1x_ps_dev->kobj); + input_free_device(gt1x_ps_dev->input_dev); +#endif + kfree(gt1x_ps_dev); + } +} + +#endif /*GTP_PROXIMITY */ + +/** + * ESD Protect Module + */ +#ifdef CONFIG_GTP_ESD_PROTECT +static int esd_work_cycle = 200; +static struct delayed_work esd_check_work; +static int esd_running = 0; +static struct mutex esd_lock; +static void gt1x_esd_check_func(struct work_struct *); + +void gt1x_init_esd_protect(void) +{ + esd_work_cycle = 2 * HZ; // HZ: clock ticks in 1 second generated by system + GTP_DEBUG("Clock ticks for an esd cycle: %d", esd_work_cycle); + INIT_DELAYED_WORK(&esd_check_work, gt1x_esd_check_func); + mutex_init(&esd_lock); +} + +static void gt1x_deinit_esd_protect(void) +{ + gt1x_esd_switch(SWITCH_OFF); +} + +void gt1x_esd_switch(s32 on) +{ + mutex_lock(&esd_lock); + if (SWITCH_ON == on) { /* switch on esd check */ + if (!esd_running) { + esd_running = 1; + GTP_INFO("Esd protector started!"); + queue_delayed_work(gt1x_workqueue, + &esd_check_work, esd_work_cycle); + } + } else { /* switch off esd check */ + if (esd_running) { + esd_running = 0; + GTP_INFO("Esd protector stoped!"); + cancel_delayed_work(&esd_check_work); + } + } + mutex_unlock(&esd_lock); +} + +static void gt1x_esd_check_func(struct work_struct *work) +{ + s32 i = 0; + s32 ret = -1; + u8 esd_buf[4] = { 0 }; + + if (!esd_running) { + GTP_INFO("Esd protector suspended!"); + return; + } + + for (i = 0; i < 3; i++) { + ret = gt1x_i2c_read(GTP_REG_CMD, esd_buf, 4); + GTP_DEBUG("[Esd]0x8040 = 0x%02X, 0x8043 = 0x%02X", + esd_buf[0], esd_buf[3]); + if (!ret && esd_buf[0] != 0xAA && esd_buf[3] == 0xAA) { + break; + } + msleep(50); + } + + if (likely(i < 3)) { + /* IC works normally, Write 0x8040 0xAA, feed the watchdog */ + gt1x_send_cmd(GTP_CMD_ESD, 0); + } else { + if (esd_running) { + GTP_ERROR("IC works abnormally! Process reset guitar."); + memset(esd_buf, 0x01, sizeof(esd_buf)); + gt1x_i2c_write(0x4226, esd_buf, sizeof(esd_buf)); + msleep(50); + + gt1x_power_reset(); + } else { + GTP_INFO("Esd protector suspended, no need reset!"); + } + } + + mutex_lock(&esd_lock); + if (esd_running) { + queue_delayed_work(gt1x_workqueue, &esd_check_work, esd_work_cycle); + } else { + GTP_INFO("Esd protector suspended!"); + } + mutex_unlock(&esd_lock); +} +#endif + +/** + * Smart Cover Module + */ +#ifdef CONFIG_GTP_SMART_COVER +struct smart_cover_device{ + int enabled; + int state; // 0:cover faraway 1:near + int suspended; // suspended or woring + struct kobject *kobj; + u8 config[GTP_CONFIG_ORG_LENGTH + GTP_CONFIG_EXT_LENGTH]; + int cfg_len; +}; +static struct smart_cover_device *gt1x_sc_dev; + +/** + * gt1x_smart_cover_update_state - update smart cover config + */ +static int gt1x_smart_cover_update_state(void) +{ + int ret = 0; + struct smart_cover_device *dev = gt1x_sc_dev; + + if (!dev) { + return -ENODEV; + } + + if(!dev->suspended) { + if(dev->state) { /* near */ + ret = gt1x_send_cfg(dev->config, dev->cfg_len); + } else { + #ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_charger_config(1); // charger detector module check and + // send a config + #else + ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length); + #endif + } + GTP_DEBUG("Update cover state %s.", dev->state ? "Nearby" : "Far away"); + } else { + GTP_DEBUG("TP is suspended, do nothing."); + } + return ret; +} + +static ssize_t smart_cover_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct smart_cover_device *dev = gt1x_sc_dev; + + if (!dev) { + return -ENODEV; + } + + return scnprintf(buf, PAGE_SIZE, "%d", dev->state); +} + +static ssize_t smart_cover_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct smart_cover_device *dev = gt1x_sc_dev; + int s = (buf[0] - '0'); + + if (!dev || !dev->enabled || s > 1 || s == dev->state) { + return count; + } + + dev->state = s; + gt1x_smart_cover_update_state(); + + return count; +} + +/** + * gt1x_parse_sc_cfg - parse smart cover config + * @sensor_id: sensor id of the hardware + */ +int gt1x_parse_sc_cfg(int sensor_id) +{ +#ifdef CONFIG_MTK_PLATFORM + struct device *dev = tpd->tpd_dev; +#else + struct device *dev = >1x_i2c_client->dev; +#endif + u8 *cfg; + int size; + + if (!gt1x_sc_dev) + return -ENODEV; + cfg = gt1x_sc_dev->config; + + size = gt1x_find_tp_config(dev, "smartcover-config", + sensor_id, cfg); + if (size < 0) { + GTP_ERROR("Failed to obtain smartcover config"); + return size; + } + + cfg[0] &= 0x7F; + set_reg_bit(cfg[TRIGGER_LOC], 0, gt1x_int_type); + set_reg_bit(cfg[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); + gt1x_sc_dev->cfg_len = size; + return 0; +} + +static struct kobj_attribute sc_attr = + __ATTR(state, S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + smart_cover_show, smart_cover_store); + +static int gt1x_smart_cover_init(void) +{ + int err = 0; + + gt1x_sc_dev = kzalloc(sizeof(struct smart_cover_device), GFP_KERNEL); + if (!gt1x_sc_dev) { + GTP_ERROR("SmartCover init failed in step: 1."); + return -ENOMEM; + } + + gt1x_sc_dev->enabled = 1; + gt1x_parse_sc_cfg(gt1x_version.sensor_id); + + if (!sysfs_rootdir) { + // this kobject is shared between modules, do not free it when error occur + sysfs_rootdir = kobject_create_and_add(GOODIX_SYSFS_DIR, NULL); + if (!sysfs_rootdir) { + err = -2; + goto exit_free_mem; + } + } + + if (!gt1x_sc_dev->kobj) + gt1x_sc_dev->kobj = kobject_create_and_add("smartcover", + sysfs_rootdir); + if (!gt1x_sc_dev->kobj) { + err = -3; + goto exit_free_mem; + } + + if(sysfs_create_file(gt1x_sc_dev->kobj, &sc_attr.attr)) { + err = -4; + goto exit_put_kobj; + } + + GTP_INFO("SmartCover module init OK."); + return 0; + +exit_put_kobj: + kobject_put(gt1x_sc_dev->kobj); +exit_free_mem: + kfree(gt1x_sc_dev); + gt1x_sc_dev = NULL; + GTP_ERROR("SmartCover init failed in step:%d", -err); + return err; +} + +static void gt1x_smart_cover_deinit(void) +{ + if (!gt1x_sc_dev) { + return; + } + + kobject_del(gt1x_sc_dev->kobj); + kfree(gt1x_sc_dev); + gt1x_sc_dev = NULL; +} +#endif + +/** + * Charger Detect & Switch Module + */ +#ifdef CONFIG_GTP_CHARGER_SWITCH +static u8 gt1x_config_charger[GTP_CONFIG_ORG_LENGTH + + GTP_CONFIG_EXT_LENGTH] = { 0 }; +static struct delayed_work charger_switch_work; +static int charger_work_cycle = 200; +static spinlock_t charger_lock; +static int charger_running = 0; +static void gt1x_charger_work_func(struct work_struct *); + +/** + * gt1x_parse_chr_cfg - parse charger config + * @sensor_id: sensor id of the hardware + * Return: 0: succeed, <0 error + */ +int gt1x_parse_chr_cfg(int sensor_id) +{ +#ifdef CONFIG_MTK_PLATFORM + struct device *dev = tpd->tpd_dev; +#else + struct device *dev = >1x_i2c_client->dev; +#endif + u8 *cfg = gt1x_config_charger; + int len; + + len = gt1x_find_tp_config(dev, "charger-config", + sensor_id, cfg); + if (len < 0) { + GTP_ERROR("Failed to obtain charger config"); + return len; + } + + cfg[0] &= 0x7F; + cfg[RESOLUTION_LOC] = (u8) gt1x_abs_x_max; + cfg[RESOLUTION_LOC + 1] = (u8) (gt1x_abs_x_max >> 8); + cfg[RESOLUTION_LOC + 2] = (u8) gt1x_abs_y_max; + cfg[RESOLUTION_LOC + 3] = (u8) (gt1x_abs_y_max >> 8); + set_reg_bit(cfg[TRIGGER_LOC], 0, gt1x_int_type); + set_reg_bit(cfg[MODULE_SWITCH3_LOC], 5, !gt1x_wakeup_level); + return 0; +} + + +static void gt1x_init_charger(void) +{ + charger_work_cycle = 2 * HZ; // HZ: clock ticks in 1 second generated by system + GTP_DEBUG("Clock ticks for an charger cycle: %d", charger_work_cycle); + INIT_DELAYED_WORK(&charger_switch_work, gt1x_charger_work_func); + spin_lock_init(&charger_lock); + + if (gt1x_parse_chr_cfg(gt1x_version.sensor_id) < 0) { + GTP_ERROR("Error occured when parse charger config."); + } +} + +/** + * gt1x_charger_switch - switch states of charging work thread + * + * @on: SWITCH_ON - start work thread, SWITCH_OFF: stop . + * + */ +void gt1x_charger_switch(s32 on) +{ + spin_lock(&charger_lock); + if (SWITCH_ON == on) { + if (!charger_running) { + charger_running = 1; + spin_unlock(&charger_lock); + GTP_INFO("Charger checker started!"); + queue_delayed_work(gt1x_workqueue, + &charger_switch_work, charger_work_cycle); + } else { + spin_unlock(&charger_lock); + } + } else { + if (charger_running) { + charger_running = 0; + spin_unlock(&charger_lock); + cancel_delayed_work(&charger_switch_work); + GTP_INFO("Charger checker stoped!"); + } else { + spin_unlock(&charger_lock); + } + } +} + +/** + * gt1x_charger_config - check and update charging status configuration + * @dir_update + * 0: check before send charging status configuration + * 1: directly send charging status configuration + * + */ +void gt1x_charger_config(s32 dir_update) +{ + static u8 chr_pluggedin = 0; + +#ifdef CONFIG_GTP_SMART_COVER + if (gt1x_sc_dev && gt1x_sc_dev->enabled + && gt1x_sc_dev->state) { + return; + } +#endif + + if (gt1x_get_charger_status()) { + if (!chr_pluggedin || dir_update) { + GTP_INFO("Charger Plugin."); + if (gt1x_send_cfg(gt1x_config_charger, gt1x_cfg_length)) { + GTP_ERROR("Send config for Charger Plugin failed!"); + } + if (gt1x_send_cmd(GTP_CMD_CHARGER_ON, 0)) { + GTP_ERROR("Update status for Charger Plugin failed!"); + } + chr_pluggedin = 1; + } + } else { + if (chr_pluggedin || dir_update) { + GTP_INFO("Charger Plugout."); + if (gt1x_send_cfg(gt1x_config, gt1x_cfg_length)) { + GTP_ERROR("Send config for Charger Plugout failed!"); + } + if (gt1x_send_cmd(GTP_CMD_CHARGER_OFF, 0)) { + GTP_ERROR("Update status for Charger Plugout failed!"); + } + chr_pluggedin = 0; + } + } +} + +static void gt1x_charger_work_func(struct work_struct *work) +{ + if (!charger_running) { + GTP_INFO("Charger checker suspended!"); + return; + } + + gt1x_charger_config(0); + + GTP_DEBUG("Charger check done!"); + if (charger_running) { + queue_delayed_work(gt1x_workqueue, + &charger_switch_work, charger_work_cycle); + } +} +#endif + +int gt1x_suspend(void) +{ + s32 ret = -1; +#if defined(CONFIG_GTP_HOTKNOT) && !defined(CONFIG_HOTKNOT_BLOCK_RW) + u8 buf[1] = { 0 }; +#endif + + if (update_info.status) { + return 0; + } +#ifdef CONFIG_GTP_SMART_COVER + if (gt1x_sc_dev) { + gt1x_sc_dev->suspended = 1; + } +#endif + GTP_INFO("Suspend start..."); +#ifdef CONFIG_GTP_PROXIMITY + if (gt1x_ps_dev && gt1x_ps_dev->enabled) { + GTP_INFO("proximity is detected!"); + return 0; + } +#endif + +#ifdef CONFIG_GTP_HOTKNOT + if (hotknot_enabled) { +#ifdef CONFIG_HOTKNOT_BLOCK_RW + if (hotknot_paired_flag) { + GTP_INFO("hotknot is paired!"); + return 0; + } +#else + ret = gt1x_i2c_read_dbl_check(GTP_REG_HN_PAIRED, buf, sizeof(buf)); + if ((!ret && buf[0] == 0x55) || hotknot_transfer_mode) { + GTP_DEBUG("0x81AA: 0x%02X", buf[0]); + GTP_INFO("hotknot is paired!"); + return 0; + } +#endif + } +#endif + + gt1x_halt = 1; +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif +#ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_OFF); +#endif + gt1x_irq_disable(); + +#ifdef CONFIG_GTP_GESTURE_WAKEUP + gesture_clear_wakeup_data(); + if (gesture_enabled) { + gesture_enter_doze(); + gt1x_irq_enable(); +#ifndef CONFIG_MTK_PLATFORM + enable_irq_wake(gt1x_i2c_client->irq); +#endif + gt1x_halt = 0; + } else +#endif + { + ret = gt1x_enter_sleep(); + if (ret < 0) { + GTP_ERROR("Suspend failed."); + } + } + + /* to avoid waking up while not sleeping + delay 48 + 10ms to ensure reliability */ + msleep(58); + GTP_INFO("Suspend end..."); + return 0; +} + +int gt1x_resume(void) +{ + s32 ret = -1; + + if (update_info.status) { + return 0; + } + +#ifdef CONFIG_GTP_SMART_COVER + if (gt1x_sc_dev) { + gt1x_sc_dev->suspended = 0; + } +#endif + GTP_INFO("Resume start..."); + +#ifdef CONFIG_GTP_PROXIMITY + if (gt1x_ps_dev && gt1x_ps_dev->enabled) { + GTP_INFO("Proximity is on!"); + return 0; + } +#endif + +#ifdef CONFIG_GTP_HOTKNOT + if (hotknot_enabled) { + #ifdef CONFIG_HOTKNOT_BLOCK_RW + if (hotknot_paired_flag) { + hotknot_paired_flag = 0; + hotknot_wakeup_block(); + GTP_INFO("Hotknot is paired!"); + return 0; + } + #endif + } +#endif + +#ifdef CONFIG_GTP_GESTURE_WAKEUP + /* just return 0 if IC does not suspend */ + if (!gesture_enabled && !gt1x_halt){ + return 0; + } +#else + if (!gt1x_halt){ + return 0; + } +#endif + + ret = gt1x_wakeup_sleep(); + if (ret < 0) { + GTP_ERROR("Resume failed."); + } +#ifdef CONFIG_GTP_HOTKNOT + if (!hotknot_enabled) { + gt1x_send_cmd(GTP_CMD_HN_EXIT_SLAVE, 0); + } +#endif + +#ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_charger_config(0); + gt1x_charger_switch(SWITCH_ON); +#endif + + gt1x_halt = 0; + gt1x_irq_enable(); + +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + + GTP_DEBUG("Resume end."); + return 0; +} + +s32 gt1x_init(void) +{ + s32 ret = -1; + s32 retry = 0; + u8 reg_val[1]; + + while (retry++ < GTP_RETRY_3) { + gt1x_init_failed = 0; + /* check main system firmware */ + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_MAINSYS, reg_val, 1); + if (ret != 0) { + gt1x_init_failed = 1; + gt1x_reset_guitar(); + continue; + } else if (reg_val[0] != 0xBE) { + GTP_ERROR("Check main system not pass[0x%2X].", reg_val[0]); + gt1x_init_failed = 1; + msleep(20); + } + +#ifndef CONFIG_GTP_AUTO_UPDATE + /* debug info */ + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_SUBSYS, reg_val, 1); + if (!ret && reg_val[0] == 0xAA) { + GTP_ERROR("Check subsystem not pass[0x%2X].", reg_val[0]); + } +#endif + break; + } + + /* if the initialization fails, set default setting */ + if (gt1x_init_failed) { + GTP_ERROR("Init failed, use default setting"); + gt1x_abs_x_max = GTP_MAX_WIDTH; + gt1x_abs_y_max = GTP_MAX_HEIGHT; + gt1x_int_type = GTP_INT_TRIGGER; + gt1x_wakeup_level = GTP_WAKEUP_LEVEL; + } + + /* get chip type */ + ret = gt1x_get_chip_type(); + if (ret != 0) + GTP_ERROR("Get chip type failed!"); + + /* read version information */ + ret = gt1x_read_version(>1x_version); + if (ret != 0) + GTP_ERROR("Get verision failed!"); + + /* init and send configs */ + ret = gt1x_init_panel(); + if (ret != 0) + GTP_ERROR("Init panel failed."); + + gt1x_workqueue = create_singlethread_workqueue("gt1x_workthread"); + if (gt1x_workqueue == NULL) + GTP_ERROR("Create workqueue failed!"); + + /* init auxiliary node and functions */ + gt1x_init_debug_node(); + +#ifdef CONFIG_GTP_CREATE_WR_NODE + gt1x_init_tool_node(); +#endif + +#if defined(CONFIG_GTP_GESTURE_WAKEUP) || defined(CONFIG_GTP_HOTKNOT) + gt1x_init_node(); +#endif + +#ifdef CONFIG_GTP_PROXIMITY + gt1x_ps_init(); +#endif + +#ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_init_charger(); + gt1x_charger_config(1); + gt1x_charger_switch(SWITCH_ON); +#endif + +#ifdef CONFIG_GTP_SMART_COVER + gt1x_smart_cover_init(); +#endif + +#ifdef CONFIG_GTP_WITH_STYLUS + gt1x_pen_init(); +#endif + + return ret; +} + +void gt1x_deinit(void) +{ + gt1x_deinit_debug_node(); + +#if defined(CONFIG_GTP_GESTURE_WAKEUP) || defined(CONFIG_GTP_HOTKNOT) + gt1x_deinit_node(); +#endif + +#ifdef CONFIG_GTP_CREATE_WR_NODE + gt1x_deinit_tool_node(); +#endif + +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_deinit_esd_protect(); +#endif + +#ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_OFF); +#endif + +#ifdef CONFIG_GTP_PROXIMITY + gt1x_ps_deinit(); +#endif + +#ifdef CONFIG_GTP_SMART_COVER + gt1x_smart_cover_deinit(); +#endif + + if (sysfs_rootdir) { + kobject_del(sysfs_rootdir); + sysfs_rootdir = NULL; + } + + if (gt1x_workqueue) { + destroy_workqueue(gt1x_workqueue); + } + +} + diff --git a/drivers/input/touchscreen/gt1x/gt1x_generic.h b/drivers/input/touchscreen/gt1x/gt1x_generic.h new file mode 100755 index 00000000000..b74b7d8eb29 --- /dev/null +++ b/drivers/input/touchscreen/gt1x/gt1x_generic.h @@ -0,0 +1,517 @@ +/* drivers/input/touchscreen/gt1x_generic.h + * + * 2010 - 2017 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.6 + */ + +#ifndef _GT1X_GENERIC_H_ +#define _GT1X_GENERIC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#ifdef CONFIG_OF +#include +#include +#endif +#ifdef CONFIG_FB +#include +#include +#endif +#include + + +#define GTP_DRIVER_VERSION "V1.6<2016/11/02>" +#define GTP_I2C_NAME "Goodix-TS" +#define GT1X_DEBUG_PROC_FILE "gt1x_debug" +#define GTP_POLL_TIME 10 +#define GTP_ADDR_LENGTH 2 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 240 +#define GTP_CONFIG_ORG_LENGTH 239 +#define GTP_CONFIG_EXT_LENGTH 128 +#define GTP_MAX_I2C_XFER_LEN 250 +#define SWITCH_OFF 0 +#define SWITCH_ON 1 + +/* buffer used to store ges track points coor. */ +//#define GES_BUFFER_ADDR 0xA2A0 // GT1151 +#define GES_BUFFER_ADDR 0x8A40 // GT9L +//#define GES_BUFFER_ADDR 0x9734 // GT1152 +//#define GES_BUFFER_ADDR 0xBDA8 // GT9286 +//#define GES_BUFFER_ADDR 0xBC74 // GT6286 +#ifndef GES_BUFFER_ADDR +#warning [GOODIX] need define GES_BUFFER_ADDR . +#endif + +#define KEY_GES_REGULAR KEY_F2 // regular gesture-key +#define KEY_GES_CUSTOM KEY_F3 //customize gesture-key + +#ifdef CONFIG_GTP_DEBUG_ON +#define GTP_DEBUG_ON 1 +#else +#define GTP_DEBUG_ON 0 +#endif + +#ifdef CONFIG_GTP_DEBUG_ARRAY_ON +#define GTP_DEBUG_ARRAY_ON 1 +#else +#define GTP_DEBUG_ARRAY_ON 0 +#endif + +#ifdef CONFIG_GTP_DEBUG_FUNC_ON +#define GTP_DEBUG_FUNC_ON 1 +#else +#define GTP_DEBUG_FUNC_ON 0 +#endif + +#ifdef CONFIG_GTP_CUSTOM_CFG +#define GTP_MAX_HEIGHT 800 +#define GTP_MAX_WIDTH 480 +#define GTP_INT_TRIGGER 1 //0:Rising 1:Falling +#define GTP_WAKEUP_LEVEL 1 +#else +#define GTP_MAX_HEIGHT 800 +#define GTP_MAX_WIDTH 480 +#define GTP_INT_TRIGGER 1 +#define GTP_WAKEUP_LEVEL 1 +#endif + +#define GTP_MAX_TOUCH 10 + +#ifdef CONFIG_GTP_WITH_STYLUS +#define GTP_STYLUS_KEY_TAB {BTN_STYLUS, BTN_STYLUS2} +#endif + +#ifdef CONFIG_GTP_HAVE_TOUCH_KEY +#define GTP_KEY_TAB {KEY_BACK, KEY_HOMEPAGE, KEY_MENU, KEY_SEARCH} +#define GTP_MAX_KEY_NUM 4 +#endif + +#define GTP_REG_MATRIX_DRVNUM 0x8069 +#define GTP_REG_MATRIX_SENNUM 0x806A +#define GTP_REG_RQST 0x8044 +#define GTP_REG_BAK_REF 0x90EC +#define GTP_REG_MAIN_CLK 0x8020 +#define GTP_REG_HAVE_KEY 0x8057 +#define GTP_REG_HN_STATE 0x8800 + +#define GTP_REG_WAKEUP_GESTURE 0x814C +#define GTP_REG_WAKEUP_GESTURE_DETAIL 0xA2A0 // need change +#define GTP_BAK_REF_PATH "/data/gt1x_ref.bin" +#define GTP_MAIN_CLK_PATH "/data/gt1x_clk.bin" + +/* request type */ +#define GTP_RQST_CONFIG 0x01 +#define GTP_RQST_BAK_REF 0x02 +#define GTP_RQST_RESET 0x03 +#define GTP_RQST_MAIN_CLOCK 0x04 +#define GTP_RQST_HOTKNOT_CODE 0x20 +#define GTP_RQST_RESPONDED 0x00 +#define GTP_RQST_IDLE 0xFF + +#define HN_DEVICE_PAIRED 0x80 +#define HN_MASTER_DEPARTED 0x40 +#define HN_SLAVE_DEPARTED 0x20 +#define HN_MASTER_SEND 0x10 +#define HN_SLAVE_RECEIVED 0x08 + +/*Register define */ +#define GTP_READ_COOR_ADDR 0x814E +#define GTP_REG_CMD 0x8040 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_CONFIG_DATA 0x8050 +#define GTP_REG_CONFIG_RESOLUTION 0x8051 +#define GTP_REG_CONFIG_TRIGGER 0x8056 +#define GTP_REG_CONFIG_CHECKSUM 0x813C +#define GTP_REG_CONFIG_UPDATE 0x813E +#define GTP_REG_EXT_CFG_FLAG 0x805A +#define GTP_REG_EXT_CONFIG 0xBF7B +#define GTP_REG_VERSION 0x8140 +#define GTP_REG_HW_INFO 0x4220 +#define GTP_REG_REFRESH_RATE 0x8056 +#define GTP_REG_ESD_CHECK 0x8043 +#define GTP_REG_FLASH_PASSBY 0x8006 +#define GTP_REG_HN_PAIRED 0x81AA +#define GTP_REG_HN_MODE 0x81A8 +#define GTP_REG_MODULE_SWITCH3 0x8058 +#define GTP_REG_FW_CHK_MAINSYS 0x41E4 +#define GTP_REG_FW_CHK_SUBSYS 0x5095 + +#define set_reg_bit(reg,pos,val) ((reg)=((reg) & (~(1<<(pos))))|(!!(val)<<(pos))) + +/* cmd define */ +#define GTP_CMD_SLEEP 0x05 +#define GTP_CMD_CHARGER_ON 0x06 +#define GTP_CMD_CHARGER_OFF 0x07 +#define GTP_CMD_GESTURE_WAKEUP 0x08 +#define GTP_CMD_CLEAR_CFG 0x10 +#define GTP_CMD_ESD 0xAA +#define GTP_CMD_HN_TRANSFER 0x22 +#define GTP_CMD_HN_EXIT_SLAVE 0x28 + +/* define offset in the config*/ +#define RESOLUTION_LOC (GTP_REG_CONFIG_RESOLUTION - GTP_REG_CONFIG_DATA) +#define TRIGGER_LOC (GTP_REG_CONFIG_TRIGGER - GTP_REG_CONFIG_DATA) +#define MODULE_SWITCH3_LOC (GTP_REG_MODULE_SWITCH3 - GTP_REG_CONFIG_DATA) + +#ifdef CONFIG_GTP_WARP_X_ON +#define GTP_WARP_X(x_max, x) ( x_max - 1 - x ) +#else +#define GTP_WARP_X(x_max, x) x +#endif + +#ifdef CONFIG_GTP_WARP_Y_ON +#define GTP_WARP_Y(y_max, y) ( y_max - 1 - y ) +#else +#define GTP_WARP_Y(y_max, y) y +#endif + +#define IS_NUM_OR_CHAR(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= '0' && (x) <= '9')) + +//Log define +#define GTP_INFO(fmt,arg...) pr_debug("<>[%s:%d] "fmt"\n", __func__, __LINE__, ##arg) +#define GTP_ERROR(fmt,arg...) pr_err("<>[%s:%d] "fmt"\n", __func__, __LINE__, ##arg) +#define GTP_DEBUG(fmt,arg...) do{\ + if(GTP_DEBUG_ON)\ + pr_err("<>[%s:%d]"fmt"\n",__func__, __LINE__, ##arg);\ + }while(0) +#define GTP_DEBUG_ARRAY(array, num) do{\ + s32 i;\ + u8* a = array;\ + if(GTP_DEBUG_ARRAY_ON)\ + {\ + printk("<>");\ + for (i = 0; i < (num); i++)\ + {\ + printk("%02x ", (a)[i]);\ + if ((i + 1 ) %10 == 0)\ + {\ + printk("\n<>");\ + }\ + }\ + printk("\n");\ + }\ + }while(0) +#define GTP_DEBUG_FUNC() do{\ + if(GTP_DEBUG_FUNC_ON)\ + printk("<> Func:%s@Line:%d\n",__func__,__LINE__);\ + }while(0) + +#define GTP_SWAP(x, y) do{\ + typeof(x) z = x;\ + x = y;\ + y = z;\ + }while (0) + +#pragma pack(1) +struct gt1x_version_info { + u8 product_id[5]; + u32 patch_id; + u32 mask_id; + u8 sensor_id; + u8 match_opt; +}; +#pragma pack() + +typedef enum { + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +} DOZE_T; + +typedef enum { + CHIP_TYPE_GT1X = 0, + CHIP_TYPE_GT2X = 1, + CHIP_TYPE_NONE = 0xFF +} gt1x_chip_type_t; + +#define _ERROR(e) ((0x01 << e) | (0x01 << (sizeof(s32) * 8 - 1))) +#define ERROR _ERROR(1) //for common use +//system relevant +#define ERROR_IIC _ERROR(2) //IIC communication error. +#define ERROR_MEM _ERROR(3) //memory error. + +//system irrelevant +#define ERROR_HN_VER _ERROR(10) //HotKnot version error. +#define ERROR_CHECK _ERROR(11) //Compare src and dst error. +#define ERROR_RETRY _ERROR(12) //Too many retries. +#define ERROR_PATH _ERROR(13) //Mount path error +#define ERROR_FW _ERROR(14) +#define ERROR_FILE _ERROR(15) +#define ERROR_VALUE _ERROR(16) //Illegal value of variables + +#define GTP_RETRY_3 3 +#define GTP_RETRY_5 5 + +/* bit operation */ +#define SET_BIT(data, flag) ((data) |= (flag)) +#define CLR_BIT(data, flag) ((data) &= ~(flag)) +#define CHK_BIT(data, flag) ((data) & (flag)) + +/* touch states */ +#define BIT_TOUCH 0x01 +#define BIT_TOUCH_KEY 0x02 +#define BIT_STYLUS 0x04 +#define BIT_STYLUS_KEY 0x08 +#define BIT_HOVER 0x10 + +#include +struct i2c_msg; + +/* Export global variables and functions */ + +/* Export from gt1x_extents.c and gt1x_firmware.h */ +#ifdef CONFIG_GTP_HOTKNOT +extern u8 hotknot_enabled; +extern u8 hotknot_transfer_mode; +extern u8 gt1x_patch_jump_fw[]; +extern u8 hotknot_auth_fw[]; +extern u8 hotknot_transfer_fw[]; +extern void hotknot_wakeup_block(void); +#ifdef CONFIG_HOTKNOT_BLOCK_RW +extern s32 hotknot_paired_flag; +extern s32 hotknot_event_handler(u8 * data); +#endif +#endif //GTP_HOTKNOT + +extern s32 gt1x_init_node(void); +extern void gt1x_deinit_node(void); + +#ifdef CONFIG_GTP_GESTURE_WAKEUP +extern DOZE_T gesture_doze_status; +extern int gesture_enabled; +extern void gt1x_gesture_debug(int on) ; +extern s32 gesture_event_handler(struct input_dev *dev); +extern s32 gesture_enter_doze(void); +extern void gesture_clear_wakeup_data(void); +#endif + +struct goodix_pinctrl { + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_wakeup; + struct pinctrl_state *pinctrl_normal; + struct pinctrl_state *pinctrl_poweroff; + struct pinctrl_state *pinctrl_sleep; +}; + +/* Export from gt1x.c */ +extern struct goodix_pinctrl gt_pinctrl; +extern void gt1x_touch_down(s32 x, s32 y, s32 size, s32 id); +extern void gt1x_touch_up(s32 id); +extern int gt1x_power_switch(s32 state); +extern void gt1x_irq_enable(void); +extern void gt1x_irq_disable(void); +extern int gt1x_debug_proc(u8 * buf, int count); + +struct fw_update_info { + int update_type; + int status; + int progress; + int max_progress; + int force_update; + struct fw_info *firmware_info; + u32 fw_length; + const struct firmware *fw; + + // file update + char *fw_name; + u8 *buffer; + mm_segment_t old_fs; + struct file *fw_file; + + // header update + u8 *fw_data; +}; + +/* Export form gt1x_update.c */ +extern struct fw_update_info update_info; + +extern u8 gt1x_default_FW[]; +extern int gt1x_hold_ss51_dsp(void); +extern int gt1x_auto_update_proc(void *data); +extern int gt1x_update_firmware(void *filename); + +extern void gt1x_enter_update_mode(void); +extern void gt1x_leave_update_mode(void); +extern int gt1x_hold_ss51_dsp_no_reset(void); +extern int gt1x_load_patch(u8 * patch, u32 patch_size, int offset, int bank_size); +extern int gt1x_startup_patch(void); + +/* Export from gt1x_tool.c */ +#ifdef CONFIG_GTP_CREATE_WR_NODE +extern int gt1x_init_tool_node(void); +extern void gt1x_deinit_tool_node(void); +#endif + +/* Export from gt1x_generic.c */ +extern struct i2c_client *gt1x_i2c_client; + +extern gt1x_chip_type_t gt1x_chip_type; +extern struct gt1x_version_info gt1x_version; + +extern s32 _do_i2c_read(struct i2c_msg *msgs, u16 addr, u8 * buffer, s32 len); +extern s32 _do_i2c_write(struct i2c_msg *msg, u16 addr, u8 * buffer, s32 len); +extern s32 gt1x_i2c_write(u16 addr, u8 * buffer, s32 len); +extern s32 gt1x_i2c_read(u16 addr, u8 * buffer, s32 len); +extern s32 gt1x_i2c_read_dbl_check(u16 addr, u8 * buffer, s32 len); + +extern u8 gt1x_int_type; +extern u32 gt1x_abs_x_max; +extern u32 gt1x_abs_y_max; +extern u8 gt1x_init_failed; +extern int gt1x_halt; +extern volatile int gt1x_rawdiff_mode; + +extern s32 gt1x_init(void); +extern void gt1x_deinit(void); +extern s32 gt1x_read_version(struct gt1x_version_info *ver_info); +extern s32 gt1x_init_panel(void); +extern s32 gt1x_get_chip_type(void); +extern s32 gt1x_request_event_handler(void); +extern int gt1x_send_cmd(u8 cmd, u8 data); +extern s32 gt1x_send_cfg(u8 * config, int cfg_len); +extern void gt1x_select_addr(void); +extern s32 gt1x_reset_guitar(void); +extern void gt1x_power_reset(void); +extern int gt1x_parse_config(char *filename, u8 * gt1x_config); +extern s32 gt1x_touch_event_handler(u8 * data, struct input_dev *dev, struct input_dev *pen_dev); +extern int gt1x_suspend(void); +extern int gt1x_resume(void); + +#ifdef CONFIG_GTP_HAVE_TOUCH_KEY +extern const u16 gt1x_touch_key_array[]; +#endif + +#ifdef CONFIG_GTP_WITH_STYLUS +extern struct input_dev *pen_dev; +extern void gt1x_pen_up(s32 id); +extern void gt1x_pen_down(s32 x, s32 y, s32 size, s32 id); +#endif + +#ifdef CONFIG_GTP_PROXIMITY +extern u8 gt1x_proximity_flag; +extern int gt1x_prox_event_handler(u8 * data); +#endif + +#ifdef CONFIG_GTP_SMART_COVER +extern int gt1x_parse_sc_cfg(int sensor_id); +#endif + +#ifdef CONFIG_GTP_ESD_PROTECT +extern void gt1x_init_esd_protect(void); +extern void gt1x_esd_switch(s32 on); +#endif + +#ifdef CONFIG_GTP_CHARGER_SWITCH +extern u32 gt1x_get_charger_status(void); +extern void gt1x_charger_switch(s32 on); +extern void gt1x_charger_config(s32 dir_update); +extern int gt1x_parse_chr_cfg(int sensor_id); +#endif + +#define IIC_MAX_TRANSFER_SIZE 250 + +#ifdef CONFIG_MTK_PLATFORM +/* MTK platform */ +#include +#ifdef CONFIG_MTK_BOOT +#include "mt_boot_common.h" +#endif +#include +#include +#ifndef MT6589 +#include +#endif +#include "tpd.h" +#include "upmu_common.h" + +#define GTP_GPIO_AS_INT(pin) tpd_gpio_as_int(pin) +#define GTP_GPIO_OUTPUT(pin, level) tpd_gpio_output(pin, level) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)) +#define GTP_MTK_LEGACY +#endif + +#define PLATFORM_MTK +#define GTP_I2C_ADDRESS 0x5D +#define TPD_I2C_NUMBER 1 + +#ifdef CONFIG_MTK_I2C_EXTENSION +#define TPD_SUPPORT_I2C_DMA 1 +#else +#define TPD_SUPPORT_I2C_DMA 0 +#endif + +#if defined(CONFIG_MTK_LEGACY) +#define TPD_POWER_SOURCE_CUSTOM MT6328_POWER_LDO_VGP1 +#endif + +#ifdef MT6589 +extern void mt65xx_eint_unmask(unsigned int line); +extern void mt65xx_eint_mask(unsigned int line); +#define mt_eint_mask mt65xx_eint_mask +#define mt_eint_unmask mt65xx_eint_unmask +#endif + +#define IIC_DMA_MAX_TRANSFER_SIZE 250 +#define I2C_MASTER_CLOCK 300 +#define TPD_HAVE_CALIBRATION +#define TPD_CALIBRATION_MATRIX {962,0,0,0,1600,0,0,0}; + +extern void tpd_on(void); +extern void tpd_off(void); + +#else +/* Generic Platform(Qcom or othter) */ +#ifdef CONFIG_OF +extern int gt1x_rst_gpio; +extern int gt1x_int_gpio; +#define GTP_RST_PORT gt1x_rst_gpio +#define GTP_INT_PORT gt1x_int_gpio +#else +#define GTP_RST_PORT 102 +#define GTP_INT_PORT 52 +#endif + +#define GTP_GPIO_AS_INPUT(pin) gpio_direction_input(pin) +#define GTP_GPIO_AS_INT(pin) GTP_GPIO_AS_INPUT(pin) +#define GTP_GPIO_OUTPUT(pin,level) gpio_direction_output(pin,level) +#define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING,\ + IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH} + +#endif /* CONFIG_MTK_PLATFORM */ + +#endif // _GT1X_GENERIC_H_ + diff --git a/drivers/input/touchscreen/gt1x/gt1x_tools.c b/drivers/input/touchscreen/gt1x/gt1x_tools.c new file mode 100755 index 00000000000..29395b29c91 --- /dev/null +++ b/drivers/input/touchscreen/gt1x/gt1x_tools.c @@ -0,0 +1,468 @@ +/* drivers/input/touchscreen/goodix_tool.c + * + * 2010 - 2017 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.6 + */ + +#include +#include +#include +#include +#include "gt1x_generic.h" + +static ssize_t gt1x_tool_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos); +static ssize_t gt1x_tool_write(struct file *filp, const char __user *buffer, size_t count, loff_t * ppos); + + +static int gt1x_tool_release(struct inode *inode, struct file *filp); +static int gt1x_tool_open(struct inode *inode,struct file *file); + +#pragma pack(1) +typedef struct { + u8 wr; //write read flag£¬0:R 1:W 2:PID 3: + u8 flag; //0:no need flag/int 1: need flag 2:need int + u8 flag_addr[2]; //flag address + u8 flag_val; //flag val + u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:< + u16 circle; //polling cycle + u8 times; //plling times + u8 retry; //I2C retry times + u16 delay; //delay befor read or after write + u16 data_len; //data length + u8 addr_len; //address length + u8 addr[2]; //address + u8 res[3]; //reserved + u8 *data; //data pointer +} st_cmd_head; +#pragma pack() +static st_cmd_head cmd_head; + +static s32 DATA_LENGTH = 0; +static s8 IC_TYPE[16] = "GT1X"; + +#define UPDATE_FUNCTIONS +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*)) + +static char procname[20] = { 0 }; + +static struct proc_dir_entry *gt1x_tool_proc_entry; +static struct file_operations gt1x_tool_fops = { + .read = gt1x_tool_read, + .write = gt1x_tool_write, + .open = gt1x_tool_open, + .release = gt1x_tool_release, + .owner = THIS_MODULE, +}; + +static void set_tool_node_name(char *procname) +{ + + int v0 = 0, v1 = 0, v2 = 0; + + sscanf(UTS_RELEASE, "%d.%d.%d", &v0, &v1, &v2); + sprintf(procname, "gmnode%02d%02d%02d", v0, v1, v2); +} + +int gt1x_init_tool_node(void) +{ + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.wr = 1; //if the first operation is read, will return fail. + cmd_head.data = kzalloc(DATA_LENGTH_UINT, GFP_KERNEL); + if (NULL == cmd_head.data) { + GTP_ERROR("Apply for memory failed."); + return -1; + } + DATA_LENGTH = DATA_LENGTH_UINT - GTP_ADDR_LENGTH; + + set_tool_node_name(procname); + + gt1x_tool_proc_entry = proc_create(procname, 0666, NULL, >1x_tool_fops); + if (gt1x_tool_proc_entry == NULL) { + GTP_ERROR("CAN't create proc entry /proc/%s.", procname); + return -1; + } else { + GTP_INFO("Created proc entry /proc/%s.", procname); + } + return 0; +} + +void gt1x_deinit_tool_node(void) +{ + remove_proc_entry(procname, NULL); + kfree(cmd_head.data); + cmd_head.data = NULL; +} + +static s32 tool_i2c_read(u8 * buf, u16 len) +{ + u16 addr = (buf[0] << 8) + buf[1]; + if (!gt1x_i2c_read(addr, &buf[2], len)) { + return 1; + } + return -1; +} + +static s32 tool_i2c_write(u8 * buf, u16 len) +{ + u16 addr = (buf[0] << 8) + buf[1]; + if (!gt1x_i2c_write(addr, &buf[2], len - 2)) { + return 1; + } + return -1; +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32) ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* +Function: + Comfirm function. +Input: + None. +Output: + Return write length. +********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + + memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); + + for (i = 0; i < cmd_head.times; i++) { + if (tool_i2c_read(buf, 1) <= 0) { + GTP_ERROR("Read flag data failed!"); + return -1; + } + + if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation)) { + GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]); + GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) { + GTP_ERROR("Didn't get the flag to continue!"); + return -1; + } + + return 0; +} + +/******************************************************* +Function: + Goodix tool write function. +Input: + standard proc write function param. +Output: + Return write length. +********************************************************/ +static ssize_t gt1x_tool_write(struct file *filp, const char __user * buff, size_t len, loff_t * data) +{ + u64 ret = 0; + u8 temp_data = 0; + + GTP_DEBUG_FUNC(); + //GTP_DEBUG_ARRAY((u8 *) buff, len); + + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if (ret) { + GTP_ERROR("copy_from_user failed."); + } + + ret = copy_from_user(&temp_data, &buff[CMD_HEAD_LENGTH], 1); + if (ret) { + GTP_ERROR("copy_from_user failed."); + } + + GTP_DEBUG("wr :0x%02x.", cmd_head.wr); + /* + GTP_DEBUG("flag:0x%02x.", cmd_head.flag); + GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]); + GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val); + GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation); + GTP_DEBUG("circle :%d.", (s32)cmd_head.circle); + GTP_DEBUG("times :%d.", (s32)cmd_head.times); + GTP_DEBUG("retry :%d.", (s32)cmd_head.retry); + GTP_DEBUG("delay :%d.", (s32)cmd_head.delay); + GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len); + GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len); + GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); + GTP_DEBUG("len:%d.", (s32)len); + GTP_DEBUG("buf[20]:0x%02x.", temp_data); + */ + + if (1 == cmd_head.wr) { + u16 addr, data_len, pos; + + if (1 == cmd_head.flag) { + if (comfirm()) { + GTP_ERROR("[WRITE]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head.flag) { + //Need interrupt! + } + + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + data_len = cmd_head.data_len; + pos = 0; + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH + pos], len); + if (ret) { + GTP_ERROR("[WRITE]copy_from_user failed."); + return -1; + } + cmd_head.data[0] = ((addr >> 8) & 0xFF); + cmd_head.data[1] = (addr & 0xFF); + + GTP_DEBUG_ARRAY(cmd_head.data, len + GTP_ADDR_LENGTH); + + if (tool_i2c_write(cmd_head.data, len + GTP_ADDR_LENGTH) <= 0) { + GTP_ERROR("[WRITE]Write data failed!"); + return -1; + } + addr += len; + pos += len; + data_len -= len; + } + + if (cmd_head.delay) { + msleep(cmd_head.delay); + } + + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (3 == cmd_head.wr) { //gt1x unused + + memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (5 == cmd_head.wr) { //? + + //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + return cmd_head.data_len + CMD_HEAD_LENGTH; + } else if (7 == cmd_head.wr) { //disable irq! + gt1x_irq_disable(); +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif + return CMD_HEAD_LENGTH; + } else if (9 == cmd_head.wr) { //enable irq! + gt1x_irq_enable(); +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + return CMD_HEAD_LENGTH; + } else if (17 == cmd_head.wr) { + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if (ret) { + GTP_ERROR("copy_from_user failed."); + return -1; + } + + if (cmd_head.data[GTP_ADDR_LENGTH]) { + GTP_DEBUG("gtp enter rawdiff."); + gt1x_rawdiff_mode = true; + } else { + gt1x_rawdiff_mode = false; + GTP_DEBUG("gtp leave rawdiff."); + } + + return CMD_HEAD_LENGTH; + } else if (11 == cmd_head.wr) { + gt1x_enter_update_mode(); + } else if (13 == cmd_head.wr) { + gt1x_leave_update_mode(); + } else if (15 == cmd_head.wr) { + struct task_struct *thrd = NULL; + memset(cmd_head.data, 0, cmd_head.data_len + 1); + //memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + ret = copy_from_user(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len); + if (ret) { + GTP_ERROR("copy_from_user failed."); + } + GTP_DEBUG("update firmware, filename: %s", cmd_head.data); + thrd = kthread_run(gt1x_update_firmware, (void *)cmd_head.data, "GT1x FW Update"); + if (IS_ERR(thrd)) { + return PTR_ERR(thrd); + } + } + + return CMD_HEAD_LENGTH; +} + +static u8 devicecount = 0; +static int gt1x_tool_open(struct inode *inode,struct file *file) +{ + if (devicecount > 0) { + return -ERESTARTSYS; + GTP_ERROR("tools open failed!"); + } + + devicecount++; + return 0; +} + +static int gt1x_tool_release(struct inode *inode, struct file *filp) +{ + devicecount--; + return 0; +} +/******************************************************* +Function: + Goodix tool read function. +Input: + standard proc read function param. +Output: + Return read length. +********************************************************/ +static ssize_t gt1x_tool_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) +{ + s32 ret = 0; + + GTP_DEBUG_FUNC(); + if(*ppos) { + GTP_DEBUG("[PARAM]size: %zd, *ppos: %d", count, (int)*ppos); + *ppos = 0; + return 0; + } + + if (cmd_head.wr % 2) { + GTP_ERROR("[READ] invaild operator fail!"); + return -1; + } else if (!cmd_head.wr) { + /* general i2c read */ + u16 addr, data_len, len, loc; + + if (1 == cmd_head.flag) { + if (comfirm()) { + GTP_ERROR("[READ]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head.flag) { + //Need interrupt! + } + + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + data_len = cmd_head.data_len; + loc = 0; + + GTP_DEBUG("[READ] ADDR:0x%04X.", addr); + GTP_DEBUG("[READ] Length: %d", data_len); + + if (cmd_head.delay) { + msleep(cmd_head.delay); + } + + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + cmd_head.data[0] = (addr >> 8) & 0xFF; + cmd_head.data[1] = (addr & 0xFF); + if (tool_i2c_read(cmd_head.data, len) <= 0) { + GTP_ERROR("[READ]Read data failed!"); + return -1; + } + //memcpy(&buffer[loc], &cmd_head.data[GTP_ADDR_LENGTH], len); + if (copy_to_user(&buffer[loc], &cmd_head.data[GTP_ADDR_LENGTH], len)) + { + GTP_ERROR("[Read]copy_to_user failed."); + return -1; + } + data_len -= len; + addr += len; + loc += len; + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len); + } + *ppos += cmd_head.data_len; + return cmd_head.data_len; + } else if (2 == cmd_head.wr) { + ret = copy_to_user(buffer, IC_TYPE, sizeof(IC_TYPE)); + *ppos += sizeof(IC_TYPE); + GTP_DEBUG("Return ic type:%s len:%d.", IC_TYPE, sizeof(IC_TYPE)); + return ret; + } else if (4 == cmd_head.wr) + { + u8 progress_buf[4]; + /* read fw update progress */ + progress_buf[0] = update_info.progress >> 8; + progress_buf[1] = update_info.progress & 0xff; + progress_buf[2] = update_info.max_progress >> 8; + progress_buf[3] = update_info.max_progress & 0xff; + if (copy_to_user(buffer, progress_buf, 4)) + { + GTP_ERROR("[Read]copy_to_user failed."); + return -1; + } + *ppos += 4; + return 4; + } else if (6 == cmd_head.wr) { + //Read error code! + return -1; + } else if (8 == cmd_head.wr) { + /* Read driver version */ + s32 tmp_len; + tmp_len = strlen(GTP_DRIVER_VERSION); + //memcpy(buffer, GTP_DRIVER_VERSION, tmp_len); + if (copy_to_user(buffer, GTP_DRIVER_VERSION, tmp_len) || copy_to_user(&buffer[tmp_len], "\n", 1)) + { + GTP_ERROR("[Read]copy_to_user failed."); + return -1; + } + //buffer[tmp_len] = 0; + *ppos += tmp_len + 1; + return (tmp_len + 1); + } + *ppos += cmd_head.data_len; + return cmd_head.data_len; +} diff --git a/drivers/input/touchscreen/gt1x/gt1x_update.c b/drivers/input/touchscreen/gt1x/gt1x_update.c new file mode 100755 index 00000000000..4ab7a9beaa6 --- /dev/null +++ b/drivers/input/touchscreen/gt1x/gt1x_update.c @@ -0,0 +1,1494 @@ +/* drivers/input/touchscreen/gt1x_update.c + * + * 2010 - 2017 Goodix Technology. + * + * 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 a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * 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. + * + * Version: 1.6 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gt1x_generic.h" + +#define GT1X_FW_NAME "gt1x_fw.bin" +#define UPDATE_FILE_PATH_1 "/data/_goodix_update_.bin" +#define UPDATE_FILE_PATH_2 "/sdcard/_goodix_update_.bin" + +#define CONFIG_FILE_PATH_1 "/data/_gt1x_config_.cfg" +#define CONFIG_FILE_PATH_2 "/sdcard/_gt1x_config_.cfg" + +#define FOUND_FW_PATH_1 0x01 +#define FOUND_FW_PATH_2 0x02 +#define FOUND_CFG_PATH_1 0x04 +#define FOUND_CFG_PATH_2 0x08 + +#define PACK_SIZE 256 + +// hardware register define +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 +#define _bRW_MISCTL__DSP_MCU_PWR_ 0x4010 +#define _bRW_MISCTL__PATCH_AREA_EN_ 0x404D + +/* + 1. firmware structure + header: 128b + + offset size content + 0 4 firmware length + 4 2 checksum + 6 6 target MASK name + 12 3 target MASK version + 15 6 TP subsystem PID + 21 3 TP subsystem version + 24 1 subsystem count + 25 1 chip type 0x91: GT1X, 0x92: GT2X + 26 6 reserved + 32 8 subsystem info[0] + 32 8 subsystem info[1] + ..... + 120 8 subsystem info[11] + + body: followed header + + 128 N0 subsystem[0] + 128+N0 N1 subsystem[1] + .... + + 2. subsystem info structure + offset size content + 0 1 subsystem type + 1 2 subsystem length + 3 2 stored address in flash addr = value * 256 + 5 3 reserved + +*/ + +#define FW_HEAD_SIZE 128 +#define FW_HEAD_SUBSYSTEM_INFO_SIZE 8 +#define FW_HEAD_OFFSET_SUBSYSTEM_INFO_BASE 32 + +#define FW_SECTION_TYPE_SS51_ISP 0x01 +#define FW_SECTION_TYPE_SS51_PATCH 0x02 +#define FW_SECTION_TYPE_SS51_PATCH_OVERLAY 0x03 +#define FW_SECTION_TYPE_DSP 0x04 +#define FW_SECTION_TYPE_HOTKNOT 0x05 +#define FW_SECTION_TYPE_GESTURE 0x06 +#define FW_SECTION_TYPE_GESTURE_OVERLAY 0x07 +#define FW_SECTION_TYPE_FLASHLESS_FAST_POWER 0x08 + +#define UPDATE_TYPE_FILE 1 +#define UPDATE_TYPE_REQUEST 2 + +#define UPDATE_STATUS_IDLE 0 +#define UPDATE_STATUS_RUNNING 1 +#define UPDATE_STATUS_ABORT 2 + +struct fw_subsystem_info { + int type; + int length; + u32 address; + int offset; +}; + +#pragma pack(1) +struct fw_info { + u32 length; + u16 checksum; + u8 target_mask[6]; + u8 target_mask_version[3]; + u8 pid[6]; + u8 version[3]; + u8 subsystem_count; + u8 chip_type; + u8 reserved[6]; + struct fw_subsystem_info subsystem[12]; +}; +#pragma pack() + +struct fw_update_info update_info = { + .status = UPDATE_STATUS_IDLE, + .progress = 0, + .max_progress = 9, + .force_update = 0 +}; + +int gt1x_update_prepare(char *filename); +int gt1x_check_firmware(void); +u8 *gt1x_get_fw_data(u32 offset, int length); +int gt1x_update_judge(void); +int gt1x_run_ss51_isp(u8 * ss51_isp, int length); +int gt1x_burn_subsystem(struct fw_subsystem_info *subsystem); +u16 gt1x_calc_checksum(u8 * fw, u32 length); +int gt1x_recall_check(u8 * chk_src, u16 start_rd_addr, u16 chk_length); +void gt1x_update_cleanup(void); +int gt1x_check_subsystem_in_flash(struct fw_subsystem_info *subsystem); +int gt1x_read_flash(u32 addr, int length); +int gt1x_error_erase(void); +void dump_to_file(u16 addr, int length, char *filepath); +int gt1x_update_firmware(void *filename); +int gt1x_auto_update_proc(void *data); +static int gt1x_search_update_files(void); + +int gt1x_hold_ss51_dsp(void); +void gt1x_leave_update_mode(void); + +/** + * @return: return 0 if success, otherwise return a negative number + * which contains the error code. + */ +s32 gt1x_check_fs_mounted(char *path_name) +{ + struct path root_path; + struct path path; + s32 err; + + err = kern_path("/", LOOKUP_FOLLOW, &root_path); + if (err) + return ERROR_PATH; + + err = kern_path(path_name, LOOKUP_FOLLOW, &path); + if (err) { + err = ERROR_PATH; + goto check_fs_fail; + } + + if (path.mnt->mnt_sb == root_path.mnt->mnt_sb) { + // not mounted + err = ERROR_PATH; + } else { + err = 0; + } + + path_put(&path); +check_fs_fail: + path_put(&root_path); + return err; +} + +int gt1x_i2c_write_with_readback(u16 addr, u8 * buffer, int length) +{ + u8 buf[100]; + int ret = gt1x_i2c_write(addr, buffer, length); + if (ret) { + return ret; + } + ret = gt1x_i2c_read(addr, buf, length); + if (ret) { + return ret; + } + if (memcmp(buf, buffer, length)) { + return ERROR_CHECK; + } + return 0; +} + +#define getU32(a) ((u32)getUint((u8 *)(a), 4)) +#define getU16(a) ((u16)getUint((u8 *)(a), 2)) +u32 getUint(u8 * buffer, int len) +{ + u32 num = 0; + int i; + for (i = 0; i < len; i++) { + num <<= 8; + num += buffer[i]; + } + return num; +} + +int gt1x_auto_update_proc(void *data) +{ + int ret; + char *filename; + u8 config[GTP_CONFIG_ORG_LENGTH + GTP_CONFIG_EXT_LENGTH] = { 0 }; + + if (data == NULL) { + GTP_INFO("Start auto update thread from request..."); + gt1x_update_firmware(NULL); + return 0; + } + + GTP_INFO("Start auto update thread from file..."); + ret = gt1x_search_update_files(); + if (ret & (FOUND_FW_PATH_1 | FOUND_FW_PATH_2)) { + if (ret & FOUND_FW_PATH_1) { + filename = UPDATE_FILE_PATH_1; + } else { + filename = UPDATE_FILE_PATH_2; + } + gt1x_update_firmware(filename); + } + + if (ret & (FOUND_CFG_PATH_1 | FOUND_CFG_PATH_2)) { + if (ret & FOUND_CFG_PATH_1) { + filename = CONFIG_FILE_PATH_1; + } else { + filename = CONFIG_FILE_PATH_2; + } + + if (gt1x_parse_config(filename, config) > 0) { + ret = gt1x_i2c_write(GTP_REG_CONFIG_DATA, config, GTP_CONFIG_ORG_LENGTH); + if (ret < 0) { + GTP_ERROR("Update config failed!"); + return 0; + } + + /* extends config */ + if (config[0x805A - GTP_REG_CONFIG_DATA] & 0x40) { + ret = gt1x_i2c_write(GTP_REG_EXT_CONFIG, + &config[GTP_CONFIG_ORG_LENGTH], GTP_CONFIG_EXT_LENGTH); + + if (ret < 0) { + GTP_ERROR("Update ext config failed!"); + return 0; + } + } + + GTP_INFO("Update config successfully!"); + } + } + + return 0; +} + +static int gt1x_search_update_files(void) +{ + int retry = 20 * 2; //wait 10s(max) if fs is not ready + struct file *pfile = NULL; + mm_segment_t old_fs; + int found = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + GTP_INFO("Search firmware file..."); + while (retry-- > 0) { + msleep(500); + + // check if rootfs is ready + if (gt1x_check_fs_mounted("/data")) { + GTP_DEBUG("filesystem is not ready"); + continue; + } + // search firmware + pfile = filp_open(UPDATE_FILE_PATH_1, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pfile = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0); + if (!IS_ERR(pfile)) { + found |= FOUND_FW_PATH_2; + } + } else { + found |= FOUND_FW_PATH_1; + } + + if (!IS_ERR(pfile)) { + filp_close(pfile, NULL); + } + // search config file + pfile = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pfile = filp_open(CONFIG_FILE_PATH_2, O_RDONLY, 0); + if (!IS_ERR(pfile)) { + found |= FOUND_CFG_PATH_2; + } + } else { + found |= FOUND_CFG_PATH_1; + } + if (!IS_ERR(pfile)) { + filp_close(pfile, NULL); + } + + if (found) { + break; + } + + GTP_INFO("Not found firmware or config file, retry."); + } + set_fs(old_fs); + + return found; +} + +void gt1x_enter_update_mode(void) +{ + GTP_DEBUG("Enter FW update mode."); +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_OFF); +#endif +#ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_OFF); +#endif + gt1x_irq_disable(); +} + +int gt1x_update_firmware(void *filename) +{ + int i = 0; + int ret = 0; + u8 *p; + + if (update_info.status != UPDATE_STATUS_IDLE) { + GTP_ERROR("Update process is running!"); + return ERROR; + } + update_info.status = UPDATE_STATUS_RUNNING; + update_info.progress = 0; + + gt1x_enter_update_mode(); + + ret = gt1x_update_prepare(filename); + if (ret) { + update_info.status = UPDATE_STATUS_ABORT; + goto gt1x_update_exit; + } + + ret = gt1x_check_firmware(); + if (ret) { + update_info.status = UPDATE_STATUS_ABORT; + goto gt1x_update_exit; + } +#ifdef CONFIG_GTP_FW_UPDATE_VERIFY + update_info.max_progress = + 6 + update_info.firmware_info->subsystem_count; +#else + update_info.max_progress = + 3 + update_info.firmware_info->subsystem_count; +#endif + update_info.progress++; // 1 + + ret = gt1x_update_judge(); + if (ret) { + update_info.status = UPDATE_STATUS_ABORT; + goto gt1x_update_exit; + } + update_info.progress++; // 2 + + p = gt1x_get_fw_data(update_info.firmware_info->subsystem[0].offset, update_info.firmware_info->subsystem[0].length); + if (p == NULL) { + GTP_ERROR("get isp fail"); + ret = ERROR_FW; + update_info.status = UPDATE_STATUS_ABORT; + goto gt1x_update_exit; + } + update_info.progress++; // 3 + + ret = gt1x_run_ss51_isp(p, update_info.firmware_info->subsystem[0].length); + if (ret) { + GTP_ERROR("run isp fail"); + goto gt1x_update_exit; + } + update_info.progress++; // 4 + msleep(800); + + for (i = 1; i < update_info.firmware_info->subsystem_count; i++) { + GTP_INFO("subsystem: %d", update_info.firmware_info->subsystem[i].type); + GTP_INFO("Length: %d", update_info.firmware_info->subsystem[i].length); + GTP_INFO("Address: %d", update_info.firmware_info->subsystem[i].address); + + ret = gt1x_burn_subsystem(&(update_info.firmware_info->subsystem[i])); + if (ret) { + GTP_ERROR("burn subsystem fail!"); + goto gt1x_update_exit; + } + update_info.progress++; + } + +#ifdef CONFIG_GTP_FW_UPDATE_VERIFY + gt1x_reset_guitar(); + + p = gt1x_get_fw_data(update_info.firmware_info->subsystem[0].offset, update_info.firmware_info->subsystem[0].length); + if (p == NULL) { + GTP_ERROR("get isp fail"); + ret = ERROR_FW; + goto gt1x_update_exit; + } + update_info.progress++; + + ret = gt1x_run_ss51_isp(p, update_info.firmware_info->subsystem[0].length); + if (ret) { + GTP_ERROR("run isp fail"); + goto gt1x_update_exit; + } + update_info.progress++; + + GTP_INFO("Reset guitar & check firmware in flash."); + for (i = 1; i < update_info.firmware_info->subsystem_count; i++) { + GTP_INFO("subsystem: %d", update_info.firmware_info->subsystem[i].type); + GTP_INFO("Length: %d", update_info.firmware_info->subsystem[i].length); + GTP_INFO("Address: %d", update_info.firmware_info->subsystem[i].address); + + ret = gt1x_check_subsystem_in_flash(&(update_info.firmware_info->subsystem[i])); + if (ret) { + gt1x_error_erase(); + break; + } + } + update_info.progress++; +#endif + +gt1x_update_exit: + gt1x_update_cleanup(); + gt1x_leave_update_mode(); + gt1x_read_version(NULL); + if (ret) { + update_info.progress = 2 * update_info.max_progress; + GTP_ERROR("Update firmware failed!"); + return ret; + } else if (gt1x_init_failed) { + gt1x_read_version(>1x_version); + gt1x_init_panel(); + #ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_parse_chr_cfg(gt1x_version.sensor_id); + #endif + #ifdef CONFIG_GTP_SMART_COVER + gt1x_parse_sc_cfg(gt1x_version.sensor_id); + #endif + } + GTP_INFO("Update firmware succeefully!"); + + return ret; +} + +int gt1x_update_prepare(char *filename) +{ + int ret = 0; + int retry = 5; + + if (filename == NULL) { + update_info.fw_name = NULL; + update_info.fw = NULL; + ret = request_firmware(&update_info.fw, GT1X_FW_NAME, >1x_i2c_client->dev); + if (ret < 0) { + GTP_ERROR("Request firmware failed - %s (%d)", GT1X_FW_NAME, ret); + return ERROR_FW; + } + + update_info.update_type = UPDATE_TYPE_REQUEST; + update_info.fw_data = (u8*)update_info.fw->data; + update_info.fw_length = update_info.fw->size; + } else { + GTP_INFO("Firmware: %s", filename); + update_info.old_fs = get_fs(); + set_fs(KERNEL_DS); + update_info.fw_name = filename; + update_info.update_type = UPDATE_TYPE_FILE; + update_info.fw_file = filp_open(update_info.fw_name, O_RDONLY, 0); + if (IS_ERR(update_info.fw_file)) { + GTP_ERROR("Open update file(%s) error!", update_info.fw_name); + set_fs(update_info.old_fs); + return ERROR_FILE; + } + update_info.fw_file->f_op->llseek(update_info.fw_file, 0, SEEK_SET); + update_info.fw_length = update_info.fw_file->f_op->llseek(update_info.fw_file, 0, SEEK_END); + } + + while (retry > 0) { + retry--; + update_info.firmware_info = (struct fw_info *)kzalloc(sizeof(struct fw_info), GFP_KERNEL); + if (update_info.firmware_info == NULL) { + GTP_INFO("Alloc %zu bytes memory fail.", sizeof(struct fw_info)); + continue; + } else { + break; + } + } + if (retry <= 0) { + ret = ERROR_RETRY; + goto gt1x_update_pre_fail1; + } + + retry = 5; + while (retry > 0) { + update_info.buffer = (u8 *) kzalloc(1024 * 4, GFP_KERNEL); + if (update_info.buffer == NULL) { + GTP_ERROR("Alloc %d bytes memory fail.", 1024 * 4); + continue; + } else { + break; + } + } + if (retry <= 0) { + ret = ERROR_RETRY; + goto gt1x_update_pre_fail0; + } + + return 0; + +gt1x_update_pre_fail0: + kfree(update_info.firmware_info); +gt1x_update_pre_fail1: + if (update_info.update_type == UPDATE_TYPE_REQUEST) { + release_firmware(update_info.fw); + update_info.fw = NULL; + } else if (update_info.update_type == UPDATE_TYPE_FILE) { + filp_close(update_info.fw_file, NULL); + } + + return ret; +} + +void gt1x_update_cleanup(void) +{ + if (update_info.update_type == UPDATE_TYPE_FILE) { + if (update_info.fw_file != NULL) { + filp_close(update_info.fw_file, NULL); + update_info.fw_file = NULL; + } + set_fs(update_info.old_fs); + } else if (update_info.update_type == UPDATE_TYPE_REQUEST) { + if (update_info.fw) { + release_firmware(update_info.fw); + update_info.fw = NULL; + } + } + + if (update_info.buffer != NULL) { + kfree(update_info.buffer); + update_info.buffer = NULL; + } + if (update_info.firmware_info != NULL) { + kfree(update_info.firmware_info); + update_info.firmware_info = NULL; + } +} + +int gt1x_check_firmware(void) +{ + u16 checksum; + u16 checksum_in_header; + u8 *p; + struct fw_info *firmware_temp; + int i; + int offset; + + // compare file length with the length field in the firmware header + if (update_info.fw_length < FW_HEAD_SIZE) { + GTP_ERROR("Bad firmware!(file length: %d)", update_info.fw_length); + return ERROR_CHECK; + } + p = gt1x_get_fw_data(0, 6); + if (p == NULL) { + return ERROR_FW; + } + + if (getU32(p) + 6 != update_info.fw_length) { + GTP_ERROR("Bad firmware!(file length: %d, header define: %d)", update_info.fw_length, getU32(p)); + return ERROR_CHECK; + } + // check firmware's checksum + checksum_in_header = getU16(&p[4]); + checksum = 0; + for (i = 6; i < update_info.fw_length; i++) { + p = gt1x_get_fw_data(i, 1); + if (p == NULL) { + return ERROR_FW; + } + checksum += p[0]; + } + + if (checksum != checksum_in_header) { + GTP_ERROR("Bad firmware!(checksum: 0x%04X, header define: 0x%04X)", checksum, checksum_in_header); + return ERROR_CHECK; + } + // parse firmware + p = gt1x_get_fw_data(0, FW_HEAD_SIZE); + if (p == NULL) { + return ERROR_FW; + } + memcpy((u8 *) update_info.firmware_info, p, FW_HEAD_SIZE - 8 * 12); + update_info.firmware_info->pid[5] = 0; + + p = &p[FW_HEAD_OFFSET_SUBSYSTEM_INFO_BASE]; + firmware_temp = update_info.firmware_info; + offset = FW_HEAD_SIZE; + for (i = 0; i < firmware_temp->subsystem_count; i++) { + firmware_temp->subsystem[i].type = p[i * FW_HEAD_SUBSYSTEM_INFO_SIZE]; + firmware_temp->subsystem[i].length = getU16(&p[i * FW_HEAD_SUBSYSTEM_INFO_SIZE + 1]); + firmware_temp->subsystem[i].address = getU16(&p[i * FW_HEAD_SUBSYSTEM_INFO_SIZE + 3]) * 256; + firmware_temp->subsystem[i].offset = offset; + offset += firmware_temp->subsystem[i].length; + } + + // print update information + GTP_INFO("Update type: %s", update_info.update_type == UPDATE_TYPE_REQUEST ? "RequestFW" : "FileFW"); + GTP_INFO("Firmware length: %d", update_info.fw_length); + GTP_INFO("Firmware product: GT%s", update_info.firmware_info->pid); + GTP_INFO("Firmware patch: %02X%02X%02X", update_info.firmware_info->version[0], update_info.firmware_info->version[1], update_info.firmware_info->version[2]); + GTP_INFO("Firmware chip: 0x%02X", update_info.firmware_info->chip_type); + GTP_INFO("Subsystem count: %d", update_info.firmware_info->subsystem_count); + for (i = 0; i < update_info.firmware_info->subsystem_count; i++) { + GTP_DEBUG("------------------------------------------"); + GTP_DEBUG("Subsystem: %d", i); + GTP_DEBUG("Type: %d", update_info.firmware_info->subsystem[i].type); + GTP_DEBUG("Length: %d", update_info.firmware_info->subsystem[i].length); + GTP_DEBUG("Address: 0x%08X", update_info.firmware_info->subsystem[i].address); + GTP_DEBUG("Offset: %d", update_info.firmware_info->subsystem[i].offset); + } + + return 0; +} + +/** + * @return: return a pointer pointed at the content of firmware + * if success, otherwise return NULL. + */ +u8 *gt1x_get_fw_data(u32 offset, int length) +{ + int ret; + if (update_info.update_type == UPDATE_TYPE_FILE) { + update_info.fw_file->f_op->llseek(update_info.fw_file, offset, SEEK_SET); + ret = update_info.fw_file->f_op->read(update_info.fw_file, (char *)update_info.buffer, length, &update_info.fw_file->f_pos); + if (ret < 0) { + GTP_ERROR("Read data error!"); + return NULL; + } + return update_info.buffer; + } else { + return &update_info.fw_data[offset]; + } +} + +int gt1x_update_judge(void) +{ + int ret; + u8 reg_val[2] = {0}; + u8 retry = 2; + struct gt1x_version_info ver_info; + struct gt1x_version_info fw_ver_info; + + fw_ver_info.mask_id = (update_info.firmware_info->target_mask_version[0] << 16) + | (update_info.firmware_info->target_mask_version[1] << 8) + | (update_info.firmware_info->target_mask_version[2]); + fw_ver_info.patch_id = (update_info.firmware_info->version[0] << 16) + | (update_info.firmware_info->version[1] << 8) + | (update_info.firmware_info->version[2]); + memcpy(fw_ver_info.product_id, update_info.firmware_info->pid, 4); + fw_ver_info.product_id[4] = 0; + + /* check fw status reg */ + do { + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_MAINSYS, reg_val, 1); + if (ret < 0) { /* read reg failed */ + goto _reset; + } else if (ret > 0) { + continue; + } + + ret = gt1x_i2c_read_dbl_check(GTP_REG_FW_CHK_SUBSYS, ®_val[1], 1); + if (ret < 0) { + goto _reset; + } else if (ret > 0) { + continue; + } + + break; +_reset: + gt1x_reset_guitar(); + }while (--retry); + + if (!retry) { + GTP_INFO("Update abort because of i2c error."); + return ERROR_CHECK; + } + if (reg_val[0] != 0xBE || reg_val[1] == 0xAA) { + GTP_INFO("Check fw status reg not pass,reg[0x814E]=0x%2X,reg[0x5095]=0x%2X!", + reg_val[0], reg_val[1]); + return 0; + } + +#ifdef CONFIG_GTP_DEBUG_ON + if (update_info.force_update) { + GTP_DEBUG("Debug mode, force update fw."); + return 0; + } +#endif + + ret = gt1x_read_version(&ver_info); + if (ret < 0) { + GTP_INFO("Get IC's version info failed, force update!"); + return 0; + } + if (memcmp(fw_ver_info.product_id, ver_info.product_id, 4)) { + GTP_INFO("Product id is not match!"); + return ERROR_CHECK; + } + if ((fw_ver_info.mask_id & 0xFFFFFF00) != (ver_info.mask_id & 0xFFFFFF00)) { + GTP_INFO("Mask id is not match!"); + return ERROR_CHECK; + } + if ((fw_ver_info.patch_id & 0xFF0000) != (ver_info.patch_id & 0xFF0000)){ + GTP_INFO("CID is not equal, need update!"); + return 0; + } + + if ((fw_ver_info.patch_id & 0xFFFF) <= (ver_info.patch_id & 0xFFFF)) { + GTP_INFO("The version of the fw is not high than the IC's!"); + return ERROR_CHECK; + } + return 0; +} + +int __gt1x_hold_ss51_dsp_20(void) +{ + int ret = -1; + int retry = 0; + u8 buf[1]; + int hold_times = 0; + + while (retry++ < 30) { + + // Hold ss51 & dsp + buf[0] = 0x0C; + ret = gt1x_i2c_write(_rRW_MISCTL__SWRST_B0_, buf, 1); + if (ret) { + GTP_ERROR("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + // Confirm hold + buf[0] = 0x00; + ret = gt1x_i2c_read(_rRW_MISCTL__SWRST_B0_, buf, 1); + if (ret) { + GTP_ERROR("Hold ss51 & dsp I2C error,retry:%d", retry); + continue; + } + if (0x0C == buf[0]) { + if (hold_times++ < 20) { + continue; + } else { + break; + } + } + GTP_ERROR("Hold ss51 & dsp confirm 0x4180 failed,value:%d", buf[0]); + } + if (retry >= 30) { + GTP_ERROR("Hold ss51&dsp failed!"); + return ERROR_RETRY; + } + + GTP_INFO("Hold ss51&dsp successfully."); + return 0; +} + +int gt1x_hold_ss51_dsp(void) +{ + int ret = ERROR, retry = 5; + u8 buffer[2]; + + do { + gt1x_select_addr(); + usleep_range(20000, 20010); + ret = gt1x_i2c_read(0x4220, buffer, 1); + } while (retry-- && ret < 0); + + if (ret < 0) + return ERROR; + + //hold ss51_dsp + ret = __gt1x_hold_ss51_dsp_20(); + if (ret) { + return ret; + } + // enable dsp & mcu power + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__DSP_MCU_PWR_, buffer, 1); + if (ret) { + GTP_ERROR("enabel dsp & mcu power fail!"); + return ret; + } + // disable watchdog + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__TMR0_EN, buffer, 1); + if (ret) { + GTP_ERROR("disable wdt fail!"); + return ret; + } + // clear cache + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__CACHE_EN, buffer, 1); + if (ret) { + GTP_ERROR("clear cache fail!"); + return ret; + } + // soft reset + buffer[0] = 0x01; + ret = gt1x_i2c_write(_bWO_MISCTL__CPU_SWRST_PULSE, buffer, 1); + if (ret) { + GTP_ERROR("software reset fail!"); + return ret; + } + // set scramble + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_rRW_MISCTL__BOOT_OPT_B0_, buffer, 1); + if (ret) { + GTP_ERROR("set scramble fail!"); + return ret; + } + + return 0; +} + +int gt1x_run_ss51_isp(u8 * ss51_isp, int length) +{ + int ret; + u8 buffer[10]; + + ret = gt1x_hold_ss51_dsp(); + if (ret) { + return ret; + } + // select bank4 + buffer[0] = 0x04; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__SRAM_BANK, buffer, 1); + if (ret) { + GTP_ERROR("select bank4 fail."); + return ret; + } + // enable patch area access + buffer[0] = 0x01; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__PATCH_AREA_EN_, buffer, 1); + if (ret) { + GTP_ERROR("enable patch area access fail!"); + return ret; + } + + GTP_INFO("ss51_isp length: %d, checksum: 0x%04X", length, gt1x_calc_checksum(ss51_isp, length)); + // load ss51 isp + ret = gt1x_i2c_write(0xC000, ss51_isp, length); + if (ret) { + GTP_ERROR("load ss51 isp fail!"); + return ret; + } + // recall compare + ret = gt1x_recall_check(ss51_isp, 0xC000, length); + if (ret) { + GTP_ERROR("recall check ss51 isp fail!"); + return ret; + } + + memset(buffer, 0xAA, 10); + ret = gt1x_i2c_write_with_readback(0x8140, buffer, 10); + + // disable patch area access + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__PATCH_AREA_EN_, buffer, 1); + if (ret) { + GTP_ERROR("disable patch area access fail!"); + return ret; + } + // set 0x8006 + memset(buffer, 0x55, 8); + ret = gt1x_i2c_write_with_readback(0x8006, buffer, 8); + if (ret) { + GTP_ERROR("set 0x8006[0~7] 0x55 fail!"); + return ret; + } + // release ss51 + buffer[0] = 0x08; + ret = gt1x_i2c_write_with_readback(_rRW_MISCTL__SWRST_B0_, buffer, 1); + if (ret) { + GTP_ERROR("release ss51 fail!"); + return ret; + } + + msleep(100); + // check run state + ret = gt1x_i2c_read(0x8006, buffer, 2); + if (ret) { + GTP_ERROR("read 0x8006 fail!"); + return ret; + } + if (!(buffer[0] == 0xAA && buffer[1] == 0xBB)) { + GTP_ERROR("ERROR: isp is not running! 0x8006: %02X %02X", buffer[0], buffer[1]); + return ERROR_CHECK; + } + + return 0; +} + +u16 gt1x_calc_checksum(u8 * fw, u32 length) +{ + u32 i = 0; + u32 checksum = 0; + + for (i = 0; i < length; i += 2) { + checksum += (((int)fw[i]) << 8); + checksum += fw[i + 1]; + } + return (checksum & 0xFFFF); +} + +int gt1x_recall_check(u8 * chk_src, u16 start_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE]; + s32 ret = 0; + u16 len = 0; + u32 compared_length = 0; + + while (chk_length > 0) { + len = (chk_length > PACK_SIZE ? PACK_SIZE : chk_length); + + ret = gt1x_i2c_read(start_addr + compared_length, rd_buf, len); + if (ret) { + GTP_ERROR("recall i2c error,exit!"); + return ret; + } + + if (memcmp(rd_buf, &chk_src[compared_length], len)) { + GTP_ERROR("Recall frame not equal(addr: 0x%04X)", start_addr + compared_length); + GTP_DEBUG("chk_src array:"); + GTP_DEBUG_ARRAY(&chk_src[compared_length], len); + GTP_DEBUG("recall array:"); + GTP_DEBUG_ARRAY(rd_buf, len); + return ERROR_CHECK; + } + + chk_length -= len; + compared_length += len; + } + + GTP_DEBUG("Recall check %d bytes(address: 0x%04X) success.", compared_length, start_addr); + return 0; +} + +int gt1x_burn_subsystem(struct fw_subsystem_info *subsystem) +{ + int block_len; + u16 checksum; + int burn_len = 0; + u16 cur_addr; + u32 length = subsystem->length; + u8 buffer[10]; + int ret; + int wait_time; + int burn_state; + int retry = 5; + u8 *fw; + + GTP_INFO("Subsystem: %d", subsystem->type); + GTP_INFO("Length: %d", subsystem->length); + GTP_INFO("Address: 0x%08X", subsystem->address); + + while (length > 0 && retry > 0) { + retry--; + + block_len = length > 1024 * 4 ? 1024 * 4 : length; + + GTP_INFO("Burn block ==> length: %d, address: 0x%08X", block_len, subsystem->address + burn_len); + fw = gt1x_get_fw_data(subsystem->offset + burn_len, block_len); + if (fw == NULL) { + return ERROR_FW; + } + + cur_addr = ((subsystem->address + burn_len) >> 8); + + checksum = 0; + checksum += block_len; + checksum += cur_addr; + checksum += gt1x_calc_checksum(fw, block_len); + checksum = (0 - checksum); + + buffer[0] = ((block_len >> 8) & 0xFF); + buffer[1] = (block_len & 0xFF); + buffer[2] = ((cur_addr >> 8) & 0xFF); + buffer[3] = (cur_addr & 0xFF); + + ret = gt1x_i2c_write_with_readback(0x8100, buffer, 4); + if (ret) { + GTP_ERROR("write length & address fail!"); + continue; + } + + ret = gt1x_i2c_write(0x8100 + 4, fw, block_len); + if (ret) { + GTP_ERROR("write fw data fail!"); + continue; + } + + buffer[0] = ((checksum >> 8) & 0xFF); + buffer[1] = (checksum & 0xFF); + ret = gt1x_i2c_write_with_readback(0x8100 + 4 + block_len, buffer, 2); + if (ret) { + GTP_ERROR("write checksum fail!"); + continue; + } + + buffer[0] = 0; + ret = gt1x_i2c_write_with_readback(0x8022, buffer, 1); + if (ret) { + GTP_ERROR("clear control flag fail!"); + continue; + } + + buffer[0] = subsystem->type; + buffer[1] = subsystem->type; + ret = gt1x_i2c_write_with_readback(0x8020, buffer, 2); + if (ret) { + GTP_ERROR("write subsystem type fail!"); + continue; + } + burn_state = ERROR; + wait_time = 200; + msleep(5); + + while (wait_time-- > 0) { + u8 confirm = 0x55; + + ret = gt1x_i2c_read(0x8022, buffer, 1); + if (ret < 0) { + continue; + } + msleep(5); + ret = gt1x_i2c_read(0x8022, &confirm, 1); + if (ret < 0) { + continue; + } + if (buffer[0] != confirm) { + continue; + } + + if (buffer[0] == 0xAA) { + GTP_DEBUG("burning....."); + continue; + } else if (buffer[0] == 0xDD) { + GTP_ERROR("checksum error!"); + break; + } else if (buffer[0] == 0xBB) { + GTP_INFO("burning success."); + burn_state = 0; + break; + } else if (buffer[0] == 0xCC) { + GTP_ERROR("burning failed!"); + break; + } else { + GTP_DEBUG("unknown state!(0x8022: 0x%02X)", buffer[0]); + } + } + + if (!burn_state) { + length -= block_len; + burn_len += block_len; + retry = 5; + } + } + if (length == 0) { + return 0; + } else { + return ERROR_RETRY; + } +} + +int gt1x_check_subsystem_in_flash(struct fw_subsystem_info *subsystem) +{ + int block_len; + int checked_len = 0; + u32 length = subsystem->length; + int ret; + int check_state = 0; + int retry = 5; + u8 *fw; + + GTP_INFO("Subsystem: %d", subsystem->type); + GTP_INFO("Length: %d", subsystem->length); + GTP_INFO("Address: 0x%08X", subsystem->address); + + while (length > 0) { + block_len = length > 1024 * 4 ? 1024 * 4 : length; + + GTP_INFO("Check block ==> length: %d, address: 0x%08X", block_len, subsystem->address + checked_len); + fw = gt1x_get_fw_data(subsystem->offset + checked_len, block_len); + if (fw == NULL) { + return ERROR_FW; + } + ret = gt1x_read_flash(subsystem->address + checked_len, block_len); + if (ret) { + check_state |= ret; + } + + ret = gt1x_recall_check(fw, 0x8100, block_len); + if (ret) { + GTP_ERROR("Block in flash is broken!"); + check_state |= ret; + } + + length -= block_len; + checked_len += block_len; + retry = 5; + } + if (check_state) { + GTP_ERROR("Subsystem in flash is broken!"); + } else { + GTP_INFO("Subsystem in flash is correct!"); + } + return check_state; +} + +int gt1x_read_flash(u32 addr, int length) +{ + int wait_time; + int ret = 0; + u8 buffer[4]; + u16 read_addr = (addr >> 8); + + GTP_INFO("Read flash: 0x%04X, length: %d", addr, length); + + buffer[0] = 0; + ret = gt1x_i2c_write_with_readback(0x8022, buffer, 1); + + buffer[0] = ((length >> 8) & 0xFF); + buffer[1] = (length & 0xFF); + buffer[2] = ((read_addr >> 8) & 0xFF); + buffer[3] = (read_addr & 0xFF); + ret |= gt1x_i2c_write_with_readback(0x8100, buffer, 4); + + buffer[0] = 0xAA; + buffer[1] = 0xAA; + ret |= gt1x_i2c_write(0x8020, buffer, 2); + if (ret) { + GTP_ERROR("Error occured."); //comment + return ret; + } + + wait_time = 200; + while (wait_time > 0) { + wait_time--; + msleep(5); + ret = gt1x_i2c_read_dbl_check(0x8022, buffer, 1); + if (ret) { + continue; + } + if (buffer[0] == 0xBB) { + GTP_INFO("Read success(addr: 0x%04X, length: %d)", addr, length); + break; + } + } + if (wait_time == 0) { + GTP_ERROR("Read Flash FAIL!"); + return ERROR_RETRY; + } + return 0; +} + + +int gt1x_error_erase(void) +{ + int block_len; + u16 checksum; + u16 erase_addr; + u8 buffer[10]; + int ret; + int wait_time; + int burn_state = ERROR; + int retry = 5; + u8 *fw = NULL; + + GTP_INFO("Erase flash area of ss51."); + + gt1x_reset_guitar(); + + fw = gt1x_get_fw_data(update_info.firmware_info->subsystem[0].offset, + update_info.firmware_info->subsystem[0].length); + if (fw == NULL) { + GTP_ERROR("get isp fail"); + return ERROR_FW; + } + ret = gt1x_run_ss51_isp(fw, update_info.firmware_info->subsystem[0].length); + if (ret) { + GTP_ERROR("run isp fail"); + return ERROR_PATH; + } + + fw = kmalloc(1024 * 4, GFP_KERNEL); + if (!fw) { + GTP_ERROR("error when alloc mem."); + return ERROR_MEM; + } + + memset(fw, 0xFF, 1024 * 4); + erase_addr = 0x00; + block_len = 1024 * 4; + + while (retry-- > 0) { + + checksum = 0; + checksum += block_len; + checksum += erase_addr; + checksum += gt1x_calc_checksum(fw, block_len); + checksum = (0 - checksum); + + buffer[0] = ((block_len >> 8) & 0xFF); + buffer[1] = (block_len & 0xFF); + buffer[2] = ((erase_addr >> 8) & 0xFF); + buffer[3] = (erase_addr & 0xFF); + + ret = gt1x_i2c_write_with_readback(0x8100, buffer, 4); + if (ret) { + GTP_ERROR("write length & address fail!"); + continue; + } + + ret = gt1x_i2c_write(0x8100 + 4, fw, block_len); + if (ret) { + GTP_ERROR("write fw data fail!"); + continue; + } + + ret = gt1x_recall_check(fw, 0x8100 + 4, block_len); + if (ret) { + continue; + } + + buffer[0] = ((checksum >> 8) & 0xFF); + buffer[1] = (checksum & 0xFF); + ret = gt1x_i2c_write_with_readback(0x8100 + 4 + block_len, buffer, 2); + if (ret) { + GTP_ERROR("write checksum fail!"); + continue; + } + + buffer[0] = 0; + ret = gt1x_i2c_write_with_readback(0x8022, buffer, 1); + if (ret) { + GTP_ERROR("clear control flag fail!"); + continue; + } + + buffer[0] = FW_SECTION_TYPE_SS51_PATCH; + buffer[1] = FW_SECTION_TYPE_SS51_PATCH; + ret = gt1x_i2c_write_with_readback(0x8020, buffer, 2); + if (ret) { + GTP_ERROR("write subsystem type fail!"); + continue; + } + burn_state = ERROR; + wait_time = 200; + while (wait_time > 0) { + wait_time--; + msleep(5); + ret = gt1x_i2c_read_dbl_check(0x8022, buffer, 1); + if (ret) { + continue; + } + + if (buffer[0] == 0xAA) { + GTP_DEBUG("burning....."); + continue; + } else if (buffer[0] == 0xDD) { + GTP_ERROR("checksum error!"); + break; + } else if (buffer[0] == 0xBB) { + GTP_INFO("burning success."); + burn_state = 0; + break; + } else if (buffer[0] == 0xCC) { + GTP_ERROR("burning failed!"); + break; + } else { + GTP_DEBUG("unknown state!(0x8022: 0x%02X)", buffer[0]); + } + } + } + + kfree(fw); + if (burn_state == 0) { + return 0; + } else { + return ERROR_RETRY; + } +} + +void gt1x_leave_update_mode(void) +{ + GTP_DEBUG("Leave FW update mode."); + if (update_info.status != UPDATE_STATUS_ABORT) + gt1x_reset_guitar(); + +#ifdef CONFIG_GTP_CHARGER_SWITCH + gt1x_charger_switch(SWITCH_ON); +#endif +#ifdef CONFIG_GTP_ESD_PROTECT + gt1x_esd_switch(SWITCH_ON); +#endif + + update_info.status = UPDATE_STATUS_IDLE; + gt1x_irq_enable(); +} + +void dump_to_file(u16 addr, int length, char *filepath) +{ + struct file *flp = NULL; + u8 buf[128]; + const int READ_BLOCK_SIZE = 128; + int read_length = 0; + int len = 0; + + GTP_INFO("Dump(0x%04X, %d bytes) to file: %s\n", addr, length, filepath); + flp = filp_open(filepath, O_RDWR | O_CREAT, 0666); + if (IS_ERR(flp)) { + GTP_ERROR("can not open file: %s\n", filepath); + return; + } + flp->f_op->llseek(flp, 0, SEEK_SET); + + while (length > 0) { + len = (length > READ_BLOCK_SIZE ? READ_BLOCK_SIZE : length); + memset(buf, 0x33, len); + if (gt1x_i2c_read(addr + read_length, buf, len)) { + memset(buf, 0x33, len); + } + flp->f_op->write(flp, (char *)buf, len, &flp->f_pos); + read_length += len; + length -= len; + } + filp_close(flp, NULL); +} + +int gt1x_hold_ss51_dsp_no_reset(void) +{ + int ret = ERROR; + u8 buffer[2]; + + //hold ss51_dsp + ret = __gt1x_hold_ss51_dsp_20(); + if (ret) { + return ret; + } + // enable dsp & mcu power + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__DSP_MCU_PWR_, buffer, 1); + if (ret) { + GTP_ERROR("enabel dsp & mcu power fail!"); + return ret; + } + // disable watchdog + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__TMR0_EN, buffer, 1); + if (ret) { + GTP_ERROR("disable wdt fail!"); + return ret; + } + // clear cache + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__CACHE_EN, buffer, 1); + if (ret) { + GTP_ERROR("clear cache fail!"); + return ret; + } + // soft reset + buffer[0] = 0x01; + ret = gt1x_i2c_write(_bWO_MISCTL__CPU_SWRST_PULSE, buffer, 1); + if (ret) { + GTP_ERROR("software reset fail!"); + return ret; + } + // set scramble + buffer[0] = 0x00; + ret = gt1x_i2c_write_with_readback(_rRW_MISCTL__BOOT_OPT_B0_, buffer, 1); + if (ret) { + GTP_ERROR("set scramble fail!"); + return ret; + } + + return 0; +} + +#define GT1X_LOAD_PACKET_SIZE (1024 * 2) + +int gt1x_load_patch(u8 * patch, u32 patch_size, int offset, int bank_size) +{ + s32 loaded_length = 0; + s32 len = 0; + s32 ret = 0; + u8 bank = 0, tmp; + u16 address; + + GTP_INFO("Load patch code(size: %d, checksum: 0x%04X, position: 0x%04X, bank-size: %d", patch_size, gt1x_calc_checksum(patch, patch_size), 0xC000 + offset, bank_size); + while (loaded_length != patch_size) { + if (loaded_length == 0 || (loaded_length + offset) % bank_size == 0) { + // select bank + bank = 0x04 + (loaded_length + offset) / bank_size; + ret = gt1x_i2c_write(_bRW_MISCTL__SRAM_BANK, &bank, 1); + if (ret) { + GTP_ERROR("select bank%d fail!", bank); + return ret; + } + GTP_INFO("Select bank%d success.", bank); + // enable patch area access + tmp = 0x01; + ret = gt1x_i2c_write_with_readback(_bRW_MISCTL__PATCH_AREA_EN_ + bank - 4, &tmp, 1); + if (ret) { + GTP_ERROR("enable patch area access fail!"); + return ret; + } + } + + len = patch_size - loaded_length > GT1X_LOAD_PACKET_SIZE ? GT1X_LOAD_PACKET_SIZE : patch_size - loaded_length; + address = 0xC000 + (loaded_length + offset) % bank_size; + + ret = gt1x_i2c_write(address, &patch[loaded_length], len); + if (ret) { + GTP_ERROR("load 0x%04X, %dbytes fail!", address, len); + return ret; + } + ret = gt1x_recall_check(&patch[loaded_length], address, len); + if (ret) { + GTP_ERROR("Recall check 0x%04X, %dbytes fail!", address, len); + return ret; + } + GTP_INFO("load code 0x%04X, %dbytes success.", address, len); + + loaded_length += len; + } + + return 0; +} + +int gt1x_startup_patch(void) +{ + s32 ret = 0; + u8 buffer[8] = { 0x55 }; + buffer[0] = 0x00; + buffer[1] = 0x00; + ret |= gt1x_i2c_write(_bRW_MISCTL__PATCH_AREA_EN_, buffer, 2); + + memset(buffer, 0x55, 8); + ret |= gt1x_i2c_write(GTP_REG_FLASH_PASSBY, buffer, 8); + ret |= gt1x_i2c_write(GTP_REG_VERSION, buffer, 5); + + buffer[0] = 0xAA; + ret |= gt1x_i2c_write(GTP_REG_CMD, buffer, 1); + ret |= gt1x_i2c_write(GTP_REG_ESD_CHECK, buffer, 1); + + buffer[0] = 0x00; + ret |= gt1x_i2c_write(_rRW_MISCTL__SWRST_B0_, buffer, 1); + + msleep(200); + + return ret; +} + -- 2.25.1 From a82fe2dc0358ddefcea5441576100d4f95378737 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 5 Nov 2020 16:42:37 -0700 Subject: [PATCH 62/76] kernel/msm-3.18: liangdi:solve TP irq warning Change-Id: Ib29f590fa515074d12b6311b7da63190027a8c53 --- drivers/input/touchscreen/gt1x/gt1x.c | 32 +++++++++++++++++-- drivers/input/touchscreen/gt1x/gt1x_generic.c | 12 ++++++- drivers/input/touchscreen/gt1x/gt1x_generic.h | 2 ++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/gt1x/gt1x.c b/drivers/input/touchscreen/gt1x/gt1x.c index e781490536e..36a9d2a7cc6 100755 --- a/drivers/input/touchscreen/gt1x/gt1x.c +++ b/drivers/input/touchscreen/gt1x/gt1x.c @@ -33,6 +33,9 @@ int gt1x_rst_gpio; int gt1x_int_gpio; #endif +#if(USE_OTHER_THREAD != 0) +static irqreturn_t gt1x_ts_work_thread(void); +#endif static int gt1x_register_powermanger(void); static int gt1x_unregister_powermanger(void); @@ -149,6 +152,12 @@ u32 gt1x_get_charger_status(void) * IRQ_WAKE_THREAD: top half work finished, * wake up bottom half thread to continue the rest work. */ +#if(USE_OTHER_THREAD != 0) +static irqreturn_t gt1x_ts_irq_handler(int irq, void *dev_id) +{ + return gt1x_ts_work_thread(); +} +#else static irqreturn_t gt1x_ts_irq_handler(int irq, void *dev_id) { unsigned long irqflags; @@ -167,7 +176,7 @@ static irqreturn_t gt1x_ts_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } } - +#endif /** * gt1x_touch_down - Report touch point event . * @id: trackId @@ -220,7 +229,11 @@ void gt1x_touch_up(s32 id) * @iwork: work struct of gt1x_workqueue. * Return: none. */ +#if(USE_OTHER_THREAD != 0) +static irqreturn_t gt1x_ts_work_thread(void) +#else static irqreturn_t gt1x_ts_work_thread(int irq, void *data) +#endif { u8 point_data[11] = { 0 }; u8 end_cmd = 0; @@ -486,11 +499,25 @@ static s32 gt1x_request_irq(void) const u8 irq_table[] = GTP_IRQ_TAB; GTP_DEBUG("INT trigger type:%x", gt1x_int_type); +#if(USE_OTHER_THREAD != 0) + ret = request_threaded_irq(gt1x_i2c_client->irq, NULL, + gt1x_ts_irq_handler, + irq_table[gt1x_int_type] | IRQF_ONESHOT, + gt1x_i2c_client->name, + NULL); + if (ret < 0) { + GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret); + return ret; + }else { + gt1x_irq_disable(); + return 0; + } +#else ret = devm_request_threaded_irq(>1x_i2c_client->dev, gt1x_i2c_client->irq, gt1x_ts_irq_handler, gt1x_ts_work_thread, - irq_table[gt1x_int_type], + irq_table[gt1x_int_type] | IRQF_ONESHOT, gt1x_i2c_client->name, gt1x_i2c_client); if (ret) { @@ -500,6 +527,7 @@ static s32 gt1x_request_irq(void) gt1x_irq_disable(); return 0; } +#endif } /** diff --git a/drivers/input/touchscreen/gt1x/gt1x_generic.c b/drivers/input/touchscreen/gt1x/gt1x_generic.c index 401a71206eb..c47ec9f090b 100755 --- a/drivers/input/touchscreen/gt1x/gt1x_generic.c +++ b/drivers/input/touchscreen/gt1x/gt1x_generic.c @@ -776,7 +776,7 @@ else //#else /* DRIVER NOT SEND CONFIG */ gt1x_config[TRIGGER_LOC] = (gt1x_config[TRIGGER_LOC] & 0xFC) | gt1x_int_type; } - GTP_INFO("X_MAX=%d,Y_MAX=%d,TRIGGER=0x%02x,WAKEUP_LEVEL=%d", + GTP_ERROR("X_MAX=%d,Y_MAX=%d,TRIGGER=0x%02x,WAKEUP_LEVEL=%d", gt1x_abs_x_max, gt1x_abs_y_max, gt1x_int_type, gt1x_wakeup_level); gt1x_cfg_length = cfg_len; @@ -1128,7 +1128,10 @@ static s32 gt1x_wakeup_sleep(void) #endif GTP_DEBUG("Wake up begin."); +#if(USE_OTHER_THREAD != 0) +#else gt1x_irq_disable(); +#endif #ifdef CONFIG_GTP_POWER_CTRL_SLEEP /* power manager unit control the procedure */ @@ -1240,7 +1243,10 @@ void gt1x_power_reset(void) } GTP_INFO("force_reset_guitar"); rst_flag = 1; +#if(USE_OTHER_THREAD != 0) +#else gt1x_irq_disable(); +#endif gt1x_power_switch(SWITCH_OFF); msleep(30); gt1x_power_switch(SWITCH_ON); @@ -2377,7 +2383,11 @@ int gt1x_suspend(void) #ifdef CONFIG_GTP_CHARGER_SWITCH gt1x_charger_switch(SWITCH_OFF); #endif + +#if(USE_OTHER_THREAD != 0) +#else gt1x_irq_disable(); +#endif #ifdef CONFIG_GTP_GESTURE_WAKEUP gesture_clear_wakeup_data(); diff --git a/drivers/input/touchscreen/gt1x/gt1x_generic.h b/drivers/input/touchscreen/gt1x/gt1x_generic.h index b74b7d8eb29..0121bdf8304 100755 --- a/drivers/input/touchscreen/gt1x/gt1x_generic.h +++ b/drivers/input/touchscreen/gt1x/gt1x_generic.h @@ -511,6 +511,8 @@ extern int gt1x_int_gpio; #define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING,\ IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH} +#define USE_OTHER_THREAD 1 //add by liangdi for irq warning 20201021 + #endif /* CONFIG_MTK_PLATFORM */ #endif // _GT1X_GENERIC_H_ -- 2.25.1 From c12b12affa73d8b1c5c626b428312184cc8d1958 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 5 Nov 2020 16:50:37 -0700 Subject: [PATCH 63/76] kernel/msm-3.18: liangdi:update TP1158 config Change-Id: I972673c7a58ceeffe71470024a6bce1ec22758dc --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index dd961f507ee..b133d5a12d6 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -183,13 +183,13 @@ goodix,reset-gpio = <&msm_gpio 12 0x0>; goodix,irq-gpio = <&msm_gpio 13 0x2800>; goodix,default-config2 = [ - 01 E0 01 20 03 05 3D 15 A0 00 - 42 0C 6E 50 35 01 00 08 04 20 + 02 E0 01 20 03 05 0D 14 00 00 + 42 0C 64 50 55 01 00 08 04 20 00 00 00 00 00 00 00 28 00 00 3C 08 32 28 28 64 00 00 8C A0 C8 00 00 00 00 00 00 00 00 00 - 50 BE 00 00 85 05 0E 37 39 7C - 05 00 3D 33 24 F8 1E 18 32 C7 + 50 BE 00 00 85 25 0E 37 39 7C + 05 00 3D 33 24 FA 1E 18 32 C7 30 A9 38 82 41 7F 49 00 00 00 00 3C 00 00 00 00 57 50 32 FF FF 77 00 00 00 00 00 00 00 00 @@ -206,7 +206,7 @@ FF FF FF FF FF FF FF FF FF 00 C4 09 23 23 50 5D 54 50 3C 14 32 FF FF 06 51 00 8A 02 40 00 - AA 00 22 22 00 40 9A 46 01 01 + AA 00 22 22 00 40 53 25 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -- 2.25.1 From 3d7c396665eda4f53e56a34a0d5449d2eb823972 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 3 Dec 2020 14:41:06 -0700 Subject: [PATCH 64/76] kernel/msm-3.18: liangdi: add boardid Change-Id: I4381b08dfacd21f6be39901a7cfcea680b706acb --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 4 +- arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi | 76 ++++----------------- drivers/mg_driver/nrf/nrf.c | 60 ++++++++++++++++ 3 files changed, 78 insertions(+), 62 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index b133d5a12d6..ca08575787b 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -402,10 +402,12 @@ qcom,chip_wakeup = <&msm_gpio 28 0x2002>; qcom,chip_status = <&msm_gpio 30 0x0>; qcom,ant_reset = <&msm_gpio 29 0x0>; + qcom,board_id0 = <&msm_gpio 26 0x0>; + qcom,board_id1 = <&msm_gpio 27 0x0>; pinctrl-names = "nrf_active", "nrf_suspend", "nrf_release"; - pinctrl-0 = <&nrf_int_active &nrf_status_active &nrf_ant_reset_active>; + pinctrl-0 = <&nrf_int_active &nrf_status_active &nrf_ant_reset_active &nrf_board_id_active>; pinctrl-1 = <&nrf_int_suspend &nrf_status_suspend &nrf_ant_reset_suspend>; pinctrl-2 = <&nrf_release>; status = "ok"; diff --git a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi index a998a6a3f81..900c78dda9c 100755 --- a/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-pinctrl.dtsi @@ -20,37 +20,6 @@ interrupt-controller; #interrupt-cells = <2>; - /* sensors */ - cam_sensor_mclk0_default: cam_sensor_mclk0_default { - /* MCLK0 */ - mux { - /* CLK, DATA */ - pins = "gpio26"; - function = "cam_mclk"; - }; - - config { - pins = "gpio26"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_mclk0_sleep: cam_sensor_mclk0_sleep { - /* MCLK0 */ - mux { - /* CLK, DATA */ - pins = "gpio26"; - function = "cam_mclk"; - }; - - config { - pins = "gpio26"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - cam_sensor_rear_default: cam_sensor_rear_default { /* RESET, STANDBY */ mux { @@ -79,36 +48,6 @@ }; }; - cam_sensor_mclk1_default: cam_sensor_mclk1_default { - /* MCLK1 */ - mux { - /* CLK, DATA */ - pins = "gpio27"; - function = "cam_mclk"; - }; - - config { - pins = "gpio27"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ - }; - }; - - cam_sensor_mclk1_sleep: cam_sensor_mclk1_sleep { - /* MCLK1 */ - mux { - /* CLK, DATA */ - pins = "gpio27"; - function = "cam_mclk"; - }; - - config { - pins = "gpio27"; - bias-pull-down; /* PULL DOWN */ - drive-strength = <2>; /* 2 MA */ - }; - }; - cam_sensor_front_default: cam_sensor_front_default { /* RESET, STANDBY */ mux { @@ -1135,6 +1074,21 @@ }; }; + nrf_board_id_active { + nrf_board_id_active: nrf_board_id_active { + mux { + pins = "gpio26","gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio26","gpio27"; + drive-strength = <8>; + bias-pull-down; + }; + }; + }; + nrf52_active: nrf52_active { mux { pins = "gpio20", "gpio21"; diff --git a/drivers/mg_driver/nrf/nrf.c b/drivers/mg_driver/nrf/nrf.c index 669b7cb6ab8..14c8c1c85d2 100755 --- a/drivers/mg_driver/nrf/nrf.c +++ b/drivers/mg_driver/nrf/nrf.c @@ -57,6 +57,10 @@ struct nrf_drv { unsigned int wakeup_irq; int chip_status;//msm8909 status 0:power off or sleep; 1: power on int ant_reset; + int board_id0; + int board_id1; + int board_id0_val; + int board_id1_val; unsigned char *stxb; unsigned char *srxb; @@ -186,6 +190,39 @@ int nrf_parse_dt(struct device *dev) return -ENODEV; } + + nrf_driver->board_id0 = of_get_named_gpio(node, "qcom,board_id0", 0); + if (nrf_driver->board_id0 < 0) { + pr_err("board_id0 is missing\n"); + return -1; + } + + if (nrf_driver->board_id0 < 0) + return nrf_driver->board_id0; + + ret = gpio_request(nrf_driver->board_id0, "board_id0"); + if (ret < 0) { + pr_err("board_id0 failed\n"); + return -ENODEV; + } + + nrf_driver->board_id1 = of_get_named_gpio(node, "qcom,board_id1", 0); + if (nrf_driver->board_id1 < 0) { + pr_err("board_id1 is missing\n"); + return -1; + } + + if (nrf_driver->board_id1 < 0) + return nrf_driver->board_id1; + + ret = gpio_request(nrf_driver->board_id1, "board_id1"); + if (ret < 0) { + pr_err("board_id1 failed\n"); + return -ENODEV; + } + + gpio_direction_input(nrf_driver->board_id0); + gpio_direction_input(nrf_driver->board_id1); gpio_direction_output(nrf_driver->chip_status, 1); gpio_direction_output(nrf_driver->ant_reset, 1); dev_info(dev, "end nrf_parse_dt\n"); @@ -243,9 +280,23 @@ static ssize_t store_driver_attr_wake_timeout(struct device_driver *dev, const c return count; } +static ssize_t show_driver_attr_board_id(struct device_driver *dev, char *buf) +{ + int board_id = ((gl_nrf_driver->board_id0_val & 0x01) << 1) | ((gl_nrf_driver->board_id1_val & 0x01)); + return snprintf(buf, 20, "%d\n", board_id); +} + +static ssize_t store_driver_attr_board_id(struct device_driver *dev, const char *buf, size_t count) +{ + pr_err("nrf board_id set\n"); + return count; +} + + static DRIVER_ATTR(ant_reset, S_IWUSR | S_IRUGO, show_driver_attr_ant_reset, store_driver_attr_ant_reset); static DRIVER_ATTR(wake_timeout, S_IWUSR | S_IRUGO, show_driver_attr_wake_timeout, store_driver_attr_wake_timeout); static DRIVER_ATTR(chip_status, S_IWUSR | S_IRUGO, show_driver_attr_chip_status, store_driver_attr_chip_status); +static DRIVER_ATTR(board_id, S_IWUSR | S_IRUGO, show_driver_attr_board_id, store_driver_attr_board_id); int nrf_sync(u8 *txb, u8 *rxb, int len) { @@ -483,6 +534,9 @@ static int nrf_drv_probe(struct spi_device *spi) return -ENODEV; } + nrf_drv->board_id0_val = gpio_get_value(nrf_drv->board_id0); + nrf_drv->board_id1_val = gpio_get_value(nrf_drv->board_id1); + pr_err("board id %d, %d\n",nrf_drv->board_id0_val,nrf_drv->board_id1_val); ret = init_file_node(&nrf_drv->spi->dev); if(ret){ goto exit; @@ -508,6 +562,12 @@ static int nrf_drv_probe(struct spi_device *spi) goto exit; } + if(driver_create_file(&nrf_drv_driver.driver, &driver_attr_board_id)) + { + pr_err("driver_create_file board_id ERROR \n"); + goto exit; + } + nrf_drv->nrf_wq = create_singlethread_workqueue("nrf_wq"); INIT_WORK(&nrf_drv->work, nrf_wakeup_work_func); -- 2.25.1 From 28ca12089ff0cae707ee49ec2b5cf3817637cd68 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 18 Dec 2020 01:24:38 -0700 Subject: [PATCH 65/76] kernel/msm-3.18: - MeiG: liangdi:Improve TP sensitivity Change-Id: I7deca7bccdd9bf8dbc2541875367bdd7d986f967 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index ca08575787b..f9588a4a79f 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -183,15 +183,15 @@ goodix,reset-gpio = <&msm_gpio 12 0x0>; goodix,irq-gpio = <&msm_gpio 13 0x2800>; goodix,default-config2 = [ - 02 E0 01 20 03 05 0D 14 00 00 - 42 0C 64 50 55 01 00 08 04 20 + 04 E0 01 20 03 05 0D 14 08 00 + 42 0F 50 3C 55 01 00 08 05 28 00 00 00 00 00 00 00 28 00 00 - 3C 08 32 28 28 64 00 00 8C A0 + 64 08 32 28 28 64 00 00 8C A0 C8 00 00 00 00 00 00 00 00 00 50 BE 00 00 85 25 0E 37 39 7C - 05 00 3D 33 24 FA 1E 18 32 C7 - 30 A9 38 82 41 7F 49 00 00 00 - 00 3C 00 00 00 00 57 50 32 FF + 05 00 3E 33 24 FA 1E 18 32 EB + 06 22 32 02 28 28 28 00 00 00 + 00 50 00 00 00 00 57 50 32 FF FF 77 00 00 00 00 00 00 00 00 00 00 00 00 28 5A C0 94 52 28 00 04 B6 30 9F 38 8D 41 80 49 @@ -206,7 +206,7 @@ FF FF FF FF FF FF FF FF FF 00 C4 09 23 23 50 5D 54 50 3C 14 32 FF FF 06 51 00 8A 02 40 00 - AA 00 22 22 00 40 53 25 01 01 + AA 00 22 22 00 40 9E 54 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -- 2.25.1 From d3754f0d1c0924434a7190dac3638d0257c82936 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 18 Dec 2020 01:31:17 -0700 Subject: [PATCH 66/76] kernel/msm-3.18: - MeiG: liangdi: compatible with smb1358 Change-Id: I91f0e9bf0050c6f1f1fa7623bfe3c030f4a8d2f6 --- drivers/power/smb135x-charger.c | 38 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/power/smb135x-charger.c b/drivers/power/smb135x-charger.c index 98140e1f5e1..92ced46dd69 100644 --- a/drivers/power/smb135x-charger.c +++ b/drivers/power/smb135x-charger.c @@ -4840,6 +4840,7 @@ static int smb135x_main_charger_probe(struct i2c_client *client, struct power_supply *usb_psy; u8 reg = 0; u8 product_id = 0; + int i = 0; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) { @@ -4898,28 +4899,35 @@ static int smb135x_main_charger_probe(struct i2c_client *client, wakeup_source_init(&chip->wake_source.source, "smb_wake_source"); //add by liangdi for check smb135x 20191115 - rc = read_version2(chip, &product_id);//check smb1358 05-0-06 - if (rc < 0) { - dev_err(chip->dev, - "Couldn't read product id rc = %d,addr 0x%x\n", rc,chip->client->addr); - - chip->client->addr = 0x1C;//check smb1358 05-0-05 - rc = read_version2(chip, &product_id); - - if (rc < 0) { + for(i=0; i<5; i++) + { + rc = read_version2(chip, &product_id);//check smb1358 05-0-06 + if (rc < 0) + { dev_err(chip->dev, "Couldn't read product id rc = %d,addr 0x%x\n", rc,chip->client->addr); - //goto read_version_fail; + + chip->client->addr = 0x1C;//check smb1358 05-0-05 + rc = read_version2(chip, &product_id); + + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read product id rc = %d,addr 0x%x\n", rc,chip->client->addr); + chip->client->addr = 0x57;//check smb1358 05-0-06 again + continue; + } + else + { + pr_info("smb1358 05-0-05 read product id 0x%x",product_id); + break; + } } else { - pr_info("smb1358 05-0-05 read product id 0x%x",product_id); + pr_info("smb1358 05-0-06 read product id 0x%x",product_id); + break; } } - else - { - pr_info("smb1358 05-0-06 read product id 0x%x",product_id); - } //add end /* probe the device to check if its actually connected */ -- 2.25.1 From e5be4c5f6be703e25c9f889d22358b0dfdc69033 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 12 Jan 2021 14:43:04 -0700 Subject: [PATCH 67/76] MeiG: liangdi: Enable to run file system check only if a bug was reported by the f2fs kernel module Change-Id: Ib2094740c9954066ca51bfe63e0a316504d9158f --- drivers/video/msm/mdss/mdss_dsi_panel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c index 9aff9da775a..1e7910a81b1 100644 --- a/drivers/video/msm/mdss/mdss_dsi_panel.c +++ b/drivers/video/msm/mdss/mdss_dsi_panel.c @@ -73,6 +73,8 @@ end: #define T_HIGH 2 //2us //0.5us < tHI #define T_LOW 2 //2us //0.5us < tLO < 500us //#define MAX_PULSE_STEP 5 //set brightness step manually +static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_panel_cmds *pcmds, u32 flags); void mdss_brightness_control_by_pulse(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int level) { int pulse = 0, count =0; @@ -89,9 +91,13 @@ void mdss_brightness_control_by_pulse(struct mdss_dsi_ctrl_pdata *ctrl_pdata, in return; } + //pr_err("set brightness %d\n",level); if(level == 0) { //LCD off + if (ctrl_pdata->off_cmds.cmd_cnt) + mdss_dsi_panel_cmds_send(ctrl_pdata, &ctrl_pdata->off_cmds, CMD_REQ_COMMIT); + gpio_direction_output(ctrl_pdata->bklt_pulse_gpio, 0); pre_pulse = -1; return; -- 2.25.1 From 44357450b8e853b9f064bee17fe49087a68fab5c Mon Sep 17 00:00:00 2001 From: vipinbb Date: Fri, 22 Jan 2021 07:23:04 -0700 Subject: [PATCH 68/76] kernel/msm-3.18: MeiG: liangdi:bmi120 bmi220 compatible Change-Id: I5ce02f7910b836c93039b43800eb664124ed73b7 --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 1 + arch/arm/boot/dts/qcom/msm8909.dtsi | 2 +- arch/arm/configs/msm8909-perf_defconfig | 2 + drivers/input/misc/Kconfig | 7 + drivers/input/misc/Makefile | 2 + drivers/input/misc/bmi160_i2c.c | 150 +- drivers/input/misc/bmi220/Kconfig | 8 + drivers/input/misc/bmi220/Makefile | 10 + drivers/input/misc/bmi220/bmi2.c | 19616 ++++++++++++++++++++ drivers/input/misc/bmi220/bmi2.h | 1342 ++ drivers/input/misc/bmi220/bmi220.c | 637 + drivers/input/misc/bmi220/bmi220.h | 125 + drivers/input/misc/bmi220/bmi2_defs.h | 2061 ++ drivers/input/misc/bmi220/bmi2xy_driver.c | 3841 ++++ drivers/input/misc/bmi220/bmi2xy_driver.h | 288 + drivers/input/misc/bmi220/bmi2xy_i2c.c | 332 + drivers/input/misc/bmi220/bmi2xy_spi.c | 204 + drivers/input/misc/bmi220/bs_log.c | 51 + drivers/input/misc/bmi220/bs_log.h | 169 + 19 files changed, 28845 insertions(+), 3 deletions(-) create mode 100755 drivers/input/misc/bmi220/Kconfig create mode 100755 drivers/input/misc/bmi220/Makefile create mode 100755 drivers/input/misc/bmi220/bmi2.c create mode 100755 drivers/input/misc/bmi220/bmi2.h create mode 100755 drivers/input/misc/bmi220/bmi220.c create mode 100755 drivers/input/misc/bmi220/bmi220.h create mode 100755 drivers/input/misc/bmi220/bmi2_defs.h create mode 100755 drivers/input/misc/bmi220/bmi2xy_driver.c create mode 100755 drivers/input/misc/bmi220/bmi2xy_driver.h create mode 100755 drivers/input/misc/bmi220/bmi2xy_i2c.c create mode 100755 drivers/input/misc/bmi220/bmi2xy_spi.c create mode 100755 drivers/input/misc/bmi220/bs_log.c create mode 100755 drivers/input/misc/bmi220/bs_log.h diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index f9588a4a79f..f3c75fb3fa2 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -570,6 +570,7 @@ vio-supply = <&pm8909_l6>; bosch,place = <5>; bosch,gpio-int1 = <&msm_gpio 96 0x2002>; + bmi2xy,gpio_irq = <&msm_gpio 96 0x2002>; }; ptn5150@1d { diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index 9e92e2c749b..ded2c7cee0a 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -1494,7 +1494,7 @@ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, <&clock_gcc clk_gcc_blsp1_qup1_i2c_apps_clk>; clock-names = "iface_clk", "core_clk"; - qcom,clk-freq-out = <100000>; + qcom,clk-freq-out = <400000>; qcom,clk-freq-in = <19200000>; pinctrl-names = "i2c_active", "i2c_sleep"; pinctrl-0 = <&i2c_1_active>; diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 89041e625f9..9b8c576a475 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -556,6 +556,7 @@ CONFIG_SENSORS_BMI160=y CONFIG_SENSORS_BMI160_I2C=y CONFIG_SENSORS_BMI160_ENABLE_INT1=y # CONFIG_SENSORS_BMI160_ENABLE_INT2=y +CONFIG_SENSORS_BMI220=y CONFIG_SENSORS_BMP280=y CONFIG_SENSORS_BMP280_I2C=y # CONFIG_TOUCHSCREEN_GT9XX=y @@ -569,4 +570,5 @@ CONFIG_GTP_POWER_CTRL_SLEEP=y CONFIG_NRF_DRIVER=y CONFIG_EXTCON=y CONFIG_EXTCON_PTN5150=y +CONFIG_FRAME_WARN=2048 diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 0897a5c101d..0da921998b0 100755 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -888,6 +888,13 @@ config SENSORS_BMI160_ENABLE_INT2 If you say yes here, you get INT2 support for Bosch Sensortec sensors BMI160. +config SENSORS_BMI220 + tristate "BMI220 Sensor Support" + depends on I2C || SPI_MASTER + help + If you say yes here, you get support for Bosch Sensortec's + sensor driver of BMI220. + config SENSORS_BMP280 tristate "BMP280 digital Pressure Sensor" depends on (I2C || SPI_MASTER) && SYSFS diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 5355259fc5e..ea90b45818b 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -114,3 +114,5 @@ ifeq ($(CONFIG_SENSORS_BMP280_I2C),y) endif endif +obj-$(CONFIG_SENSORS_BMI220) += bmi220/ + diff --git a/drivers/input/misc/bmi160_i2c.c b/drivers/input/misc/bmi160_i2c.c index b72291fc963..d21ac9f70d9 100755 --- a/drivers/input/misc/bmi160_i2c.c +++ b/drivers/input/misc/bmi160_i2c.c @@ -289,6 +289,143 @@ exit_err_clean: return err; } +//add by liangdi for bmi120 bmi220 compatible 20210114 +extern int bmi2xy_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id); +extern int bmi2xy_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +extern int bmi2xy_i2c_resume(struct i2c_client *client); +extern int bmi2xy_i2c_remove(struct i2c_client *client); +static uint8_t gl_chip_id = 0; +struct bmi160_type_mapping_type { + + /*! bmi16x sensor chip id */ + uint16_t chip_id; + + /*! bmi16x chip revision code */ + uint16_t revision_id; + + /*! bmi160 sensor name */ + const char *sensor_name; +}; + +/*! sensor support type map */ +static const struct bmi160_type_mapping_type bmi_sensor_type_map[] = { + + {SENSOR_CHIP_ID_BMI, SENSOR_CHIP_REV_ID_BMI, "BMI160/162AB"}, + {SENSOR_CHIP_ID_BMI_C2, SENSOR_CHIP_REV_ID_BMI, "BMI160C2"}, + {SENSOR_CHIP_ID_BMI_C3, SENSOR_CHIP_REV_ID_BMI, "BMI160C3"}, + {0x26, 0x00, "BMI220"}, +}; + +static int check_chip_id(struct i2c_client *client) +{ + int8_t err = 0; + int8_t i = 0; + uint8_t chip_id = 0; + uint8_t read_count = 0; + u8 bmi_sensor_cnt = sizeof(bmi_sensor_type_map) + / sizeof(struct bmi160_type_mapping_type); + /* read and check chip id */ + while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { + if (bmi_i2c_read_wrapper(client->addr,BMI_REG_NAME(USER_CHIP_ID), &chip_id, 1) < 0) { + + pr_err("Bosch Sensortec Device not found""read chip_id:%d\n", chip_id); + continue; + + } else { + for (i = 0; i < bmi_sensor_cnt; i++) { + if (bmi_sensor_type_map[i].chip_id == chip_id) { + gl_chip_id = chip_id; + pr_err( + "Bosch Sensortec Device detected,HW IC name: %s\n", bmi_sensor_type_map[i].sensor_name); + break; + } + } + if (i < bmi_sensor_cnt) + break; + else { + if (read_count == CHECK_CHIP_ID_TIME_MAX) { + pr_err("Failed!Bosch Sensortec Device not found mismatch chip_id:%d\n", chip_id); + err = -ENODEV; + return err; + } + } + mdelay(1); + } + } + return err; + +} + +static int bmi_i2c_compatible_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c_check_functionality error!"); + err = -EIO; + goto exit_err_clean; + } + + if (NULL == bmi_client) { + bmi_client = client; + } else { + dev_err(&client->dev, + "this driver does not support multiple clients"); + err = -EBUSY; + goto exit_err_clean; + } + + if(!check_chip_id(client)) + { + bmi_client = NULL; + if(gl_chip_id == 0x26) + { + //BMI220 + err = -EIO; + goto exit_err_clean; + } + else + { + bmi_i2c_probe(client, id); + } + + } + +exit_err_clean: + if (err) + bmi_client = NULL; + return err; +} + +static const struct i2c_device_id bmi2xy_id[] = { + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, bmi2xy_id); +static const struct of_device_id bmi2xy_of_match[] = { + { .compatible = "bosch,bmi160", }, + { .compatible = "bmi2xy", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bmi2xy_of_match); + +static struct i2c_driver bmi2xy_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = bmi2xy_of_match, + }, + .class = I2C_CLASS_HWMON, + .id_table = bmi2xy_id, + .probe = bmi2xy_i2c_probe, + .remove = bmi2xy_i2c_remove, + .suspend = bmi2xy_i2c_suspend, + .resume = bmi2xy_i2c_resume, +}; +//add end + static int bmi_i2c_suspend(struct i2c_client *client, pm_message_t mesg) { int err = 0; @@ -341,7 +478,7 @@ static struct i2c_driver bmi_i2c_driver = { }, .class = I2C_CLASS_HWMON, .id_table = bmi_id, - .probe = bmi_i2c_probe, + .probe = bmi_i2c_compatible_probe, .remove = bmi_i2c_remove, .suspend = bmi_i2c_suspend, .resume = bmi_i2c_resume, @@ -349,7 +486,16 @@ static struct i2c_driver bmi_i2c_driver = { static int __init BMI_i2c_init(void) { - return i2c_add_driver(&bmi_i2c_driver); + int err = 0; + + err = i2c_add_driver(&bmi_i2c_driver); + if(gl_chip_id == 0x26) + { + pr_err("i2c add bmi2xy driver\n"); + i2c_del_driver(&bmi_i2c_driver); + return i2c_add_driver(&bmi2xy_driver); + } + return err; } static void __exit BMI_i2c_exit(void) diff --git a/drivers/input/misc/bmi220/Kconfig b/drivers/input/misc/bmi220/Kconfig new file mode 100755 index 00000000000..ea5e39746cc --- /dev/null +++ b/drivers/input/misc/bmi220/Kconfig @@ -0,0 +1,8 @@ +# +# Makefile for Bosch sensors driver. +# +config BOSCH_DRIVER_LOG_FUNC + tristate "Bosch Sensortec driver smart log function support" + depends on (I2C || SPI_MASTER) && SYSFS + help + If you say yes here, you get support for smart log function in Bosch Sensortec driver. \ No newline at end of file diff --git a/drivers/input/misc/bmi220/Makefile b/drivers/input/misc/bmi220/Makefile new file mode 100755 index 00000000000..1f8c7faf413 --- /dev/null +++ b/drivers/input/misc/bmi220/Makefile @@ -0,0 +1,10 @@ + +# +# Makefile for Bosch sensor driver. +# + +EXTRA_CFLAGS += -DBOSCH_DRIVER_LOG_FUNC +EXTRA_CFLAGS += -DBMI2XY_LOAD_CONFIG_FILE_IN_INIT +obj-y += bs_log.o +obj-y += bmi2xy_driver.o bmi2.o bmi220.o +obj-y += bmi2xy_i2c.o diff --git a/drivers/input/misc/bmi220/bmi2.c b/drivers/input/misc/bmi220/bmi2.c new file mode 100755 index 00000000000..230dc26af79 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi2.c @@ -0,0 +1,19616 @@ +/** +* Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. 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. +* +* 3. Neither the name of the copyright holder 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 AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS 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 bmi2.c +* @date 2020-01-24 +* @version v2.47.0 +* +*/ +/******************************************************************************/ + +/*! @name Header Files */ +/******************************************************************************/ +#include "bmi2.h" + +/******************************************************************************/ +/*! @name Macros */ +/******************************************************************************/ +/*! @name Offsets from feature start address for BMI2 feature enable/disable */ +#define ANY_MOT_FEAT_EN_OFFSET UINT8_C(0x03) +#define NO_MOT_FEAT_EN_OFFSET UINT8_C(0x03) +#define SIG_MOT_FEAT_EN_OFFSET UINT8_C(0x0A) +#define STEP_COUNT_FEAT_EN_OFFSET UINT8_C(0x01) +#define GYR_USER_GAIN_FEAT_EN_OFFSET UINT8_C(0x05) +#define HIGH_G_FEAT_EN_OFFSET UINT8_C(0x03) +#define LOW_G_FEAT_EN_OFFSET UINT8_C(0x03) + +/*! @name Mask definitions for BMI2 feature enable/disable */ +#define ANY_NO_MOT_EN_MASK UINT8_C(0x80) +#define TILT_FEAT_EN_MASK UINT8_C(0x01) +#define ORIENT_FEAT_EN_MASK UINT8_C(0x01) +#define SIG_MOT_FEAT_EN_MASK UINT8_C(0x01) +#define STEP_DET_FEAT_EN_MASK UINT8_C(0x08) +#define STEP_COUNT_FEAT_EN_MASK UINT8_C(0x10) +#define STEP_ACT_FEAT_EN_MASK UINT8_C(0x20) +#define GYR_USER_GAIN_FEAT_EN_MASK UINT8_C(0x08) +#define UP_HOLD_TO_WAKE_FEAT_EN_MASK UINT8_C(0x01) +#define GLANCE_FEAT_EN_MASK UINT8_C(0x01) +#define WAKE_UP_FEAT_EN_MASK UINT8_C(0x01) +#define HIGH_G_FEAT_EN_MASK UINT8_C(0x80) +#define LOW_G_FEAT_EN_MASK UINT8_C(0x10) +#define FLAT_FEAT_EN_MASK UINT8_C(0x01) +#define EXT_SENS_SYNC_FEAT_EN_MASK UINT8_C(0x01) +#define GYR_SELF_OFF_CORR_FEAT_EN_MASK UINT8_C(0x02) +#define WRIST_GEST_FEAT_EN_MASK UINT8_C(0x20) +#define WRIST_WEAR_WAKE_UP_FEAT_EN_MASK UINT8_C(0x10) +#define ACTIVITY_RECOG_EN_MASK UINT8_C(0x01) +#define ACC_SELF_TEST_FEAT_EN_MASK UINT8_C(0x02) +#define GYRO_SELF_TEST_CRT_EN_MASK UINT8_C(0x01) +#define ABORT_FEATURE_EN_MASK UINT8_C(0x02) +#define NVM_PREP_FEATURE_EN_MASK UINT8_C(0x04) +#define FREE_FALL_DET_FEAT_EN_MASK UINT8_C(0x01) + +/*! @name Bit position definitions for BMI2 feature enable/disable */ +#define ANY_NO_MOT_EN_POS UINT8_C(0x07) +#define STEP_DET_FEAT_EN_POS UINT8_C(0x03) +#define STEP_COUNT_FEAT_EN_POS UINT8_C(0x04) +#define STEP_ACT_FEAT_EN_POS UINT8_C(0x05) +#define GYR_USER_GAIN_FEAT_EN_POS UINT8_C(0x03) +#define HIGH_G_FEAT_EN_POS UINT8_C(0x07) +#define LOW_G_FEAT_EN_POS UINT8_C(0x04) +#define GYR_SELF_OFF_CORR_FEAT_EN_POS UINT8_C(0x01) +#define WRIST_GEST_FEAT_EN_POS UINT8_C(0x05) +#define WRIST_WEAR_WAKE_UP_FEAT_EN_POS UINT8_C(0x04) +#define ACC_SELF_TEST_FEAT_EN_POS UINT8_C(0x01) +#define ABORT_FEATURE_EN_POS UINT8_C(0x1) +#define NVM_PREP_FEATURE_EN_POS UINT8_C(0x02) + +/*! Primary OIS low pass filter configuration position and mask */ +#define LP_FILTER_EN_MASK UINT8_C(0x01) + +#define LP_FILTER_CONFIG_POS UINT8_C(0x01) +#define LP_FILTER_CONFIG_MASK UINT8_C(0x06) + +#define PRIMARY_OIS_GYR_EN_POS UINT8_C(0x06) +#define PRIMARY_OIS_GYR_EN_MASK UINT8_C(0x40) + +#define PRIMARY_OIS_ACC_EN_POS UINT8_C(0x07) +#define PRIMARY_OIS_ACC_EN_MASK UINT8_C(0x80) + +/*! @name Mask definitions for BMI2 any and no-motion feature configuration */ +#define ANY_NO_MOT_DUR_MASK UINT16_C(0x1FFF) +#define ANY_NO_MOT_X_SEL_MASK UINT16_C(0x2000) +#define ANY_NO_MOT_Y_SEL_MASK UINT16_C(0x4000) +#define ANY_NO_MOT_Z_SEL_MASK UINT16_C(0x8000) +#define ANY_NO_MOT_THRES_MASK UINT16_C(0x07FF) +#define ANY_NO_MOT_OUT_CONF_MASK UINT16_C(0x7800) + +/*! @name Bit position definitions for BMI2 any and no-motion feature + * configuration + */ +#define ANY_NO_MOT_X_SEL_POS UINT8_C(0x0D) +#define ANY_NO_MOT_Y_SEL_POS UINT8_C(0x0E) +#define ANY_NO_MOT_Z_SEL_POS UINT8_C(0x0F) +#define ANY_NO_MOT_OUT_CONF_POS UINT8_C(0x0B) + +/*! @name Mask definitions for BMI2 tilt feature configuration */ +#define TILT_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 tilt feature configuration */ +#define TILT_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 orientation feature configuration */ +#define ORIENT_UP_DOWN_MASK UINT16_C(0x0002) +#define ORIENT_SYMM_MODE_MASK UINT16_C(0x000C) +#define ORIENT_BLOCK_MODE_MASK UINT16_C(0x0030) +#define ORIENT_THETA_MASK UINT16_C(0x0FC0) +#define ORIENT_HYST_MASK UINT16_C(0x07FF) +#define ORIENT_OUT_CONF_MASK UINT16_C(0x7800) + +/*! @name Bit position definitions for BMI2 orientation feature configuration */ +#define ORIENT_UP_DOWN_POS UINT8_C(0x01) +#define ORIENT_SYMM_MODE_POS UINT8_C(0x02) +#define ORIENT_BLOCK_MODE_POS UINT8_C(0x04) +#define ORIENT_THETA_POS UINT8_C(0x06) +#define ORIENT_OUT_CONF_POS UINT8_C(0x0B) + +/*! @name Mask definitions for BMI2 sig-motion feature configuration */ +#define SIG_MOT_PARAM_1_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_2_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_3_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_4_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_5_MASK UINT16_C(0xFFFF) +#define SIG_MOT_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 sig-motion feature configuration */ +#define SIG_MOT_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 parameter configurations */ +#define STEP_COUNT_PARAMS_MASK UINT16_C(0xFFFF) + +/*! @name Mask definitions for BMI2 step-counter/detector feature configuration */ +#define STEP_COUNT_WM_LEVEL_MASK UINT16_C(0x03FF) +#define STEP_COUNT_RST_CNT_MASK UINT16_C(0x0400) +#define STEP_DET_OUT_CONF_MASK UINT16_C(0x000F) +#define STEP_ACT_OUT_CONF_MASK UINT16_C(0x00F0) +#define STEP_BUFFER_SIZE_MASK UINT16_C(0XFF00) + +/*! @name Bit position definitions for BMI2 step-counter/detector feature + * configuration + */ +#define STEP_COUNT_RST_CNT_POS UINT8_C(0x0A) +#define STEP_ACT_OUT_CONF_POS UINT8_C(0x04) +#define STEP_BUFFER_SIZE_POS UINT8_C(0X08) + +/*! @name Mask definitions for BMI2 gyroscope user gain feature + * configuration + */ +#define GYR_USER_GAIN_RATIO_X_MASK UINT16_C(0x07FF) +#define GYR_USER_GAIN_RATIO_Y_MASK UINT16_C(0x07FF) +#define GYR_USER_GAIN_RATIO_Z_MASK UINT16_C(0x07FF) + +/*! @name Mask definitions for BMI2 gyroscope user gain saturation status */ +#define GYR_USER_GAIN_SAT_STAT_X_MASK UINT8_C(0x01) +#define GYR_USER_GAIN_SAT_STAT_Y_MASK UINT8_C(0x02) +#define GYR_USER_GAIN_SAT_STAT_Z_MASK UINT8_C(0x04) +#define G_TRIGGER_STAT_MASK UINT8_C(0x38) + +/*! @name Bit position definitions for BMI2 gyroscope user gain saturation status */ +#define GYR_USER_GAIN_SAT_STAT_Y_POS UINT8_C(0x01) +#define GYR_USER_GAIN_SAT_STAT_Z_POS UINT8_C(0x02) +#define G_TRIGGER_STAT_POS UINT8_C(0x03) + +/*! @name Mask definitions for MSB values of BMI2 gyroscope compensation */ +#define GYR_OFF_COMP_MSB_X_MASK UINT8_C(0x03) +#define GYR_OFF_COMP_MSB_Y_MASK UINT8_C(0x0C) +#define GYR_OFF_COMP_MSB_Z_MASK UINT8_C(0x30) + +/*! @name Bit positions for MSB values of BMI2 gyroscope compensation */ +#define GYR_OFF_COMP_MSB_Y_POS UINT8_C(0x02) +#define GYR_OFF_COMP_MSB_Z_POS UINT8_C(0x04) + +/*! @name Mask definitions for MSB values of BMI2 gyroscope compensation from user input */ +#define GYR_OFF_COMP_MSB_MASK UINT16_C(0x0300) +#define GYR_OFF_COMP_LSB_MASK UINT16_C(0x00FF) + +/*! @name Mask definitions for BMI2 orientation status */ +#define BMI2_ORIENT_DETECT_MASK UINT8_C(0x03) +#define BMI2_ORIENT_FACE_UP_DWN_MASK UINT8_C(0x04) + +/*! @name Bit position definitions for BMI2 orientation status */ +#define BMI2_ORIENT_FACE_UP_DWN_POS UINT8_C(0x02) + +/*! @name Mask definitions for NVM-VFRM error status */ +#define NVM_LOAD_ERR_STATUS_MASK UINT8_C(0x01) +#define NVM_PROG_ERR_STATUS_MASK UINT8_C(0x02) +#define NVM_ERASE_ERR_STATUS_MASK UINT8_C(0x04) +#define NVM_END_EXCEED_STATUS_MASK UINT8_C(0x08) +#define NVM_PRIV_ERR_STATUS_MASK UINT8_C(0x10) +#define VFRM_LOCK_ERR_STATUS_MASK UINT8_C(0x20) +#define VFRM_WRITE_ERR_STATUS_MASK UINT8_C(0x40) +#define VFRM_FATAL_ERR_STATUS_MASK UINT8_C(0x80) + +/*! @name Bit positions for NVM-VFRM error status */ +#define NVM_PROG_ERR_STATUS_POS UINT8_C(0x01) +#define NVM_ERASE_ERR_STATUS_POS UINT8_C(0x02) +#define NVM_END_EXCEED_STATUS_POS UINT8_C(0x03) +#define NVM_PRIV_ERR_STATUS_POS UINT8_C(0x04) +#define VFRM_LOCK_ERR_STATUS_POS UINT8_C(0x05) +#define VFRM_WRITE_ERR_STATUS_POS UINT8_C(0x06) +#define VFRM_FATAL_ERR_STATUS_POS UINT8_C(0x07) + +/*! @name Mask definitions for accelerometer self-test status */ +#define ACC_SELF_TEST_DONE_MASK UINT8_C(0x01) +#define ACC_X_OK_MASK UINT8_C(0x02) +#define ACC_Y_OK_MASK UINT8_C(0x04) +#define ACC_Z_OK_MASK UINT8_C(0x08) + +/*! @name Bit Positions for accelerometer self-test status */ +#define ACC_X_OK_POS UINT8_C(0x01) +#define ACC_Y_OK_POS UINT8_C(0x02) +#define ACC_Z_OK_POS UINT8_C(0x03) + +/*! @name Mask definitions for BMI2 uphold to wake feature configuration */ +#define UP_HOLD_TO_WAKE_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 uphold to wake feature configuration */ +#define UP_HOLD_TO_WAKE_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 glance detector feature configuration */ +#define GLANCE_DET_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 glance detector feature + * configuration + */ +#define GLANCE_DET_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 wake-up feature configuration */ +#define WAKE_UP_SENSITIVITY_MASK UINT16_C(0x000E) +#define WAKE_UP_SINGLE_TAP_EN_MASK UINT16_C(0x0010) +#define WAKE_UP_OUT_CONF_MASK UINT16_C(0x01E0) + +/*! @name Bit position definitions for BMI2 wake-up feature configuration */ +#define WAKE_UP_SENSITIVITY_POS UINT8_C(0x01) +#define WAKE_UP_SINGLE_TAP_EN_POS UINT8_C(0x04) +#define WAKE_UP_OUT_CONF_POS UINT8_C(0x05) + +/*! @name Mask definitions for BMI2 high-g feature configuration */ +#define HIGH_G_THRES_MASK UINT16_C(0x7FFF) +#define HIGH_G_HYST_MASK UINT16_C(0x0FFF) +#define HIGH_G_X_SEL_MASK UINT16_C(0x1000) +#define HIGH_G_Y_SEL_MASK UINT16_C(0x2000) +#define HIGH_G_Z_SEL_MASK UINT16_C(0x4000) +#define HIGH_G_DUR_MASK UINT16_C(0x0FFF) +#define HIGH_G_OUT_CONF_MASK UINT16_C(0xF000) + +/*! @name Bit position definitions for BMI2 high-g feature configuration */ +#define HIGH_G_OUT_CONF_POS UINT8_C(0x0C) +#define HIGH_G_X_SEL_POS UINT8_C(0x0C) +#define HIGH_G_Y_SEL_POS UINT8_C(0x0D) +#define HIGH_G_Z_SEL_POS UINT8_C(0x0E) + +/*! @name Mask definitions for BMI2 low-g feature configuration */ +#define LOW_G_THRES_MASK UINT16_C(0x7FFF) +#define LOW_G_HYST_MASK UINT16_C(0x0FFF) +#define LOW_G_DUR_MASK UINT16_C(0x0FFF) +#define LOW_G_OUT_CONF_MASK UINT16_C(0xF000) + +/*! @name Mask definitions for BMI2 free-fall detection feature configuration */ +#define FREE_FALL_OUT_CONF_MASK UINT16_C(0x001E) +#define FREE_FALL_ACCEL_SETT_MASK UINT16_C(0xFFFF) + +/*! @name Bit position definitions for BMI2 free-fall detection feature configuration */ +#define FREE_FALL_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Bit position definitions for BMI2 low-g feature configuration */ +#define LOW_G_OUT_CONF_POS UINT8_C(0x0C) + +/*! @name Mask definitions for BMI2 flat feature configuration */ +#define FLAT_THETA_MASK UINT16_C(0x007E) +#define FLAT_BLOCK_MASK UINT16_C(0x0180) +#define FLAT_OUT_CONF_MASK UINT16_C(0x1E00) +#define FLAT_HYST_MASK UINT16_C(0x003F) +#define FLAT_HOLD_TIME_MASK UINT16_C(0x3FC0) + +/*! @name Bit position definitions for BMI2 flat feature configuration */ +#define FLAT_THETA_POS UINT8_C(0x01) +#define FLAT_BLOCK_POS UINT8_C(0x07) +#define FLAT_OUT_CONF_POS UINT8_C(0x09) +#define FLAT_HOLD_TIME_POS UINT8_C(0x06) + +/*! @name Mask definitions for BMI2 external sensor sync configuration */ +#define EXT_SENS_SYNC_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for external sensor sync configuration */ +#define EXT_SENS_SYNC_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 wrist gesture configuration */ +#define WRIST_GEST_WEAR_ARM_MASK UINT16_C(0x0010) +#define WRIST_GEST_OUT_CONF_MASK UINT16_C(0x000F) + +/*! @name Bit position definitions for wrist gesture configuration */ +#define WRIST_GEST_WEAR_ARM_POS UINT8_C(0x04) + +/*! @name Mask definitions for BMI2 wrist wear wake-up configuration */ +#define WRIST_WAKE_UP_OUT_CONF_MASK UINT16_C(0x000F) + +/*! @name Mask definition for BMI2 wrist wear wake-up configuration for wearable variant */ +#define WRIST_WAKE_UP_ANGLE_LR_MASK UINT16_C(0x00FF) +#define WRIST_WAKE_UP_ANGLE_LL_MASK UINT16_C(0xFF00) +#define WRIST_WAKE_UP_ANGLE_PD_MASK UINT16_C(0x00FF) +#define WRIST_WAKE_UP_ANGLE_PU_MASK UINT16_C(0xFF00) +#define WRIST_WAKE_UP_MIN_DUR_MOVED_MASK UINT16_C(0x00FF) +#define WRIST_WAKE_UP_MIN_DUR_QUITE_MASK UINT16_C(0xFF00) + +/*! @name Bit position definition for BMI2 wrist wear wake-up configuration for wearable variant */ +#define WRIST_WAKE_UP_ANGLE_LL_POS UINT16_C(0x0008) +#define WRIST_WAKE_UP_ANGLE_PU_POS UINT16_C(0x0008) +#define WRIST_WAKE_UP_MIN_DUR_QUITE_POS UINT16_C(0x0008) + +/*! @name Macros to define values of BMI2 axis and its sign for re-map + * settings + */ +#define MAP_X_AXIS UINT8_C(0x00) +#define MAP_Y_AXIS UINT8_C(0x01) +#define MAP_Z_AXIS UINT8_C(0x02) +#define MAP_POSITIVE UINT8_C(0x00) +#define MAP_NEGATIVE UINT8_C(0x01) + +/*! @name Mask definitions of BMI2 axis re-mapping */ +#define X_AXIS_MASK UINT8_C(0x03) +#define X_AXIS_SIGN_MASK UINT8_C(0x04) +#define Y_AXIS_MASK UINT8_C(0x18) +#define Y_AXIS_SIGN_MASK UINT8_C(0x20) +#define Z_AXIS_MASK UINT8_C(0xC0) +#define Z_AXIS_SIGN_MASK UINT8_C(0x01) + +/*! @name Bit position definitions of BMI2 axis re-mapping */ +#define X_AXIS_SIGN_POS UINT8_C(0x02) +#define Y_AXIS_POS UINT8_C(0x03) +#define Y_AXIS_SIGN_POS UINT8_C(0x05) +#define Z_AXIS_POS UINT8_C(0x06) + +/*! @name Macros to define polarity */ +#define NEG_SIGN INT16_C(-1) +#define POS_SIGN INT16_C(1) + +/*! @name Macro to define related to CRT */ +#define CRT_READY_FOR_DOWNLOAD_US UINT16_C(2000) +#define CRT_READY_FOR_DOWNLOAD_RETRY UINT8_C(100) + +#define CRT_WAIT_RUNNING_US UINT16_C(10000) +#define CRT_WAIT_RUNNING_RETRY_EXECUTION UINT8_C(200) + +#define CRT_MIN_BURST_WORD_LENGTH UINT8_C(2) +#define CRT_MAX_BURST_WORD_LENGTH UINT16_C(255) + +#define ACC_FOC_2G_REF UINT16_C(16384) +#define ACC_FOC_4G_REF UINT16_C(8192) +#define ACC_FOC_8G_REF UINT16_C(4096) +#define ACC_FOC_16G_REF UINT16_C(2048) + +#define GYRO_FOC_NOISE_LIMIT_NEGATIVE INT8_C(-20) +#define GYRO_FOC_NOISE_LIMIT_POSITIVE INT8_C(20) + +/* reference value with positive and negative noise range in lsb */ +#define ACC_2G_MAX_NOISE_LIMIT (ACC_FOC_2G_REF + UINT16_C(255)) +#define ACC_2G_MIN_NOISE_LIMIT (ACC_FOC_2G_REF - UINT16_C(255)) +#define ACC_4G_MAX_NOISE_LIMIT (ACC_FOC_4G_REF + UINT16_C(255)) +#define ACC_4G_MIN_NOISE_LIMIT (ACC_FOC_4G_REF - UINT16_C(255)) +#define ACC_8G_MAX_NOISE_LIMIT (ACC_FOC_8G_REF + UINT16_C(255)) +#define ACC_8G_MIN_NOISE_LIMIT (ACC_FOC_8G_REF - UINT16_C(255)) +#define ACC_16G_MAX_NOISE_LIMIT (ACC_FOC_16G_REF + UINT16_C(255)) +#define ACC_16G_MIN_NOISE_LIMIT (ACC_FOC_16G_REF - UINT16_C(255)) + +#define BMI2_FOC_SAMPLE_LIMIT UINT8_C(128) + +/***************************************************************************/ + +/*! Local structures + ****************************************************************************/ + +/*! @name Structure to define the difference in accelerometer values */ +struct selftest_delta_limit +{ + /*! X data */ + int32_t x; + + /*! Y data */ + int32_t y; + + /*! Z data */ + int32_t z; +}; + +/*! @name Structure to store the local copy of the re-mapped axis and + * the value of its sign for register settings + */ +struct axes_remap +{ + /*! Re-mapped x-axis */ + uint8_t x_axis; + + /*! Re-mapped y-axis */ + uint8_t y_axis; + + /*! Re-mapped z-axis */ + uint8_t z_axis; + + /*! Re-mapped x-axis sign */ + uint8_t x_axis_sign; + + /*! Re-mapped y-axis sign */ + uint8_t y_axis_sign; + + /*! Re-mapped z-axis sign */ + uint8_t z_axis_sign; +}; + +/*! @name Structure to store temporary accelerometer/gyroscope values */ +struct foc_temp_value +{ + /*! X data */ + int32_t x; + + /*! Y data */ + int32_t y; + + /*! Z data */ + int32_t z; +}; + +/*! @name Structure to store accelerometer data deviation from ideal value */ +struct offset_delta +{ + /*! X axis */ + int16_t x; + + /*! Y axis */ + int16_t y; + + /*! Z axis */ + int16_t z; +}; + +/*! @name Structure to store accelerometer offset values */ +struct accel_offset +{ + /*! offset X data */ + uint8_t x; + + /*! offset Y data */ + uint8_t y; + + /*! offset Z data */ + uint8_t z; +}; + +/******************************************************************************/ + +/*! Local Function Prototypes + ******************************************************************************/ + +/*! + * @brief This internal API writes the configuration file. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t write_config_file(struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables the loading of the configuration + * file. + * + * @param[in] enable : To enable/disable configuration load. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_config_load(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API loads the configuration file. + * + * @param[in] config_data : Pointer to the configuration file. + * @param[in] index : Variable to define array index. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t upload_file(const uint8_t *config_data, uint16_t index, uint16_t write_len, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the selected sensor/features. + * + * @param[in] sensor_sel : Selects the desired sensor. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +static int8_t sensor_enable(uint32_t sensor_sel, struct bmi2_dev *dev); + +/*! + * @brief This internal API disables the selected sensor/features. + * + * @param[in] sensor_sel : Selects the desired sensor. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +static int8_t sensor_disable(uint32_t sensor_sel, struct bmi2_dev *dev); + +/*! + * @brief This internal API selects the sensors/features to be enabled or + * disabled. + * + * @param[in] sens_list : Pointer to select the sensor. + * @param[in] n_sens : Number of sensors selected. + * @param[out] sensor_sel : Gets the selected sensor. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t select_sensor(const uint8_t *sens_list, uint8_t n_sens, uint32_t *sensor_sel); + +/*! + * @brief This internal API is used to enable/disable any-motion feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables any-motion. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables any-motion. + * BMI2_ENABLE | Enables any-motion. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_any_motion(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable no-motion feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables no-motion. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables no-motion. + * BMI2_ENABLE | Enables no-motion. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_no_motion(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable sig-motion feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables sig-motion. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables sig-motion. + * BMI2_ENABLE | Enables sig-motion. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_sig_motion(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable step detector feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables step-detector. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables step detector + * BMI2_ENABLE | Enables step detector + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_detector(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable step counter feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables step counter. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables step counter + * BMI2_ENABLE | Enables step counter + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_counter(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable step activity detection. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables step activity. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables step activity + * BMI2_ENABLE | Enables step activity + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_activity(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable tilt feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables tilt. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables tilt + * BMI2_ENABLE | Enables tilt + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_tilt(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable uphold to wake feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables uphold to wake. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables uphold to wake + * BMI2_ENABLE | Enables uphold to wake + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_up_hold_to_wake(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable glance detector feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables glance. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables glance detector + * BMI2_ENABLE | Enables glance detector + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_glance_detector(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable wake-up feature through + * single or double tap. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables single or double tap. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables single/double tap. + * BMI2_ENABLE | Enables single/double tap + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wake_up(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable orientation feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables orientation. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables orientation + * BMI2_ENABLE | Enables orientation + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_orientation(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable high-g feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables high-g. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables high-g + * BMI2_ENABLE | Enables high-g + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_high_g(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable low-g feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables low-g. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables low-g + * BMI2_ENABLE | Enables low-g + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_low_g(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable flat feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables flat. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables flat + * BMI2_ENABLE | Enables flat + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_flat(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable ext-sensor-sync feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables ext-sensor-sync. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables ext-sensor-sync + * BMI2_ENABLE | Enables ext-sensor-sync + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_ext_sens_sync(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API gives an option to enable offset correction + * feature of gyroscope, either internally or by the host. + * + * @param[in] enable : Enables/Disables self-offset correction. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | gyroscope offset correction values are set internally + * BMI2_DISABLE | gyroscope offset correction values has to be set by host + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_gyro_self_offset_corr(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable gyroscope user gain + * feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables gyroscope user gain. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables gyroscope user gain + * BMI2_ENABLE | Enables gyroscope user gain + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_gyro_user_gain(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the wrist gesture feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables wrist gesture. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables wrist gesture + * BMI2_ENABLE | Enables wrist gesture + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_gesture(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the wrist wear wake up feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables wrist wear wake up. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables wrist wear wake up + * BMI2_ENABLE | Enables wrist wear wake up + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_wear_wake_up(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the wrist gesture feature for wearable variant. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables wrist gesture. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables wrist gesture + * BMI2_ENABLE | Enables wrist gesture + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_gesture_wh(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the wrist wear wake up feature for wearable variant. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables wrist wear wake up. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables wrist wear wake up + * BMI2_ENABLE | Enables wrist wear wake up + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_wear_wake_up_wh(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables the activity recognition feature. + * + * @param[in] enable : Enables/Disables activity recognition. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enables activity recognition. + * BMI2_DISABLE | Disables activity recognition. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_act_recog(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API gives an option to enable accelerometer self-test + * in the feature register. + * + * @param[in] enable : Enables/Disables accelerometer self-test. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enables accelerometer self-test. + * BMI2_DISABLE | Disables accelerometer self-test. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_feat_accel_self_test(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API gives an option to enable low pass filter + * in the feature register. + * + * @param[in] enable : Enables/Disables accelerometer self-test. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enables low pass filter. + * BMI2_DISABLE | Disables low pass filter. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_primary_ois_low_pass_filter(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets accelerometer configurations like ODR, + * bandwidth, performance mode and g-range. + * + * @param[in,out] config : Structure instance of bmi2_accel_config. + * @param[in,out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_ACC_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_ACC_GYR_INVALID_CFG - Error: Invalid accelerometer and + * gyroscope configuration + * + */ +static int8_t set_accel_config(struct bmi2_accel_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API validates bandwidth and performance mode of the + * accelerometer set by the user. + * + * @param[in, out] bandwidth : Pointer to bandwidth value set by the user. + * @param[in, out] perf_mode : Pointer to performance mode set by the user. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t validate_bw_perf_mode(uint8_t *bandwidth, uint8_t *perf_mode, struct bmi2_dev *dev); + +/*! + * @brief This internal API validates ODR and range of the accelerometer set by + * the user. + * + * @param[in, out] odr : Pointer to ODR value set by the user. + * @param[in, out] range : Pointer to range value set by the user. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t validate_odr_range(uint8_t *odr, uint8_t *range, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets gyroscope configurations like ODR, bandwidth, + * low power/high performance mode, performance mode and range. + * + * @param[in,out] config : Structure instance of bmi2_gyro_config. + * @param[in,out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_GYRO_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_ACC_GYR_INVALID_CFG - Error: Invalid accelerometer and + * gyroscope configuration + */ +static int8_t set_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API validates bandwidth, performance mode, low power/ + * high performance mode, ODR, and range set by the user. + * + * @param[in] config : Structure instance of bmi2_gyro_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t validate_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API shows the error status when illegal sensor + * configuration is set. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_ACC_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_GYRO_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_ACC_GYR_INVALID_CFG - Error: Invalid accelerometer and + * gyroscope configuration + */ +static int8_t cfg_error_status(const struct bmi2_dev *dev); + +/*! + * @brief This internal API: + * 1) Enables/Disables auxiliary interface. + * 2) Sets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3)It maps/un-maps data interrupts to that of hardware interrupt line. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t set_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables auxiliary interface. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_aux_interface(const struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Auxiliary sensor should not be busy when configuring aux_i2c_addr, + * man_rd_burst_len, aux_rd_burst_len and aux_rd_addr. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t config_aux_interface(const struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API triggers read out offset and sets ODR of the + * auxiliary sensor. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t config_aux(const struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API validates auxiliary configuration set by the user. + * + * @param[in, out] config : Structure instance of bmi2_aux_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t validate_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets any-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[in] config : Structure instance of bmi2_any_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_any_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_any_motion_config(const struct bmi2_any_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets no-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[in] config : Structure instance of bmi2_no_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_no_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_no_motion_config(const struct bmi2_no_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets sig-motion configurations like block-size, + * output-configuration and other parameters. + * + * @param[in] config : Structure instance of bmi2_sig_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + *---------------------------------------------------------------------------- + * bmi2_sig_motion_config | + * Structure parameters | Description + * -------------------------|--------------------------------------------------- + * | Defines the duration after which the significant + * block_size | motion interrupt is triggered. It is expressed in + * | 50 Hz samples (20 ms). Default value is 0xFA=5sec. + *--------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + *--------------------------|--------------------------------------------------- + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_sig_motion_config(const struct bmi2_sig_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets step counter parameter configurations. + * + * @param[in] step_count_params : Array that stores parameters 1 to 25. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_count_params_config(const uint16_t *step_count_params, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets step counter/detector/activity configurations. + * + * @param[in] config : Structure instance of bmi2_step_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + *--------------------------------------------------------------------------- + * bmi2_step_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | The Step-counter will trigger output every time + * | the number of steps are counted. Holds implicitly + * water-mark level | a 20x factor, so the range is 0 to 10230, + * | with resolution of 20 steps. + * -------------------------|--------------------------------------------------- + * reset counter | Flag to reset the counted steps. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_det_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step detector. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_act_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step activity. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_config(const struct bmi2_step_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + * + * @param[in] config : Structure instance of bmi2_gyro_user_gain_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_gyro_user_gain_config| + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * ratio_x | Gain update value for x-axis + * -------------------------|--------------------------------------------------- + * ratio_y | Gain update value for y-axis + * -------------------------|--------------------------------------------------- + * ratio_z | Gain update value for z-axis + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_gyro_user_gain_config(const struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets tilt configurations like output-configuration. + * + * @param[in] config : Structure instance of bmi2_tilt_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_tilt_config | + * Structure parameters | Description + *------------------------- |-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * ------------------------ |--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_tilt_config(const struct bmi2_tilt_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets uphold to wake configurations like output + * configuration. + * + * @param[in] config : Structure instance of bmi2_uphold_to_wake_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_uphold_to_wake_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_up_hold_to_wake_config(const struct bmi2_up_hold_to_wake_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets glance detector configurations like output + * configuration. + * + * @param[in] config : Structure instance of bmi2_glance_det_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_glance_det_config| + * Structure parameters | Description + *-------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * ------------------------|---------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_glance_detect_config(const struct bmi2_glance_det_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + * + * @param[in] config : Structure instance of bmi2_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wake_up_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Configures wake-up sensitivity, the range goes + * sensitivity | from 0 (high sensitive) to 7 (low sensitive). + * -------------------------|--------------------------------------------------- + * | Enable - Single Tap detection + * single_tap_en | Disable- Double Tap detection (Default value) + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wake_up_config(const struct bmi2_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + * + * @param[in] config : Structure instance of bmi2_orient_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_orient_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * upside/down | Enables upside/down detection, if set to 1. + * detection | + * -------------------------|--------------------------------------------------- + * | Sets the mode: + * mode | Values 0 or 3 - symmetrical. + * | Value 1 - high asymmetrical + * | Value 2 - low asymmetrical + * -------------------------|--------------------------------------------------- + * | Enable - no orientation interrupt will be set. + * blocking | Default value: 3, the most restrictive blocking. + * -------------------------|--------------------------------------------------- + * | Threshold angle used in blocking mode. + * theta | Theta = 64 * (tan(angle)^2) + * | Default value: 40, equivalent to 38 degrees angle. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for Orientation detection + * | is expressed in 5.11g format. + * hysteresis | Default value is 128 = 0.0625g. + * | Range is 0 to 1g. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_orient_config(const struct bmi2_orient_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets high-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[in] config : Structure instance of bmi2_high_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_high_g_config | + * Structure parameter | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | high_g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * | Range is 0 to 16g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for high-g detection + * | is expressed in 1.11g format. + * hysteresis | Default value is 256 = 0.125 g. + * | Range is 0 to 2g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 200 Hz samples (5 ms) for + * | which the threshold has to be exceeded. + * duration | Default value 4 = 20 msec. + * | Range is 0 to 20sec. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_high_g_config(const struct bmi2_high_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[in] config : Structure instance of bmi2_low_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_low_g_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | low-g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for low-g detection + * hysteresis | is expressed in 1.11g format. + * | Default value is 512 = 0.250 g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50 Hz samples (20 ms) for + * | which the threshold has to be exceeded. + * duration | Default value 0 = 1 validation sample = (0+1)*20 + * | = 20 ms. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_low_g_config(const struct bmi2_low_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + * + * @param[in] config : Structure instance of bmi2_flat_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_flat_config | + * Structure parameters| Description + *--------------------------|-------------------------------------------------- + * | Sets the theta angle, used for detecting flat + * | position. + * theta | Theta = 64 * (tan(angle)^2); + * | Default value is 8, equivalent to 20 degrees angle + * -------------------------|--------------------------------------------------- + * | Hysteresis for Theta Flat detection. + * hysteresis | Default value is 9 = 2.5 degrees, corresponding + * | to the default Theta angle of 20 degrees. + * -------------------------|--------------------------------------------------- + * | Sets the blocking mode. If blocking is set, no + * | Flat interrupt will be triggered. + * blocking | Default value is 2, the most restrictive blocking + * | mode. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50Hz samples for which the + * | condition has to be respected. + * hold-time | Default value is 32 = 640 m-sec. + * | Range is 0 to 5.1 sec. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_flat_config(const struct bmi2_flat_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets external sensor sync configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_ext_sens_sync_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + *---------------------------------------------------------------------------- + * bmi2_ext_sens_sync_config | + * Structure parameters | Description + * -----------------------------|---------------------------------------------- + * |Enable bits for enabling output into the + * out_conf |register status bits and, if desired, onto the + * |interrupt pin. + * -----------------------------|---------------------------------------------- + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_ext_sens_sync_config(const struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wrist gesture configurations like wearable-arm, + * and output-configuration. + * + * @param[in] config : Structure instance of bmi2_wrist_gest_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_gest_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Device in left (0) or right (1) arm. By default, + * wear_arm | the wearable device is assumed to be in left arm + * | i.e. default value is 0. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_gest_config(const struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wrist wear wake-up configurations like + * output-configuration. + * + * @param[in] config : Structure instance of + * bmi2_wrist_wear_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_wear_wake_up_config | + * Structure parameters | Description + *----------------------------------|------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto + * | the interrupt pin. + * ---------------------------------|------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_wear_wake_up_config(const struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wrist gesture configurations like wearable-arm, + * and output-configuration for wearable variant. + * + * @param[in] config : Structure instance of bmi2_wrist_gest_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_gest_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Device in left (0) or right (1) arm. By default, + * wear_arm | the wearable device is assumed to be in left arm + * | i.e. default value is 0. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_gest_w_config(const struct bmi2_wrist_gest_w_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wrist wear wake-up configurations like + * output-configuration for wearable variant. + * + * @param[in] config : Structure instance of + * bmi2_wrist_wear_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_wear_wake_up_config | + * Structure parameters | Description + *----------------------------------|------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto + * | the interrupt pin. + * ---------------------------------|------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_wear_wake_up_wh_config(const struct bmi2_wrist_wear_wake_up_wh_config *config, + struct bmi2_dev *dev); + +/*! + * @brief This internal API gets accelerometer configurations like ODR, + * bandwidth, performance mode and g-range. + * + * @param[out] config : Structure instance of bmi2_accel_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t get_accel_config(struct bmi2_accel_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets gyroscope configurations like ODR, bandwidth, + * low power/ high performance mode, performance mode and range. + * + * @param[out] config : Structure instance of bmi2_gyro_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_config(struct bmi2_gyro_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API: + * 1) Gets the status of auxiliary interface enable. + * 2) Gets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3) Gets ODR and offset. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the enable status of auxiliary interface. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_interface(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_interface_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets read out offset and ODR of the auxiliary + * sensor. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_cfg(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets any-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[out] config : Structure instance of bmi2_any_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_any_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_any_motion_config(struct bmi2_any_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets no-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[out] config : Structure instance of bmi2_no_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_no_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_no_motion_config(struct bmi2_no_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets sig-motion configurations like block-size, + * output-configuration and other parameters. + * + * @param[out] config : Structure instance of bmi2_sig_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + *---------------------------------------------------------------------------- + * bmi2_sig_motion_config | + * Structure parameters | Description + * -------------------------|--------------------------------------------------- + * | Defines the duration after which the significant + * block_size | motion interrupt is triggered. It is expressed in + * | 50 Hz samples (20 ms). Default value is 0xFA=5sec. + *--------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + *--------------------------|--------------------------------------------------- + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_sig_motion_config(struct bmi2_sig_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets step counter parameter configurations. + * + * @param[in] step_count_params : Array that stores parameters 1 to 25. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_step_count_params_config(uint16_t *step_count_params, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets step counter/detector/activity configurations. + * + * @param[out] config : Structure instance of bmi2_step_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_step_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | The Step-counter will trigger output every time + * | the number of steps are counted. Holds implicitly + * water-mark level | a 20x factor, so the range is 0 to 10230, + * | with resolution of 20 steps. + * -------------------------|--------------------------------------------------- + * reset counter | Flag to reset the counted steps. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_det_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step detector. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_act_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step activity. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_step_config(struct bmi2_step_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + * + * @param[out] config : Structure instance of bmi2_gyro_user_gain_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_gyro_user_gain_config| + * Structure parameters | Description + *-------------------------|-------------------------------------------------- + * ratio_x | Gain update value for x-axis + * ------------------------|--------------------------------------------------- + * ratio_y | Gain update value for y-axis + * ------------------------|--------------------------------------------------- + * ratio_z | Gain update value for z-axis + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_gain_update_config(struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets tilt configurations like output-configuration. + * + * @param[out] config : Structure instance of bmi2_tilt_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_tilt_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_tilt_config(struct bmi2_tilt_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets uphold to wake configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_up_hold_to_wake_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_up_hold_to_wake_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_up_hold_to_wake_config(struct bmi2_up_hold_to_wake_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets glance detector configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_glance_det_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_glance_det_config| + * Structure parameters | Description + *-------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * ------------------------|---------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_glance_detect_config(struct bmi2_glance_det_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + * + * @param[out] config : Structure instance of bmi2_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wake_up_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Configures wake-up sensitivity, the range goes + * sensitivity | from 0 (high sensitive) to 7 (low sensitive). + * -------------------------|--------------------------------------------------- + * | Enable - Single Tap detection + * single_tap_en | Disable- Double Tap detection (Default value) + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wake_up_config(struct bmi2_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wrist gesture configurations like wearable-arm, + * and output-configuration. + * + * @param[out] config : Structure instance of bmi2_wrist_gest_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_gest_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Device in left (0) or right (1) arm. By default, + * wear_arm | the wearable device is assumed to be in left arm + * | i.e. default value is 0. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_gest_config(struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wrist wear wake-up configurations like + * output-configuration. + * + * @param[out] config : Structure instance of + * bmi2_wrist_wear_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_wear_wake_up_config | + * Structure parameters | Description + *----------------------------------|------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto + * | the interrupt pin. + * ---------------------------------|------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_wear_wake_up_config(struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wrist gesture configurations like wearable-arm, + * and output-configuration for wearable variant. + * + * @param[out] config : Structure instance of bmi2_wrist_gest_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_gest_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Device in left (0) or right (1) arm. By default, + * wear_arm | the wearable device is assumed to be in left arm + * | i.e. default value is 0. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_gest_w_config(struct bmi2_wrist_gest_w_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wrist wear wake-up configurations like + * output-configuration for wearable variant. + * + * @param[out] config : Structure instance of + * bmi2_wrist_wear_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_wear_wake_up_config | + * Structure parameters | Description + *----------------------------------|------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto + * | the interrupt pin. + * ---------------------------------|------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_wear_wake_up_wh_config(struct bmi2_wrist_wear_wake_up_wh_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + * + * @param[out] config : Structure instance of bmi2_orient_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_orient_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * upside/down | Enables upside/down detection, if set to 1. + * detection | + * -------------------------|--------------------------------------------------- + * | Sets the mode: + * mode | Values 0 or 3 - symmetrical. + * | Value 1 - high asymmetrical + * | Value 2 - low asymmetrical + * -------------------------|--------------------------------------------------- + * | Enable - no orientation interrupt will be set. + * blocking | Default value: 3, the most restrictive blocking. + * -------------------------|--------------------------------------------------- + * | Threshold angle used in blocking mode. + * theta | Theta = 64 * (tan(angle)^2) + * | Default value: 40, equivalent to 38 degrees angle. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for Orientation detection + * | is expressed in 5.11g format. + * hysteresis | Default value is 128 = 0.0625g. + * | Range is 0 to 1g. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_orient_config(struct bmi2_orient_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets high-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[out] config : Structure instance of bmi2_high_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_high_g_config | + * Structure parameter | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | high_g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * | Range is 0 to 16g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for high-g detection + * | is expressed in 1.11g format. + * hysteresis | Default value is 256 = 0.125 g. + * | Range is 0 to 2g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 200 Hz samples (5 ms) for + * | which the threshold has to be exceeded. + * duration |Default value 4 = 20 msec. + * | Range is 0 to 20sec. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_high_g_config(struct bmi2_high_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[out] config : Structure instance of bmi2_low_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + * bmi2_low_g_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | low-g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for low-g detection + * hysteresis | is expressed in 1.11g format. + * | Default value is 512 = 0.250 g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50 Hz samples (20 ms) for + * | which the threshold has to be exceeded. + * duration | Default value 0 = 1 validation sample = (0+1)*20 + * | = 20 ms. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_low_g_config(struct bmi2_low_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + * + * @param[out] config : Structure instance of bmi2_flat_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_flat_config | + * Structure parameters| Description + *--------------------------|-------------------------------------------------- + * | Theta angle, used for detecting flat + * | position. + * theta | Theta = 64 * (tan(angle)^2); + * | Default value is 8, equivalent to 20 degrees angle + * -------------------------|--------------------------------------------------- + * | Hysteresis for Theta Flat detection. + * hysteresis | Default value is 9 = 2.5 degrees, corresponding + * | to the default Theta angle of 20 degrees. + * -------------------------|--------------------------------------------------- + * | Sets the blocking mode. If blocking is set, no + * | Flat interrupt will be triggered. + * blocking | Default value is 2, the most restrictive blocking + * | mode. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50Hz samples for which the + * | condition has to be respected. + * hold-time | Default value is 32 = 640 m-sec. + * | Range is 0 to 5.1 sec. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_flat_config(struct bmi2_flat_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets external sensor sync configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_ext_sens_sync_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_ext_sens_sync_config | + * Structure parameters | Description + * -----------------------------|---------------------------------------------- + * |Enable bits for enabling output into the + * out_conf |register status bits and, if desired, onto the + * |interrupt pin. + * -----------------------------|---------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_ext_sens_sync_config(struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the accelerometer data from the register. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] reg_addr : Register address where data is stored. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t get_accel_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the gyroscope data from the register. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] reg_addr : Register address where data is stored. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t get_gyro_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the accelerometer/gyroscope data. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] reg_data : Data stored in the register. + * + * @return None + * + * @retval None + */ +static void get_acc_gyr_data(struct bmi2_sens_axes_data *data, const uint8_t *reg_data); + +/*! + * @brief This internal API gets the re-mapped accelerometer/gyroscope data. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * + * @retval None + */ +static void get_remapped_data(struct bmi2_sens_axes_data *data, const struct bmi2_dev *dev); + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in data mode. + * + * @param[out] aux_data : Pointer to the stored auxiliary data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration + */ +static int8_t read_aux_data_mode(uint8_t *aux_data, const struct bmi2_dev *dev); + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in manual mode. + * + * @param[in] reg_addr : AUX address from where data is read. + * @param[out] aux_data : Pointer to the stored auxiliary data. + * @param[in] len : Total bytes to be read. + * @param[in] burst_len : Bytes of data to be read in bursts. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t read_aux_data(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, uint8_t burst_len, struct bmi2_dev *dev); + +/*! + * @brief This internal API checks the busy status of auxiliary sensor and sets + * the auxiliary register addresses when not busy. + * + * @param[in] reg_addr : Address in which AUX register address is + * set. + * @param[in] reg_data : Auxiliary register address to be set when AUX is + * not busy. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t set_if_aux_not_busy(uint8_t reg_addr, uint8_t reg_data, struct bmi2_dev *dev); + +/*! + * @brief his internal API maps the actual burst read length with that of the + * register value set by user. + * + * @param[out] len : Actual burst length. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration + */ +static int8_t map_read_len(uint8_t *len, const struct bmi2_dev *dev); + +/*! + * @brief This internal API writes AUX write address and the user-defined bytes + * of data to the AUX sensor in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + * + * @param[in] reg_addr : AUX address in which data is to be written. + * @param[in] reg_data : Data to be written + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t write_aux_data(uint8_t reg_addr, uint8_t reg_data, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of step counter. + * + * @param[out] step_count : Pointer to the stored step counter data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_step_counter_output(uint32_t *step_count, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of step activity. + * + * @param[out] step_act : Pointer to the stored step activity data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * *step_act | Output + * -----------|------------ + * 0x00 | STILL + * 0x01 | WALKING + * 0x02 | RUNNING + * 0x03 | UNKNOWN + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_step_activity_output(uint8_t *step_act, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of orientation: portrait- + * landscape and face up-down. + * + * @param[out] orient_out : Structure pointer to the orientation data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * + * portrait | + * landscape | Output + * -----------|------------ + * 0x00 | PORTRAIT UPRIGHT + * 0x01 | LANDSCAPE LEFT + * 0x02 | PORTRAIT UPSIDE DOWN + * 0x03 | LANDSCAPE RIGHT + * + * Face | + * up-down | Output + * -----------|------------ + * 0x00 | FACE-UP + * 0x01 | FACE-DOWN + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_orient_output(struct bmi2_orientation_output *orient_out, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of high-g. + * + * @param[out] high_g_out : Pointer to the stored high-g output. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_high_g_output(uint8_t *high_g_out, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of wrist gesture. + * + * @param[out] wrist_gest : Pointer to the stored wrist gesture. + * @param[in] dev : Structure instance of bmi2_dev. + * + * *wrist_gest | Output + * -------------|------------ + * 0x00 | UNKNOWN + * 0x01 | PUSH_ARM_DOWN + * 0x02 | PIVOT_UP + * 0x03 | WRIST_SHAKE_JIGGLE + * 0x04 | FLICK_IN + * 0x05 | FLICK_OUT + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_gest_status(uint8_t *wrist_gest, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the cross sensitivity coefficient between + * gyroscope's X and Z axes. + * + * @param[out] cross_sense : Pointer to the stored cross sensitivity + * coefficient. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_cross_sense(int16_t *cross_sense, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the saturation status for the gyroscope user + * gain update. + * + * @param[out] user_gain_stat : Stores the saturation status of the axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_gain_update_status(struct bmi2_gyr_user_gain_status *user_gain, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the error status related to NVM. + * + * @param[out] nvm_err_stat : Stores the NVM error status. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_nvm_error_status(struct bmi2_nvm_err_status *nvm_err_stat, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the error status related to virtual frames. + * + * @param[out] vfrm_err_stat : Stores the VFRM related error status. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_vfrm_error_status(struct bmi2_vfrm_err_status *vfrm_err_stat, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse and store the activity recognition + * output from the FIFO data. + * + * @param[out] act_recog : Structure to retrieve output of activity + * recognition frame. + * @param[in] data_index : Index of the FIFO data which contains + * activity recognition frame. + * @param[out] fifo : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_act_recog_output(struct bmi2_act_recog_output *act_recog, + uint16_t *data_index, + const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to get enable status of gyroscope user gain + * update. + * + * @param[out] status : Stores status of gyroscope user gain update. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_user_gain_upd_status(uint8_t *status, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the accelerometer self-test status. + * + * @param[out] acc_self_test_stat : Stores status of accelerometer self- + * test. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_accel_self_test_status(struct bmi2_acc_self_test_status *acc_self_test_stat, struct bmi2_dev *dev); + +/*! + * @brief This internal API maps/unmaps feature interrupts to that of interrupt + * pins. + * + * @param[in] int_pin : Interrupt pin selected. + * @param[in] feat_int : Type of feature interrupt to be mapped or the value + * of out_conf. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_FEAT_BIT - Error: Invalid feature Interrupt + */ +static int8_t map_feat_int(uint8_t *reg_data_array, enum bmi2_hw_int_pin int_pin, uint8_t int_mask); + +/*! + * @brief This internal API computes the number of bytes of accelerometer FIFO + * data which is to be parsed in header-less mode. + * + * @param[out] start_idx : The start index for parsing data. + * @param[out] len : Number of bytes to be parsed. + * @param[in] acc_count : Number of accelerometer frames to be read. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + */ +static int8_t parse_fifo_accel_len(uint16_t *start_idx, + uint16_t *len, + const uint16_t *acc_count, + const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to parse accelerometer data from the FIFO + * data in header mode. + * + * @param[out] acc : Structure instance of bmi2_sens_axes_data where + * the parsed accelerometer data bytes are stored. + * @param[in] accel_length : Number of accelerometer frames (x,y,z data). + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t extract_accel_header_mode(struct bmi2_sens_axes_data *acc, + uint16_t *accel_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse the accelerometer data from the + * FIFO data in both header and header-less mode. It updates the current data + * byte to be parsed. + * + * @param[in,out] acc : Structure instance of bmi2_sens_axes_data where + * where the parsed data bytes are stored. + * @param[in,out] idx : Index value of number of bytes parsed. + * @param[in,out] acc_idx : Index value of accelerometer data (x,y,z axes) + * frame to be parsed. + * @param[in] frame : Either data is enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_accel_frame(struct bmi2_sens_axes_data *acc, + uint16_t *idx, + uint16_t *acc_idx, + uint8_t frame, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse accelerometer data from the FIFO + * data. + * + * @param[out] acc : Structure instance of bmi2_sens_axes_data + * where the parsed data bytes are stored. + * @param[in] data_start_index : Index value of the accelerometer data bytes + * which is to be parsed from the FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void unpack_accel_data(struct bmi2_sens_axes_data *acc, + uint16_t data_start_index, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API computes the number of bytes of gyroscope FIFO data + * which is to be parsed in header-less mode. + * + * @param[out] start_idx : The start index for parsing data. + * @param[out] len : Number of bytes to be parsed. + * @param[in] gyr_count : Number of gyroscope frames to be read. + * @param[in] frame : Either data enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + */ +static int8_t parse_fifo_gyro_len(uint16_t *start_idx, + uint16_t(*len), + const uint16_t *gyr_count, + const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to parse the gyroscope data from the FIFO + * data in both header and header-less mode It updates the current data byte to + * be parsed. + * + * @param[in,out] gyr : Structure instance of bmi2_sens_axes_data. + * @param[in,out] idx : Index value of number of bytes parsed + * @param[in,out] gyr_idx : Index value of gyroscope data (x,y,z axes) + * frame to be parsed. + * @param[in] frame : Either data is enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_gyro_frame(struct bmi2_sens_axes_data *gyr, + uint16_t *idx, + uint16_t *gyr_idx, + uint8_t frame, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse gyroscope data from the FIFO data. + * + * @param[out] gyr : Structure instance of bmi2_sens_axes_data where + * the parsed gyroscope data bytes are stored. + * @param[in] data_start_index : Index value of the gyroscope data bytes + * which is to be parsed from the FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void unpack_gyro_data(struct bmi2_sens_axes_data *gyr, + uint16_t data_start_index, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse the gyroscope data from the + * FIFO data in header mode. + * + * @param[out] gyr : Structure instance of bmi2_sens_axes_data where + * the parsed gyroscope data bytes are stored. + * @param[in] gyro_length : Number of gyroscope frames (x,y,z data). + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t extract_gyro_header_mode(struct bmi2_sens_axes_data *gyr, + uint16_t *gyro_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API computes the number of bytes of auxiliary FIFO data + * which is to be parsed in header-less mode. + * + * @param[out] start_idx : The start index for parsing data. + * @param[out] len : Number of bytes to be parsed. + * @param[in] aux_count : Number of accelerometer frames to be read. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + */ +static int8_t parse_fifo_aux_len(uint16_t *start_idx, + uint16_t(*len), + const uint16_t *aux_count, + const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This API is used to parse auxiliary data from the FIFO data. + * + * @param[out] aux : Pointer to buffer where the parsed auxiliary data + * bytes are stored. + * @param[in] aux_length : Number of auxiliary frames (x,y,z data). + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t extract_aux_header_mode(struct bmi2_aux_fifo_data *aux, + uint16_t *aux_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API is used to parse the auxiliary data from the FIFO data in + * both header and header-less mode. It updates the current data byte to be + * parsed. + * + * @param[out] aux : Pointer to structure where the parsed auxiliary data + * bytes are stored. + * @param[in,out] idx : Index value of number of bytes parsed + * @param[in,out] aux_idx : Index value of auxiliary data (x,y,z axes) + * frame to be parsed + * @param[in] frame : Either data is enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_aux_frame(struct bmi2_aux_fifo_data *aux, + uint16_t *idx, + uint16_t *aux_idx, + uint8_t frame, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API is used to parse auxiliary data from the FIFO data. + * + * @param[out] aux : Pointer to structure where the parsed + * auxiliary data bytes are stored. + * @param[in] data_start_index : Index value of the auxiliary data bytes which + * is to be parsed from the FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void unpack_aux_data(struct bmi2_aux_fifo_data *aux, + uint16_t data_start_index, + const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to reset the FIFO related configurations + * in the FIFO frame structure for the next FIFO read. + * + * @param[in, out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void reset_fifo_frame_structure(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * @brief This internal API checks whether the FIFO data read is an empty frame. + * If empty frame, index is moved to the last byte. + * + * @param[in,out] data_index : The index of the current data to be parsed from + * FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t check_empty_fifo(uint16_t *data_index, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to move the data index ahead of the + * current frame length parameter when unnecessary FIFO data appears while + * extracting the user specified data. + * + * @param[in,out] data_index : Index of the FIFO data which is to be + * moved ahead of the current frame length + * @param[in] current_frame_length : Number of bytes in the current frame. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to parse and store the sensor time from the + * FIFO data. + * + * @param[in,out] data_index : Index of the FIFO data which has the sensor time. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_sensortime_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to parse and store the skipped frame count + * from the FIFO data. + * + * @param[in,out] data_index : Index of the FIFO data which contains skipped + * frame count. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_skipped_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API enables and configures the accelerometer which is + * needed for self-test operation. It also sets the amplitude for the self-test. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t pre_self_test_config(struct bmi2_dev *dev); + +/*! + * @brief This internal API performs the steps needed for self-test operation + * before reading the accelerometer self-test data. + * + * @param[in] sign : Selects sign of self-test excitation + * @param[in] dev : Structure instance of bmi2_dev. + * + * sign | Description + * -------------|--------------- + * BMI2_ENABLE | positive excitation + * BMI2_DISABLE | negative excitation + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t self_test_config(uint8_t sign, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables or disables the accelerometer self-test + * feature in the sensor. + * + * @param[in] enable : Enables/ Disables self-test. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sign | Description + * -------------|--------------- + * BMI2_ENABLE | Enables self-test + * BMI2_DISABLE | Disables self-test + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_accel_self_test_enable(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API selects the sign for accelerometer self-test + * excitation. + * + * @param[in] sign : Selects sign of self-test excitation + * @param[in] dev : Structure instance of bmi2_dev. + * + * sign | Description + * -------------|--------------- + * BMI2_ENABLE | positive excitation + * BMI2_DISABLE | negative excitation + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_acc_self_test_sign(uint8_t sign, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets the amplitude of the accelerometer self-test + * deflection in the sensor. + * + * @param[in] amp : Select amplitude of the self-test deflection. + * @param[in] dev : Structure instance of bmi2_dev. + * + * amp | Description + * -------------|--------------- + * BMI2_ENABLE | self-test amplitude is high + * BMI2_DISABLE | self-test amplitude is low + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_accel_self_test_amp(uint8_t amp, struct bmi2_dev *dev); + +/*! + * @brief This internal API reads the accelerometer data for x,y and z axis from + * the sensor. The data units is in LSB format. + * + * @param[out] accel : Buffer to store the acceleration value. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t read_accel_xyz(struct bmi2_sens_axes_data *accel, const struct bmi2_dev *dev); + +/*! + * @brief This internal API converts LSB value of accelerometer axes to form + * 'g' to 'mg' for self-test. + * + * @param[in] acc_data_diff : Stores the acceleration value difference in g. + * @param[out]acc_data_diff_mg : Stores the acceleration value difference in mg. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void convert_lsb_g(const struct selftest_delta_limit *acc_data_diff, + struct selftest_delta_limit *acc_data_diff_mg, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to calculate the power of a value. + * + * @param[in] base : base for power calculation. + * @param[in] resolution : exponent for power calculation. + * + * @return the calculated power + * @retval the power value + */ +static int32_t power(int16_t base, uint8_t resolution); + +/*! + * @brief This internal API validates the accelerometer self-test data and + * decides the result of self-test operation. + * + * @param[in] accel_data_diff : Stores the acceleration value difference. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_SELF_TEST_FAIL - Error: Self-test fail + */ +static int8_t validate_self_test(const struct selftest_delta_limit *accel_data_diff); + +/*! + * @brief This internal API gets the re-mapped x, y and z axes from the sensor. + * + * @param[out] remap : Structure that stores local copy of re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_remap_axes(struct axes_remap *remap, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets the re-mapped x, y and z axes in the sensor. + * + * @param[in] remap : Structure that stores local copy of re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_remap_axes(const struct axes_remap *remap, struct bmi2_dev *dev); + +/*! + * @brief Interface to get max burst length + * + * @param[in] max_burst_len : Pointer to store max burst length + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_maxburst_len(uint8_t *max_burst_len, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets the max burst length. + * + * @param[in] write_len_byte : read & write length + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_maxburst_len(const uint16_t write_len_byte, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to get the feature configuration from the + * selected page. + * + * @param[in] sw_page : Switches to the desired page. + * @param[out] feat_config : Pointer to the feature configuration. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_feat_config(uint8_t sw_page, uint8_t *feat_config, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables compensation of the gain defined + * in the GAIN register. + * + * @param[in] enable : Enables/Disables gain compensation + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enable gain compensation. + * BMI2_DISABLE | Disable gain compensation. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t enable_gyro_gain(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API parses virtual frame header from the FIFO data. + * + * @param[in, out] frame_header : FIFO frame header. + * @param[in, out] data_index : Index value of the FIFO data bytes + * from which sensor frame header is to be parsed + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void parse_if_virtual_header(uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API gets sensor time from the accelerometer and + * gyroscope virtual frames and updates in the data structure. + * + * @param[out] sens : Sensor data structure + * @param[in, out] idx : Index of FIFO from where the data is to retrieved. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void unpack_virt_sensor_time(struct bmi2_sens_axes_data *sens, uint16_t *idx, + const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API gets sensor time from the auxiliary virtual + * frames and updates in the data structure. + * + * @param[out] aux : Auxiliary sensor data structure + * @param[in, out] idx : Index of FIFO from where the data is to retrieved. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void unpack_virt_aux_sensor_time(struct bmi2_aux_fifo_data *aux, + uint16_t *idx, + const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API skips S4S frame in the FIFO data while getting + * activity recognition output. + * + * @param[in, out] frame_header : FIFO frame header. + * @param[in, out] data_index : Index value of the FIFO data bytes + * from which S4S frame header is to be + * skipped. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t move_if_s4s_frame(const uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API corrects the gyroscope cross-axis sensitivity + * between the z and the x axis. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[out] gyr_data : Structure instance of gyroscope data + * + * @return Result of API execution status + * + * @return None + * @retval None + */ +static void comp_gyro_cross_axis_sensitivity(struct bmi2_sens_axes_data *gyr_data, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to extract the input feature configuration + * details like page and start address from the look-up table. + * + * @param[out] feat_config : Structure that stores feature configurations. + * @param[in] type : Type of feature or sensor. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Returns the feature found flag. + * + * @retval BMI2_FALSE : Feature not found + * BMI2_TRUE : Feature found + */ +static uint8_t extract_input_feat_config(struct bmi2_feature_config *feat_config, + uint8_t type, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to extract the output feature configuration + * details like page and start address from the look-up table. + * + * @param[out] feat_output : Structure that stores output feature + * configurations. + * @param[in] type : Type of feature or sensor. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Returns the feature found flag. + * + * @retval BMI2_FALSE : Feature not found + * BMI2_TRUE : Feature found + */ +static uint8_t extract_output_feat_config(struct bmi2_feature_config *feat_output, + uint8_t type, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API saves the configurations before performing FOC. + * + * @param[out] acc_cfg : Accelerometer configuration value + * @param[out] aps : Advance power mode value + * @param[out] acc_en : Accelerometer enable value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t save_accel_foc_config(struct bmi2_accel_config *acc_cfg, + uint8_t *aps, + uint8_t *acc_en, + struct bmi2_dev *dev); + +/*! + * @brief This internal API performs Fast Offset Compensation for accelerometer. + * + * @param[in] accel_g_value : This parameter selects the accel foc + * axis to be performed + * + * input format is {x, y, z, sign}. '1' to enable. '0' to disable + * + * eg to choose x axis {1, 0, 0, 0} + * eg to choose -x axis {1, 0, 0, 1} + * + * @param[in] acc_cfg : Accelerometer configuration value + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t perform_accel_foc(const struct accel_foc_g_value *accel_g_value, + const struct bmi2_accel_config *acc_cfg, + struct bmi2_dev *dev); + +/*! + * @brief This internal sets configurations for performing accelerometer FOC. + * + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t set_accel_foc_config(struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables the offset compensation for + * filtered and un-filtered accelerometer data. + * + * @param[in] offset_en : enables/disables offset compensation. + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_accel_offset_comp(uint8_t offset_en, struct bmi2_dev *dev); + +/*! + * @brief This internal API converts the range value into accelerometer + * corresponding integer value. + * + * @param[in] range_in : Input range value. + * @param[out] range_out : Stores the integer value of range. + * + * @return None + * @retval None + */ +static void map_accel_range(uint8_t range_in, uint8_t *range_out); + +/*! + * @brief This internal API compensate the accelerometer data against gravity. + * + * @param[in] lsb_per_g : LSB value pre 1g. + * @param[in] g_val : G reference value of all axis. + * @param[in] data : Accelerometer data + * @param[out] comp_data : Stores the data that is compensated by taking the + * difference in accelerometer data and lsb_per_g + * value. + * + * @return None + * @retval None + */ +static void comp_for_gravity(uint16_t lsb_per_g, + const struct accel_foc_g_value *g_val, + const struct bmi2_sens_axes_data *data, + struct offset_delta *comp_data); + +/*! + * @brief This internal API scales the compensated accelerometer data according + * to the offset register resolution. + * + * @param[in] range : G-range of the accelerometer. + * @param[out] comp_data : Data that is compensated by taking the + * difference in accelerometer data and lsb_per_g + * value. + * @param[out] data : Stores offset data + * + * @return None + * @retval None + */ +static void scale_accel_offset(uint8_t range, const struct offset_delta *comp_data, struct accel_offset *data); + +/*! + * @brief This internal API finds the bit position of 3.9mg according to given + * range and resolution. + * + * @param[in] range : G-range of the accelerometer. + * + * @return Result of API execution status + * @retval Bit position of 3.9mg + */ +static int8_t get_bit_pos_3_9mg(uint8_t range); + +/*! + * @brief This internal API inverts the accelerometer offset data. + * + * @param[out] offset_data : Stores the inverted offset data + * + * @return None + * @retval None + */ +static void invert_accel_offset(struct accel_offset *offset_data); + +/*! + * @brief This internal API writes the offset data in the offset compensation + * register. + * + * @param[in] offset : offset data + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t write_accel_offset(const struct accel_offset *offset, struct bmi2_dev *dev); + +/*! + * @brief This internal API restores the configurations saved before performing + * accelerometer FOC. + * + * @param[in] acc_cfg : Accelerometer configuration value + * @param[in] acc_en : Accelerometer enable value + * @param[in] aps : Advance power mode value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +static int8_t restore_accel_foc_config(struct bmi2_accel_config *acc_cfg, + uint8_t aps, + uint8_t acc_en, + struct bmi2_dev *dev); + +/*! + * @brief This internal API saves the configurations before performing gyroscope + * FOC. + * + * @param[out] gyr_cfg : Gyroscope configuration value + * @param[out] gyr_en : Gyroscope enable value + * @param[out] aps : Advance power mode value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t save_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t *aps, uint8_t *gyr_en, struct bmi2_dev *dev); + +/*! + * @brief This internal sets configurations for performing gyroscope FOC. + * + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t set_gyro_foc_config(struct bmi2_dev *dev); + +/*! + * @brief This internal API inverts the gyroscope offset data. + * + * @param[out] offset_data : Stores the inverted offset data + * + * @return None + * @retval None + */ +static void invert_gyro_offset(struct bmi2_sens_axes_data *offset_data); + +/*! + * @brief This internal API restores the gyroscope configurations saved + * before performing FOC. + * + * @param[in] gyr_cfg : Gyroscope configuration value + * @param[in] gyr_en : Gyroscope enable value + * @param[in] aps : Advance power mode value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t restore_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t aps, uint8_t gyr_en, struct bmi2_dev *dev); + +/*! + * @brief This internal API saturates the gyroscope data value before writing to + * to 10 bit offset register. + * + * @param[in, out] gyr_off : Gyroscope data to be stored in offset register + * + * @return None + * @retval None + */ +static void saturate_gyro_data(struct bmi2_sens_axes_data *gyr_off); + +/*! + * @brief This internal API reads the gyroscope data for x, y and z axis from + * the sensor. + * + * @param[out] gyro : Buffer to store the gyroscope value. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t read_gyro_xyz(struct bmi2_sens_axes_data *gyro, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to check the boundary conditions. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in,out] val : Pointer to the value to be validated. + * @param[in] min : minimum value. + * @param[in] max : maximum value. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * + */ +static int8_t check_boundary_val(uint8_t *val, uint8_t min, uint8_t max, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to validate the device pointer for + * null conditions. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev); + +/*! + * @brief This updates the result for CRT or gyro self-test. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_CRT_ERROR - Error: CRT Fail + * + */ +static int8_t crt_gyro_st_update_result(struct bmi2_dev *dev); + +/*! + * @brief This function is to get the st_status status. + * + * @param[in] *st_status: gets the crt running status + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t get_st_running(uint8_t *st_status, const struct bmi2_dev *dev); + +/*! + * @brief This function is to set crt bit to running. + * + * @param[in] enable + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t set_st_running(uint8_t st_status, struct bmi2_dev *dev); + +/*! + * @brief This function is to make the initial changes for CRT. + * Disable the gyro, OIS, aps + * Note: For the purpose of preparing CRT Gyro, OIS and APS are disabled + * + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t crt_prepare_setup(struct bmi2_dev *dev); + +static int8_t do_gtrigger_test(uint8_t gyro_st_crt, struct bmi2_dev *dev); + +/*! + * @brief This function is to get the rdy for dl bit status + * this will toggle from 0 to 1 and visevers according to the + * dowload status + * + * @param[in] *rdy_for_dl: gets the rdy_for_dl status + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t get_rdy_for_dl(uint8_t *rdy_for_dl, const struct bmi2_dev *dev); + +/*! + * @brief This function is to write the config file in the given location for crt. + * which inter checks the status of the rdy_for_dl bit and also the crt running, and + * wirtes the given size. + * + * @param[in] write_len: length of the words to be written + * @param[in] config_file_size: length of the words to be written + * @param[in] start_index: provide the start index from where config file has to written + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t write_crt_config_file(uint16_t write_len, + uint16_t config_file_size, + uint16_t start_index, + struct bmi2_dev *dev); + +/*! + * @brief This function is to check for rdy_for_dl bit to toggle for CRT process + * + * @param[in] retry_complete: wait for given time to toggle + * @param[in] download_ready: get the status for rdy_for_dl + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t wait_rdy_for_dl_toggle(uint8_t retry_complete, uint8_t download_ready, const struct bmi2_dev *dev); + +/*! + * @brief This function is to wait till the CRT or gyro self-test process is completed + * + * @param[in] retry_complete: wait for given time to complete the crt process + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t wait_st_running(uint8_t retry_complete, const struct bmi2_dev *dev); + +/*! + * @brief This function is to complete the crt process if max burst length is not zero + * this checks for the crt status and rdy_for_dl bit to toggle + * + * @param[in] last_byte_flag: to provide the last toggled state + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * + */ +static int8_t process_crt_download(uint8_t last_byte_flag, struct bmi2_dev *dev); + +/*! + * @brief This api is used to enable the gyro self-test or crt. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t select_self_test(uint8_t gyro_st_crt, struct bmi2_dev *dev); + +/*! + * @brief This api is used to enable/disable abort. + * + * @param[in] abort_enable : variable to enable the abort feature. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t abort_bmi2(uint8_t abort_enable, struct bmi2_dev *dev); + +/*! + * @brief This api is use to wait till gyro self-test is completed and update the status of gyro + * self-test. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval <0 - Fail + */ +static int8_t gyro_self_test_completed(struct bmi2_gyro_self_test_status *gyro_st_result, const struct bmi2_dev *dev); + +/*! + * @brief This api is used to trigger the preparation for system for NVM programming. + * + * @param[out] nvm_prep : pointer to variable to store the status of nvm_prep_prog. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_nvm_prep_prog(uint8_t nvm_prep, struct bmi2_dev *dev); + +/*! + * @brief This api validates accel foc position as per the range + * + * @param[in] sens_list : Sensor type + * @param[in] accel_g_axis : accel axis to foc. NA for gyro foc + * @param[in] avg_foc_data : average value of sensor sample datas + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_INVALID_INPUT - Error: Invalid input + */ +static int8_t validate_foc_position(uint8_t sens_list, + const struct accel_foc_g_value *accel_g_axis, + struct bmi2_sens_axes_data avg_foc_data, + struct bmi2_dev *dev); + +/*! + * @brief This api validates accel foc axis given as input + * + * @param[in] avg_foc_data : average value of sensor sample datas + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_INVALID_INPUT - Error: Invalid input + */ +static int8_t validate_foc_accel_axis(int16_t avg_foc_data, struct bmi2_dev *dev); + +/*! + * @brief This api is used to verify the right position of the sensor before doing accel foc + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] sens_list: Sensor type + * @param[in] accel_g_axis: Accel Foc axis and sign input + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_INVALID_INPUT - Error: Invalid input + */ +static int8_t verify_foc_position(uint8_t sens_list, const struct accel_foc_g_value *accel_g_axis, + struct bmi2_dev *dev); + +/*! + * @brief This API reads and provides average for 128 samples of sensor data for foc operation + * gyro. + * + * @param[in] sens_list : Sensor type. + * @param[in] bmi2_dev: Structure instance of bmi2_dev. + * @param[in] temp_foc_data: to store data samples + * + * @return Result of API execution status + * + * @retval BMI2_OK + */ +static int8_t get_average_of_sensor_data(uint8_t sens_list, struct foc_temp_value *temp_foc_data, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets primary OIS configurations, + * low pass filter cut-off frequency. + * + * @param[in] config : Structure instance of bmi2_primary_ois_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_primary_ois_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * lp filter config | Lp filter cut off frequency + * | Value Name Description + * | 00 280_Hz Cut off frequency configured to 280 Hz + * | 01 350_Hz Cut off frequency configured to 350 Hz + * | 10 410_Hz Cut off frequency configured to 410 Hz + * | 11 612_Hz Cut off frequency configured to 612 Hz + * ---------------------------------------------------------------------------- + * + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_primary_ois_config(const struct bmi2_primary_ois_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets primary OIS configurations, + * low pass filter cut-off frequency. + * + * @param[out] config : Structure instance of bmi2_primary_ois_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_primary_ois_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * lp filter config | Lp filter cut off frequency + * | Value Name Description + * | 00 280_Hz Cut off frequency configured to 280 Hz + * | 01 350_Hz Cut off frequency configured to 350 Hz + * | 10 410_Hz Cut off frequency configured to 410 Hz + * | 11 612_Hz Cut off frequency configured to 612 Hz + * ---------------------------------------------------------------------------- + * + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_primary_ois_config(struct bmi2_primary_ois_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output data of OIS. + * + * @param[out] ois_output : Structure instance to the stored OIS data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_ois_output(struct bmi2_ois_output *ois_output, struct bmi2_dev *dev); + +/*! + * @brief This internal api gets major and minor version for config file + * + * @param[out] config_major : Pointer to store the major version + * @param[out] config_minor : Pointer to store the minor version + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t extract_config_file(uint16_t *config_major, uint8_t *config_minor, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets free-fall configurations like free-fall accel settings, + * and output configuration. + * + * @param[in] config : Structure instance of bmi2_free_fall_det_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_free_fall_det_config | + * Structure parameters | Description + *------------------------------|-------------------------------------------------- + * free-fall accel settings | Free-fall accel settings. + * 1 - 7 | + * -----------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -----------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_free_fall_det_config(struct bmi2_free_fall_det_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets free-fall configurations like free-fall accel settings, + * and output configuration. + * + * @param[in] config : Structure instance of bmi2_free_fall_det_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_free_fall_det_config | + * Structure parameters | Description + *------------------------------|-------------------------------------------------- + * free-fall accel settings | Free-fall accel settings. + * 1 - 7 | + * -----------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -----------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_free_fall_det_config(const struct bmi2_free_fall_det_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable free-fall detection feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables free-fall detection. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables free-fall detection + * BMI2_ENABLE | Enables free-fall detection + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_free_fall_det(uint8_t enable, struct bmi2_dev *dev); + +/******************************************************************************/ +/*! @name User Interface Definitions */ +/******************************************************************************/ + +/*! + * @brief This API is the entry point for bmi2 sensor. It selects between + * I2C/SPI interface, based on user selection. It reads and validates the + * chip-id of the sensor. + */ +int8_t bmi2_sec_init(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to assign chip id */ + uint8_t chip_id = 0; + + /* Structure to define the default values for axes re-mapping */ + struct bmi2_axes_remap axes_remap = { + .x_axis = MAP_X_AXIS, .x_axis_sign = POS_SIGN, .y_axis = MAP_Y_AXIS, .y_axis_sign = POS_SIGN, + .z_axis = MAP_Z_AXIS, .z_axis_sign = POS_SIGN + }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Perform soft-reset to bring all register values to their + * default values + */ + rslt = bmi2_soft_reset(dev); + if (rslt == BMI2_OK) + { + /* Read chip-id of the BMI2 sensor */ + rslt = bmi2_get_regs(BMI2_CHIP_ID_ADDR, &chip_id, 1, dev); + if (rslt == BMI2_OK) + { + /* Validate chip-id */ + if (chip_id == dev->chip_id) + { + /* Assign resolution to the structure */ + dev->resolution = 16; + + /* Set manual enable flag */ + dev->aux_man_en = 1; + + /* Set the default values for axis + * re-mapping in the device structure + */ + dev->remap = axes_remap; + } + else + { + /* Storing the chip-id value read from + * the register to identify the sensor + */ + dev->chip_id = chip_id; + rslt = BMI2_E_DEV_NOT_FOUND; + } + } + } + } + + return rslt; +} + +/*! + * @brief This API reads the data from the given register address of bmi2 + * sensor. + * + * @note For most of the registers auto address increment applies, with the + * exception of a few special registers, which trap the address. For e.g., + * Register address - 0x26, 0x5E. + */ +int8_t bmi2_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define temporary length */ + uint16_t temp_len = len + dev->dummy_byte; + + /* Variable to define temporary buffer */ + uint8_t temp_buf[temp_len]; + + /* Variable to define loop */ + uint16_t index = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (data != NULL)) + { + /* Configuring reg_addr for SPI Interface */ + if (dev->intf == BMI2_SPI_INTERFACE) + { + reg_addr = (reg_addr | BMI2_SPI_RD_MASK); + } + if (dev->aps_status == BMI2_ENABLE) + { + rslt = dev->read(dev->dev_id, reg_addr, temp_buf, temp_len); + dev->delay_us(450); + } + else + { + rslt = dev->read(dev->dev_id, reg_addr, temp_buf, temp_len); + dev->delay_us(20); + } + + if (rslt == BMI2_OK) + { + /* Read the data from the position next to dummy byte */ + while (index < len) + { + data[index] = temp_buf[index + dev->dummy_byte]; + index++; + } + } + else + { + rslt = BMI2_E_COM_FAIL; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes data to the given register address of bmi2 sensor. + */ +int8_t bmi2_set_regs(uint8_t reg_addr, const uint8_t *data, uint16_t len, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define loop */ + uint16_t loop = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (data != NULL)) + { + /* Configuring reg_addr for SPI Interface */ + if (dev->intf == BMI2_SPI_INTERFACE) + { + reg_addr = (reg_addr & BMI2_SPI_WR_MASK); + } + + if (dev->aps_status == BMI2_ENABLE) + { + for (loop = 0; loop < len; loop++) + { + /* Byte write if APS is enabled */ + rslt = dev->write(dev->dev_id, (uint8_t)((uint16_t) reg_addr + loop), &data[loop], 1); + dev->delay_us(450); + if (rslt != BMI2_OK) + { + break; + } + } + } + else + { + /* Burst write if APS is disabled */ + rslt = dev->write(dev->dev_id, reg_addr, data, len); + dev->delay_us(20); + } + + /* updating the advance power saver flag */ + if (reg_addr == BMI2_PWR_CONF_ADDR) + { + if (*data & BMI2_ADV_POW_EN_MASK) + { + dev->aps_status = BMI2_ENABLE; + } + else + { + dev->aps_status = BMI2_DISABLE; + } + } + if (rslt != BMI2_OK) + { + rslt = BMI2_E_COM_FAIL; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API resets bmi2 sensor. All registers are overwritten with + * their default values. + */ +int8_t bmi2_soft_reset(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define soft reset value */ + uint8_t data = BMI2_SOFT_RESET_CMD; + + /* Variable to read the dummy byte */ + uint8_t dummy_read = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Reset bmi2 device */ + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &data, 1, dev); + dev->delay_us(2000); + + /* set APS flag as after soft reset the sensor is on advance power save mode */ + dev->aps_status = BMI2_ENABLE; + + /* Performing a dummy read to bring interface back to SPI from + * I2C after a soft-reset + */ + if ((rslt == BMI2_OK) && (dev->intf == BMI2_SPI_INTERFACE)) + { + rslt = bmi2_get_regs(BMI2_CHIP_ID_ADDR, &dummy_read, 1, dev); + } + + if (rslt == BMI2_OK) + { + /* Write the configuration file */ + rslt = bmi2_write_config_file(dev); + } + + /* Reset the sensor status flag in the device structure */ + if (rslt == BMI2_OK) + { + dev->sens_en_stat = 0; + } + } + + return rslt; +} + +/*! + * @brief This API is used to get the config file major and minor version information. + */ +int8_t bmi2_get_config_file_version(uint16_t *config_major, uint8_t *config_minor, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* NULL pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (config_major != NULL) && (config_minor != NULL)) + { + /* Extract the config file identification from the dmr page and get the major and minor version */ + rslt = extract_config_file(config_major, config_minor, dev); + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API selects the sensors/features to be enabled. + */ +int8_t bmi2_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to select sensor */ + uint32_t sensor_sel = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_list != NULL)) + { + /* Get the selected sensors */ + rslt = select_sensor(sens_list, n_sens, &sensor_sel); + if (rslt == BMI2_OK) + { + /* Enable the selected sensors */ + rslt = sensor_enable(sensor_sel, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API selects the sensors/features to be disabled. + */ +int8_t bmi2_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to select sensor */ + uint32_t sensor_sel = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_list != NULL)) + { + /* Get the selected sensors */ + rslt = select_sensor(sens_list, n_sens, &sensor_sel); + if (rslt == BMI2_OK) + { + /* Disable the selected sensors */ + rslt = sensor_disable(sensor_sel, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the sensor/feature configuration. + */ +int8_t bmi2_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define loop */ + uint8_t loop; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_cfg != NULL)) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + for (loop = 0; loop < n_sens; loop++) + { + /* Disable Advance power save if enabled for auxiliary + * and feature configurations + */ + if ((sens_cfg[loop].type != BMI2_ACCEL) || (sens_cfg[loop].type != BMI2_GYRO) || + (sens_cfg[loop].type != BMI2_TEMP) || (sens_cfg[loop].type != BMI2_AUX)) + { + + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if + * enabled + */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + if (rslt == BMI2_OK) + { + switch (sens_cfg[loop].type) + { + /* Set accelerometer configuration */ + case BMI2_ACCEL: + rslt = set_accel_config(&sens_cfg[loop].cfg.acc, dev); + break; + + /* Set gyroscope configuration */ + case BMI2_GYRO: + rslt = set_gyro_config(&sens_cfg[loop].cfg.gyr, dev); + break; + + /* Set auxiliary configuration */ + case BMI2_AUX: + rslt = set_aux_config(&sens_cfg[loop].cfg.aux, dev); + break; + + /* Set any motion configuration */ + case BMI2_ANY_MOTION: + rslt = set_any_motion_config(&sens_cfg[loop].cfg.any_motion, dev); + break; + + /* Set no motion configuration */ + case BMI2_NO_MOTION: + rslt = set_no_motion_config(&sens_cfg[loop].cfg.no_motion, dev); + break; + + /* Set sig-motion configuration */ + case BMI2_SIG_MOTION: + rslt = set_sig_motion_config(&sens_cfg[loop].cfg.sig_motion, dev); + break; + + /* Set the step counter parameters */ + case BMI2_STEP_COUNTER_PARAMS: + rslt = set_step_count_params_config(sens_cfg[loop].cfg.step_counter_params, dev); + break; + + /* Set step counter/detector/activity configuration */ + case BMI2_STEP_DETECTOR: + case BMI2_STEP_COUNTER: + case BMI2_STEP_ACTIVITY: + rslt = set_step_config(&sens_cfg[loop].cfg.step_counter, dev); + break; + + /* Set gyroscope user gain configuration */ + case BMI2_GYRO_GAIN_UPDATE: + rslt = set_gyro_user_gain_config(&sens_cfg[loop].cfg.gyro_gain_update, dev); + break; + + /* Set tilt configuration */ + case BMI2_TILT: + rslt = set_tilt_config(&sens_cfg[loop].cfg.tilt, dev); + break; + + /* Set uphold to wake configuration */ + case BMI2_UP_HOLD_TO_WAKE: + rslt = set_up_hold_to_wake_config(&sens_cfg[loop].cfg.up_hold_to_wake, dev); + break; + + /* Set glance detector configuration */ + case BMI2_GLANCE_DETECTOR: + rslt = set_glance_detect_config(&sens_cfg[loop].cfg.glance_det, dev); + break; + + /* Set wake-up configuration */ + case BMI2_WAKE_UP: + rslt = set_wake_up_config(&sens_cfg[loop].cfg.tap, dev); + break; + + /* Set orientation configuration */ + case BMI2_ORIENTATION: + rslt = set_orient_config(&sens_cfg[loop].cfg.orientation, dev); + break; + + /* Set high-g configuration */ + case BMI2_HIGH_G: + rslt = set_high_g_config(&sens_cfg[loop].cfg.high_g, dev); + break; + + /* Set low-g configuration */ + case BMI2_LOW_G: + rslt = set_low_g_config(&sens_cfg[loop].cfg.low_g, dev); + break; + + /* Set flat configuration */ + case BMI2_FLAT: + rslt = set_flat_config(&sens_cfg[loop].cfg.flat, dev); + break; + + /* Set external sensor sync configuration */ + case BMI2_EXT_SENS_SYNC: + rslt = set_ext_sens_sync_config(&sens_cfg[loop].cfg.ext_sens_sync, dev); + break; + + /* Set the wrist gesture configuration */ + case BMI2_WRIST_GESTURE: + rslt = set_wrist_gest_config(&sens_cfg[loop].cfg.wrist_gest, dev); + break; + + /* Set the wrist wear wake-up configuration */ + case BMI2_WRIST_WEAR_WAKE_UP: + rslt = set_wrist_wear_wake_up_config(&sens_cfg[loop].cfg.wrist_wear_wake_up, dev); + break; + + /* Set the wrist gesture configuration */ + case BMI2_WRIST_GESTURE_WH: + rslt = set_wrist_gest_w_config(&sens_cfg[loop].cfg.wrist_gest_w, dev); + break; + + /* Set the wrist wear wake-up configuration for wearable variant */ + case BMI2_WRIST_WEAR_WAKE_UP_WH: + rslt = set_wrist_wear_wake_up_wh_config(&sens_cfg[loop].cfg.wrist_wear_wake_up_wh, dev); + break; + + /* Set primary OIS configuration */ + case BMI2_PRIMARY_OIS: + rslt = set_primary_ois_config(&sens_cfg[loop].cfg.primary_ois, dev); + break; + + /* Set the free-fall detection configurations */ + case BMI2_FREE_FALL_DET: + rslt = set_free_fall_det_config(&sens_cfg[loop].cfg.free_fall_det, dev); + break; + + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + /* Return error if any of the set configurations fail */ + if (rslt != BMI2_OK) + { + break; + } + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the sensor/feature configuration. + */ +int8_t bmi2_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define loop */ + uint8_t loop; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_cfg != NULL)) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + for (loop = 0; loop < n_sens; loop++) + { + /* Disable Advance power save if enabled for auxiliary + * and feature configurations + */ + if ((sens_cfg[loop].type >= BMI2_MAIN_SENS_MAX_NUM) || (sens_cfg[loop].type == BMI2_AUX)) + { + + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if + * enabled + */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + if (rslt == BMI2_OK) + { + switch (sens_cfg[loop].type) + { + /* Get accelerometer configuration */ + case BMI2_ACCEL: + rslt = get_accel_config(&sens_cfg[loop].cfg.acc, dev); + break; + + /* Get gyroscope configuration */ + case BMI2_GYRO: + rslt = get_gyro_config(&sens_cfg[loop].cfg.gyr, dev); + break; + + /* Get auxiliary configuration */ + case BMI2_AUX: + rslt = get_aux_config(&sens_cfg[loop].cfg.aux, dev); + break; + + /* Get sig-motion configuration */ + case BMI2_SIG_MOTION: + rslt = get_sig_motion_config(&sens_cfg[loop].cfg.sig_motion, dev); + break; + + /* Get any motion configuration */ + case BMI2_ANY_MOTION: + rslt = get_any_motion_config(&sens_cfg[loop].cfg.any_motion, dev); + break; + + /* Get no motion configuration */ + case BMI2_NO_MOTION: + rslt = get_no_motion_config(&sens_cfg[loop].cfg.no_motion, dev); + break; + + /* Set the step counter parameters */ + case BMI2_STEP_COUNTER_PARAMS: + rslt = get_step_count_params_config(sens_cfg[loop].cfg.step_counter_params, dev); + break; + + /* Get step counter/detector/activity configuration */ + case BMI2_STEP_DETECTOR: + case BMI2_STEP_COUNTER: + case BMI2_STEP_ACTIVITY: + rslt = get_step_config(&sens_cfg[loop].cfg.step_counter, dev); + break; + + /* Get gyroscope user gain configuration */ + case BMI2_GYRO_GAIN_UPDATE: + rslt = get_gyro_gain_update_config(&sens_cfg[loop].cfg.gyro_gain_update, dev); + break; + + /* Get tilt configuration */ + case BMI2_TILT: + rslt = get_tilt_config(&sens_cfg[loop].cfg.tilt, dev); + break; + + /* Get up hold to wake configuration */ + case BMI2_UP_HOLD_TO_WAKE: + rslt = get_up_hold_to_wake_config(&sens_cfg[loop].cfg.up_hold_to_wake, dev); + break; + + /* Get glance detector configuration */ + case BMI2_GLANCE_DETECTOR: + rslt = get_glance_detect_config(&sens_cfg[loop].cfg.glance_det, dev); + break; + + /* Get wake-up configuration */ + case BMI2_WAKE_UP: + rslt = get_wake_up_config(&sens_cfg[loop].cfg.tap, dev); + break; + + /* Get orientation configuration */ + case BMI2_ORIENTATION: + rslt = get_orient_config(&sens_cfg[loop].cfg.orientation, dev); + break; + + /* Get high-g configuration */ + case BMI2_HIGH_G: + rslt = get_high_g_config(&sens_cfg[loop].cfg.high_g, dev); + break; + + /* Get low-g configuration */ + case BMI2_LOW_G: + rslt = get_low_g_config(&sens_cfg[loop].cfg.low_g, dev); + break; + + /* Get flat configuration */ + case BMI2_FLAT: + rslt = get_flat_config(&sens_cfg[loop].cfg.flat, dev); + break; + + /* Get external sensor sync configuration */ + case BMI2_EXT_SENS_SYNC: + rslt = get_ext_sens_sync_config(&sens_cfg[loop].cfg.ext_sens_sync, dev); + break; + + /* Get the wrist gesture configuration */ + case BMI2_WRIST_GESTURE: + rslt = get_wrist_gest_config(&sens_cfg[loop].cfg.wrist_gest, dev); + break; + + /* Get the wrist wear wake-up configuration */ + case BMI2_WRIST_WEAR_WAKE_UP: + rslt = get_wrist_wear_wake_up_config(&sens_cfg[loop].cfg.wrist_wear_wake_up, dev); + break; + + /* Get the wrist gesture configuration for wearable variant */ + case BMI2_WRIST_GESTURE_WH: + rslt = get_wrist_gest_w_config(&sens_cfg[loop].cfg.wrist_gest_w, dev); + break; + + /* Get the wrist wear wake-up configuration for wearable variant */ + case BMI2_WRIST_WEAR_WAKE_UP_WH: + rslt = get_wrist_wear_wake_up_wh_config(&sens_cfg[loop].cfg.wrist_wear_wake_up_wh, dev); + break; + + /* Get the primary OIS filter configuration */ + case BMI2_PRIMARY_OIS: + rslt = get_primary_ois_config(&sens_cfg[loop].cfg.primary_ois, dev); + break; + + /* Get the free-fall detection configurations */ + case BMI2_FREE_FALL_DET: + rslt = get_free_fall_det_config(&sens_cfg[loop].cfg.free_fall_det, dev); + break; + + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + /* Return error if any of the get configurations fail */ + if (rslt != BMI2_OK) + { + break; + } + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the sensor/feature data for accelerometer, gyroscope, + * auxiliary sensor, step counter, high-g, gyroscope user-gain update, + * orientation, gyroscope cross sensitivity and error status for NVM and VFRM. + */ +int8_t bmi2_get_sensor_data(struct bmi2_sensor_data *sensor_data, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define loop */ + uint8_t loop; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sensor_data != NULL)) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + for (loop = 0; loop < n_sens; loop++) + { + /* Disable Advance power save if enabled for feature + * configurations + */ + if (sensor_data[loop].type >= BMI2_MAIN_SENS_MAX_NUM) + { + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if + * enabled + */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + if (rslt == BMI2_OK) + { + switch (sensor_data[loop].type) + { + case BMI2_ACCEL: + + /* Get accelerometer data */ + rslt = get_accel_sensor_data(&sensor_data[loop].sens_data.acc, BMI2_ACC_X_LSB_ADDR, dev); + break; + case BMI2_GYRO: + + /* Get gyroscope data */ + rslt = get_gyro_sensor_data(&sensor_data[loop].sens_data.gyr, BMI2_GYR_X_LSB_ADDR, dev); + break; + case BMI2_AUX: + + /* Get auxiliary sensor data in data mode */ + rslt = read_aux_data_mode(sensor_data[loop].sens_data.aux_data, dev); + break; + case BMI2_STEP_COUNTER: + + /* Get step counter output */ + rslt = get_step_counter_output(&sensor_data[loop].sens_data.step_counter_output, dev); + break; + case BMI2_STEP_ACTIVITY: + + /* Get step activity output */ + rslt = get_step_activity_output(&sensor_data[loop].sens_data.activity_output, dev); + break; + case BMI2_ORIENTATION: + + /* Get orientation output */ + rslt = get_orient_output(&sensor_data[loop].sens_data.orient_output, dev); + break; + case BMI2_HIGH_G: + + /* Get high-g output */ + rslt = get_high_g_output(&sensor_data[loop].sens_data.high_g_output, dev); + break; + case BMI2_GYRO_GAIN_UPDATE: + + /* Get saturation status of gyroscope user gain update */ + rslt = get_gyro_gain_update_status(&sensor_data[loop].sens_data.gyro_user_gain_status, dev); + break; + case BMI2_NVM_STATUS: + + /* Get NVM error status */ + rslt = get_nvm_error_status(&sensor_data[loop].sens_data.nvm_status, dev); + break; + case BMI2_VFRM_STATUS: + + /* Get VFRM error status */ + rslt = get_vfrm_error_status(&sensor_data[loop].sens_data.vfrm_status, dev); + break; + case BMI2_WRIST_GESTURE: + case BMI2_WRIST_GESTURE_WH: + + /* Get wrist gesture status */ + rslt = get_wrist_gest_status(&sensor_data[loop].sens_data.wrist_gesture_output, dev); + break; + case BMI2_GYRO_CROSS_SENSE: + + /* Get Gyroscope cross sense value of z axis */ + rslt = get_gyro_cross_sense(&sensor_data[loop].sens_data.correction_factor_zx, dev); + break; + case BMI2_ACCEL_SELF_TEST: + + /* Get accelerometer self-test */ + rslt = get_accel_self_test_status(&sensor_data[loop].sens_data.accel_self_test_output, dev); + break; + case BMI2_OIS_OUTPUT: + + /* Get OIS accel and gyro x,y,z data */ + rslt = get_ois_output(&sensor_data[loop].sens_data.ois_output, dev); + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + + /* Return error if any of the get sensor data fails */ + if (rslt != BMI2_OK) + { + break; + } + } + + /* Enable Advance power save if disabled while + * configuring and not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API enables/disables the advance power save mode in the sensor. + */ +int8_t bmi2_set_adv_power_save(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_ADV_POW_EN, enable); + rslt = bmi2_set_regs(BMI2_PWR_CONF_ADDR, ®_data, 1, dev); + dev->delay_us(500); + if (rslt != BMI2_OK) + { + /* Return error if enable/disable APS fails */ + rslt = BMI2_E_SET_APS_FAIL; + } + if (rslt == BMI2_OK) + { + dev->aps_status = BMI2_GET_BIT_POS0(reg_data, BMI2_ADV_POW_EN); + } + } + } + + return rslt; +} + +/*! + * @brief This API gets the status of advance power save mode in the sensor. + */ +int8_t bmi2_get_adv_power_save(uint8_t *aps_status, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aps_status != NULL)) + { + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + *aps_status = BMI2_GET_BIT_POS0(reg_data, BMI2_ADV_POW_EN); + dev->aps_status = *aps_status; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API loads the configuration file into the bmi2 sensor. + */ +int8_t bmi2_write_config_file(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to know the load status */ + uint8_t load_status = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (dev->config_size != 0)) + { + /* Bytes written are multiples of 2 */ + if ((dev->read_write_len % 2) != 0) + { + dev->read_write_len = dev->read_write_len - 1; + } + if (dev->read_write_len < 2) + { + dev->read_write_len = 2; + } + + /* Write the configuration file */ + rslt = write_config_file(dev); + if (rslt == BMI2_OK) + { + /* Check the configuration load status */ + rslt = bmi2_get_internal_status(&load_status, dev); + + /* Return error if loading not successful */ + if ((rslt == BMI2_OK) && (!(load_status & BMI2_CONFIG_LOAD_SUCCESS))) + { + rslt = BMI2_E_CONFIG_LOAD; + } + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + */ +int8_t bmi2_set_int_pin_config(const struct bmi2_int_pin_config *int_cfg, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define data array */ + uint8_t data_array[3] = { 0 }; + + /* Variable to store register data */ + uint8_t reg_data = 0; + + /* Variable to define type of interrupt pin */ + uint8_t int_pin = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_cfg != NULL)) + { + /* Copy the pin type to a local variable */ + int_pin = int_cfg->pin_type; + if ((int_pin > BMI2_INT_NONE) && (int_pin < BMI2_INT_PIN_MAX)) + { + /* Get the previous configuration data */ + rslt = bmi2_get_regs(BMI2_INT1_IO_CTRL_ADDR, data_array, 3, dev); + if (rslt == BMI2_OK) + { + /* Set interrupt pin 1 configuration */ + if ((int_pin == BMI2_INT1) || (int_pin == BMI2_INT_BOTH)) + { + /* Configure active low or high */ + reg_data = BMI2_SET_BITS(data_array[0], BMI2_INT_LEVEL, int_cfg->pin_cfg[0].lvl); + + /* Configure push-pull or open drain */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OPEN_DRAIN, int_cfg->pin_cfg[0].od); + + /* Configure output enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OUTPUT_EN, int_cfg->pin_cfg[0].output_en); + + /* Configure input enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_INPUT_EN, int_cfg->pin_cfg[0].input_en); + + /* Copy the data to be written in the respective array */ + data_array[0] = reg_data; + } + + /* Set interrupt pin 2 configuration */ + if ((int_pin == BMI2_INT2) || (int_pin == BMI2_INT_BOTH)) + { + /* Configure active low or high */ + reg_data = BMI2_SET_BITS(data_array[1], BMI2_INT_LEVEL, int_cfg->pin_cfg[1].lvl); + + /* Configure push-pull or open drain */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OPEN_DRAIN, int_cfg->pin_cfg[1].od); + + /* Configure output enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OUTPUT_EN, int_cfg->pin_cfg[1].output_en); + + /* Configure input enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_INPUT_EN, int_cfg->pin_cfg[1].input_en); + + /* Copy the data to be written in the respective array */ + data_array[1] = reg_data; + } + + /* Configure the interrupt mode */ + data_array[2] = BMI2_SET_BIT_POS0(data_array[2], BMI2_INT_LATCH, int_cfg->int_latch); + + /* Set the configurations simultaneously as + * INT1_IO_CTRL, INT2_IO_CTRL, and INT_LATCH lie + * in consecutive addresses + */ + rslt = bmi2_set_regs(BMI2_INT1_IO_CTRL_ADDR, data_array, 3, dev); + } + } + else + { + rslt = BMI2_E_INVALID_INT_PIN; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + */ +int8_t bmi2_get_int_pin_config(struct bmi2_int_pin_config *int_cfg, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define data array */ + uint8_t data_array[3] = { 0 }; + + /* Variable to define type of interrupt pin */ + uint8_t int_pin = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_cfg != NULL)) + { + /* Copy the pin type to a local variable */ + int_pin = int_cfg->pin_type; + + /* Get the previous configuration data */ + rslt = bmi2_get_regs(BMI2_INT1_IO_CTRL_ADDR, data_array, 3, dev); + if (rslt == BMI2_OK) + { + /* Get interrupt pin 1 configuration */ + if ((int_pin == BMI2_INT1) || (int_pin == BMI2_INT_BOTH)) + { + /* Get active low or high */ + int_cfg->pin_cfg[0].lvl = BMI2_GET_BITS(data_array[0], BMI2_INT_LEVEL); + + /* Get push-pull or open drain */ + int_cfg->pin_cfg[0].od = BMI2_GET_BITS(data_array[0], BMI2_INT_OPEN_DRAIN); + + /* Get output enable */ + int_cfg->pin_cfg[0].output_en = BMI2_GET_BITS(data_array[0], BMI2_INT_OUTPUT_EN); + + /* Get input enable */ + int_cfg->pin_cfg[0].input_en = BMI2_GET_BITS(data_array[0], BMI2_INT_INPUT_EN); + } + + /* Get interrupt pin 2 configuration */ + if ((int_pin == BMI2_INT2) || (int_pin == BMI2_INT_BOTH)) + { + /* Get active low or high */ + int_cfg->pin_cfg[1].lvl = BMI2_GET_BITS(data_array[1], BMI2_INT_LEVEL); + + /* Get push-pull or open drain */ + int_cfg->pin_cfg[1].od = BMI2_GET_BITS(data_array[1], BMI2_INT_OPEN_DRAIN); + + /* Get output enable */ + int_cfg->pin_cfg[1].output_en = BMI2_GET_BITS(data_array[1], BMI2_INT_OUTPUT_EN); + + /* Get input enable */ + int_cfg->pin_cfg[1].input_en = BMI2_GET_BITS(data_array[1], BMI2_INT_INPUT_EN); + } + + /* Get interrupt mode */ + int_cfg->int_latch = BMI2_GET_BIT_POS0(data_array[2], BMI2_INT_LATCH); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the interrupt status of both feature and data + * interrupts + */ +int8_t bmi2_get_int_status(uint16_t *int_status, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store data */ + uint8_t data_array[2] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_status != NULL)) + { + /* Get the interrupt status */ + rslt = bmi2_get_regs(BMI2_INT_STATUS_0_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) + { + *int_status = (uint16_t) data_array[0] | ((uint16_t) data_array[1] << 8); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the FIFO configuration in the sensor. + */ +int8_t bmi2_set_fifo_config(uint16_t config, uint8_t enable, struct bmi2_dev *dev) +{ + int8_t rslt; + uint8_t data[2] = { 0 }; + uint8_t max_burst_len = 0; + + /* Variable to store data of FIFO configuration register 0 */ + uint8_t fifo_config_0 = (uint8_t)(config & BMI2_FIFO_CONFIG_0_MASK); + + /* Variable to store data of FIFO configuration register 1 */ + uint8_t fifo_config_1 = (uint8_t)((config & BMI2_FIFO_CONFIG_1_MASK) >> 8); + + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + rslt = bmi2_get_regs(BMI2_FIFO_CONFIG_0_ADDR, data, BMI2_FIFO_CONFIG_LENGTH, dev); + if (rslt == BMI2_OK) + { + /* Get data to set FIFO configuration register 0 */ + if (fifo_config_0 > 0) + { + if (enable == BMI2_ENABLE) + { + data[0] = data[0] | fifo_config_0; + } + else + { + data[0] = data[0] & (~fifo_config_0); + } + } + + /* Get data to set FIFO configuration register 1 */ + if (enable == BMI2_ENABLE) + { + data[1] = data[1] | fifo_config_1; + if (dev->variant_feature & BMI2_CRT_RTOSK_ENABLE) + { + + /* Burst length is needed for CRT + * FIFO enable will reset the default values + * So configure the max burst length again. + */ + rslt = get_maxburst_len(&max_burst_len, dev); + if (rslt == BMI2_OK && max_burst_len == 0) + { + rslt = set_maxburst_len(CRT_MIN_BURST_WORD_LENGTH, dev); + } + } + } + else + { + data[1] = data[1] & (~fifo_config_1); + } + + /* Set the FIFO configurations */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_regs(BMI2_FIFO_CONFIG_0_ADDR, data, 2, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API reads the FIFO configuration from the sensor. + */ +int8_t bmi2_get_fifo_config(uint16_t *fifo_config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store data */ + uint8_t data[2] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_config != NULL)) + { + /* Get the FIFO configuration value */ + rslt = bmi2_get_regs(BMI2_FIFO_CONFIG_0_ADDR, data, BMI2_FIFO_CONFIG_LENGTH, dev); + if (rslt == BMI2_OK) + { + (*fifo_config) = (uint16_t)((uint16_t) data[0] & BMI2_FIFO_CONFIG_0_MASK); + (*fifo_config) |= (uint16_t)(((uint16_t) data[1] << 8) & BMI2_FIFO_CONFIG_1_MASK); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the FIFO data. + */ +int8_t bmi2_read_fifo_data(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store FIFO configuration data */ + uint8_t config_data[2] = { 0 }; + + /* Variable to define FIFO address */ + uint8_t addr = BMI2_FIFO_DATA_ADDR; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo != NULL)) + { + /* Clear the FIFO data structure */ + reset_fifo_frame_structure(fifo, dev); + + /* Read FIFO data */ + rslt = bmi2_get_regs(addr, fifo->data, fifo->length, dev); + if (rslt == BMI2_OK) + { + + /* Get the set FIFO frame configurations */ + rslt = bmi2_get_regs(BMI2_FIFO_CONFIG_0_ADDR, config_data, 2, dev); + if (rslt == BMI2_OK) + { + /* Get FIFO header status */ + fifo->header_enable = (uint8_t)((config_data[1]) & (BMI2_FIFO_HEADER_EN >> 8)); + + /* Get sensor enable status, of which the data is to be read */ + fifo->data_enable = + (uint16_t)(((config_data[0]) | ((uint16_t) config_data[1] << 8)) & BMI2_FIFO_ALL_EN); + } + } + else + { + rslt = BMI2_E_COM_FAIL; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the accelerometer frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in the "accel_data" + * structure instance. + */ +int8_t bmi2_extract_accel(struct bmi2_sens_axes_data *accel_data, + uint16_t *accel_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to index the bytes */ + uint16_t data_index = 0; + + /* Variable to index accelerometer frames */ + uint16_t accel_index = 0; + + /* Variable to store the number of bytes to be read */ + uint16_t data_read_length = 0; + + /* Variable to define the data enable byte */ + uint8_t data_enable = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (accel_data != NULL) && (accel_length != NULL) && (fifo != NULL)) + { + /* Parsing the FIFO data in header-less mode */ + if (fifo->header_enable == 0) + { + + /* Get the number of accelerometer bytes to be read */ + rslt = parse_fifo_accel_len(&data_index, &data_read_length, accel_length, fifo); + + /* Convert word to byte since all sensor enables are in a byte */ + data_enable = (uint8_t)(fifo->data_enable >> 8); + for (; (data_index < data_read_length) && (rslt != BMI2_W_FIFO_EMPTY);) + { + /* Unpack frame to get the accelerometer data */ + rslt = unpack_accel_frame(accel_data, &data_index, &accel_index, data_enable, fifo, dev); + if (rslt != BMI2_W_FIFO_EMPTY) + { + /* Check for the availability of next two bytes of FIFO data */ + rslt = check_empty_fifo(&data_index, fifo); + } + } + + /* Update number of accelerometer frames to be read */ + (*accel_length) = accel_index; + + /* Update the accelerometer byte index */ + fifo->acc_byte_start_idx = data_index; + } + else + { + /* Parsing the FIFO data in header mode */ + rslt = extract_accel_header_mode(accel_data, accel_length, fifo, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the gyroscope frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in the "gyro_data" + * structure instance. + */ +int8_t bmi2_extract_gyro(struct bmi2_sens_axes_data *gyro_data, + uint16_t *gyro_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to index the bytes */ + uint16_t data_index = 0; + + /* Variable to index gyroscope frames */ + uint16_t gyro_index = 0; + + /* Variable to store the number of bytes to be read */ + uint16_t data_read_length = 0; + + /* Variable to define the data enable byte */ + uint8_t data_enable = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyro_data != NULL) && (gyro_length != NULL) && (fifo != NULL)) + { + /* Parsing the FIFO data in header-less mode */ + if (fifo->header_enable == 0) + { + /* Get the number of gyro bytes to be read */ + rslt = parse_fifo_gyro_len(&data_index, &data_read_length, gyro_length, fifo); + + /* Convert word to byte since all sensor enables are in a byte */ + data_enable = (uint8_t)(fifo->data_enable >> 8); + for (; (data_index < data_read_length) && (rslt != BMI2_W_FIFO_EMPTY);) + { + /* Unpack frame to get gyroscope data */ + rslt = unpack_gyro_frame(gyro_data, &data_index, &gyro_index, data_enable, fifo, dev); + if (rslt != BMI2_W_FIFO_EMPTY) + { + /* Check for the availability of next two bytes of FIFO data */ + rslt = check_empty_fifo(&data_index, fifo); + } + } + + /* Update number of gyroscope frames to be read */ + (*gyro_length) = gyro_index; + + /* Update the gyroscope byte index */ + fifo->acc_byte_start_idx = data_index; + } + else + { + /* Parsing the FIFO data in header mode */ + rslt = extract_gyro_header_mode(gyro_data, gyro_length, fifo, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the auxiliary frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in "aux_data" buffer. + */ +int8_t bmi2_extract_aux(struct bmi2_aux_fifo_data *aux, + uint16_t *aux_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to index the bytes */ + uint16_t data_index = 0; + + /* Variable to index auxiliary frames */ + uint16_t aux_index = 0; + + /* Variable to store the number of bytes to be read */ + uint16_t data_read_length = 0; + + /* Variable to define the data enable byte */ + uint8_t data_enable = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux != NULL) && (aux_length != NULL) && (fifo != NULL)) + { + /* Parsing the FIFO data in header-less mode */ + if (fifo->header_enable == 0) + { + rslt = parse_fifo_aux_len(&data_index, &data_read_length, aux_length, fifo); + + /* Convert word to byte since all sensor enables are in + * a byte + */ + data_enable = (uint8_t)(fifo->data_enable >> 8); + for (; (data_index < data_read_length) && (rslt != BMI2_W_FIFO_EMPTY);) + { + /* Unpack frame to get auxiliary data */ + rslt = unpack_aux_frame(aux, &data_index, &aux_index, data_enable, fifo, dev); + if (rslt != BMI2_W_FIFO_EMPTY) + { + /* Check for the availability of next + * two bytes of FIFO data + */ + rslt = check_empty_fifo(&data_index, fifo); + } + } + + /* Update number of auxiliary frames to be read */ + *aux_length = aux_index; + + /* Update the auxiliary byte index */ + fifo->aux_byte_start_idx = data_index; + } + else + { + /* Parsing the FIFO data in header mode */ + rslt = extract_aux_header_mode(aux, aux_length, fifo, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes the available sensor specific commands to the sensor. + */ +int8_t bmi2_set_command_register(uint8_t command, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Set the command in the command register */ + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &command, 1, dev); + } + + return rslt; +} + +/* + * @brief This API sets the FIFO self wake up functionality in the sensor. + */ +int8_t bmi2_set_fifo_self_wake_up(uint8_t fifo_self_wake_up, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Set FIFO self wake-up */ + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BITS(data, BMI2_FIFO_SELF_WAKE_UP, fifo_self_wake_up); + rslt = bmi2_set_regs(BMI2_PWR_CONF_ADDR, &data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API gets the status of FIFO self wake up functionality from + * the sensor. + */ +int8_t bmi2_get_fifo_self_wake_up(uint8_t *fifo_self_wake_up, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_self_wake_up != NULL)) + { + /* Get the status of FIFO self wake-up */ + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + (*fifo_self_wake_up) = BMI2_GET_BITS(data, BMI2_FIFO_SELF_WAKE_UP); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the FIFO water-mark level in the sensor. + */ +int8_t bmi2_set_fifo_wm(uint16_t fifo_wm, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store data */ + uint8_t data[2] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Get LSB value of FIFO water-mark */ + data[0] = BMI2_GET_LSB(fifo_wm); + + /* Get MSB value of FIFO water-mark */ + data[1] = BMI2_GET_MSB(fifo_wm); + + /* Set the FIFO water-mark level */ + rslt = bmi2_set_regs(BMI2_FIFO_WTM_0_ADDR, data, 2, dev); + } + + return rslt; +} + +/*! + * @brief This API reads the FIFO water mark level set in the sensor. + */ +int8_t bmi2_get_fifo_wm(uint16_t *fifo_wm, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to to store data */ + uint8_t data[2] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_wm != NULL)) + { + /* Read the FIFO water mark level */ + rslt = bmi2_get_regs(BMI2_FIFO_WTM_0_ADDR, data, BMI2_FIFO_WM_LENGTH, dev); + if (rslt == BMI2_OK) + { + (*fifo_wm) = (uint16_t)((uint16_t) data[1] << 8) | (data[0]); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets either filtered or un-filtered FIFO accelerometer or + * gyroscope data. + */ +int8_t bmi2_set_fifo_filter_data(uint8_t sens_sel, uint8_t fifo_filter_data, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + switch (sens_sel) + { + case BMI2_ACCEL: + + /* Validate filter mode */ + if (fifo_filter_data <= BMI2_MAX_VALUE_FIFO_FILTER) + { + /* Set the accelerometer FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BITS(data, BMI2_ACC_FIFO_FILT_DATA, fifo_filter_data); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + } + else + { + rslt = BMI2_E_OUT_OF_RANGE; + } + break; + case BMI2_GYRO: + + /* Validate filter mode */ + if (fifo_filter_data <= BMI2_MAX_VALUE_FIFO_FILTER) + { + /* Set the gyroscope FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BITS(data, BMI2_GYR_FIFO_FILT_DATA, fifo_filter_data); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + } + else + { + rslt = BMI2_E_OUT_OF_RANGE; + } + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + return rslt; +} + +/*! + * @brief This API gets the FIFO accelerometer or gyroscope filter data. + */ +int8_t bmi2_get_fifo_filter_data(uint8_t sens_sel, uint8_t *fifo_filter_data, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store FIFO filter mode */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_filter_data != NULL)) + { + switch (sens_sel) + { + case BMI2_ACCEL: + + /* Read the accelerometer FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + (*fifo_filter_data) = BMI2_GET_BITS(data, BMI2_ACC_FIFO_FILT_DATA); + } + break; + case BMI2_GYRO: + + /* Read the gyroscope FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + (*fifo_filter_data) = BMI2_GET_BITS(data, BMI2_GYR_FIFO_FILT_DATA); + } + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the down-sampling rates for accelerometer or gyroscope + * FIFO data. + */ +int8_t bmi2_set_fifo_down_sample(uint8_t sens_sel, uint8_t fifo_down_samp, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store sampling rate */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + switch (sens_sel) + { + case BMI2_ACCEL: + + /* Set the accelerometer FIFO down sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BITS(data, BMI2_ACC_FIFO_DOWNS, fifo_down_samp); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + break; + case BMI2_GYRO: + + /* Set the gyroscope FIFO down sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BIT_POS0(data, BMI2_GYR_FIFO_DOWNS, fifo_down_samp); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + return rslt; +} + +/*! + * @brief This API reads the down sampling rates which is configured for + * accelerometer or gyroscope FIFO data. + */ +int8_t bmi2_get_fifo_down_sample(uint8_t sens_sel, uint8_t *fifo_down_samp, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store sampling rate */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_down_samp != NULL)) + { + switch (sens_sel) + { + case BMI2_ACCEL: + + /* Read the accelerometer FIFO down data sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + (*fifo_down_samp) = BMI2_GET_BITS(data, BMI2_ACC_FIFO_DOWNS); + } + break; + case BMI2_GYRO: + + /* Read the gyroscope FIFO down data sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + (*fifo_down_samp) = BMI2_GET_BIT_POS0(data, BMI2_GYR_FIFO_DOWNS); + } + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the length of FIFO data available in the sensor in + * bytes. + */ +int8_t bmi2_get_fifo_length(uint16_t *fifo_length, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define byte index */ + uint8_t index = 0; + + /* Array to store FIFO data length */ + uint8_t data[BMI2_FIFO_DATA_LENGTH] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_length != NULL)) + { + /* Read FIFO length */ + rslt = bmi2_get_regs(BMI2_FIFO_LENGTH_0_ADDR, data, BMI2_FIFO_DATA_LENGTH, dev); + if (rslt == BMI2_OK) + { + /* Get the MSB byte index */ + index = BMI2_FIFO_LENGTH_MSB_BYTE; + + /* Get the MSB byte of FIFO length */ + data[index] = BMI2_GET_BIT_POS0(data[index], BMI2_FIFO_BYTE_COUNTER_MSB); + + /* Get total FIFO length */ + (*fifo_length) = ((data[index] << 8) | data[index - 1]); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the user-defined bytes of data from the given register + * address of auxiliary sensor in manual mode. + * + * @note Change of BMI2_AUX_RD_ADDR is only allowed if AUX is not busy. + */ +int8_t bmi2_read_aux_man_mode(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store burst length */ + uint8_t burst_len = 0; + + /* Variable to define APS status */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux_data != NULL)) + { + /* Validate if manual mode */ + if (dev->aux_man_en) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable APS if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Map the register value set to that of burst + * length + */ + rslt = map_read_len(&burst_len, dev); + if (rslt == BMI2_OK) + { + /* Read auxiliary data */ + rslt = read_aux_data(reg_addr, aux_data, len, burst_len, dev); + } + } + + /* Enable Advance power save if disabled for reading + * data and not when already disabled + */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + else + { + rslt = BMI2_E_AUX_INVALID_CFG; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + */ +int8_t bmi2_write_aux_man_mode(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define loop */ + uint8_t loop = 0; + + /* Variable to define APS status */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux_data != NULL)) + { + /* Validate if manual mode */ + if (dev->aux_man_en) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable APS if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + /* Byte write data in the corresponding address */ + if (rslt == BMI2_OK) + { + for (; ((loop < len) && (rslt == BMI2_OK)); loop++) + { + rslt = write_aux_data((reg_addr + loop), aux_data[loop], dev); + dev->delay_us(1000); + } + } + + /* Enable Advance power save if disabled for writing + * data and not when already disabled + */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + else + { + rslt = BMI2_E_AUX_INVALID_CFG; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written, from an interleaved input, + * in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + */ +int8_t bmi2_write_aux_interleaved(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define loop */ + uint8_t loop = 1; + + /* Variable to define APS status */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux_data != NULL)) + { + /* Validate if manual mode */ + if (dev->aux_man_en) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable APS if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Write the start register address extracted + * from the interleaved data + */ + rslt = write_aux_data(reg_addr, aux_data[0], dev); + + /* Extract the remaining address and data from + * the interleaved data and write it in the + * corresponding addresses byte by byte + */ + for (; ((loop < len) && (rslt == BMI2_OK)); loop += 2) + { + rslt = write_aux_data(aux_data[loop], aux_data[loop + 1], dev); + dev->delay_us(1000); + } + + /* Enable Advance power save if disabled for + * writing data and not when already disabled + */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + } + else + { + rslt = BMI2_E_AUX_INVALID_CFG; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the data ready status of accelerometer, gyroscope, + * auxiliary, command decoder and busy status of auxiliary. + */ +int8_t bmi2_get_status(uint8_t *status, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (status != NULL)) + { + rslt = bmi2_get_regs(BMI2_STATUS_ADDR, status, 1, dev); + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API enables/disables OIS interface. + */ +int8_t bmi2_set_ois_interface(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + rslt = bmi2_get_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Enable/Disable OIS interface */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_OIS_IF_EN, enable); + if (enable) + { + /* Disable auxiliary interface if OIS is enabled */ + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_AUX_IF_EN); + } + + /* Set the OIS interface configurations */ + rslt = bmi2_set_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API can be used to write sync commands like ODR, sync period, + * frequency and phase, resolution ratio, sync time and delay time. + */ +int8_t bmi2_write_sync_commands(const uint8_t *command, uint8_t n_comm, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (command != NULL)) + { + rslt = bmi2_set_regs(BMI2_SYNC_COMMAND_ADDR, command, n_comm, dev); + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API performs self-test to check the proper functionality of the + * accelerometer sensor. + */ +int8_t bmi2_perform_accel_self_test(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store self-test result */ + int8_t st_rslt = 0; + + /* Structure to define positive accelerometer axes */ + struct bmi2_sens_axes_data positive = { 0, 0, 0, 0 }; + + /* Structure to define negative accelerometer axes */ + struct bmi2_sens_axes_data negative = { 0, 0, 0, 0 }; + + /* Structure for difference of accelerometer values in g */ + struct selftest_delta_limit accel_data_diff = { 0, 0, 0 }; + + /* Structure for difference of accelerometer values in mg */ + struct selftest_delta_limit accel_data_diff_mg = { 0, 0, 0 }; + + /* Initialize the polarity of self-test as positive */ + int8_t sign = BMI2_ENABLE; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Sets the configuration required before enabling self-test */ + rslt = pre_self_test_config(dev); + + /* Wait for greater than 2 milliseconds */ + dev->delay_us(3000); + if (rslt == BMI2_OK) + { + do + { + /* Select positive first, then negative polarity + * after enabling self-test + */ + rslt = self_test_config((uint8_t) sign, dev); + if (rslt == BMI2_OK) + { + /* Wait for greater than 50 milli-sec */ + dev->delay_us(51000); + + /* If polarity is positive */ + if (sign == BMI2_ENABLE) + { + /* Read and store positive acceleration value */ + rslt = read_accel_xyz(&positive, dev); + } + /* If polarity is negative */ + else if (sign == BMI2_DISABLE) + { + /* Read and store negative acceleration value */ + rslt = read_accel_xyz(&negative, dev); + } + } + else + { + /* Break if error */ + break; + } + + /* Break if error */ + if (rslt != BMI2_OK) + { + break; + } + + /* Turn the polarity of self-test negative */ + sign--; + } while (sign >= 0); + if (rslt == BMI2_OK) + { + /* Subtract -ve acceleration values from that of +ve values */ + accel_data_diff.x = (positive.x) - (negative.x); + accel_data_diff.y = (positive.y) - (negative.y); + accel_data_diff.z = (positive.z) - (negative.z); + + /* Convert differences of acceleration values + * from 'g' to 'mg' + */ + convert_lsb_g(&accel_data_diff, &accel_data_diff_mg, dev); + + /* Validate self-test for acceleration values + * in mg and get the self-test result + */ + st_rslt = validate_self_test(&accel_data_diff_mg); + + /* Trigger a soft reset after performing self-test */ + rslt = bmi2_soft_reset(dev); + + /* Return the self-test result */ + if (rslt == BMI2_OK) + { + rslt = st_rslt; + } + } + } + } + + return rslt; +} + +/*! + * @brief This API maps/unmaps feature interrupts to that of interrupt pins. + */ +int8_t bmi2_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define loop */ + uint8_t loop; + + /* Variable to define the value of feature interrupts */ + uint8_t feat_int = 0; + + /* Variable to define the mask bits of feature interrupts */ + uint8_t feat_int_mask = 0; + + /* Array to store the interrupt mask bits */ + uint8_t data_array[2] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_int != NULL)) + { + /* Read interrupt map1 and map2 and register */ + rslt = bmi2_get_regs(BMI2_INT1_MAP_FEAT_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) + { + for (loop = 0; loop < n_sens; loop++) + { + switch (sens_int[loop].type) + { + case BMI2_SIG_MOTION: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.sig_mot_out_conf; + break; + case BMI2_ANY_MOTION: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.any_mot_out_conf; + break; + case BMI2_NO_MOTION: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.no_mot_out_conf; + break; + case BMI2_STEP_DETECTOR: + case BMI2_STEP_COUNTER: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.step_det_out_conf; + break; + case BMI2_STEP_ACTIVITY: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.step_act_out_conf; + break; + case BMI2_TILT: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.tilt_out_conf; + break; + case BMI2_UP_HOLD_TO_WAKE: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.up_hold_to_wake_out_conf; + break; + case BMI2_GLANCE_DETECTOR: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.glance_out_conf; + break; + case BMI2_WAKE_UP: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.wake_up_out_conf; + break; + case BMI2_ORIENTATION: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.orient_out_conf; + break; + case BMI2_HIGH_G: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.high_g_out_conf; + break; + case BMI2_LOW_G: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.low_g_out_conf; + break; + case BMI2_FLAT: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.flat_out_conf; + break; + case BMI2_EXT_SENS_SYNC: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.ext_sync_out_conf; + break; + case BMI2_WRIST_GESTURE: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.wrist_gest_out_conf; + break; + case BMI2_WRIST_WEAR_WAKE_UP: + + /* Get the value of the feature interrupt to be mapped */ + feat_int = dev->int_map.wrist_wear_wake_up_out_conf; + break; + case BMI2_WRIST_GESTURE_WH: + + /* Get the value of the feature interrupt to be mapped for wearable variant */ + feat_int = dev->int_map.wrist_gest_out_conf; + break; + case BMI2_WRIST_WEAR_WAKE_UP_WH: + + /* Get the value of the feature interrupt to be mapped for wearable variant */ + feat_int = dev->int_map.wrist_wear_wake_up_out_conf; + break; + case BMI2_FREE_FALL_DET: + + /* Get the value of the feature interrupt to be mapped for free-fall detection */ + feat_int = dev->int_map.freefall_out_conf; + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + + /* Map the features to the required interrupt */ + if (rslt != BMI2_E_INVALID_SENSOR) + { + if ((feat_int > BMI2_FEAT_BIT_DISABLE) && (feat_int < BMI2_FEAT_BIT_MAX)) + { + /* Get the interrupt mask */ + feat_int_mask = (uint8_t)((uint32_t) 1 << (feat_int - 1)); + + /* Map the interrupts */ + rslt = map_feat_int(data_array, sens_int[loop].hw_int_pin, feat_int_mask); + } + else + { + rslt = BMI2_E_INVALID_FEAT_BIT; + } + } + + /* Return error if interrupt mapping fails */ + if (rslt != BMI2_OK) + { + break; + } + } + + /* Map the interrupts to INT1 and INT2 map register */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_regs(BMI2_INT1_MAP_FEAT_ADDR, data_array, 2, dev); + } + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API maps/un-maps data interrupts to that of interrupt pins. + */ +int8_t bmi2_map_data_int(uint8_t data_int, enum bmi2_hw_int_pin int_pin, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to mask interrupt pin 1 - lower nibble */ + uint8_t int1_mask = data_int; + + /* Variable to mask interrupt pin 2 - higher nibble */ + uint8_t int2_mask = (uint8_t)(data_int << 4); + + /* Variable to store register data */ + uint8_t reg_data = 0; + + /* Read interrupt map1 and map2 and register */ + rslt = bmi2_get_regs(BMI2_INT_MAP_DATA_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + if (int_pin < BMI2_INT_PIN_MAX) + { + switch (int_pin) + { + case BMI2_INT_NONE: + + /* Un-Map the corresponding data + * interrupt to both interrupt pin 1 and 2 + */ + reg_data &= ~(int1_mask | int2_mask); + break; + case BMI2_INT1: + + /* Map the corresponding data interrupt to + * interrupt pin 1 + */ + reg_data |= int1_mask; + break; + case BMI2_INT2: + + /* Map the corresponding data interrupt to + * interrupt pin 2 + */ + reg_data |= int2_mask; + break; + case BMI2_INT_BOTH: + + /* Map the corresponding data + * interrupt to both interrupt pin 1 and 2 + */ + reg_data |= (int1_mask | int2_mask); + break; + default: + break; + } + + /* Set the interrupts in the map register */ + rslt = bmi2_set_regs(BMI2_INT_MAP_DATA_ADDR, ®_data, 1, dev); + } + else + { + /* Return error if invalid pin selection */ + rslt = BMI2_E_INVALID_INT_PIN; + } + } + + return rslt; +} + +/*! + * @brief This API gets the re-mapped x, y and z axes from the sensor and + * updates the values in the device structure. + */ +int8_t bmi2_get_remap_axes(struct bmi2_remap *remapped_axis, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Initialize the local structure for axis re-mapping */ + struct axes_remap remap = { 0, 0, 0, 0, 0, 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (remapped_axis != NULL)) + { + /* Get the re-mapped axes from the sensor */ + rslt = get_remap_axes(&remap, dev); + if (rslt == BMI2_OK) + { + /* Store the re-mapped x-axis value in device structure + * and its user-value in the interface structure + */ + switch (remap.x_axis) + { + case MAP_X_AXIS: + + /* If mapped to x-axis */ + dev->remap.x_axis = MAP_X_AXIS; + remapped_axis->x = BMI2_X; + break; + case MAP_Y_AXIS: + + /* If mapped to y-axis */ + dev->remap.x_axis = MAP_Y_AXIS; + remapped_axis->x = BMI2_Y; + break; + case MAP_Z_AXIS: + + /* If mapped to z-axis */ + dev->remap.x_axis = MAP_Z_AXIS; + remapped_axis->x = BMI2_Z; + break; + default: + break; + } + + /* Store the re-mapped x-axis sign in device structure + * and its user-value in the interface structure + */ + if (remap.x_axis_sign) + { + /* If x-axis is mapped to -ve sign */ + dev->remap.x_axis_sign = NEG_SIGN; + remapped_axis->x |= BMI2_AXIS_SIGN; + } + else + { + dev->remap.x_axis_sign = POS_SIGN; + } + + /* Store the re-mapped y-axis value in device structure + * and its user-value in the interface structure + */ + switch (remap.y_axis) + { + case MAP_X_AXIS: + + /* If mapped to x-axis */ + dev->remap.y_axis = MAP_X_AXIS; + remapped_axis->y = BMI2_X; + break; + case MAP_Y_AXIS: + + /* If mapped to y-axis */ + dev->remap.y_axis = MAP_Y_AXIS; + remapped_axis->y = BMI2_Y; + break; + case MAP_Z_AXIS: + + /* If mapped to z-axis */ + dev->remap.y_axis = MAP_Z_AXIS; + remapped_axis->y = BMI2_Z; + break; + default: + break; + } + + /* Store the re-mapped y-axis sign in device structure + * and its user-value in the interface structure + */ + if (remap.y_axis_sign) + { + /* If y-axis is mapped to -ve sign */ + dev->remap.y_axis_sign = NEG_SIGN; + remapped_axis->y |= BMI2_AXIS_SIGN; + } + else + { + dev->remap.y_axis_sign = POS_SIGN; + } + + /* Store the re-mapped z-axis value in device structure + * and its user-value in the interface structure + */ + switch (remap.z_axis) + { + case MAP_X_AXIS: + + /* If mapped to x-axis */ + dev->remap.z_axis = MAP_X_AXIS; + remapped_axis->z = BMI2_X; + break; + case MAP_Y_AXIS: + + /* If mapped to y-axis */ + dev->remap.z_axis = MAP_Y_AXIS; + remapped_axis->z = BMI2_Y; + break; + case MAP_Z_AXIS: + + /* If mapped to z-axis */ + dev->remap.z_axis = MAP_Z_AXIS; + remapped_axis->z = BMI2_Z; + break; + default: + break; + } + + /* Store the re-mapped z-axis sign in device structure + * and its user-value in the interface structure + */ + if (remap.z_axis_sign) + { + /* If z-axis is mapped to -ve sign */ + dev->remap.z_axis_sign = NEG_SIGN; + remapped_axis->z |= BMI2_AXIS_SIGN; + } + else + { + dev->remap.z_axis_sign = POS_SIGN; + } + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the re-mapped x, y and z axes to the sensor and + * updates the them in the device structure. + */ +int8_t bmi2_set_remap_axes(const struct bmi2_remap *remapped_axis, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store all the re-mapped axes */ + uint8_t remap_axes = 0; + + /* Variable to store the re-mapped x-axes */ + uint8_t remap_x = 0; + + /* Variable to store the re-mapped y-axes */ + uint8_t remap_y = 0; + + /* Variable to store the re-mapped z-axes */ + uint8_t remap_z = 0; + + /* Initialize the local structure for axis re-mapping */ + struct axes_remap remap = { 0, 0, 0, 0, 0, 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (remapped_axis != NULL)) + { + /* Check whether all the axes are re-mapped */ + remap_axes = remapped_axis->x | remapped_axis->y | remapped_axis->z; + + /* If all the axes are re-mapped */ + if ((remap_axes & BMI2_AXIS_MASK) == BMI2_AXIS_MASK) + { + /* Get the re-mapped value of x, y and z axis */ + remap_x = remapped_axis->x & BMI2_AXIS_MASK; + remap_y = remapped_axis->y & BMI2_AXIS_MASK; + remap_z = remapped_axis->z & BMI2_AXIS_MASK; + + /* Store the value of re-mapped x-axis in both + * device structure and the local structure + */ + switch (remap_x) + { + case BMI2_X: + + /* If mapped to x-axis */ + dev->remap.x_axis = MAP_X_AXIS; + remap.x_axis = MAP_X_AXIS; + break; + case BMI2_Y: + + /* If mapped to y-axis */ + dev->remap.x_axis = MAP_Y_AXIS; + remap.x_axis = MAP_Y_AXIS; + break; + case BMI2_Z: + + /* If mapped to z-axis */ + dev->remap.x_axis = MAP_Z_AXIS; + remap.x_axis = MAP_Z_AXIS; + break; + default: + break; + } + + /* Store the re-mapped x-axis sign in the device + * structure and its value in local structure + */ + if (remapped_axis->x & BMI2_AXIS_SIGN) + { + /* If x-axis is mapped to -ve sign */ + dev->remap.x_axis_sign = NEG_SIGN; + remap.x_axis_sign = MAP_NEGATIVE; + } + else + { + dev->remap.x_axis_sign = POS_SIGN; + remap.x_axis_sign = MAP_POSITIVE; + } + + /* Store the value of re-mapped y-axis in both + * device structure and the local structure + */ + switch (remap_y) + { + case BMI2_X: + + /* If mapped to x-axis */ + dev->remap.y_axis = MAP_X_AXIS; + remap.y_axis = MAP_X_AXIS; + break; + case BMI2_Y: + + /* If mapped to y-axis */ + dev->remap.y_axis = MAP_Y_AXIS; + remap.y_axis = MAP_Y_AXIS; + break; + case BMI2_Z: + + /* If mapped to z-axis */ + dev->remap.y_axis = MAP_Z_AXIS; + remap.y_axis = MAP_Z_AXIS; + break; + default: + break; + } + + /* Store the re-mapped y-axis sign in the device + * structure and its value in local structure + */ + if (remapped_axis->y & BMI2_AXIS_SIGN) + { + /* If y-axis is mapped to -ve sign */ + dev->remap.y_axis_sign = NEG_SIGN; + remap.y_axis_sign = MAP_NEGATIVE; + } + else + { + dev->remap.y_axis_sign = POS_SIGN; + remap.y_axis_sign = MAP_POSITIVE; + } + + /* Store the value of re-mapped z-axis in both + * device structure and the local structure + */ + switch (remap_z) + { + case BMI2_X: + + /* If mapped to x-axis */ + dev->remap.z_axis = MAP_X_AXIS; + remap.z_axis = MAP_X_AXIS; + break; + case BMI2_Y: + + /* If mapped to y-axis */ + dev->remap.z_axis = MAP_Y_AXIS; + remap.z_axis = MAP_Y_AXIS; + break; + case BMI2_Z: + + /* If mapped to z-axis */ + dev->remap.z_axis = MAP_Z_AXIS; + remap.z_axis = MAP_Z_AXIS; + break; + default: + break; + } + + /* Store the re-mapped z-axis sign in the device + * structure and its value in local structure + */ + if (remapped_axis->z & BMI2_AXIS_SIGN) + { + /* If z-axis is mapped to -ve sign */ + dev->remap.z_axis_sign = NEG_SIGN; + remap.z_axis_sign = MAP_NEGATIVE; + } + else + { + dev->remap.z_axis_sign = POS_SIGN; + remap.z_axis_sign = MAP_POSITIVE; + } + + /* Set the re-mapped axes in the sensor */ + rslt = set_remap_axes(&remap, dev); + } + else + { + rslt = BMI2_E_REMAP_ERROR; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API updates the gyroscope user-gain. + */ +int8_t bmi2_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to select sensor */ + uint8_t sens_sel[2] = { BMI2_GYRO, BMI2_GYRO_GAIN_UPDATE }; + + /* Structure to define sensor configurations */ + struct bmi2_sens_config sens_cfg; + + /* Variable to store status of user-gain update module */ + uint8_t status = 0; + + /* Variable to define count */ + uint8_t count = 100; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (user_gain != NULL)) + { + /* Select type of feature */ + sens_cfg.type = BMI2_GYRO_GAIN_UPDATE; + + /* Get the user gain configurations */ + rslt = bmi2_get_sensor_config(&sens_cfg, 1, dev); + if (rslt == BMI2_OK) + { + /* Get the user-defined ratio */ + sens_cfg.cfg.gyro_gain_update = *user_gain; + + /* Set rate ratio for all axes */ + rslt = bmi2_set_sensor_config(&sens_cfg, 1, dev); + } + + /* Disable gyroscope */ + if (rslt == BMI2_OK) + { + rslt = bmi2_sensor_disable(&sens_sel[0], 1, dev); + } + + /* Enable gyroscope user-gain update module */ + if (rslt == BMI2_OK) + { + rslt = bmi2_sensor_enable(&sens_sel[1], 1, dev); + } + + /* Set the command to trigger the computation */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_command_register(BMI2_USR_GAIN_CMD, dev); + } + if (rslt == BMI2_OK) + { + /* Poll until enable bit of user-gain update is 0 */ + while (count--) + { + rslt = get_user_gain_upd_status(&status, dev); + if ((rslt == BMI2_OK) && (status == 0)) + { + /* Enable compensation of gain defined + * in the GAIN register + */ + rslt = enable_gyro_gain(BMI2_ENABLE, dev); + + /* Enable gyroscope */ + if (rslt == BMI2_OK) + { + rslt = bmi2_sensor_enable(&sens_sel[0], 1, dev); + } + break; + } + dev->delay_us(10000); + } + + /* Return error if user-gain update is failed */ + if ((rslt == BMI2_OK) && (status != 0)) + { + rslt = BMI2_E_GYR_USER_GAIN_UPD_FAIL; + } + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the compensated gyroscope user-gain values. + */ +int8_t bmi2_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define register data */ + uint8_t reg_data[3] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyr_usr_gain != NULL)) + { + /* Get the gyroscope compensated gain values */ + rslt = bmi2_get_regs(BMI2_GYR_USR_GAIN_0_ADDR, reg_data, 3, dev); + if (rslt == BMI2_OK) + { + /* Gyroscope user gain correction X-axis */ + gyr_usr_gain->x = (int8_t)BMI2_GET_BIT_POS0(reg_data[0], BMI2_GYR_USR_GAIN_X); + + /* Gyroscope user gain correction Y-axis */ + gyr_usr_gain->y = (int8_t)BMI2_GET_BIT_POS0(reg_data[1], BMI2_GYR_USR_GAIN_Y); + + /* Gyroscope user gain correction z-axis */ + gyr_usr_gain->z = (int8_t)BMI2_GET_BIT_POS0(reg_data[2], BMI2_GYR_USR_GAIN_Z); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API enables/disables gyroscope offset compensation. It adds the + * offsets defined in the offset register with gyroscope data. + */ +int8_t bmi2_set_gyro_offset_comp(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define register data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Get the status of gyroscope offset enable */ + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_OFF_COMP_EN, enable); + + /* Enable/Disable gyroscope offset compensation */ + rslt = bmi2_set_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + */ +int8_t bmi2_read_gyro_offset_comp_axes(struct bmi2_sens_axes_data *gyr_off_comp_axes, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define register data */ + uint8_t reg_data[4] = { 0 }; + + /* Variable to store LSB value of offset compensation for x-axis */ + uint8_t gyr_off_lsb_x; + + /* Variable to store LSB value of offset compensation for y-axis */ + uint8_t gyr_off_lsb_y; + + /* Variable to store LSB value of offset compensation for z-axis */ + uint8_t gyr_off_lsb_z; + + /* Variable to store MSB value of offset compensation for x-axis */ + uint8_t gyr_off_msb_x; + + /* Variable to store MSB value of offset compensation for y-axis */ + uint8_t gyr_off_msb_y; + + /* Variable to store MSB value of offset compensation for z-axis */ + uint8_t gyr_off_msb_z; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyr_off_comp_axes != NULL)) + { + /* Get the gyroscope compensated offset values */ + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_3_ADDR, reg_data, 4, dev); + if (rslt == BMI2_OK) + { + /* Get LSB and MSB values of offset compensation for + * x, y and z axis + */ + gyr_off_lsb_x = reg_data[0]; + gyr_off_lsb_y = reg_data[1]; + gyr_off_lsb_z = reg_data[2]; + gyr_off_msb_x = reg_data[3] & GYR_OFF_COMP_MSB_X_MASK; + gyr_off_msb_y = reg_data[3] & GYR_OFF_COMP_MSB_Y_MASK; + gyr_off_msb_z = reg_data[3] & GYR_OFF_COMP_MSB_Z_MASK; + + /* Gyroscope offset compensation value for x-axis */ + gyr_off_comp_axes->x = (int16_t)(((uint16_t) gyr_off_msb_x << 8) | gyr_off_lsb_x); + + /* Gyroscope offset compensation value for y-axis */ + gyr_off_comp_axes->y = (int16_t)(((uint16_t) gyr_off_msb_y << 6) | gyr_off_lsb_y); + + /* Gyroscope offset compensation value for z-axis */ + gyr_off_comp_axes->z = (int16_t)(((uint16_t) gyr_off_msb_z << 4) | gyr_off_lsb_z); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + */ +int8_t bmi2_write_gyro_offset_comp_axes(const struct bmi2_sens_axes_data *gyr_off_comp_axes, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define register data */ + uint8_t reg_data[4] = { 0 }; + + /* Variable to store MSB value of offset compensation for x-axis */ + uint8_t gyr_off_msb_x; + + /* Variable to store MSB value of offset compensation for y-axis */ + uint8_t gyr_off_msb_y; + + /* Variable to store MSB value of offset compensation for z-axis */ + uint8_t gyr_off_msb_z; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyr_off_comp_axes != NULL)) + { + /* Get the MSB values of gyroscope compensated offset values */ + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data[3], 1, dev); + if (rslt == BMI2_OK) + { + /* Get MSB value of x-axis from user-input */ + gyr_off_msb_x = (uint8_t)((gyr_off_comp_axes->x & GYR_OFF_COMP_MSB_MASK) >> 8); + + /* Get MSB value of y-axis from user-input */ + gyr_off_msb_y = (uint8_t)((gyr_off_comp_axes->y & GYR_OFF_COMP_MSB_MASK) >> 8); + + /* Get MSB value of z-axis from user-input */ + gyr_off_msb_z = (uint8_t)((gyr_off_comp_axes->z & GYR_OFF_COMP_MSB_MASK) >> 8); + + /* Get LSB value of x-axis from user-input */ + reg_data[0] = (uint8_t)(gyr_off_comp_axes->x & GYR_OFF_COMP_LSB_MASK); + + /* Get LSB value of y-axis from user-input */ + reg_data[1] = (uint8_t)(gyr_off_comp_axes->y & GYR_OFF_COMP_LSB_MASK); + + /* Get LSB value of z-axis from user-input */ + reg_data[2] = (uint8_t)(gyr_off_comp_axes->z & GYR_OFF_COMP_LSB_MASK); + + /* Get MSB value of x-axis to be set */ + reg_data[3] = BMI2_SET_BIT_POS0(reg_data[3], GYR_OFF_COMP_MSB_X, gyr_off_msb_x); + + /* Get MSB value of y-axis to be set */ + reg_data[3] = BMI2_SET_BITS(reg_data[3], GYR_OFF_COMP_MSB_Y, gyr_off_msb_y); + + /* Get MSB value of z-axis to be set */ + reg_data[3] = BMI2_SET_BITS(reg_data[3], GYR_OFF_COMP_MSB_Z, gyr_off_msb_z); + + /* Set the offset compensation values of axes */ + rslt = bmi2_set_regs(BMI2_GYR_OFF_COMP_3_ADDR, reg_data, 4, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse the activity output from the + * FIFO in header mode. + */ +int8_t bmi2_get_act_recog_output(struct bmi2_act_recog_output *act_recog, + uint16_t *act_frm_len, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define header frame */ + uint8_t frame_header = 0; + + /* Variable to index the data bytes */ + uint16_t data_index; + + /* Variable to index activity frames */ + uint16_t act_idx = 0; + + /* Variable to indicate activity frames read */ + uint16_t frame_to_read = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (act_recog != NULL) && (act_frm_len != NULL) && (fifo != NULL)) + { + + /* Store the number of frames to be read */ + frame_to_read = *act_frm_len; + for (data_index = fifo->act_recog_byte_start_idx; data_index < fifo->length;) + { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Skip S4S frames if S4S is enabled */ + rslt = move_if_s4s_frame(&frame_header, &data_index, fifo); + + /* Break if FIFO is empty */ + if (rslt == BMI2_W_FIFO_EMPTY) + { + break; + } + + /* Index shifted to next byte where data starts */ + data_index++; + switch (frame_header) + { + /* If header defines accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_frm_len, fifo); + break; + + /* If header defines accelerometer and auxiliary frames */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_aux_frm_len, fifo); + break; + + /* If header defines accelerometer and gyroscope frames */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_gyr_frm_len, fifo); + break; + + /* If header defines accelerometer, auxiliary and gyroscope frames */ + case BMI2_FIFO_HEADER_ALL_FRM: + rslt = move_next_frame(&data_index, fifo->all_frm_len, fifo); + break; + + /* If header defines only gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->gyr_frm_len, fifo); + break; + + /* If header defines only auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + rslt = move_next_frame(&data_index, fifo->aux_frm_len, fifo); + break; + + /* If header defines auxiliary and gyroscope frame */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->aux_gyr_frm_len, fifo); + break; + + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = move_next_frame(&data_index, BMI2_SENSOR_TIME_LENGTH, fifo); + break; + + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_SKIP_FRM_LENGTH, fifo); + break; + + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + + /* If header defines invalid frame or end of valid data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + + /* Move the data index to the last byte to mark completion */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + + /* If header defines activity recognition frame */ + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + + /* Get the activity output */ + rslt = unpack_act_recog_output(&act_recog[(act_idx)], &data_index, fifo); + + /* Update activity frame index */ + (act_idx)++; + break; + default: + + /* Move the data index to the last byte in case of invalid values */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Number of frames to be read is complete or FIFO is empty */ + if ((frame_to_read == act_idx) || (rslt == BMI2_W_FIFO_EMPTY)) + { + break; + } + } + + /* Update the activity frame index */ + (*act_frm_len) = act_idx; + + /* Update the activity byte index */ + fifo->act_recog_byte_start_idx = data_index; + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API updates the cross sensitivity coefficient between gyroscope's + * X and Z axes. + */ +int8_t bmi2_get_gyro_cross_sense(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + struct bmi2_sensor_data data; + + /* Check if the feature is supported by this variant */ + if (dev->variant_feature & BMI2_GYRO_CROSS_SENS_ENABLE) + { + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Select the feature whose data is to be acquired */ + data.type = BMI2_GYRO_CROSS_SENSE; + + /* Get the respective data */ + rslt = bmi2_get_sensor_data(&data, 1, dev); + if (rslt == BMI2_OK) + { + /* Update the gyroscope cross sense value of z axis + * in the device structure + */ + dev->gyr_cross_sens_zx = data.sens_data.correction_factor_zx; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + } + + return rslt; +} + +/*! + * @brief This API gets Error bits and message indicating internal status. + */ +int8_t bmi2_get_internal_status(uint8_t *int_stat, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_stat != NULL)) + { + /* Delay to read the internal status */ + dev->delay_us(20000); + + /* Get the error bits and message */ + rslt = bmi2_get_regs(BMI2_INTERNAL_STATUS_ADDR, int_stat, 1, dev); + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API verifies and allows only the correct position to do Fast Offset Compensation for + * accelerometer & gyro. + */ +static int8_t verify_foc_position(uint8_t sens_list, const struct accel_foc_g_value *accel_g_axis, struct bmi2_dev *dev) +{ + int8_t rslt; + + struct bmi2_sens_axes_data avg_foc_data = { 0 }; + struct foc_temp_value temp_foc_data = { 0 }; + + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Enable sensor */ + rslt = bmi2_sensor_enable(&sens_list, 1, dev); + } + if (rslt == BMI2_OK) + { + + rslt = get_average_of_sensor_data(sens_list, &temp_foc_data, dev); + if (rslt == BMI2_OK) + { + if (sens_list == BMI2_ACCEL) + { + + /* Taking modulus to make negative values as positive */ + if ((accel_g_axis->x == 1) && (accel_g_axis->sign == 1)) + { + temp_foc_data.x = temp_foc_data.x * -1; + } + else if ((accel_g_axis->y == 1) && (accel_g_axis->sign == 1)) + { + temp_foc_data.y = temp_foc_data.y * -1; + } + else if ((accel_g_axis->z == 1) && (accel_g_axis->sign == 1)) + { + temp_foc_data.z = temp_foc_data.z * -1; + } + } + + /* Typecasting into 16bit */ + avg_foc_data.x = (int16_t)(temp_foc_data.x); + avg_foc_data.y = (int16_t)(temp_foc_data.y); + avg_foc_data.z = (int16_t)(temp_foc_data.z); + + rslt = validate_foc_position(sens_list, accel_g_axis, avg_foc_data, dev); + } + } + + return rslt; +} + +/*! + * @brief This API performs Fast Offset Compensation for accelerometer. + */ +int8_t bmi2_perform_accel_foc(const struct accel_foc_g_value *accel_g_value, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Structure to define the accelerometer configurations */ + struct bmi2_accel_config acc_cfg = { 0, 0, 0, 0 }; + + /* Variable to store status of advance power save */ + uint8_t aps = 0; + + /* Variable to store status of accelerometer enable */ + uint8_t acc_en = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (accel_g_value != NULL)) + { + /* Check for input validity */ + if ((((BMI2_ABS(accel_g_value->x)) + (BMI2_ABS(accel_g_value->y)) + (BMI2_ABS(accel_g_value->z))) == 1) && + ((accel_g_value->sign == 1) || (accel_g_value->sign == 0))) + { + rslt = verify_foc_position(BMI2_ACCEL, accel_g_value, dev); + if (rslt == BMI2_OK) + { + + /* Save accelerometer configurations, accelerometer + * enable status and advance power save status + */ + rslt = save_accel_foc_config(&acc_cfg, &aps, &acc_en, dev); + } + + /* Set configurations for FOC */ + if (rslt == BMI2_OK) + { + rslt = set_accel_foc_config(dev); + } + + /* Perform accelerometer FOC */ + if (rslt == BMI2_OK) + { + rslt = perform_accel_foc(accel_g_value, &acc_cfg, dev); + } + + /* Restore the saved configurations */ + if (rslt == BMI2_OK) + { + rslt = restore_accel_foc_config(&acc_cfg, aps, acc_en, dev); + } + } + else + { + rslt = BMI2_E_INVALID_INPUT; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API performs Fast Offset Compensation for gyroscope. + */ +int8_t bmi2_perform_gyro_foc(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Structure to define the gyroscope configurations */ + struct bmi2_gyro_config gyr_cfg = { 0, 0, 0, 0, 0, 0 }; + + /* Variable to store status of advance power save */ + uint8_t aps = 0; + + /* Variable to store status of gyroscope enable */ + uint8_t gyr_en = 0; + + /* Array of structure to store gyroscope data */ + struct bmi2_sens_axes_data gyr_value[128]; + + /* Structure to store gyroscope data temporarily */ + struct foc_temp_value temp = { 0, 0, 0 }; + + /* Variable to store status read from the status register */ + uint8_t reg_status = 0; + + /* Variable to define count */ + uint8_t loop = 0; + + /* Structure to store the offset values to be stored in the register */ + struct bmi2_sens_axes_data gyro_offset = { 0, 0, 0, 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Argument2 is not applicable for gyro */ + rslt = verify_foc_position(BMI2_GYRO, 0, dev); + if (rslt == BMI2_OK) + { + /* Save gyroscope configurations, gyroscope enable + * status and advance power save status + */ + rslt = save_gyro_config(&gyr_cfg, &aps, &gyr_en, dev); + + /* Set configurations for gyroscope FOC */ + if (rslt == BMI2_OK) + { + rslt = set_gyro_foc_config(dev); + } + + /* Perform FOC */ + if (rslt == BMI2_OK) + { + for (loop = 0; loop < 128; loop++) + { + /* Giving a delay of more than 40ms since ODR is configured as 25Hz */ + dev->delay_us(50000); + + /* Get gyroscope data ready interrupt status */ + rslt = bmi2_get_status(®_status, dev); + + /* Read 128 samples of gyroscope data on data ready interrupt */ + if ((rslt == BMI2_OK) && (reg_status & BMI2_DRDY_GYR)) + { + rslt = read_gyro_xyz(&gyr_value[loop], dev); + if (rslt == BMI2_OK) + { + /* Store the data in a temporary structure */ + temp.x = temp.x + (int32_t)gyr_value[loop].x; + temp.y = temp.y + (int32_t)gyr_value[loop].y; + temp.z = temp.z + (int32_t)gyr_value[loop].z; + } + } + if (rslt != BMI2_OK) + { + break; + } + else if ((reg_status & BMI2_DRDY_GYR) != BMI2_DRDY_GYR) + { + rslt = BMI2_E_INVALID_STATUS; + break; + } + } + if (rslt == BMI2_OK) + { + /* Take average of x, y and z data for lesser + * noise. It is same as offset data since lsb/dps + * is same for both data and offset register + */ + gyro_offset.x = (int16_t)(temp.x / 128); + gyro_offset.y = (int16_t)(temp.y / 128); + gyro_offset.z = (int16_t)(temp.z / 128); + + /* Saturate gyroscope data since the offset + * registers are of 10 bit value where as the + * gyroscope data is of 16 bit value + */ + saturate_gyro_data(&gyro_offset); + + /* Invert the gyroscope offset data */ + invert_gyro_offset(&gyro_offset); + + /* Write offset data in the gyroscope offset + * compensation register + */ + rslt = bmi2_write_gyro_offset_comp_axes(&gyro_offset, dev); + } + + /* Enable gyroscope offset compensation */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_gyro_offset_comp(BMI2_ENABLE, dev); + } + + /* Restore the saved gyroscope configurations */ + if (rslt == BMI2_OK) + { + rslt = restore_gyro_config(&gyr_cfg, aps, gyr_en, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This api is used for retrieving the activity recognition settings currently set. + */ +int8_t bmi2_get_act_recg_sett(struct act_recg_sett *sett, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat; + + /* Variable to set flag */ + uint8_t feat_found; + uint16_t msb_lsb; + uint8_t lsb; + uint8_t msb; + + /* Initialize feature configuration for activity recognition */ + struct bmi2_feature_config act_recg_sett = { 0, 0, 0 }; + + /* Search for bmi2 Abort feature and extract its configuration details */ + feat_found = extract_input_feat_config(&act_recg_sett, BMI2_ACTIVITY_RECOGNITION_SETTINGS, dev); + if (feat_found) + { + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + /* Get the configuration from the page where activity recognition setting feature resides */ + if (rslt == BMI2_OK) + { + rslt = get_feat_config(act_recg_sett.page, feat_config, dev); + } + if (rslt == BMI2_OK) + { + /* Define the offset in bytes */ + idx = act_recg_sett.start_addr; + + /* get the status of enable/disable post processing */ + sett->act_rec_1 = BMI2_GET_BIT_POS0(feat_config[idx], BMI2_ACT_RECG_POST_PROS_EN_DIS); + + /* increment idx by 2 to point min gdi thres addres */ + idx = idx + 2; + lsb = feat_config[idx]; + idx++; + msb = feat_config[idx]; + msb_lsb = (uint16_t)(lsb | msb << 8); + sett->act_rec_2 = msb_lsb; + + /* increment idx by 1 to point max gdi thres addres */ + idx++; + lsb = feat_config[idx]; + idx++; + msb = feat_config[idx]; + msb_lsb = (uint16_t)(lsb | msb << 8); + sett->act_rec_3 = msb_lsb; + + /* increment idx by 1 to point buffer size */ + idx++; + sett->act_rec_4 = BMI2_GET_BIT_POS0(feat_config[idx], BMI2_ACT_RECG_BUFF_SIZE); + + /* increment idx by 2 to to point to min segment confidence */ + idx = idx + 2; + sett->act_rec_5 = BMI2_GET_BIT_POS0(feat_config[idx], BMI2_ACT_RECG_MIN_SEG_CONF); + + } + + /* Enable Advance power save if disabled while + * configuring and not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This api is used for setting the activity recognition settings. + */ +int8_t bmi2_set_act_recg_sett(const struct act_recg_sett *sett, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for activity recognition */ + struct bmi2_feature_config act_recg_sett = { 0, 0, 0 }; + + /* Search for bmi2 Abort feature and extract its configuration details */ + feat_found = extract_input_feat_config(&act_recg_sett, BMI2_ACTIVITY_RECOGNITION_SETTINGS, dev); + if (feat_found) + { + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + /* Get the configuration from the page where activity recognition setting feature resides */ + if (rslt == BMI2_OK) + { + rslt = get_feat_config(act_recg_sett.page, feat_config, dev); + } + if (rslt == BMI2_OK) + { + /* Define the offset in bytes */ + idx = act_recg_sett.start_addr; + if ((sett->act_rec_4 > 10) || (sett->act_rec_5 > 10)) + { + rslt = BMI2_E_INVALID_INPUT; + } + if (rslt == BMI2_OK) + { + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], BMI2_ACT_RECG_POST_PROS_EN_DIS, sett->act_rec_1); + + /* increment idx by 2 to point min gdi thres addres */ + idx = idx + 2; + feat_config[idx] = BMI2_GET_LSB(sett->act_rec_2); + idx++; + feat_config[idx] = BMI2_GET_MSB(sett->act_rec_2); + + /* increment idx by 1 to point max gdi thres addres */ + idx++; + feat_config[idx] = BMI2_GET_LSB(sett->act_rec_3); + idx++; + feat_config[idx] = BMI2_GET_MSB(sett->act_rec_3); + + /* increment idx by 1 to point buffer size */ + idx++; + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], BMI2_ACT_RECG_BUFF_SIZE, sett->act_rec_4); + + /* increment idx by 2 to to point to min segment confidence */ + idx = idx + 2; + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], BMI2_ACT_RECG_MIN_SEG_CONF, sett->act_rec_5); + + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + + } + + /* Enable Advance power save if disabled while + * configuring and not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/***************************************************************************/ + +/*! Local Function Definitions + ****************************************************************************/ + +/*! + * @brief This internal API writes the configuration file. + */ +static int8_t write_config_file(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to update the configuration file index */ + uint16_t index = 0; + + /* config file size */ + uint16_t config_size = dev->config_size; + + /* Variable to get the remainder */ + uint8_t remain = (uint8_t)(config_size % dev->read_write_len); + + /* Variable to get the balance bytes */ + uint16_t bal_byte = 0; + + /* Variable to define temporary read/write length */ + uint16_t read_write_len = 0; + + /* Disable advanced power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + /* Disable loading of the configuration */ + rslt = set_config_load(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + if (!remain) + { + /* Write the configuration file */ + for (index = 0; (index < config_size) && (rslt == BMI2_OK); index += dev->read_write_len) + { + rslt = upload_file((dev->config_file_ptr + index), index, dev->read_write_len, dev); + } + } + else + { + /* Get the balance bytes */ + bal_byte = (uint16_t) config_size - (uint16_t) remain; + + /* Write the configuration file for the balancem bytes */ + for (index = 0; (index < bal_byte) && (rslt == BMI2_OK); index += dev->read_write_len) + { + rslt = upload_file((dev->config_file_ptr + index), index, dev->read_write_len, dev); + } + if (rslt == BMI2_OK) + { + /* Update length in a temporary variable */ + read_write_len = dev->read_write_len; + + /* Write the remaining bytes in 2 bytes length */ + dev->read_write_len = 2; + + /* Write the configuration file for the remaining bytes */ + for (index = bal_byte; + (index < config_size) && (rslt == BMI2_OK); + index += dev->read_write_len) + { + rslt = upload_file((dev->config_file_ptr + index), index, dev->read_write_len, dev); + } + + /* Restore the user set length back from the temporary variable */ + dev->read_write_len = read_write_len; + } + } + if (rslt == BMI2_OK) + { + /* Enable loading of the configuration */ + rslt = set_config_load(BMI2_ENABLE, dev); + + /* Wait till ASIC is initialized */ + dev->delay_us(150000); + if (rslt == BMI2_OK) + { + /* Enable advanced power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + dev->delay_us(1000); + } + } + } + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables the loading of the configuration + * file. + */ +static int8_t set_config_load(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data = 0; + + rslt = bmi2_get_regs(BMI2_INIT_CTRL_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_CONF_LOAD_EN, enable); + rslt = bmi2_set_regs(BMI2_INIT_CTRL_ADDR, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API loads the configuration file. + */ +static int8_t upload_file(const uint8_t *config_data, uint16_t index, uint16_t write_len, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store address */ + uint8_t addr_array[2] = { 0 }; + + if (config_data != NULL) + { + /* Store 0 to 3 bits of address in first byte */ + addr_array[0] = (uint8_t)((index / 2) & 0x0F); + + /* Store 4 to 11 bits of address in the second byte */ + addr_array[1] = (uint8_t)((index / 2) >> 4); + + /* Write the 2 bytes of address in consecutive locations */ + rslt = bmi2_set_regs(BMI2_INIT_ADDR_0, addr_array, 2, dev); + if (rslt == BMI2_OK) + { + /* Burst write configuration file data corresponding to user set length */ + rslt = bmi2_set_regs(BMI2_INIT_DATA_ADDR, (uint8_t *)config_data, write_len, dev); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the selected sensor/features. + */ +static int8_t sensor_enable(uint32_t sensor_sel, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store register values */ + uint8_t reg_data = 0; + + /* Variable to define loop */ + uint8_t loop = 1; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Enable accelerometer */ + if (sensor_sel & BMI2_ACCEL_SENS_SEL) + { + reg_data = BMI2_SET_BITS(reg_data, BMI2_ACC_EN, BMI2_ENABLE); + } + + /* Enable gyroscope */ + if (sensor_sel & BMI2_GYRO_SENS_SEL) + { + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_EN, BMI2_ENABLE); + } + + /* Enable auxiliary sensor */ + if (sensor_sel & BMI2_AUX_SENS_SEL) + { + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_AUX_EN, BMI2_ENABLE); + } + + /* Enable temperature sensor */ + if (sensor_sel & BMI2_TEMP_SENS_SEL) + { + reg_data = BMI2_SET_BITS(reg_data, BMI2_TEMP_EN, BMI2_ENABLE); + } + + /* Enable the sensors that are set in the power control register */ + if (sensor_sel & BMI2_MAIN_SENSORS) + { + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + } + } + if ((rslt == BMI2_OK) && (sensor_sel & ~(BMI2_MAIN_SENSORS))) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + while (loop--) + { + /* Enable sig-motion feature */ + if (sensor_sel & BMI2_SIG_MOTION_SEL) + { + rslt = set_sig_motion(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_SIG_MOTION_SEL; + } + else + { + break; + } + } + + /* Enable any motion feature */ + if (sensor_sel & BMI2_ANY_MOT_SEL) + { + rslt = set_any_motion(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_ANY_MOT_SEL; + } + else + { + break; + } + } + + /* Enable no motion feature */ + if (sensor_sel & BMI2_NO_MOT_SEL) + { + rslt = set_no_motion(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_NO_MOT_SEL; + } + else + { + break; + } + } + + /* Enable step detector feature */ + if (sensor_sel & BMI2_STEP_DETECT_SEL) + { + rslt = set_step_detector(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_STEP_DETECT_SEL; + } + else + { + break; + } + } + + /* Enable step counter feature */ + if (sensor_sel & BMI2_STEP_COUNT_SEL) + { + rslt = set_step_counter(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_STEP_COUNT_SEL; + } + else + { + break; + } + } + + /* Enable step activity feature */ + if (sensor_sel & BMI2_STEP_ACT_SEL) + { + rslt = set_step_activity(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_STEP_ACT_SEL; + } + else + { + break; + } + } + + /* Enable gyroscope user gain */ + if (sensor_sel & BMI2_GYRO_GAIN_UPDATE_SEL) + { + rslt = set_gyro_user_gain(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_GYRO_GAIN_UPDATE_SEL; + } + else + { + break; + } + } + + /* Enable tilt feature */ + if (sensor_sel & BMI2_TILT_SEL) + { + rslt = set_tilt(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_TILT_SEL; + } + else + { + break; + } + } + + /* Enable uphold to wake feature */ + if (sensor_sel & BMI2_UP_HOLD_TO_WAKE_SEL) + { + rslt = set_up_hold_to_wake(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_UP_HOLD_TO_WAKE_SEL; + } + else + { + break; + } + } + + /* Enable glance feature */ + if (sensor_sel & BMI2_GLANCE_DET_SEL) + { + rslt = set_glance_detector(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_GLANCE_DET_SEL; + } + else + { + break; + } + } + + /* Enable wake-up feature */ + if (sensor_sel & BMI2_WAKE_UP_SEL) + { + rslt = set_wake_up(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_WAKE_UP_SEL; + } + else + { + break; + } + } + + /* Enable orientation feature */ + if (sensor_sel & BMI2_ORIENT_SEL) + { + rslt = set_orientation(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_ORIENT_SEL; + } + else + { + break; + } + } + + /* Enable high-g feature */ + if (sensor_sel & BMI2_HIGH_G_SEL) + { + rslt = set_high_g(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_HIGH_G_SEL; + } + else + { + break; + } + } + + /* Enable low-g feature */ + if (sensor_sel & BMI2_LOW_G_SEL) + { + rslt = set_low_g(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_LOW_G_SEL; + } + else + { + break; + } + } + + /* Enable flat feature */ + if (sensor_sel & BMI2_FLAT_SEL) + { + rslt = set_flat(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_FLAT_SEL; + } + else + { + break; + } + } + + /* Enable external sensor feature */ + if (sensor_sel & BMI2_EXT_SENS_SEL) + { + rslt = set_ext_sens_sync(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_EXT_SENS_SEL; + } + else + { + break; + } + } + + /* Enable gyroscope self-offset correction feature */ + if (sensor_sel & BMI2_GYRO_SELF_OFF_SEL) + { + rslt = set_gyro_self_offset_corr(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_GYRO_SELF_OFF_SEL; + } + else + { + break; + } + } + + /* Enable wrist gesture feature */ + if (sensor_sel & BMI2_WRIST_GEST_SEL) + { + rslt = set_wrist_gesture(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_WRIST_GEST_SEL; + } + else + { + break; + } + } + + /* Enable wrist wear wake-up feature */ + if (sensor_sel & BMI2_WRIST_WEAR_WAKE_UP_SEL) + { + rslt = set_wrist_wear_wake_up(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_WRIST_WEAR_WAKE_UP_SEL; + } + else + { + break; + } + } + + /* Enable wrist gesture feature for wearable variant */ + if (sensor_sel & BMI2_WRIST_GEST_W_SEL) + { + rslt = set_wrist_gesture_wh(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_WRIST_GEST_SEL; + } + else + { + break; + } + } + + /* Enable wrist wear wake-up feature for wearable variant */ + if (sensor_sel & BMI2_WRIST_WEAR_WAKE_UP_WH_SEL) + { + rslt = set_wrist_wear_wake_up_wh(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_WRIST_WEAR_WAKE_UP_SEL; + } + else + { + break; + } + } + + /* Enable activity recognition feature */ + if (sensor_sel & BMI2_ACTIVITY_RECOGNITION_SEL) + { + rslt = set_act_recog(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_ACTIVITY_RECOGNITION_SEL; + } + else + { + break; + } + } + + /* Enable accelerometer self-test feature */ + if (sensor_sel & BMI2_ACCEL_SELF_TEST_SEL) + { + rslt = set_feat_accel_self_test(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_ACCEL_SELF_TEST_SEL; + } + else + { + break; + } + } + + /* Enable low pass filter feature for wearable variant */ + if (sensor_sel & BMI2_PRIMARY_OIS_SEL) + { + rslt = set_primary_ois_low_pass_filter(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_PRIMARY_OIS_SEL; + } + else + { + break; + } + } + + if (sensor_sel & BMI2_FREE_FALL_DET_SEL) + { + rslt = set_free_fall_det(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_FREE_FALL_DET_SEL; + } + else + { + break; + } + } + } + + /* Enable Advance power save if disabled while + * configuring and not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API disables the selected sensors/features. + */ +static int8_t sensor_disable(uint32_t sensor_sel, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store register values */ + uint8_t reg_data = 0; + + /* Variable to define loop */ + uint8_t loop = 1; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Disable accelerometer */ + if (sensor_sel & BMI2_ACCEL_SENS_SEL) + { + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_ACC_EN); + } + + /* Disable gyroscope */ + if (sensor_sel & BMI2_GYRO_SENS_SEL) + { + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_GYR_EN); + } + + /* Disable auxiliary sensor */ + if (sensor_sel & BMI2_AUX_SENS_SEL) + { + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_AUX_EN); + } + + /* Disable temperature sensor */ + if (sensor_sel & BMI2_TEMP_SENS_SEL) + { + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_TEMP_EN); + } + + /* Disable the sensors that are set in the power control register */ + if (sensor_sel & BMI2_MAIN_SENSORS) + { + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + } + } + if ((rslt == BMI2_OK) && (sensor_sel & ~(BMI2_MAIN_SENSORS))) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + while (loop--) + { + /* Disable sig-motion feature */ + if (sensor_sel & BMI2_SIG_MOTION_SEL) + { + rslt = set_sig_motion(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_SIG_MOTION_SEL; + } + else + { + break; + } + } + + /* Disable any-motion feature */ + if (sensor_sel & BMI2_ANY_MOT_SEL) + { + rslt = set_any_motion(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_ANY_MOT_SEL; + } + else + { + break; + } + } + + /* Disable no-motion feature */ + if (sensor_sel & BMI2_NO_MOT_SEL) + { + rslt = set_no_motion(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_NO_MOT_SEL; + } + else + { + break; + } + } + + /* Disable step detector feature */ + if (sensor_sel & BMI2_STEP_DETECT_SEL) + { + rslt = set_step_detector(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_STEP_DETECT_SEL; + } + else + { + break; + } + } + + /* Disable step counter feature */ + if (sensor_sel & BMI2_STEP_COUNT_SEL) + { + rslt = set_step_counter(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_STEP_COUNT_SEL; + } + else + { + break; + } + } + + /* Disable step activity feature */ + if (sensor_sel & BMI2_STEP_ACT_SEL) + { + rslt = set_step_activity(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_STEP_ACT_SEL; + } + else + { + break; + } + } + + /* Disable gyroscope user gain */ + if (sensor_sel & BMI2_GYRO_GAIN_UPDATE_SEL) + { + rslt = set_gyro_user_gain(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_GYRO_GAIN_UPDATE_SEL; + } + else + { + break; + } + } + + /* Disable tilt feature */ + if (sensor_sel & BMI2_TILT_SEL) + { + rslt = set_tilt(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_TILT_SEL; + } + else + { + break; + } + } + + /* Disable uphold to wake feature */ + if (sensor_sel & BMI2_UP_HOLD_TO_WAKE_SEL) + { + rslt = set_up_hold_to_wake(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_UP_HOLD_TO_WAKE_SEL; + } + else + { + break; + } + } + + /* Disable glance feature */ + if (sensor_sel & BMI2_GLANCE_DET_SEL) + { + rslt = set_glance_detector(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_GLANCE_DET_SEL; + } + else + { + break; + } + } + + /* Disable wake-up feature */ + if (sensor_sel & BMI2_WAKE_UP_SEL) + { + rslt = set_wake_up(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_WAKE_UP_SEL; + } + else + { + break; + } + } + + /* Disable orientation feature */ + if (sensor_sel & BMI2_ORIENT_SEL) + { + rslt = set_orientation(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_ORIENT_SEL; + } + else + { + break; + } + } + + /* Disable high-g feature */ + if (sensor_sel & BMI2_HIGH_G_SEL) + { + rslt = set_high_g(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_HIGH_G_SEL; + } + else + { + break; + } + } + + /* Disable low-g feature */ + if (sensor_sel & BMI2_LOW_G_SEL) + { + rslt = set_low_g(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_LOW_G_SEL; + } + else + { + break; + } + } + + /* Disable flat feature */ + if (sensor_sel & BMI2_FLAT_SEL) + { + rslt = set_flat(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_FLAT_SEL; + } + else + { + break; + } + } + + /* Disable external sensor feature */ + if (sensor_sel & BMI2_EXT_SENS_SEL) + { + rslt = set_ext_sens_sync(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_EXT_SENS_SEL; + } + else + { + break; + } + } + + /* Disable gyroscope self-offset correction feature */ + if (sensor_sel & BMI2_GYRO_SELF_OFF_SEL) + { + rslt = set_gyro_self_offset_corr(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_GYRO_SELF_OFF_SEL; + } + else + { + break; + } + } + + /* Disable wrist gesture feature */ + if (sensor_sel & BMI2_WRIST_GEST_SEL) + { + rslt = set_wrist_gesture(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_WRIST_GEST_SEL; + } + else + { + break; + } + } + + /* Disable wrist wear wake-up feature */ + if (sensor_sel & BMI2_WRIST_WEAR_WAKE_UP_SEL) + { + rslt = set_wrist_wear_wake_up(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_WRIST_WEAR_WAKE_UP_SEL; + } + else + { + break; + } + } + + /* Disable wrist gesture feature for wearable variant*/ + if (sensor_sel & BMI2_WRIST_GEST_W_SEL) + { + rslt = set_wrist_gesture_wh(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_WRIST_GEST_W_SEL; + } + else + { + break; + } + } + + /* Disable wrist wear wake-up feature for wearable variant*/ + if (sensor_sel & BMI2_WRIST_WEAR_WAKE_UP_WH_SEL) + { + rslt = set_wrist_wear_wake_up_wh(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_WRIST_WEAR_WAKE_UP_WH_SEL; + } + else + { + break; + } + } + + /* Disable activity recognition feature */ + if (sensor_sel & BMI2_ACTIVITY_RECOGNITION_SEL) + { + rslt = set_act_recog(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_ACTIVITY_RECOGNITION_SEL; + } + else + { + break; + } + } + + /* Disable accelerometer self-test feature */ + if (sensor_sel & BMI2_ACCEL_SELF_TEST_SEL) + { + rslt = set_feat_accel_self_test(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat &= ~BMI2_ACCEL_SELF_TEST_SEL; + } + else + { + break; + } + } + + /* Disable accelerometer free-fall detection feature */ + if (sensor_sel & BMI2_FREE_FALL_DET_SEL) + { + rslt = set_free_fall_det(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + dev->sens_en_stat |= BMI2_FREE_FALL_DET_SEL; + } + else + { + break; + } + } + + /* Enable Advance power save if disabled while + * configuring and not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This internal API selects the sensor/features to be enabled or + * disabled. + */ +static int8_t select_sensor(const uint8_t *sens_list, uint8_t n_sens, uint32_t *sensor_sel) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variable to define loop */ + uint8_t count; + + for (count = 0; count < n_sens; count++) + { + switch (sens_list[count]) + { + case BMI2_ACCEL: + *sensor_sel |= BMI2_ACCEL_SENS_SEL; + break; + case BMI2_GYRO: + *sensor_sel |= BMI2_GYRO_SENS_SEL; + break; + case BMI2_AUX: + *sensor_sel |= BMI2_AUX_SENS_SEL; + break; + case BMI2_TEMP: + *sensor_sel |= BMI2_TEMP_SENS_SEL; + break; + case BMI2_SIG_MOTION: + *sensor_sel |= BMI2_SIG_MOTION_SEL; + break; + case BMI2_ANY_MOTION: + *sensor_sel |= BMI2_ANY_MOT_SEL; + break; + case BMI2_NO_MOTION: + *sensor_sel |= BMI2_NO_MOT_SEL; + break; + case BMI2_STEP_DETECTOR: + *sensor_sel |= BMI2_STEP_DETECT_SEL; + break; + case BMI2_STEP_COUNTER: + *sensor_sel |= BMI2_STEP_COUNT_SEL; + break; + case BMI2_STEP_ACTIVITY: + *sensor_sel |= BMI2_STEP_ACT_SEL; + break; + case BMI2_GYRO_GAIN_UPDATE: + *sensor_sel |= BMI2_GYRO_GAIN_UPDATE_SEL; + break; + case BMI2_TILT: + *sensor_sel |= BMI2_TILT_SEL; + break; + case BMI2_UP_HOLD_TO_WAKE: + *sensor_sel |= BMI2_UP_HOLD_TO_WAKE_SEL; + break; + case BMI2_GLANCE_DETECTOR: + *sensor_sel |= BMI2_GLANCE_DET_SEL; + break; + case BMI2_WAKE_UP: + *sensor_sel |= BMI2_WAKE_UP_SEL; + break; + case BMI2_ORIENTATION: + *sensor_sel |= BMI2_ORIENT_SEL; + break; + case BMI2_HIGH_G: + *sensor_sel |= BMI2_HIGH_G_SEL; + break; + case BMI2_LOW_G: + *sensor_sel |= BMI2_LOW_G_SEL; + break; + case BMI2_FLAT: + *sensor_sel |= BMI2_FLAT_SEL; + break; + case BMI2_EXT_SENS_SYNC: + *sensor_sel |= BMI2_EXT_SENS_SEL; + break; + case BMI2_GYRO_SELF_OFF: + *sensor_sel |= BMI2_GYRO_SELF_OFF_SEL; + break; + case BMI2_WRIST_GESTURE: + *sensor_sel |= BMI2_WRIST_GEST_SEL; + break; + + case BMI2_WRIST_GESTURE_WH: + *sensor_sel |= BMI2_WRIST_GEST_W_SEL; + break; + case BMI2_WRIST_WEAR_WAKE_UP: + *sensor_sel |= BMI2_WRIST_WEAR_WAKE_UP_SEL; + break; + case BMI2_WRIST_WEAR_WAKE_UP_WH: + *sensor_sel |= BMI2_WRIST_WEAR_WAKE_UP_WH_SEL; + break; + case BMI2_ACTIVITY_RECOGNITION: + *sensor_sel |= BMI2_ACTIVITY_RECOGNITION_SEL; + break; + case BMI2_ACCEL_SELF_TEST: + *sensor_sel |= BMI2_ACCEL_SELF_TEST_SEL; + break; + case BMI2_PRIMARY_OIS: + *sensor_sel |= BMI2_PRIMARY_OIS_SEL; + break; + case BMI2_FREE_FALL_DET: + *sensor_sel |= BMI2_FREE_FALL_DET_SEL; + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable any motion feature. + */ +static int8_t set_any_motion(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for any-motion */ + struct bmi2_feature_config any_mot_config = { 0, 0, 0 }; + + /* Search for any-motion feature and extract its configurations details */ + feat_found = extract_input_feat_config(&any_mot_config, BMI2_ANY_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where any-motion feature resides */ + rslt = get_feat_config(any_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of any-motion axes */ + idx = any_mot_config.start_addr + ANY_MOT_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], ANY_NO_MOT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable no-motion feature. + */ +static int8_t set_no_motion(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for no-motion */ + struct bmi2_feature_config no_mot_config = { 0, 0, 0 }; + + /* Search for no-motion feature and extract its configurations details */ + feat_found = extract_input_feat_config(&no_mot_config, BMI2_NO_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where any/no-motion feature resides */ + rslt = get_feat_config(no_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of no-motion axes */ + idx = no_mot_config.start_addr + NO_MOT_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], ANY_NO_MOT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable sig-motion feature. + */ +static int8_t set_sig_motion(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for sig-motion */ + struct bmi2_feature_config sig_mot_config = { 0, 0, 0 }; + + /* Search for sig-motion feature and extract its configuration details */ + feat_found = extract_input_feat_config(&sig_mot_config, BMI2_SIG_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where sig-motion feature resides */ + rslt = get_feat_config(sig_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of sig-motion */ + idx = sig_mot_config.start_addr + SIG_MOT_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], SIG_MOT_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable step detector feature. + */ +static int8_t set_step_detector(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for step detector */ + struct bmi2_feature_config step_det_config = { 0, 0, 0 }; + + /* Search for step detector feature and extract its configuration details */ + feat_found = extract_input_feat_config(&step_det_config, BMI2_STEP_DETECTOR, dev); + if (feat_found) + { + /* Get the configuration from the page where step detector feature resides */ + rslt = get_feat_config(step_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of step detector */ + idx = step_det_config.start_addr + STEP_COUNT_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], STEP_DET_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable step counter feature. + */ +static int8_t set_step_counter(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for step counter */ + struct bmi2_feature_config step_count_config = { 0, 0, 0 }; + + /* Search for step counter feature and extract its configuration details */ + feat_found = extract_input_feat_config(&step_count_config, BMI2_STEP_COUNTER, dev); + if (feat_found) + { + /* Get the configuration from the page where step-counter feature resides */ + rslt = get_feat_config(step_count_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of step counter */ + idx = step_count_config.start_addr + STEP_COUNT_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], STEP_COUNT_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable step activity detection. + */ +static int8_t set_step_activity(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for step activity */ + struct bmi2_feature_config step_act_config = { 0, 0, 0 }; + + /* Search for step activity feature and extract its configuration details */ + feat_found = extract_input_feat_config(&step_act_config, BMI2_STEP_ACTIVITY, dev); + if (feat_found) + { + /* Get the configuration from the page where step-activity + * feature resides + */ + rslt = get_feat_config(step_act_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of step activity */ + idx = step_act_config.start_addr + STEP_COUNT_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], STEP_ACT_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable tilt feature. + */ +static int8_t set_tilt(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for tilt */ + struct bmi2_feature_config tilt_config = { 0, 0, 0 }; + + /* Search for tilt feature and extract its configuration details */ + feat_found = extract_input_feat_config(&tilt_config, BMI2_TILT, dev); + if (feat_found) + { + /* Get the configuration from the page where tilt feature resides */ + rslt = get_feat_config(tilt_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of tilt */ + idx = tilt_config.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], TILT_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable uphold to wake feature. + */ +static int8_t set_up_hold_to_wake(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for uphold to wake */ + struct bmi2_feature_config up_hold_to_wake_config = { 0, 0, 0 }; + + /* Search for uphold to wake feature and extract its configuration details */ + feat_found = extract_input_feat_config(&up_hold_to_wake_config, BMI2_UP_HOLD_TO_WAKE, dev); + if (feat_found) + { + /* Get the configuration from the page where uphold to wake feature resides */ + rslt = get_feat_config(up_hold_to_wake_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of uphold to wake */ + idx = up_hold_to_wake_config.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], UP_HOLD_TO_WAKE_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable glance detector feature. + */ +static int8_t set_glance_detector(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for glance detector */ + struct bmi2_feature_config glance_det_config = { 0, 0, 0 }; + + /* Search for glance detector feature and extract its configuration details */ + feat_found = extract_input_feat_config(&glance_det_config, BMI2_GLANCE_DETECTOR, dev); + if (feat_found) + { + /* Get the configuration from the page where glance detector + * feature resides + */ + rslt = get_feat_config(glance_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of glance */ + idx = glance_det_config.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], GLANCE_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable wake-up feature through + * single or double tap. + */ +static int8_t set_wake_up(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wake-up */ + struct bmi2_feature_config wake_up_config = { 0, 0, 0 }; + + /* Search for wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wake_up_config, BMI2_WAKE_UP, dev); + if (feat_found) + { + /* Get the configuration from the page where wake-up feature resides */ + rslt = get_feat_config(wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of wake-up */ + idx = wake_up_config.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], WAKE_UP_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable orientation feature. + */ +static int8_t set_orientation(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for orientation */ + struct bmi2_feature_config orient_config = { 0, 0, 0 }; + + /* Search for orientation feature and extract its configuration details */ + feat_found = extract_input_feat_config(&orient_config, BMI2_ORIENTATION, dev); + if (feat_found) + { + /* Get the configuration from the page where orientation feature resides */ + rslt = get_feat_config(orient_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of orientation */ + idx = orient_config.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], ORIENT_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable high-g feature. + */ +static int8_t set_high_g(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for high-g */ + struct bmi2_feature_config high_g_config = { 0, 0, 0 }; + + /* Search for high-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&high_g_config, BMI2_HIGH_G, dev); + if (feat_found) + { + /* Get the configuration from the page where high-g feature resides */ + rslt = get_feat_config(high_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of high-g */ + idx = high_g_config.start_addr + HIGH_G_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], HIGH_G_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable low-g feature. + */ +static int8_t set_low_g(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for low-g */ + struct bmi2_feature_config low_g_config = { 0, 0, 0 }; + + /* Search for low-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&low_g_config, BMI2_LOW_G, dev); + if (feat_found) + { + /* Get the configuration from the page where low-g feature resides */ + rslt = get_feat_config(low_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of low-g */ + idx = low_g_config.start_addr + LOW_G_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], LOW_G_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable flat feature. + */ +static int8_t set_flat(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for flat */ + struct bmi2_feature_config flat_config = { 0, 0, 0 }; + + /* Search for flat feature and extract its configuration details */ + feat_found = extract_input_feat_config(&flat_config, BMI2_FLAT, dev); + if (feat_found) + { + /* Get the configuration from the page where flat feature resides */ + rslt = get_feat_config(flat_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of flat */ + idx = flat_config.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], FLAT_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable external sensor sync + * feature. + */ +static int8_t set_ext_sens_sync(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for external sensor sync */ + struct bmi2_feature_config ext_sens_sync_cfg = { 0, 0, 0 }; + + /* Search for sync feature and extract its configuration details */ + feat_found = extract_input_feat_config(&ext_sens_sync_cfg, BMI2_EXT_SENS_SYNC, dev); + if (feat_found) + { + /* Get the configuration from the page where sync feature resides */ + rslt = get_feat_config(ext_sens_sync_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of sync */ + idx = ext_sens_sync_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], EXT_SENS_SYNC_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gives an option to enable self-offset correction + * feature of gyroscope, either internally or by the host. + */ +static int8_t set_gyro_self_offset_corr(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for self-offset correction */ + struct bmi2_feature_config self_off_corr_cfg = { 0, 0, 0 }; + + /* Search for self-offset correction and extract its configuration details */ + feat_found = extract_input_feat_config(&self_off_corr_cfg, BMI2_GYRO_SELF_OFF, dev); + if (feat_found) + { + /* Get the configuration from the page where self-offset + * correction feature resides + */ + rslt = get_feat_config(self_off_corr_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of self-offset correction */ + idx = self_off_corr_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], GYR_SELF_OFF_CORR_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the wrist gesture feature. + */ +static int8_t set_wrist_gesture(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_cfg = { 0, 0, 0 }; + + /* Search for wrist gesture and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_gest_cfg, BMI2_WRIST_GESTURE, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist gesture feature resides */ + rslt = get_feat_config(wrist_gest_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of wrist gesture */ + idx = wrist_gest_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], WRIST_GEST_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the wrist wear wake up feature. + */ +static int8_t set_wrist_wear_wake_up(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist wear wake up */ + struct bmi2_feature_config wrist_wake_up_cfg = { 0, 0, 0 }; + + /* Search for wrist wear wake up and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_wake_up_cfg, BMI2_WRIST_WEAR_WAKE_UP, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist wear wake up + * feature resides + */ + rslt = get_feat_config(wrist_wake_up_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of wrist wear wake up */ + idx = wrist_wake_up_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], WRIST_WEAR_WAKE_UP_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the wrist gesture feature. + */ +static int8_t set_wrist_gesture_wh(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_cfg = { 0, 0, 0 }; + + /* Search for wrist gesture and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_gest_cfg, BMI2_WRIST_GESTURE_WH, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist gesture feature resides */ + rslt = get_feat_config(wrist_gest_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of wrist gesture */ + idx = wrist_gest_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], WRIST_GEST_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the wrist wear wake up feature. + */ +static int8_t set_wrist_wear_wake_up_wh(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist wear wake up */ + struct bmi2_feature_config wrist_wake_up_cfg = { 0, 0, 0 }; + + /* Search for wrist wear wake up and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_wake_up_cfg, BMI2_WRIST_WEAR_WAKE_UP_WH, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist wear wake up + * feature resides + */ + rslt = get_feat_config(wrist_wake_up_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of wrist wear wake up */ + idx = wrist_wake_up_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], WRIST_WEAR_WAKE_UP_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables the activity recognition feature. + */ +static int8_t set_act_recog(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for activity recognition */ + struct bmi2_feature_config act_recog_cfg = { 0, 0, 0 }; + + /* Search for activity recognition and extract its configuration details */ + feat_found = extract_input_feat_config(&act_recog_cfg, BMI2_ACTIVITY_RECOGNITION, dev); + if (feat_found) + { + /* Get the configuration from the page where activity + * recognition feature resides + */ + rslt = get_feat_config(act_recog_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of activity recognition */ + idx = act_recog_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], ACTIVITY_RECOG_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable gyroscope user gain + * feature. + */ +static int8_t set_gyro_user_gain(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for gyroscope user gain */ + struct bmi2_feature_config gyr_user_gain_cfg = { 0, 0, 0 }; + + /* Search for user gain feature and extract its configuration details */ + feat_found = extract_input_feat_config(&gyr_user_gain_cfg, BMI2_GYRO_GAIN_UPDATE, dev); + if (feat_found) + { + /* Get the configuration from the page where user gain feature resides */ + rslt = get_feat_config(gyr_user_gain_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of user gain */ + idx = gyr_user_gain_cfg.start_addr + GYR_USER_GAIN_FEAT_EN_OFFSET; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], GYR_USER_GAIN_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gives an option to enable accelerometer self-test + * in the feature register. + */ +static int8_t set_feat_accel_self_test(uint8_t enable, struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + uint8_t idx = 0; + uint8_t feat_found; + struct bmi2_feature_config acc_feat_self_test_cfg = { 0, 0, 0 }; + + /* Search for accelerometer self-test and extract its configuration details */ + feat_found = extract_input_feat_config(&acc_feat_self_test_cfg, BMI2_ACCEL_SELF_TEST, dev); + if (feat_found) + { + /* Get the configuration from the page where accelerometer self-test feature resides */ + rslt = get_feat_config(acc_feat_self_test_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of accelerometer self-test */ + idx = acc_feat_self_test_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], ACC_SELF_TEST_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + + /* Delay added as per the firmware spec */ + dev->delay_us(160000); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gives an option to enable low pass filter + * in the feature register. + */ +static int8_t set_primary_ois_low_pass_filter(uint8_t enable, struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + uint8_t idx = 0; + uint8_t feat_found; + struct bmi2_feature_config primary_ois_lp_filter_cfg = { 0, 0, 0 }; + + /* Search for low pass filter and extract its configuration details */ + feat_found = extract_input_feat_config(&primary_ois_lp_filter_cfg, BMI2_PRIMARY_OIS, dev); + if (feat_found) + { + /* Get the configuration from the page where low pass filter feature resides */ + rslt = get_feat_config(primary_ois_lp_filter_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of low pass filter */ + idx = primary_ois_lp_filter_cfg.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], LP_FILTER_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets accelerometer configurations like ODR, + * bandwidth, performance mode and g-range. + */ +static int8_t set_accel_config(struct bmi2_accel_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data; + + /* Array to store the default value of accelerometer configuration + * reserved registers + */ + uint8_t data_array[2] = { 0 }; + + /* Validate bandwidth and performance mode */ + rslt = validate_bw_perf_mode(&config->bwp, &config->filter_perf, dev); + if (rslt == BMI2_OK) + { + /* Validate ODR and range */ + rslt = validate_odr_range(&config->odr, &config->range, dev); + if (rslt == BMI2_OK) + { + /* Set accelerometer performance mode */ + reg_data = BMI2_SET_BITS(data_array[0], BMI2_ACC_FILTER_PERF_MODE, config->filter_perf); + + /* Set accelerometer bandwidth */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_ACC_BW_PARAM, config->bwp); + + /* Set accelerometer ODR */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_ACC_ODR, config->odr); + + /* Copy the register data to the array */ + data_array[0] = reg_data; + + /* Set accelerometer range */ + reg_data = BMI2_SET_BIT_POS0(data_array[1], BMI2_ACC_RANGE, config->range); + + /* Copy the register data to the array */ + data_array[1] = reg_data; + + /* Write accelerometer configuration to ACC_CONFand + * ACC_RANGE registers simultaneously as they lie in consecutive places + */ + rslt = bmi2_set_regs(BMI2_ACC_CONF_ADDR, data_array, 2, dev); + + /* Get error status to check for invalid configurations */ + if (rslt == BMI2_OK) + { + rslt = cfg_error_status(dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API validates bandwidth and performance mode of the + * accelerometer set by the user. + */ +static int8_t validate_bw_perf_mode(uint8_t *bandwidth, uint8_t *perf_mode, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate and auto-correct performance mode */ + rslt = check_boundary_val(perf_mode, BMI2_POWER_OPT_MODE, BMI2_PERF_OPT_MODE, dev); + if (rslt == BMI2_OK) + { + /* Validate and auto-correct bandwidth parameter */ + if (*perf_mode == BMI2_PERF_OPT_MODE) + { + /* Validate for continuous filter mode */ + rslt = check_boundary_val(bandwidth, BMI2_ACC_OSR4_AVG1, BMI2_ACC_CIC_AVG8, dev); + } + else + { + /* Validate for CIC averaging mode */ + rslt = check_boundary_val(bandwidth, BMI2_ACC_OSR4_AVG1, BMI2_ACC_RES_AVG128, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API validates ODR and range of the accelerometer set by + * the user. + */ +static int8_t validate_odr_range(uint8_t *odr, uint8_t *range, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate and auto correct ODR */ + rslt = check_boundary_val(odr, BMI2_ACC_ODR_0_78HZ, BMI2_ACC_ODR_1600HZ, dev); + if (rslt == BMI2_OK) + { + /* Validate and auto correct Range */ + rslt = check_boundary_val(range, BMI2_ACC_RANGE_2G, BMI2_ACC_RANGE_16G, dev); + } + + return rslt; +} + +/*! + * @brief This internal API sets gyroscope configurations like ODR, bandwidth, + * low power/high performance mode, performance mode and range. It also + * maps/un-maps data interrupts to that of hardware interrupt line. + */ +static int8_t set_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data; + + /* Array to store the default value of gyroscope configuration reserved registers */ + uint8_t data_array[2] = { 0 }; + + /* Validate gyroscope configurations */ + rslt = validate_gyro_config(config, dev); + if (rslt == BMI2_OK) + { + /* Set gyroscope performance mode */ + reg_data = BMI2_SET_BITS(data_array[0], BMI2_GYR_FILTER_PERF_MODE, config->filter_perf); + + /* Set gyroscope noise performance mode */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_NOISE_PERF_MODE, config->noise_perf); + + /* Set gyroscope bandwidth */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_BW_PARAM, config->bwp); + + /* Set gyroscope ODR */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_GYR_ODR, config->odr); + + /* Copy the register data to the array */ + data_array[0] = reg_data; + + /* Set gyroscope OIS range */ + reg_data = BMI2_SET_BITS(data_array[1], BMI2_GYR_OIS_RANGE, config->ois_range); + + /* Set gyroscope range */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_GYR_RANGE, config->range); + + /* Copy the register data to the array */ + data_array[1] = reg_data; + + /* Write accelerometer configuration to GYR_CONF and GYR_RANGE + * registers simultaneously as they lie in consecutive places + */ + rslt = bmi2_set_regs(BMI2_GYR_CONF_ADDR, data_array, 2, dev); + + /* Get error status to check for invalid configurations */ + if (rslt == BMI2_OK) + { + rslt = cfg_error_status(dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API validates bandwidth, performance mode, low power/ + * high performance mode, ODR, and range set by the user. + */ +static int8_t validate_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate and auto-correct performance mode */ + rslt = check_boundary_val(&config->filter_perf, BMI2_POWER_OPT_MODE, BMI2_PERF_OPT_MODE, dev); + if (rslt == BMI2_OK) + { + /* Validate and auto-correct bandwidth parameter */ + rslt = check_boundary_val(&config->bwp, BMI2_GYR_OSR4_MODE, BMI2_GYR_CIC_MODE, dev); + if (rslt == BMI2_OK) + { + /* Validate and auto-correct low power/high-performance parameter */ + rslt = check_boundary_val(&config->noise_perf, BMI2_POWER_OPT_MODE, BMI2_PERF_OPT_MODE, dev); + if (rslt == BMI2_OK) + { + /* Validate and auto-correct ODR parameter */ + rslt = check_boundary_val(&config->odr, BMI2_GYR_ODR_25HZ, BMI2_GYR_ODR_3200HZ, dev); + if (rslt == BMI2_OK) + { + /* Validate and auto-correct OIS range */ + rslt = check_boundary_val(&config->ois_range, BMI2_GYR_OIS_250, BMI2_GYR_OIS_2000, dev); + if (rslt == BMI2_OK) + { + /* Validate and auto-correct range parameter */ + rslt = check_boundary_val(&config->range, BMI2_GYR_RANGE_2000, BMI2_GYR_RANGE_125, dev); + } + } + } + } + } + + return rslt; +} + +/*! + * @brief This internal API shows the error status when illegal sensor + * configuration is set. + */ +static int8_t cfg_error_status(const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data; + + /* Get error status of the set sensor configuration */ + rslt = bmi2_get_regs(BMI2_EVENT_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + reg_data = BMI2_GET_BITS(reg_data, BMI2_EVENT_FLAG); + switch (reg_data) + { + case BMI2_NO_ERROR: + rslt = BMI2_OK; + break; + case BMI2_ACC_ERROR: + rslt = BMI2_E_ACC_INVALID_CFG; + break; + case BMI2_GYR_ERROR: + rslt = BMI2_E_GYRO_INVALID_CFG; + break; + case BMI2_ACC_GYR_ERROR: + rslt = BMI2_E_ACC_GYR_INVALID_CFG; + break; + default: + break; + } + } + + return rslt; +} + +/*! + * @brief This internal API: + * 1) Enables/Disables auxiliary interface. + * 2) Sets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3)It maps/un-maps data interrupts to that of hardware interrupt line. + */ +static int8_t set_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate auxiliary configurations */ + rslt = validate_aux_config(config, dev); + if (rslt == BMI2_OK) + { + /* Enable/Disable auxiliary interface */ + rslt = set_aux_interface(config, dev); + if (rslt == BMI2_OK) + { + /* Set the auxiliary interface configurations */ + rslt = config_aux_interface(config, dev); + if (rslt == BMI2_OK) + { + /* Set read out offset and ODR */ + rslt = config_aux(config, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables auxiliary interface. + */ +static int8_t set_aux_interface(const struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data; + + rslt = bmi2_get_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + reg_data = BMI2_SET_BITS(reg_data, BMI2_AUX_IF_EN, config->aux_en); + + /* Enable/Disable auxiliary interface */ + rslt = bmi2_set_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API sets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + * + * @note Auxiliary sensor should not be busy when configuring aux_i2c_addr, + * man_rd_burst_len, aux_rd_burst_len and aux_rd_addr. + */ +static int8_t config_aux_interface(const struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data[2] = { 0 }; + + /* Variable to store status */ + uint8_t status = 0; + + /* Variable to define count */ + uint8_t count = 0; + + rslt = bmi2_get_regs(BMI2_AUX_DEV_ID_ADDR, reg_data, 2, dev); + if (rslt == BMI2_OK) + { + /* Set I2C address for AUX sensor */ + reg_data[0] = BMI2_SET_BITS(reg_data[0], BMI2_AUX_SET_I2C_ADDR, config->i2c_device_addr); + + /* Set the AUX IF to either manual or auto mode */ + reg_data[1] = BMI2_SET_BITS(reg_data[1], BMI2_AUX_MAN_MODE_EN, config->manual_en); + + /* Enables FCU write command on AUX IF for auxiliary sensors that need a trigger */ + reg_data[1] = BMI2_SET_BITS(reg_data[1], BMI2_AUX_FCU_WR_EN, config->fcu_write_en); + + /* Set the burst read length for manual mode */ + reg_data[1] = BMI2_SET_BITS(reg_data[1], BMI2_AUX_MAN_READ_BURST, config->man_rd_burst); + + /* Set the burst read length for data mode */ + reg_data[1] = BMI2_SET_BIT_POS0(reg_data[1], BMI2_AUX_READ_BURST, config->aux_rd_burst); + for (;;) + { + /* Check if auxiliary sensor is busy */ + rslt = bmi2_get_status(&status, dev); + if ((rslt == BMI2_OK) && (!(status & BMI2_AUX_BUSY))) + { + /* Set the configurations if AUX is not busy */ + rslt = bmi2_set_regs(BMI2_AUX_DEV_ID_ADDR, reg_data, 2, dev); + dev->delay_us(1000); + if (rslt == BMI2_OK) + { + /* If data mode */ + if (!config->manual_en) + { + /* Disable manual enable flag in device structure */ + dev->aux_man_en = 0; + + /* Set the read address of the AUX sensor */ + rslt = bmi2_set_regs(BMI2_AUX_RD_ADDR, (uint8_t *) &config->read_addr, 1, dev); + dev->delay_us(1000); + } + else + { + /* Enable manual enable flag in device structure */ + dev->aux_man_en = 1; + + /* Update manual read burst length in device structure */ + dev->aux_man_rd_burst_len = config->man_rd_burst; + } + } + + /* Break after setting the register */ + break; + } + + /* Increment count after every 10 seconds */ + dev->delay_us(10000); + count++; + + /* Break after 2 seconds if AUX still busy - since slowest ODR is 0.78Hz*/ + if (count > 20) + { + rslt = BMI2_E_AUX_BUSY; + break; + } + } + } + + return rslt; +} + +/*! + * @brief This internal API triggers read out offset and sets ODR of the + * auxiliary sensor. + */ +static int8_t config_aux(const struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data; + + rslt = bmi2_get_regs(BMI2_AUX_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Trigger read out offset */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_AUX_OFFSET_READ_OUT, config->offset); + + /* Set ODR */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_AUX_ODR_EN, config->odr); + + /* Set auxiliary configuration register */ + rslt = bmi2_set_regs(BMI2_AUX_CONF_ADDR, ®_data, 1, dev); + dev->delay_us(1000); + } + + return rslt; +} + +/*! + * @brief This internal API checks the busy status of auxiliary sensor and sets + * the auxiliary register addresses when not busy. + */ +static int8_t set_if_aux_not_busy(uint8_t reg_addr, uint8_t reg_data, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to get status of AUX_BUSY */ + uint8_t status = 0; + + /* Variable to define count for time-out */ + uint8_t count = 0; + + for (;;) + { + /* Check if AUX is busy */ + rslt = bmi2_get_status(&status, dev); + + /* Set the registers if not busy */ + if ((rslt == BMI2_OK) && (!(status & BMI2_AUX_BUSY))) + { + rslt = bmi2_set_regs(reg_addr, ®_data, 1, dev); + dev->delay_us(1000); + + /* Break after setting the register */ + break; + } + + /* Increment count after every 10 seconds */ + dev->delay_us(10000); + count++; + + /* Break after 2 seconds if AUX still busy - since slowest ODR is 0.78Hz*/ + if (count > 20) + { + rslt = BMI2_E_AUX_BUSY; + break; + } + } + + return rslt; +} + +/*! + * @brief This internal API validates auxiliary configuration set by the user. + */ +static int8_t validate_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate ODR for auxiliary sensor */ + rslt = check_boundary_val(&config->odr, BMI2_AUX_ODR_0_78HZ, BMI2_AUX_ODR_800HZ, dev); + + return rslt; +} + +/*! + * @brief This internal API sets any-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t set_any_motion_config(const struct bmi2_any_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define count */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for any motion */ + struct bmi2_feature_config any_mot_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for any-motion feature and extract its configuration details */ + feat_found = extract_input_feat_config(&any_mot_config, BMI2_ANY_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where any-motion feature resides */ + rslt = get_feat_config(any_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for any-motion select */ + idx = any_mot_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_DUR, config->duration); + + /* Set x-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_X_SEL, config->select_x); + + /* Set y-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Y_SEL, config->select_y); + + /* Set z-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Z_SEL, config->select_z); + + /* Increment offset by 1 word to set threshold and output configuration */ + idx++; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_THRES, config->threshold); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - any_mot_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[any_mot_config.start_addr + i] = *((uint8_t *) data_p + any_mot_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.any_mot_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets no-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t set_no_motion_config(const struct bmi2_no_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define count */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for no-motion */ + struct bmi2_feature_config no_mot_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for no-motion feature and extract its configuration details */ + feat_found = extract_input_feat_config(&no_mot_config, BMI2_NO_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where no-motion feature resides */ + rslt = get_feat_config(no_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for no-motion select */ + idx = no_mot_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_DUR, config->duration); + + /* Set x-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_X_SEL, config->select_x); + + /* Set y-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Y_SEL, config->select_y); + + /* Set z-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Z_SEL, config->select_z); + + /* Increment offset by 1 word to set threshold and output configuration */ + idx++; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_THRES, config->threshold); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - no_mot_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[no_mot_config.start_addr + i] = *((uint8_t *) data_p + no_mot_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.no_mot_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets sig-motion configurations like block-size, + * output-configuration and other parameters. + */ +static int8_t set_sig_motion_config(const struct bmi2_sig_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for sig-motion */ + struct bmi2_feature_config sig_mot_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for sig-motion feature and extract its configuration details */ + feat_found = extract_input_feat_config(&sig_mot_config, BMI2_SIG_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where sig-motion feature resides */ + rslt = get_feat_config(sig_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for sig-motion select */ + idx = sig_mot_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set parameter 1 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_1, config->block_size); + + /* Increment offset by 1 word to set parameter 2 */ + idx++; + + /* Set parameter 2 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_2, config->param_2); + + /* Increment offset by 1 word to set parameter 3 */ + idx++; + + /* Set parameter 3 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_3, config->param_3); + + /* Increment offset by 1 word to set parameter 4 */ + idx++; + + /* Set parameter 4 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_4, config->param_4); + + /* Increment offset by 1 word to set parameter 5 */ + idx++; + + /* Set parameter 5 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_5, config->param_5); + + /* Increment offset by 1 word to set output- configuration */ + idx++; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), SIG_MOT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - sig_mot_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[sig_mot_config.start_addr + i] = *((uint8_t *) data_p + sig_mot_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure for mapping */ + dev->int_map.sig_mot_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets step counter parameter configurations. + */ +static int8_t set_step_count_params_config(const uint16_t *step_count_params, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for step counter parameters */ + struct bmi2_feature_config step_params_config = { 0, 0, 0 }; + + /* Variable to index the page number */ + uint8_t page_idx; + + /* Variable to define the start page */ + uint8_t start_page; + + /* Variable to define start address of the parameters */ + uint8_t start_addr; + + /* Variable to define number of bytes */ + uint8_t n_bytes = (BMI2_STEP_CNT_N_PARAMS * 2); + + /* Variable to store number of pages */ + uint8_t n_pages = (n_bytes / 16); + + /* Variable to define the end page */ + uint8_t end_page; + + /* Variable to define the remaining bytes to be read */ + uint8_t remain_len; + + /* Variable to define the maximum words(16 bytes or 8 words) to be read in a page */ + uint8_t max_len = 8; + + /* Variable index bytes in a page */ + uint8_t page_byte_idx; + + /* Variable to index the parameters */ + uint8_t param_idx = 0; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for step counter parameter feature and extract its configuration details */ + feat_found = extract_input_feat_config(&step_params_config, BMI2_STEP_COUNTER_PARAMS, dev); + if (feat_found) + { + /* Get the start page for the step counter parameters */ + start_page = step_params_config.page; + + /* Get the end page for the step counter parameters */ + end_page = start_page + n_pages; + + /* Get the start address for the step counter parameters */ + start_addr = step_params_config.start_addr; + + /* Get the remaining length of bytes to be read */ + remain_len = (uint8_t)((n_bytes - (n_pages * 16)) + start_addr); + for (page_idx = start_page; page_idx <= end_page; page_idx++) + { + /* Get the configuration from the respective page */ + rslt = get_feat_config(page_idx, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Start from address 0x00 when switched to next page */ + if (page_idx > start_page) + { + start_addr = 0; + } + + /* Remaining number of words to be read in the page */ + if (page_idx == end_page) + { + max_len = (remain_len / 2); + } + + /* Get offset in words since all the features are set in words length */ + page_byte_idx = start_addr / 2; + for (; page_byte_idx < max_len;) + { + /* Set parameters 1 to 25 */ + *(data_p + page_byte_idx) = BMI2_SET_BIT_POS0(*(data_p + page_byte_idx), + STEP_COUNT_PARAMS, + step_count_params[param_idx]); + + /* Increment offset by 1 word to set to the next parameter */ + page_byte_idx++; + + /* Increment to next parameter */ + param_idx++; + } + + /* Get total length in bytes to copy from local pointer to the array */ + page_byte_idx = (uint8_t)(page_byte_idx * 2) - step_params_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < page_byte_idx; i++) + { + feat_config[step_params_config.start_addr + + i] = *((uint8_t *) data_p + step_params_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets step counter configurations like water-mark + * level, reset-counter and output-configuration step detector and activity. + */ +static int8_t set_step_config(const struct bmi2_step_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for step counter 4 */ + struct bmi2_feature_config step_count_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for step counter feature and extract its configuration details */ + feat_found = extract_input_feat_config(&step_count_config, BMI2_STEP_COUNTER, dev); + if (feat_found) + { + /* Get the configuration from the page where step counter resides */ + rslt = get_feat_config(step_count_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes */ + idx = step_count_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set water-mark level */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), STEP_COUNT_WM_LEVEL, config->watermark_level); + + /* Set reset-counter */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), STEP_COUNT_RST_CNT, config->reset_counter); + + /* Increment offset by 1 word to set output + * configuration of step detector and step activity + */ + idx++; + + /* Set output configuration of step-detector */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), STEP_DET_OUT_CONF, config->out_conf_step_detector); + + /* Set output configuration of step-activity */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), STEP_ACT_OUT_CONF, config->out_conf_activity); + + /* Set step buffer size */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), STEP_BUFFER_SIZE, config->step_buffer_size); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - step_count_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[step_count_config.start_addr + + i] = *((uint8_t *) data_p + step_count_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure for step-detector */ + dev->int_map.step_det_out_conf = (uint8_t) config->out_conf_step_detector; + + /* Copy out_conf value to a local copy in device structure for step-activity */ + dev->int_map.step_act_out_conf = (uint8_t) config->out_conf_activity; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + */ +static int8_t set_gyro_user_gain_config(const struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for user-gain */ + struct bmi2_feature_config user_gain_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for user-gain feature and extract its configuration details */ + feat_found = extract_input_feat_config(&user_gain_config, BMI2_GYRO_GAIN_UPDATE, dev); + if (feat_found) + { + /* Get the configuration from the page where user-gain feature resides */ + rslt = get_feat_config(user_gain_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for user-gain select */ + idx = user_gain_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set ratio_x */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), GYR_USER_GAIN_RATIO_X, config->ratio_x); + + /* Increment offset by 1 word to set ratio_y */ + idx++; + + /* Set ratio_y */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), GYR_USER_GAIN_RATIO_Y, config->ratio_y); + + /* Increment offset by 1 word to set ratio_z */ + idx++; + + /* Set ratio_z */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), GYR_USER_GAIN_RATIO_Z, config->ratio_z); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - user_gain_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[user_gain_config.start_addr + i] = *((uint8_t *) data_p + user_gain_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets tilt configurations like output-configuration. + */ +static int8_t set_tilt_config(const struct bmi2_tilt_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for tilt */ + struct bmi2_feature_config tilt_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for tilt feature and extract its configuration details */ + feat_found = extract_input_feat_config(&tilt_config, BMI2_TILT, dev); + if (feat_found) + { + /* Get the configuration from the page where tilt feature resides */ + rslt = get_feat_config(tilt_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for tilt select */ + idx = tilt_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), TILT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - tilt_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[tilt_config.start_addr + i] = *((uint8_t *) data_p + tilt_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.tilt_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets uphold to wake config configurations like output + * configuration. + */ +static int8_t set_up_hold_to_wake_config(const struct bmi2_up_hold_to_wake_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for uphold to wake */ + struct bmi2_feature_config up_hold_to_wake_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for uphold to wake feature and extract its configuration details */ + feat_found = extract_input_feat_config(&up_hold_to_wake_config, BMI2_UP_HOLD_TO_WAKE, dev); + if (feat_found) + { + /* Get the configuration from the page where uphold to wake feature resides */ + rslt = get_feat_config(up_hold_to_wake_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for uphold to wake select */ + idx = up_hold_to_wake_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), UP_HOLD_TO_WAKE_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - up_hold_to_wake_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[up_hold_to_wake_config.start_addr + + i] = *((uint8_t *) data_p + up_hold_to_wake_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.up_hold_to_wake_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets glance detector configurations like output + * configuration. + */ +static int8_t set_glance_detect_config(const struct bmi2_glance_det_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for glance detector */ + struct bmi2_feature_config glance_det_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for glance detector feature and extract its configuration details */ + feat_found = extract_input_feat_config(&glance_det_config, BMI2_GLANCE_DETECTOR, dev); + if (feat_found) + { + /* Get the configuration from the page where glance detector feature resides */ + rslt = get_feat_config(glance_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for glance detector select */ + idx = glance_det_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), GLANCE_DET_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - glance_det_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[glance_det_config.start_addr + + i] = *((uint8_t *) data_p + glance_det_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.glance_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + */ +static int8_t set_wake_up_config(const struct bmi2_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wake-up */ + struct bmi2_feature_config wake_up_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wake_up_config, BMI2_WAKE_UP, dev); + if (feat_found) + { + /* Get the configuration from the page where wake-up feature resides */ + rslt = get_feat_config(wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wake-up select */ + idx = wake_up_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set sensitivity */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WAKE_UP_SENSITIVITY, config->sensitivity); + + /* Set single/double tap enable */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WAKE_UP_SINGLE_TAP_EN, config->single_tap_en); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WAKE_UP_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - wake_up_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[wake_up_config.start_addr + i] = *((uint8_t *) data_p + wake_up_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wake_up_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + */ +static int8_t set_orient_config(const struct bmi2_orient_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for orient */ + struct bmi2_feature_config orient_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for orient feature and extract its configuration details */ + feat_found = extract_input_feat_config(&orient_config, BMI2_ORIENTATION, dev); + if (feat_found) + { + /* Get the configuration from the page where orient feature resides */ + rslt = get_feat_config(orient_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for orient select */ + idx = orient_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set upside/down detection */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_UP_DOWN, config->ud_en); + + /* Set symmetrical modes */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_SYMM_MODE, config->mode); + + /* Set blocking mode */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_BLOCK_MODE, config->blocking); + + /* Set theta */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_THETA, config->theta); + + /* Increment offset by 1 more word to set hysteresis and output configuration */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ORIENT_HYST, config->hysteresis); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - orient_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[orient_config.start_addr + i] = *((uint8_t *) data_p + orient_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.orient_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets high-g configurations like threshold, + * hysteresis, duration, and out0put configuration. + */ +static int8_t set_high_g_config(const struct bmi2_high_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for high-g */ + struct bmi2_feature_config high_g_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for high-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&high_g_config, BMI2_HIGH_G, dev); + if (feat_found) + { + /* Get the configuration from the page where high-g feature resides */ + rslt = get_feat_config(high_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for high-g select */ + idx = high_g_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), HIGH_G_THRES, config->threshold); + + /* Increment offset by 1 more word to set hysteresis */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), HIGH_G_HYST, config->hysteresis); + + /* Set x-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_X_SEL, config->select_x); + + /* Set y-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_Y_SEL, config->select_y); + + /* Set z-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_Z_SEL, config->select_z); + + /* Increment offset by 1 more word to set duration and output configuration */ + idx++; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), HIGH_G_DUR, config->duration); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - high_g_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[high_g_config.start_addr + i] = *((uint8_t *) data_p + high_g_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.high_g_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + */ +static int8_t set_low_g_config(const struct bmi2_low_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for low-g */ + struct bmi2_feature_config low_g_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for low-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&low_g_config, BMI2_LOW_G, dev); + if (feat_found) + { + /* Get the configuration from the page where low-g feature resides */ + rslt = get_feat_config(low_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for low-g select */ + idx = low_g_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), LOW_G_THRES, config->threshold); + + /* Increment offset by 1 more word to set hysteresis */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), LOW_G_HYST, config->hysteresis); + + /* Increment offset by 1 more word to set duration and output configuration */ + idx++; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), LOW_G_DUR, config->duration); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), LOW_G_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - low_g_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[low_g_config.start_addr + i] = *((uint8_t *) data_p + low_g_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.low_g_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + */ +static int8_t set_flat_config(const struct bmi2_flat_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for flat */ + struct bmi2_feature_config flat_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for flat feature and extract its configuration details */ + feat_found = extract_input_feat_config(&flat_config, BMI2_FLAT, dev); + if (feat_found) + { + /* Get the configuration from the page where flat feature resides */ + rslt = get_feat_config(flat_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for flat select */ + idx = flat_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set theta */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_THETA, config->theta); + + /* Set blocking */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_BLOCK, config->blocking); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to set hysteresis and hold-time */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), FLAT_HYST, config->hysteresis); + + /* Set hold-time */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_HOLD_TIME, config->hold_time); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - flat_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[flat_config.start_addr + i] = *((uint8_t *) data_p + flat_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.flat_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets external sensor sync configurations like output + * configuration. + */ +static int8_t set_ext_sens_sync_config(const struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for external sensor sync */ + struct bmi2_feature_config ext_sens_sync_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for external sensor sync feature and extract its configuration details */ + feat_found = extract_input_feat_config(&ext_sens_sync_config, BMI2_EXT_SENS_SYNC, dev); + if (feat_found) + { + /* Get the configuration from the page where external sensor sync feature resides */ + rslt = get_feat_config(ext_sens_sync_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for external sensor sync select */ + idx = ext_sens_sync_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), EXT_SENS_SYNC_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - ext_sens_sync_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[ext_sens_sync_config.start_addr + + i] = *((uint8_t *) data_p + ext_sens_sync_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.ext_sync_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wrist gesture configurations like wearable-arm, + * and output-configuration. + */ +static int8_t set_wrist_gest_config(const struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist gesture feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_gest_config, BMI2_WRIST_GESTURE, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist gesture feature resides */ + rslt = get_feat_config(wrist_gest_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for gesture select */ + idx = wrist_gest_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set wearable arm */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_GEST_WEAR_ARM, config->wearable_arm); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), WRIST_GEST_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to set minimum tilt angle (min_flick_peak) */ + idx++; + *(data_p + idx) = config->min_flick_peak; + + /* Increment offset by 1 more word to set min_flick_samples */ + idx++; + *(data_p + idx) = config->min_flick_samples; + + /* Increment offset by 1 more word to set max time within gesture moment has to be completed */ + idx++; + *(data_p + idx) = config->max_duration; + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - wrist_gest_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[wrist_gest_config.start_addr + + i] = *((uint8_t *) data_p + wrist_gest_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_gest_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wrist wear wake-up configurations like + * output-configuration. + */ +static int8_t set_wrist_wear_wake_up_config(const struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist wear wake-up */ + struct bmi2_feature_config wrist_wake_up_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist wear wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_wake_up_config, BMI2_WRIST_WEAR_WAKE_UP, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist wear wake-up feature resides */ + rslt = get_feat_config(wrist_wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wrist wear wake-up select */ + idx = wrist_wake_up_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to set min_angle_focus */ + idx++; + *(data_p + idx) = config->min_angle_focus; + + /* Increment offset by 1 more word to set min_angle_nonfocus */ + idx++; + *(data_p + idx) = config->min_angle_nonfocus; + + /* Increment offset by 1 more word to set max_tilt_lr */ + idx++; + *(data_p + idx) = config->max_tilt_lr; + + /* Increment offset by 1 more word to set max_tilt_ll */ + idx++; + *(data_p + idx) = config->max_tilt_ll; + + /* Increment offset by 1 more word to set max_tilt_pd */ + idx++; + *(data_p + idx) = config->max_tilt_pd; + + /* Increment offset by 1 more word to set max_tilt_pu */ + idx++; + *(data_p + idx) = config->max_tilt_pu; + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - wrist_wake_up_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[wrist_wake_up_config.start_addr + + i] = *((uint8_t *) data_p + wrist_wake_up_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_wear_wake_up_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wrist gesture configurations like wearable-arm, + * and output-configuration for wearable variant. + */ +static int8_t set_wrist_gest_w_config(const struct bmi2_wrist_gest_w_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist gesture feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_gest_config, BMI2_WRIST_GESTURE_WH, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist gesture feature resides */ + rslt = get_feat_config(wrist_gest_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for gesture select */ + idx = wrist_gest_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set wearable arm */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_GEST_WEAR_ARM, config->wearable_arm); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), WRIST_GEST_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to set minimum tilt angle (min_flick_peak) */ + idx++; + *(data_p + idx) = config->min_flick_peak; + + /* Increment offset by 1 more word to set min_flick_samples */ + idx++; + *(data_p + idx) = config->min_flick_samples; + + /* Increment offset by 1 more word to set max time within gesture moment has to be completed */ + idx++; + *(data_p + idx) = config->max_duration; + + /* Increment offset by 1 more word to set reporting delay */ + idx++; + *(data_p + idx) = config->reporting_delay; + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - wrist_gest_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[wrist_gest_config.start_addr + + i] = *((uint8_t *) data_p + wrist_gest_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_gest_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wrist wear wake-up configurations like + * output-configuration for wearable variant. + */ +static int8_t set_wrist_wear_wake_up_wh_config(const struct bmi2_wrist_wear_wake_up_wh_config *config, + struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist wear wake-up */ + struct bmi2_feature_config wrist_wake_up_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist wear wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_wake_up_config, BMI2_WRIST_WEAR_WAKE_UP_WH, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist wear wake-up feature resides */ + rslt = get_feat_config(wrist_wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wrist wear wake-up select */ + idx = wrist_wake_up_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to set min_angle_focus */ + idx++; + *(data_p + idx) = config->min_angle_focus; + + /* Increment offset by 1 more word to set min_angle_nonfocus */ + idx++; + *(data_p + idx) = config->min_angle_nonfocus; + + /* Increment offset by 1 more word to set angle landscape right and angle landscape left */ + idx++; + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_ANGLE_LR, config->angle_lr); + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_WAKE_UP_ANGLE_LL, config->angle_ll); + + /* Increment offset by 1 more word to set angle portrait down and angle portrait left */ + idx++; + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_ANGLE_PD, config->angle_pd); + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_WAKE_UP_ANGLE_PU, config->angle_pu); + + /* Increment offset by 1 more word to set min duration moved and min duration quite */ + idx++; + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_MIN_DUR_MOVED, config->min_dur_mov); + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_WAKE_UP_MIN_DUR_QUITE, config->min_dur_quite); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - wrist_wake_up_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[wrist_wake_up_config.start_addr + + i] = *((uint8_t *) data_p + wrist_wake_up_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_wear_wake_up_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets accelerometer configurations like ODR, + * bandwidth, performance mode and g-range. + */ +static int8_t get_accel_config(struct bmi2_accel_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store data */ + uint8_t data_array[2] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (config != NULL)) + { + /* Read the sensor configuration details */ + rslt = bmi2_get_regs(BMI2_ACC_CONF_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) + { + /* Get accelerometer performance mode */ + config->filter_perf = BMI2_GET_BITS(data_array[0], BMI2_ACC_FILTER_PERF_MODE); + + /* Get accelerometer bandwidth */ + config->bwp = BMI2_GET_BITS(data_array[0], BMI2_ACC_BW_PARAM); + + /* Get accelerometer ODR */ + config->odr = BMI2_GET_BIT_POS0(data_array[0], BMI2_ACC_ODR); + + /* Get accelerometer range */ + config->range = BMI2_GET_BIT_POS0(data_array[1], BMI2_ACC_RANGE); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API gets gyroscope configurations like ODR, bandwidth, + * low power/high performance mode, performance mode and range. + */ +static int8_t get_gyro_config(struct bmi2_gyro_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store data */ + uint8_t data_array[2] = { 0 }; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (config != NULL)) + { + /* Read the sensor configuration details */ + rslt = bmi2_get_regs(BMI2_GYR_CONF_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) + { + /* Get gyroscope performance mode */ + config->filter_perf = BMI2_GET_BITS(data_array[0], BMI2_GYR_FILTER_PERF_MODE); + + /* Get gyroscope noise performance mode */ + config->noise_perf = BMI2_GET_BITS(data_array[0], BMI2_GYR_NOISE_PERF_MODE); + + /* Get gyroscope bandwidth */ + config->bwp = BMI2_GET_BITS(data_array[0], BMI2_GYR_BW_PARAM); + + /* Get gyroscope ODR */ + config->odr = BMI2_GET_BIT_POS0(data_array[0], BMI2_GYR_ODR); + + /* Get gyroscope OIS range */ + config->ois_range = BMI2_GET_BITS(data_array[1], BMI2_GYR_OIS_RANGE); + + /* Get gyroscope range */ + config->range = BMI2_GET_BIT_POS0(data_array[1], BMI2_GYR_RANGE); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API: + * 1) Gets the status of auxiliary interface enable. + * 2) Gets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3) Gets ODR and offset. + */ +static int8_t get_aux_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (config != NULL)) + { + /* Get enable status of auxiliary interface */ + rslt = get_aux_interface(config, dev); + if (rslt == BMI2_OK) + { + /* Get the auxiliary interface configurations */ + rslt = get_aux_interface_config(config, dev); + if (rslt == BMI2_OK) + { + /* Get read out offset and ODR */ + rslt = get_aux_cfg(config, dev); + } + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the enable status of auxiliary interface. + */ +static int8_t get_aux_interface(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data; + + /* Get the enable status of auxiliary interface */ + rslt = bmi2_get_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + config->aux_en = BMI2_GET_BITS(reg_data, BMI2_AUX_IF_EN); + } + + return rslt; +} + +/*! + * @brief This internal API gets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + */ +static int8_t get_aux_interface_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data[2] = { 0 }; + + rslt = bmi2_get_regs(BMI2_AUX_DEV_ID_ADDR, reg_data, 2, dev); + if (rslt == BMI2_OK) + { + /* Get I2C address for auxiliary sensor */ + config->i2c_device_addr = BMI2_GET_BITS(reg_data[0], BMI2_AUX_SET_I2C_ADDR); + + /* Get the AUX IF to either manual or auto mode */ + config->manual_en = BMI2_GET_BITS(reg_data[1], BMI2_AUX_MAN_MODE_EN); + + /* Enables FCU write command on AUX IF for auxiliary sensors that need a trigger */ + config->fcu_write_en = BMI2_GET_BITS(reg_data[1], BMI2_AUX_FCU_WR_EN); + + /* Get the burst read length for manual mode */ + config->man_rd_burst = BMI2_GET_BITS(reg_data[1], BMI2_AUX_MAN_READ_BURST); + + /* Get the burst read length for data mode */ + config->aux_rd_burst = BMI2_GET_BIT_POS0(reg_data[1], BMI2_AUX_READ_BURST); + + /* If data mode, get the read address of the auxiliary sensor from where data is to be read */ + if (!config->manual_en) + { + rslt = bmi2_get_regs(BMI2_AUX_RD_ADDR, &config->read_addr, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API gets read out offset and ODR of the auxiliary + * sensor. + */ +static int8_t get_aux_cfg(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t reg_data; + + rslt = bmi2_get_regs(BMI2_AUX_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Get read out offset */ + config->offset = BMI2_GET_BITS(reg_data, BMI2_AUX_OFFSET_READ_OUT); + + /* Get ODR */ + config->odr = BMI2_GET_BIT_POS0(reg_data, BMI2_AUX_ODR_EN); + } + + return rslt; +} + +/*! + * @brief This internal API gets any-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t get_any_motion_config(struct bmi2_any_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb; + + /* Variable to define MSB */ + uint16_t msb; + + /* Variable to define a word */ + uint16_t lsb_msb; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for any-motion */ + struct bmi2_feature_config any_mot_config = { 0, 0, 0 }; + + /* Search for any-motion feature and extract its configuration details */ + feat_found = extract_input_feat_config(&any_mot_config, BMI2_ANY_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where any-motion feature resides */ + rslt = get_feat_config(any_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for feature enable for any-motion */ + idx = any_mot_config.start_addr; + + /* Get word to calculate duration, x, y and z select */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & ANY_NO_MOT_DUR_MASK; + + /* Get x-select */ + config->select_x = (lsb_msb & ANY_NO_MOT_X_SEL_MASK) >> ANY_NO_MOT_X_SEL_POS; + + /* Get y-select */ + config->select_y = (lsb_msb & ANY_NO_MOT_Y_SEL_MASK) >> ANY_NO_MOT_Y_SEL_POS; + + /* Get z-select */ + config->select_z = (lsb_msb & ANY_NO_MOT_Z_SEL_MASK) >> ANY_NO_MOT_Z_SEL_POS; + + /* Get word to calculate threshold, output configuration from the same word */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & ANY_NO_MOT_THRES_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & ANY_NO_MOT_OUT_CONF_MASK) >> ANY_NO_MOT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.any_mot_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets no-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t get_no_motion_config(struct bmi2_no_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for no-motion */ + struct bmi2_feature_config no_mot_config = { 0, 0, 0 }; + + /* Search for no-motion feature and extract its configuration details */ + feat_found = extract_input_feat_config(&no_mot_config, BMI2_NO_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where no-motion feature resides */ + rslt = get_feat_config(no_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for feature enable for no-motion */ + idx = no_mot_config.start_addr; + + /* Get word to calculate duration, x, y and z select */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & ANY_NO_MOT_DUR_MASK; + + /* Get x-select */ + config->select_x = (lsb_msb & ANY_NO_MOT_X_SEL_MASK) >> ANY_NO_MOT_X_SEL_POS; + + /* Get y-select */ + config->select_y = (lsb_msb & ANY_NO_MOT_Y_SEL_MASK) >> ANY_NO_MOT_Y_SEL_POS; + + /* Get z-select */ + config->select_z = (lsb_msb & ANY_NO_MOT_Z_SEL_MASK) >> ANY_NO_MOT_Z_SEL_POS; + + /* Get word to calculate threshold, output configuration from the same word */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & ANY_NO_MOT_THRES_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & ANY_NO_MOT_OUT_CONF_MASK) >> ANY_NO_MOT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.no_mot_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets sig-motion configurations like block-size, + * output-configuration and other parameters. + */ +static int8_t get_sig_motion_config(struct bmi2_sig_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration sig-motion */ + struct bmi2_feature_config sig_mot_config = { 0, 0, 0 }; + + /* Search for sig-motion feature and extract its configuration details */ + feat_found = extract_input_feat_config(&sig_mot_config, BMI2_SIG_MOTION, dev); + if (feat_found) + { + /* Get the configuration from the page where sig-motion feature resides */ + rslt = get_feat_config(sig_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for feature enable for sig-motion */ + idx = sig_mot_config.start_addr; + + /* Get word to calculate parameter 1 */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 1 */ + config->block_size = lsb_msb & SIG_MOT_PARAM_1_MASK; + + /* Get word to calculate parameter 2 */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 2 */ + config->param_2 = lsb_msb & SIG_MOT_PARAM_2_MASK; + + /* Get word to calculate parameter 3 */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 3 */ + config->param_3 = lsb_msb & SIG_MOT_PARAM_3_MASK; + + /* Get word to calculate parameter 4 */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 4 */ + config->param_4 = lsb_msb & SIG_MOT_PARAM_4_MASK; + + /* Get word to calculate parameter 5 */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 5 */ + config->param_5 = lsb_msb & SIG_MOT_PARAM_5_MASK; + + /* Get word to calculate and output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & SIG_MOT_OUT_CONF_MASK) >> SIG_MOT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.sig_mot_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets step counter parameter configurations. + */ +static int8_t get_step_count_params_config(uint16_t *step_count_params, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Initialize feature configuration for step counter 1 */ + struct bmi2_feature_config step_params_config = { 0, 0, 0 }; + + /* Variable to index the page number */ + uint8_t page_idx; + + /* Variable to define the start page */ + uint8_t start_page; + + /* Variable to define start address of the parameters */ + uint8_t start_addr; + + /* Variable to define number of bytes */ + uint8_t n_bytes = (BMI2_STEP_CNT_N_PARAMS * 2); + + /* Variable to store number of pages */ + uint8_t n_pages = (n_bytes / 16); + + /* Variable to define the end page */ + uint8_t end_page; + + /* Variable to define the remaining bytes to be read */ + uint8_t remain_len; + + /* Variable to define the maximum words to be read in a page */ + uint8_t max_len = BMI2_FEAT_SIZE_IN_BYTES; + + /* Variable index bytes in a page */ + uint8_t page_byte_idx; + + /* Variable to index the parameters */ + uint8_t param_idx = 0; + + /* Search for step counter parameter feature and extract its configuration details */ + feat_found = extract_input_feat_config(&step_params_config, BMI2_STEP_COUNTER_PARAMS, dev); + if (feat_found) + { + /* Get the start page for the step counter parameters */ + start_page = step_params_config.page; + + /* Get the end page for the step counter parameters */ + end_page = start_page + n_pages; + + /* Get the start address for the step counter parameters */ + start_addr = step_params_config.start_addr; + + /* Get the remaining length of bytes to be read */ + remain_len = (uint8_t)((n_bytes - (n_pages * 16)) + start_addr); + for (page_idx = start_page; page_idx <= end_page; page_idx++) + { + /* Get the configuration from the respective page */ + rslt = get_feat_config(page_idx, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Start from address 0x00 when switched to next page */ + if (page_idx > start_page) + { + start_addr = 0; + } + + /* Remaining number of bytes to be read in the page */ + if (page_idx == end_page) + { + max_len = remain_len; + } + + /* Get the offset */ + page_byte_idx = start_addr; + while (page_byte_idx < max_len) + { + /* Get word to calculate the parameter*/ + lsb = (uint16_t) feat_config[page_byte_idx++]; + if (page_byte_idx < max_len) + { + msb = ((uint16_t) feat_config[page_byte_idx++] << 8); + } + lsb_msb = lsb | msb; + + /* Get parameters 1 to 25 */ + step_count_params[param_idx] = lsb_msb & STEP_COUNT_PARAMS_MASK; + + /* Increment to next parameter */ + param_idx++; + } + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets step counter/detector/activity configurations. + */ +static int8_t get_step_config(struct bmi2_step_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for step counter */ + struct bmi2_feature_config step_count_config = { 0, 0, 0 }; + + /* Search for step counter 4 feature and extract its configuration details */ + feat_found = extract_input_feat_config(&step_count_config, BMI2_STEP_COUNTER, dev); + if (feat_found) + { + /* Get the configuration from the page where step counter 4 parameter resides */ + rslt = get_feat_config(step_count_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for feature enable for step counter/detector/activity */ + idx = step_count_config.start_addr; + + /* Get word to calculate water-mark level and reset counter */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get water-mark level */ + config->watermark_level = lsb_msb & STEP_COUNT_WM_LEVEL_MASK; + + /* Get reset counter */ + config->reset_counter = (lsb_msb & STEP_COUNT_RST_CNT_MASK) >> STEP_COUNT_RST_CNT_POS; + + /* Get word to calculate output configuration of step detector and activity */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration of step detector */ + config->out_conf_step_detector = lsb_msb & STEP_DET_OUT_CONF_MASK; + + /* Get output configuration of step activity */ + config->out_conf_activity = (lsb_msb & STEP_ACT_OUT_CONF_MASK) >> STEP_ACT_OUT_CONF_POS; + + /* Get step buffer size */ + config->step_buffer_size = (lsb_msb & STEP_BUFFER_SIZE_MASK) >> STEP_BUFFER_SIZE_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.step_det_out_conf = (uint8_t) config->out_conf_step_detector; + dev->int_map.step_act_out_conf = (uint8_t) config->out_conf_activity; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + */ +static int8_t get_gyro_gain_update_config(struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for user-gain */ + struct bmi2_feature_config user_gain_config = { 0, 0, 0 }; + + /* Search for user-gain feature and extract its configuration details */ + feat_found = extract_input_feat_config(&user_gain_config, BMI2_GYRO_GAIN_UPDATE, dev); + if (feat_found) + { + /* Get the configuration from the page where user-gain feature resides */ + rslt = get_feat_config(user_gain_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for user-gain select */ + idx = user_gain_config.start_addr; + + /* Get word to calculate ratio_x */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get ratio_x */ + config->ratio_x = lsb_msb & GYR_USER_GAIN_RATIO_X_MASK; + + /* Get word to calculate ratio_y */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get ratio_y */ + config->ratio_y = lsb_msb & GYR_USER_GAIN_RATIO_Y_MASK; + + /* Get word to calculate ratio_z */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get ratio_z */ + config->ratio_z = lsb_msb & GYR_USER_GAIN_RATIO_Z_MASK; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets tilt configurations like output-configuration. + */ +static int8_t get_tilt_config(struct bmi2_tilt_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for tilt */ + struct bmi2_feature_config tilt_config = { 0, 0, 0 }; + + /* Search for tilt feature and extract its configuration details */ + feat_found = extract_input_feat_config(&tilt_config, BMI2_TILT, dev); + if (feat_found) + { + /* Get the configuration from the page where tilt feature resides */ + rslt = get_feat_config(tilt_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for tilt select */ + idx = tilt_config.start_addr; + + /* Get word to calculate threshold and output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & TILT_OUT_CONF_MASK) >> TILT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.tilt_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets uphold to wake configurations like output + * configuration. + */ +static int8_t get_up_hold_to_wake_config(struct bmi2_up_hold_to_wake_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for uphold to wake */ + struct bmi2_feature_config up_hold_to_wake_config = { 0, 0, 0 }; + + /* Search for uphold to wake feature and extract its configuration details */ + feat_found = extract_input_feat_config(&up_hold_to_wake_config, BMI2_UP_HOLD_TO_WAKE, dev); + if (feat_found) + { + /* Get the configuration from the page where uphold to wake feature resides */ + rslt = get_feat_config(up_hold_to_wake_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for uphold to wake select */ + idx = up_hold_to_wake_config.start_addr; + + /* Get word to calculate output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & UP_HOLD_TO_WAKE_OUT_CONF_MASK) >> UP_HOLD_TO_WAKE_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.up_hold_to_wake_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets glance detector configurations like output + * configuration. + */ +static int8_t get_glance_detect_config(struct bmi2_glance_det_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for glance detector */ + struct bmi2_feature_config glance_det_config = { 0, 0, 0 }; + + /* Search for glance detector feature and extract its configuration details */ + feat_found = extract_input_feat_config(&glance_det_config, BMI2_GLANCE_DETECTOR, dev); + if (feat_found) + { + /* Get the configuration from the page where glance detector feature resides */ + rslt = get_feat_config(glance_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for glance detector select */ + idx = glance_det_config.start_addr; + + /* Get word to calculate output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & GLANCE_DET_OUT_CONF_MASK) >> GLANCE_DET_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.glance_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + */ +static int8_t get_wake_up_config(struct bmi2_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wake-up */ + struct bmi2_feature_config wake_up_config = { 0, 0, 0 }; + + /* Search for wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wake_up_config, BMI2_WAKE_UP, dev); + if (feat_found) + { + /* Get the configuration from the page where wake-up feature resides */ + rslt = get_feat_config(wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wake-up select */ + idx = wake_up_config.start_addr; + + /* Get word to calculate sensitivity, single/double tap + * enable and output configuration + */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get sensitivity */ + config->sensitivity = (lsb_msb & WAKE_UP_SENSITIVITY_MASK) >> WAKE_UP_SENSITIVITY_POS; + + /* Get single/double tap enable */ + config->single_tap_en = (lsb_msb & WAKE_UP_SINGLE_TAP_EN_MASK) >> WAKE_UP_SINGLE_TAP_EN_POS; + + /* Get output configuration */ + config->out_conf = (lsb_msb & WAKE_UP_OUT_CONF_MASK) >> WAKE_UP_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wake_up_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wrist gesture configurations like wearable-arm, + * and output-configuration. + */ +static int8_t get_wrist_gest_config(struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist gesture feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_gest_config, BMI2_WRIST_GESTURE, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist gesture feature resides */ + rslt = get_feat_config(wrist_gest_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wrist gesture select */ + idx = wrist_gest_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Get wearable arm */ + config->wearable_arm = (*(data_p + idx) & WRIST_GEST_WEAR_ARM_MASK) >> WRIST_GEST_WEAR_ARM_POS; + + /* Get output configuration */ + config->out_conf = BMI2_GET_BIT_POS0(*(data_p + idx), WRIST_GEST_OUT_CONF); + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_gest_out_conf = (uint8_t) config->out_conf; + + /* Increment the offset by 1 word to get min_flick_peak */ + idx++; + config->min_flick_peak = *(data_p + idx); + + /* Increment the offset by 1 word to get min_flick_samples */ + idx++; + config->min_flick_samples = *(data_p + idx); + + /* Increment the offset by 1 word to get max_duration */ + idx++; + config->max_duration = *(data_p + idx); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wrist wear wake-up configurations like + * output-configuration. + */ +static int8_t get_wrist_wear_wake_up_config(struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist wear wake-up */ + struct bmi2_feature_config wrist_wake_up_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist wear wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_wake_up_config, BMI2_WRIST_WEAR_WAKE_UP, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist wear wake-up feature resides */ + rslt = get_feat_config(wrist_wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wrist wear wake-up select */ + idx = wrist_wake_up_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Get output configuration */ + config->out_conf = BMI2_GET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_OUT_CONF); + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_wear_wake_up_out_conf = (uint8_t) config->out_conf; + + /* Increment the offset value by 1 word to get min_angle_focus */ + idx++; + config->min_angle_focus = *(data_p + idx); + + /* Increment the offset value by 1 word to get min_angle_nonfocus */ + idx++; + config->min_angle_nonfocus = *(data_p + idx); + + /* Increment the offset value by 1 word to get max_tilt_lr */ + idx++; + config->max_tilt_lr = *(data_p + idx); + + /* Increment the offset value by 1 word to get max_tilt_ll */ + idx++; + config->max_tilt_ll = *(data_p + idx); + + /* Increment the offset value by 1 word to get max_tilt_pd */ + idx++; + config->max_tilt_pd = *(data_p + idx); + + /* Increment the offset value by 1 word to get max_tilt_pu */ + idx++; + config->max_tilt_pu = *(data_p + idx); + + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wrist gesture configurations like wearable-arm, + * and output-configuration for wearable variant. + */ +static int8_t get_wrist_gest_w_config(struct bmi2_wrist_gest_w_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist gesture feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_gest_config, BMI2_WRIST_GESTURE_WH, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist gesture feature resides */ + rslt = get_feat_config(wrist_gest_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wrist gesture select */ + idx = wrist_gest_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Get wearable arm */ + config->wearable_arm = (*(data_p + idx) & WRIST_GEST_WEAR_ARM_MASK) >> WRIST_GEST_WEAR_ARM_POS; + + /* Get output configuration */ + config->out_conf = BMI2_GET_BIT_POS0(*(data_p + idx), WRIST_GEST_OUT_CONF); + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_gest_out_conf = (uint8_t) config->out_conf; + + /* Increment the offset by 1 word to get min_flick_peak */ + idx++; + config->min_flick_peak = *(data_p + idx); + + /* Increment the offset by 1 word to get min_flick_samples */ + idx++; + config->min_flick_samples = *(data_p + idx); + + /* Increment the offset by 1 word to get max_duration */ + idx++; + config->max_duration = *(data_p + idx); + + /* Increment the offset by 1 word to get reporting delay */ + idx++; + config->reporting_delay = *(data_p + idx); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wrist wear wake-up configurations like + * output-configuration for wearable variant. + */ +static int8_t get_wrist_wear_wake_up_wh_config(struct bmi2_wrist_wear_wake_up_wh_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist wear wake-up */ + struct bmi2_feature_config wrist_wake_up_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for wrist wear wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_wake_up_config, BMI2_WRIST_WEAR_WAKE_UP_WH, dev); + if (feat_found) + { + /* Get the configuration from the page where wrist wear wake-up feature resides */ + rslt = get_feat_config(wrist_wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wrist wear wake-up select */ + idx = wrist_wake_up_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Get output configuration */ + config->out_conf = BMI2_GET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_OUT_CONF); + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.wrist_wear_wake_up_out_conf = (uint8_t) config->out_conf; + + /* Increment the offset value by 1 word to get min_angle_focus */ + idx++; + config->min_angle_focus = *(data_p + idx); + + /* Increment the offset value by 1 word to get min_angle_nonfocus */ + idx++; + config->min_angle_nonfocus = *(data_p + idx); + + /* Increment the offset value by 1 word to get angle landscape right and angle landscape left */ + idx++; + config->angle_lr = BMI2_GET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_ANGLE_LR); + config->angle_ll = BMI2_GET_BITS(*(data_p + idx), WRIST_WAKE_UP_ANGLE_LL); + + /* Increment the offset value by 1 word to get angle portrait down and angle portrait up */ + idx++; + config->angle_pd = BMI2_GET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_ANGLE_PD); + config->angle_pu = BMI2_GET_BITS(*(data_p + idx), WRIST_WAKE_UP_ANGLE_PU); + + /* Increment the offset value by 1 word to get min duration quite and min duration moved */ + idx++; + config->min_dur_mov = BMI2_GET_BIT_POS0(*(data_p + idx), WRIST_WAKE_UP_MIN_DUR_MOVED); + config->min_dur_quite = BMI2_GET_BITS(*(data_p + idx), WRIST_WAKE_UP_MIN_DUR_QUITE); + + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + */ +static int8_t get_orient_config(struct bmi2_orient_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for orient */ + struct bmi2_feature_config orient_config = { 0, 0, 0 }; + + /* Search for orient feature and extract its configuration details */ + feat_found = extract_input_feat_config(&orient_config, BMI2_ORIENTATION, dev); + if (feat_found) + { + /* Get the configuration from the page where orient feature resides */ + rslt = get_feat_config(orient_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for orient select */ + idx = orient_config.start_addr; + + /* Get word to calculate upside/down detection, + * symmetrical modes, blocking mode and theta + */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get upside/down detection */ + config->ud_en = (lsb_msb & ORIENT_UP_DOWN_MASK) >> ORIENT_UP_DOWN_POS; + + /* Get symmetrical modes */ + config->mode = (lsb_msb & ORIENT_SYMM_MODE_MASK) >> ORIENT_SYMM_MODE_POS; + + /* Get blocking mode */ + config->blocking = (lsb_msb & ORIENT_BLOCK_MODE_MASK) >> ORIENT_BLOCK_MODE_POS; + + /* Get theta */ + config->theta = (lsb_msb & ORIENT_THETA_MASK) >> ORIENT_THETA_POS; + + /* Get the next word to calculate hysteresis and output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & ORIENT_HYST_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & ORIENT_OUT_CONF_MASK) >> ORIENT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.orient_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets high-g configurations like threshold, + * hysteresis, duration, and output configuration. + */ +static int8_t get_high_g_config(struct bmi2_high_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for high-g */ + struct bmi2_feature_config high_g_config = { 0, 0, 0 }; + + /* Search for high-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&high_g_config, BMI2_HIGH_G, dev); + if (feat_found) + { + /* Get the configuration from the page where high-g feature resides */ + rslt = get_feat_config(high_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for high-g select */ + idx = high_g_config.start_addr; + + /* Get word to calculate threshold */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & HIGH_G_THRES_MASK; + + /* Get word to calculate hysteresis */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & HIGH_G_HYST_MASK; + + /* Get x_select */ + config->select_x = (lsb_msb & HIGH_G_X_SEL_MASK) >> HIGH_G_X_SEL_POS; + + /* Get y_select */ + config->select_y = (lsb_msb & HIGH_G_Y_SEL_MASK) >> HIGH_G_Y_SEL_POS; + + /* Get z_select */ + config->select_z = (lsb_msb & HIGH_G_Z_SEL_MASK) >> HIGH_G_Z_SEL_POS; + + /* Get word to calculate duration and output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & HIGH_G_DUR_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & HIGH_G_OUT_CONF_MASK) >> HIGH_G_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.high_g_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + */ +static int8_t get_low_g_config(struct bmi2_low_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for low-g */ + struct bmi2_feature_config low_g_config = { 0, 0, 0 }; + + /* Search for low-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&low_g_config, BMI2_LOW_G, dev); + if (feat_found) + { + /* Get the configuration from the page where low-g feature resides */ + rslt = get_feat_config(low_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for low-g select */ + idx = low_g_config.start_addr; + + /* Get word to calculate threshold */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & LOW_G_THRES_MASK; + + /* Get word to calculate hysteresis */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & LOW_G_HYST_MASK; + + /* Get word to calculate duration and output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & LOW_G_DUR_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & LOW_G_OUT_CONF_MASK) >> LOW_G_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.low_g_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + */ +static int8_t get_flat_config(struct bmi2_flat_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for flat */ + struct bmi2_feature_config flat_config = { 0, 0, 0 }; + + /* Search for flat feature and extract its configuration details */ + feat_found = extract_input_feat_config(&flat_config, BMI2_FLAT, dev); + if (feat_found) + { + /* Get the configuration from the page where flat feature resides */ + rslt = get_feat_config(flat_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for flat select */ + idx = flat_config.start_addr; + + /* Get word to calculate theta, blocking mode and output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get theta */ + config->theta = (lsb_msb & FLAT_THETA_MASK) >> FLAT_THETA_POS; + + /* Get blocking mode */ + config->blocking = (lsb_msb & FLAT_BLOCK_MASK) >> FLAT_BLOCK_POS; + + /* Get output configuration */ + config->out_conf = (lsb_msb & FLAT_OUT_CONF_MASK) >> FLAT_OUT_CONF_POS; + + /* Get word to calculate hysteresis and hold-time */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & FLAT_HYST_MASK; + + /* Get hold-time */ + config->hold_time = (lsb_msb & FLAT_HOLD_TIME_MASK) >> FLAT_HOLD_TIME_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.flat_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets external sensor sync configurations like output + * configuration. + */ +static int8_t get_ext_sens_sync_config(struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for external sensor sync */ + struct bmi2_feature_config ext_sens_sync_config = { 0, 0, 0 }; + + /* Search for external sensor sync feature and extract its configuration details */ + feat_found = extract_input_feat_config(&ext_sens_sync_config, BMI2_EXT_SENS_SYNC, dev); + if (feat_found) + { + /* Get the configuration from the page where external sensor sync feature resides */ + rslt = get_feat_config(ext_sens_sync_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for external sensor sync select */ + idx = ext_sens_sync_config.start_addr; + + /* Get word to calculate output configuration */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & EXT_SENS_SYNC_OUT_CONF_MASK) >> EXT_SENS_SYNC_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.ext_sync_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API maps/un-maps feature interrupts to that of interrupt + * pins. + */ +static int8_t map_feat_int(uint8_t *reg_data_array, enum bmi2_hw_int_pin int_pin, uint8_t int_mask) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Check for NULL error */ + if (reg_data_array != NULL) + { + /* Check validity on interrupt pin selection */ + if (int_pin < BMI2_INT_PIN_MAX) + { + switch (int_pin) + { + case BMI2_INT_NONE: + + /* Un-Map the corresponding feature interrupt to interrupt pin 1 and 2 */ + reg_data_array[0] &= ~(int_mask); + reg_data_array[1] &= ~(int_mask); + break; + case BMI2_INT1: + + /* Map the corresponding feature interrupt to interrupt pin 1 */ + reg_data_array[0] |= int_mask; + + /* Un-map the corresponding feature interrupt to interrupt pin 2 */ + reg_data_array[1] &= ~(int_mask); + break; + case BMI2_INT2: + + /* Map the corresponding feature interrupt to interrupt pin 2 */ + reg_data_array[1] |= int_mask; + + /* Un-map the corresponding feature interrupt to interrupt pin 1 */ + reg_data_array[0] &= ~(int_mask); + break; + case BMI2_INT_BOTH: + + /* Map the corresponding feature interrupt to interrupt pin 1 and 2 */ + reg_data_array[0] |= int_mask; + reg_data_array[1] |= int_mask; + break; + default: + break; + } + } + else + { + /* Return error if invalid pin selection */ + rslt = BMI2_E_INVALID_INT_PIN; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the accelerometer data from the register. + */ +static int8_t get_accel_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define data stored in register */ + uint8_t reg_data[BMI2_ACC_GYR_NUM_BYTES] = { 0 }; + + /* Read the sensor data */ + rslt = bmi2_get_regs(reg_addr, reg_data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Get accelerometer data from the register */ + get_acc_gyr_data(data, reg_data); + + /* Get the re-mapped accelerometer data */ + get_remapped_data(data, dev); + } + + return rslt; +} + +/*! + * @brief This internal API gets the gyroscope data from the register. + */ +static int8_t get_gyro_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define data stored in register */ + uint8_t reg_data[BMI2_ACC_GYR_NUM_BYTES] = { 0 }; + + /* Read the sensor data */ + rslt = bmi2_get_regs(reg_addr, reg_data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Get gyroscope data from the register */ + get_acc_gyr_data(data, reg_data); + + /* Get the compensated gyroscope data */ + comp_gyro_cross_axis_sensitivity(data, dev); + + /* Get the re-mapped gyroscope data */ + get_remapped_data(data, dev); + + } + + return rslt; +} + +/*! + * @brief This internal API gets the accelerometer/gyroscope data. + */ +static void get_acc_gyr_data(struct bmi2_sens_axes_data *data, const uint8_t *reg_data) +{ + /* Variables to store msb value */ + uint8_t msb; + + /* Variables to store lsb value */ + uint8_t lsb; + + /* Variables to store both msb and lsb value */ + uint16_t msb_lsb; + + /* Variables to define index */ + uint8_t index = 0; + + /* Read x-axis data */ + lsb = reg_data[index++]; + msb = reg_data[index++]; + msb_lsb = ((uint16_t) msb << 8) | (uint16_t) lsb; + data->x = (int16_t) msb_lsb; + + /* Read y-axis data */ + lsb = reg_data[index++]; + msb = reg_data[index++]; + msb_lsb = ((uint16_t) msb << 8) | (uint16_t) lsb; + data->y = (int16_t) msb_lsb; + + /* Read z-axis data */ + lsb = reg_data[index++]; + msb = reg_data[index++]; + msb_lsb = ((uint16_t) msb << 8) | (uint16_t) lsb; + data->z = (int16_t) msb_lsb; +} + +/*! + * @brief This internal API gets the re-mapped accelerometer/gyroscope data. + */ +static void get_remapped_data(struct bmi2_sens_axes_data *data, const struct bmi2_dev *dev) +{ + /* Array to defined the re-mapped sensor data */ + int16_t remap_data[3] = { 0 }; + + /* Fill the array with the un-mapped sensor data */ + remap_data[0] = data->x; + remap_data[1] = data->y; + remap_data[2] = data->z; + + /* Get the re-mapped x, y and z axes data */ + data->x = (int16_t)(remap_data[dev->remap.x_axis] * dev->remap.x_axis_sign); + data->y = (int16_t)(remap_data[dev->remap.y_axis] * dev->remap.y_axis_sign); + data->z = (int16_t)(remap_data[dev->remap.z_axis] * dev->remap.z_axis_sign); +} + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in manual mode. + */ +static int8_t read_aux_data(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, uint8_t burst_len, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to store the register data */ + uint8_t reg_data[15] = { 0 }; + + /* Variable to define number of bytes to read */ + uint16_t read_length = 0; + + /* Variable to define loop */ + uint8_t loop = 0; + + /* Variable to define counts to get the correct array index */ + uint8_t count = 0; + + /* Variable to define index for the array */ + uint8_t idx = 0; + + while (len > 0) + { + /* Set the read address if AUX is not busy */ + rslt = set_if_aux_not_busy(BMI2_AUX_RD_ADDR, reg_addr, dev); + if (rslt == BMI2_OK) + { + /* Read data from bmi2 data register */ + rslt = bmi2_get_regs(BMI2_AUX_X_LSB_ADDR, reg_data, (uint16_t) burst_len, dev); + dev->delay_us(1000); + if (rslt == BMI2_OK) + { + /* Get number of bytes to be read */ + if (len < burst_len) + { + read_length = (uint8_t) len; + } + else + { + read_length = burst_len; + } + + /* Update array index and store the data */ + for (loop = 0; loop < read_length; loop++) + { + idx = loop + count; + aux_data[idx] = reg_data[loop]; + } + } + } + + /* Update address for the next read */ + reg_addr += burst_len; + + /* Update count for the array index */ + count += burst_len; + + /* Update no of bytes left to read */ + len -= read_length; + } + + return rslt; +} + +/*! + * @brief This internal API writes AUX write address and the user-defined bytes + * of data to the AUX sensor in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + */ +static int8_t write_aux_data(uint8_t reg_addr, uint8_t reg_data, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Write data to be written to the AUX sensor in bmi2 register */ + rslt = bmi2_set_regs(BMI2_AUX_WR_DATA_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Write the AUX address where data is to be stored when AUX is not busy */ + rslt = set_if_aux_not_busy(BMI2_AUX_WR_ADDR, reg_addr, dev); + } + + return rslt; +} + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in data mode. + */ +static int8_t read_aux_data_mode(uint8_t *aux_data, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variables to define loop */ + uint8_t count = 0; + + /* Variables to define index */ + uint8_t index = 0; + + /* Array to define data stored in register */ + uint8_t reg_data[BMI2_AUX_NUM_BYTES] = { 0 }; + + /* Check if data mode */ + if (!dev->aux_man_en) + { + /* Read the auxiliary sensor data */ + rslt = bmi2_get_regs(BMI2_AUX_X_LSB_ADDR, reg_data, BMI2_AUX_NUM_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Get the 8 bytes of auxiliary data */ + do + { + *(aux_data + count++) = *(reg_data + index++); + } while (count < BMI2_AUX_NUM_BYTES); + } + } + else + { + rslt = BMI2_E_AUX_INVALID_CFG; + } + + return rslt; +} + +/*! + * @brief This internal API maps the actual burst read length with that of the + * register value set by user. + */ +static int8_t map_read_len(uint8_t *len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Get the burst read length against the values set by the user */ + switch (dev->aux_man_rd_burst_len) + { + case BMI2_AUX_READ_LEN_0: + *len = 1; + break; + case BMI2_AUX_READ_LEN_1: + *len = 2; + break; + case BMI2_AUX_READ_LEN_2: + *len = 6; + break; + case BMI2_AUX_READ_LEN_3: + *len = 8; + break; + default: + rslt = BMI2_E_AUX_INVALID_CFG; + break; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of step counter. + */ +static int8_t get_step_counter_output(uint32_t *step_count, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for step counter */ + struct bmi2_feature_config step_cnt_out_config = { 0, 0, 0 }; + + /* Search for step counter output feature and extract its configuration details */ + feat_found = extract_output_feat_config(&step_cnt_out_config, BMI2_STEP_COUNTER, dev); + if (feat_found) + { + /* Get the feature output configuration for step-counter */ + rslt = get_feat_config(step_cnt_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for step counter output */ + idx = step_cnt_out_config.start_addr; + + /* Get the step counter output in 4 bytes */ + *step_count = (uint32_t) feat_config[idx++]; + *step_count |= ((uint32_t) feat_config[idx++] << 8); + *step_count |= ((uint32_t) feat_config[idx++] << 16); + *step_count |= ((uint32_t) feat_config[idx++] << 24); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of step activity. + */ +static int8_t get_step_activity_output(uint8_t *step_act, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for step activity */ + struct bmi2_feature_config step_act_out_config = { 0, 0, 0 }; + + /* Search for step activity output feature and extract its configuration details */ + feat_found = extract_output_feat_config(&step_act_out_config, BMI2_STEP_ACTIVITY, dev); + if (feat_found) + { + /* Get the feature output configuration for step-activity */ + rslt = get_feat_config(step_act_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for step activity output */ + idx = step_act_out_config.start_addr; + + /* Get the step activity output */ + *step_act = feat_config[idx]; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of orientation: portrait- + * landscape and face up-down. + */ +static int8_t get_orient_output(struct bmi2_orientation_output *orient_out, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for orientation */ + struct bmi2_feature_config orient_out_config = { 0, 0, 0 }; + + /* Search for orientation output feature and extract its configuration details */ + feat_found = extract_output_feat_config(&orient_out_config, BMI2_ORIENTATION, dev); + if (feat_found) + { + /* Get the feature output configuration for orientation */ + rslt = get_feat_config(orient_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for orientation output */ + idx = orient_out_config.start_addr; + + /* Get the output value of the orientation detection feature */ + orient_out->portrait_landscape = BMI2_GET_BIT_POS0(feat_config[idx], BMI2_ORIENT_DETECT); + + /* Get the output value of the orientation face up-down feature */ + orient_out->faceup_down = BMI2_GET_BITS(feat_config[idx], BMI2_ORIENT_FACE_UP_DWN); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of high-g. + */ +static int8_t get_high_g_output(uint8_t *high_g_out, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for high-g */ + struct bmi2_feature_config high_g_out_config = { 0, 0, 0 }; + + /* Search for high-g output feature and extract its configuration details */ + feat_found = extract_output_feat_config(&high_g_out_config, BMI2_HIGH_G, dev); + if (feat_found) + { + /* Get the feature output configuration for high-g */ + rslt = get_feat_config(high_g_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for high-g output */ + idx = high_g_out_config.start_addr; + + /* Get the high-g output byte */ + *high_g_out = feat_config[idx]; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the saturation status for the gyroscope user + * gain update. + */ +static int8_t get_gyro_gain_update_status(struct bmi2_gyr_user_gain_status *user_gain_stat, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for gyroscope user gain status */ + struct bmi2_feature_config user_gain_cfg = { 0, 0, 0 }; + + /* Search for gyroscope user gain status output feature and extract its + * configuration details + */ + feat_found = extract_output_feat_config(&user_gain_cfg, BMI2_GYRO_GAIN_UPDATE, dev); + if (feat_found) + { + /* Get the feature output configuration for gyroscope user gain status */ + rslt = get_feat_config(user_gain_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for gyroscope user gain status */ + idx = user_gain_cfg.start_addr; + + /* Get the saturation status for x-axis */ + user_gain_stat->sat_x = BMI2_GET_BIT_POS0(feat_config[idx], GYR_USER_GAIN_SAT_STAT_X); + + /* Get the saturation status for y-axis */ + user_gain_stat->sat_y = BMI2_GET_BITS(feat_config[idx], GYR_USER_GAIN_SAT_STAT_Y); + + /* Get the saturation status for z-axis */ + user_gain_stat->sat_z = BMI2_GET_BITS(feat_config[idx], GYR_USER_GAIN_SAT_STAT_Z); + + /* Get g trigger status */ + user_gain_stat->g_trigger_status = BMI2_GET_BITS(feat_config[idx], G_TRIGGER_STAT); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the error status related to NVM. + */ +static int8_t get_nvm_error_status(struct bmi2_nvm_err_status *nvm_err_stat, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for NVM error status */ + struct bmi2_feature_config nvm_err_cfg = { 0, 0, 0 }; + + /* Search for NVM error status feature and extract its configuration details */ + feat_found = extract_output_feat_config(&nvm_err_cfg, BMI2_NVM_STATUS, dev); + if (feat_found) + { + /* Get the feature output configuration for NVM error status */ + rslt = get_feat_config(nvm_err_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for NVM error status */ + idx = nvm_err_cfg.start_addr; + + /* Increment index to get the error status */ + idx++; + + /* Error when NVM load action fails */ + nvm_err_stat->load_error = BMI2_GET_BIT_POS0(feat_config[idx], NVM_LOAD_ERR_STATUS); + + /* Error when NVM program action fails */ + nvm_err_stat->prog_error = BMI2_GET_BITS(feat_config[idx], NVM_PROG_ERR_STATUS); + + /* Error when NVM erase action fails */ + nvm_err_stat->erase_error = BMI2_GET_BITS(feat_config[idx], NVM_ERASE_ERR_STATUS); + + /* Error when NVM program limit is exceeded */ + nvm_err_stat->exceed_error = BMI2_GET_BITS(feat_config[idx], NVM_END_EXCEED_STATUS); + + /* Error when NVM privilege mode is not acquired */ + nvm_err_stat->privil_error = BMI2_GET_BITS(feat_config[idx], NVM_PRIV_ERR_STATUS); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the error status related to virtual frames. + */ +static int8_t get_vfrm_error_status(struct bmi2_vfrm_err_status *vfrm_err_stat, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for VFRM error status */ + struct bmi2_feature_config vfrm_err_cfg = { 0, 0, 0 }; + + /* Search for VFRM error status feature and extract its configuration details */ + feat_found = extract_output_feat_config(&vfrm_err_cfg, BMI2_VFRM_STATUS, dev); + if (feat_found) + { + /* Get the feature output configuration for VFRM error status */ + rslt = get_feat_config(vfrm_err_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for VFRM error status */ + idx = vfrm_err_cfg.start_addr; + + /* Increment index to get the error status */ + idx++; + + /* Internal error while acquiring lock for FIFO */ + vfrm_err_stat->lock_error = BMI2_GET_BITS(feat_config[idx], VFRM_LOCK_ERR_STATUS); + + /* Internal error while writing byte into FIFO */ + vfrm_err_stat->write_error = BMI2_GET_BITS(feat_config[idx], VFRM_WRITE_ERR_STATUS); + + /* Internal error while writing into FIFO */ + vfrm_err_stat->fatal_error = BMI2_GET_BITS(feat_config[idx], VFRM_FATAL_ERR_STATUS); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of the wrist gesture. + */ +static int8_t get_wrist_gest_status(uint8_t *wrist_gest, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for wrist gesture */ + struct bmi2_feature_config wrist_gest_out_config = { 0, 0, 0 }; + + /* Search for wrist gesture feature and extract its configuration details */ + feat_found = extract_output_feat_config(&wrist_gest_out_config, BMI2_WRIST_GESTURE, dev); + if (feat_found) + { + /* Get the feature output configuration for wrist gesture */ + rslt = get_feat_config(wrist_gest_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for wrist gesture output */ + idx = wrist_gest_out_config.start_addr; + + /* Get the wrist gesture output */ + *wrist_gest = feat_config[idx]; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the cross sensitivity coefficient between + * gyroscope's X and Z axes. + */ +static int8_t get_gyro_cross_sense(int16_t *cross_sense, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + uint8_t corr_fact_zx; + + /* Initialize feature output for gyroscope cross sensitivity */ + struct bmi2_feature_config cross_sense_out_config = { 0, 0, 0 }; + + if (dev->variant_feature & BMI2_MINIMAL_VARIANT) + { + /* For minimal variant fetch the correction factor from GPIO0 */ + rslt = bmi2_get_regs(BMI2_GYR_CAS_GPIO0_ADDR, &corr_fact_zx, 1, dev); + if (rslt == BMI2_OK) + { + /* Get the gyroscope cross sensitivity coefficient */ + if (corr_fact_zx & BMI2_GYRO_CROSS_AXES_SENSE_SIGN_BIT_MASK) + { + *cross_sense = (int16_t)(((int16_t)corr_fact_zx) - 128); + } + else + { + *cross_sense = (int16_t)(corr_fact_zx); + } + } + } + else + { + /* Search for gyroscope cross sensitivity feature and extract its configuration details */ + feat_found = extract_output_feat_config(&cross_sense_out_config, BMI2_GYRO_CROSS_SENSE, dev); + if (feat_found) + { + /* Get the feature output configuration for gyroscope cross sensitivity + * feature */ + rslt = get_feat_config(cross_sense_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for gyroscope cross sensitivity output */ + idx = cross_sense_out_config.start_addr; + + /* discard the MSB as GYR_CAS is of only 7 bit */ + feat_config[idx] = feat_config[idx] & BMI2_GYRO_CROSS_AXES_SENSE_MASK; + + /* Get the gyroscope cross sensitivity coefficient */ + if (feat_config[idx] & BMI2_GYRO_CROSS_AXES_SENSE_SIGN_BIT_MASK) + { + *cross_sense = (int16_t)(((int16_t)feat_config[idx]) - 128); + } + else + { + *cross_sense = (int16_t)(feat_config[idx]); + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to get enable status of gyroscope user gain + * update. + */ +static int8_t get_user_gain_upd_status(uint8_t *status, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Variable to check APS status */ + uint8_t aps_stat = 0; + + /* Initialize feature configuration for gyroscope user gain */ + struct bmi2_feature_config gyr_user_gain_cfg = { 0, 0, 0 }; + + /* Search for user gain feature and extract its configuration details */ + feat_found = extract_input_feat_config(&gyr_user_gain_cfg, BMI2_GYRO_GAIN_UPDATE, dev); + if (feat_found) + { + /* Disable advance power save */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Get the configuration from the page where user gain feature resides */ + rslt = get_feat_config(gyr_user_gain_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for enable/disable of user gain */ + idx = gyr_user_gain_cfg.start_addr + GYR_USER_GAIN_FEAT_EN_OFFSET; + + /* Set the feature enable status */ + *status = BMI2_GET_BITS(feat_config[idx], GYR_USER_GAIN_FEAT_EN); + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and not when already disabled */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + + return rslt; +} + +/*! + * @brief This internal API gets the accelerometer self-test status. + */ +static int8_t get_accel_self_test_status(struct bmi2_acc_self_test_status *acc_self_test_stat, struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + uint8_t idx = 0; + uint8_t feat_found; + struct bmi2_feature_config acc_self_test_cfg = { 0, 0, 0 }; + + /* Search for accelerometer self-test feature and extract its configuration details */ + feat_found = extract_output_feat_config(&acc_self_test_cfg, BMI2_ACCEL_SELF_TEST, dev); + if (feat_found) + { + /* Get the feature output configuration for accelerometer self-test status */ + rslt = get_feat_config(acc_self_test_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for accelerometer self-test */ + idx = acc_self_test_cfg.start_addr; + + /* Bit to check if self-test is done */ + acc_self_test_stat->acc_self_test_done = BMI2_GET_BIT_POS0(feat_config[idx], ACC_SELF_TEST_DONE); + + /* Bit to check if accelerometer X-axis test is passed */ + acc_self_test_stat->acc_x_ok = BMI2_GET_BITS(feat_config[idx], ACC_X_OK); + + /* Bit to check if accelerometer Y-axis test is passed */ + acc_self_test_stat->acc_y_ok = BMI2_GET_BITS(feat_config[idx], ACC_Y_OK); + + /* Bit to check if accelerometer Z-axis test is passed */ + acc_self_test_stat->acc_z_ok = BMI2_GET_BITS(feat_config[idx], ACC_Z_OK); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API computes the number of bytes of accelerometer FIFO + * data which is to be parsed in header-less mode. + */ +static int8_t parse_fifo_accel_len(uint16_t *start_idx, + uint16_t *len, + const uint16_t *acc_count, + const struct bmi2_fifo_frame *fifo) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Data start index */ + (*start_idx) = fifo->acc_byte_start_idx; + + /* If only accelerometer is enabled */ + if (fifo->data_enable == BMI2_FIFO_ACC_EN) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*acc_count) * BMI2_FIFO_ACC_LENGTH); + } + /* If only accelerometer and auxiliary are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_AUX_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*acc_count) * BMI2_FIFO_ACC_AUX_LENGTH); + } + /* If only accelerometer and gyroscope are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_GYR_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*acc_count) * BMI2_FIFO_ACC_GYR_LENGTH); + } + /* If only accelerometer, gyroscope and auxiliary are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_GYR_EN | BMI2_FIFO_AUX_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*acc_count) * BMI2_FIFO_ALL_LENGTH); + } + else + { + /* Move the data index to the last byte to mark completion when + * no sensors or sensors apart from accelerometer are enabled + */ + (*start_idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + + /* If more data is requested than available */ + if ((*len) > fifo->length) + { + (*len) = fifo->length; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse the accelerometer data from the + * FIFO in header mode. + */ +static int8_t extract_accel_header_mode(struct bmi2_sens_axes_data *acc, + uint16_t *accel_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variable to define header frame */ + uint8_t frame_header = 0; + + /* Variable to index the data bytes */ + uint16_t data_index; + + /* Variable to index accelerometer frames */ + uint16_t accel_index = 0; + + /* Variable to indicate accelerometer frames read */ + uint16_t frame_to_read = *accel_length; + + for (data_index = fifo->acc_byte_start_idx; data_index < fifo->length;) + { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Parse virtual header if S4S is enabled */ + parse_if_virtual_header(&frame_header, &data_index, fifo); + + /* Index shifted to next byte where data starts */ + data_index++; + switch (frame_header) + { + /* If header defines accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEADER_ALL_FRM: + + /* Unpack from normal frames */ + rslt = unpack_accel_frame(acc, &data_index, &accel_index, frame_header, fifo, dev); + break; + + /* If header defines only gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->gyr_frm_len, fifo); + break; + + /* If header defines only auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + rslt = move_next_frame(&data_index, fifo->aux_frm_len, fifo); + break; + + /* If header defines only auxiliary and gyroscope frame */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->aux_gyr_frm_len, fifo); + break; + + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = unpack_sensortime_frame(&data_index, fifo); + break; + + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = unpack_skipped_frame(&data_index, fifo); + break; + + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + + /* If header defines invalid frame or end of valid data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + + /* Move the data index to the last byte to mark completion */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_VIRT_ACT_DATA_LENGTH, fifo); + break; + default: + + /* Move the data index to the last byte in case of invalid values */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Break if Number of frames to be read is complete or FIFO is mpty */ + if ((frame_to_read == accel_index) || (rslt == BMI2_W_FIFO_EMPTY)) + { + break; + } + } + + /* Update the accelerometer frame index */ + (*accel_length) = accel_index; + + /* Update the accelerometer byte index */ + fifo->acc_byte_start_idx = data_index; + + return rslt; +} + +/*! + * @brief This internal API is used to parse the accelerometer data from the + * FIFO data in both header and header-less mode. It updates the current data + * byte to be parsed. + */ +static int8_t unpack_accel_frame(struct bmi2_sens_axes_data *acc, + uint16_t *idx, + uint16_t *acc_idx, + uint8_t frame, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + switch (frame) + { + /* If frame contains only accelerometer data */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_ACC_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_frm_len) > fifo->length) + { + /* Update the data index as complete*/ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], *idx, fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + } + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer and gyroscope data */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_gyr_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], ((*idx) + BMI2_FIFO_GYR_LENGTH), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_GYR_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + } + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_aux_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], ((*idx) + BMI2_FIFO_AUX_LENGTH), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + } + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer, gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_ALL_FRM: + case BMI2_FIFO_HEAD_LESS_ALL_FRM: + + /* Partially read, then skip the data*/ + if ((*idx + fifo->all_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], ((*idx) + BMI2_FIFO_GYR_AUX_LENGTH), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ALL_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + } + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->aux_gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains only auxiliary data */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->aux_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains only gyroscope data */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + default: + + /* Move the data index to the last byte in case of invalid values */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse accelerometer data from the + * FIFO data. + */ +static void unpack_accel_data(struct bmi2_sens_axes_data *acc, + uint16_t data_start_index, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variables to store LSB value */ + uint16_t data_lsb; + + /* Variables to store MSB value */ + uint16_t data_msb; + + /* Array to defined the re-mapped accelerometer data */ + int16_t remap_data[3] = { 0 }; + + /* Accelerometer raw x data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + acc->x = (int16_t)((data_msb << 8) | data_lsb); + + /* Accelerometer raw y data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + acc->y = (int16_t)((data_msb << 8) | data_lsb); + + /* Accelerometer raw z data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + acc->z = (int16_t)((data_msb << 8) | data_lsb); + + /* Fill the array with the un-mapped accelerometer data */ + remap_data[0] = acc->x; + remap_data[1] = acc->y; + remap_data[2] = acc->z; + + /* Get the re-mapped x, y and z accelerometer data */ + acc->x = (int16_t)(remap_data[dev->remap.x_axis] * dev->remap.x_axis_sign); + acc->y = (int16_t)(remap_data[dev->remap.y_axis] * dev->remap.y_axis_sign); + acc->z = (int16_t)(remap_data[dev->remap.z_axis] * dev->remap.z_axis_sign); +} + +/*! + * @brief This internal API computes the number of bytes of gyroscope FIFO data + * which is to be parsed in header-less mode. + */ +static int8_t parse_fifo_gyro_len(uint16_t *start_idx, + uint16_t(*len), + const uint16_t *gyr_count, + const struct bmi2_fifo_frame *fifo) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Data start index */ + (*start_idx) = fifo->gyr_byte_start_idx; + + /* If only gyroscope is enabled */ + if (fifo->data_enable == BMI2_FIFO_GYR_EN) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*gyr_count) * BMI2_FIFO_GYR_LENGTH); + } + /* If only gyroscope and auxiliary are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_GYR_EN | BMI2_FIFO_AUX_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*gyr_count) * BMI2_FIFO_GYR_AUX_LENGTH); + } + /* If only accelerometer and gyroscope are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_GYR_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*gyr_count) * BMI2_FIFO_ACC_GYR_LENGTH); + } + /* If only accelerometer, gyroscope and auxiliary are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_GYR_EN | BMI2_FIFO_AUX_EN | BMI2_FIFO_ACC_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*gyr_count) * BMI2_FIFO_ALL_LENGTH); + } + else + { + /* Move the data index to the last byte to mark completion when + * no sensors or sensors apart from gyroscope are enabled + */ + (*start_idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + + /* If more data is requested than available */ + if (((*len)) > fifo->length) + { + (*len) = fifo->length; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse the gyroscope data from the + * FIFO data in header mode. + */ +static int8_t extract_gyro_header_mode(struct bmi2_sens_axes_data *gyr, + uint16_t *gyro_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variable to define header frame */ + uint8_t frame_header = 0; + + /* Variable to index the data bytes */ + uint16_t data_index; + + /* Variable to index gyroscope frames */ + uint16_t gyro_index = 0; + + /* Variable to indicate gyroscope frames read */ + uint16_t frame_to_read = (*gyro_length); + + for (data_index = fifo->gyr_byte_start_idx; data_index < fifo->length;) + { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Parse virtual header if S4S is enabled */ + parse_if_virtual_header(&frame_header, &data_index, fifo); + + /* Index shifted to next byte where data starts */ + data_index++; + switch (frame_header) + { + /* If header defines gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEADER_ALL_FRM: + + /* Unpack from normal frames */ + rslt = unpack_gyro_frame(gyr, &data_index, &gyro_index, frame_header, fifo, dev); + break; + + /* If header defines only accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_frm_len, fifo); + break; + + /* If header defines only auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + rslt = move_next_frame(&data_index, fifo->aux_frm_len, fifo); + break; + + /* If header defines only auxiliary and accelerometer frame */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_aux_frm_len, fifo); + break; + + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = unpack_sensortime_frame(&data_index, fifo); + break; + + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = unpack_skipped_frame(&data_index, fifo); + break; + + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + + /* If header defines invalid frame or end of valid data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + + /* Move the data index to the last byte */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_VIRT_ACT_DATA_LENGTH, fifo); + break; + default: + + /* Move the data index to the last byte in case of invalid values */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Break if number of frames to be read is complete or FIFO is empty */ + if ((frame_to_read == gyro_index) || (rslt == BMI2_W_FIFO_EMPTY)) + { + break; + } + } + + /* Update the gyroscope frame index */ + (*gyro_length) = gyro_index; + + /* Update the gyroscope byte index */ + fifo->gyr_byte_start_idx = data_index; + + return rslt; +} + +/*! + * @brief This internal API is used to parse the gyroscope data from the FIFO + * data in both header and header-less mode. It updates the current data byte to + * be parsed. + */ +static int8_t unpack_gyro_frame(struct bmi2_sens_axes_data *gyr, + uint16_t *idx, + uint16_t *gyr_idx, + uint8_t frame, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + switch (frame) + { + /* If frame contains only gyroscope data */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->gyr_frm_len) > fifo->length) + { + /* Update the data index as complete*/ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], *idx, fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_GYR_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + } + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer and gyroscope data */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_gyr_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], (*idx), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_GYR_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + } + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->aux_gyr_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], ((*idx) + BMI2_FIFO_AUX_LENGTH), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_GYR_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + } + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer, gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_ALL_FRM: + case BMI2_FIFO_HEAD_LESS_ALL_FRM: + + /* Partially read, then skip the data*/ + if ((*idx + fifo->all_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], ((*idx) + BMI2_FIFO_AUX_LENGTH), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ALL_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + } + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->acc_aux_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains only auxiliary data */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->aux_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains only accelerometer data */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_ACC_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->acc_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + default: + + /* Move the data index to the last byte in case of invalid values */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse gyroscope data from the FIFO data. + */ +static void unpack_gyro_data(struct bmi2_sens_axes_data *gyr, + uint16_t data_start_index, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variables to store LSB value */ + uint16_t data_lsb; + + /* Variables to store MSB value */ + uint16_t data_msb; + + /* Array to defined the re-mapped gyroscope data */ + int16_t remap_data[3] = { 0 }; + + /* Gyroscope raw x data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + gyr->x = (int16_t)((data_msb << 8) | data_lsb); + + /* Gyroscope raw y data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + gyr->y = (int16_t)((data_msb << 8) | data_lsb); + + /* Gyroscope raw z data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + gyr->z = (int16_t)((data_msb << 8) | data_lsb); + + /* Get the compensated gyroscope data */ + comp_gyro_cross_axis_sensitivity(gyr, dev); + + /* Fill the array with the un-mapped gyroscope data */ + remap_data[0] = gyr->x; + remap_data[1] = gyr->y; + remap_data[2] = gyr->z; + + /* Get the re-mapped x, y and z gyroscope data */ + gyr->x = (int16_t)(remap_data[dev->remap.x_axis] * dev->remap.x_axis_sign); + gyr->y = (int16_t)(remap_data[dev->remap.y_axis] * dev->remap.y_axis_sign); + gyr->z = (int16_t)(remap_data[dev->remap.z_axis] * dev->remap.z_axis_sign); +} + +/*! + * @brief This API computes the number of bytes of auxiliary FIFO data which is + * to be parsed in header-less mode. + */ +static int8_t parse_fifo_aux_len(uint16_t *start_idx, + uint16_t(*len), + const uint16_t *aux_count, + const struct bmi2_fifo_frame *fifo) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Data start index */ + *start_idx = fifo->aux_byte_start_idx; + + /* If only auxiliary is enabled */ + if (fifo->data_enable == BMI2_FIFO_AUX_EN) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*aux_count) * BMI2_FIFO_AUX_LENGTH); + } + /* If only accelerometer and auxiliary are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_AUX_EN | BMI2_FIFO_ACC_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*aux_count) * BMI2_FIFO_ACC_AUX_LENGTH); + } + /* If only accelerometer and gyroscope are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_AUX_EN | BMI2_FIFO_GYR_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*aux_count) * BMI2_FIFO_GYR_AUX_LENGTH); + } + /* If only accelerometer, gyroscope and auxiliary are enabled */ + else if (fifo->data_enable == (BMI2_FIFO_AUX_EN | BMI2_FIFO_GYR_EN | BMI2_FIFO_ACC_EN)) + { + /* Number of bytes to be read */ + (*len) = (uint16_t)((*aux_count) * BMI2_FIFO_ALL_LENGTH); + } + else + { + /* Move the data index to the last byte to mark completion when + * no sensors or sensors apart from gyroscope are enabled + */ + (*start_idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + + /* If more data is requested than available */ + if (((*len)) > fifo->length) + { + (*len) = fifo->length; + } + + return rslt; +} + +/*! + * @brief This API is used to parse the auxiliary data from the FIFO data in + * header mode. + */ +static int8_t extract_aux_header_mode(struct bmi2_aux_fifo_data *aux, + uint16_t *aux_len, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variable to define header frame */ + uint8_t frame_header = 0; + + /* Variable to index the data bytes */ + uint16_t data_index; + + /* Variable to index gyroscope frames */ + uint16_t aux_index = 0; + + /* Variable to indicate auxiliary frames read */ + uint16_t frame_to_read = *aux_len; + + for (data_index = fifo->aux_byte_start_idx; data_index < fifo->length;) + { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Parse virtual header if S4S is enabled */ + parse_if_virtual_header(&frame_header, &data_index, fifo); + + /* Index shifted to next byte where data starts */ + data_index++; + switch (frame_header) + { + /* If header defines auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEADER_ALL_FRM: + + /* Unpack from normal frames */ + rslt = unpack_aux_frame(aux, &data_index, &aux_index, frame_header, fifo, dev); + break; + + /* If header defines only accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_frm_len, fifo); + break; + + /* If header defines only gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->gyr_frm_len, fifo); + break; + + /* If header defines only gyroscope and accelerometer frame */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_gyr_frm_len, fifo); + break; + + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = unpack_sensortime_frame(&data_index, fifo); + break; + + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = unpack_skipped_frame(&data_index, fifo); + break; + + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + + /* If header defines invalid frame or end of valid data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + + /* Move the data index to the last byte */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_VIRT_ACT_DATA_LENGTH, fifo); + break; + default: + + /* Move the data index to the last byte in case + * of invalid values + */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Break if number of frames to be read is complete or FIFO is + * empty + */ + if ((frame_to_read == aux_index) || (rslt == BMI2_W_FIFO_EMPTY)) + { + break; + } + } + + /* Update the gyroscope frame index */ + (*aux_len) = aux_index; + + /* Update the gyroscope byte index */ + fifo->aux_byte_start_idx = data_index; + + return rslt; +} + +/*! + * @brief This API is used to parse the auxiliary frame from the FIFO data in + * both header mode and header-less mode and update the data_index value which + * is used to store the index of the current data byte which is parsed. + */ +static int8_t unpack_aux_frame(struct bmi2_aux_fifo_data *aux, + uint16_t *idx, + uint16_t *aux_idx, + uint8_t frame, + const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + switch (frame) + { + /* If frame contains only auxiliary data */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->aux_frm_len) > fifo->length) + { + /* Update the data index as complete*/ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + } + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_aux_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + } + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM: + + /* Partially read, then skip the data */ + if (((*idx) + fifo->aux_gyr_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_GYR_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + } + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer, gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_ALL_FRM: + case BMI2_FIFO_HEAD_LESS_ALL_FRM: + + /* Partially read, then skip the data*/ + if ((*idx + fifo->all_frm_len) > fifo->length) + { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ALL_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + { + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + } + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains only accelerometer data */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_ACC_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->acc_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains only gyroscope data */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + + /* If frame contains accelerometer and gyroscope data */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM: + + /* Update data index */ + (*idx) = (*idx) + fifo->acc_gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + default: + + /* Move the data index to the last byte in case of + * invalid values + */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse auxiliary data from the FIFO data. + */ +static void unpack_aux_data(struct bmi2_aux_fifo_data *aux, + uint16_t data_start_index, + const struct bmi2_fifo_frame *fifo) +{ + /* Variables to store index */ + uint16_t idx = 0; + + /* Get auxiliary data */ + for (; idx < 8; idx++) + { + aux->data[idx] = fifo->data[data_start_index++]; + } +} + +/*! + * @brief This internal API parses virtual frame header from the FIFO data. + */ +static void parse_if_virtual_header(uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variable to extract virtual header byte */ + uint8_t virtual_header_mode; + + /* Extract virtual header mode from the frame header */ + virtual_header_mode = BMI2_GET_BITS(*frame_header, BMI2_FIFO_VIRT_FRM_MODE); + + /* If the extracted header byte is a virtual header */ + if (virtual_header_mode == BMI2_FIFO_VIRT_FRM_MODE) + { + /* If frame header is not activity recognition header */ + if (*frame_header != 0xC8) + { + /* Index shifted to next byte where sensor frame is present */ + (*data_index) = (*data_index) + 1; + + /* Get the sensor frame header */ + *frame_header = fifo->data[*data_index] & BMI2_FIFO_TAG_INTR_MASK; + } + } +} + +/*! + * @brief This internal API gets sensor time from the accelerometer and + * gyroscope virtual frames and updates in the data structure. + */ +static void unpack_virt_sensor_time(struct bmi2_sens_axes_data *sens, uint16_t *idx, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define 3 bytes of sensor time */ + uint32_t sensor_time_byte3; + uint16_t sensor_time_byte2; + uint8_t sensor_time_byte1; + + /* Get sensor time from the FIFO data */ + sensor_time_byte3 = (uint32_t)(fifo->data[(*idx) + BMI2_SENSOR_TIME_MSB_BYTE] << 16); + sensor_time_byte2 = (uint16_t) fifo->data[(*idx) + BMI2_SENSOR_TIME_XLSB_BYTE] << 8; + sensor_time_byte1 = fifo->data[(*idx)]; + + /* Store sensor time in the sensor data structure */ + sens->virt_sens_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1); + + /* Move the data index by 3 bytes */ + (*idx) = (*idx) + BMI2_SENSOR_TIME_LENGTH; +} + +/*! + * @brief This internal API gets sensor time from the auxiliary virtual + * frames and updates in the data structure. + */ +static void unpack_virt_aux_sensor_time(struct bmi2_aux_fifo_data *aux, + uint16_t *idx, + const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define 3 bytes of sensor time */ + uint32_t sensor_time_byte3; + uint16_t sensor_time_byte2; + uint8_t sensor_time_byte1; + + /* Get sensor time from the FIFO data */ + sensor_time_byte3 = (uint32_t)(fifo->data[(*idx) + BMI2_SENSOR_TIME_MSB_BYTE] << 16); + sensor_time_byte2 = (uint16_t) fifo->data[(*idx) + BMI2_SENSOR_TIME_XLSB_BYTE] << 8; + sensor_time_byte1 = fifo->data[(*idx)]; + + /* Store sensor time in the sensor data structure */ + aux->virt_sens_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1); + + /* Move the data index by 3 bytes */ + (*idx) = (*idx) + BMI2_SENSOR_TIME_LENGTH; +} + +/*! + * @brief This internal API is used to reset the FIFO related configurations in + * the FIFO frame structure for the next FIFO read. + */ +static void reset_fifo_frame_structure(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Reset FIFO data structure */ + fifo->acc_byte_start_idx = 0; + fifo->aux_byte_start_idx = 0; + fifo->gyr_byte_start_idx = 0; + fifo->sensor_time = 0; + fifo->skipped_frame_count = 0; + fifo->act_recog_byte_start_idx = 0; + + /* If S4S is enabled */ + if ((dev->sens_en_stat & BMI2_EXT_SENS_SEL) == BMI2_EXT_SENS_SEL) + { + fifo->acc_frm_len = BMI2_FIFO_VIRT_ACC_LENGTH; + fifo->gyr_frm_len = BMI2_FIFO_VIRT_GYR_LENGTH; + fifo->aux_frm_len = BMI2_FIFO_VIRT_AUX_LENGTH; + fifo->acc_gyr_frm_len = BMI2_FIFO_VIRT_ACC_GYR_LENGTH; + fifo->acc_aux_frm_len = BMI2_FIFO_VIRT_ACC_AUX_LENGTH; + fifo->aux_gyr_frm_len = BMI2_FIFO_VIRT_GYR_AUX_LENGTH; + fifo->all_frm_len = BMI2_FIFO_VIRT_ALL_LENGTH; + + /* If S4S is not enabled */ + } + else + { + fifo->acc_frm_len = BMI2_FIFO_ACC_LENGTH; + fifo->gyr_frm_len = BMI2_FIFO_GYR_LENGTH; + fifo->aux_frm_len = BMI2_FIFO_AUX_LENGTH; + fifo->acc_gyr_frm_len = BMI2_FIFO_ACC_GYR_LENGTH; + fifo->acc_aux_frm_len = BMI2_FIFO_ACC_AUX_LENGTH; + fifo->aux_gyr_frm_len = BMI2_FIFO_GYR_AUX_LENGTH; + fifo->all_frm_len = BMI2_FIFO_ALL_LENGTH; + } +} + +/*! + * @brief This API internal checks whether the FIFO data read is an empty frame. + * If empty frame, index is moved to the last byte. + */ +static int8_t check_empty_fifo(uint16_t *data_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + + /* Validate data index */ + if (((*data_index) + 2) < fifo->length) + { + /* Check if FIFO is empty */ + if ((fifo->data[(*data_index)] == BMI2_FIFO_MSB_CONFIG_CHECK) && + (fifo->data[(*data_index) + 1] == BMI2_FIFO_LSB_CONFIG_CHECK)) + { + /* Move the data index to the last byte to mark completion */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + else + { + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to move the data index ahead of the + * current_frame_length parameter when unnecessary FIFO data appears while + * extracting the user specified data. + */ +static int8_t move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + + /* Validate data index */ + if (((*data_index) + current_frame_length) > fifo->length) + { + /* Move the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + else + { + /* Move the data index to next frame */ + (*data_index) = (*data_index) + current_frame_length; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse and store the sensor time from the + * FIFO data. + */ +static int8_t unpack_sensortime_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + + /* Variables to define 3 bytes of sensor time */ + uint32_t sensor_time_byte3 = 0; + uint16_t sensor_time_byte2 = 0; + uint8_t sensor_time_byte1 = 0; + + /* Validate data index */ + if (((*data_index) + BMI2_SENSOR_TIME_LENGTH) > fifo->length) + { + /* Move the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + else + { + /* Get sensor time from the FIFO data */ + sensor_time_byte3 = fifo->data[(*data_index) + BMI2_SENSOR_TIME_MSB_BYTE] << 16; + sensor_time_byte2 = fifo->data[(*data_index) + BMI2_SENSOR_TIME_XLSB_BYTE] << 8; + sensor_time_byte1 = fifo->data[(*data_index)]; + + /* Update sensor time in the FIFO structure */ + fifo->sensor_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1); + + /* Move the data index by 3 bytes */ + (*data_index) = (*data_index) + BMI2_SENSOR_TIME_LENGTH; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse and store the skipped frame count + * from the FIFO data. + */ +static int8_t unpack_skipped_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + + /* Validate data index */ + if ((*data_index) >= fifo->length) + { + /* Update the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + else + { + /* Update skipped frame count in the FIFO structure */ + fifo->skipped_frame_count = fifo->data[(*data_index)]; + + /* Move the data index by 1 byte */ + (*data_index) = (*data_index) + 1; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse and store the activity recognition + * output from the FIFO data. + */ +static int8_t unpack_act_recog_output(struct bmi2_act_recog_output *act_recog, + uint16_t *data_index, + const struct bmi2_fifo_frame *fifo) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variables to define 4 bytes of sensor time */ + uint32_t time_stamp_byte4 = 0; + uint32_t time_stamp_byte3 = 0; + uint32_t time_stamp_byte2 = 0; + uint32_t time_stamp_byte1 = 0; + + /* Validate data index */ + if ((*data_index + BMI2_FIFO_VIRT_ACT_DATA_LENGTH) >= fifo->length) + { + /* Update the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + else + { + /* Get time-stamp from the activity recognition frame */ + time_stamp_byte4 = ((uint32_t)(fifo->data[(*data_index) + 3]) << 24); + time_stamp_byte3 = ((uint32_t)(fifo->data[(*data_index) + 2]) << 16); + time_stamp_byte2 = fifo->data[(*data_index) + 1] << 8; + time_stamp_byte1 = fifo->data[(*data_index)]; + + /* Update time-stamp from the virtual frame */ + act_recog->time_stamp = (time_stamp_byte4 | time_stamp_byte3 | time_stamp_byte2 | time_stamp_byte1); + + /* Move the data index by 4 bytes */ + (*data_index) = (*data_index) + BMI2_FIFO_VIRT_ACT_TIME_LENGTH; + + /* Update the previous activity from the virtual frame */ + act_recog->prev_act = fifo->data[(*data_index)]; + + /* Move the data index by 1 byte */ + (*data_index) = (*data_index) + BMI2_FIFO_VIRT_ACT_TYPE_LENGTH; + + /* Update the current activity from the virtual frame */ + act_recog->curr_act = fifo->data[(*data_index)]; + + /* Move the data index by 1 byte */ + (*data_index) = (*data_index) + BMI2_FIFO_VIRT_ACT_STAT_LENGTH; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API enables and configures the accelerometer which is + * needed for self-test operation. It also sets the amplitude for the self-test. + */ +static int8_t pre_self_test_config(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Structure to define sensor configurations */ + struct bmi2_sens_config sens_cfg; + + /* List the sensors to be selected */ + uint8_t sens_sel = BMI2_ACCEL; + + /* Enable accelerometer */ + rslt = bmi2_sensor_enable(&sens_sel, 1, dev); + dev->delay_us(1000); + + /* Enable self-test amplitude */ + if (rslt == BMI2_OK) + { + rslt = set_accel_self_test_amp(BMI2_ENABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Select accelerometer for sensor configurations */ + sens_cfg.type = BMI2_ACCEL; + + /* Get the default values */ + rslt = bmi2_get_sensor_config(&sens_cfg, 1, dev); + if (rslt == BMI2_OK) + { + /* Set the configurations required for self-test */ + sens_cfg.cfg.acc.odr = BMI2_ACC_ODR_1600HZ; + sens_cfg.cfg.acc.bwp = BMI2_ACC_NORMAL_AVG4; + sens_cfg.cfg.acc.filter_perf = BMI2_PERF_OPT_MODE; + sens_cfg.cfg.acc.range = BMI2_ACC_RANGE_16G; + + /* Set accelerometer configurations */ + rslt = bmi2_set_sensor_config(&sens_cfg, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API performs the steps needed for self-test operation + * before reading the accelerometer self-test data. + */ +static int8_t self_test_config(uint8_t sign, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Enable the accelerometer self-test feature */ + rslt = set_accel_self_test_enable(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + /* Selects the sign of accelerometer self-test excitation */ + rslt = set_acc_self_test_sign(sign, dev); + } + + return rslt; +} + +/*! + * @brief This internal API enables or disables the accelerometer self-test + * feature in the sensor. + */ +static int8_t set_accel_self_test_enable(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define data */ + uint8_t data = 0; + + /* Enable/Disable self-test feature */ + rslt = bmi2_get_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BIT_POS0(data, BMI2_ACC_SELF_TEST_EN, enable); + rslt = bmi2_set_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API selects the sign for accelerometer self-test + * excitation. + */ +static int8_t set_acc_self_test_sign(uint8_t sign, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define data */ + uint8_t data = 0; + + /* Select the sign for self-test excitation */ + rslt = bmi2_get_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BITS(data, BMI2_ACC_SELF_TEST_SIGN, sign); + rslt = bmi2_set_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API sets the amplitude of the accelerometer self-test + * deflection in the sensor. + */ +static int8_t set_accel_self_test_amp(uint8_t amp, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define data */ + uint8_t data = 0; + + /* Select amplitude of the self-test deflection */ + rslt = bmi2_get_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BITS(data, BMI2_ACC_SELF_TEST_AMP, amp); + rslt = bmi2_set_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API reads the accelerometer data for x,y and z axis from + * the sensor. The data units is in LSB format. + */ +static int8_t read_accel_xyz(struct bmi2_sens_axes_data *accel, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Array to define data buffer */ + uint8_t data[BMI2_ACC_GYR_NUM_BYTES] = { 0 }; + + rslt = bmi2_get_regs(BMI2_ACC_X_LSB_ADDR, data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Accelerometer data x axis */ + msb = data[1]; + lsb = data[0]; + accel->x = (int16_t)((msb << 8) | lsb); + + /* Accelerometer data y axis */ + msb = data[3]; + lsb = data[2]; + accel->y = (int16_t)((msb << 8) | lsb); + + /* Accelerometer data z axis */ + msb = data[5]; + lsb = data[4]; + accel->z = (int16_t)((msb << 8) | lsb); + } + + return rslt; +} + +/*! + * @brief This internal API reads the gyroscope data for x, y and z axis from + * the sensor. The data units is in LSB format. + */ +static int8_t read_gyro_xyz(struct bmi2_sens_axes_data *gyro, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Array to define data buffer */ + uint8_t data[BMI2_ACC_GYR_NUM_BYTES] = { 0 }; + + rslt = bmi2_get_regs(BMI2_GYR_X_LSB_ADDR, data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Gyroscope data x axis */ + msb = data[1]; + lsb = data[0]; + gyro->x = (int16_t)((msb << 8) | lsb); + + /* Gyroscope data y axis */ + msb = data[3]; + lsb = data[2]; + gyro->y = (int16_t)((msb << 8) | lsb); + + /* Gyroscope data z axis */ + msb = data[5]; + lsb = data[4]; + gyro->z = (int16_t)((msb << 8) | lsb); + } + + return rslt; +} + +/*! + * @brief This internal API skips S4S frame in the FIFO data while getting + * step activity output. + */ +static int8_t move_if_s4s_frame(const uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variable to extract virtual header byte */ + uint8_t virtual_header_mode; + + /* Variable to define pay-load in words */ + uint8_t payload_word = 0; + + /* Variable to define pay-load in bytes */ + uint8_t payload_bytes = 0; + + /* Extract virtual header mode from the frame header */ + virtual_header_mode = BMI2_GET_BITS(*frame_header, BMI2_FIFO_VIRT_FRM_MODE); + + /* If the extracted header byte is a virtual header */ + if (virtual_header_mode == BMI2_FIFO_VIRT_FRM_MODE) + { + /* If frame header is not activity recognition header */ + if (*frame_header != 0xC8) + { + /* Extract pay-load in words from the header byte */ + payload_word = BMI2_GET_BITS(*frame_header, BMI2_FIFO_VIRT_PAYLOAD) + 1; + + /* Convert to bytes */ + payload_bytes = (uint8_t)(payload_word * 2); + + /* Move the data index by those pay-load bytes */ + rslt = move_next_frame(data_index, payload_bytes, fifo); + } + } + + return rslt; +} + +/*! + * @brief This internal API converts LSB value of accelerometer axes to form + * 'g' to 'mg' for self-test. + */ +static void convert_lsb_g(const struct selftest_delta_limit *acc_data_diff, + struct selftest_delta_limit *acc_data_diff_mg, + const struct bmi2_dev *dev) +{ + /* Variable to define LSB/g value of axes */ + uint32_t lsb_per_g; + + /* Range considered for self-test is +/-16g */ + uint8_t range = BMI2_ACC_SELF_TEST_RANGE; + + /* lsb_per_g for the respective resolution and 16g range */ + lsb_per_g = (uint32_t)(power(2, dev->resolution) / (2 * range)); + + /* Accelerometer x value in mg */ + acc_data_diff_mg->x = (acc_data_diff->x / (int32_t) lsb_per_g) * 1000; + + /* Accelerometer y value in mg */ + acc_data_diff_mg->y = (acc_data_diff->y / (int32_t) lsb_per_g) * 1000; + + /* Accelerometer z value in mg */ + acc_data_diff_mg->z = (acc_data_diff->z / (int32_t) lsb_per_g) * 1000; +} + +/*! + * @brief This internal API is used to calculate the power of a value. + */ +static int32_t power(int16_t base, uint8_t resolution) +{ + /* Initialize loop */ + uint8_t loop = 1; + + /* Initialize variable to store the power of 2 value */ + int32_t value = 1; + + for (; loop <= resolution; loop++) + { + value = (int32_t)(value * base); + } + + return value; +} + +/*! + * @brief This internal API validates the accelerometer self-test data and + * decides the result of self-test operation. + */ +static int8_t validate_self_test(const struct selftest_delta_limit *accel_data_diff) +{ + /* Variable to define error */ + int8_t rslt; + + /* As per the data sheet, The actually measured signal differences should be significantly + * larger than the minimum differences for each axis in order for the self-test to pass. + */ + if ((accel_data_diff->x > BMI2_ST_ACC_X_SIG_MIN_DIFF) && (accel_data_diff->y < BMI2_ST_ACC_Y_SIG_MIN_DIFF) && + (accel_data_diff->z > BMI2_ST_ACC_Z_SIG_MIN_DIFF)) + { + /* Self-test pass */ + rslt = BMI2_OK; + } + else + { + /* Self-test fail*/ + rslt = BMI2_E_SELF_TEST_FAIL; + } + + return rslt; +} + +/*! + * @brief This internal API gets the re-mapped x, y and z axes from the sensor. + */ +static int8_t get_remap_axes(struct axes_remap *remap, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for axis re-mapping */ + struct bmi2_feature_config remap_config = { 0, 0, 0 }; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat; + + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Search for axis re-mapping and extract its configuration details */ + feat_found = extract_input_feat_config(&remap_config, BMI2_AXIS_MAP, dev); + if (feat_found) + { + rslt = get_feat_config(remap_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for axis re-mapping */ + idx = remap_config.start_addr; + + /* Get the re-mapped x-axis */ + remap->x_axis = BMI2_GET_BIT_POS0(feat_config[idx], X_AXIS); + + /* Get the re-mapped x-axis polarity */ + remap->x_axis_sign = BMI2_GET_BITS(feat_config[idx], X_AXIS_SIGN); + + /* Get the re-mapped y-axis */ + remap->y_axis = BMI2_GET_BITS(feat_config[idx], Y_AXIS); + + /* Get the re-mapped y-axis polarity */ + remap->y_axis_sign = BMI2_GET_BITS(feat_config[idx], Y_AXIS_SIGN); + + /* Get the re-mapped z-axis */ + remap->z_axis = BMI2_GET_BITS(feat_config[idx], Z_AXIS); + + /* Increment byte to fetch the next data */ + idx++; + + /* Get the re-mapped z-axis polarity */ + remap->z_axis_sign = BMI2_GET_BIT_POS0(feat_config[idx], Z_AXIS_SIGN); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API sets the re-mapped x, y and z axes in the sensor. + */ +static int8_t set_remap_axes(const struct axes_remap *remap, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define the register address */ + uint8_t reg_addr = 0; + + /* Variable to set the re-mapped x-axes in the sensor */ + uint8_t x_axis = 0; + + /* Variable to set the re-mapped y-axes in the sensor */ + uint8_t y_axis = 0; + + /* Variable to set the re-mapped z-axes in the sensor */ + uint8_t z_axis = 0; + + /* Variable to set the re-mapped x-axes sign in the sensor */ + uint8_t x_axis_sign = 0; + + /* Variable to set the re-mapped y-axes sign in the sensor */ + uint8_t y_axis_sign = 0; + + /* Variable to set the re-mapped z-axes sign in the sensor */ + uint8_t z_axis_sign = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for axis re-mapping */ + struct bmi2_feature_config remap_config = { 0, 0, 0 }; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat; + + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Search for axis-re-mapping and extract its configuration details */ + feat_found = extract_input_feat_config(&remap_config, BMI2_AXIS_MAP, dev); + if (feat_found) + { + /* Get the configuration from the page where axis re-mapping feature resides */ + rslt = get_feat_config(remap_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes */ + idx = remap_config.start_addr; + + /* Set the value of re-mapped x-axis */ + x_axis = remap->x_axis & X_AXIS_MASK; + + /* Set the value of re-mapped x-axis sign */ + x_axis_sign = ((remap->x_axis_sign << X_AXIS_SIGN_POS) & X_AXIS_SIGN_MASK); + + /* Set the value of re-mapped y-axis */ + y_axis = ((remap->y_axis << Y_AXIS_POS) & Y_AXIS_MASK); + + /* Set the value of re-mapped y-axis sign */ + y_axis_sign = ((remap->y_axis_sign << Y_AXIS_SIGN_POS) & Y_AXIS_SIGN_MASK); + + /* Set the value of re-mapped z-axis */ + z_axis = ((remap->z_axis << Z_AXIS_POS) & Z_AXIS_MASK); + + /* Set the value of re-mapped z-axis sign */ + z_axis_sign = remap->z_axis_sign & Z_AXIS_SIGN_MASK; + + /* Arrange axes in the first byte */ + feat_config[idx] = x_axis | x_axis_sign | y_axis | y_axis_sign | z_axis; + + /* Increment the index */ + idx++; + + /* Cannot OR in the second byte since it holds + * gyroscope self-offset correction bit + */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], Z_AXIS_SIGN, z_axis_sign); + + /* Update the register address */ + reg_addr = BMI2_FEATURES_REG_ADDR + remap_config.start_addr; + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(reg_addr, &feat_config[remap_config.start_addr], 2, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to get the feature configuration from the + * selected page. + */ +static int8_t get_feat_config(uint8_t sw_page, uint8_t *feat_config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define bytes remaining to read */ + uint8_t bytes_remain = BMI2_FEAT_SIZE_IN_BYTES; + + /* Variable to define the read-write length */ + uint8_t read_write_len = 0; + + /* Variable to define the feature configuration address */ + uint8_t addr = BMI2_FEATURES_REG_ADDR; + + /* Variable to define index */ + uint8_t index = 0; + + if (feat_config != NULL) + { + /* Check whether the page is valid */ + if (sw_page < dev->page_max) + { + /* Switch page */ + rslt = bmi2_set_regs(BMI2_FEAT_PAGE_ADDR, &sw_page, 1, dev); + + /* If user length is less than feature length */ + if ((rslt == BMI2_OK) && (dev->read_write_len < BMI2_FEAT_SIZE_IN_BYTES)) + { + /* Read-write should be even */ + if ((dev->read_write_len % 2) != 0) + { + dev->read_write_len--; + } + while (bytes_remain > 0) + { + if (bytes_remain >= dev->read_write_len) + { + /* Read from the page */ + rslt = bmi2_get_regs(addr, &feat_config[index], dev->read_write_len, dev); + + /* Update index */ + index += (uint8_t) dev->read_write_len; + + /* Update address */ + addr += (uint8_t) dev->read_write_len; + + /* Update read-write length */ + read_write_len += (uint8_t) dev->read_write_len; + } + else + { + /* Read from the page */ + rslt = bmi2_get_regs(addr, (uint8_t *) (feat_config + index), (uint16_t) bytes_remain, dev); + + /* Update read-write length */ + read_write_len += bytes_remain; + } + + /* Remaining bytes */ + bytes_remain = BMI2_FEAT_SIZE_IN_BYTES - read_write_len; + if (rslt != BMI2_OK) + { + break; + } + } + + /* Burst read 16 bytes */ + } + else if (rslt == BMI2_OK) + { + /* Get configuration from the page */ + rslt = bmi2_get_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + + } + else + { + rslt = BMI2_E_INVALID_PAGE; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables compensation of the gain defined + * in the GAIN register. + */ +static int8_t enable_gyro_gain(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to define register data */ + uint8_t reg_data = 0; + + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_GAIN_EN, enable); + rslt = bmi2_set_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API corrects the gyroscope cross-axis sensitivity + * between the z and the x axis. + */ +static void comp_gyro_cross_axis_sensitivity(struct bmi2_sens_axes_data *gyr_data, const struct bmi2_dev *dev) +{ + /* Get the compensated gyroscope x-axis */ + gyr_data->x = gyr_data->x - (int16_t)(((int32_t) dev->gyr_cross_sens_zx * (int32_t) gyr_data->z) / 512); +} + +/*! + * @brief This internal API is used to extract the input feature configuration + * details from the look-up table. + */ +static uint8_t extract_input_feat_config(struct bmi2_feature_config *feat_config, + uint8_t type, + const struct bmi2_dev *dev) +{ + /* Variable to define loop */ + uint8_t loop = 0; + + /* Variable to set flag */ + uint8_t feat_found = BMI2_FALSE; + + /* Search for the input feature from the input configuration array */ + while (loop < dev->input_sens) + { + if (dev->feat_config[loop].type == type) + { + *feat_config = dev->feat_config[loop]; + feat_found = BMI2_TRUE; + break; + } + loop++; + } + + /* Return flag */ + return feat_found; +} + +/*! + * @brief This internal API is used to extract the output feature configuration + * details from the look-up table. + */ +static uint8_t extract_output_feat_config(struct bmi2_feature_config *feat_output, + uint8_t type, + const struct bmi2_dev *dev) +{ + /* Variable to define loop */ + uint8_t loop = 0; + + /* Variable to set flag */ + uint8_t feat_found = BMI2_FALSE; + + /* Search for the output feature from the output configuration array */ + while (loop < dev->out_sens) + { + if (dev->feat_output[loop].type == type) + { + *feat_output = dev->feat_output[loop]; + feat_found = BMI2_TRUE; + break; + } + loop++; + } + + /* Return flag */ + return feat_found; +} + +/*! + * @brief This internal API is used to validate the boundary conditions. + */ +static int8_t check_boundary_val(uint8_t *val, uint8_t min, uint8_t max, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + if (val != NULL) + { + /* Check if value is below minimum value */ + if (*val < min) + { + /* Auto correct the invalid value to minimum value */ + *val = min; + dev->info |= BMI2_I_MIN_VALUE; + } + + /* Check if value is above maximum value */ + if (*val > max) + { + /* Auto correct the invalid value to maximum value */ + *val = max; + dev->info |= BMI2_I_MAX_VALUE; + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API saves the configurations before performing FOC. + */ +static int8_t save_accel_foc_config(struct bmi2_accel_config *acc_cfg, + uint8_t *aps, + uint8_t *acc_en, + struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to get the status from PWR_CTRL register */ + uint8_t pwr_ctrl_data = 0; + + /* Get accelerometer configurations to be saved */ + rslt = get_accel_config(acc_cfg, dev); + if (rslt == BMI2_OK) + { + /* Get accelerometer enable status to be saved */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + *acc_en = BMI2_GET_BITS(pwr_ctrl_data, BMI2_ACC_EN); + + /* Get advance power save mode to be saved */ + if (rslt == BMI2_OK) + { + rslt = bmi2_get_adv_power_save(aps, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal sets configurations for performing accelerometer FOC. + */ +static int8_t set_accel_foc_config(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to set the accelerometer configuration value */ + uint8_t acc_conf_data = BMI2_FOC_ACC_CONF_VAL; + + /* Variable to select the sensor */ + uint8_t sens_list = BMI2_ACCEL; + + /* Disabling offset compensation */ + rslt = set_accel_offset_comp(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + /* Set accelerometer configurations to 50Hz, continuous mode, CIC mode */ + rslt = bmi2_set_regs(BMI2_ACC_CONF_ADDR, &acc_conf_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Set accelerometer to normal mode by enabling it */ + rslt = bmi2_sensor_enable(&sens_list, 1, dev); + if (rslt == BMI2_OK) + { + /* Disable advance power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API performs Fast Offset Compensation for accelerometer. + */ +static int8_t perform_accel_foc(const struct accel_foc_g_value *accel_g_value, + const struct bmi2_accel_config *acc_cfg, + struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_E_INVALID_STATUS; + + /* Variable to define count */ + uint8_t loop; + + /* Variable to store status read from the status register */ + uint8_t reg_status = 0; + + /* Array of structure to store accelerometer data */ + struct bmi2_sens_axes_data accel_value[128] = { { 0 } }; + + /* Structure to store accelerometer data temporarily */ + struct foc_temp_value temp = { 0, 0, 0 }; + + /* Structure to store the average of accelerometer data */ + struct bmi2_sens_axes_data accel_avg = { 0, 0, 0, 0 }; + + /* Variable to define LSB per g value */ + uint16_t lsb_per_g = 0; + + /* Variable to define range */ + uint8_t range = 0; + + /* Structure to store accelerometer data deviation from ideal value */ + struct offset_delta delta = { 0, 0, 0 }; + + /* Structure to store accelerometer offset values */ + struct accel_offset offset = { 0, 0, 0 }; + + /* Variable tries max 5 times for interrupt then generates timeout */ + uint8_t try_cnt; + + for (loop = 0; loop < 128; loop++) + { + try_cnt = 5; + while (try_cnt && (!(reg_status & BMI2_DRDY_ACC))) + { + /* 20ms delay for 50Hz ODR */ + dev->delay_us(20000); + rslt = bmi2_get_status(®_status, dev); + try_cnt--; + } + if ((rslt == BMI2_OK) && (reg_status & BMI2_DRDY_ACC)) + { + rslt = read_accel_xyz(&accel_value[loop], dev); + } + + if (rslt == BMI2_OK) + { + rslt = read_accel_xyz(&accel_value[loop], dev); + } + if (rslt == BMI2_OK) + { + /* Store the data in a temporary structure */ + temp.x = temp.x + (int32_t)accel_value[loop].x; + temp.y = temp.y + (int32_t)accel_value[loop].y; + temp.z = temp.z + (int32_t)accel_value[loop].z; + } + else + { + break; + } + } + if (rslt == BMI2_OK) + { + /* Take average of x, y and z data for lesser noise */ + accel_avg.x = (int16_t)(temp.x / 128); + accel_avg.y = (int16_t)(temp.y / 128); + accel_avg.z = (int16_t)(temp.z / 128); + + /* Get the exact range value */ + map_accel_range(acc_cfg->range, &range); + + /* Get the smallest possible measurable acceleration level given the range and + * resolution */ + lsb_per_g = (uint16_t)(power(2, dev->resolution) / (2 * range)); + + /* Compensate acceleration data against gravity */ + comp_for_gravity(lsb_per_g, accel_g_value, &accel_avg, &delta); + + /* Scale according to offset register resolution */ + scale_accel_offset(range, &delta, &offset); + + /* Invert the accelerometer offset data */ + invert_accel_offset(&offset); + + /* Write offset data in the offset compensation register */ + rslt = write_accel_offset(&offset, dev); + + /* Enable offset compensation */ + if (rslt == BMI2_OK) + { + rslt = set_accel_offset_comp(BMI2_ENABLE, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables the offset compensation for + * filtered and un-filtered accelerometer data. + */ +static int8_t set_accel_offset_comp(uint8_t offset_en, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to store data */ + uint8_t data = 0; + + /* Enable/Disable offset compensation */ + rslt = bmi2_get_regs(BMI2_NV_CONF_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + { + data = BMI2_SET_BITS(data, BMI2_NV_ACC_OFFSET, offset_en); + rslt = bmi2_set_regs(BMI2_NV_CONF_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API converts the accelerometer range value into + * corresponding integer value. + */ +static void map_accel_range(uint8_t range_in, uint8_t *range_out) +{ + switch (range_in) + { + case BMI2_ACC_RANGE_2G: + *range_out = 2; + break; + case BMI2_ACC_RANGE_4G: + *range_out = 4; + break; + case BMI2_ACC_RANGE_8G: + *range_out = 8; + break; + case BMI2_ACC_RANGE_16G: + *range_out = 16; + break; + default: + + /* By default RANGE 8G is set */ + *range_out = 8; + break; + } +} + +/*! + * @brief This internal API compensate the accelerometer data against gravity. + */ +static void comp_for_gravity(uint16_t lsb_per_g, + const struct accel_foc_g_value *g_val, + const struct bmi2_sens_axes_data *data, + struct offset_delta *comp_data) +{ + /* Array to store the accelerometer values in LSB */ + int16_t accel_value_lsb[3] = { 0 }; + + /* Convert g-value to LSB */ + accel_value_lsb[BMI2_X_AXIS] = (int16_t)(lsb_per_g * g_val->x); + accel_value_lsb[BMI2_Y_AXIS] = (int16_t)(lsb_per_g * g_val->y); + accel_value_lsb[BMI2_Z_AXIS] = (int16_t)(lsb_per_g * g_val->z); + + /* Get the compensated values for X, Y and Z axis */ + comp_data->x = (data->x - accel_value_lsb[BMI2_X_AXIS]); + comp_data->y = (data->y - accel_value_lsb[BMI2_Y_AXIS]); + comp_data->z = (data->z - accel_value_lsb[BMI2_Z_AXIS]); +} + +/*! + * @brief This internal API scales the compensated accelerometer data according + * to the offset register resolution. + * + * @note The bit position is always greater than 0 since accelerometer data is + * 16 bit wide. + */ +static void scale_accel_offset(uint8_t range, const struct offset_delta *comp_data, struct accel_offset *data) +{ + /* Variable to store the position of bit having 3.9mg resolution */ + int8_t bit_pos_3_9mg; + + /* Variable to store the position previous of bit having 3.9mg resolution */ + int8_t bit_pos_3_9mg_prev_bit; + + /* Variable to store the round-off value */ + uint8_t round_off; + + /* Find the bit position of 3.9mg */ + bit_pos_3_9mg = get_bit_pos_3_9mg(range); + + /* Round off, consider if the next bit is high */ + bit_pos_3_9mg_prev_bit = bit_pos_3_9mg - 1; + round_off = (uint8_t)(power(2, ((uint8_t) bit_pos_3_9mg_prev_bit))); + + /* Scale according to offset register resolution */ + data->x = (uint8_t)((comp_data->x + round_off) / power(2, ((uint8_t) bit_pos_3_9mg))); + data->y = (uint8_t)((comp_data->y + round_off) / power(2, ((uint8_t) bit_pos_3_9mg))); + data->z = (uint8_t)((comp_data->z + round_off) / power(2, ((uint8_t) bit_pos_3_9mg))); +} + +/*! + * @brief This internal API finds the bit position of 3.9mg according to given + * range and resolution. + */ +static int8_t get_bit_pos_3_9mg(uint8_t range) +{ + /* Variable to store the bit position of 3.9mg resolution*/ + int8_t bit_pos_3_9mg; + + /* Variable to shift the bits according to the resolution */ + uint32_t divisor = 1; + + /* Scaling factor to get the bit position of 3.9 mg resolution */ + int16_t scale_factor = -1; + + /* Variable to store temporary value */ + uint16_t temp; + + /* Shift left by the times of resolution */ + divisor = divisor << 16; + + /* Get the bit position to be shifted */ + temp = (uint16_t)(divisor / (range * 256)); + + /* Get the scaling factor until bit position is shifted to last bit */ + while (temp != 1) + { + scale_factor++; + temp = temp >> 1; + } + + /* Scaling factor is the bit position of 3.9 mg resolution */ + bit_pos_3_9mg = (int8_t) scale_factor; + + return bit_pos_3_9mg; +} + +/*! + * @brief This internal API inverts the accelerometer offset data. + */ +static void invert_accel_offset(struct accel_offset *offset_data) +{ + /* Get the offset data */ + offset_data->x = (uint8_t)((offset_data->x) * (-1)); + offset_data->y = (uint8_t)((offset_data->y) * (-1)); + offset_data->z = (uint8_t)((offset_data->z) * (-1)); +} + +/*! + * @brief This internal API writes the offset data in the offset compensation + * register. + */ +static int8_t write_accel_offset(const struct accel_offset *offset, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to store the offset data */ + uint8_t data_array[3] = { 0 }; + + data_array[0] = offset->x; + data_array[1] = offset->y; + data_array[2] = offset->z; + + /* Offset values are written in the offset register */ + rslt = bmi2_set_regs(BMI2_ACC_OFF_COMP_0_ADDR, data_array, 3, dev); + + return rslt; +} + +/*! + * @brief This internal API restores the configurations saved before performing + * accelerometer FOC. + */ +static int8_t restore_accel_foc_config(struct bmi2_accel_config *acc_cfg, + uint8_t aps, + uint8_t acc_en, + struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to get the status from PWR_CTRL register */ + uint8_t pwr_ctrl_data = 0; + + /* Restore the saved accelerometer configurations */ + rslt = set_accel_config(acc_cfg, dev); + if (rslt == BMI2_OK) + { + /* Restore the saved accelerometer enable status */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + if (rslt == BMI2_OK) + { + pwr_ctrl_data = BMI2_SET_BITS(pwr_ctrl_data, BMI2_ACC_EN, acc_en); + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + + /* Restore the saved advance power save */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_adv_power_save(aps, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API saves the configurations before performing gyroscope + * FOC. + */ +static int8_t save_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t *aps, uint8_t *gyr_en, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Variable to get the status from PWR_CTRL register */ + uint8_t pwr_ctrl_data = 0; + + /* Get gyroscope configurations to be saved */ + rslt = get_gyro_config(gyr_cfg, dev); + if (rslt == BMI2_OK) + { + /* Get gyroscope enable status to be saved */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + *gyr_en = BMI2_GET_BITS(pwr_ctrl_data, BMI2_GYR_EN); + + /* Get advance power save mode to be saved */ + if (rslt == BMI2_OK) + { + rslt = bmi2_get_adv_power_save(aps, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal sets configurations for performing gyroscope FOC. + */ +static int8_t set_gyro_foc_config(struct bmi2_dev *dev) +{ + int8_t rslt; + + /* Array to set the gyroscope configuration value (ODR, Performance mode + * and bandwidth) and gyroscope range + */ + uint8_t gyr_conf_data[2] = { BMI2_FOC_GYR_CONF_VAL, BMI2_GYR_RANGE_2000 }; + + /* Variable to select the sensor */ + uint8_t sens_list = BMI2_GYRO; + + /* Disabling gyroscope offset compensation */ + rslt = bmi2_set_gyro_offset_comp(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + { + /* Set gyroscope configurations to 25Hz, continuous mode, + * CIC mode, and 2000 dps range + */ + rslt = bmi2_set_regs(BMI2_GYR_CONF_ADDR, gyr_conf_data, 2, dev); + if (rslt == BMI2_OK) + { + /* Set gyroscope to normal mode by enabling it */ + rslt = bmi2_sensor_enable(&sens_list, 1, dev); + if (rslt == BMI2_OK) + { + /* Disable advance power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API inverts the gyroscope offset data. + */ +static void invert_gyro_offset(struct bmi2_sens_axes_data *offset_data) +{ + /* Invert the values */ + offset_data->x = (int16_t)((offset_data->x) * (-1)); + offset_data->y = (int16_t)((offset_data->y) * (-1)); + offset_data->z = (int16_t)((offset_data->z) * (-1)); +} + +/*! + * @brief This internal API restores the gyroscope configurations saved + * before performing FOC. + */ +static int8_t restore_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t aps, uint8_t gyr_en, struct bmi2_dev *dev) +{ + int8_t rslt; + uint8_t pwr_ctrl_data = 0; + + /* Restore the saved gyroscope configurations */ + rslt = set_gyro_config(gyr_cfg, dev); + if (rslt == BMI2_OK) + { + /* Restore the saved gyroscope enable status */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + if (rslt == BMI2_OK) + { + pwr_ctrl_data = BMI2_SET_BITS(pwr_ctrl_data, BMI2_GYR_EN, gyr_en); + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + + /* Restore the saved advance power save */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_adv_power_save(aps, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API saturates the gyroscope data value before writing to + * to 10 bit offset register. + */ +static void saturate_gyro_data(struct bmi2_sens_axes_data *gyr_off) +{ + if (gyr_off->x > 511) + { + gyr_off->x = 511; + } + if (gyr_off->x < -512) + { + gyr_off->x = -512; + } + if (gyr_off->y > 511) + { + gyr_off->y = 511; + } + if (gyr_off->y < -512) + { + gyr_off->y = -512; + } + if (gyr_off->z > 511) + { + gyr_off->z = 511; + } + if (gyr_off->z < -512) + { + gyr_off->z = -512; + } +} + +/*! + * @brief This internal API is used to validate the device structure pointer for + * null conditions. + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_us == NULL)) + { + /* Device structure pointer is not valid */ + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API is to get the status of st_status from gry_crt_conf register + */ +static int8_t get_st_running(uint8_t *st_status, const struct bmi2_dev *dev) +{ + int8_t rslt; + uint8_t reg_data = 0; + + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Get the status of crt running */ + rslt = bmi2_get_regs(BMI2_GYR_CRT_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + (*st_status) = BMI2_GET_BITS(reg_data, BMI2_GYR_CRT_RUNNING); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API enables/disables the CRT running. + */ +static int8_t set_st_running(uint8_t st_status, struct bmi2_dev *dev) +{ + int8_t rslt; + uint8_t reg_data = 0; + + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + rslt = bmi2_get_regs(BMI2_GYR_CRT_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_CRT_RUNNING, st_status); + rslt = bmi2_set_regs(BMI2_GYR_CRT_CONF_ADDR, ®_data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API gets the status of rdy for dl bit. + */ +static int8_t get_rdy_for_dl(uint8_t *rdy_for_dl, const struct bmi2_dev *dev) +{ + int8_t rslt; + uint8_t reg_data = 0; + + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Get the status of rdy_fo_dl */ + rslt = bmi2_get_regs(BMI2_GYR_CRT_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + (*rdy_for_dl) = BMI2_GET_BITS(reg_data, BMI2_GYR_RDY_FOR_DL); + } + } + else + { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API does the crt process if max burst length is not zero. + */ +static int8_t process_crt_download(uint8_t last_byte_flag, struct bmi2_dev *dev) +{ + int8_t rslt; + uint8_t rdy_for_dl = 0; + uint8_t cmd = BMI2_G_TRIGGER_CMD; + + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + rslt = get_rdy_for_dl(&rdy_for_dl, dev); + } + + /* Trigger next CRT command */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &cmd, 1, dev); + } + if ((!last_byte_flag) && (rslt == BMI2_OK)) + { + rslt = wait_rdy_for_dl_toggle(CRT_READY_FOR_DOWNLOAD_RETRY, rdy_for_dl, dev); + } + + return rslt; +} + +/*! + * @brief This API to write the 2kb size of crt configuration + */ +static int8_t write_crt_config_file(uint16_t write_len, + uint16_t config_file_size, + uint16_t start_index, + struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint16_t index = 0; + uint8_t last_byte_flag = 0; + uint8_t remain = (uint8_t)(config_file_size % write_len); + uint16_t balance_byte = 0; + + if (!remain) + { + + /* Write the configuration file */ + for (index = start_index; + (index < (start_index + config_file_size)) && (rslt == BMI2_OK); + index += write_len) + { + rslt = upload_file((dev->config_file_ptr + index), index, write_len, dev); + if (index >= ((start_index + config_file_size) - (write_len))) + { + last_byte_flag = 1; + } + + if (rslt == BMI2_OK) + { + rslt = process_crt_download(last_byte_flag, dev); + } + } + } + else + { + /* Get the balance bytes */ + balance_byte = (uint16_t)start_index + (uint16_t)config_file_size - (uint16_t)remain; + + /* Write the configuration file for the balance bytes */ + for (index = start_index; (index < balance_byte) && (rslt == BMI2_OK); index += write_len) + { + rslt = upload_file((dev->config_file_ptr + index), index, write_len, dev); + if (rslt == BMI2_OK) + { + rslt = process_crt_download(last_byte_flag, dev); + } + } + if (rslt == BMI2_OK) + { + /* Write the remaining bytes in 2 bytes length */ + write_len = 2; + rslt = set_maxburst_len(write_len, dev); + + /* Write the configuration file for the remaining bytes */ + for (index = balance_byte; + (index < (start_index + config_file_size)) && (rslt == BMI2_OK); + index += write_len) + { + rslt = upload_file((dev->config_file_ptr + index), index, write_len, dev); + if (index < ((start_index + config_file_size) - write_len)) + { + last_byte_flag = 1; + } + if (rslt == BMI2_OK) + { + rslt = process_crt_download(last_byte_flag, dev); + } + } + } + } + + return rslt; +} + +/*! + * @brief This API is to wait till the rdy for dl bit toggles after every pack of bytes. + */ +static int8_t wait_rdy_for_dl_toggle(uint8_t retry_complete, uint8_t download_ready, const struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint8_t dl_ready = 0; + uint8_t st_status = 0; + + while ((rslt == BMI2_OK) && (retry_complete--)) + { + rslt = get_rdy_for_dl(&dl_ready, dev); + if (download_ready != dl_ready) + { + break; + } + dev->delay_us(CRT_READY_FOR_DOWNLOAD_US); + } + if ((rslt == BMI2_OK) && (download_ready == dl_ready)) + { + rslt = BMI2_E_CRT_READY_FOR_DL_FAIL_ABORT; + } + if (rslt == BMI2_OK) + { + rslt = get_st_running(&st_status, dev); + if ((rslt == BMI2_OK) && (st_status == 0)) + { + rslt = BMI2_E_ST_ALREADY_RUNNING; + } + + } + + return rslt; +} + +/*! + * @brief This API is to wait till crt status complete. + */ +static int8_t wait_st_running(uint8_t retry_complete, const struct bmi2_dev *dev) +{ + uint8_t st_status = 1; + int8_t rslt = BMI2_OK; + + while (retry_complete--) + { + rslt = get_st_running(&st_status, dev); + if ((rslt == BMI2_OK) && (st_status == 0)) + { + break; + } + dev->delay_us(CRT_WAIT_RUNNING_US); + } + if ((rslt == BMI2_OK) && (st_status == 1)) + { + rslt = BMI2_E_ST_ALREADY_RUNNING; + } + + return rslt; +} + +/*! + * @brief This api is used to perform gyroscope self-test. + */ +int8_t bmi2_do_gyro_st(struct bmi2_dev *dev) +{ + int8_t rslt; + + rslt = do_gtrigger_test(BMI2_SELECT_GYRO_SELF_TEST, dev); + + return rslt; +} + +/*! + * @brief This API is to run the CRT process for both max burst length 0 and non zero condition. + */ +int8_t bmi2_do_crt(struct bmi2_dev *dev) +{ + int8_t rslt; + + rslt = do_gtrigger_test(BMI2_SELECT_CRT, dev); + + return rslt; +} + +/*! + * @brief This API is to run the crt process for both max burst length 0 and non zero condition. + */ +static int8_t do_gtrigger_test(uint8_t gyro_st_crt, struct bmi2_dev *dev) +{ + int8_t rslt; + int8_t rslt_crt = BMI2_OK; + uint8_t st_status = 0; + uint8_t max_burst_length = 0; + uint8_t download_ready = 0; + uint8_t cmd = BMI2_G_TRIGGER_CMD; + struct bmi2_gyro_self_test_status gyro_st_result = { 0 }; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Check if the variant supports this feature */ + if (dev->variant_feature & BMI2_CRT_RTOSK_ENABLE) + { + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + /* Get max burst length */ + if (rslt == BMI2_OK) + { + rslt = get_maxburst_len(&max_burst_length, dev); + } + + /* Checking for CRT running status */ + if (rslt == BMI2_OK) + { + rslt = get_st_running(&st_status, dev); + } + + /* CRT is not running and Max burst length is zero */ + if (st_status == 0) + { + if (rslt == BMI2_OK) + { + rslt = set_st_running(BMI2_ENABLE, dev); + } + + /* Preparing the setup */ + if (rslt == BMI2_OK) + { + rslt = crt_prepare_setup(dev); + } + + /* Enable the gyro self-test, CRT */ + if (rslt == BMI2_OK) + { + rslt = select_self_test(gyro_st_crt, dev); + } + + /* Check if FIFO is unchanged by checking the max burst length */ + if ((rslt == BMI2_OK) && (max_burst_length == 0)) + { + /* Trigger CRT */ + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &cmd, 1, dev); + if (rslt == BMI2_OK) + { + /* Wait until st_status = 0 or time out is 2 seconds */ + rslt = wait_st_running(CRT_WAIT_RUNNING_RETRY_EXECUTION, dev); + + /* CRT Running wait & check is successful */ + if (rslt == BMI2_OK) + { + rslt = crt_gyro_st_update_result(dev); + } + } + } + else + { + /* FIFO may be used */ + if (rslt == BMI2_OK) + { + if (dev->read_write_len < 2) + { + dev->read_write_len = 2; + } + if (dev->read_write_len > (CRT_MAX_BURST_WORD_LENGTH * 2)) + { + dev->read_write_len = CRT_MAX_BURST_WORD_LENGTH * 2; + } + + /* Reset the max burst length to default value */ + rslt = set_maxburst_len(dev->read_write_len, dev); + } + if (rslt == BMI2_OK) + { + rslt = get_rdy_for_dl(&download_ready, dev); + } + + /* Trigger CRT */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &cmd, 1, dev); + } + + /* Wait till either ready for download toggle or crt running = 0 */ + if (rslt == BMI2_OK) + { + rslt = wait_rdy_for_dl_toggle(CRT_READY_FOR_DOWNLOAD_RETRY, download_ready, dev); + if (rslt == BMI2_OK) + { + rslt = write_crt_config_file(dev->read_write_len, BMI2_CRT_CONFIG_FILE_SIZE, 0x1800, dev); + } + if (rslt == BMI2_OK) + { + rslt = wait_st_running(CRT_WAIT_RUNNING_RETRY_EXECUTION, dev); + rslt_crt = crt_gyro_st_update_result(dev); + if (rslt == BMI2_OK) + { + rslt = rslt_crt; + } + } + } + } + } + else + { + rslt = BMI2_E_ST_ALREADY_RUNNING; + } + + if (rslt == BMI2_OK) + { + if (gyro_st_crt == BMI2_SELECT_GYRO_SELF_TEST) + { + rslt = gyro_self_test_completed(&gyro_st_result, dev); + } + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This API to set up environment for processing the crt. + */ +static int8_t crt_prepare_setup(struct bmi2_dev *dev) +{ + int8_t rslt; + + /* Variable to select the sensor */ + uint8_t sens_list = BMI2_GYRO; + + rslt = null_ptr_check(dev); + + if (rslt == BMI2_OK) + { + /* Disable gyroscope */ + rslt = bmi2_sensor_disable(&sens_list, 1, dev); + } + + /* Disable FIFO for all sensors */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_fifo_config(BMI2_FIFO_ALL_EN, BMI2_DISABLE, dev); + } + + if (rslt == BMI2_OK) + { + /* Enable accelerometer */ + sens_list = BMI2_ACCEL; + rslt = bmi2_sensor_enable(&sens_list, 1, dev); + } + if (rslt == BMI2_OK) + { + /* Disable Abort after 1 msec */ + dev->delay_us(1000); + rslt = abort_bmi2(BMI2_DISABLE, dev); + } + + return rslt; +} + +/*! + * @brief This API is to update the CRT or gyro self-test final result. + */ +static int8_t crt_gyro_st_update_result(struct bmi2_dev *dev) +{ + int8_t rslt; + struct bmi2_gyr_user_gain_status user_gain_stat = { 0, 0, 0, 0 }; + + rslt = null_ptr_check(dev); + + /* CRT status has to be read from the config register map */ + if (rslt == BMI2_OK) + { + rslt = get_gyro_gain_update_status(&user_gain_stat, dev); + } + if (rslt == BMI2_OK) + { + switch (user_gain_stat.g_trigger_status) + { + case BMI2_G_TRIGGER_NO_ERROR: + + /* CRT is successful - Reset the Max Burst Length */ + rslt = set_maxburst_len(0, dev); + break; + + case BMI2_G_TRIGGER_DL_ERROR: + + /* CRT is Download Error - Keep non zero value for Max Burst Length */ + rslt = set_maxburst_len(dev->read_write_len, dev); + if (rslt == BMI2_OK) + { + rslt = BMI2_E_DL_ERROR; + } + break; + case BMI2_G_TRIGGER_ABORT_ERROR: + + /* Command is aborted either by host via the block bit or due to motion + * detection. Keep non zero value for Max Burst Length + */ + rslt = set_maxburst_len(dev->read_write_len, dev); + if (rslt == BMI2_OK) + { + rslt = BMI2_E_ABORT_ERROR; + } + break; + + case BMI2_G_TRIGGER_PRECON_ERROR: + + /* Pre-condition to start the feature was not completed. */ + rslt = BMI2_E_PRECON_ERROR; + break; + + default: + rslt = BMI2_E_INVALID_STATUS; + + break; + } + } + + return rslt; +} + +/*! + * @brief This internal API gets the max burst length. + */ +static int8_t get_maxburst_len(uint8_t *max_burst_len, struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + uint8_t idx = 0; + uint8_t feat_found = 0; + struct bmi2_feature_config maxburst_length_bytes = { 0, 0, 0 }; + uint8_t aps_stat; + + if ((dev->variant_feature & BMI2_CRT_IN_FIFO_NOT_REQ) != 0) + { + *max_burst_len = 0; + + return BMI2_OK; + } + + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Search for max burst length */ + feat_found = extract_input_feat_config(&maxburst_length_bytes, BMI2_MAX_BURST_LEN, dev); + if (feat_found) + { + rslt = get_feat_config(maxburst_length_bytes.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for max burst length */ + idx = maxburst_length_bytes.start_addr; + + /* Get the max burst length */ + *max_burst_len = feat_config[idx]; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API sets the max burst length. + */ +static int8_t set_maxburst_len(const uint16_t write_len_byte, struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + uint8_t idx = 0; + uint8_t reg_addr = 0; + uint8_t max_burst_len = 0; + uint8_t feat_found = 0; + struct bmi2_feature_config maxburst_length_bytes = { 0, 0, 0 }; + uint8_t aps_stat; + uint16_t burst_len = write_len_byte / 2; + + /* for variant that support crt outside fifo, do not modify the max burst len */ + if ((dev->variant_feature & BMI2_CRT_IN_FIFO_NOT_REQ) != 0) + { + return BMI2_OK; + } + + /* Max burst length is only 1 byte */ + if (burst_len > CRT_MAX_BURST_WORD_LENGTH) + { + max_burst_len = UINT8_C(0xFF); + } + else + { + max_burst_len = (uint8_t)burst_len; + } + + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Search for axis-re-mapping and extract its configuration details */ + feat_found = extract_input_feat_config(&maxburst_length_bytes, BMI2_MAX_BURST_LEN, dev); + if (feat_found) + { + /* Get the configuration from the page where axis + * re-mapping feature resides + */ + rslt = get_feat_config(maxburst_length_bytes.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes */ + idx = maxburst_length_bytes.start_addr; + + /* update Max burst length */ + feat_config[idx] = max_burst_len; + + /* Update the register address */ + reg_addr = BMI2_FEATURES_REG_ADDR + maxburst_length_bytes.start_addr; + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(reg_addr, &feat_config[maxburst_length_bytes.start_addr], 2, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + + return rslt; +} + +/*! + * @brief This api is used to trigger the preparation for system for NVM programming. + */ +static int8_t set_nvm_prep_prog(uint8_t nvm_prep, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + uint8_t reg_addr = 0; + + /* Initialize feature configuration for nvm preparation*/ + struct bmi2_feature_config nvm_config = { 0, 0, 0 }; + + /* Search for bmi2 gyro self offset correction feature as nvm program preparation feature is + * present in the same Word and extract its configuration details + */ + feat_found = extract_input_feat_config(&nvm_config, BMI2_NVM_PROG_PREP, dev); + if (feat_found) + { + /* Get the configuration from the page where nvm preparation feature enable feature + * resides */ + rslt = get_feat_config(nvm_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for nvm preparation feature enable */ + idx = nvm_config.start_addr; + + /* update nvm_prog_prep enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], NVM_PREP_FEATURE_EN, nvm_prep); + + /* Update the register address */ + reg_addr = BMI2_FEATURES_REG_ADDR + nvm_config.start_addr - 1; + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(reg_addr, &feat_config[nvm_config.start_addr - 1], 2, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This api is used to enable the CRT. + */ +static int8_t select_self_test(uint8_t gyro_st_crt, struct bmi2_dev *dev) +{ + int8_t rslt; + + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + uint8_t idx = 0; + + uint8_t feat_found; + uint8_t reg_addr = 0; + + struct bmi2_feature_config gyro_self_test_crt_config = { 0, 0, 0 }; + + /* Search for bmi2 crt gyro self-test feature and extract its configuration details */ + feat_found = extract_input_feat_config(&gyro_self_test_crt_config, BMI2_CRT_GYRO_SELF_TEST, dev); + if (feat_found) + { + /* Get the configuration from the page where gyro self-test and crt enable feature + * resides */ + rslt = get_feat_config(gyro_self_test_crt_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes */ + idx = gyro_self_test_crt_config.start_addr; + + /* update the gyro self-test crt enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], GYRO_SELF_TEST_CRT_EN, gyro_st_crt); + + /* Update the register address */ + reg_addr = BMI2_FEATURES_REG_ADDR + (gyro_self_test_crt_config.start_addr - 1); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(reg_addr, &feat_config[gyro_self_test_crt_config.start_addr - 1], 2, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This api is used to abort ongoing crt or gyro self-test. + */ +int8_t bmi2_abort_crt_gyro_st(struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + uint8_t aps_stat; + uint8_t st_running = 0; + uint8_t cmd = BMI2_G_TRIGGER_CMD; + + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + /* Checking for ST running status */ + if (rslt == BMI2_OK) + { + rslt = get_st_running(&st_running, dev); + if (rslt == BMI2_OK) + { + /* ST is not running */ + if (st_running == 0) + { + rslt = BMI2_E_ST_NOT_RUNING; + } + } + } + if (rslt == BMI2_OK) + { + rslt = abort_bmi2(BMI2_ENABLE, dev); + } + + /* send the g trigger command */ + if (rslt == BMI2_OK) + { + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &cmd, 1, dev); + } + if (rslt == BMI2_OK) + { + /* wait until st_status = 0 or time out is 2 seconds */ + rslt = wait_st_running(CRT_WAIT_RUNNING_RETRY_EXECUTION, dev); + } + + /* Check G trigger status for error */ + if (rslt == BMI2_OK) + { + rslt = crt_gyro_st_update_result(dev); + if (rslt == BMI2_E_ABORT_ERROR) + { + rslt = BMI2_OK; + } + else + { + rslt = BMI2_E_ABORT_ERROR; + } + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + + return rslt; +} + +/*! + * @brief This api is used to enable/disable abort. + */ +static int8_t abort_bmi2(uint8_t abort_enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + uint8_t reg_addr = 0; + + /* Initialize feature configuration for blocking a feature */ + struct bmi2_feature_config block_config = { 0, 0, 0 }; + + /* Search for bmi2 Abort feature and extract its configuration details */ + feat_found = extract_input_feat_config(&block_config, BMI2_ABORT_CRT_GYRO_SELF_TEST, dev); + if (feat_found) + { + /* Get the configuration from the page where abort(block) feature resides */ + rslt = get_feat_config(block_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes */ + idx = block_config.start_addr; + + /* update the gyro self-test crt abort enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], ABORT_FEATURE_EN, abort_enable); + + /* Update the register address */ + reg_addr = BMI2_FEATURES_REG_ADDR + (block_config.start_addr - 1); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(reg_addr, &feat_config[block_config.start_addr - 1], 2, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This api is use to wait till gyro self-test is completed and update the status of gyro + * self-test. + */ +static int8_t gyro_self_test_completed(struct bmi2_gyro_self_test_status *gyro_st_result, const struct bmi2_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + rslt = bmi2_get_regs(BMI2_GYR_SELF_TEST_AXES_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + gyro_st_result->gyr_st_axes_done = BMI2_GET_BIT_POS0(reg_data, BMI2_GYR_ST_AXES_DONE); + if (gyro_st_result->gyr_st_axes_done == 0x01) + { + gyro_st_result->gyr_axis_x_ok = BMI2_GET_BITS(reg_data, BMI2_GYR_AXIS_X_OK); + gyro_st_result->gyr_axis_y_ok = BMI2_GET_BITS(reg_data, BMI2_GYR_AXIS_Y_OK); + gyro_st_result->gyr_axis_z_ok = BMI2_GET_BITS(reg_data, BMI2_GYR_AXIS_Z_OK); + } + else + { + rslt = BMI2_E_SELF_TEST_NOT_DONE; + } + } + + return rslt; +} + +/*! + * @brief This api validates accel foc position as per the range + */ +static int8_t validate_foc_position(uint8_t sens_list, + const struct accel_foc_g_value *accel_g_axis, + struct bmi2_sens_axes_data avg_foc_data, + struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_E_INVALID_INPUT; + + if (sens_list == BMI2_ACCEL) + { + if (accel_g_axis->x == 1) + { + rslt = validate_foc_accel_axis(avg_foc_data.x, dev); + } + else if (accel_g_axis->y == 1) + { + rslt = validate_foc_accel_axis(avg_foc_data.y, dev); + } + else + { + rslt = validate_foc_accel_axis(avg_foc_data.z, dev); + } + } + else if (sens_list == BMI2_GYRO) + { + if (((avg_foc_data.x >= GYRO_FOC_NOISE_LIMIT_NEGATIVE) && (avg_foc_data.x <= GYRO_FOC_NOISE_LIMIT_POSITIVE)) && + ((avg_foc_data.y >= GYRO_FOC_NOISE_LIMIT_NEGATIVE) && (avg_foc_data.y <= GYRO_FOC_NOISE_LIMIT_POSITIVE)) && + ((avg_foc_data.z >= GYRO_FOC_NOISE_LIMIT_NEGATIVE) && (avg_foc_data.z <= GYRO_FOC_NOISE_LIMIT_POSITIVE))) + { + rslt = BMI2_OK; + } + else + { + rslt = BMI2_E_INVALID_FOC_POSITION; + } + } + + return rslt; +} + +/*! + * @brief This api validates depends on accel foc access input + */ +static int8_t validate_foc_accel_axis(int16_t avg_foc_data, struct bmi2_dev *dev) +{ + struct bmi2_sens_config sens_cfg = { 0 }; + uint8_t range; + int8_t rslt; + + sens_cfg.type = BMI2_ACCEL; + rslt = bmi2_get_sensor_config(&sens_cfg, 1, dev); + range = sens_cfg.cfg.acc.range; + + /* reference LSB value of 16G */ + if ((range == BMI2_ACC_RANGE_2G) && (avg_foc_data > ACC_2G_MIN_NOISE_LIMIT) && + (avg_foc_data < ACC_2G_MAX_NOISE_LIMIT)) + { + rslt = BMI2_OK; + } + /* reference LSB value of 16G */ + else if ((range == BMI2_ACC_RANGE_4G) && (avg_foc_data > ACC_4G_MIN_NOISE_LIMIT) && + (avg_foc_data < ACC_4G_MAX_NOISE_LIMIT)) + { + rslt = BMI2_OK; + } + /* reference LSB value of 16G */ + else if ((range == BMI2_ACC_RANGE_8G) && (avg_foc_data > ACC_8G_MIN_NOISE_LIMIT) && + (avg_foc_data < ACC_8G_MAX_NOISE_LIMIT)) + { + rslt = BMI2_OK; + } + /* reference LSB value of 16G */ + else if ((range == BMI2_ACC_RANGE_16G) && (avg_foc_data > ACC_16G_MIN_NOISE_LIMIT) && + (avg_foc_data < ACC_16G_MAX_NOISE_LIMIT)) + { + rslt = BMI2_OK; + } + else + { + rslt = BMI2_E_INVALID_FOC_POSITION; + } + + return rslt; +} + +/*! @brief This api is used for programming the non volatile memory(nvm) */ +int8_t bmi2_nvm_prog(struct bmi2_dev *dev) +{ + int8_t rslt = BMI2_OK; + + /* Variable to get the status of advance power save */ + uint8_t aps_stat; + uint8_t status; + uint8_t cmd_rdy; + uint8_t reg_data; + uint8_t write_timeout = 100; + + /* Get status of advance power save mode */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + /* Check the Write status and proceed only if there is no ongoing write cycle */ + if (rslt == BMI2_OK) + { + rslt = bmi2_get_status(&status, dev); + + cmd_rdy = BMI2_GET_BITS(status, BMI2_CMD_RDY); + if (cmd_rdy) + { + rslt = set_nvm_prep_prog(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + { + dev->delay_us(40000); + + /* Set the NVM_CONF.nvm_prog_en bit in order to enable the NVM + * programming */ + reg_data = BMI2_NVM_UNLOCK_ENABLE; + rslt = bmi2_set_regs(BMI2_NVM_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + { + /* Send NVM prog command to command register */ + reg_data = BMI2_NVM_PROG_CMD; + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, ®_data, 1, dev); + } + + /* Wait till write operation is completed */ + if (rslt == BMI2_OK) + { + while (write_timeout--) + { + rslt = bmi2_get_status(&status, dev); + if (rslt == BMI2_OK) + { + cmd_rdy = BMI2_GET_BITS(status, BMI2_CMD_RDY); + + /* Nvm is complete once cmd_rdy is 1, break if 1 */ + if (cmd_rdy) + { + break; + } + + /* Wait till cmd_rdy becomes 1 indicating + * nvm process completes */ + dev->delay_us(20000); + } + } + } + if ((rslt == BMI2_OK) && (cmd_rdy != BMI2_TRUE)) + { + rslt = BMI2_E_WRITE_CYCLE_ONGOING; + } + } + } + else + { + rslt = BMI2_E_WRITE_CYCLE_ONGOING; + } + } + if (rslt == BMI2_OK) + { + /* perform soft reset */ + rslt = bmi2_soft_reset(dev); + } + + /* Enable Advance power save if disabled while configuring and not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + + return rslt; +} + +/*! + * @brief This API reads and provides average for 128 samples of sensor data for foc operation + * gyro. + */ +static int8_t get_average_of_sensor_data(uint8_t sens_list, struct foc_temp_value *temp_foc_data, struct bmi2_dev *dev) +{ + int8_t rslt = 0; + struct bmi2_sensor_data sensor_data = { 0 }; + uint8_t sample_count = 0; + uint8_t datardy_try_cnt; + uint8_t drdy_status = 0; + uint8_t sensor_drdy = 0; + + sensor_data.type = sens_list; + if (sens_list == BMI2_ACCEL) + { + sensor_drdy = BMI2_DRDY_ACC; + } + else + { + sensor_drdy = BMI2_DRDY_GYR; + } + + /* Read sensor values before FOC */ + while (sample_count < BMI2_FOC_SAMPLE_LIMIT) + { + datardy_try_cnt = 5; + do + { + dev->delay_us(20000); + rslt = bmi2_get_status(&drdy_status, dev); + datardy_try_cnt--; + } while ((rslt == BMI2_OK) && (!(drdy_status & sensor_drdy)) && (datardy_try_cnt)); + + if ((rslt != BMI2_OK) || (datardy_try_cnt == 0)) + { + rslt = BMI2_E_DATA_RDY_INT_FAILED; + break; + } + rslt = bmi2_get_sensor_data(&sensor_data, 1, dev); + + if (rslt == BMI2_OK) + { + if (sensor_data.type == BMI2_ACCEL) + { + temp_foc_data->x += sensor_data.sens_data.acc.x; + temp_foc_data->y += sensor_data.sens_data.acc.y; + temp_foc_data->z += sensor_data.sens_data.acc.z; + } + else if (sensor_data.type == BMI2_GYRO) + { + temp_foc_data->x += sensor_data.sens_data.gyr.x; + temp_foc_data->y += sensor_data.sens_data.gyr.y; + temp_foc_data->z += sensor_data.sens_data.gyr.z; + } + } + else + { + break; + } + sample_count++; + } + if (rslt == BMI2_OK) + { + temp_foc_data->x = (temp_foc_data->x / BMI2_FOC_SAMPLE_LIMIT); + temp_foc_data->y = (temp_foc_data->y / BMI2_FOC_SAMPLE_LIMIT); + temp_foc_data->z = (temp_foc_data->z / BMI2_FOC_SAMPLE_LIMIT); + } + + return rslt; +} + +/*! + * @brief This internal API sets primary OIS configurations for + * selecting filter cut-off frequency . + */ +static int8_t set_primary_ois_config(const struct bmi2_primary_ois_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define count */ + uint8_t i = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for primary OIS */ + struct bmi2_feature_config primary_ois_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *)(void *)feat_config; + + /* Search for priamry OIS feature and extract its configuration details */ + feat_found = extract_input_feat_config(&primary_ois_config, BMI2_PRIMARY_OIS, dev); + if (feat_found) + { + /* Get the configuration from the page where primary OIS feature resides */ + rslt = get_feat_config(primary_ois_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for priamry OIS select */ + idx = primary_ois_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Enable lp filter */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), LP_FILTER_EN, config->lp_filter_enable); + + /* Set lp filter cut-off frequency */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), LP_FILTER_CONFIG, config->lp_filter_config); + + /* Enable Gyro on OIS */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), PRIMARY_OIS_GYR_EN, config->primary_ois_gyro_en); + + /* Enable Accel on OIS */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), PRIMARY_OIS_ACC_EN, config->primary_ois_accel_en); + + /* Increment offset by 1 more word to get the total length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - primary_ois_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[primary_ois_config.start_addr + + i] = *((uint8_t *)data_p + primary_ois_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets priamry OIS configurations for + * low pass cut-off frequency. + */ +static int8_t get_primary_ois_config(struct bmi2_primary_ois_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for primary OIS */ + struct bmi2_feature_config primary_ois_config = { 0, 0, 0 }; + + /* Search for primary OIS feature and extract its configuration details */ + feat_found = extract_input_feat_config(&primary_ois_config, BMI2_PRIMARY_OIS, dev); + if (feat_found) + { + /* Get the configuration from the page where primary OIS feature resides */ + rslt = get_feat_config(primary_ois_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for feature enable for primary OIS */ + idx = primary_ois_config.start_addr; + + /* Get word to calculate filter state, cut-off frequency, gyro-OIS, + * accel-OIS select */ + lsb = (uint16_t)feat_config[idx++]; + + /* Get low pass filter state */ + config->lp_filter_enable = lsb & LP_FILTER_EN_MASK; + + /* Get lp filter cut-off frequency */ + config->lp_filter_config = (lsb & LP_FILTER_CONFIG_MASK) >> LP_FILTER_CONFIG_POS; + + /* Get primary OIS gyro on ois state */ + config->primary_ois_gyro_en = (lsb & PRIMARY_OIS_GYR_EN_MASK) >> PRIMARY_OIS_GYR_EN_POS; + + /* Get primary OIS accel on ois state */ + config->primary_ois_accel_en = (lsb & PRIMARY_OIS_ACC_EN_MASK) >> PRIMARY_OIS_ACC_EN_POS; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API extract the identification feature from the DMR page + * and retrieve the config file major and minor version. + */ +static int8_t extract_config_file(uint16_t *config_major, uint8_t *config_minor, struct bmi2_dev *dev) +{ + /* Variable to define the result */ + int8_t rslt = BMI2_OK; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Variable to define advance power save mode status */ + uint8_t aps_stat; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Initialize feature configuration for config file identification */ + struct bmi2_feature_config config_id = { 0, 0, 0 }; + + /* Check the power mode status */ + aps_stat = dev->aps_status; + if (aps_stat == BMI2_ENABLE) + { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + if (rslt == BMI2_OK) + { + /* Search for config file identification feature and extract its configuration + * details */ + feat_found = extract_input_feat_config(&config_id, BMI2_CONFIG_ID, dev); + if (feat_found) + { + /* Get the configuration from the page where config file identification + * feature resides */ + rslt = get_feat_config(config_id.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset for config file identification */ + idx = config_id.start_addr; + + /* Get word to calculate config file identification */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get major and minor version */ + *config_major = BMI2_GET_BITS(lsb_msb, BMI2_CONFIG_MAJOR); + *config_minor = BMI2_GET_BIT_POS0(lsb, BMI2_CONFIG_MINOR); + } + } + + /* Enable Advance power save if disabled while configuring and + * not when already disabled + */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + { + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output data of OIS. + */ +static int8_t get_ois_output(struct bmi2_ois_output *ois_output, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variables to store MSB value */ + uint8_t msb = 0; + + /* Variables to store LSB value */ + uint8_t lsb = 0; + + /* Variables to store both MSB and LSB value */ + uint16_t lsb_msb = 0; + + /* Variables to define index */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for OIS */ + struct bmi2_feature_config ois_config = { 0, 0, 0 }; + + /* Search for OIS output feature and extract its configuration details */ + feat_found = extract_output_feat_config(&ois_config, BMI2_OIS_OUTPUT, dev); + if (feat_found) + { + /* Get the feature output configuration for OIS */ + rslt = get_feat_config(ois_config.page, feat_config, dev); + + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for OIS output start address */ + idx = ois_config.start_addr; + + /* Read OIS accel x axis */ + lsb = feat_config[idx++]; + msb = feat_config[idx++]; + lsb_msb = (uint16_t)lsb | (uint16_t)msb << 8; + ois_output->ois_acc_x = (int16_t)lsb_msb; + + /* Read OIS accel y axis */ + lsb = feat_config[idx++]; + msb = feat_config[idx++]; + lsb_msb = (uint16_t)lsb | (uint16_t)msb << 8; + ois_output->ois_acc_y = (int16_t)lsb_msb; + + /* Read OIS accel z axis */ + lsb = feat_config[idx++]; + msb = feat_config[idx++]; + lsb_msb = (uint16_t)lsb | (uint16_t)msb << 8; + ois_output->ois_acc_z = (int16_t)lsb_msb; + + /* Read OIS gyro x axis */ + lsb = feat_config[idx++]; + msb = feat_config[idx++]; + lsb_msb = (uint16_t)lsb | (uint16_t)msb << 8; + ois_output->ois_gyro_x = (int16_t)lsb_msb; + + /* Read OIS gyro y axis */ + lsb = feat_config[idx++]; + msb = feat_config[idx++]; + lsb_msb = (uint16_t)lsb | (uint16_t)msb << 8; + ois_output->ois_gyro_y = (int16_t)lsb_msb; + + /* Read OIS gyro z axis */ + lsb = feat_config[idx++]; + msb = feat_config[idx++]; + lsb_msb = (uint16_t)lsb | (uint16_t)msb << 8; + ois_output->ois_gyro_z = (int16_t)lsb_msb; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable free-fall detection feature. + */ +static int8_t set_free_fall_det(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for free-fall detection */ + struct bmi2_feature_config freefall_config = { 0, 0, 0 }; + + /* Search for free-fall detection feature and extract its configuration details */ + feat_found = extract_input_feat_config(&freefall_config, BMI2_FREE_FALL_DET, dev); + if (feat_found) + { + /* Get the configuration from the page where free-fall detection feature resides */ + rslt = get_feat_config(freefall_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Assign the offset address for free-fall detection */ + idx = freefall_config.start_addr; + + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], FREE_FALL_DET_FEAT_EN, enable); + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets free-fall detection configurations like + * free-fall accel settings, and output configuration. + */ +static int8_t set_free_fall_det_config(const struct bmi2_free_fall_det_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define index */ + uint8_t i = 0; + + /* Variable to define set accel settings in loop */ + uint8_t indx; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for free-fall */ + struct bmi2_feature_config freefall_config = { 0, 0, 0 }; + + /* Copy the feature configuration address to a local pointer */ + uint16_t *data_p = (uint16_t *) (void *)feat_config; + + /* Search for free-fall detection feature and extract its configuration details */ + feat_found = extract_input_feat_config(&freefall_config, BMI2_FREE_FALL_DET, dev); + if (feat_found) + { + /* Get the configuration from the page where low-g feature resides */ + rslt = get_feat_config(freefall_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for free-fall detection select */ + idx = freefall_config.start_addr; + + /* Get offset in words since all the features are set in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FREE_FALL_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to set free-fall detection accel settings 1 configuration */ + idx++; + + /* Set the free-fall accel param settings */ + for (indx = 0; indx < BMI2_FREE_FALL_ACCEL_SET_PARAMS; indx++) + { + /* Set free-fall detection accel settings */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), + FREE_FALL_ACCEL_SETT, + config->freefall_accel_settings[indx]); + + /* Increment offset by 1 more word to set free-fall detection accel settings configuration */ + idx++; + } + + /* Get total length in bytes to copy from local pointer to the array */ + idx = (uint8_t)(idx * 2) - freefall_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) + { + feat_config[freefall_config.start_addr + i] = *((uint8_t *) data_p + freefall_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) + { + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.freefall_out_conf = (uint8_t) config->out_conf; + } + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets free-fall detection configurations like + * free-fall detection accel settings, and output configuration. + */ +static int8_t get_free_fall_det_config(struct bmi2_free_fall_det_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = { 0 }; + + /* Variable to define the array offset */ + uint8_t idx = 0; + + /* Variable to define get accel settings in loop */ + uint8_t indx; + + /* Variable to define LSB */ + uint16_t lsb = 0; + + /* Variable to define MSB */ + uint16_t msb = 0; + + /* Variable to define a word */ + uint16_t lsb_msb = 0; + + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for free-fall detection */ + struct bmi2_feature_config freefall_config = { 0, 0, 0 }; + + /* Search for free-fall detection feature and extract its configuration details */ + feat_found = extract_input_feat_config(&freefall_config, BMI2_FREE_FALL_DET, dev); + if (feat_found) + { + /* Get the configuration from the page where free-fall detection feature resides */ + rslt = get_feat_config(freefall_config.page, feat_config, dev); + if (rslt == BMI2_OK) + { + /* Define the offset in bytes for free-fall detection select */ + idx = freefall_config.start_addr; + + /* Get word to calculate out conf */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get out conf */ + config->out_conf = (lsb_msb & FREE_FALL_OUT_CONF_MASK) >> FREE_FALL_OUT_CONF_POS; + + /* Get the free-fall accel param settings */ + for (indx = 0; indx < BMI2_FREE_FALL_ACCEL_SET_PARAMS; indx++) + { + /* Get word to calculate free-fall detection accel settings */ + lsb = (uint16_t) feat_config[idx++]; + msb = ((uint16_t) feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get free-fall detection accel settings */ + config->freefall_accel_settings[indx] = lsb_msb & FREE_FALL_ACCEL_SETT_MASK; + } + + /* Copy out_conf value to a local copy in device structure */ + dev->int_map.freefall_out_conf = (uint8_t) config->out_conf; + } + } + else + { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} diff --git a/drivers/input/misc/bmi220/bmi2.h b/drivers/input/misc/bmi220/bmi2.h new file mode 100755 index 00000000000..a770d59fac7 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi2.h @@ -0,0 +1,1342 @@ +/** +* Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. 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. +* +* 3. Neither the name of the copyright holder 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 AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS 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 bmi2.h +* @date 2020-01-24 +* @version v2.47.0 +* +*/ +#ifndef BMI2_H_ +#define BMI2_H_ + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +/*! Header files + ****************************************************************************/ +#include "bmi2_defs.h" + +/***************************************************************************/ + +/*! BMI2XY User Interface function prototypes + ****************************************************************************/ + +/*! + * @brief This API is the entry point for bmi2 sensor. It selects between + * I2C/SPI interface, based on user selection. It also reads the chip-id of + * the sensor. + * + * @param[in,out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_DEV_NOT_FOUND - Invalid device + */ +int8_t bmi2_sec_init(struct bmi2_dev *dev); + +/*! + * @brief This API reads the data from the given register address of bmi2 + * sensor. + * + * @param[in] reg_addr : Register address from which data is read. + * @param[out] data : Pointer to data buffer where read data is stored. + * @param[in] len : No. of bytes of data to be read. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note For most of the registers auto address increment applies, with the + * exception of a few special registers, which trap the address. For e.g., + * Register address - 0x26, 0x5E. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi2_dev *dev); + +/*! + * @brief This API writes data to the given register address of bmi2 sensor. + * + * @param[in] reg_addr : Register address to which the data is written. + * @param[in] data : Pointer to data buffer in which data to be written + * is stored. + * @param[in] len : No. of bytes of data to be written. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_regs(uint8_t reg_addr, const uint8_t *data, uint16_t len, struct bmi2_dev *dev); + +/*! + * @brief This API resets bmi2 sensor. All registers are overwritten with + * their default values. + * + * @note If selected interface is SPI, an extra dummy byte is read to bring the + * interface back to SPI from default, after the soft reset command. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_soft_reset(struct bmi2_dev *dev); + +/*! + * @brief This API is used to get the config file major and minor information. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[out] config_major : pointer to data buffer to store the config major. + * @param[out] config_minor : pointer to data buffer to store the config minor. + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_config_file_version(uint16_t *config_major, uint8_t *config_minor, struct bmi2_dev *dev); + +/*! + * @brief This API selects the sensors/features to be enabled. + * + * @param[in] sens_list : Pointer to select the sensor/feature. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features that can be enabled. + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_UP_HOLD_TO_WAKE | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_WRIST_GESTURE | 20 + * BMI2_WRIST_WEAR_WAKE_UP | 21 + * BMI2_ACTIVITY_RECOGNITION| 22 + * + * @example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO}; + * uint8_t n_sens = 2; + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API selects the sensors/features to be disabled. + * + * @param[in] sens_list : Pointer to select the sensor/feature. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features that can be disabled. + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_UP_HOLD_TO_WAKE | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_WRIST_GESTURE | 20 + * BMI2_WRIST_WEAR_WAKE_UP | 21 + * BMI2_ACTIVITY_RECOGNITION| 22 + * + * @example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO}; + * uint8_t n_sens = 2; + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API sets the sensor/feature configuration. + * + * @param[in] sens_cfg : Structure instance of bmi2_sens_config. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features that can be configured + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_UP_HOLD_TO_WAKE | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_WRIST_GESTURE | 21 + * BMI2_WRIST_WEAR_WAKE_UP | 22 + * BMI2_STEP_COUNTER_PARAMS | 25 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API gets the sensor/feature configuration. + * + * @param[in] sens_cfg : Structure instance of bmi2_sens_config. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features whose configurations can be read. + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_UP_HOLD_TO_WAKE | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_WRIST_GESTURE | 21 + * BMI2_WRIST_WEAR_WAKE_UP | 22 + * BMI2_STEP_COUNTER_PARAMS | 25 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API gets the sensor/feature data for accelerometer, gyroscope, + * auxiliary sensor, step counter, high-g, gyroscope user-gain update, + * orientation, gyroscope cross sensitivity and error status for NVM and VFRM. + * + * @param[out] sensor_data : Structure instance of bmi2_sensor_data. + * @param[in] n_sens : Number of sensors selected. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features whose data can be read + * + * sens_list | Values + * ---------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_ORIENTATION | 7 + * BMI2_STEP_COUNTER | 10 + * BMI2_GYRO_GAIN_UPDATE| 12 + * BMI2_HIGH_G | 16 + * BMI2_NVM_STATUS | 26 + * BMI2_VFRM_STATUS | 27 + * BMI2_GYRO_CROSS_SENSE| 28 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_get_sensor_data(struct bmi2_sensor_data *sensor_data, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API enables/disables the advance power save mode in the sensor. + * + * @param[in] enable : To enable/disable advance power mode. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables advance power save. + * BMI2_ENABLE | Enables advance power save. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_set_adv_power_save(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This API gets the status of advance power save mode in the sensor. + * + * @param[out] aps_status : Pointer to get the status of APS mode. + * @param[in] dev : Structure instance of bmi2_dev. + * + * aps_status | Description + * -------------|--------------- + * BMI2_DISABLE | Advance power save disabled. + * BMI2_ENABLE | Advance power save enabled. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_get_adv_power_save(uint8_t *aps_status, struct bmi2_dev *dev); + +/*! + * @brief This API loads the configuration file to the bmi2 sensor. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_CONFIG_LOAD - Configuration load fail + */ +int8_t bmi2_write_config_file(struct bmi2_dev *dev); + +/*! + * @brief This API sets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + * + * @param[in] int_cfg : Structure instance of bmi2_int_pin_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_INT_PIN - Error: Invalid interrupt pin + */ +int8_t bmi2_set_int_pin_config(const struct bmi2_int_pin_config *int_cfg, struct bmi2_dev *dev); + +/*! + * @brief This API gets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + * + * @param[in,out] int_cfg : Structure instance of bmi2_int_pin_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_INT_PIN - Error: Invalid interrupt pin + */ +int8_t bmi2_get_int_pin_config(struct bmi2_int_pin_config *int_cfg, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the interrupt status of both feature and data + * interrupts. + * + * @param[out] int_status : Pointer to get the status of the interrupts. + * @param[in] dev : Structure instance of bmi2_dev. + * + * int_status | Status + * -----------|------------ + * 0x00 | BIT0 + * 0x01 | BIT1 + * 0x02 | BIT2 + * 0x03 | BIT3 + * 0x04 | BIT4 + * 0x05 | BIT5 + * 0x06 | BIT6 + * 0x07 | BIT7 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_int_status(uint16_t *int_status, const struct bmi2_dev *dev); + +/*! + * @brief This API sets the FIFO configuration in the sensor. + * + * @param[in] config : FIFO configurations to be enabled/disabled. + * @param[in] enable : Enable/Disable FIFO configurations. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables FIFO configuration. + * BMI2_ENABLE | Enables FIFO configuration. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_fifo_config(uint16_t config, uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO configuration from the sensor. + * + * @param[out] fifo_config : Pointer variable to get FIFO configuration value. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_config(uint16_t *fifo_config, const struct bmi2_dev *dev); + +/*! + * @ brief This api is used to enable the gyro self-test and crt. + * *gyro_self_test_crt -> 0 then gyro self test enable + * *gyro_self_test_crt -> 1 then CRT enable + * + * @param[in] gyro_self_test_crt : enable the gyro self test or crt. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_gyro_self_test_crt(uint8_t *gyro_self_test_crt, struct bmi2_dev *dev); + +/*! + * @brief This API reads FIFO data. + * + * @param[in, out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note APS has to be disabled before calling this function. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_read_fifo_data(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * This API parses and extracts the accelerometer frames from FIFO data read by + * the "bmi2_read_fifo_data" API and stores it in the "accel_data" structure + * instance. + * + * @param[out] accel_data : Structure instance of bmi2_sens_axes_data + * where the parsed data bytes are stored. + * @param[in,out] accel_length : Number of accelerometer frames. + * @param[in,out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_extract_accel(struct bmi2_sens_axes_data *accel_data, + uint16_t *accel_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API parses and extracts the auxiliary frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in "aux_data" buffer. + * + * @param[out] aux : Pointer to structure where the parsed auxiliary + * data bytes are stored. + * @param[in,out] aux_length : Number of auxiliary frames. + * @param[in,out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_extract_aux(struct bmi2_aux_fifo_data *aux, + uint16_t *aux_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * This API parses and extracts the gyroscope frames from FIFO data read by the + * "bmi2_read_fifo_data" API and stores it in the "gyro_data" + * structure instance. + * + * @param[out] gyro_data : Structure instance of bmi2_sens_axes_data + * where the parsed data bytes are stored. + * @param[in,out] gyro_length : Number of gyroscope frames. + * @param[in,out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_extract_gyro(struct bmi2_sens_axes_data *gyro_data, + uint16_t *gyro_length, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API writes the available sensor specific commands to the sensor. + * + * @param[in] command : Commands to be given to the sensor. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Commands | Values + * ---------------------|--------------------- + * BMI2_SOFT_RESET_CMD | 0xB6 + * BMI2_FIFO_FLUSH_CMD | 0xB0 + * BMI2_USR_GAIN_CMD | 0x03 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_command_register(uint8_t command, struct bmi2_dev *dev); + +/*! + * @brief This API sets the FIFO self wake up functionality in the sensor. + * + * @param[in] fifo_self_wake_up : Variable to set FIFO self wake-up. + * @param[in] dev : Structure instance of bmi2_dev. + * + * fifo_self_wake_up | Description + * -------------------|--------------- + * BMI2_DISABLE | Disables self wake-up. + * BMI2_ENABLE | Enables self wake-up. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_fifo_self_wake_up(uint8_t fifo_self_wake_up, struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO self wake up functionality from the sensor. + * + * @param[out] fifo_self_wake_up : Pointer variable to get the status of FIFO + * self wake-up. + * @param[in] dev : Structure instance of bmi2_dev. + * + * fifo_self_wake_up | Description + * -------------------|--------------- + * BMI2_DISABLE | Self wake-up disabled + * BMI2_ENABLE | Self wake-up enabled. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_self_wake_up(uint8_t *fifo_self_wake_up, const struct bmi2_dev *dev); + +/*! + * @brief This API sets the FIFO water mark level which is set in the sensor. + * + * @param[in] fifo_wm : Variable to set FIFO water-mark level. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_fifo_wm(uint16_t fifo_wm, struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO water mark level which is set in the sensor. + * + * @param[out] fifo_wm : Pointer variable to store FIFO water-mark level. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_wm(uint16_t *fifo_wm, const struct bmi2_dev *dev); + +/*! + * @brief This API sets either filtered or un-filtered FIFO accelerometer or + * gyroscope data. + * + * @param[in] sens_sel : Selects either accelerometer or + * gyroscope sensor. + * @param[in] fifo_filter_data : Variable to set the filter data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * -----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * + * Value | fifo_filter_data + * ---------|--------------------- + * 0x00 | Un-filtered data + * 0x01 | Filtered data + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_OUT_OF_RANGE - Error: Out of range + */ +int8_t bmi2_set_fifo_filter_data(uint8_t sens_sel, uint8_t fifo_filter_data, struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO accelerometer or gyroscope filter data. + * + * @param[in] sens_sel : Selects either accelerometer or + * gyroscope sensor. + * @param[out] fifo_filter_data : Pointer variable to get the filter data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * -----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * + * Value | fifo_filter_data + * ---------|--------------------- + * 0x00 | Un-filtered data + * 0x01 | Filtered data + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_get_fifo_filter_data(uint8_t sens_sel, uint8_t *fifo_filter_data, const struct bmi2_dev *dev); + +/*! + * @brief This API sets the down sampling rate for FIFO accelerometer or + * gyroscope FIFO data. + * + * @param[in] sens_sel : Selects either either accelerometer or + * gyroscope sensor. + * @param[in] fifo_down_samp : Variable to set the down sampling rate. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * ----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_OUT_OF_RANGE - Error: Out of range + */ +int8_t bmi2_set_fifo_down_sample(uint8_t sens_sel, uint8_t fifo_down_samp, struct bmi2_dev *dev); + +/*! + * @brief This API gets the down sampling rate, configured for FIFO + * accelerometer or gyroscope data. + * + * @param[in] sens_sel : Selects either either accelerometer or + * gyroscope sensor. + * @param[out] fifo_down_samp : Pointer variable to store the down sampling rate + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * ----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_get_fifo_down_sample(uint8_t sens_sel, uint8_t *fifo_down_samp, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the length of FIFO data available in the sensor in + * bytes. + * + * @param[out] fifo_length : Pointer variable to store the value of FIFO byte + * counter. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note The byte counter is updated each time a complete frame is read or + * written. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_length(uint16_t *fifo_length, const struct bmi2_dev *dev); + +/*! + * @brief This API reads the user-defined bytes of data from the given register + * address of auxiliary sensor in manual mode. + * + * @param[in] reg_addr : Address from where data is read. + * @param[out] aux_data : Pointer to the stored buffer. + * @param[in] len : Total length of data to be read. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_RD_ADDR is only allowed if AUX is not busy. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration. + */ +int8_t bmi2_read_aux_man_mode(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, struct bmi2_dev *dev); + +/*! + * @brief This API enables/disables OIS interface. + * + * @param[in] enable : To enable/disable OIS interface. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables OIS interface. + * BMI2_ENABLE | Enables OIS interface. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_ois_interface(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written in manual mode. + * + * @param[in] reg_addr : AUX address where data is to be written. + * @param[in] aux_data : Pointer to data to be written. + * @param[in] len : Total length of data to be written. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration. + */ +int8_t bmi2_write_aux_man_mode(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, struct bmi2_dev *dev); + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written, from an interleaved input, + * in manual mode. + * + * @param[in] reg_addr : AUX address where data is to be written. + * @param[in] aux_data : Pointer to data to be written. + * @param[in] len : Total length of data to be written. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration. + */ +int8_t bmi2_write_aux_interleaved(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, struct bmi2_dev *dev); + +/*! + * @brief This API gets the data ready status of accelerometer, gyroscope, + * auxiliary, ready status of command decoder and busy status of auxiliary. + * + * @param[out] status : Pointer variable to the status. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Value | Status + * ---------|--------------------- + * 0x80 | DRDY_ACC + * 0x40 | DRDY_GYR + * 0x20 | DRDY_AUX + * 0x10 | CMD_RDY + * 0x04 | AUX_BUSY + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_status(uint8_t *status, const struct bmi2_dev *dev); + +/*! + * @brief This API can be used to write sync commands like ODR, sync period, + * frequency and phase, resolution ratio, sync time and delay time. + * + * @param[in] command : Sync command to be written. + * @param[in] n_comm : Length of the command. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_write_sync_commands(const uint8_t *command, uint8_t n_comm, struct bmi2_dev *dev); + +/*! + * @brief This API performs self-test to check the proper functionality of the + * accelerometer sensor. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SELF_TEST_FAIL - Error: Self test fail + */ +int8_t bmi2_perform_accel_self_test(struct bmi2_dev *dev); + +/*! + * @brief This API maps/unmaps feature interrupts to that of interrupt pins. + * + * @param[in] sens_int : Structure instance of bmi2_sens_int_config. + * @param[in] n_sens : Number of features to be mapped. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_FEAT_INT - Error: Invalid feature Interrupt + */ +int8_t bmi2_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API maps/un-maps data interrupts to that of interrupt pins. + * + * @param[in] int_pin : Interrupt pin selected. + * @param[in] data_int : Type of data interrupt to be mapped. + * @param[in] dev : Structure instance of bmi2_dev. + * + * data_int | Mask values + * ---------------------|--------------------- + * BMI2_FFULL_INT | 0x01 + * BMI2_FWM_INT | 0x02 + * BMI2_DRDY_INT | 0x04 + * BMI2_ERR_INT | 0x08 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_INT_PIN - Error: Invalid interrupt pin + */ +int8_t bmi2_map_data_int(uint8_t data_int, enum bmi2_hw_int_pin int_pin, struct bmi2_dev *dev); + +/*! + * @brief This API gets the re-mapped x, y and z axes from the sensor and + * updates the values in the device structure. + * + * @param[out] remapped_axis : Structure that stores re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_get_remap_axes(struct bmi2_remap *remapped_axis, struct bmi2_dev *dev); + +/*! + * @brief This API sets the re-mapped x, y and z axes to the sensor and + * updates them in the device structure. + * + * @param[in] remapped_axis : Structure that stores re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_set_remap_axes(const struct bmi2_remap *remapped_axis, struct bmi2_dev *dev); + +/*! + * @brief This API updates the gyroscope user-gain. + * + * @param[in] user_gain : Structure that stores user-gain configurations. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_GYR_USER_GAIN_UPD_FAIL - Gyroscope user gain update fail + */ +int8_t bmi2_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev); + +/*! + * @brief This API reads the compensated gyroscope user-gain values. + * + * @param[out] gyr_usr_gain : Structure that stores gain values. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, const struct bmi2_dev *dev); + +/*! + * @brief This API enables/disables gyroscope offset compensation. It adds the + * offsets defined in the offset register with gyroscope data. + * + * @param[in] enable : Enables/Disables gyroscope offset compensation. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enables gyroscope offset compensation. + * BMI2_DISABLE | Disables gyroscope offset compensation. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_gyro_offset_comp(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This API reads the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + * + * @param[out] gyr_off_comp_axes: Structure to store gyroscope offset + * compensated values. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_read_gyro_offset_comp_axes(struct bmi2_sens_axes_data *gyr_off_comp_axes, const struct bmi2_dev *dev); + +/*! + * @brief This API writes the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + * + * @param[in] gyr_off_comp_axes : Structure to store gyroscope offset + * compensated values. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_write_gyro_offset_comp_axes(const struct bmi2_sens_axes_data *gyr_off_comp_axes, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse the activity output from the + * FIFO in header mode. + * + * @param[out] act_recog : Pointer to buffer where the parsed activity data + * bytes are stored. + * @param[in] act_frm_len : Number of activity frames parsed. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @verbatim + * bmi2_act_rec_output | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * time_stamp | time-stamp (expressed in 50Hz ticks) + * -------------------------|--------------------------------------------------- + * type | Type of activity + * -------------------------|--------------------------------------------------- + * stat | Activity status + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * type | Activities + *----------|--------------------- + * 0 | UNKNOWN + * 1 | STILL + * 2 | WALK + * 3 | RUN + * 4 | BIKE + * 5 | VEHICLE + * 6 | TILTED + * + * + * stat | Activity status + *----------|--------------------- + * 1 | START + * 2 | END + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_get_act_recog_output(struct bmi2_act_recog_output *act_recog, + uint16_t *act_frm_len, + struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API updates the cross sensitivity coefficient between gyroscope's + * X and Z axes. + * + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_gyro_cross_sense(struct bmi2_dev *dev); + +/*! + * @brief This API gets error bits and message indicating internal status. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[out] int_stat : Pointer variable to store error bits and + * message. + * + * Internal status | *int_stat + * ---------------------|--------------------- + * BMI2_NOT_INIT | 0x00 + * BMI2_INIT_OK | 0x01 + * BMI2_INIT_ERR | 0x02 + * BMI2_DRV_ERR | 0x03 + * BMI2_SNS_STOP | 0x04 + * BMI2_NVM_ERROR | 0x05 + * BMI2_START_UP_ERROR | 0x06 + * BMI2_COMPAT_ERROR | 0x07 + * BMI2_VFM_SKIPPED | 0x10 + * BMI2_AXES_MAP_ERROR | 0x20 + * BMI2_ODR_50_HZ_ERROR | 0x40 + * BMI2_ODR_HIGH_ERROR | 0x80 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_internal_status(uint8_t *int_stat, const struct bmi2_dev *dev); + +/*! + * @brief This API performs Fast Offset Compensation for accelerometer. + * + * @param[in] accel_g_value : This parameter selects the accel foc + * axis to be performed + * + * input format is {x, y, z, sign}. '1' to enable. '0' to disable + * + * eg to choose x axis {1, 0, 0, 0} + * eg to choose -x axis {1, 0, 0, 1} + * + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_perform_accel_foc(const struct accel_foc_g_value *accel_g_value, struct bmi2_dev *dev); + +/*! + * @brief This API performs Fast Offset Compensation for gyroscope. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_perform_gyro_foc(struct bmi2_dev *dev); + +/*! + * @brief API performs Component Re-Trim calibration (CRT). + * + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_CRT_ERROR - Error in CRT download + * + * @note CRT calibration takes approximately 500ms & maximum time out configured as 2 seconds + */ +int8_t bmi2_do_crt(struct bmi2_dev *dev); + +/*! + * @brief This api is used to abort ongoing crt or gyro self test. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ + +int8_t bmi2_abort_crt_gyro_st(struct bmi2_dev *dev); + +/*! + * @brief this api is used to perform gyroscope self test. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval < 0 - Fail + */ +int8_t bmi2_do_gyro_st(struct bmi2_dev *dev); + +/*! @brief This api is used for programming the non volatile memory(nvm) + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval < 0 - Fail + */ +int8_t bmi2_nvm_prog(struct bmi2_dev *dev); + +/*! @brief This api is used for retrieving the following activity recognition settings currently set. + * enable/disable post processing(0/1) by default -> 1(enable), + * Setting the min & max Gini's diversity index (GDI) threshold. min_GDI_tres(0-0XFFFF) by default ->(0x06e1) + * max_GDI_tres(0-0xFFFF) by default ->(0x0A66) + * buffer size for post processing. range (1-0x0A) default -> (0x0A) + * min segment confidence. range (1-0x0A) default -> (0x0A) + * + * @param[in] sett : Structure instance of act_recg_sett. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status. + * + * @retval BMI2_OK - Success. + * @retval < 0 - Fail + */ +int8_t bmi2_get_act_recg_sett(struct act_recg_sett *sett, struct bmi2_dev *dev); + +/*! @brief This api is used for setting the following activity recognition settings + * enable/disable post processing(0/1) by default -> 1(enable), + * Setting the min & max Gini's diversity index (GDI) threshold. min_GDI_tres(0-0XFFFF) by default ->(0x06e1) + * max_GDI_tres(0-0xFFFF) by default ->(0x0A66) + * buffer size for post processing. range (1-0x0A) default -> (0x0A) + * min segment confidence. range (1-0x0A) default -> (0x0A) + * + * @param[in] sett : Structure instance of act_recg_sett. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status. + * + * @retval BMI2_OK - Success. + * @retval < 0 - Fail + */ +int8_t bmi2_set_act_recg_sett(const struct act_recg_sett *sett, struct bmi2_dev *dev); + +/******************************************************************************/ +/*! @name C++ Guard Macros */ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* BMI2_H_ */ diff --git a/drivers/input/misc/bmi220/bmi220.c b/drivers/input/misc/bmi220/bmi220.c new file mode 100755 index 00000000000..81af86685f7 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi220.c @@ -0,0 +1,637 @@ +/** +* Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. 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. +* +* 3. Neither the name of the copyright holder 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 AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS 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 bmi220.c +* @date 2020-01-24 +* @version v2.47.0 +* +*/ +/***************************************************************************/ + +/*! Header files + ****************************************************************************/ +#include "bmi220.h" + +/***************************************************************************/ + +/*! Global Variable + ****************************************************************************/ + +/*! @name Global array that stores the configuration file of BMI220 */ +const uint8_t bmi220_config_file[] = { + 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0xb6, 0xb0, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0xed, 0x00, 0x80, 0x2e, 0x6a, + 0x01, 0x80, 0x2e, 0xad, 0x01, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x01, 0xb0, 0x50, 0x32, 0x21, 0x2e, 0x59, 0xf5, + 0x10, 0x30, 0x21, 0x2e, 0x6a, 0xf5, 0x80, 0x2e, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x21, 0x01, 0x00, 0x22, + 0x00, 0x7f, 0x00, 0x00, 0x0c, 0xff, 0x0f, 0xbc, 0x00, 0x78, 0xaf, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xac, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x32, 0x01, 0xe6, 0x78, 0x84, 0x00, 0x9c, 0x6c, 0x07, 0x00, 0x64, 0x75, 0xaa, + 0x7e, 0x5f, 0x05, 0xbe, 0x0a, 0x5f, 0x05, 0x96, 0xe8, 0xef, 0x41, 0x01, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x4a, 0x00, + 0xa0, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xf0, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x4a, 0x00, 0x00, 0x6d, 0x57, 0x00, 0x00, 0x77, 0x8e, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xd3, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xff, 0xff, 0xee, 0xe1, 0xff, 0xff, 0x7c, 0x13, 0x00, 0x00, + 0x46, 0xe6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x24, 0x22, 0x00, 0x80, 0x2e, 0x48, 0x02, 0x10, + 0x50, 0xf7, 0x7f, 0x00, 0x2e, 0x0f, 0x2e, 0x69, 0xf5, 0xff, 0xbf, 0xff, 0xbb, 0xc0, 0x91, 0x02, 0x2f, 0x37, 0x30, + 0x2f, 0x2e, 0x69, 0xf5, 0xf7, 0x6f, 0xf0, 0x5f, 0xc8, 0x2e, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xc1, + 0x00, 0xaa, 0xaa, 0xd0, 0x07, 0xc0, 0xf5, 0xdb, 0x00, 0x1e, 0xf2, 0x69, 0xf5, 0x19, 0xf4, 0x66, 0xf5, 0x00, 0x04, + 0xff, 0x00, 0x64, 0xf5, 0xc5, 0x00, 0x08, 0x02, 0xc8, 0x00, 0xa2, 0x00, 0xa4, 0x00, 0x87, 0x00, 0xd9, 0x00, 0xff, + 0x3f, 0xff, 0xfb, 0x00, 0x18, 0x00, 0x10, 0xfd, 0xf5, 0xe1, 0x00, 0xac, 0x00, 0xe1, 0x00, 0xe4, 0x00, 0x34, 0x43, + 0x34, 0x4b, 0xff, 0xfd, 0x9a, 0xf1, 0x99, 0x51, 0x9a, 0xf9, 0xc1, 0xf5, 0x8d, 0xf1, 0x80, 0x00, 0x00, 0x40, 0x4d, + 0x01, 0xeb, 0x00, 0x7f, 0xff, 0xc2, 0xf5, 0x68, 0xf7, 0xba, 0x00, 0xae, 0x00, 0xb4, 0x00, 0xc0, 0x00, 0x60, 0x01, + 0x61, 0xf7, 0x5b, 0xf7, 0x63, 0x01, 0x78, 0xf7, 0x77, 0xf7, 0x00, 0x80, 0xff, 0x7f, 0x86, 0x00, 0x52, 0x01, 0x65, + 0x01, 0xb3, 0xf1, 0x5f, 0x01, 0x6c, 0xf7, 0xb9, 0xf1, 0xc6, 0xf1, 0x00, 0xe0, 0x00, 0xff, 0xd1, 0xf5, 0x67, 0x01, + 0x6a, 0x01, 0xff, 0x03, 0x00, 0xfc, 0xf0, 0x3f, 0x0d, 0x02, 0x10, 0x02, 0x12, 0x02, 0xb9, 0x00, 0x2d, 0xf5, 0xca, + 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x50, 0x80, 0x7f, 0x91, 0x7f, 0xd7, 0x7f, 0xc5, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0xe4, 0x7f, 0xf6, + 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x0d, 0x50, 0x00, 0x2e, 0x01, 0x40, 0x9f, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x02, 0x2f, + 0x31, 0x30, 0x23, 0x2e, 0x69, 0xf5, 0x37, 0x80, 0x00, 0x2e, 0x00, 0x40, 0x60, 0x7f, 0x98, 0x2e, 0xdc, 0x01, 0x62, + 0x6f, 0x01, 0x32, 0x91, 0x08, 0x80, 0xb2, 0x0d, 0x2f, 0x00, 0xb2, 0x03, 0x2f, 0x05, 0x2e, 0x18, 0x00, 0x80, 0x90, + 0x05, 0x2f, 0x17, 0x56, 0x02, 0x30, 0xc1, 0x42, 0xc2, 0x86, 0x00, 0x2e, 0xc2, 0x42, 0x23, 0x2e, 0x60, 0xf5, 0x00, + 0x90, 0x00, 0x30, 0x06, 0x2f, 0x21, 0x2e, 0x81, 0x00, 0x15, 0x50, 0x21, 0x2e, 0x5a, 0xf2, 0x98, 0x2e, 0xf0, 0x01, + 0xf6, 0x6f, 0xe4, 0x6f, 0x80, 0x6f, 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc5, 0x6f, 0xd7, 0x6f, 0x7b, 0x6f, 0x60, + 0x5f, 0xc8, 0x2e, 0x30, 0x50, 0xe5, 0x7f, 0xf6, 0x7f, 0xd7, 0x7f, 0x00, 0x2e, 0x0d, 0x5a, 0x00, 0x2e, 0x46, 0x41, + 0x6f, 0xbf, 0x6f, 0xbb, 0x80, 0x91, 0x02, 0x2f, 0x36, 0x30, 0x2d, 0x2e, 0x69, 0xf5, 0x46, 0x30, 0x0f, 0x2e, 0xa4, + 0xf1, 0xbe, 0x09, 0x77, 0x8b, 0x80, 0xb3, 0x06, 0x2f, 0x0d, 0x2e, 0xa8, 0x00, 0x84, 0xaf, 0x02, 0x2f, 0x16, 0x30, + 0x2d, 0x2e, 0x84, 0x00, 0x86, 0x30, 0x46, 0x43, 0x00, 0x2e, 0xf6, 0x6f, 0xe5, 0x6f, 0xd7, 0x6f, 0xd0, 0x5f, 0xc8, + 0x2e, 0x03, 0x2e, 0xa7, 0x00, 0x16, 0xb8, 0x02, 0x34, 0x4a, 0x0c, 0x21, 0x2e, 0x2d, 0xf5, 0xc0, 0x2e, 0x23, 0x2e, + 0xa7, 0x00, 0x2f, 0x52, 0x00, 0x2e, 0x60, 0x40, 0x41, 0x40, 0x0d, 0xbc, 0x98, 0xbc, 0xc0, 0x2e, 0x01, 0x0a, 0x0f, + 0xb8, 0x43, 0x86, 0x25, 0x40, 0x04, 0x40, 0xd8, 0xbe, 0x2c, 0x0b, 0x22, 0x11, 0x54, 0x42, 0x03, 0x80, 0x4b, 0x0e, + 0xf6, 0x2f, 0xb8, 0x2e, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x56, 0xc7, 0xfb, 0x6f, 0xf0, 0x5f, 0x80, 0x2e, 0x49, + 0xc3, 0x21, 0x2e, 0x59, 0xf5, 0x10, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0x4a, 0xf1, 0x80, 0x2e, 0x00, 0xc1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x0d, + 0x21, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xe0, 0xaa, 0x38, 0x05, 0xe0, 0x90, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x50, 0x10, 0x50, 0x31, 0x52, 0x05, 0x2e, 0xa7, 0x00, 0xfb, 0x7f, 0x00, 0x2e, + 0x13, 0x40, 0x93, 0x42, 0x41, 0x0e, 0xfb, 0x2f, 0x98, 0x2e, 0xd2, 0x01, 0x98, 0x2e, 0x87, 0xcf, 0x01, 0x2e, 0xad, + 0x00, 0x00, 0xb2, 0x08, 0x2f, 0x01, 0x2e, 0x69, 0xf7, 0xb1, 0x3f, 0x01, 0x08, 0x01, 0x30, 0x23, 0x2e, 0xad, 0x00, + 0x21, 0x2e, 0x69, 0xf7, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e, 0x44, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, 0x98, 0x2e, 0xee, 0xb5, 0x00, 0x30, 0xf0, 0x7f, + 0xe0, 0x7f, 0x21, 0x2e, 0x69, 0xf5, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x00, 0x2e, 0x01, 0x80, 0x08, 0xa2, 0xfb, + 0x2f, 0x01, 0x2e, 0xc4, 0x00, 0x00, 0xb2, 0x1a, 0x2f, 0x05, 0x2e, 0x0c, 0x02, 0x01, 0x52, 0x98, 0x2e, 0xc7, 0xc1, + 0x03, 0x2e, 0x18, 0x00, 0x40, 0xb2, 0xf0, 0x7f, 0x10, 0x2f, 0x01, 0x2e, 0x0c, 0x02, 0x06, 0xbc, 0x0f, 0xb8, 0x00, + 0x90, 0x0a, 0x2f, 0x01, 0x50, 0x98, 0x2e, 0x4d, 0xc3, 0x01, 0x50, 0x98, 0x2e, 0x5a, 0xc7, 0x98, 0x2e, 0x3a, 0xb1, + 0x10, 0x30, 0x21, 0x2e, 0x19, 0x00, 0x01, 0x2e, 0x0c, 0x02, 0x06, 0xbc, 0x0f, 0xb8, 0x00, 0xb2, 0x0e, 0x2f, 0xe0, + 0x6f, 0x00, 0x90, 0x0b, 0x2f, 0x07, 0x52, 0x00, 0x2e, 0x50, 0x40, 0x41, 0x40, 0x21, 0x2e, 0xe7, 0x00, 0x23, 0x2e, + 0xe8, 0x00, 0x98, 0x2e, 0x91, 0x03, 0x10, 0x30, 0xe0, 0x7f, 0x98, 0x2e, 0xd3, 0xb1, 0x01, 0x2e, 0xa8, 0x00, 0x04, + 0xae, 0x0b, 0x2f, 0x01, 0x2e, 0xc4, 0x00, 0x00, 0xb2, 0x07, 0x2f, 0x01, 0x52, 0x98, 0x2e, 0xa5, 0xb5, 0x00, 0xb2, + 0x02, 0x2f, 0x10, 0x30, 0x21, 0x2e, 0x86, 0x00, 0x01, 0x2e, 0x86, 0x00, 0x00, 0x90, 0x36, 0x2f, 0x01, 0x2e, 0xab, + 0x00, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0xf2, 0x03, 0x00, 0x30, 0x21, 0x2e, 0x84, 0x00, 0x01, 0x2e, 0x84, 0x00, + 0x00, 0xb2, 0x0b, 0x2f, 0x01, 0x2e, 0xa8, 0x00, 0x00, 0x90, 0x02, 0x2f, 0x98, 0x2e, 0x3f, 0xb5, 0x02, 0x2d, 0x98, + 0x2e, 0x97, 0xb4, 0x00, 0x30, 0x21, 0x2e, 0x84, 0x00, 0x01, 0x2e, 0x85, 0x00, 0x00, 0xb2, 0x31, 0x2f, 0x01, 0x2e, + 0x85, 0x00, 0x01, 0x31, 0x01, 0x08, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0x47, 0xcb, 0x10, 0x30, 0x21, 0x2e, 0x19, + 0x00, 0x81, 0x30, 0x01, 0x2e, 0x85, 0x00, 0x01, 0x08, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0x4f, 0xb5, 0x00, 0x30, + 0x21, 0x2e, 0xa8, 0x00, 0x00, 0x30, 0x21, 0x2e, 0x85, 0x00, 0x18, 0x2d, 0x01, 0x2e, 0xa8, 0x00, 0x03, 0xaa, 0x01, + 0x2f, 0x98, 0x2e, 0x5c, 0xb5, 0x01, 0x2e, 0xa8, 0x00, 0x3f, 0x80, 0x03, 0xa2, 0x01, 0x2f, 0x00, 0x2e, 0x02, 0x2d, + 0x98, 0x2e, 0x72, 0xb5, 0x30, 0x30, 0x98, 0x2e, 0xbf, 0x03, 0x00, 0x30, 0x21, 0x2e, 0x86, 0x00, 0x50, 0x32, 0x98, + 0x2e, 0xf8, 0x01, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x1f, 0x2f, 0x98, 0x2e, 0xf5, 0xcb, 0x03, 0x2e, 0xa9, 0x00, + 0x01, 0x0a, 0x21, 0x2e, 0xdb, 0x00, 0x09, 0x52, 0x7e, 0x82, 0x0b, 0x50, 0x41, 0x40, 0x18, 0xb9, 0x11, 0x42, 0x02, + 0x82, 0x02, 0x42, 0xd1, 0x7f, 0xf0, 0x31, 0x41, 0x40, 0xf2, 0x6f, 0x25, 0xbd, 0x08, 0x08, 0x02, 0x0a, 0xc0, 0x7f, + 0x98, 0x2e, 0xa8, 0xcf, 0x06, 0xbc, 0xc1, 0x6f, 0xd2, 0x6f, 0x08, 0x0a, 0x80, 0x42, 0x98, 0x2e, 0x20, 0x02, 0x00, + 0x30, 0x03, 0x2e, 0xa8, 0x00, 0x21, 0x2e, 0x19, 0x00, 0x21, 0x2e, 0xc4, 0x00, 0x44, 0x90, 0x90, 0x2e, 0x4e, 0x02, + 0x03, 0x2e, 0xfd, 0xf5, 0x42, 0x30, 0x8a, 0x08, 0x80, 0xb2, 0x05, 0x2f, 0x05, 0x2e, 0xc0, 0xf5, 0x28, 0xbd, 0x2f, + 0xb9, 0x80, 0x90, 0x0b, 0x2f, 0x22, 0x30, 0x4a, 0x08, 0x40, 0xb2, 0x90, 0x2e, 0x4e, 0x02, 0x03, 0x2e, 0xc2, 0xf5, + 0x98, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, 0x90, 0x2e, 0x4e, 0x02, 0x03, 0x52, 0x05, 0x54, 0x03, 0x30, 0x23, 0x2e, 0x00, + 0xb0, 0x41, 0x16, 0xc1, 0x86, 0x23, 0x2e, 0xff, 0xb7, 0x5a, 0x0e, 0xf7, 0x2f, 0x80, 0x2e, 0x4e, 0x02, 0x11, 0x30, + 0x81, 0x08, 0x01, 0x2e, 0x6a, 0xf7, 0x71, 0x3f, 0x23, 0xbd, 0x01, 0x08, 0x02, 0x0a, 0xc0, 0x2e, 0x21, 0x2e, 0x6a, + 0xf7, 0x80, 0x2e, 0x00, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x01, + 0x34, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x2f, 0x50, 0x41, 0x30, 0x02, 0x40, 0x51, 0x0a, 0x01, 0x42, 0x41, 0x3c, 0x01, 0x00, 0x31, 0x30, 0x02, + 0x40, 0x51, 0x0a, 0x21, 0x42, 0x71, 0x3f, 0x33, 0x54, 0x02, 0x42, 0x90, 0x31, 0x05, 0x2e, 0xed, 0xf4, 0x51, 0x08, + 0x23, 0x2e, 0xed, 0xf4, 0x21, 0x2e, 0xc0, 0x00, 0x01, 0x30, 0xc0, 0x2e, 0x23, 0x2e, 0xaa, 0x00, 0x03, 0xbc, 0x21, + 0x2e, 0xa9, 0x00, 0x03, 0x2e, 0xa9, 0x00, 0x40, 0xb2, 0x10, 0x30, 0x21, 0x2e, 0x19, 0x00, 0x01, 0x30, 0x05, 0x2f, + 0x05, 0x2e, 0xac, 0x00, 0x80, 0x90, 0x01, 0x2f, 0x23, 0x2e, 0x6f, 0xf5, 0xc0, 0x2e, 0x21, 0x2e, 0xad, 0x00, 0x30, + 0x25, 0x00, 0x30, 0x21, 0x2e, 0x5a, 0xf5, 0x10, 0x50, 0x21, 0x2e, 0x84, 0x00, 0x21, 0x2e, 0x85, 0x00, 0xfb, 0x7f, + 0x98, 0x2e, 0x43, 0x03, 0x40, 0x30, 0x21, 0x2e, 0xa8, 0x00, 0xfb, 0x6f, 0xf0, 0x5f, 0x03, 0x25, 0x80, 0x2e, 0xab, + 0x03, 0x01, 0x2e, 0x5d, 0xf7, 0x08, 0xbc, 0x80, 0xac, 0x0e, 0xbb, 0x02, 0x2f, 0x00, 0x30, 0x41, 0x04, 0x82, 0x06, + 0xc0, 0xa4, 0x00, 0x30, 0x11, 0x2f, 0x40, 0xa9, 0x03, 0x2f, 0x40, 0x91, 0x0d, 0x2f, 0x00, 0xa7, 0x0b, 0x2f, 0x80, + 0xb3, 0x4b, 0x58, 0x02, 0x2f, 0x90, 0xa1, 0x26, 0x13, 0x20, 0x23, 0x80, 0x90, 0x10, 0x30, 0x01, 0x2f, 0xcc, 0x0e, + 0x00, 0x2f, 0x00, 0x30, 0xb8, 0x2e, 0x01, 0x2e, 0xab, 0x00, 0x03, 0x2e, 0xaa, 0x00, 0x48, 0x0e, 0x01, 0x2f, 0x80, + 0x2e, 0x3f, 0xb5, 0xb8, 0x2e, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xfd, 0x2d, 0x00, 0x00, 0xa0, 0x50, + 0x82, 0x7f, 0x90, 0x7f, 0xa1, 0x7f, 0xd7, 0x7f, 0xc5, 0x7f, 0xb3, 0x7f, 0xe4, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, 0x00, + 0x2e, 0x0d, 0x54, 0x00, 0x2e, 0x80, 0x40, 0x0f, 0xbc, 0x0f, 0xb8, 0x00, 0x90, 0x02, 0x2f, 0x30, 0x30, 0x21, 0x2e, + 0x69, 0xf5, 0xf0, 0x3e, 0x03, 0x2e, 0xeb, 0xf0, 0x48, 0x08, 0x01, 0x2e, 0xa8, 0x00, 0xb7, 0x84, 0x23, 0x2e, 0xeb, + 0xf0, 0x04, 0x90, 0x62, 0x7f, 0x05, 0x2f, 0xf2, 0x3b, 0x01, 0x2e, 0xc2, 0xf5, 0x82, 0x08, 0x25, 0x2e, 0xc2, 0xf5, + 0x98, 0x2e, 0xdc, 0x01, 0x00, 0xb2, 0x63, 0x2f, 0x05, 0x2e, 0x11, 0x02, 0x01, 0x2e, 0x13, 0x02, 0x8f, 0xb8, 0x07, + 0x2e, 0x08, 0x02, 0x2f, 0xb9, 0x91, 0x0a, 0xb3, 0xbd, 0x01, 0x2e, 0x08, 0x02, 0xbf, 0xb8, 0x04, 0xbc, 0x91, 0x0a, + 0x0f, 0xb8, 0x90, 0x0a, 0x25, 0x2e, 0x18, 0x00, 0x05, 0x2e, 0xc1, 0xf5, 0x2e, 0xbc, 0x05, 0x2e, 0xa8, 0x00, 0x84, + 0xa2, 0x0e, 0xb8, 0x31, 0x30, 0x88, 0x04, 0x07, 0x2f, 0x01, 0x2e, 0x18, 0x00, 0x00, 0x90, 0x03, 0x2f, 0x01, 0x2e, + 0x82, 0x00, 0x00, 0xb2, 0x19, 0x2f, 0x0f, 0x50, 0x01, 0x52, 0x98, 0x2e, 0xe5, 0x01, 0x05, 0x2e, 0x81, 0x00, 0x25, + 0x2e, 0xc4, 0x00, 0x05, 0x2e, 0x81, 0x00, 0x80, 0x90, 0x02, 0x2f, 0x12, 0x30, 0x25, 0x2e, 0x81, 0x00, 0x01, 0x2e, + 0x82, 0x00, 0x00, 0xb2, 0x10, 0x30, 0x05, 0x2e, 0x18, 0x00, 0x01, 0x2f, 0x21, 0x2e, 0x18, 0x00, 0x25, 0x2e, 0x82, + 0x00, 0x05, 0x2e, 0x18, 0x00, 0x80, 0xb2, 0x20, 0x2f, 0x01, 0x2e, 0xc0, 0xf5, 0xf2, 0x30, 0x02, 0x08, 0x07, 0xaa, + 0x73, 0x30, 0x03, 0x2e, 0x83, 0x00, 0x18, 0x22, 0x41, 0x1a, 0x05, 0x2f, 0x03, 0x2e, 0x66, 0xf5, 0x9f, 0xbc, 0x9f, + 0xb8, 0x40, 0x90, 0x0c, 0x2f, 0x11, 0x52, 0x03, 0x30, 0x53, 0x42, 0x2b, 0x30, 0x90, 0x04, 0x5b, 0x42, 0x21, 0x2e, + 0x83, 0x00, 0x24, 0xbd, 0x7e, 0x80, 0x81, 0x84, 0x43, 0x42, 0x02, 0x42, 0x02, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x05, + 0x2e, 0xaa, 0x00, 0x81, 0x80, 0x21, 0x2e, 0xaa, 0x00, 0x62, 0x6f, 0x00, 0x31, 0x80, 0x42, 0x00, 0x2e, 0x05, 0x2e, + 0x0c, 0x02, 0x13, 0x50, 0x90, 0x08, 0x80, 0xb2, 0x0b, 0x2f, 0x05, 0x2e, 0xca, 0xf5, 0xf0, 0x3e, 0x90, 0x08, 0x25, + 0x2e, 0xca, 0xf5, 0x05, 0x2e, 0x59, 0xf5, 0xe0, 0x3f, 0x90, 0x08, 0x25, 0x2e, 0x59, 0xf5, 0xf6, 0x6f, 0xe4, 0x6f, + 0x90, 0x6f, 0xa1, 0x6f, 0xb3, 0x6f, 0xc5, 0x6f, 0xd7, 0x6f, 0x7b, 0x6f, 0x82, 0x6f, 0x60, 0x5f, 0xc8, 0x2e, 0xd0, + 0x50, 0x80, 0x7f, 0x91, 0x7f, 0xd7, 0x7f, 0xc5, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0xe4, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, + 0x00, 0x2e, 0x0d, 0x50, 0x00, 0x2e, 0x01, 0x40, 0x9f, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x02, 0x2f, 0x31, 0x30, 0x23, + 0x2e, 0x69, 0xf5, 0x38, 0x82, 0x61, 0x7f, 0x20, 0x30, 0x41, 0x40, 0x23, 0x2e, 0x85, 0x00, 0x03, 0x2e, 0x85, 0x00, + 0x08, 0x08, 0x00, 0xb2, 0x11, 0x2f, 0x19, 0x50, 0x1a, 0x25, 0x12, 0x40, 0x32, 0x7f, 0x73, 0x82, 0x12, 0x40, 0x42, + 0x7f, 0x00, 0x2e, 0x00, 0x40, 0x50, 0x7f, 0x98, 0x2e, 0x6a, 0xd6, 0x01, 0x2e, 0x61, 0xf7, 0x01, 0x31, 0x01, 0x0a, + 0x21, 0x2e, 0x61, 0xf7, 0x80, 0x30, 0x03, 0x2e, 0x85, 0x00, 0x08, 0x08, 0x00, 0xb2, 0x3c, 0x2f, 0x03, 0x2e, 0x0b, + 0x02, 0x01, 0x2e, 0x0b, 0x02, 0x97, 0xbc, 0x06, 0xbc, 0x9f, 0xb8, 0x0f, 0xb8, 0x00, 0x90, 0x23, 0x2e, 0xac, 0x00, + 0x10, 0x30, 0x01, 0x30, 0x24, 0x2f, 0x03, 0x2e, 0xa8, 0x00, 0x44, 0xb2, 0x05, 0x2f, 0x47, 0xb2, 0x00, 0x30, 0x27, + 0x2f, 0x21, 0x2e, 0x85, 0x00, 0x25, 0x2d, 0x03, 0x2e, 0xfd, 0xf5, 0x9e, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x0e, 0x2f, + 0x03, 0x2e, 0xfc, 0xf5, 0x99, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x08, 0x2f, 0x98, 0x2e, 0xdc, 0x01, 0x00, 0xb2, 0x10, + 0x30, 0x03, 0x2f, 0x50, 0x30, 0x21, 0x2e, 0xa8, 0x00, 0x10, 0x2d, 0x98, 0x2e, 0xab, 0x03, 0x00, 0x30, 0x21, 0x2e, + 0x85, 0x00, 0x0a, 0x2d, 0x05, 0x2e, 0x69, 0xf7, 0x2d, 0xbd, 0x2f, 0xb9, 0x80, 0xb2, 0x01, 0x2f, 0x21, 0x2e, 0x86, + 0x00, 0x23, 0x2e, 0x85, 0x00, 0x60, 0x6f, 0xe1, 0x31, 0x01, 0x42, 0x00, 0x2e, 0xf6, 0x6f, 0xe4, 0x6f, 0x80, 0x6f, + 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc5, 0x6f, 0xd7, 0x6f, 0x7b, 0x6f, 0x30, 0x5f, 0xc8, 0x2e, 0x1b, 0x50, 0xe0, + 0x50, 0x12, 0x40, 0x06, 0x40, 0x1a, 0x25, 0x6c, 0xbe, 0x77, 0x8a, 0x75, 0x80, 0xfb, 0x7f, 0x0b, 0x30, 0x2b, 0x56, + 0xd3, 0x08, 0x4c, 0xba, 0x68, 0xbb, 0x0b, 0x42, 0xd0, 0x7f, 0x6b, 0x7f, 0x4b, 0x43, 0xc0, 0xb2, 0x2d, 0x2e, 0x8c, + 0x00, 0xc4, 0x7f, 0xe5, 0x7f, 0xb3, 0x7f, 0x74, 0x2f, 0x01, 0x2e, 0xa6, 0x00, 0x00, 0xb2, 0x0b, 0x2f, 0x1d, 0x52, + 0x01, 0x2e, 0xa1, 0x00, 0xa2, 0x7f, 0x98, 0x2e, 0xbb, 0xcc, 0x01, 0x30, 0x23, 0x2e, 0xa6, 0x00, 0xa2, 0x6f, 0xb3, + 0x6f, 0x1a, 0x25, 0x26, 0xbc, 0x86, 0xba, 0x25, 0xbc, 0x0f, 0xb8, 0x54, 0xb1, 0x00, 0xb2, 0xa6, 0x7f, 0x0c, 0x2f, + 0x1f, 0x50, 0x21, 0x54, 0x0b, 0x30, 0x0b, 0x2e, 0x08, 0x02, 0x29, 0x58, 0x1b, 0x42, 0x9b, 0x42, 0x6c, 0x09, 0x0b, + 0x42, 0x2b, 0x2e, 0x08, 0x02, 0x8b, 0x42, 0x72, 0x84, 0x2d, 0x50, 0x58, 0x09, 0x27, 0x52, 0x01, 0x50, 0x92, 0x7f, + 0x85, 0x7f, 0x98, 0x2e, 0xc2, 0xc0, 0x01, 0x2e, 0xa1, 0x00, 0xe5, 0x6f, 0xd4, 0x6f, 0x83, 0x6f, 0x92, 0x6f, 0x1d, + 0x52, 0x23, 0x5c, 0x98, 0x2e, 0x06, 0xcd, 0xb3, 0x6f, 0x1f, 0x50, 0x72, 0x6f, 0xb4, 0xbc, 0x14, 0x40, 0x80, 0xb2, + 0x9f, 0xba, 0x02, 0x40, 0x01, 0x30, 0xe0, 0x7f, 0x05, 0x2f, 0x40, 0xb3, 0x03, 0x2f, 0x21, 0x5c, 0x11, 0x30, 0x94, + 0x43, 0x82, 0x43, 0xb3, 0xbd, 0xbf, 0xb9, 0xc0, 0xb2, 0x1c, 0x2f, 0x53, 0x6f, 0x23, 0x01, 0x63, 0x6f, 0x93, 0x02, + 0x02, 0x42, 0x40, 0x91, 0x29, 0x2e, 0xa2, 0x00, 0x21, 0x50, 0x12, 0x2f, 0x21, 0x56, 0x00, 0x2e, 0xd5, 0x40, 0xc3, + 0x40, 0x65, 0x05, 0xd3, 0x06, 0xc0, 0xaa, 0x04, 0x2f, 0xc0, 0x90, 0x08, 0x2f, 0xa3, 0x6f, 0x5d, 0x0f, 0x05, 0x2f, + 0xa5, 0x6f, 0x40, 0xb3, 0x02, 0x2f, 0x14, 0x42, 0x02, 0x42, 0x11, 0x30, 0xc0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0xe2, + 0x6f, 0x25, 0x52, 0x01, 0x2e, 0xa2, 0x00, 0x82, 0x40, 0x50, 0x42, 0x08, 0x2c, 0x42, 0x42, 0x11, 0x30, 0x23, 0x2e, + 0xa6, 0x00, 0x01, 0x30, 0xc0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x00, 0x2e, 0xfb, 0x6f, 0x20, 0x5f, 0xb8, 0x2e, 0x01, + 0x2e, 0xc0, 0x00, 0x19, 0xb2, 0x90, 0x2e, 0x84, 0xb2, 0x1a, 0xb2, 0x76, 0x2f, 0x1b, 0xb2, 0x25, 0x2f, 0x1d, 0x90, + 0x90, 0x2e, 0x9b, 0xb2, 0x03, 0x2e, 0xaa, 0x00, 0x41, 0xa2, 0x90, 0x2e, 0x9b, 0xb2, 0x02, 0x30, 0x25, 0x2e, 0xaa, + 0x00, 0x45, 0x52, 0x05, 0x2e, 0xe8, 0x00, 0x62, 0x42, 0xd2, 0x33, 0x07, 0x2e, 0xe7, 0x00, 0x43, 0x42, 0x4a, 0x00, + 0x42, 0x30, 0x43, 0x40, 0x9a, 0x0a, 0x42, 0x42, 0x11, 0x30, 0x49, 0x56, 0x03, 0x0a, 0x05, 0x2e, 0x0c, 0x02, 0x3d, + 0x58, 0x21, 0x2e, 0xc0, 0x00, 0x23, 0x2e, 0x19, 0x00, 0x94, 0x08, 0xc0, 0x2e, 0x25, 0x2e, 0x0c, 0x02, 0x01, 0x2e, + 0xaa, 0x00, 0x03, 0xa2, 0x90, 0x2e, 0x9b, 0xb2, 0x00, 0x30, 0x21, 0x2e, 0xaa, 0x00, 0x47, 0x52, 0x05, 0x2e, 0xc1, + 0xf5, 0x66, 0x40, 0xae, 0xbd, 0x44, 0x40, 0xbe, 0xb9, 0x35, 0x30, 0x43, 0x82, 0x68, 0xbf, 0xeb, 0x04, 0x62, 0x40, + 0x74, 0x0b, 0x28, 0xbf, 0x43, 0x84, 0x44, 0x40, 0xa7, 0x40, 0x34, 0x0b, 0x86, 0x40, 0xab, 0x10, 0xf8, 0xbf, 0x35, + 0x52, 0x7e, 0x0b, 0x56, 0x40, 0x23, 0x11, 0xb2, 0x05, 0x3f, 0x5e, 0xeb, 0x10, 0xb7, 0x01, 0x39, 0x5a, 0x57, 0x40, + 0x75, 0x0e, 0xbc, 0x05, 0x41, 0x5e, 0xb7, 0x01, 0x21, 0x2e, 0xed, 0xf4, 0x17, 0x30, 0x38, 0x22, 0x75, 0x0e, 0x37, + 0x5a, 0x41, 0x40, 0x52, 0x43, 0x8b, 0x04, 0x21, 0x30, 0x41, 0x0a, 0x48, 0x22, 0x43, 0x50, 0x54, 0x43, 0x10, 0x00, + 0x3b, 0x54, 0x43, 0x43, 0x42, 0x0e, 0x43, 0x30, 0x8b, 0x0a, 0xc0, 0x33, 0x45, 0x56, 0x18, 0x00, 0x51, 0x22, 0x02, + 0x40, 0x91, 0xbc, 0xb3, 0x3f, 0x93, 0x08, 0x41, 0x82, 0xd4, 0x31, 0x29, 0x2e, 0xc0, 0x00, 0x02, 0x42, 0x23, 0x2e, + 0xdc, 0x00, 0xb8, 0x2e, 0x01, 0x2e, 0xaa, 0x00, 0x03, 0xa2, 0x45, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0xaa, 0x00, 0x47, + 0x54, 0x03, 0x2e, 0xc1, 0xf5, 0xa0, 0x40, 0x83, 0x8a, 0x83, 0x40, 0x08, 0xbe, 0x60, 0x41, 0x42, 0x41, 0x43, 0x8b, + 0x08, 0xbf, 0x60, 0x41, 0xe3, 0x0a, 0x44, 0x41, 0xb2, 0x0a, 0x0b, 0x2e, 0xed, 0xf4, 0xb6, 0x3f, 0x6e, 0x09, 0x9e, + 0xbc, 0x08, 0xbc, 0x04, 0x0b, 0x9e, 0xb8, 0x36, 0x30, 0x71, 0x04, 0x2b, 0x2e, 0xed, 0xf4, 0x35, 0x50, 0x59, 0x11, + 0x15, 0x42, 0x91, 0x10, 0x07, 0x2e, 0xed, 0xf4, 0x16, 0x30, 0x12, 0x42, 0x61, 0x10, 0xde, 0x0a, 0xb5, 0x31, 0x2b, + 0x2e, 0xc0, 0x00, 0x01, 0x42, 0x27, 0x2e, 0xed, 0xf4, 0xb8, 0x2e, 0x01, 0x2e, 0xaa, 0x00, 0x01, 0xa2, 0x12, 0x2f, + 0x00, 0x30, 0x21, 0x2e, 0xaa, 0x00, 0x01, 0x2e, 0xed, 0xf4, 0x41, 0x30, 0x01, 0x0a, 0x21, 0x2e, 0xed, 0xf4, 0x01, + 0x2e, 0xed, 0xf4, 0x11, 0x30, 0x01, 0x0a, 0x21, 0x2e, 0xed, 0xf4, 0xa1, 0x31, 0xc0, 0x2e, 0x23, 0x2e, 0xc0, 0x00, + 0xb8, 0x2e, 0x53, 0x56, 0x4d, 0x54, 0xd0, 0x40, 0xc4, 0x40, 0x0b, 0x2e, 0xfd, 0xf3, 0x53, 0x52, 0x90, 0x42, 0x94, + 0x42, 0x95, 0x42, 0x05, 0x30, 0x55, 0x50, 0x0f, 0x88, 0x06, 0x40, 0x04, 0x41, 0x96, 0x42, 0xc5, 0x42, 0x48, 0xbe, + 0x73, 0x30, 0x0d, 0x2e, 0xac, 0x00, 0x4f, 0xba, 0x84, 0x42, 0x03, 0x42, 0x81, 0xb3, 0x02, 0x2f, 0x2b, 0x2e, 0x6f, + 0xf5, 0x06, 0x2d, 0x05, 0x2e, 0x77, 0xf7, 0x51, 0x56, 0x93, 0x08, 0x25, 0x2e, 0x77, 0xf7, 0x4f, 0x54, 0x25, 0x2e, + 0xc2, 0xf5, 0x07, 0x2e, 0xfd, 0xf3, 0x42, 0x30, 0xb4, 0x33, 0xda, 0x0a, 0x4c, 0x00, 0x27, 0x2e, 0xfd, 0xf3, 0x43, + 0x40, 0xd4, 0x3f, 0xdc, 0x08, 0x43, 0x42, 0x00, 0x2e, 0x00, 0x2e, 0x43, 0x40, 0x24, 0x30, 0xdc, 0x0a, 0x43, 0x42, + 0x04, 0x80, 0x03, 0x2e, 0xfd, 0xf3, 0x4a, 0x0a, 0x23, 0x2e, 0xfd, 0xf3, 0x61, 0x34, 0xc0, 0x2e, 0x01, 0x42, 0x00, + 0x2e, 0xf0, 0x52, 0xfb, 0x7f, 0x98, 0x2e, 0x09, 0xb5, 0x98, 0x2e, 0x30, 0xb5, 0x5f, 0x58, 0xe1, 0x7f, 0x32, 0x83, + 0x81, 0x7f, 0x3a, 0x25, 0x57, 0x54, 0xe5, 0x8a, 0xc2, 0x7f, 0xeb, 0x86, 0x59, 0x52, 0xb4, 0x7f, 0x51, 0x7f, 0x73, + 0x7f, 0x65, 0x7f, 0xd0, 0x7f, 0xa3, 0x7f, 0x95, 0x7f, 0x14, 0x30, 0x5b, 0x54, 0x81, 0x6f, 0x42, 0x7f, 0x00, 0x2e, + 0x53, 0x40, 0x45, 0x8c, 0x42, 0x40, 0x90, 0x41, 0xbb, 0x83, 0x86, 0x41, 0xd8, 0x04, 0x16, 0x06, 0x00, 0xac, 0x81, + 0x7f, 0x02, 0x2f, 0x02, 0x30, 0xd3, 0x04, 0x10, 0x06, 0xc1, 0x84, 0x01, 0x30, 0xc1, 0x02, 0x0b, 0x16, 0x04, 0x09, + 0x14, 0x01, 0x99, 0x02, 0xc1, 0xb9, 0xaf, 0xbc, 0x59, 0x0a, 0xc4, 0x6f, 0x51, 0x43, 0xa1, 0xb4, 0x12, 0x41, 0x13, + 0x41, 0x41, 0x43, 0x35, 0x7f, 0xc4, 0x7f, 0x26, 0x31, 0xe5, 0x6f, 0xd4, 0x6f, 0x98, 0x2e, 0x37, 0xca, 0x32, 0x6f, + 0x65, 0x6f, 0x83, 0x40, 0x42, 0x41, 0x23, 0x7f, 0x12, 0x7f, 0xf6, 0x30, 0x40, 0x25, 0x51, 0x25, 0x98, 0x2e, 0x37, + 0xca, 0x14, 0x6f, 0x20, 0x05, 0x60, 0x6f, 0x25, 0x6f, 0x69, 0x07, 0x72, 0x6f, 0x31, 0x6f, 0x0b, 0x30, 0x04, 0x42, + 0x9b, 0x42, 0x8b, 0x42, 0x55, 0x42, 0x32, 0x7f, 0x40, 0xa9, 0xb3, 0x6f, 0x61, 0x7f, 0x02, 0x30, 0xd0, 0x40, 0xb3, + 0x7f, 0x03, 0x2f, 0x40, 0x91, 0x15, 0x2f, 0x00, 0xa7, 0x13, 0x2f, 0x00, 0xa4, 0x11, 0x2f, 0x84, 0xbd, 0x98, 0x2e, + 0x79, 0xca, 0x55, 0x6f, 0x6b, 0x54, 0x54, 0x41, 0x82, 0x00, 0xf3, 0x3f, 0x45, 0x41, 0xcb, 0x02, 0xf6, 0x30, 0x98, + 0x2e, 0x37, 0xca, 0x33, 0x6f, 0x74, 0x6f, 0xc1, 0x42, 0x03, 0x2c, 0x00, 0x43, 0x74, 0x6f, 0x33, 0x6f, 0x00, 0x2e, + 0x42, 0x6f, 0x55, 0x6f, 0x91, 0x40, 0x42, 0x8b, 0x00, 0x41, 0x41, 0x00, 0x01, 0x43, 0x55, 0x7f, 0x14, 0x30, 0xc1, + 0x40, 0x95, 0x40, 0x4d, 0x02, 0xb5, 0x6f, 0x65, 0x50, 0x68, 0x0e, 0x65, 0x6f, 0xd1, 0x42, 0x73, 0x7f, 0x8a, 0x2f, + 0x09, 0x2e, 0xac, 0x00, 0x01, 0xb3, 0x23, 0x2f, 0x5f, 0x58, 0x90, 0x6f, 0x17, 0x30, 0x13, 0x41, 0xa6, 0x6f, 0xe4, + 0x7f, 0x00, 0x2e, 0x91, 0x41, 0x14, 0x40, 0x92, 0x41, 0x15, 0x40, 0x17, 0x2e, 0x6f, 0xf5, 0xa6, 0x7f, 0xd0, 0x7f, + 0xcb, 0x7f, 0x98, 0x2e, 0xd3, 0x03, 0x07, 0x15, 0xc2, 0x6f, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, 0xc3, 0xa3, 0xc1, + 0x8f, 0xe4, 0x6f, 0xd0, 0x6f, 0xe6, 0x2f, 0x14, 0x30, 0x05, 0x2e, 0x6f, 0xf5, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, + 0x80, 0x2e, 0x93, 0xb4, 0x61, 0x54, 0x34, 0x30, 0x85, 0x40, 0xab, 0x84, 0xec, 0x08, 0x91, 0x40, 0xb8, 0xbd, 0xd9, + 0x00, 0x36, 0xbc, 0xc1, 0x30, 0xe9, 0x08, 0x86, 0xb6, 0x25, 0x7e, 0x98, 0x8a, 0x81, 0x40, 0x69, 0x85, 0xb6, 0xbd, + 0x59, 0x00, 0x45, 0x41, 0x90, 0x32, 0xd0, 0x00, 0x6c, 0x09, 0x82, 0x40, 0xd8, 0xbe, 0x96, 0xbc, 0x6a, 0x01, 0x16, + 0xb5, 0x32, 0x7e, 0x1a, 0x25, 0x70, 0x3d, 0x88, 0x00, 0x56, 0xbc, 0x0b, 0x30, 0x06, 0xb4, 0x7b, 0x7d, 0x62, 0x82, + 0x40, 0x7e, 0x8b, 0x7d, 0xfd, 0x8a, 0xd1, 0x7f, 0x9b, 0x7d, 0xe2, 0x7f, 0xe1, 0x30, 0xc3, 0x40, 0x69, 0x50, 0x9c, + 0x09, 0xb1, 0x15, 0xee, 0xb7, 0x56, 0x41, 0xf8, 0xbf, 0xb7, 0x0b, 0x42, 0xbe, 0x7e, 0x82, 0x68, 0x0e, 0x96, 0x42, + 0xf4, 0x2f, 0x4a, 0x25, 0xa2, 0x3d, 0x22, 0x01, 0x2a, 0x25, 0xa0, 0x82, 0xb4, 0x7f, 0xc4, 0x7f, 0x81, 0x7f, 0x05, + 0x30, 0x67, 0x54, 0xb7, 0x80, 0x15, 0x56, 0x6b, 0x58, 0xa0, 0x8c, 0x60, 0x7f, 0x72, 0x7f, 0x00, 0x2e, 0x80, 0x41, + 0xc3, 0x08, 0xb8, 0xbd, 0x38, 0xb7, 0xe6, 0xbd, 0x82, 0x40, 0x1c, 0x01, 0x29, 0xbd, 0xce, 0x16, 0x29, 0xb5, 0x6a, + 0xbb, 0xb6, 0xbd, 0xa0, 0x6f, 0x52, 0x7f, 0xde, 0x0a, 0x5d, 0x03, 0x12, 0x40, 0x54, 0x42, 0x45, 0x42, 0x41, 0x7f, + 0xf6, 0x30, 0x13, 0x40, 0xa0, 0x7f, 0x98, 0x2e, 0x37, 0xca, 0x1a, 0xbd, 0x16, 0xb6, 0x86, 0xba, 0x00, 0xa9, 0xaa, + 0x0a, 0x6d, 0x52, 0x0f, 0x2f, 0x00, 0x91, 0x6d, 0x52, 0x03, 0x2f, 0x6d, 0x5a, 0x55, 0x0f, 0x6d, 0x52, 0x08, 0x2f, + 0x3f, 0xa1, 0x04, 0x2f, 0x3f, 0x91, 0x03, 0x2f, 0x6b, 0x58, 0xd4, 0x0f, 0x00, 0x2f, 0x6b, 0x54, 0x12, 0x25, 0xf2, + 0x33, 0x98, 0x2e, 0xd9, 0xc0, 0x74, 0x6f, 0xf2, 0x37, 0x42, 0x09, 0x05, 0x43, 0x21, 0x85, 0x54, 0x6f, 0xd9, 0xbe, + 0x72, 0x7f, 0x8c, 0x16, 0xd9, 0xb5, 0x66, 0x6f, 0x26, 0xbc, 0xca, 0xba, 0xa1, 0x41, 0x8b, 0x16, 0x45, 0x0b, 0x3a, + 0xb8, 0x56, 0x7f, 0x26, 0xbd, 0x90, 0x0a, 0x98, 0xbf, 0x86, 0x41, 0x80, 0x6f, 0xfe, 0x0b, 0x41, 0x6f, 0x06, 0x40, + 0xb6, 0xbd, 0x60, 0x40, 0xf3, 0x00, 0x46, 0xbe, 0x82, 0x02, 0x34, 0x01, 0x2f, 0xbf, 0x47, 0x7f, 0x81, 0x7f, 0xb1, + 0xb8, 0x3f, 0xbd, 0xcf, 0x17, 0x45, 0x03, 0xf1, 0x0a, 0x37, 0x7f, 0x98, 0x2e, 0x79, 0xca, 0xb4, 0x6f, 0x35, 0x6f, + 0x10, 0x43, 0x11, 0x43, 0xb4, 0x7f, 0xf6, 0x30, 0x44, 0x6f, 0x20, 0x25, 0x31, 0x25, 0x98, 0x2e, 0x37, 0xca, 0x62, + 0x6f, 0x88, 0xb6, 0x85, 0x42, 0x02, 0x32, 0x54, 0x6f, 0x75, 0x6f, 0x63, 0x52, 0x00, 0x43, 0x69, 0x0e, 0x03, 0x81, + 0xaa, 0x00, 0x81, 0x6f, 0x15, 0x56, 0x6b, 0x58, 0x05, 0x30, 0x82, 0x2f, 0xe1, 0x6f, 0xf3, 0x30, 0xd4, 0x6f, 0xd1, + 0x7f, 0x22, 0x30, 0x15, 0x41, 0x41, 0x40, 0xb4, 0x7f, 0xa1, 0x7f, 0x85, 0x7f, 0x98, 0x2e, 0x0f, 0xca, 0xc1, 0x6f, + 0x82, 0x6f, 0x54, 0x40, 0x90, 0x00, 0x55, 0x40, 0xca, 0x16, 0xc1, 0x7f, 0x82, 0x7f, 0xf6, 0x30, 0x98, 0x2e, 0x37, + 0xca, 0x84, 0x6f, 0x60, 0x04, 0x22, 0x30, 0xf3, 0x30, 0x98, 0x2e, 0x5a, 0xca, 0xa4, 0x6f, 0xa0, 0x00, 0xd1, 0x6f, + 0xb4, 0x6f, 0x95, 0x6f, 0x65, 0x0e, 0x52, 0x42, 0xf3, 0x30, 0xdc, 0x2f, 0x69, 0x58, 0x0d, 0x2e, 0x77, 0xf7, 0x3d, + 0x85, 0xe5, 0x6f, 0x31, 0x30, 0x03, 0x30, 0x30, 0x30, 0xc0, 0x17, 0xb7, 0x09, 0x5d, 0x5e, 0xb7, 0x0b, 0x57, 0x41, + 0x97, 0x42, 0xf8, 0xbb, 0xf9, 0x09, 0xfb, 0x15, 0x02, 0xbc, 0xc2, 0x86, 0x54, 0x0e, 0xb7, 0x0b, 0xf1, 0x2f, 0x86, + 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0x10, 0x5d, 0xb8, 0x2e, 0x10, 0x50, 0x01, 0x2e, 0xa8, 0x00, 0x00, 0xb2, 0xfb, 0x7f, + 0x5d, 0x2f, 0x01, 0xb2, 0x54, 0x2f, 0x02, 0xb2, 0x4e, 0x2f, 0x03, 0x90, 0x63, 0x2f, 0x73, 0x50, 0x39, 0x82, 0x02, + 0x40, 0x81, 0x88, 0x75, 0x54, 0x41, 0x40, 0x7b, 0x56, 0x04, 0x42, 0x00, 0x2e, 0x94, 0x40, 0x95, 0x40, 0xd8, 0xbe, + 0x2c, 0x0b, 0x45, 0x40, 0x6c, 0x01, 0x55, 0x42, 0x0c, 0x17, 0x45, 0x40, 0x2c, 0x03, 0x54, 0x42, 0x53, 0x0e, 0xf2, + 0x2f, 0x7d, 0x56, 0x3e, 0x82, 0xe2, 0x40, 0xc3, 0x40, 0x28, 0xbd, 0x93, 0x0a, 0x43, 0x40, 0xda, 0x00, 0x53, 0x42, + 0x8a, 0x16, 0x43, 0x40, 0x9a, 0x02, 0x52, 0x42, 0x00, 0x2e, 0x41, 0x40, 0x49, 0x54, 0x4a, 0x0e, 0x3b, 0x2f, 0x3a, + 0x82, 0x00, 0x30, 0x41, 0x40, 0x21, 0x2e, 0x65, 0x01, 0x40, 0xb2, 0x0a, 0x2f, 0x98, 0x2e, 0xde, 0xb2, 0x98, 0x2e, + 0x5c, 0xb5, 0x98, 0x2e, 0x72, 0xb5, 0xfb, 0x6f, 0xf0, 0x5f, 0x00, 0x30, 0x80, 0x2e, 0xbf, 0x03, 0x79, 0x54, 0x6f, + 0x56, 0x83, 0x42, 0x8f, 0x86, 0x74, 0x30, 0x77, 0x54, 0xc4, 0x42, 0x11, 0x30, 0x23, 0x2e, 0xa8, 0x00, 0xa1, 0x42, + 0x23, 0x30, 0x27, 0x2e, 0xab, 0x00, 0x21, 0x2e, 0xaa, 0x00, 0xba, 0x82, 0x18, 0x2c, 0x81, 0x42, 0x30, 0x30, 0x21, + 0x2e, 0xa8, 0x00, 0x13, 0x2d, 0x21, 0x30, 0x00, 0x30, 0x23, 0x2e, 0xa8, 0x00, 0x21, 0x2e, 0x7b, 0xf7, 0x0c, 0x2d, + 0x77, 0x30, 0x98, 0x2e, 0x9c, 0xb2, 0x71, 0x50, 0x0c, 0x82, 0x12, 0x30, 0x40, 0x42, 0x25, 0x2e, 0xa8, 0x00, 0x2f, + 0x2e, 0x7b, 0xf7, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0x0a, 0x25, 0x39, 0x86, 0xfb, 0x7f, 0xe1, 0x32, + 0x62, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0x15, 0x56, 0xa5, 0x6f, 0xab, 0x08, 0x91, 0x6f, 0x4b, 0x08, 0x7f, 0x56, 0xc4, + 0x6f, 0x23, 0x09, 0x4d, 0xba, 0x93, 0xbc, 0x8c, 0x0b, 0xd1, 0x6f, 0x0b, 0x09, 0x5f, 0x52, 0x81, 0x5e, 0x56, 0x42, + 0xaf, 0x09, 0x4d, 0xba, 0x23, 0xbd, 0x94, 0x0a, 0xe5, 0x6f, 0x68, 0xbb, 0xeb, 0x08, 0xbd, 0xb9, 0x63, 0xbe, 0xfb, + 0x6f, 0x52, 0x42, 0xe3, 0x0a, 0xc0, 0x2e, 0x43, 0x42, 0x90, 0x5f, 0x65, 0x50, 0x03, 0x2e, 0x25, 0xf3, 0x12, 0x40, + 0x00, 0x40, 0x28, 0xba, 0x9b, 0xbc, 0x88, 0xbd, 0x93, 0xb4, 0xe3, 0x0a, 0x89, 0x16, 0x08, 0xb6, 0xc0, 0x2e, 0x19, + 0x00, 0x62, 0x02, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x97, 0xb4, 0x01, 0x2e, 0xa8, 0x00, 0x31, 0x30, 0x08, 0x04, + 0xfb, 0x6f, 0x01, 0x30, 0xf0, 0x5f, 0x23, 0x2e, 0xaa, 0x00, 0x21, 0x2e, 0xab, 0x00, 0xb8, 0x2e, 0x83, 0x50, 0x21, + 0x34, 0x01, 0x42, 0x82, 0x30, 0xc1, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x01, 0x00, 0x22, 0x30, 0x01, 0x40, 0x4a, 0x0a, + 0x01, 0x42, 0xb8, 0x2e, 0x83, 0x54, 0xf0, 0x3b, 0x83, 0x40, 0xd8, 0x08, 0x85, 0x52, 0x83, 0x42, 0x00, 0x30, 0x83, + 0x30, 0x50, 0x42, 0xc4, 0x32, 0x27, 0x2e, 0x64, 0xf5, 0x94, 0x00, 0x50, 0x42, 0x40, 0x42, 0xd3, 0x3f, 0x84, 0x40, + 0x7d, 0x82, 0xe3, 0x08, 0x40, 0x42, 0x83, 0x42, 0xb8, 0x2e, 0x79, 0x52, 0x00, 0x30, 0x40, 0x42, 0x7c, 0x86, 0x4d, + 0x52, 0x09, 0x2e, 0x50, 0x01, 0x53, 0x54, 0xc4, 0x42, 0xd3, 0x86, 0x54, 0x40, 0x55, 0x40, 0x94, 0x42, 0x85, 0x42, + 0x21, 0x2e, 0xab, 0x00, 0x42, 0x40, 0x25, 0x2e, 0xfd, 0xf3, 0xc0, 0x42, 0x7e, 0x82, 0x05, 0x2e, 0x86, 0x00, 0x80, + 0xb2, 0x14, 0x2f, 0x05, 0x2e, 0x0b, 0x02, 0x27, 0xbd, 0x2f, 0xb9, 0x80, 0x90, 0x02, 0x2f, 0x21, 0x2e, 0x6f, 0xf5, + 0x0c, 0x2d, 0x07, 0x2e, 0x51, 0x01, 0x14, 0x30, 0x1c, 0x09, 0x05, 0x2e, 0x77, 0xf7, 0x51, 0x56, 0x47, 0xbe, 0x93, + 0x08, 0x94, 0x0a, 0x25, 0x2e, 0x77, 0xf7, 0x87, 0x54, 0x50, 0x42, 0x4a, 0x0e, 0xfc, 0x2f, 0xb8, 0x2e, 0x50, 0x50, + 0x02, 0x30, 0x43, 0x86, 0x85, 0x50, 0xfb, 0x7f, 0xe3, 0x7f, 0xd2, 0x7f, 0xc0, 0x7f, 0xb1, 0x7f, 0x00, 0x2e, 0x41, + 0x40, 0x00, 0x40, 0x48, 0x04, 0x98, 0x2e, 0x74, 0xc0, 0x1e, 0xaa, 0xd3, 0x6f, 0x14, 0x30, 0xb1, 0x6f, 0xe3, 0x22, + 0xc0, 0x6f, 0x52, 0x40, 0xe4, 0x6f, 0x4c, 0x0e, 0x12, 0x42, 0xd3, 0x7f, 0xeb, 0x2f, 0x03, 0x2e, 0x66, 0x01, 0x40, + 0x90, 0x11, 0x30, 0x03, 0x2f, 0x23, 0x2e, 0x66, 0x01, 0x02, 0x2c, 0x00, 0x30, 0xd0, 0x6f, 0xfb, 0x6f, 0xb0, 0x5f, + 0xb8, 0x2e, 0x40, 0x50, 0xf1, 0x7f, 0x0a, 0x25, 0x3c, 0x86, 0xeb, 0x7f, 0x41, 0x33, 0x22, 0x30, 0x98, 0x2e, 0xc2, + 0xc4, 0xd3, 0x6f, 0xf4, 0x30, 0xdc, 0x09, 0x8b, 0x58, 0xc2, 0x6f, 0x94, 0x09, 0x8d, 0x58, 0x6a, 0xbb, 0xdc, 0x08, + 0xb4, 0xb9, 0xb1, 0xbd, 0x89, 0x5a, 0x95, 0x08, 0x21, 0xbd, 0xf6, 0xbf, 0x77, 0x0b, 0x51, 0xbe, 0xf1, 0x6f, 0xeb, + 0x6f, 0x52, 0x42, 0x54, 0x42, 0xc0, 0x2e, 0x43, 0x42, 0xc0, 0x5f, 0x50, 0x50, 0x97, 0x50, 0x91, 0x30, 0x11, 0x42, + 0xfb, 0x7f, 0x3b, 0x30, 0x0b, 0x42, 0x11, 0x30, 0x02, 0x80, 0x23, 0x33, 0x01, 0x42, 0x03, 0x00, 0x07, 0x2e, 0x80, + 0x03, 0x05, 0x2e, 0xa7, 0x00, 0x19, 0x52, 0xe2, 0x7f, 0xd3, 0x7f, 0xc0, 0x7f, 0x98, 0x2e, 0xcd, 0xb5, 0xd1, 0x6f, + 0x08, 0x0a, 0x1a, 0x25, 0x7b, 0x86, 0xd0, 0x7f, 0x01, 0x33, 0x12, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xd1, 0x6f, 0x08, + 0x0a, 0x00, 0xb2, 0x0d, 0x2f, 0xe3, 0x6f, 0x01, 0x2e, 0x80, 0x03, 0x51, 0x30, 0xc7, 0x86, 0x23, 0x2e, 0x21, 0xf2, + 0x08, 0xbc, 0xc0, 0x42, 0x98, 0x2e, 0xd2, 0x01, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0xb0, 0x6f, 0x0b, 0xb8, 0x03, + 0x2e, 0x1b, 0x00, 0x08, 0x1a, 0xb0, 0x7f, 0x70, 0x30, 0x04, 0x2f, 0x21, 0x2e, 0x21, 0xf2, 0x00, 0x2e, 0x00, 0x2e, + 0xd0, 0x2e, 0x98, 0x2e, 0x6d, 0xc0, 0x98, 0x2e, 0x5d, 0xc0, 0x8f, 0x50, 0x98, 0x2e, 0x44, 0xcb, 0x91, 0x50, 0x98, + 0x2e, 0x46, 0xc3, 0x93, 0x50, 0x98, 0x2e, 0x53, 0xc7, 0x20, 0x26, 0xc0, 0x6f, 0x02, 0x31, 0x12, 0x42, 0xab, 0x31, + 0x0b, 0x42, 0x37, 0x80, 0x01, 0x30, 0x01, 0x42, 0x23, 0x33, 0x99, 0x52, 0xf0, 0x37, 0x44, 0x40, 0xa2, 0x0a, 0x42, + 0x42, 0x4b, 0x00, 0x07, 0x2e, 0x5e, 0xf7, 0x18, 0x08, 0x21, 0x2e, 0xdf, 0x00, 0xe1, 0x7f, 0x98, 0x2e, 0x20, 0x02, + 0xe0, 0x6f, 0x81, 0x30, 0x01, 0x42, 0x01, 0x30, 0xfb, 0x6f, 0x95, 0x56, 0x02, 0x30, 0x00, 0x2e, 0x00, 0x2e, 0x81, + 0x84, 0x53, 0x0e, 0xfa, 0x2f, 0x01, 0x42, 0x10, 0x30, 0xb0, 0x5f, 0x21, 0x2e, 0x21, 0xf2, 0xb8, 0x2e, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x00, 0x00, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, + 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, + 0x2e, 0x00, 0xc1 +}; + +/*! @name Global array that stores the feature input configuration of BMI220 */ +const struct bmi2_feature_config bmi220_feat_in[BMI220_MAX_FEAT_IN] = { + { .type = BMI2_CONFIG_ID, .page = BMI2_PAGE_1, .start_addr = BMI220_CONFIG_ID_STRT_ADDR }, + { .type = BMI2_STEP_DETECTOR, .page = BMI2_PAGE_1, .start_addr = BMI220_STEP_COUNT_STRT_ADDR }, + { .type = BMI2_STEP_COUNTER, .page = BMI2_PAGE_1, .start_addr = BMI220_STEP_COUNT_STRT_ADDR }, + { .type = BMI2_MAX_BURST_LEN, .page = BMI2_PAGE_1, .start_addr = BMI220_MAX_BURST_LEN_STRT_ADDR }, + { .type = BMI2_CRT_GYRO_SELF_TEST, .page = BMI2_PAGE_1, .start_addr = BMI220_CRT_GYRO_SELF_TEST_STRT_ADDR }, + { .type = BMI2_ABORT_CRT_GYRO_SELF_TEST, .page = BMI2_PAGE_1, .start_addr = BMI220_ABORT_STRT_ADDR }, + { .type = BMI2_AXIS_MAP, .page = BMI2_PAGE_1, .start_addr = BMI220_AXIS_MAP_STRT_ADDR }, + { .type = BMI2_ACCEL_SELF_TEST, .page = BMI2_PAGE_1, .start_addr = BMI220_ACCEL_SELF_TEST_STRT_ADDR }, + { .type = BMI2_NVM_PROG_PREP, .page = BMI2_PAGE_1, .start_addr = BMI220_NVM_PROG_PREP_STRT_ADDR }, + { .type = BMI2_GYRO_GAIN_UPDATE, .page = BMI2_PAGE_1, .start_addr = BMI220_GYRO_GAIN_UPDATE_STRT_ADDR }, + { .type = BMI2_ANY_MOTION, .page = BMI2_PAGE_2, .start_addr = BMI220_ANY_MOT_STRT_ADDR }, + { .type = BMI2_NO_MOTION, .page = BMI2_PAGE_2, .start_addr = BMI220_NO_MOT_STRT_ADDR } +}; + +/*! @name Global array that stores the feature output configuration */ +const struct bmi2_feature_config bmi220_feat_out[BMI220_MAX_FEAT_OUT] = { + { .type = BMI2_STEP_COUNTER, .page = BMI2_PAGE_0, .start_addr = BMI220_STEP_CNT_OUT_STRT_ADDR }, + { .type = BMI2_GYRO_GAIN_UPDATE, .page = BMI2_PAGE_0, .start_addr = BMI220_GYR_USER_GAIN_OUT_STRT_ADDR }, + { .type = BMI2_ACCEL_SELF_TEST, .page = BMI2_PAGE_0, .start_addr = BMI220_ACCEL_SELF_TEST_OUT_STRT_ADDR }, + { .type = BMI2_GYRO_CROSS_SENSE, .page = BMI2_PAGE_0, .start_addr = BMI220_GYRO_CROSS_SENSE_STRT_ADDR }, + { .type = BMI2_NVM_STATUS, .page = BMI2_PAGE_0, .start_addr = BMI220_NVM_VFRM_OUT_STRT_ADDR }, + { .type = BMI2_VFRM_STATUS, .page = BMI2_PAGE_0, .start_addr = BMI220_NVM_VFRM_OUT_STRT_ADDR } +}; + +/******************************************************************************/ + +/*! Local Function Prototypes + ******************************************************************************/ + +/*! + * @brief This internal API is used to validate the device pointer for + * null conditions. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev); + +/***************************************************************************/ + +/*! User Interface Definitions + ****************************************************************************/ + +/*! + * @brief This API: + * 1) updates the device structure with address of the configuration file. + * 2) Initializes BMI220 sensor. + * 3) Writes the configuration file. + * 4) Updates the feature offset parameters in the device structure. + * 5) Updates the maximum number of pages, in the device structure. + */ +int8_t bmi220_init(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) + { + /* Assign chip id of BMI220 */ + dev->chip_id = BMI220_CHIP_ID; + + /* get the size of config array */ + dev->config_size = sizeof(bmi220_config_file); + pr_err("config size %d\n",dev->config_size); + + /* Enable the variant specific features if any*/ + dev->variant_feature = BMI2_CRT_RTOSK_ENABLE | BMI2_GYRO_CROSS_SENS_ENABLE | BMI2_CRT_IN_FIFO_NOT_REQ; + + /* An extra dummy byte is read during SPI read */ + if (dev->intf == BMI2_SPI_INTERFACE) + { + dev->dummy_byte = 1; + } + else + { + dev->dummy_byte = 0; + } + + /* If configuration file pointer is not assigned any address */ + if (!dev->config_file_ptr) + { + /* Give the address of the configuration file array to + * the device pointer + */ + dev->config_file_ptr = bmi220_config_file; + } + + /* Initialize BMI2 sensor */ + rslt = bmi2_sec_init(dev); + if (rslt == BMI2_OK) + { + /* Assign the offsets of the feature input + * configuration to the device structure + */ + dev->feat_config = bmi220_feat_in; + + /* Assign the offsets of the feature output to + * the device structure + */ + dev->feat_output = bmi220_feat_out; + + /* Assign the maximum number of pages to the + * device structure + */ + dev->page_max = BMI220_NUMBER_OF_PAGES; + + /* Assign maximum number of input sensors + * features to device structure + */ + dev->input_sens = BMI220_MAX_FEAT_IN; + + /* Assign maximum number of output sensors + * features to device structure + */ + dev->out_sens = BMI220_MAX_FEAT_OUT; + + /* Get the gyroscope cross axis sensitivity */ + rslt = bmi2_get_gyro_cross_sense(dev); + + } + } + + return rslt; +} + +/***************************************************************************/ + +/*! Local Function Definitions + ****************************************************************************/ + +/*! + * @brief This internal API is used to validate the device structure pointer for + * null conditions. + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_us == NULL)) + { + /* Device structure pointer is not valid */ + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} diff --git a/drivers/input/misc/bmi220/bmi220.h b/drivers/input/misc/bmi220/bmi220.h new file mode 100755 index 00000000000..e8606b320b6 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi220.h @@ -0,0 +1,125 @@ +/** +* Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. 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. +* +* 3. Neither the name of the copyright holder 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 AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS 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 bmi220.h +* @date 2020-01-24 +* @version v2.47.0 +* +*/ +#ifndef BMI220_H_ +#define BMI220_H_ + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************/ + +/*! Header files + ****************************************************************************/ +#include "bmi2.h" + +/***************************************************************************/ + +/*! Macro definitions + ****************************************************************************/ + +/*! @name BMI220 chip identifier */ +#define BMI220_CHIP_ID UINT8_C(0x26) + +/*! @name BMI220 feature input start addresses */ +#define BMI220_CONFIG_ID_STRT_ADDR UINT8_C(0x04) +#define BMI220_STEP_COUNT_STRT_ADDR UINT8_C(0x00) +#define BMI220_MAX_BURST_LEN_STRT_ADDR UINT8_C(0x06) +#define BMI220_CRT_GYRO_SELF_TEST_STRT_ADDR UINT8_C(0x07) +#define BMI220_ABORT_STRT_ADDR UINT8_C(0x07) +#define BMI220_AXIS_MAP_STRT_ADDR UINT8_C(0x08) +#define BMI220_ACCEL_SELF_TEST_STRT_ADDR UINT8_C(0x09) +#define BMI220_NVM_PROG_PREP_STRT_ADDR UINT8_C(0x09) +#define BMI220_GYRO_GAIN_UPDATE_STRT_ADDR UINT8_C(0x0A) +#define BMI220_ANY_MOT_STRT_ADDR UINT8_C(0x00) +#define BMI220_NO_MOT_STRT_ADDR UINT8_C(0x04) + +/*! @name BMI220 feature output start addresses */ +#define BMI220_STEP_CNT_OUT_STRT_ADDR UINT8_C(0x00) +#define BMI220_GYR_USER_GAIN_OUT_STRT_ADDR UINT8_C(0x04) +#define BMI220_ACCEL_SELF_TEST_OUT_STRT_ADDR UINT8_C(0x06) +#define BMI220_GYRO_CROSS_SENSE_STRT_ADDR UINT8_C(0x0C) +#define BMI220_NVM_VFRM_OUT_STRT_ADDR UINT8_C(0x0E) + +/*! @name Defines maximum number of pages */ +#define BMI220_NUMBER_OF_PAGES UINT8_C(4) + +/*! @name Defines maximum number of feature input configurations */ +#define BMI220_MAX_FEAT_IN UINT8_C(12) + +/*! @name Defines maximum number of feature outputs */ +#define BMI220_MAX_FEAT_OUT UINT8_C(6) + +/*! @name Mask definitions for feature interrupt status bits */ +#define BMI220_STEP_CNT_STATUS_MASK UINT8_C(0x02) +#define BMI220_NO_MOT_STATUS_MASK UINT8_C(0x20) +#define BMI220_ANY_MOT_STATUS_MASK UINT8_C(0x40) + +/***************************************************************************/ + +/*! BMI220 User Interface function prototypes + ****************************************************************************/ + +/*! + * @brief This API: + * 1) updates the device structure with address of the configuration file. + * 2) Initializes BMI220 sensor. + * 3) Writes the configuration file. + * 4) Updates the feature offset parameters in the device structure. + * 5) Updates the maximum number of pages, in the device structure. + * + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_DEV_NOT_FOUND - Invalid device + */ +int8_t bmi220_init(struct bmi2_dev *dev); + +/******************************************************************************/ +/*! @name C++ Guard Macros */ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* BMI220_H_ */ diff --git a/drivers/input/misc/bmi220/bmi2_defs.h b/drivers/input/misc/bmi220/bmi2_defs.h new file mode 100755 index 00000000000..d84e1f47f81 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi2_defs.h @@ -0,0 +1,2061 @@ +/** +* Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. 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. +* +* 3. Neither the name of the copyright holder 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 AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS 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 bmi2_defs.h +* @date 2020-01-24 +* @version v2.47.0 +* +*/ +#ifndef BMI2_DEFS_H_ +#define BMI2_DEFS_H_ + +/******************************************************************************/ +/*! @name Header includes */ +/******************************************************************************/ +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +/******************************************************************************/ +/*! @name Common macros */ +/******************************************************************************/ +#ifdef __KERNEL__ +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) S8_C(x) +#define UINT8_C(x) U8_C(x) +#endif + +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) S16_C(x) +#define UINT16_C(x) U16_C(x) +#endif + +#if !defined(INT32_C) && !defined(UINT32_C) +#define INT32_C(x) S32_C(x) +#define UINT32_C(x) U32_C(x) +#endif + +#if !defined(INT64_C) && !defined(UINT64_C) +#define INT64_C(x) S64_C(x) +#define UINT64_C(x) U64_C(x) +#endif +#endif + +/*! @name C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *) 0) +#endif +#endif + +/******************************************************************************/ +/*! @name General Macro Definitions */ +/******************************************************************************/ +/*! @name Utility macros */ +#define BMI2_SET_BITS(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MASK)) | \ + ((data << bitname##_POS) & bitname##_MASK)) + +#define BMI2_GET_BITS(reg_data, bitname) \ + ((reg_data & (bitname##_MASK)) >> \ + (bitname##_POS)) + +#define BMI2_SET_BIT_POS0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MASK)) | \ + (data & bitname##_MASK)) + +#define BMI2_GET_BIT_POS0(reg_data, bitname) (reg_data & (bitname##_MASK)) +#define BMI2_SET_BIT_VAL0(reg_data, bitname) (reg_data & ~(bitname##_MASK)) + +/*! @name For getting LSB and MSB */ +#define BMI2_GET_LSB(var) (uint8_t)(var & BMI2_SET_LOW_BYTE) +#define BMI2_GET_MSB(var) (uint8_t)((var & BMI2_SET_HIGH_BYTE) >> 8) + +/*! @name For defining absolute values */ +#define BMI2_ABS(a) ((a) > 0 ? (a) : -(a)) + +/*! @name LSB and MSB mask definitions */ +#define BMI2_SET_LOW_BYTE UINT16_C(0x00FF) +#define BMI2_SET_HIGH_BYTE UINT16_C(0xFF00) +#define BMI2_SET_LOW_NIBBLE UINT8_C(0x0F) + +/*! @name For enable and disable */ +#define BMI2_ENABLE UINT8_C(1) +#define BMI2_DISABLE UINT8_C(0) + +/*! @name To define TRUE or FALSE */ +#define BMI2_TRUE UINT8_C(1) +#define BMI2_FALSE UINT8_C(0) + +/*! @name To define success code */ +#define BMI2_OK INT8_C(0) + +/*! @name To define error codes */ +#define BMI2_E_NULL_PTR INT8_C(-1) +#define BMI2_E_COM_FAIL INT8_C(-2) +#define BMI2_E_DEV_NOT_FOUND INT8_C(-3) +#define BMI2_E_OUT_OF_RANGE INT8_C(-4) +#define BMI2_E_ACC_INVALID_CFG INT8_C(-5) +#define BMI2_E_GYRO_INVALID_CFG INT8_C(-6) +#define BMI2_E_ACC_GYR_INVALID_CFG INT8_C(-7) +#define BMI2_E_INVALID_SENSOR INT8_C(-8) +#define BMI2_E_CONFIG_LOAD INT8_C(-9) +#define BMI2_E_INVALID_PAGE INT8_C(-10) +#define BMI2_E_INVALID_FEAT_BIT INT8_C(-11) +#define BMI2_E_INVALID_INT_PIN INT8_C(-12) +#define BMI2_E_SET_APS_FAIL INT8_C(-13) +#define BMI2_E_AUX_INVALID_CFG INT8_C(-14) +#define BMI2_E_AUX_BUSY INT8_C(-15) +#define BMI2_E_SELF_TEST_FAIL INT8_C(-16) +#define BMI2_E_REMAP_ERROR INT8_C(-17) +#define BMI2_E_GYR_USER_GAIN_UPD_FAIL INT8_C(-18) +#define BMI2_E_SELF_TEST_NOT_DONE INT8_C(-19) +#define BMI2_E_INVALID_INPUT INT8_C(-20) +#define BMI2_E_INVALID_STATUS INT8_C(-21) +#define BMI2_E_CRT_ERROR INT8_C(-22) +#define BMI2_E_ST_ALREADY_RUNNING INT8_C(-23) +#define BMI2_E_CRT_READY_FOR_DL_FAIL_ABORT INT8_C(-24) +#define BMI2_E_DL_ERROR INT8_C(-25) +#define BMI2_E_PRECON_ERROR INT8_C(-26) +#define BMI2_E_ABORT_ERROR INT8_C(-27) +#define BMI2_E_GYRO_SELF_TEST_ERROR INT8_C(-28) +#define BMI2_E_GYRO_SELF_TEST_TIMEOUT INT8_C(-29) +#define BMI2_E_WRITE_CYCLE_ONGOING INT8_C(-30) +#define BMI2_E_WRITE_CYCLE_TIMEOUT INT8_C(-31) +#define BMI2_E_ST_NOT_RUNING INT8_C(-32) +#define BMI2_E_DATA_RDY_INT_FAILED INT8_C(-33) +#define BMI2_E_INVALID_FOC_POSITION INT8_C(-34) + +/*! @name To define warnings for FIFO activity */ +#define BMI2_W_FIFO_EMPTY INT8_C(1) +#define BMI2_W_PARTIAL_READ INT8_C(2) + +/*! @name Bit wise to define information */ +#define BMI2_I_MIN_VALUE UINT8_C(1) +#define BMI2_I_MAX_VALUE UINT8_C(2) + +/*! @name BMI2 register addresses */ +#define BMI2_CHIP_ID_ADDR UINT8_C(0x00) +#define BMI2_STATUS_ADDR UINT8_C(0x03) +#define BMI2_AUX_X_LSB_ADDR UINT8_C(0x04) +#define BMI2_ACC_X_LSB_ADDR UINT8_C(0x0C) +#define BMI2_GYR_X_LSB_ADDR UINT8_C(0x12) +#define BMI2_EVENT_ADDR UINT8_C(0x1B) +#define BMI2_INT_STATUS_0_ADDR UINT8_C(0x1C) +#define BMI2_INT_STATUS_1_ADDR UINT8_C(0x1D) +#define BMI2_SC_OUT_0_ADDR UINT8_C(0x1E) +#define BMI2_SYNC_COMMAND_ADDR UINT8_C(0x1E) +#define BMI2_GYR_CAS_GPIO0_ADDR UINT8_C(0x1E) +#define BMI2_INTERNAL_STATUS_ADDR UINT8_C(0x21) +#define BMI2_FIFO_LENGTH_0_ADDR UINT8_C(0X24) +#define BMI2_FIFO_DATA_ADDR UINT8_C(0X26) +#define BMI2_FEAT_PAGE_ADDR UINT8_C(0x2F) +#define BMI2_FEATURES_REG_ADDR UINT8_C(0x30) +#define BMI2_ACC_CONF_ADDR UINT8_C(0x40) +#define BMI2_GYR_CONF_ADDR UINT8_C(0x42) +#define BMI2_AUX_CONF_ADDR UINT8_C(0x44) +#define BMI2_FIFO_DOWNS_ADDR UINT8_C(0X45) +#define BMI2_FIFO_WTM_0_ADDR UINT8_C(0X46) +#define BMI2_FIFO_WTM_1_ADDR UINT8_C(0X47) +#define BMI2_FIFO_CONFIG_0_ADDR UINT8_C(0X48) +#define BMI2_FIFO_CONFIG_1_ADDR UINT8_C(0X49) +#define BMI2_AUX_DEV_ID_ADDR UINT8_C(0x4B) +#define BMI2_AUX_IF_CONF_ADDR UINT8_C(0x4C) +#define BMI2_AUX_RD_ADDR UINT8_C(0x4D) +#define BMI2_AUX_WR_ADDR UINT8_C(0x4E) +#define BMI2_AUX_WR_DATA_ADDR UINT8_C(0x4F) +#define BMI2_INT1_IO_CTRL_ADDR UINT8_C(0x53) +#define BMI2_INT2_IO_CTRL_ADDR UINT8_C(0x54) +#define BMI2_INT_LATCH_ADDR UINT8_C(0x55) +#define BMI2_INT1_MAP_FEAT_ADDR UINT8_C(0x56) +#define BMI2_INT2_MAP_FEAT_ADDR UINT8_C(0x57) +#define BMI2_INT_MAP_DATA_ADDR UINT8_C(0x58) +#define BMI2_INIT_CTRL_ADDR UINT8_C(0x59) +#define BMI2_INIT_ADDR_0 UINT8_C(0x5B) +#define BMI2_INIT_ADDR_1 UINT8_C(0x5C) +#define BMI2_INIT_DATA_ADDR UINT8_C(0x5E) +#define BMI2_AUX_IF_TRIM UINT8_C(0x68) +#define BMI2_GYR_CRT_CONF_ADDR UINT8_C(0X69) +#define BMI2_NVM_CONF_ADDR UINT8_C(0x6A) +#define BMI2_IF_CONF_ADDR UINT8_C(0X6B) +#define BMI2_ACC_SELF_TEST_ADDR UINT8_C(0X6D) +#define BMI2_GYR_SELF_TEST_AXES_ADDR UINT8_C(0x6E) +#define BMI2_SELF_TEST_MEMS_ADDR UINT8_C(0X6F) +#define BMI2_NV_CONF_ADDR UINT8_C(0x70) +#define BMI2_ACC_OFF_COMP_0_ADDR UINT8_C(0X71) +#define BMI2_GYR_OFF_COMP_3_ADDR UINT8_C(0X74) +#define BMI2_GYR_OFF_COMP_6_ADDR UINT8_C(0X77) +#define BMI2_GYR_USR_GAIN_0_ADDR UINT8_C(0X78) +#define BMI2_PWR_CONF_ADDR UINT8_C(0x7C) +#define BMI2_PWR_CTRL_ADDR UINT8_C(0x7D) +#define BMI2_CMD_REG_ADDR UINT8_C(0x7E) + +/*! @name BMI2 I2C address */ +#define BMI2_I2C_PRIM_ADDR UINT8_C(0x68) +#define BMI2_I2C_SEC_ADDR UINT8_C(0x69) + +/*! @name BMI2 Commands */ +#define BMI2_G_TRIGGER_CMD UINT8_C(0x02) +#define BMI2_USR_GAIN_CMD UINT8_C(0x03) +#define BMI2_NVM_PROG_CMD UINT8_C(0xA0) +#define BMI2_SOFT_RESET_CMD UINT8_C(0xB6) +#define BMI2_FIFO_FLUSH_CMD UINT8_C(0xB0) + +/*! @name Mask definitions for ..... */ +#define BMI2_GYR_RDY_FOR_DL_MASK UINT8_C(0x08) +#define BMI2_GYR_CRT_RUNNING_MASK UINT8_C(0x04) + +/*! @name Bit position definitions..... */ +#define BMI2_GYR_RDY_FOR_DL_POS UINT8_C(0x03) +#define BMI2_GYR_CRT_RUNNING_POS UINT8_C(0x02) + +/*! @name BMI2 sensor data bytes */ + +#define BMI2_ACC_GYR_NUM_BYTES UINT8_C(6) +#define BMI2_AUX_NUM_BYTES UINT8_C(8) +#define BMI2_CRT_CONFIG_FILE_SIZE UINT16_C(2048) +#define BMI2_FEAT_SIZE_IN_BYTES UINT8_C(16) +#define BMI2_ACC_CONFIG_LENGTH UINT8_C(2) + +/*! @name BMI2 configuration load status */ +#define BMI2_CONFIG_LOAD_SUCCESS UINT8_C(1) + +/*! @name To define BMI2 pages */ +#define BMI2_PAGE_0 UINT8_C(0) +#define BMI2_PAGE_1 UINT8_C(1) +#define BMI2_PAGE_2 UINT8_C(2) +#define BMI2_PAGE_3 UINT8_C(3) +#define BMI2_PAGE_4 UINT8_C(4) +#define BMI2_PAGE_5 UINT8_C(5) +#define BMI2_PAGE_6 UINT8_C(6) +#define BMI2_PAGE_7 UINT8_C(7) + +/*! @name Array Parameter DefinItions */ +#define BMI2_SENSOR_TIME_LSB_BYTE UINT8_C(0) +#define BMI2_SENSOR_TIME_XLSB_BYTE UINT8_C(1) +#define BMI2_SENSOR_TIME_MSB_BYTE UINT8_C(2) + +/*! @name mask definition for status register */ +#define BMI2_AUX_BUSY_MASK UINT8_C(0x04) +#define BMI2_CMD_RDY_MASK UINT8_C(0x10) +#define BMI2_DRDY_AUX_MASK UINT8_C(0x20) +#define BMI2_DRDY_GYR_MASK UINT8_C(0x40) +#define BMI2_DRDY_ACC_MASK UINT8_C(0x80) + +/*! @name Bit position for status register*/ +#define BMI2_AUX_BUSY_POS UINT8_C(0x02) +#define BMI2_CMD_RDY_POS UINT8_C(0x04) +#define BMI2_DRDY_AUX_POS UINT8_C(0x05) +#define BMI2_DRDY_GYR_POS UINT8_C(0x06) +#define BMI2_DRDY_ACC_POS UINT8_C(0x07) + +/*! @name Mask definitions for SPI read/write address */ +#define BMI2_SPI_RD_MASK UINT8_C(0x80) +#define BMI2_SPI_WR_MASK UINT8_C(0x7F) + +/*! @name Mask definitions for power configuration register */ +#define BMI2_ADV_POW_EN_MASK UINT8_C(0x01) + +/*! @name Mask definitions for initialization control register */ +#define BMI2_CONF_LOAD_EN_MASK UINT8_C(0x01) + +/*! @name Mask definitions for power control register */ +#define BMI2_AUX_EN_MASK UINT8_C(0x01) +#define BMI2_GYR_EN_MASK UINT8_C(0x02) +#define BMI2_ACC_EN_MASK UINT8_C(0x04) +#define BMI2_TEMP_EN_MASK UINT8_C(0x08) + +/*! @name Bit position definitions for power control register */ +#define BMI2_GYR_EN_POS UINT8_C(0x01) +#define BMI2_ACC_EN_POS UINT8_C(0x02) +#define BMI2_TEMP_EN_POS UINT8_C(0x03) + +/*! @name Mask definitions for sensor event flags */ +#define BMI2_EVENT_FLAG_MASK UINT8_C(0x1C) + +/*! @name Bit position definitions for sensor event flags */ +#define BMI2_EVENT_FLAG_POS UINT8_C(0x02) + +/*! @name Mask definitions to switch page */ +#define BMI2_SWITCH_PAGE_EN_MASK UINT8_C(0x07) + +/*! @name Accelerometer and Gyroscope Filter/Noise performance modes */ +/* Power optimized mode */ +#define BMI2_POWER_OPT_MODE UINT8_C(0) + +/* Performance optimized */ +#define BMI2_PERF_OPT_MODE UINT8_C(1) + +/*! @name Mask definitions of NVM register */ +#define BMI2_NV_ACC_OFFSET_MASK UINT8_C(0x08) + +/*! @name Bit position definitions of NVM register */ +#define BMI2_NV_ACC_OFFSET_POS UINT8_C(0x03) + +/*! @name Mask definition for config version */ +#define BMI2_CONFIG_MAJOR_MASK UINT16_C(0x3C0) +#define BMI2_CONFIG_MINOR_MASK UINT8_C(0x3F) + +/*! @name Bit position for major version from config */ +#define BMI2_CONFIG_MAJOR_POS UINT8_C(0x06) + +#define BMI2_GYRO_CROSS_AXES_SENSE_MASK UINT8_C(0x7F) +#define BMI2_GYRO_CROSS_AXES_SENSE_SIGN_BIT_MASK UINT8_C(0x40) + +/*! @name index for config major minor information */ +#define BMI2_CONFIG_INFO_LOWER UINT8_C(52) +#define BMI2_CONFIG_INFO_HIGHER UINT8_C(53) + +/*! @name Sensor status */ +#define BMI2_DRDY_ACC UINT8_C(0x80) +#define BMI2_DRDY_GYR UINT8_C(0x40) +#define BMI2_DRDY_AUX UINT8_C(0x20) +#define BMI2_CMD_RDY UINT8_C(0x10) +#define BMI2_AUX_BUSY UINT8_C(0x04) + +/*! @name Macro to define accelerometer configuration value for FOC */ +#define BMI2_FOC_ACC_CONF_VAL UINT8_C(0xB7) + +/*! @name Macro to define gyroscope configuration value for FOC */ +#define BMI2_FOC_GYR_CONF_VAL UINT8_C(0xB6) + +/*! @name Macro to define X Y and Z axis for an array */ +#define BMI2_X_AXIS UINT8_C(0) +#define BMI2_Y_AXIS UINT8_C(1) +#define BMI2_Z_AXIS UINT8_C(2) + +/*! @name mask and bit position for activity recognition settings */ +#define BMI2_ACT_RECG_POST_PROS_EN_DIS_MASK UINT8_C(0x01) +#define BMI2_ACT_RECG_BUFF_SIZE_MASK UINT8_C(0x0F) +#define BMI2_ACT_RECG_MIN_SEG_CONF_MASK UINT8_C(0x0F) + +/******************************************************************************/ +/*! @name Sensor Macro Definitions */ +/******************************************************************************/ +/*! @name Macros to define BMI2 sensor/feature types */ +#define BMI2_ACCEL UINT8_C(0) +#define BMI2_GYRO UINT8_C(1) +#define BMI2_AUX UINT8_C(2) +#define BMI2_SIG_MOTION UINT8_C(3) +#define BMI2_ANY_MOTION UINT8_C(4) +#define BMI2_NO_MOTION UINT8_C(5) +#define BMI2_STEP_DETECTOR UINT8_C(6) +#define BMI2_STEP_COUNTER UINT8_C(7) +#define BMI2_STEP_ACTIVITY UINT8_C(8) +#define BMI2_GYRO_GAIN_UPDATE UINT8_C(9) +#define BMI2_TILT UINT8_C(10) +#define BMI2_UP_HOLD_TO_WAKE UINT8_C(11) +#define BMI2_GLANCE_DETECTOR UINT8_C(12) +#define BMI2_WAKE_UP UINT8_C(13) +#define BMI2_ORIENTATION UINT8_C(14) +#define BMI2_HIGH_G UINT8_C(15) +#define BMI2_LOW_G UINT8_C(16) +#define BMI2_FLAT UINT8_C(17) +#define BMI2_EXT_SENS_SYNC UINT8_C(18) +#define BMI2_WRIST_GESTURE UINT8_C(19) +#define BMI2_WRIST_WEAR_WAKE_UP UINT8_C(20) +#define BMI2_WRIST_WEAR_WAKE_UP_WH UINT8_C(21) +#define BMI2_WRIST_GESTURE_WH UINT8_C(22) +#define BMI2_PRIMARY_OIS UINT8_C(23) +#define BMI2_FREE_FALL_DET UINT8_C(24) + +/* Non virtual sensor features */ +#define BMI2_STEP_COUNTER_PARAMS UINT8_C(25) +#define BMI2_TEMP UINT8_C(26) +#define BMI2_ACCEL_SELF_TEST UINT8_C(27) +#define BMI2_GYRO_SELF_OFF UINT8_C(28) +#define BMI2_ACTIVITY_RECOGNITION UINT8_C(29) +#define BMI2_MAX_BURST_LEN UINT8_C(30) +#define BMI2_SENS_MAX_NUM UINT8_C(31) +#define BMI2_AXIS_MAP UINT8_C(32) +#define BMI2_NVM_STATUS UINT8_C(33) +#define BMI2_VFRM_STATUS UINT8_C(34) +#define BMI2_GYRO_CROSS_SENSE UINT8_C(35) +#define BMI2_CRT_GYRO_SELF_TEST UINT8_C(36) +#define BMI2_ABORT_CRT_GYRO_SELF_TEST UINT8_C(37) +#define BMI2_NVM_PROG_PREP UINT8_C(38) +#define BMI2_ACTIVITY_RECOGNITION_SETTINGS UINT8_C(39) +#define BMI2_OIS_OUTPUT UINT8_C(40) +#define BMI2_CONFIG_ID UINT8_C(41) + +/*! @name Bit wise for selecting BMI2 sensors/features */ +#define BMI2_ACCEL_SENS_SEL (1) +#define BMI2_GYRO_SENS_SEL (1 << BMI2_GYRO) +#define BMI2_AUX_SENS_SEL (1 << BMI2_AUX) +#define BMI2_TEMP_SENS_SEL (1 << BMI2_TEMP) +#define BMI2_ANY_MOT_SEL (1 << BMI2_ANY_MOTION) +#define BMI2_NO_MOT_SEL (1 << BMI2_NO_MOTION) +#define BMI2_TILT_SEL (1 << BMI2_TILT) +#define BMI2_ORIENT_SEL (1 << BMI2_ORIENTATION) +#define BMI2_SIG_MOTION_SEL (1 << BMI2_SIG_MOTION) +#define BMI2_STEP_DETECT_SEL (1 << BMI2_STEP_DETECTOR) +#define BMI2_STEP_COUNT_SEL (1 << BMI2_STEP_COUNTER) +#define BMI2_STEP_ACT_SEL (1 << BMI2_STEP_ACTIVITY) +#define BMI2_GYRO_GAIN_UPDATE_SEL (1 << BMI2_GYRO_GAIN_UPDATE) +#define BMI2_UP_HOLD_TO_WAKE_SEL (1 << BMI2_UP_HOLD_TO_WAKE) +#define BMI2_GLANCE_DET_SEL (1 << BMI2_GLANCE_DETECTOR) +#define BMI2_WAKE_UP_SEL (1 << BMI2_WAKE_UP) +#define BMI2_HIGH_G_SEL (1 << BMI2_HIGH_G) +#define BMI2_LOW_G_SEL (1 << BMI2_LOW_G) +#define BMI2_FLAT_SEL (1 << BMI2_FLAT) +#define BMI2_EXT_SENS_SEL (1 << BMI2_EXT_SENS_SYNC) +#define BMI2_GYRO_SELF_OFF_SEL (1 << BMI2_GYRO_SELF_OFF) +#define BMI2_WRIST_GEST_SEL (1 << BMI2_WRIST_GESTURE) +#define BMI2_WRIST_WEAR_WAKE_UP_SEL (1 << BMI2_WRIST_WEAR_WAKE_UP) +#define BMI2_ACTIVITY_RECOGNITION_SEL (1 << BMI2_ACTIVITY_RECOGNITION) +#define BMI2_ACCEL_SELF_TEST_SEL (1 << BMI2_ACCEL_SELF_TEST) +#define BMI2_WRIST_GEST_W_SEL (1 << BMI2_WRIST_GESTURE_WH) +#define BMI2_WRIST_WEAR_WAKE_UP_WH_SEL (1 << BMI2_WRIST_WEAR_WAKE_UP_WH) +#define BMI2_PRIMARY_OIS_SEL (1 << BMI2_PRIMARY_OIS) +#define BMI2_FREE_FALL_DET_SEL (1 << BMI2_FREE_FALL_DET) + +/*! @name Bit wise selection of BMI2 sensors */ +#define BMI2_MAIN_SENSORS \ + (BMI2_ACCEL_SENS_SEL | BMI2_GYRO_SENS_SEL \ + | BMI2_AUX_SENS_SEL | BMI2_TEMP_SENS_SEL) + +/*! @name Maximum number of BMI2 main sensors */ +#define BMI2_MAIN_SENS_MAX_NUM UINT8_C(4) + +/*! @name Macro to specify the number of step counter parameters */ +#define BMI2_STEP_CNT_N_PARAMS UINT8_C(25) + +/*! @name Macro to specify the number of free-fall accel setting parameters */ +#define BMI2_FREE_FALL_ACCEL_SET_PARAMS UINT8_C(7) + +/*! @name Macro to select between single and double tap */ +#define BMI2_DOUBLE_TAP_SEL UINT8_C(0) +#define BMI2_SINGLE_TAP_SEL UINT8_C(1) + +#define BMI2_SELECT_GYRO_SELF_TEST UINT8_C(0) +#define BMI2_SELECT_CRT UINT8_C(1) + +/*! @name Macro for NVM enable */ +#define BMI2_NVM_UNLOCK_ENABLE UINT8_C(0x02) +#define BMI2_NVM_UNLOCK_DISABLE UINT8_C(0x00) + +/*! @name macro to select between gyro self test and CRT */ +#define BMI2_GYRO_SELF_TEST_SEL UINT8_C(0) +#define BMI2_CRT_SEL UINT8_C(1) + +/******************************************************************************/ +/*! @name Accelerometer Macro Definitions */ +/******************************************************************************/ +/*! @name Accelerometer Bandwidth parameters */ +#define BMI2_ACC_OSR4_AVG1 UINT8_C(0x00) +#define BMI2_ACC_OSR2_AVG2 UINT8_C(0x01) +#define BMI2_ACC_NORMAL_AVG4 UINT8_C(0x02) +#define BMI2_ACC_CIC_AVG8 UINT8_C(0x03) +#define BMI2_ACC_RES_AVG16 UINT8_C(0x04) +#define BMI2_ACC_RES_AVG32 UINT8_C(0x05) +#define BMI2_ACC_RES_AVG64 UINT8_C(0x06) +#define BMI2_ACC_RES_AVG128 UINT8_C(0x07) + +/*! @name Accelerometer Output Data Rate */ +#define BMI2_ACC_ODR_0_78HZ UINT8_C(0x01) +#define BMI2_ACC_ODR_1_56HZ UINT8_C(0x02) +#define BMI2_ACC_ODR_3_12HZ UINT8_C(0x03) +#define BMI2_ACC_ODR_6_25HZ UINT8_C(0x04) +#define BMI2_ACC_ODR_12_5HZ UINT8_C(0x05) +#define BMI2_ACC_ODR_25HZ UINT8_C(0x06) +#define BMI2_ACC_ODR_50HZ UINT8_C(0x07) +#define BMI2_ACC_ODR_100HZ UINT8_C(0x08) +#define BMI2_ACC_ODR_200HZ UINT8_C(0x09) +#define BMI2_ACC_ODR_400HZ UINT8_C(0x0A) +#define BMI2_ACC_ODR_800HZ UINT8_C(0x0B) +#define BMI2_ACC_ODR_1600HZ UINT8_C(0x0C) + +/*! @name Accelerometer G Range */ +#define BMI2_ACC_RANGE_2G UINT8_C(0x00) +#define BMI2_ACC_RANGE_4G UINT8_C(0x01) +#define BMI2_ACC_RANGE_8G UINT8_C(0x02) +#define BMI2_ACC_RANGE_16G UINT8_C(0x03) + +/*! @name Mask definitions for accelerometer configuration register */ +#define BMI2_ACC_RANGE_MASK UINT8_C(0x03) +#define BMI2_ACC_ODR_MASK UINT8_C(0x0F) +#define BMI2_ACC_BW_PARAM_MASK UINT8_C(0x70) +#define BMI2_ACC_FILTER_PERF_MODE_MASK UINT8_C(0x80) + +/*! @name Bit position definitions for accelerometer configuration register */ +#define BMI2_ACC_BW_PARAM_POS UINT8_C(0x04) +#define BMI2_ACC_FILTER_PERF_MODE_POS UINT8_C(0x07) + +/*! @name Self test macro to define range */ +#define BMI2_ACC_SELF_TEST_RANGE UINT8_C(16) + +/*! @name Self test macro to show resulting minimum and maximum difference + * signal of the axes in mg + */ +#define BMI2_ST_ACC_X_SIG_MIN_DIFF INT16_C(16000) +#define BMI2_ST_ACC_Y_SIG_MIN_DIFF INT16_C(-15000) +#define BMI2_ST_ACC_Z_SIG_MIN_DIFF INT16_C(10000) + +/*! @name Mask definitions for accelerometer self-test */ +#define BMI2_ACC_SELF_TEST_EN_MASK UINT8_C(0x01) +#define BMI2_ACC_SELF_TEST_SIGN_MASK UINT8_C(0x04) +#define BMI2_ACC_SELF_TEST_AMP_MASK UINT8_C(0x08) + +/*! @name Bit Positions for accelerometer self-test */ +#define BMI2_ACC_SELF_TEST_SIGN_POS UINT8_C(0x02) +#define BMI2_ACC_SELF_TEST_AMP_POS UINT8_C(0x03) + +/*! @name MASK definition for gyro self test status */ +#define BMI2_GYR_ST_AXES_DONE_MASK UINT8_C(0X01) +#define BMI2_GYR_AXIS_X_OK_MASK UINT8_C(0x02) +#define BMI2_GYR_AXIS_Y_OK_MASK UINT8_C(0x04) +#define BMI2_GYR_AXIS_Z_OK_MASK UINT8_C(0x08) + +/*! @name Bit position for gyro self test status */ +#define BMI2_GYR_AXIS_X_OK_POS UINT8_C(0x01) +#define BMI2_GYR_AXIS_Y_OK_POS UINT8_C(0x02) +#define BMI2_GYR_AXIS_Z_OK_POS UINT8_C(0x03) + +/******************************************************************************/ +/*! @name Gyroscope Macro Definitions */ +/******************************************************************************/ +/*! @name Gyroscope Bandwidth parameters */ +#define BMI2_GYR_OSR4_MODE UINT8_C(0x00) +#define BMI2_GYR_OSR2_MODE UINT8_C(0x01) +#define BMI2_GYR_NORMAL_MODE UINT8_C(0x02) +#define BMI2_GYR_CIC_MODE UINT8_C(0x03) + +/*! @name Gyroscope Output Data Rate */ +#define BMI2_GYR_ODR_25HZ UINT8_C(0x06) +#define BMI2_GYR_ODR_50HZ UINT8_C(0x07) +#define BMI2_GYR_ODR_100HZ UINT8_C(0x08) +#define BMI2_GYR_ODR_200HZ UINT8_C(0x09) +#define BMI2_GYR_ODR_400HZ UINT8_C(0x0A) +#define BMI2_GYR_ODR_800HZ UINT8_C(0x0B) +#define BMI2_GYR_ODR_1600HZ UINT8_C(0x0C) +#define BMI2_GYR_ODR_3200HZ UINT8_C(0x0D) + +/*! @name Gyroscope OIS Range */ +#define BMI2_GYR_OIS_250 UINT8_C(0x00) +#define BMI2_GYR_OIS_2000 UINT8_C(0x01) + +/*! @name Gyroscope Angular Rate Measurement Range */ +#define BMI2_GYR_RANGE_2000 UINT8_C(0x00) +#define BMI2_GYR_RANGE_1000 UINT8_C(0x01) +#define BMI2_GYR_RANGE_500 UINT8_C(0x02) +#define BMI2_GYR_RANGE_250 UINT8_C(0x03) +#define BMI2_GYR_RANGE_125 UINT8_C(0x04) + +/*! @name Mask definitions for gyroscope configuration register */ +#define BMI2_GYR_RANGE_MASK UINT8_C(0x07) +#define BMI2_GYR_OIS_RANGE_MASK UINT8_C(0x08) +#define BMI2_GYR_ODR_MASK UINT8_C(0x0F) +#define BMI2_GYR_BW_PARAM_MASK UINT8_C(0x30) +#define BMI2_GYR_NOISE_PERF_MODE_MASK UINT8_C(0x40) +#define BMI2_GYR_FILTER_PERF_MODE_MASK UINT8_C(0x80) + +/*! @name Bit position definitions for gyroscope configuration register */ +#define BMI2_GYR_OIS_RANGE_POS UINT8_C(0x03) +#define BMI2_GYR_BW_PARAM_POS UINT8_C(0x04) +#define BMI2_GYR_NOISE_PERF_MODE_POS UINT8_C(0x06) +#define BMI2_GYR_FILTER_PERF_MODE_POS UINT8_C(0x07) + +/******************************************************************************/ +/*! @name Auxiliary Macro Definitions */ +/******************************************************************************/ +/*! @name Auxiliary Output Data Rate */ +#define BMI2_AUX_ODR_RESERVED UINT8_C(0x00) +#define BMI2_AUX_ODR_0_78HZ UINT8_C(0x01) +#define BMI2_AUX_ODR_1_56HZ UINT8_C(0x02) +#define BMI2_AUX_ODR_3_12HZ UINT8_C(0x03) +#define BMI2_AUX_ODR_6_25HZ UINT8_C(0x04) +#define BMI2_AUX_ODR_12_5HZ UINT8_C(0x05) +#define BMI2_AUX_ODR_25HZ UINT8_C(0x06) +#define BMI2_AUX_ODR_50HZ UINT8_C(0x07) +#define BMI2_AUX_ODR_100HZ UINT8_C(0x08) +#define BMI2_AUX_ODR_200HZ UINT8_C(0x09) +#define BMI2_AUX_ODR_400HZ UINT8_C(0x0A) +#define BMI2_AUX_ODR_800HZ UINT8_C(0x0B) + +/*! @name Macro to define burst read lengths for both manual and auto modes */ +#define BMI2_AUX_READ_LEN_0 UINT8_C(0x00) +#define BMI2_AUX_READ_LEN_1 UINT8_C(0x01) +#define BMI2_AUX_READ_LEN_2 UINT8_C(0x02) +#define BMI2_AUX_READ_LEN_3 UINT8_C(0x03) + +/*! @name Mask definitions for auxiliary interface configuration register */ +#define BMI2_AUX_SET_I2C_ADDR_MASK UINT8_C(0xFE) +#define BMI2_AUX_MAN_MODE_EN_MASK UINT8_C(0x80) +#define BMI2_AUX_FCU_WR_EN_MASK UINT8_C(0x40) +#define BMI2_AUX_MAN_READ_BURST_MASK UINT8_C(0x0C) +#define BMI2_AUX_READ_BURST_MASK UINT8_C(0x03) +#define BMI2_AUX_ODR_EN_MASK UINT8_C(0x0F) +#define BMI2_AUX_OFFSET_READ_OUT_MASK UINT8_C(0xF0) + +/*! @name Bit positions for auxiliary interface configuration register */ +#define BMI2_AUX_SET_I2C_ADDR_POS UINT8_C(0x01) +#define BMI2_AUX_MAN_MODE_EN_POS UINT8_C(0x07) +#define BMI2_AUX_FCU_WR_EN_POS UINT8_C(0x06) +#define BMI2_AUX_MAN_READ_BURST_POS UINT8_C(0x02) +#define BMI2_AUX_OFFSET_READ_OUT_POS UINT8_C(0x04) + +/******************************************************************************/ +/*! @name FIFO Macro Definitions */ +/******************************************************************************/ +/*! @name Macros to define virtual FIFO frame mode */ +#define BMI2_FIFO_VIRT_FRM_MODE UINT8_C(0x03) + +/*! @name FIFO Header Mask definitions */ +#define BMI2_FIFO_HEADER_ACC_FRM UINT8_C(0x84) +#define BMI2_FIFO_HEADER_AUX_FRM UINT8_C(0x90) +#define BMI2_FIFO_HEADER_GYR_FRM UINT8_C(0x88) +#define BMI2_FIFO_HEADER_GYR_ACC_FRM UINT8_C(0x8C) +#define BMI2_FIFO_HEADER_AUX_ACC_FRM UINT8_C(0x94) +#define BMI2_FIFO_HEADER_AUX_GYR_FRM UINT8_C(0x98) +#define BMI2_FIFO_HEADER_ALL_FRM UINT8_C(0x9C) +#define BMI2_FIFO_HEADER_SENS_TIME_FRM UINT8_C(0x44) +#define BMI2_FIFO_HEADER_SKIP_FRM UINT8_C(0x40) +#define BMI2_FIFO_HEADER_INPUT_CFG_FRM UINT8_C(0x48) +#define BMI2_FIFO_HEAD_OVER_READ_MSB UINT8_C(0x80) +#define BMI2_FIFO_VIRT_ACT_RECOG_FRM UINT8_C(0xC8) + +/*! @name BMI2 sensor selection for header-less frames */ +#define BMI2_FIFO_HEAD_LESS_ACC_FRM UINT8_C(0x40) +#define BMI2_FIFO_HEAD_LESS_AUX_FRM UINT8_C(0x20) +#define BMI2_FIFO_HEAD_LESS_GYR_FRM UINT8_C(0x80) +#define BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM UINT8_C(0xA0) +#define BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM UINT8_C(0xC0) +#define BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM UINT8_C(0x60) +#define BMI2_FIFO_HEAD_LESS_ALL_FRM UINT8_C(0xE0) + +/*! @name Mask definitions for FIFO frame content configuration */ +#define BMI2_FIFO_STOP_ON_FULL UINT16_C(0x0001) +#define BMI2_FIFO_TIME_EN UINT16_C(0x0002) +#define BMI2_FIFO_TAG_INT1 UINT16_C(0x0300) +#define BMI2_FIFO_TAG_INT2 UINT16_C(0x0C00) +#define BMI2_FIFO_HEADER_EN UINT16_C(0x1000) +#define BMI2_FIFO_AUX_EN UINT16_C(0x2000) +#define BMI2_FIFO_ACC_EN UINT16_C(0x4000) +#define BMI2_FIFO_GYR_EN UINT16_C(0x8000) +#define BMI2_FIFO_ALL_EN UINT16_C(0xE000) + +/*! @name FIFO sensor data lengths */ +#define BMI2_FIFO_ACC_LENGTH UINT8_C(6) +#define BMI2_FIFO_GYR_LENGTH UINT8_C(6) +#define BMI2_FIFO_AUX_LENGTH UINT8_C(8) +#define BMI2_FIFO_ACC_AUX_LENGTH UINT8_C(14) +#define BMI2_FIFO_GYR_AUX_LENGTH UINT8_C(14) +#define BMI2_FIFO_ACC_GYR_LENGTH UINT8_C(12) +#define BMI2_FIFO_ALL_LENGTH UINT8_C(20) +#define BMI2_SENSOR_TIME_LENGTH UINT8_C(3) +#define BMI2_FIFO_CONFIG_LENGTH UINT8_C(2) +#define BMI2_FIFO_WM_LENGTH UINT8_C(2) +#define BMI2_MAX_VALUE_FIFO_FILTER UINT8_C(1) +#define BMI2_FIFO_DATA_LENGTH UINT8_C(2) +#define BMI2_FIFO_LENGTH_MSB_BYTE UINT8_C(1) +#define BMI2_FIFO_INPUT_CFG_LENGTH UINT8_C(4) +#define BMI2_FIFO_SKIP_FRM_LENGTH UINT8_C(1) + +/*! @name FIFO sensor virtual data lengths: sensor data plus sensor time */ +#define BMI2_FIFO_VIRT_ACC_LENGTH UINT8_C(9) +#define BMI2_FIFO_VIRT_GYR_LENGTH UINT8_C(9) +#define BMI2_FIFO_VIRT_AUX_LENGTH UINT8_C(11) +#define BMI2_FIFO_VIRT_ACC_AUX_LENGTH UINT8_C(17) +#define BMI2_FIFO_VIRT_GYR_AUX_LENGTH UINT8_C(17) +#define BMI2_FIFO_VIRT_ACC_GYR_LENGTH UINT8_C(15) +#define BMI2_FIFO_VIRT_ALL_LENGTH UINT8_C(23) + +/*! @name FIFO sensor virtual data lengths: activity recognition */ +#define BMI2_FIFO_VIRT_ACT_DATA_LENGTH UINT8_C(6) +#define BMI2_FIFO_VIRT_ACT_TIME_LENGTH UINT8_C(4) +#define BMI2_FIFO_VIRT_ACT_TYPE_LENGTH UINT8_C(1) +#define BMI2_FIFO_VIRT_ACT_STAT_LENGTH UINT8_C(1) + +/*! @name BMI2 FIFO data filter modes */ +#define BMI2_FIFO_UNFILTERED_DATA UINT8_C(0) +#define BMI2_FIFO_FILTERED_DATA UINT8_C(1) + +/*! @name FIFO frame masks */ +#define BMI2_FIFO_LSB_CONFIG_CHECK UINT8_C(0x00) +#define BMI2_FIFO_MSB_CONFIG_CHECK UINT8_C(0x80) +#define BMI2_FIFO_TAG_INTR_MASK UINT8_C(0xFF) + +/*! @name BMI2 Mask definitions of FIFO configuration registers */ +#define BMI2_FIFO_CONFIG_0_MASK UINT16_C(0x0003) +#define BMI2_FIFO_CONFIG_1_MASK UINT16_C(0xFF00) + +/*! @name FIFO self wake-up mask definition */ +#define BMI2_FIFO_SELF_WAKE_UP_MASK UINT8_C(0x02) + +/*! @name FIFO down sampling mask definition */ +#define BMI2_ACC_FIFO_DOWNS_MASK UINT8_C(0x70) +#define BMI2_GYR_FIFO_DOWNS_MASK UINT8_C(0x07) + +/*! @name FIFO down sampling bit positions */ +#define BMI2_ACC_FIFO_DOWNS_POS UINT8_C(0x04) + +/*! @name FIFO filter mask definition */ +#define BMI2_ACC_FIFO_FILT_DATA_MASK UINT8_C(0x80) +#define BMI2_GYR_FIFO_FILT_DATA_MASK UINT8_C(0x08) + +/*! @name FIFO filter bit positions */ +#define BMI2_ACC_FIFO_FILT_DATA_POS UINT8_C(0x07) +#define BMI2_GYR_FIFO_FILT_DATA_POS UINT8_C(0x03) + +/*! @name FIFO byte counter mask definition */ +#define BMI2_FIFO_BYTE_COUNTER_MSB_MASK UINT8_C(0x3F) + +/*! @name FIFO self wake-up bit positions */ +#define BMI2_FIFO_SELF_WAKE_UP_POS UINT8_C(0x01) + +/*! @name Mask Definitions for Virtual FIFO frames */ +#define BMI2_FIFO_VIRT_FRM_MODE_MASK UINT8_C(0xC0) +#define BMI2_FIFO_VIRT_PAYLOAD_MASK UINT8_C(0x3C) + +/*! @name Bit Positions for Virtual FIFO frames */ +#define BMI2_FIFO_VIRT_FRM_MODE_POS UINT8_C(0x06) +#define BMI2_FIFO_VIRT_PAYLOAD_POS UINT8_C(0x02) + +/******************************************************************************/ +/*! @name Interrupt Macro Definitions */ +/******************************************************************************/ +/*! @name BMI2 Interrupt Modes */ +/* Non latched */ +#define BMI2_INT_NON_LATCH UINT8_C(0) + +/* Permanently latched */ +#define BMI2_INT_LATCH UINT8_C(1) + +/*! @name BMI2 Interrupt Pin Behavior */ +#define BMI2_INT_PUSH_PULL UINT8_C(0) +#define BMI2_INT_OPEN_DRAIN UINT8_C(1) + +/*! @name BMI2 Interrupt Pin Level */ +#define BMI2_INT_ACTIVE_LOW UINT8_C(0) +#define BMI2_INT_ACTIVE_HIGH UINT8_C(1) + +/*! @name BMI2 Interrupt Output Enable */ +#define BMI2_INT_OUTPUT_DISABLE UINT8_C(0) +#define BMI2_INT_OUTPUT_ENABLE UINT8_C(1) + +/*! @name BMI2 Interrupt Input Enable */ +#define BMI2_INT_INPUT_DISABLE UINT8_C(0) +#define BMI2_INT_INPUT_ENABLE UINT8_C(1) + +/*! @name Mask definitions for interrupt pin configuration */ +#define BMI2_INT_LATCH_MASK UINT8_C(0x01) +#define BMI2_INT_LEVEL_MASK UINT8_C(0x02) +#define BMI2_INT_OPEN_DRAIN_MASK UINT8_C(0x04) +#define BMI2_INT_OUTPUT_EN_MASK UINT8_C(0x08) +#define BMI2_INT_INPUT_EN_MASK UINT8_C(0x10) + +/*! @name Bit position definitions for interrupt pin configuration */ +#define BMI2_INT_LEVEL_POS UINT8_C(0x01) +#define BMI2_INT_OPEN_DRAIN_POS UINT8_C(0x02) +#define BMI2_INT_OUTPUT_EN_POS UINT8_C(0x03) +#define BMI2_INT_INPUT_EN_POS UINT8_C(0x04) + +/*! @name Mask definitions for data interrupt mapping */ +#define BMI2_FFULL_INT UINT8_C(0x01) +#define BMI2_FWM_INT UINT8_C(0x02) +#define BMI2_DRDY_INT UINT8_C(0x04) +#define BMI2_ERR_INT UINT8_C(0x08) + +/*! @name Mask definitions for data interrupt status bits */ +#define BMI2_FFULL_INT_STATUS_MASK UINT16_C(0x0100) +#define BMI2_FWM_INT_STATUS_MASK UINT16_C(0x0200) +#define BMI2_ERR_INT_STATUS_MASK UINT16_C(0x0400) +#define BMI2_AUX_DRDY_INT_MASK UINT16_C(0x2000) +#define BMI2_GYR_DRDY_INT_MASK UINT16_C(0x4000) +#define BMI2_ACC_DRDY_INT_MASK UINT16_C(0x8000) + +/*! @name Maximum number of interrupt pins */ +#define BMI2_INT_PIN_MAX_NUM UINT8_C(2) + +/*! @name Macro for mapping feature interrupts */ +#define BMI2_FEAT_BIT_DISABLE UINT8_C(0) +#define BMI2_FEAT_BIT0 UINT8_C(1) +#define BMI2_FEAT_BIT1 UINT8_C(2) +#define BMI2_FEAT_BIT2 UINT8_C(3) +#define BMI2_FEAT_BIT3 UINT8_C(4) +#define BMI2_FEAT_BIT4 UINT8_C(5) +#define BMI2_FEAT_BIT5 UINT8_C(6) +#define BMI2_FEAT_BIT6 UINT8_C(7) +#define BMI2_FEAT_BIT7 UINT8_C(8) +#define BMI2_FEAT_BIT_MAX UINT8_C(9) + +/******************************************************************************/ +/*! @name OIS Interface Macro Definitions */ +/******************************************************************************/ +/*! @name Mask definitions for interface configuration register */ +#define BMI2_OIS_IF_EN_MASK UINT8_C(0x10) +#define BMI2_AUX_IF_EN_MASK UINT8_C(0x20) + +/*! @name Bit positions for OIS interface enable */ +#define BMI2_OIS_IF_EN_POS UINT8_C(0x04) +#define BMI2_AUX_IF_EN_POS UINT8_C(0x05) + +/******************************************************************************/ +/*! @name Macro Definitions for Axes re-mapping */ +/******************************************************************************/ +/*! @name Macros for the user-defined values of axes and their polarities */ +#define BMI2_X UINT8_C(0x01) +#define BMI2_NEG_X UINT8_C(0x09) +#define BMI2_Y UINT8_C(0x02) +#define BMI2_NEG_Y UINT8_C(0x0A) +#define BMI2_Z UINT8_C(0x04) +#define BMI2_NEG_Z UINT8_C(0x0C) +#define BMI2_AXIS_MASK UINT8_C(0x07) +#define BMI2_AXIS_SIGN UINT8_C(0x08) + +/******************************************************************************/ +/*! @name Macro Definitions for offset and gain compensation */ +/******************************************************************************/ +/*! @name Mask definitions of gyroscope offset compensation registers */ +#define BMI2_GYR_GAIN_EN_MASK UINT8_C(0x80) +#define BMI2_GYR_OFF_COMP_EN_MASK UINT8_C(0x40) + +/*! @name Bit positions of gyroscope offset compensation registers */ +#define BMI2_GYR_OFF_COMP_EN_POS UINT8_C(0x06) + +/*! @name Mask definitions of gyroscope user-gain registers */ +#define BMI2_GYR_USR_GAIN_X_MASK UINT8_C(0x7F) +#define BMI2_GYR_USR_GAIN_Y_MASK UINT8_C(0x7F) +#define BMI2_GYR_USR_GAIN_Z_MASK UINT8_C(0x7F) + +/*! @name Bit positions of gyroscope offset compensation registers */ +#define BMI2_GYR_GAIN_EN_POS UINT8_C(0x07) + +/******************************************************************************/ +/*! @name Macro Definitions for internal status */ +/******************************************************************************/ +#define BMI2_NOT_INIT UINT8_C(0x00) +#define BMI2_INIT_OK UINT8_C(0x01) +#define BMI2_INIT_ERR UINT8_C(0x02) +#define BMI2_DRV_ERR UINT8_C(0x03) +#define BMI2_SNS_STOP UINT8_C(0x04) +#define BMI2_NVM_ERROR UINT8_C(0x05) +#define BMI2_START_UP_ERROR UINT8_C(0x06) +#define BMI2_COMPAT_ERROR UINT8_C(0x07) +#define BMI2_VFM_SKIPPED UINT8_C(0x10) +#define BMI2_AXES_MAP_ERROR UINT8_C(0x20) +#define BMI2_ODR_50_HZ_ERROR UINT8_C(0x40) +#define BMI2_ODR_HIGH_ERROR UINT8_C(0x80) + +/******************************************************************************/ +/*! @name error status form gyro gain update status. */ +/******************************************************************************/ +#define BMI2_G_TRIGGER_NO_ERROR UINT8_C(0x00) + +#define BMI2_G_TRIGGER_PRECON_ERROR UINT8_C(0x01) +#define BMI2_G_TRIGGER_DL_ERROR UINT8_C(0x02) +#define BMI2_G_TRIGGER_ABORT_ERROR UINT8_C(0x03) + +/******************************************************************************/ +/*! @name Variant specific features selection macros */ +/******************************************************************************/ +#define BMI2_CRT_RTOSK_ENABLE UINT8_C(0x01) +#define BMI2_GYRO_CROSS_SENS_ENABLE UINT8_C(0x02) +#define BMI_GYRO_USER_GAIN_ENABLE UINT8_C(0x08) +#define BMI2_NO_FEATURE_ENABLE UINT8_C(0x00) +#define BMI2_CRT_IN_FIFO_NOT_REQ UINT8_C(0x10) +#define BMI2_MINIMAL_VARIANT UINT8_C(0x20) + +/*! Pull-up configuration for ASDA */ +#define BMI_ASDA_PUPSEL_OFF UINT8_C(0x00) +#define BMI_ASDA_PUPSEL_40K UINT8_C(0x01) +#define BMI_ASDA_PUPSEL_10K UINT8_C(0x02) +#define BMI_ASDA_PUPSEL_2K UINT8_C(0x03) + +/******************************************************************************/ +/*! @name Function Pointers */ +/******************************************************************************/ +/*! For interfacing to the I2C or SPI read functions */ +typedef int8_t (*bmi2_read_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len); + +/*! For interfacing to the I2C or SPI write functions */ +typedef int8_t (*bmi2_write_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, const uint8_t *data, uint16_t len); + +/*! For interfacing to the delay function */ +typedef void (*bmi2_delay_fptr_t)(uint32_t period); + +/******************************************************************************/ +/*! @name Enum Declarations */ +/******************************************************************************/ +/*! @name Enum to define BMI2 sensor interfaces */ +enum bmi2_intf_type { + BMI2_SPI_INTERFACE = 1, + BMI2_I2C_INTERFACE, + BMI2_I3C_INTERFACE +}; + +/*! @name Enum to define BMI2 sensor configuration errors for accelerometer + * and gyroscope + */ +enum bmi2_sensor_config_error { + BMI2_NO_ERROR, + BMI2_ACC_ERROR, + BMI2_GYR_ERROR, + BMI2_ACC_GYR_ERROR +}; + +/*! @name Enum to define interrupt lines */ +enum bmi2_hw_int_pin { + BMI2_INT_NONE, + BMI2_INT1, + BMI2_INT2, + BMI2_INT_BOTH, + BMI2_INT_PIN_MAX +}; + +/*! @name Enum for the position of the wearable device */ +enum bmi2_wear_arm_pos { + BMI2_ARM_LEFT, + BMI2_ARM_RIGHT +}; + +/*! @name Enum to display type of activity recognition */ +enum bmi2_act_recog_type { + BMI2_ACT_UNKNOWN, + BMI2_ACT_STILL, + BMI2_ACT_WALK, + BMI2_ACT_RUN, + BMI2_ACT_BIKE, + BMI2_ACT_VEHICLE, + BMI2_ACT_TILTED +}; + +/*! @name Enum to display activity recognition status */ +enum bmi2_act_recog_stat { + BMI2_ACT_START = 1, + BMI2_ACT_END +}; + +/******************************************************************************/ +/*! @name Structure Declarations */ +/******************************************************************************/ +/*! @name Structure to store the compensated user-gain data of gyroscope */ +struct bmi2_gyro_user_gain_data +{ + /*! x-axis */ + int8_t x; + + /*! y-axis */ + int8_t y; + + /*! z-axis */ + int8_t z; +}; + +/*! @name Structure to store the re-mapped axis */ +struct bmi2_remap +{ + /*! Re-mapped x-axis */ + uint8_t x; + + /*! Re-mapped y-axis */ + uint8_t y; + + /*! Re-mapped z-axis */ + uint8_t z; +}; + +/*! @name Structure to store the value of re-mapped axis and its sign */ +struct bmi2_axes_remap +{ + /*! Re-mapped x-axis */ + uint8_t x_axis; + + /*! Re-mapped y-axis */ + uint8_t y_axis; + + /*! Re-mapped z-axis */ + uint8_t z_axis; + + /*! Re-mapped x-axis sign */ + int16_t x_axis_sign; + + /*! Re-mapped y-axis sign */ + int16_t y_axis_sign; + + /*! Re-mapped z-axis sign */ + int16_t z_axis_sign; +}; + +/*! @name Structure to define the type of sensor and its interrupt pin */ +struct bmi2_sens_int_config +{ + /*! Defines the type of sensor */ + uint8_t type; + + /*! Type of interrupt pin */ + enum bmi2_hw_int_pin hw_int_pin; +}; + +/*! @name Structure to define the output configuration value of features */ +struct bmi2_int_map +{ + /*! Output configuration value of sig-motion */ + uint8_t sig_mot_out_conf; + + /*! Output configuration value of any-motion */ + uint8_t any_mot_out_conf; + + /*! Output configuration value of no-motion */ + uint8_t no_mot_out_conf; + + /*! Output configuration value of step-detector */ + uint8_t step_det_out_conf; + + /*! Output configuration value of step-activity */ + uint8_t step_act_out_conf; + + /*! Output configuration value of tilt */ + uint8_t tilt_out_conf; + + /*! Output configuration value of uphold to wake */ + uint8_t up_hold_to_wake_out_conf; + + /*! Output configuration value of glance */ + uint8_t glance_out_conf; + + /*! Output configuration value of wake-up */ + uint8_t wake_up_out_conf; + + /*! Output configuration value of orientation */ + uint8_t orient_out_conf; + + /*! Output configuration value of high-g */ + uint8_t high_g_out_conf; + + /*! Output configuration value of low-g */ + uint8_t low_g_out_conf; + + /*! Output configuration value of flat */ + uint8_t flat_out_conf; + + /*! Output configuration value of S4S */ + uint8_t ext_sync_out_conf; + + /*! Output configuration value of wrist gesture */ + uint8_t wrist_gest_out_conf; + + /*! Output configuration value of wrist wear wake-up */ + uint8_t wrist_wear_wake_up_out_conf; + + /*! Output configuration value of free-fall detection */ + uint8_t freefall_out_conf; +}; + +/*! @name Structure to define output for activity recognition */ +struct bmi2_act_recog_output +{ + /*! Time stamp */ + uint32_t time_stamp; + + /*! current activity */ + uint8_t curr_act; + + /*! previous activity */ + uint8_t prev_act; +}; + +/*! @name Structure to define FIFO frame configuration */ +struct bmi2_fifo_frame +{ + /*! Pointer to FIFO data */ + uint8_t *data; + + /*! Number of user defined bytes of FIFO to be read */ + uint16_t length; + + /*! Defines header/header-less mode */ + uint8_t header_enable; + + /*! Enables type of data to be streamed - accelerometer, auxiliary or + * gyroscope + */ + uint16_t data_enable; + + /*! To index accelerometer bytes */ + uint16_t acc_byte_start_idx; + + /*! To index activity output bytes */ + uint16_t act_recog_byte_start_idx; + + /*! To index auxiliary bytes */ + uint16_t aux_byte_start_idx; + + /*! To index gyroscope bytes */ + uint16_t gyr_byte_start_idx; + + /*! FIFO sensor time */ + uint32_t sensor_time; + + /*! Skipped frame count */ + uint8_t skipped_frame_count; + + /*! Type of data interrupt to be mapped */ + uint8_t data_int_map; + + /*! Water-mark level for water-mark interrupt */ + uint16_t wm_lvl; + + /*! Accelerometer frame length */ + uint8_t acc_frm_len; + + /*! Gyroscope frame length */ + uint8_t gyr_frm_len; + + /*! Auxiliary frame length */ + uint8_t aux_frm_len; + + /*! Accelerometer and gyroscope frame length */ + uint8_t acc_gyr_frm_len; + + /*! Accelerometer and auxiliary frame length */ + uint8_t acc_aux_frm_len; + + /*! Gyroscope and auxiliary frame length */ + uint8_t aux_gyr_frm_len; + + /*! Accelerometer, Gyroscope and auxiliary frame length */ + uint8_t all_frm_len; +}; + +/*! @name Structure to define Interrupt pin configuration */ +struct bmi2_int_pin_cfg +{ + /*! Configure level of interrupt pin */ + uint8_t lvl; + + /*! Configure behavior of interrupt pin */ + uint8_t od; + + /*! Output enable for interrupt pin */ + uint8_t output_en; + + /*! Input enable for interrupt pin */ + uint8_t input_en; +}; + +/*! @name Structure to define interrupt pin type, mode and configurations */ +struct bmi2_int_pin_config +{ + /*! Interrupt pin type: INT1 or INT2 or BOTH */ + uint8_t pin_type; + + /*! Latched or non-latched mode*/ + uint8_t int_latch; + + /*! Structure to define Interrupt pin configuration */ + struct bmi2_int_pin_cfg pin_cfg[BMI2_INT_PIN_MAX_NUM]; +}; + +/*! @name Structure to define an array of 8 auxiliary data bytes */ +struct bmi2_aux_fifo_data +{ + /*! Auxiliary data */ + uint8_t data[8]; + + /*! Sensor time for virtual frames */ + uint32_t virt_sens_time; +}; + +/*! @name Structure to define accelerometer and gyroscope sensor axes and + * sensor time for virtual frames + */ +struct bmi2_sens_axes_data +{ + /*! Data in x-axis */ + int16_t x; + + /*! Data in y-axis */ + int16_t y; + + /*! Data in z-axis */ + int16_t z; + + /*! Sensor time for virtual frames */ + uint32_t virt_sens_time; +}; + +/*! @name Structure to define gyroscope saturation status of user gain */ +struct bmi2_gyr_user_gain_status +{ + /*! Status in x-axis */ + uint8_t sat_x; + + /*! Status in y-axis */ + uint8_t sat_y; + + /*! Status in z-axis */ + uint8_t sat_z; + + /*! G trigger status */ + uint8_t g_trigger_status; +}; + +/*! @name Structure to store the status of gyro self test result */ +struct bmi2_gyro_self_test_status +{ + /*! gyro self test axes done */ + uint8_t gyr_st_axes_done : 1; + + /*! status of gyro X-axis self test */ + uint8_t gyr_axis_x_ok : 1; + + /*! status of gyro Y-axis self test */ + uint8_t gyr_axis_y_ok : 1; + + /*! status of gyro Z-axis self test */ + uint8_t gyr_axis_z_ok : 1; +}; + +/*! @name Structure to define NVM error status */ +struct bmi2_nvm_err_status +{ + /*! NVM load action error */ + uint8_t load_error; + + /*! NVM program action error */ + uint8_t prog_error; + + /*! NVM erase action error */ + uint8_t erase_error; + + /*! NVM program limit exceeded */ + uint8_t exceed_error; + + /*! NVM privilege error */ + uint8_t privil_error; +}; + +/*! @name Structure to define VFRM error status */ +struct bmi2_vfrm_err_status +{ + /*! VFRM lock acquire error */ + uint8_t lock_error; + + /*! VFRM write error */ + uint8_t write_error; + + /*! VFRM fatal err */ + uint8_t fatal_error; +}; + +/*! @name Structure to define accelerometer self test feature status */ +struct bmi2_acc_self_test_status +{ + /*! Accelerometer test completed */ + uint8_t acc_self_test_done; + + /*! Bit is set to 1 when accelerometer X-axis test passed */ + uint8_t acc_x_ok; + + /*! Bit is set to 1 when accelerometer y-axis test passed */ + uint8_t acc_y_ok; + + /*! Bit is set to 1 when accelerometer z-axis test passed */ + uint8_t acc_z_ok; +}; + +/*! @name Structure to define orientation output */ +struct bmi2_orientation_output +{ + /*! Orientation portrait landscape */ + uint8_t portrait_landscape; + + /*! Orientation face-up down */ + uint8_t faceup_down; +}; + +/*! @name Structure to define OIS output */ +struct bmi2_ois_output +{ + /*! OIS accel x axis */ + int16_t ois_acc_x; + + /*! OIS accel y axis */ + int16_t ois_acc_y; + + /*! OIS accel z axis */ + int16_t ois_acc_z; + + /*! ois gyro x axis */ + int16_t ois_gyro_x; + + /*! OIS gyro y axis */ + int16_t ois_gyro_y; + + /*! OIS gyro z axis */ + int16_t ois_gyro_z; +}; + +/*! @name Union to define BMI2 sensor data */ +union bmi2_sens_data +{ + /*! Accelerometer axes data */ + struct bmi2_sens_axes_data acc; + + /*! Gyroscope axes data */ + struct bmi2_sens_axes_data gyr; + + /*! Auxiliary sensor data */ + uint8_t aux_data[BMI2_AUX_NUM_BYTES]; + + /*! Step counter output */ + uint32_t step_counter_output; + + /*! Step activity output */ + uint8_t activity_output; + + /*! Orientation output */ + struct bmi2_orientation_output orient_output; + + /*! High-g output */ + uint8_t high_g_output; + + /*! Gyroscope user gain saturation status */ + struct bmi2_gyr_user_gain_status gyro_user_gain_status; + + /*! NVM error status */ + struct bmi2_nvm_err_status nvm_status; + + /*! Virtual frame error status */ + struct bmi2_vfrm_err_status vfrm_status; + + /*! Wrist gesture output */ + uint8_t wrist_gesture_output; + + /*! Gyroscope cross sense value of z axis */ + int16_t correction_factor_zx; + + /*! Accelerometer self test feature status */ + struct bmi2_acc_self_test_status accel_self_test_output; + + /*! OIS output */ + struct bmi2_ois_output ois_output; +}; + +/*! @name Structure to define type of sensor and their respective data */ +struct bmi2_sensor_data +{ + /*! Defines the type of sensor */ + uint8_t type; + + /*! Defines various sensor data */ + union bmi2_sens_data sens_data; +}; + +/*! @name Structure to define accelerometer configuration */ +struct bmi2_accel_config +{ + /*! Output data rate in Hz */ + uint8_t odr; + + /*! Bandwidth parameter */ + uint8_t bwp; + + /*! Filter performance mode */ + uint8_t filter_perf; + + /*! g-range */ + uint8_t range; +}; + +/*! @name Structure to define gyroscope configuration */ +struct bmi2_gyro_config +{ + /*! Output data rate in Hz */ + uint8_t odr; + + /*! Bandwidth parameter */ + uint8_t bwp; + + /*! Filter performance mode */ + uint8_t filter_perf; + + /*! OIS Range */ + uint8_t ois_range; + + /*! Gyroscope Range */ + uint8_t range; + + /*! Selects noise performance */ + uint8_t noise_perf; +}; + +/*! @name Structure to define auxiliary sensor configuration */ +struct bmi2_aux_config +{ + /*! Enable/Disable auxiliary interface */ + uint8_t aux_en; + + /*! Manual or Auto mode*/ + uint8_t manual_en; + + /*! Enables FCU write command on auxiliary interface */ + uint8_t fcu_write_en; + + /*! Read burst length for manual mode */ + uint8_t man_rd_burst; + + /*! Read burst length for data mode */ + uint8_t aux_rd_burst; + + /*! Output data rate */ + uint8_t odr; + + /*! Read-out offset */ + uint8_t offset; + + /*! I2c address of auxiliary sensor */ + uint8_t i2c_device_addr; + + /*! Read address of auxiliary sensor */ + uint8_t read_addr; +}; + +/*! @name Structure to define any-motion configuration */ +struct bmi2_any_motion_config +{ + /*! Duration in 50Hz samples(20msec) */ + uint16_t duration; + + /*! Acceleration slope threshold */ + uint16_t threshold; + + /*! To select per x-axis */ + uint16_t select_x; + + /*! To select per y-axis */ + uint16_t select_y; + + /*! To select per z-axis */ + uint16_t select_z; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define no-motion configuration */ +struct bmi2_no_motion_config +{ + /*! Duration in 50Hz samples(20msec) */ + uint16_t duration; + + /*! Acceleration slope threshold */ + uint16_t threshold; + + /*! To select per x-axis */ + uint16_t select_x; + + /*! To select per y-axis */ + uint16_t select_y; + + /*! To select per z-axis */ + uint16_t select_z; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define sig-motion configuration */ +struct bmi2_sig_motion_config +{ + /*! Block size */ + uint16_t block_size; + + /*! Parameter 2 */ + uint16_t param_2; + + /*! Parameter 3 */ + uint16_t param_3; + + /*! Parameter 4 */ + uint16_t param_4; + + /*! Parameter 5 */ + uint16_t param_5; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define step counter/detector/activity configuration */ +struct bmi2_step_config +{ + /*! Water-mark level */ + uint16_t watermark_level; + + /*! Reset counter */ + uint16_t reset_counter; + + /*! Enable bits for enabling output into the register status bits + * for step-detector + */ + uint16_t out_conf_step_detector; + + /*! Enable bits for enabling output into the register status bits + * for step-activity + */ + uint16_t out_conf_activity; + uint8_t step_buffer_size; +}; + +/*! @name Structure to define gyroscope user gain configuration */ +struct bmi2_gyro_user_gain_config +{ + /*! Gain update value for x-axis */ + uint16_t ratio_x; + + /*! Gain update value for y-axis */ + uint16_t ratio_y; + + /*! Gain update value for z-axis */ + uint16_t ratio_z; +}; + +/*! @name Structure to define tilt configuration */ +struct bmi2_tilt_config +{ + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define uphold to wake configuration */ +struct bmi2_up_hold_to_wake_config +{ + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define glance detector configuration */ +struct bmi2_glance_det_config +{ + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define wake-up configuration */ +struct bmi2_wake_up_config +{ + /*! Wake-up sensitivity */ + uint16_t sensitivity; + + /*! Enable -> Single Tap; Disable -> Double Tap */ + uint16_t single_tap_en; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define orientation configuration */ +struct bmi2_orient_config +{ + /*! Upside/down detection */ + uint16_t ud_en; + + /*! Symmetrical, high or low Symmetrical */ + uint16_t mode; + + /*! Blocking mode */ + uint16_t blocking; + + /*! Threshold angle */ + uint16_t theta; + + /*! Acceleration hysteresis for orientation detection */ + uint16_t hysteresis; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define high-g configuration */ +struct bmi2_high_g_config +{ + /*! Acceleration threshold */ + uint16_t threshold; + + /*! Hysteresis */ + uint16_t hysteresis; + + /*! To select per x-axis */ + uint16_t select_x; + + /*! To select per y-axis */ + uint16_t select_y; + + /*! To select per z-axis */ + uint16_t select_z; + + /*! Duration interval */ + uint16_t duration; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define low-g configuration */ +struct bmi2_low_g_config +{ + /*! Acceleration threshold */ + uint16_t threshold; + + /*! Hysteresis */ + uint16_t hysteresis; + + /*! Duration interval */ + uint16_t duration; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; + +}; + +/*! @name Structure to define flat configuration */ +struct bmi2_flat_config +{ + /*! Theta angle for flat detection */ + uint16_t theta; + + /*! Blocking mode */ + uint16_t blocking; + + /*! Hysteresis for theta flat detection */ + uint16_t hysteresis; + + /*! Holds the duration in 50Hz samples(20msec) */ + uint16_t hold_time; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define external sensor sync configuration */ +struct bmi2_ext_sens_sync_config +{ + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define wrist gesture configuration */ +struct bmi2_wrist_gest_config +{ + /*! Wearable arm (left or right) */ + uint16_t wearable_arm; + + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; + + /*! Sine of the minimum tilt angle in portrait down direction of the device when wrist is rolled + * away from user. The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). + * Range is 1448 to 1774. Default value is 1774. */ + uint16_t min_flick_peak; + + /*! Value of minimum time difference between wrist roll-out and roll-in movement during flick gesture. + * Range is 3 to 5 samples at 50Hz. Default value is 4 (i.e. 0.08 seconds). */ + uint16_t min_flick_samples; + + /*! Maximum time within which gesture movement has to be completed. Range is 150 to 250 samples at 50Hz. + * Default value is 200 (i.e. 4 seconds). */ + uint16_t max_duration; +}; + +/*! @name Structure to define wrist wear wake-up configuration */ +struct bmi2_wrist_wear_wake_up_config +{ + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; + + /*! Cosine of min expected attitude change of the device within 1 second time window when + * moving within focus position. + * The parameter is scaled by 2048 i.e. 2048 * cos(angle). Range is 1024 to 1774. + * Default is 1448. */ + uint16_t min_angle_focus; + + /*! Cosine of min expected attitude change of the device within 1 second time window when + * moving from non-focus to focus position. + * The parameter is scaled by 2048 i.e. 2048 * cos(angle). Range is 1448 to 1856. + * Default value is 1774. */ + uint16_t min_angle_nonfocus; + + /*! Sine of the max allowed downward tilt angle in landscape right direction of the device, + * when it is in focus position + * (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 700 to 1024. + * Default value is 1024. */ + uint16_t max_tilt_lr; + + /*! Sine of the max allowed downward tilt angle in landscape left direction of the device, + * when it is in focus position + * (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 700 to + * 1024. Default value is 700. */ + uint16_t max_tilt_ll; + + /*! Sine of the max allowed backward tilt angle in portrait down direction of the device, + * when it is in focus position + * (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 0 to179. + * Default value is 179. */ + uint16_t max_tilt_pd; + + /*! Sine of the maximum allowed forward tilt angle in portrait up direction of the + * device, when it is in focus position + * (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 1774 to 1978. + * Default value is 1925. */ + uint16_t max_tilt_pu; +}; + +/*! @name Structure to define wrist gesture configuration for wearable variant */ +struct bmi2_wrist_gest_w_config +{ + /*! Wearable arm (left or right) */ + uint8_t wearable_arm : 1; + + /*! Enable bits for enabling output into the register status bits */ + uint8_t out_conf : 4; + + /*! Sine of the minimum tilt angle in portrait down direction of the device when wrist is rolled + * away from user. The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). + * Range is 1448 to 1774. Default value is 1774. */ + uint16_t min_flick_peak; + + /*! Value of minimum time difference between wrist roll-out and roll-in movement during flick gesture. + * Range is 3 to 5 samples at 50Hz. Default value is 4 (i.e. 0.08 seconds). */ + uint16_t min_flick_samples; + + /*! Maximum time within which gesture movement has to be completed. Range is 150 to 250 samples at 50Hz. + * Default value is 200 (i.e. 4 seconds). */ + uint16_t max_duration; + + /*! Defines the Wait time between the detection of the wrist gesture and reporting the wrist gesture. + * The sample resolution is 20ms. The default value is 25 which is equal to reporting delay 500ms . + */ + uint16_t reporting_delay; +}; + +/*! @name Structure to define wrist wear wake-up configuration for wearable configuration */ +struct bmi2_wrist_wear_wake_up_wh_config +{ + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; + + /*! Cosine of min expected attitude change of the device within 1 second time window when + * moving within focus position. + * The parameter is scaled by 2048 i.e. 2048 * cos(angle). Range is 1024 to 1774. + * Default is 1448. */ + uint16_t min_angle_focus; + + /*! Cosine of min expected attitude change of the device within 1 second time window when + * moving from non-focus to focus position. + * The parameter is scaled by 2048 i.e. 2048 * cos(angle). Range is 1448 to 1856. + * Default value is 1774. */ + uint16_t min_angle_nonfocus; + + /*! Sine of the max allowed downward tilt angle in landscape right direction of the device, + * when it is in focus position (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 256 i.e. 256 * sin(angle). Range is 88 to 128. + * Default value is 128. */ + uint8_t angle_lr; + + /*! Sine of the max allowed downward tilt angle in landscape left direction of the device, + * when it is in focus position (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 256 i.e. 256 * sin(angle). Range is 88 to 128. + * Default value is 128. */ + uint8_t angle_ll; + + /*! Sine of the max allowed backward tilt angle in portrait down direction of the device, + * when it is in focus position (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 256 i.e. 256 * sin(angle). Range is 0 to 179. + * Default value is 22. */ + uint8_t angle_pd; + + /*! Sine of the maximum allowed forward tilt angle in portrait up direction of the device, + * when it is in focus position (i.e. user is able to comfortably look at the dial of wear device). + * The configuration parameter is scaled by 256 i.e. 256 * sin(angle). Range is 222 to 247. + * Default value is 241. */ + uint8_t angle_pu; + + /*! Minimum duration the arm should be moved while performing gesture. Range: 1 to 10, + * resolution = 20 ms. + * Default 2(40 ms)*/ + uint8_t min_dur_mov; + + /*! Minimum duration the arm should be static between two consecutive gestures. Range: 1 to + * 10, resolution = 20 ms + * Default 2(40 ms)*/ + uint8_t min_dur_quite; +}; + +/*! @name Structure to define primary OIS configuration */ +struct bmi2_primary_ois_config +{ + uint8_t lp_filter_enable; + + uint8_t lp_filter_config; + + uint8_t primary_ois_reserved; + + uint8_t primary_ois_gyro_en; + + uint8_t primary_ois_accel_en; +}; + +/*! @name Structure to configure free-fall detection settings */ +struct bmi2_free_fall_det_config +{ + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; + + /*! free-fall accel settings */ + uint16_t freefall_accel_settings[BMI2_FREE_FALL_ACCEL_SET_PARAMS]; +}; + +/*! @name Union to define the sensor configurations */ +union bmi2_sens_config_types +{ + /*! Accelerometer configuration */ + struct bmi2_accel_config acc; + + /*! Gyroscope configuration */ + struct bmi2_gyro_config gyr; + + /*! Auxiliary configuration */ + struct bmi2_aux_config aux; + + /*! Any-motion configuration */ + struct bmi2_any_motion_config any_motion; + + /*! No-motion configuration */ + struct bmi2_no_motion_config no_motion; + + /*! Sig_motion configuration */ + struct bmi2_sig_motion_config sig_motion; + + /*! Step counter parameter configuration */ + uint16_t step_counter_params[BMI2_STEP_CNT_N_PARAMS]; + + /*! Step counter/detector/activity configuration */ + struct bmi2_step_config step_counter; + + /*! Gyroscope user gain configuration */ + struct bmi2_gyro_user_gain_config gyro_gain_update; + + /*! Tilt configuration */ + struct bmi2_tilt_config tilt; + + /*! uphold to wake configuration */ + struct bmi2_up_hold_to_wake_config up_hold_to_wake; + + /*! Glance detector configuration */ + struct bmi2_glance_det_config glance_det; + + /*! Wake-up configuration */ + struct bmi2_wake_up_config tap; + + /*! Orientation configuration */ + struct bmi2_orient_config orientation; + + /*! High-g configuration */ + struct bmi2_high_g_config high_g; + + /*! Low-g configuration */ + struct bmi2_low_g_config low_g; + + /*! Flat configuration */ + struct bmi2_flat_config flat; + + /*! External sensor sync configuration */ + struct bmi2_ext_sens_sync_config ext_sens_sync; + + /*! Wrist gesture configuration */ + struct bmi2_wrist_gest_config wrist_gest; + + /*! Wrist wear wake-up configuration */ + struct bmi2_wrist_wear_wake_up_config wrist_wear_wake_up; + + /*! Wrist gesture configuration for wearable variant */ + struct bmi2_wrist_gest_w_config wrist_gest_w; + + /*! Wrist wear wake-up configuration for wearable variant */ + struct bmi2_wrist_wear_wake_up_wh_config wrist_wear_wake_up_wh; + + /*! Primary OIS configuration */ + struct bmi2_primary_ois_config primary_ois; + + /* Free-fall detection configurations */ + struct bmi2_free_fall_det_config free_fall_det; +}; + +/*! @name Structure to define the type of the sensor and its configurations */ +struct bmi2_sens_config +{ + /*! Defines the type of sensor */ + uint8_t type; + + /*! Defines various sensor configurations */ + union bmi2_sens_config_types cfg; +}; + +/*! @name Structure to define the feature configuration */ +struct bmi2_feature_config +{ + /*! Defines the type of sensor */ + uint8_t type; + + /*! Page to where the feature is mapped */ + uint8_t page; + + /*! Address of the feature */ + uint8_t start_addr; +}; + +/*! @name Structure to define BMI2 sensor configurations */ +struct bmi2_dev +{ + /*! Chip id of BMI2 */ + uint8_t chip_id; + + /*! Device id of BMI2 */ + uint8_t dev_id; + + /*! To store warnings */ + uint8_t info; + + /*! Type of Interface */ + enum bmi2_intf_type intf; + + /*! For switching from I2C to SPI */ + uint8_t dummy_byte; + + /*! Resolution for FOC */ + uint8_t resolution; + + /*! User set read/write length */ + uint16_t read_write_len; + + /*! Pointer to the configuration data buffer address */ + const uint8_t *config_file_ptr; + + /*! To define maximum page number */ + uint8_t page_max; + + /*! To define maximum number of input sensors/features */ + uint8_t input_sens; + + /*! To define maximum number of output sensors/features */ + uint8_t out_sens; + + /*! Indicate manual enable for auxiliary communication */ + uint8_t aux_man_en; + + /*! Defines manual read burst length for auxiliary communication */ + uint8_t aux_man_rd_burst_len; + + /*! Array of feature input configuration structure */ + const struct bmi2_feature_config *feat_config; + + /*! Array of feature output configuration structure */ + const struct bmi2_feature_config *feat_output; + + /*! Structure to maintain a copy of feature out_conf values */ + struct bmi2_int_map int_map; + + /*! Structure to maintain a copy of the re-mapped axis */ + struct bmi2_axes_remap remap; + + /*! Flag to hold enable status of sensors */ + uint32_t sens_en_stat; + + /*! Read function pointer */ + bmi2_read_fptr_t read; + + /*! Write function pointer */ + bmi2_write_fptr_t write; + + /*! Delay function pointer */ + bmi2_delay_fptr_t delay_us; + + /*! To store the gyroscope cross sensitivity value */ + int16_t gyr_cross_sens_zx; + + /* gyro enable status, used as a flag in CRT enabling and aborting */ + uint8_t gyro_en : 1; + + /* advance power saving mode status, used as a flag in CRT enabling and aborting */ + uint8_t aps_status; + + /* used as a flag to enable variant specific features like crt */ + uint16_t variant_feature; + + /* To store hold the size of config file */ + uint16_t config_size; +}; + +/*! @name Structure to enable an accel axis for foc */ +struct accel_foc_g_value +{ + /* '0' to disable x axis and '1' to enable x axis */ + uint8_t x; + + /* '0' to disable y axis and '1' to enable y axis */ + uint8_t y; + + /* '0' to disable z axis and '1' to enable z axis */ + uint8_t z; + + /* '0' for positive input and '1' for negative input */ + uint8_t sign; +}; + +/*! @name Structure to configure activity recognition settings */ +struct act_recg_sett +{ + /* 1 to enable & 0 to disable post processing */ + uint8_t act_rec_1 : 1; + + uint16_t act_rec_2; + + uint16_t act_rec_3; + + uint8_t act_rec_4 : 4; + + uint8_t act_rec_5 : 4; +}; + +#endif /* BMI2_DEFS_H_ */ diff --git a/drivers/input/misc/bmi220/bmi2xy_driver.c b/drivers/input/misc/bmi220/bmi2xy_driver.c new file mode 100755 index 00000000000..6fee87f81fb --- /dev/null +++ b/drivers/input/misc/bmi220/bmi2xy_driver.c @@ -0,0 +1,3841 @@ +/* + * @section LICENSE + * (C) Copyright 2011~2018 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bmi2xy_driver.c + * @date 28/01/2020 + * @version 1.34.0 + * + * @brief BMI2xy Linux Driver + */ + +/*********************************************************************/ +/* System header files */ +/*********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/*********************************************************************/ +/* Own header files */ +/*********************************************************************/ +#include "bmi2xy_driver.h" +#include "bs_log.h" + +/*********************************************************************/ +/* Local macro definitions */ +/*********************************************************************/ +#define DRIVER_VERSION "1.34.0" + +//add by liangdi for MT672 20210112 +#define ABSMIN -512 +#define ABSMAX 512 +#define GYRO_MIN_VALUE -32768 +#define GYRO_MAX_VALUE 32767 + +/*BMI power supply VDD 1.71V-3.6V VIO 1.2-3.6V */ +#define BMI220_VDD_MIN_UV 1750000 +#define BMI220_VDD_MAX_UV 3600000 +#define BMI220_VIO_MIN_UV 1200000 +#define BMI220_VIO_MAX_UV 3600000 + +static struct sensors_classdev accel_cdev = { + .name = "bmi2xy-accel", + .vendor = "Bosch Corporation", + .version = 1, + .handle = SENSORS_ACCELERATION_HANDLE, + .type = SENSOR_TYPE_ACCELEROMETER, + .max_range = "156.8", + .resolution = "0.00781", + .sensor_power = "0.13", + .min_delay = 1000, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_calibrate = NULL, + .sensors_write_cal_params = NULL, + .params = NULL, +}; + +static struct sensors_classdev gyro_cdev = { + .name = "bmi2xy-gyro", + .vendor = "Bosch Corporation", + .version = 1, + .handle = SENSORS_GYROSCOPE_HANDLE, + .type = SENSOR_TYPE_GYROSCOPE, + .max_range = "35", + .resolution = "0.06", + .sensor_power = "0.13", + .min_delay = 2000, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_calibrate = NULL, + .sensors_write_cal_params = NULL, + .params = NULL, +}; +//add end +/*********************************************************************/ +/* Global data */ +/*********************************************************************/ + +#define MS_TO_US(msec) UINT32_C((msec) * 1000) + +/** + * soft_reset_store - sysfs write callback which performs the + * soft rest in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t soft_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long soft_reset; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + /* Base of decimal number system is 10 */ + err = kstrtoul(buf, 10, &soft_reset); + + if (err) { + PERR("Soft reset: invalid input"); + return err; + } + + if (soft_reset) + /* Perform soft reset */ + err = bmi2_soft_reset(&client_data->device); + + if (err) { + PERR("Soft Reset failed"); + return -EIO; + } + + return count; +} + +/** + * bmi2xy_i2c_delay_us - Adds a delay in units of microsecs. + * + * @usec: Delay value in microsecs. + */ +static void bmi2xy_i2c_delay_us(u32 usec) +{ + + //if (usec <= (MS_TO_US(20))) + + /* Delay range of usec to usec + 1 millisecs + * required due to kernel limitation + */ + usleep_range(usec, usec + 1000); + //else + //udelay(usec); +} + +/** + * chip_id_show - sysfs callback for reading the chip id of the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 chip_id[2] = {0}; + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = bmi2_get_regs(BMI2_CHIP_ID_ADDR, chip_id, + 2, &client_data->device); + if (err) { + PERR("failed"); + return err; + } + return snprintf(buf, 96, "chip_id=0x%x rev_id=0x%x\n", + chip_id[0], chip_id[1]); +} + +/** + * acc_enable_show - sysfs callback which tells whether accelerometer is + * enabled or disabled. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t acc_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + u8 acc_enable = 0; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &acc_enable, 1, + &client_data->device); + /* Get the accel enable bit */ + acc_enable = (acc_enable & 0x04) >> 2; + if (err) { + PERR("read failed"); + return err; + } + + return snprintf(buf, 96, "%d\n", acc_enable); +} + +/** + * acc_enable_store - sysfs callback which enables or disables the + * accelerometer. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * Accelerometer will not be disabled unless all the features related to + * accelerometer are disabled. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t acc_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long op_mode; + u8 sens_list = BMI2_ACCEL; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + if (op_mode == 0 && + (client_data->sigmotion_enable == 0) && + (client_data->stepdet_enable == 0) && + (client_data->stepcounter_enable == 0) && + (client_data->wakeup_enable == 0) && + (client_data->activity_enable == 0) && + (client_data->anymotion_enable == 0) && + (client_data->nomotion_enable == 0) && + (client_data->orientation_enable == 0) && + (client_data->tap_enable == 0)) { + mutex_lock(&client_data->lock); + err = bmi2_sensor_disable(&sens_list, 1, + &client_data->device); + mutex_unlock(&client_data->lock); + PDEBUG("acc_enable %ld", op_mode); + } else if (op_mode == 1) { + mutex_lock(&client_data->lock); + err = bmi2_sensor_enable(&sens_list, 1, &client_data->device); + mutex_unlock(&client_data->lock); + PDEBUG("acc_enable %ld", op_mode); + } + if (err) { + PERR("failed"); + return err; + } + mutex_lock(&client_data->lock); + client_data->pw.acc_pm = op_mode; + mutex_unlock(&client_data->lock); + + return count; +} + +/** + * gyro_enable_show - sysfs callback which tells whether gyroscope is + * enabled or disabled. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + u8 gyro_enable = 0; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &gyro_enable, 1, + &client_data->device); + gyro_enable = (gyro_enable & 0x02) >> 1; + if (err) { + PERR("read failed"); + return err; + } + + return snprintf(buf, 96, "%d\n", gyro_enable); +} + +/** + * gyro_enable_store - sysfs callback which enables or disables the + * gyroscope. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t gyro_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long op_mode; + u8 sens_list = BMI2_GYRO; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &op_mode); + if (err) + return err; + if (op_mode == 0) { + mutex_lock(&client_data->lock); + err = bmi2_sensor_disable(&sens_list, 1, &client_data->device); + mutex_unlock(&client_data->lock); + PDEBUG("gyro_enable %ld", op_mode); + } else if (op_mode == 1) { + mutex_lock(&client_data->lock); + err = bmi2_sensor_enable(&sens_list, 1, &client_data->device); + mutex_unlock(&client_data->lock); + PDEBUG("gyro_enable %ld", op_mode); + } else { + err = -EINVAL; + } + if (err) { + PERR("failed"); + return err; + } + mutex_lock(&client_data->lock); + client_data->pw.gyro_pm = op_mode; + mutex_unlock(&client_data->lock); + + return count; +} + +/** + * acc_value_show - sysfs read callback which gives the + * raw accelerometer value from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t acc_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sensor_data sensor_data; + + sensor_data.type = BMI2_ACCEL; + mutex_lock(&client_data->lock); + err = bmi2_get_sensor_data(&sensor_data, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err < 0) + return err; + + return snprintf(buf, 48, "%hd %hd %hd\n", + sensor_data.sens_data.acc.x, + sensor_data.sens_data.acc.y, + sensor_data.sens_data.acc.z); +} + +/** + * gyro_value_show - sysfs read callback which gives the + * raw gyroscope value from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sensor_data sensor_data; + + sensor_data.type = BMI2_GYRO; + mutex_lock(&client_data->lock); + err = bmi2_get_sensor_data(&sensor_data, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err < 0) + return err; + + return snprintf(buf, 48, "%hd %hd %hd\n", + sensor_data.sens_data.gyr.x, + sensor_data.sens_data.gyr.y, + sensor_data.sens_data.gyr.z); +} + +/** + * acc_range_show - sysfs read callback which gives the + * accelerometer range which is set in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t acc_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + mutex_lock(&client_data->lock); + config.type = BMI2_ACCEL; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("read failed"); + return err; + } + + return snprintf(buf, 16, "%d\n", config.cfg.acc.range); +} + +/** + * acc_range_store - sysfs write callback which sets the + * accelerometer range to be set in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t acc_range_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long acc_range; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = kstrtoul(buf, 10, &acc_range); + if (err) + return err; + mutex_lock(&client_data->lock); + config.type = BMI2_ACCEL; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.acc.range = (u8)(acc_range); + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("failed"); + return -EIO; + } + + return count; +} + +/** + * acc_odr_show - sysfs read callback which gives the + * accelerometer output data rate of the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t acc_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + mutex_lock(&client_data->lock); + config.type = BMI2_ACCEL; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + if (err) { + PERR("read failed"); + mutex_unlock(&client_data->lock); + return err; + } + client_data->acc_odr = config.cfg.acc.odr; + mutex_unlock(&client_data->lock); + + return snprintf(buf, 16, "%d\n", client_data->acc_odr); +} + +/** + * acc_odr_store - sysfs write callback which sets the + * accelerometer output data rate in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t acc_odr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + u8 acc_odr; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = kstrtou8(buf, 10, &acc_odr); + if (err) { + PERR("ODR set failed"); + return err; + } + mutex_lock(&client_data->lock); + config.type = BMI2_ACCEL; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.acc.odr = acc_odr; + if (acc_odr < BMI2_ACC_ODR_12_5HZ) { + config.cfg.acc.filter_perf = BMI2_POWER_OPT_MODE; + config.cfg.acc.bwp = BMI2_ACC_RES_AVG16; + } else { + config.cfg.acc.filter_perf = BMI2_PERF_OPT_MODE; + config.cfg.acc.bwp = BMI2_ACC_NORMAL_AVG4; + } + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + if (err) { + PERR("ODR set failed"); + mutex_unlock(&client_data->lock); + return -EIO; + } + client_data->acc_odr = acc_odr; + mutex_unlock(&client_data->lock); + return count; +} + +/** + * gyro_range_show - sysfs read callback which gives the + * gyroscope range of the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + mutex_lock(&client_data->lock); + config.type = BMI2_GYRO; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("read failed"); + return err; + } + + return snprintf(buf, 16, "%d\n", config.cfg.gyr.range); +} + +/** + * gyro_range_store - sysfs write callback which sets the + * gyroscope range in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t gyro_range_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long gyro_range; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = kstrtoul(buf, 10, &gyro_range); + + if (err) { + PERR("gyro range failed"); + return err; + } + mutex_lock(&client_data->lock); + config.type = BMI2_GYRO; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.gyr.range = (u8)(gyro_range); + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("failed"); + return -EIO; + } + + return count; +} + +/** + * gyro_odr_show - sysfs read callback which gives the + * gyroscope output data rate of the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_odr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + mutex_lock(&client_data->lock); + config.type = BMI2_GYRO; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + if (err) { + PERR("read failed"); + mutex_unlock(&client_data->lock); + return err; + } + client_data->gyro_odr = config.cfg.gyr.odr; + mutex_unlock(&client_data->lock); + + return snprintf(buf, 16, "%d\n", client_data->gyro_odr); +} + +/** + * gyro_odr_store - sysfs write callback which sets the + * gyroscope output data rate in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t gyro_odr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long gyro_odr; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = kstrtoul(buf, 10, &gyro_odr); + if (err) + return err; + mutex_lock(&client_data->lock); + config.type = BMI2_GYRO; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.gyr.odr = (u8)(gyro_odr); + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + if (err) { + PERR("failed"); + mutex_unlock(&client_data->lock); + return -EIO; + } + client_data->gyro_odr = gyro_odr; + mutex_unlock(&client_data->lock); + + return count; +} + +/** + * accel_feat_selftest_store - sysfs write callback which performs the + * accelerometer self test in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t accel_feat_selftest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + u8 sensor_sel = BMI2_ACCEL_SELF_TEST; + unsigned long selftest; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &selftest); + if (err) + return err; + if (selftest == 1) { + mutex_lock(&client_data->lock); + /* Perform accelerometer self-test */ + err = bmi2_sensor_enable(&sensor_sel, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) + return -EINVAL; + } else { + return -EINVAL; + } + + return count; +} + +/** + * accel_feat_selftest_show - sysfs read callback which gives the + * accelerometer self test functionality in feature of the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t accel_feat_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct bmi2_sensor_data sensor_data; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + sensor_data.type = BMI2_ACCEL_SELF_TEST; + err = bmi2_get_sensor_data(&sensor_data, 1, &client_data->device); + if (err) + return err; + + return snprintf(buf, 64, "X axis %d\tY axis %d\tZ axis %d\n", + sensor_data.sens_data.accel_self_test_output.acc_x_ok, + sensor_data.sens_data.accel_self_test_output.acc_y_ok, + sensor_data.sens_data.accel_self_test_output.acc_z_ok); +} + +/** + * accel_selftest_show - sysfs read callback which gives the + * accelerometer self test result of the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t accel_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 64, "Pass => 0\tFail => 1\tNot run => 2 %d\n", + client_data->accel_selftest); +} + +/** + * accel_selftest_store - sysfs write callback which performs the + * accelerometer self test in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t accel_selftest_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long selftest; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &selftest); + if (err) + return err; + if (selftest == 1) { + mutex_lock(&client_data->lock); + /* Perform accelerometer self-test */ + err = bmi2_perform_accel_self_test(&client_data->device); + if (err) + client_data->accel_selftest = SELF_TEST_FAIL; + else + client_data->accel_selftest = SELF_TEST_PASS; + mutex_unlock(&client_data->lock); + } else { + err = -EINVAL; + return err; + } + + return count; +} + +/** + * accel_foc_show - sysfs read callback which notifies the format which + * is to be used to perform accelerometer FOC in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t accel_foc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + return snprintf(buf, 64, + "Use echo x_axis y_axis z_axis > accel_foc\n"); +} + +/** + * accel_foc_store - sysfs write callback which performs the + * accelerometer FOC in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t accel_foc_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct accel_foc_g_value g_value = {0}; + unsigned int data[4]; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err = 0; + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + err = sscanf(buf, "%d %d %d %d", + &data[0], &data[1], &data[2], &data[3]); + + if (err != 4) { + PERR("Invalid argument"); + return -EINVAL; + } + + g_value.x = data[0]; + g_value.y = data[1]; + g_value.z = data[2]; + g_value.sign = data[3]; + PDEBUG("g_value.x=%d, g_value.y=%d, g_value.z=%d g_value.sign=%d", + g_value.x, g_value.y, g_value.z, g_value.sign); + err = bmi2_perform_accel_foc(&g_value, &client_data->device); + if (err) { + PERR("FOC accel failed %d", err); + return err; + } + PINFO("FOC Accel successfully done"); + return count; +} + +/** + * gyro_foc_show - sysfs read callback which performs the gyroscope + * FOC in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_foc_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err = 0; + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + err = bmi2_perform_gyro_foc(&client_data->device); + if (err) { + PERR("FOC gyro failed %d", err); + return err; + } + + return snprintf(buf, 64, + "FOC Gyro successfully done"); +} + +/** + * fifo_data_frame_show - sysfs read callback which reads the fifo data + * according to the fifo length. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t fifo_data_frame_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err = 0; + u16 fifo_bytecount = 0; + u8 reg_data[2] = {0, }; + + mutex_lock(&client_data->lock); + if (!client_data->fifo_mag_enable && !client_data->fifo_acc_enable + && !client_data->fifo_gyro_enable) { + PERR("sensor not enabled for fifo\n"); + mutex_unlock(&client_data->lock); + return -EINVAL; + } + err = bmi2_get_regs(BMI2_FIFO_LENGTH_0_ADDR, reg_data, 2, + &client_data->device); + if (err < 0) { + PERR("read fifo_len err=%d", err); + mutex_unlock(&client_data->lock); + return -EINVAL; + } + fifo_bytecount = (reg_data[1] << 8) | reg_data[0]; + + if (fifo_bytecount == 0) { + mutex_unlock(&client_data->lock); + return 0; + } + /* Since I2c interface limit on Qualcomm based chipset is 256 */ + if (fifo_bytecount > 256) + fifo_bytecount = 256; + err += bmi2_get_regs(BMI2_FIFO_DATA_ADDR, buf, fifo_bytecount, + &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("read fifo err = %d", err); + return -EINVAL; + } + return fifo_bytecount; +} + +/** + * acc_fifo_enable_show - sysfs read callback which shows the enable or + * disable status of the accelerometer FIFO in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t acc_fifo_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + u8 fifo_acc_enable; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + mutex_lock(&client_data->lock); + /* Get the fifo config */ + err = bmi2_get_regs(0x49, &fifo_acc_enable, 1, &client_data->device); + mutex_unlock(&client_data->lock); + fifo_acc_enable = (fifo_acc_enable & 0x40) >> 6; + if (err) { + PERR("read failed"); + return err; + } + return snprintf(buf, 16, "%x\n", fifo_acc_enable); +} + +/** + * acc_fifo_enable_store - sysfs write callback enables or + * disables the accelerometer FIFO in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t acc_fifo_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long data; + u8 fifo_acc_enable; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + mutex_lock(&client_data->lock); + err = kstrtoul(buf, 10, &data); + if (err) { + mutex_unlock(&client_data->lock); + return err; + } + fifo_acc_enable = (unsigned char)(data & 0x01); + /* Disable advance power save to use FIFO */ + if (fifo_acc_enable) { + err = bmi2_set_adv_power_save(0, &client_data->device); + if (err) { + mutex_unlock(&client_data->lock); + return -EINVAL; + } + } + err = bmi2_set_fifo_config(BMI2_FIFO_ACC_EN, fifo_acc_enable, + &client_data->device); + if (err) { + PERR("failed"); + mutex_unlock(&client_data->lock); + return -EIO; + } + client_data->fifo_acc_enable = fifo_acc_enable; + mutex_unlock(&client_data->lock); + + return count; +} + +/** + * gyro_fifo_enable_store - sysfs write callback enables or + * disables the gyroscope FIFO in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t gyro_fifo_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long data; + unsigned char fifo_gyro_enable; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + mutex_lock(&client_data->lock); + err = kstrtoul(buf, 10, &data); + if (err) { + mutex_unlock(&client_data->lock); + return err; + } + fifo_gyro_enable = (unsigned char)(data & 0x01); + + /* Disable advance power save to use FIFO */ + if (fifo_gyro_enable) { + err = bmi2_set_adv_power_save(0, &client_data->device); + if (err) { + mutex_unlock(&client_data->lock); + return -EINVAL; + } + } + + err = bmi2_set_fifo_config(BMI2_FIFO_GYR_EN, fifo_gyro_enable, + &client_data->device); + if (err) { + PERR("failed"); + mutex_unlock(&client_data->lock); + return -EIO; + } + client_data->fifo_gyro_enable = fifo_gyro_enable; + mutex_unlock(&client_data->lock); + + return count; +} + +/** + * gyro_fifo_enable_show - sysfs read callback which shows the enable or + * disable status of the gyroscope FIFO in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_fifo_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + u8 fifo_gyro_enable; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + mutex_lock(&client_data->lock); + /* Get the fifo config */ + err = bmi2_get_regs(BMI2_FIFO_CONFIG_1_ADDR, &fifo_gyro_enable, 1, + &client_data->device); + mutex_unlock(&client_data->lock); + fifo_gyro_enable = (fifo_gyro_enable & 0x80) >> 7; + if (err) { + PERR("read failed"); + return err; + } + return snprintf(buf, 16, "%x\n", fifo_gyro_enable); +} + + +/** + * fifo_flush_store - sysfs write callback which flushes the fifo data + * in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t fifo_flush_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long enable; + /* Command for fifo flush */ + u8 fifo_flush = 0xB0; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = kstrtoul(buf, 10, &enable); + if (err) + return err; + if (enable == 0x01) { + mutex_lock(&client_data->lock); + err = bmi2_set_regs(BMI2_CMD_REG_ADDR, &fifo_flush, 1, + &client_data->device); + mutex_unlock(&client_data->lock); + } else { + return -EINVAL; + } + if (err) { + PERR("write failed"); + return -EIO; + } + return count; +} + +/** + * aps_enable_show - sysfs callback which tells whether the advanced power + * save mode is enabled or disabled. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t aps_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + u8 aps_status = 0; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + /* Get the status of advance power save mode */ + err = bmi2_get_adv_power_save(&aps_status, &client_data->device); + + if (err) { + PERR("read failed"); + return err; + } + + /* Maximum number of bytes used to prevent overflow */ + return snprintf(buf, 96, "%d\n", aps_status); +} + +/** + * aps_enable_store - sysfs callback which enables or disables the + * advanced power save mode. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t aps_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + u8 aps_status; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = kstrtou8(buf, 10, &aps_status); + if (err) { + PERR("set advance power mode failed"); + return err; + } + + if (aps_status) { + + /* Enable advance power save mode */ + err = bmi2_set_adv_power_save(BMI2_ENABLE, + &client_data->device); + } else { + + /* Disable advance power save mode */ + err = bmi2_set_adv_power_save(BMI2_DISABLE, + &client_data->device); + } + + if (err) + return -EINVAL; + return count; +} + +/** + * load_config_stream_show - sysfs read callback which gives the loaded + * config stream in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t load_config_stream_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + return snprintf(buf, 48, "config stream %s\n", + client_data->config_stream_name); +} + +/** + * bmi2xy_initialize_interrupt_settings - Initialize the interrupt settings of + * the sensor. + * + * @client_data: Instance of client data structure. + * + * Return: Status of the function. + * * 0 - OK + * * Negative value - Failed + */ +static int bmi2xy_initialize_interrupt_settings( + struct bmi2xy_client_data *client_data) +{ + int err = 0; + /* Input enable and open drain */ + u8 int_enable = 0x0A; + /* Permanent latched */ + u8 latch_enable = 0x01; + /* Map all feature interrupts */ + u8 int1_map = 0xff; + + mutex_lock(&client_data->lock); + err = bmi2_set_regs(BMI2_INT1_MAP_FEAT_ADDR, &int1_map, 1, + &client_data->device); + bmi2xy_i2c_delay_us(MS_TO_US(10)); + err += bmi2_set_regs(BMI2_INT1_IO_CTRL_ADDR, &int_enable, 1, + &client_data->device); + bmi2xy_i2c_delay_us(MS_TO_US(10)); + err += bmi2_set_regs(BMI2_INT_LATCH_ADDR, &latch_enable, 1, + &client_data->device); + mutex_unlock(&client_data->lock); + bmi2xy_i2c_delay_us(MS_TO_US(10)); + + if (err) + PERR("map and enable interrupt1 failed err=%d", err); + + return err; +} + +/** + * bmi2xy_init_fifo_config - Initializes the fifo configuration of the sensor. + * + * @client_data: Instance of client data structure. + * + * Return: Status of the function. + * * 0 - OK + * * Negative value - Failed + */ +static int bmi2xy_init_fifo_config(struct bmi2xy_client_data *client_data) +{ + int err = 0; + u8 reg_data; + + mutex_lock(&client_data->lock); + err = bmi2_get_regs(BMI2_FIFO_CONFIG_0_ADDR, ®_data, 1, + &client_data->device); + /* Enable fifo time */ + reg_data |= 0x02; + err = bmi2_set_regs(BMI2_FIFO_CONFIG_0_ADDR, ®_data, 1, + &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("enable fifo header failed err=%d", err); + return err; + } + mutex_lock(&client_data->lock); + err = bmi2_get_regs(BMI2_FIFO_CONFIG_1_ADDR, ®_data, 1, + &client_data->device); + /* Enable fifo header */ + reg_data |= 0x10; + err = bmi2_set_regs(BMI2_FIFO_CONFIG_1_ADDR, ®_data, 1, + &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("enable fifo header failed err=%d", err); + return err; + } + + return 0; +} + +/** + * bmi2xy_update_config_stream - Loads the config stream in the sensor. + * + * @client_data: Instance of client data structure. + * @option: Option to choose different tbin images. + * + * Return: Status of the function. + * * 0 - OK + * * Negative value - Failed + */ +int bmi2xy_update_config_stream( + struct bmi2xy_client_data *client_data, int option) +{ + const struct firmware *config_entry; + char *name; + int err = 0; + u8 load_status = 0; + + u8 crc_check = 0; + + switch (option) { + case 0: + name = "android.tbin"; + break; + case 1: + name = "legacy.tbin"; + break; + case 2: + name = "qualcomm.tbin"; + break; + default: + PERR("choose config stream = %d,use default ", option); + name = "bmi2xy_config_stream"; + break; + } + //PDEBUG("choose the config_stream %s", name); + if ((option == 0) || (option == 1) || (option == 2)) { + err = request_firmware(&config_entry, + name, &client_data->acc_input->dev); + if (err < 0) { + PERR("Failed to get config_stream from vendor path"); + return -EINVAL; + } + PDEBUG("config_stream size = %zd", config_entry->size); + + client_data->device.config_file_ptr = config_entry->data; + err = bmi220_init(&client_data->device); + /* Delay to read the configuration load status */ + client_data->device.delay_us(20); + /* Get the status */ + err = bmi2_get_regs(BMI2_INTERNAL_STATUS_ADDR, &load_status, 1, + &client_data->device); + if (!err) + client_data->config_stream_name = name; + if (err) + PERR("download config stream failed: %d load status %d", + err, load_status); + release_firmware(config_entry); + bmi2xy_i2c_delay_us(MS_TO_US(10)); + } else if (option == 3) { + err = bmi220_init(&client_data->device); + if (!err) + name = "bmi220_config_stream"; + client_data->config_stream_name = name; + + if (err) { + PERR("download config stream failed %d\n", err); + return err; + } + bmi2xy_i2c_delay_us(MS_TO_US(200)); + err = bmi2_get_regs(BMI2_INTERNAL_STATUS_ADDR, + &crc_check, 1, &client_data->device); + if (err) + PERR("reading CRC failed"); + if (crc_check != BMI2_CONFIG_LOAD_SUCCESS) + PERR("crc check error %x", crc_check); + } + return err; +} + +/** + * load_config_stream_store - sysfs write callback which loads the + * config stream in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t load_config_stream_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long choose = 0; + int err = 0; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_remap remapped_axis; + + err = kstrtoul(buf, 10, &choose); + if (err) + return err; + PDEBUG("config_stream_choose %ld", choose); + /* Load config file if not loaded in init stage */ + if (!client_data->config_file_loaded) { + err = bmi2xy_update_config_stream(client_data, choose); + if (err) { + PERR("config_stream load error"); + return err; + } + } + err = bmi2xy_initialize_interrupt_settings(client_data); + err += bmi2xy_init_fifo_config(client_data); + err += bmi2_get_remap_axes(&remapped_axis, &client_data->device); + remapped_axis.x = BMI2_NEG_X; + remapped_axis.y = BMI2_Y; + remapped_axis.z = BMI2_NEG_Z; + err = bmi2_set_remap_axes(&remapped_axis, &client_data->device); + if (err) { + PERR("Error after config stream loading %d", err); + return err; + } + + return count; +} + +/** + * reg_sel_show - sysfs read callback which provides the register + * address selected. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t reg_sel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + return snprintf(buf, 64, "reg=0X%02X, len=%d\n", + client_data->reg_sel, client_data->reg_len); +} + +/** + * reg_sel_store - sysfs write callback which stores the register + * address to be selected. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t reg_sel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err; + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + mutex_lock(&client_data->lock); + err = sscanf(buf, "%11X %11d", + &client_data->reg_sel, &client_data->reg_len); + if ((err != 2) || (client_data->reg_len > 128) + || (client_data->reg_sel > 127)) { + PERR("Invalid argument"); + mutex_unlock(&client_data->lock); + return -EINVAL; + } + mutex_unlock(&client_data->lock); + return count; +} + +/** + * reg_val_show - sysfs read callback which shows the register + * value which is read from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t reg_val_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err; + u8 reg_data[128]; + unsigned int i; + int pos; + + mutex_lock(&client_data->lock); + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + if ((client_data->reg_len > 128) || (client_data->reg_sel > 127)) { + PERR("Invalid argument"); + mutex_unlock(&client_data->lock); + return -EINVAL; + } + + err = bmi2_get_regs(client_data->reg_sel, reg_data, + client_data->reg_len, &client_data->device); + + if (err < 0) { + PERR("Reg op failed"); + mutex_unlock(&client_data->lock); + return err; + } + pos = 0; + for (i = 0; i < client_data->reg_len; ++i) { + pos += snprintf(buf + pos, 16, "%02X", reg_data[i]); + buf[pos++] = (i + 1) % 16 == 0 ? '\n' : ' '; + } + mutex_unlock(&client_data->lock); + if (buf[pos - 1] == ' ') + buf[pos - 1] = '\n'; + return pos; +} + +/** + * reg_val_store - sysfs write callback which stores the register + * value which is to be written in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t reg_val_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err; + u8 reg_data[128] = {0,}; + unsigned int i, j, status, digit; + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + status = 0; + mutex_lock(&client_data->lock); + /* Lint -save -e574 */ + for (i = j = 0; i < count && j < client_data->reg_len; ++i) { + /* Lint -restore */ + if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t' || + buf[i] == '\r') { + status = 0; + ++j; + continue; + } + digit = buf[i] & 0x10 ? (buf[i] & 0xF) : ((buf[i] & 0xF) + 9); + PDEBUG("digit is %d", digit); + switch (status) { + case 2: + ++j; /* Fall thru */ + case 0: + reg_data[j] = digit; + status = 1; + break; + case 1: + reg_data[j] = reg_data[j] * 16 + digit; + status = 2; + break; + } + } + if (status > 0) + ++j; + if (j > client_data->reg_len) + j = client_data->reg_len; + else if (j < client_data->reg_len) { + PERR("Invalid argument"); + mutex_unlock(&client_data->lock); + return -EINVAL; + } + PDEBUG("Reg data read as"); + for (i = 0; i < j; ++i) + PDEBUG("%d", reg_data[i]); + err = client_data->device.write(client_data->device.dev_id, + client_data->reg_sel, + reg_data, client_data->reg_len); + mutex_unlock(&client_data->lock); + if (err < 0) { + PERR("Reg op failed"); + return err; + } + return count; +} + +/** + * driver_version_show - sysfs read callback which provides the driver + * version. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t driver_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 128, + "Driver version: %s\n", DRIVER_VERSION); +} + +/** + * avail_sensor_show - sysfs read callback which provides the sensor-id + * to the user. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t avail_sensor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u16 avail_sensor = 220; + + return snprintf(buf, 32, "%d\n", avail_sensor); +} + +/** + * execute_crt_store - sysfs write callback which triggers the + * CRT feature in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t execute_crt_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err = 0; + unsigned int data, rd_wr_len, rd_wr_len_prev; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + rd_wr_len_prev = client_data->device.read_write_len; + err = sscanf(buf, "%u %u", &data, &rd_wr_len); + if ((err != 2) || (data != 1) || (rd_wr_len > 510)) { + PERR("Invalid argument"); + return -EINVAL; + } + + client_data->device.read_write_len = rd_wr_len; + mutex_lock(&client_data->lock); + err = bmi2_do_crt(&client_data->device); + mutex_unlock(&client_data->lock); + client_data->device.read_write_len = rd_wr_len_prev; + + PDEBUG("CRT execution status %d", err); + + return count; +} + + +/** + * gyr_usr_gain_show - sysfs callback which returns the gyro + * user gain values from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * This should be called after executing the CRT operation. + * + * Return: Number of characters returned. + */ +static ssize_t gyr_usr_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + u8 gyr_usr_gain[3]; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = bmi2_get_regs(BMI2_GYR_USR_GAIN_0_ADDR, gyr_usr_gain, + 3, &client_data->device); + + if (err) + return err; + + return snprintf(buf, 48, "x = %hd\t y = %hd\t z= %hd\n", + gyr_usr_gain[0], + gyr_usr_gain[1], + gyr_usr_gain[2]); +} + +/** + * gyro_offset_comp_show - sysfs callback which returns the gyro + * offset compensation values from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_offset_comp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + /* Structure to store gyroscope offset compensated data */ + struct bmi2_sens_axes_data gyr_off_comp = {0}; + + /* Read the offset compensation registers */ + err = bmi2_read_gyro_offset_comp_axes(&gyr_off_comp, + &client_data->device); + + if (err < 0) + return err; + + return snprintf(buf, 48, "%hd %hd %hd\n", gyr_off_comp.x, + gyr_off_comp.y, + gyr_off_comp.z); +} + +/** + * gyro_offset_comp_store - sysfs write callback which performs the + * gyroscope offset compensation in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t gyro_offset_comp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long gyro_off_comp; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + u8 sensor_sel[3] = {BMI2_ACCEL, BMI2_GYRO, BMI2_GYRO_SELF_OFF}; + + err = kstrtoul(buf, 10, &gyro_off_comp); + + if (err) { + PERR("gyro offset compenstion: invalid input"); + return err; + } + + if (gyro_off_comp) { + /* Enable self offset correction */ + err = bmi2_sensor_enable(&sensor_sel[2], 1, + &client_data->device); + /* Enable gyroscope offset compensation */ + err = bmi2_set_gyro_offset_comp(BMI2_ENABLE, + &client_data->device); + } else { + /* Disable self offset correction */ + err = bmi2_sensor_disable(&sensor_sel[2], 1, + &client_data->device); + } + + if (!err) { + /* Enable accel and gyro */ + err = bmi2_sensor_enable(&sensor_sel[0], 2, + &client_data->device); + } else { + PERR("Gyro offset compenstion failed"); + return -EIO; + } + + return count; +} + +/** + * gyro_self_test_show - sysfs callback which performs the gyro self test + * in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t gyro_self_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = bmi2_do_gyro_st(&client_data->device); + + if (err) { + PERR("Gyro self test fail %d\n", err); + return err; + } + + return snprintf(buf, 64, "Gyro Self test successful\n"); +} + +/** + * nvm_prog_show - sysfs read callback which gives the performs NVM + * back up of offset compensation values for accelerometer. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t nvm_prog_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = bmi2_nvm_prog(&client_data->device); + + if (err) { + PERR("nvm programming failed %d\n", err); + return err; + } + + return snprintf(buf, 64, "nvm programming successful\n"); + +} + +/** + * config_function_show - sysfs read callback which gives the list of + * enabled features in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t config_function_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + return snprintf(buf, PAGE_SIZE, + "sig_motion0=%d\n step_detector1=%d\n step_counter2=%d\n" + "tilt3=%d\n uphold_to_wake4=%d\n glance_detector5=%d\n" + "wakeup6=%d\n any_motion7=%d\n" + "orientation8=%d\n flat9=%d\n" + "high_g10=%d\n low_g11=%d\n" + "activity12=%d\n nomotion13=%d\n" + "ext_sync14=%d\n", + client_data->sigmotion_enable, client_data->stepdet_enable, + client_data->stepcounter_enable, client_data->tilt_enable, + client_data->uphold_to_wake, client_data->glance_enable, + client_data->wakeup_enable, client_data->anymotion_enable, + client_data->orientation_enable, client_data->flat_enable, + client_data->highg_enable, client_data->lowg_enable, + client_data->activity_enable, client_data->nomotion_enable, + client_data->s4s_enable); +} + +/** + * config_function_store - sysfs write callback which enable or disable + * the features in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t config_function_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + int config_func = 0; + int enable = 0; + u8 feature = 0; + u8 sens_list = 0; + struct bmi2_sens_config config[2]; + + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + ret = sscanf(buf, "%11d %11d", &config_func, &enable); + PDEBUG("config_func = %d, enable=%d", config_func, enable); + if (ret != 2) { + PERR("Invalid argument"); + return -EINVAL; + } + if (config_func < 0 || config_func > 14) + return -EINVAL; + + mutex_lock(&client_data->lock); + switch (config_func) { + case BMI2XY_SIG_MOTION_SENSOR: + feature = BMI2_SIG_MOTION; + client_data->sigmotion_enable = enable; + break; + case BMI2XY_NO_MOTION_SENSOR: + config[0].type = BMI2_NO_MOTION; + feature = BMI2_NO_MOTION; + ret = bmi2_get_sensor_config(&config[0], 1, + &client_data->device); + /* A TYPE_STATIONARY_DETECT event is produced if the device has + * been stationary for at least 5 seconds with a maximal latency + * of 5 additional seconds. ie: it may take up anywhere from 5 + * to 10 seconds after the device has been at rest to trigger + * this event. + */ + config[0].cfg.no_motion.duration = 0x118; + if (enable) { + /* Enable the x, y and z axis of nomotion */ + config[0].cfg.no_motion.select_x = BMI2_ENABLE; + config[0].cfg.no_motion.select_y = BMI2_ENABLE; + config[0].cfg.no_motion.select_z = BMI2_ENABLE; + + } else { + /* Disable the x, y and z axis of nomotion */ + config[0].cfg.no_motion.select_x = BMI2_DISABLE; + config[0].cfg.no_motion.select_y = BMI2_DISABLE; + config[0].cfg.no_motion.select_z = BMI2_DISABLE; + } + ret += bmi2_set_sensor_config(&config[0], 1, + &client_data->device); + if (ret == 0) + client_data->nomotion_enable = enable; + break; + case BMI2XY_ORIENTATION_SENSOR: + feature = BMI2_ORIENTATION; + client_data->orientation_enable = enable; + break; + case BMI2XY_STEP_DETECTOR_SENSOR: + feature = BMI2_STEP_DETECTOR; + client_data->stepdet_enable = enable; + break; + case BMI2XY_STEP_COUNTER_SENSOR: + feature = BMI2_STEP_COUNTER; + client_data->stepcounter_enable = enable; + break; + case BMI2XY_ANY_MOTION_SENSOR: + config[0].type = BMI2_ANY_MOTION; + feature = BMI2_ANY_MOTION; + ret = bmi2_get_sensor_config(&config[0], 1, + &client_data->device); + /* A TYPE_MOTION_DETECT event is produced if the device has been + * in motion for at least 5 seconds with a maximal latency of + * 5 additional seconds. ie: it may take up anywhere from + * 5 to 10 seconds after the device has been at rest to trigger + * this event. + */ + config[0].cfg.any_motion.duration = 0x118; + + if (enable) { + /* Enable the x, y and z axis of anymotion */ + config[0].cfg.any_motion.select_x = BMI2_ENABLE; + config[0].cfg.any_motion.select_y = BMI2_ENABLE; + config[0].cfg.any_motion.select_z = BMI2_ENABLE; + + } else { + /* Disable the x, y and z axis of anymotion */ + config[0].cfg.any_motion.select_x = BMI2_DISABLE; + config[0].cfg.any_motion.select_y = BMI2_DISABLE; + config[0].cfg.any_motion.select_z = BMI2_DISABLE; + } + ret += bmi2_set_sensor_config(&config[0], 1, + &client_data->device); + if (ret == 0) + client_data->anymotion_enable = enable; + break; + case BMI2XY_ACTIVITY_SENSOR: + feature = BMI2_STEP_ACTIVITY; + client_data->activity_enable = enable; + break; + case BMI2XY_S4S: + feature = BMI2_EXT_SENS_SYNC; + client_data->s4s_enable = enable; + break; + default: + PERR("Invalid sensor handle: %d", config_func); + mutex_unlock(&client_data->lock); + return -EINVAL; + } + sens_list = feature; + if (enable == 1) { + ret = bmi2_sensor_enable(&sens_list, 1, &client_data->device); + /* Mapping activity to unused int pin 4(starts from 1) */ + if ((feature == BMI2_STEP_ACTIVITY) && (ret == 0)) { + config[0].type = BMI2_STEP_ACTIVITY; + ret = bmi2_get_sensor_config(&config[0], 1, + &client_data->device); + config[0].cfg.step_counter.out_conf_activity = 4; + ret += bmi2_set_sensor_config(&config[0], 1, + &client_data->device); + } + } + if (enable == 0) + ret = bmi2_sensor_disable(&sens_list, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (ret) { + PERR("write failed %d\n", ret); + return -EIO; + } + + return count; +} + +/** + * feat_page_sel_show - sysfs read callback which shows the feature + * address being selected. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t feat_page_sel_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + return snprintf(buf, 64, "reg=0X%02X, len=%d\n", + client_data->feat_page_sel, client_data->feat_page_len); +} + +/** + * feat_page_sel_store - sysfs write callback which stores the feature + * address to be used for reading the data. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t feat_page_sel_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err; + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + mutex_lock(&client_data->lock); + err = sscanf(buf, "%11X %11d", + &client_data->feat_page_sel, &client_data->feat_page_len); + mutex_unlock(&client_data->lock); + if (err != 2) { + PERR("Invalid argument"); + return -EINVAL; + } + return count; +} + +/** + * feat_page_val_show - sysfs read callback which provides the feature + * data which is read from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t feat_page_val_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err = 0; + u8 reg_data[128]; + unsigned int pos, i; + u8 page; + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + mutex_lock(&client_data->lock); + page = (u8)client_data->feat_page_sel; + + err = bmi2_set_regs(BMI2_FEAT_PAGE_ADDR, &page, 1, + &client_data->device); + /* Get the configuration from the page */ + err += bmi2_get_regs(BMI2_FEATURES_REG_ADDR, + reg_data, BMI2_FEAT_SIZE_IN_BYTES, &client_data->device); + if (err < 0) { + PERR("Reg op failed"); + mutex_unlock(&client_data->lock); + return err; + } + pos = 0; + for (i = 0; i < client_data->feat_page_len; ++i) { + pos += snprintf(buf + pos, 16, "%02X", reg_data[i]); + buf[pos++] = (i + 1) % 16 == 0 ? '\n' : ' '; + } + mutex_unlock(&client_data->lock); + if (buf[pos - 1] == ' ') + buf[pos - 1] = '\n'; + return pos; +} + +/** + * feat_page_val_store - sysfs write callback which stores the feature + * data which is to be written in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t feat_page_val_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + int err; + u8 aps_status = 0; + u8 reg_data[128] = {0,}; + unsigned int i, j, status, digit; + u8 page; + + if (client_data == NULL) { + PERR("Invalid client_data pointer"); + return -ENODEV; + } + mutex_lock(&client_data->lock); + /* Get the status of advance power save mode */ + err = bmi2_get_adv_power_save(&aps_status, &client_data->device); + if (aps_status) { + /* Disable advance power save mode */ + err = bmi2_set_adv_power_save(BMI2_DISABLE, + &client_data->device); + } + page = (u8)client_data->feat_page_sel; + + status = 0; + /* Lint -save -e574 */ + for (i = j = 0; i < count && j < client_data->feat_page_len; ++i) { + /* Lint -restore */ + if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t' || + buf[i] == '\r') { + status = 0; + ++j; + continue; + } + digit = buf[i] & 0x10 ? (buf[i] & 0xF) : ((buf[i] & 0xF) + 9); + PDEBUG("digit is %d", digit); + switch (status) { + case 2: + ++j; /* Fall thru */ + case 0: + reg_data[j] = digit; + status = 1; + break; + case 1: + reg_data[j] = reg_data[j] * 16 + digit; + status = 2; + break; + } + } + if (status > 0) + ++j; + if (j > client_data->feat_page_len) + j = client_data->feat_page_len; + else if (j < client_data->feat_page_len) { + PERR("Invalid argument"); + mutex_unlock(&client_data->lock); + return -EINVAL; + } + PDEBUG("Reg data read as"); + for (i = 0; i < j; ++i) + PDEBUG("%d", reg_data[i]); + /* Switch page */ + err = bmi2_set_regs(BMI2_FEAT_PAGE_ADDR, &page, 1, + &client_data->device); + /* Set the configuration back to the page */ + err += bmi2_set_regs(BMI2_FEATURES_REG_ADDR, + reg_data, BMI2_FEAT_SIZE_IN_BYTES, &client_data->device); + + if (aps_status) { + /* Disable advance power save mode */ + err = bmi2_set_adv_power_save(BMI2_ENABLE, + &client_data->device); + } + mutex_unlock(&client_data->lock); + if (err < 0) { + PERR("Reg op failed"); + return err; + } + return count; +} + +/** + * step_counter_val_show - sysfs read callback which reads and provide + * output value of step-counter sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t step_counter_val_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + u32 step_counter_val = 0; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sensor_data step_counter_data; + + step_counter_data.type = BMI2_STEP_COUNTER; + mutex_lock(&client_data->lock); + err = bmi2_get_sensor_data(&step_counter_data, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("read failed"); + return err; + } + step_counter_val = step_counter_data.sens_data.step_counter_output; + PDEBUG("val %u", step_counter_val); + mutex_lock(&client_data->lock); + if (client_data->err_int_trigger_num == 0) { + client_data->step_counter_val = step_counter_val; + PDEBUG("report val %u", client_data->step_counter_val); + err = snprintf(buf, 96, "%u\n", client_data->step_counter_val); + client_data->step_counter_temp = client_data->step_counter_val; + } else { + PDEBUG("after err report val %u", + client_data->step_counter_val + step_counter_val); + err = snprintf(buf, 96, "%u\n", + client_data->step_counter_val + step_counter_val); + client_data->step_counter_temp = + client_data->step_counter_val + step_counter_val; + } + mutex_unlock(&client_data->lock); + return err; +} + +/** + * step_counter_watermark_show - sysfs read callback which reads and + * provide the watermark level of step-counter sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t step_counter_watermark_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err = 0; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + mutex_lock(&client_data->lock); + config.type = BMI2_STEP_COUNTER; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("read failed"); + return err; + } + return snprintf(buf, 32, "%d\n", + config.cfg.step_counter.watermark_level); +} + +/** + * step_counter_watermark_store - sysfs write callback which stores the + * watermark level of step-counter in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t step_counter_watermark_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err = 0; + unsigned long step_watermark; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = kstrtoul(buf, 10, &step_watermark); + if (err) + return err; + PDEBUG("watermark step_counter %ld", step_watermark); + mutex_lock(&client_data->lock); + config.type = BMI2_STEP_COUNTER; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.step_counter.watermark_level = (u16)step_watermark; + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("write failed"); + return err; + } + return count; +} + +/** + * step_counter_reset_store - sysfs write callback which resets the + * step-counter value in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t step_counter_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err = 0; + unsigned long reset_counter; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = kstrtoul(buf, 10, &reset_counter); + if (err) + return err; + PDEBUG("reset_counter %ld", reset_counter); + mutex_lock(&client_data->lock); + config.type = BMI2_STEP_COUNTER; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.step_counter.reset_counter = (u16)reset_counter; + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + if (err) { + PERR("write failed"); + mutex_unlock(&client_data->lock); + return err; + } + client_data->step_counter_val = 0; + client_data->step_counter_temp = 0; + mutex_unlock(&client_data->lock); + return count; +} + +/** + * step_buffer_size_store - sysfs callback which sets the step buffer size in + * the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t step_buffer_size_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long step_buffer_size; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = kstrtoul(buf, 10, &step_buffer_size); + + if (err) + return err; + + config.type = BMI2_STEP_ACTIVITY; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + + if (err == BMI2_OK) { + /* Get least significant byte */ + config.cfg.step_counter.step_buffer_size = step_buffer_size + & (0xFF); + err = bmi2_set_sensor_config(&config, 1, &client_data->device); + if (err) + return err; + } + return count; +} + +/** + * step_buffer_size_show - sysfs callback which gives the step buffer size set + * in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t step_buffer_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + config.type = BMI2_STEP_ACTIVITY; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + + if (err) { + PERR("read failed"); + return err; + } + return snprintf(buf, 16, "%d\n", + config.cfg.step_counter.step_buffer_size); +} + +/** + * any_motion_config_show - sysfs read callback which reads the + * any-motion configuration from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t any_motion_config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + mutex_lock(&client_data->lock); + config.type = BMI2_ANY_MOTION; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("read failed"); + return err; + } + return snprintf(buf, PAGE_SIZE, "duration =0x%x threshold= 0x%x\n", + config.cfg.any_motion.duration, + config.cfg.any_motion.threshold); +} + +/** + * any_motion_config_store - sysfs write callback which writes the + * any-motion configuration in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t any_motion_config_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err = 0; + unsigned int data[2] = {0}; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = sscanf(buf, "%11x %11x", &data[0], &data[1]); + if (err != 2) { + PERR("Invalid argument"); + return -EINVAL; + } + mutex_lock(&client_data->lock); + config.type = BMI2_ANY_MOTION; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.any_motion.duration = (u16)data[0]; + config.cfg.any_motion.threshold = (u16)data[1]; + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("write failed"); + return err; + } + return count; +} + +/** + * any_motion_enable_axis_store - sysfs write callback which enable or + * disable the x,y and z axis of any-motion sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t any_motion_enable_axis_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err = 0; + unsigned int data[3] = {0}; + struct bmi2_sens_config sens; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = sscanf(buf, "%11x %11x %11x", &data[0], &data[1], &data[2]); + if (err != 3) { + PERR("Invalid argument"); + return -EINVAL; + } + /* Configure the axis for any/no-motion */ + mutex_lock(&client_data->lock); + sens.type = BMI2_ANY_MOTION; + + err = bmi2_get_sensor_config(&sens, 1, &client_data->device); + sens.cfg.any_motion.select_x = data[0] & 0x01; + sens.cfg.any_motion.select_y = data[1] & 0x01; + sens.cfg.any_motion.select_z = data[2] & 0x01; + err = bmi2_set_sensor_config(&sens, 1, &client_data->device); + if (err) { + PERR("write failed"); + mutex_unlock(&client_data->lock); + return err; + } + /* If user disabled all axis,then anymotion/no-motion is disabled + * For re-enabling anymotion/nomotion, config_function sysnode or + * any_no_motion_enable_axis(with atleast 1 axis enabled) can be used. + */ + if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0)) + client_data->anymotion_enable = 0; + + mutex_unlock(&client_data->lock); + + return count; +} + +/** + * nomotion_config_show - sysfs read callback which reads the + * no-motion configuration from the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as output. + * + * Return: Number of characters returned. + */ +static ssize_t no_motion_config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int err; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + mutex_lock(&client_data->lock); + config.type = BMI2_NO_MOTION; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("read failed"); + return err; + } + return snprintf(buf, PAGE_SIZE, "duration =0x%x threshold= 0x%x\n", + config.cfg.no_motion.duration, + config.cfg.no_motion.threshold); + +} + +/** + * no_motion_config_store - sysfs write callback which writes the + * no-motion configuration in the sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t no_motion_config_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err = 0; + unsigned int data[2] = {0}; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + struct bmi2_sens_config config; + + err = sscanf(buf, "%11x %11x", &data[0], &data[1]); + if (err != 2) { + PERR("Invalid argument"); + return -EINVAL; + } + mutex_lock(&client_data->lock); + config.type = BMI2_NO_MOTION; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.no_motion.duration = (u16)data[0]; + config.cfg.no_motion.threshold = (u16)data[1]; + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + if (err) { + PERR("write failed"); + return err; + } + return count; +} + +/** + * no_motion_enable_axis_store - sysfs write callback which enable or + * disable the x,y and z axis of no-motion sensor. + * + * @dev: Device instance + * @attr: Instance of device attribute file + * @buf: Instance of the data buffer which serves as input. + * @count: Number of characters in the buffer `buf`. + * + * Return: Number of characters used from buffer `buf`, which equals count. + */ +static ssize_t no_motion_enable_axis_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int err = 0; + unsigned int data[3] = {0}; + struct bmi2_sens_config sens; + struct input_dev *input = to_input_dev(dev); + struct bmi2xy_client_data *client_data = input_get_drvdata(input); + + err = sscanf(buf, "%11x %11x %11x", &data[0], &data[1], &data[2]); + if (err != 3) { + PERR("Invalid argument"); + return -EINVAL; + } + /* Configure the axis for any/no-motion */ + mutex_lock(&client_data->lock); + + sens.type = BMI2_NO_MOTION; + err = bmi2_get_sensor_config(&sens, 1, &client_data->device); + sens.cfg.no_motion.select_x = data[0] & 0x01; + sens.cfg.no_motion.select_y = data[1] & 0x01; + sens.cfg.no_motion.select_z = data[2] & 0x01; + + err = bmi2_set_sensor_config(&sens, 1, &client_data->device); + if (err) { + PERR("write failed"); + mutex_unlock(&client_data->lock); + return err; + } + /* If user disabled all axis,then anymotion/no-motion is disabled + * For re-enabling anymotion/nomotion, config_function sysnode or + * any_no_motion_enable_axis(with atleast 1 axis enabled) can be used. + */ + if ((data[0] == 0) && (data[1] == 0) && (data[2] == 0)) + client_data->nomotion_enable = 0; + + mutex_unlock(&client_data->lock); + + return count; +} + +static DEVICE_ATTR_RO(chip_id); +static DEVICE_ATTR_RW(acc_enable); +static DEVICE_ATTR_RO(acc_value); +static DEVICE_ATTR_RW(acc_range); +static DEVICE_ATTR_RW(acc_odr); +static DEVICE_ATTR_RW(gyro_enable); +static DEVICE_ATTR_RO(gyro_value); +static DEVICE_ATTR_RW(gyro_range); +static DEVICE_ATTR_RW(gyro_odr); +static DEVICE_ATTR_RW(accel_selftest); +static DEVICE_ATTR_RO(avail_sensor); +static DEVICE_ATTR_RW(load_config_stream); +static DEVICE_ATTR_RW(aps_enable); +static DEVICE_ATTR_RW(reg_sel); +static DEVICE_ATTR_RW(reg_val); +static DEVICE_ATTR_RO(driver_version); +static DEVICE_ATTR_RW(accel_foc); +static DEVICE_ATTR_RO(gyro_foc); +static DEVICE_ATTR_WO(fifo_flush); +static DEVICE_ATTR_RO(fifo_data_frame); +static DEVICE_ATTR_RW(acc_fifo_enable); +static DEVICE_ATTR_RW(gyro_fifo_enable); +static DEVICE_ATTR_WO(soft_reset); +static DEVICE_ATTR_RW(accel_feat_selftest); +static DEVICE_ATTR_RW(feat_page_sel); +static DEVICE_ATTR_RW(feat_page_val); +static DEVICE_ATTR_RW(config_function); +static DEVICE_ATTR_RO(nvm_prog); +static DEVICE_ATTR_RO(gyro_self_test); +static DEVICE_ATTR_RW(step_buffer_size); +static DEVICE_ATTR_RW(gyro_offset_comp); +static DEVICE_ATTR_RW(any_motion_config); +static DEVICE_ATTR_WO(any_motion_enable_axis); +static DEVICE_ATTR_RO(step_counter_val); +static DEVICE_ATTR_RW(step_counter_watermark); +static DEVICE_ATTR_WO(step_counter_reset); +static DEVICE_ATTR_RO(gyr_usr_gain); +static DEVICE_ATTR_WO(execute_crt); +static DEVICE_ATTR_RW(no_motion_config); +static DEVICE_ATTR_WO(no_motion_enable_axis); + + +static struct attribute *bmi2xy_attributes[] = { + &dev_attr_chip_id.attr, + &dev_attr_acc_enable.attr, + &dev_attr_acc_value.attr, + &dev_attr_acc_range.attr, + &dev_attr_acc_odr.attr, + &dev_attr_acc_fifo_enable.attr, + &dev_attr_gyro_fifo_enable.attr, + &dev_attr_gyro_enable.attr, + &dev_attr_gyro_value.attr, + &dev_attr_gyro_range.attr, + &dev_attr_gyro_odr.attr, + &dev_attr_accel_selftest.attr, + &dev_attr_accel_feat_selftest.attr, + &dev_attr_avail_sensor.attr, + &dev_attr_driver_version.attr, + &dev_attr_load_config_stream.attr, + &dev_attr_aps_enable.attr, + &dev_attr_reg_sel.attr, + &dev_attr_reg_val.attr, + &dev_attr_fifo_flush.attr, + &dev_attr_fifo_data_frame.attr, + &dev_attr_accel_foc.attr, + &dev_attr_gyro_foc.attr, + &dev_attr_soft_reset.attr, + &dev_attr_feat_page_sel.attr, + &dev_attr_feat_page_val.attr, + &dev_attr_config_function.attr, + &dev_attr_nvm_prog.attr, + &dev_attr_gyro_self_test.attr, + &dev_attr_gyro_offset_comp.attr, + &dev_attr_step_counter_val.attr, + &dev_attr_step_counter_watermark.attr, + &dev_attr_step_counter_reset.attr, + &dev_attr_any_motion_config.attr, + &dev_attr_any_motion_enable_axis.attr, + &dev_attr_step_buffer_size.attr, + &dev_attr_gyr_usr_gain.attr, + &dev_attr_execute_crt.attr, + &dev_attr_no_motion_config.attr, + &dev_attr_no_motion_enable_axis.attr, + NULL +}; + +static struct attribute_group bmi2xy_attribute_group = { + .attrs = bmi2xy_attributes +}; + +#if defined(BMI2XY_ENABLE_INT1) || defined(BMI2XY_ENABLE_INT2) +/** + * bmi2xy_feat_function_handle - Reports the interrupt events to HAL. + * @client_data : Pointer to client data structure. + * @status : Interrupt status information. + */ +static void bmi2xy_feat_function_handle( + struct bmi2xy_client_data *client_data, u8 status) +{ + input_event(client_data->feat_input, EV_MSC, REL_FEAT_STATUS, + (u32)(status)); + PDEBUG("%x", (u32)(status)); + input_sync(client_data->feat_input); + PINFO("Interrupt occurred %x", (u32)status); +} + +/** + * bmi2xy_irq_work_func - Bottom half handler for feature interrupts. + * @work : Work data for the workqueue handler. + */ +static void bmi2xy_irq_work_func(struct work_struct *work) +{ + struct bmi2xy_client_data *client_data = container_of(work, + struct bmi2xy_client_data, irq_work); + unsigned char int_status[2] = {0, 0}; + int err = 0; + int in_suspend_copy; +#ifdef ANY_NO_MOTION_WORKAROUND + u8 feature = 0; +#endif + + in_suspend_copy = atomic_read(&client_data->in_suspend); + err = bmi2_get_regs(BMI2_INT_STATUS_0_ADDR, int_status, 2, + &client_data->device); + + if (err) { + PERR("Interrupt status read failed %d", err); + return; + } + PDEBUG("int_status0 = 0x%x int_status1 =0x%x", + int_status[0], int_status[1]); + if (in_suspend_copy && + ((int_status[0] & STEP_DET_OUT) == 0x02)) { + return; + } + + if (int_status[0]) { + mutex_lock(&client_data->lock); +#ifdef ANY_NO_MOTION_WORKAROUND + if ((int_status[0] & BMI2_ANY_MOT_INT_MASK) && + (client_data->anymotion_enable == 1)) { + feature = BMI2_ANY_MOTION; + err = bmi2_sensor_disable(&feature, 1, + &client_data->device); + if (err == 0) + client_data->anymotion_enable = 0; + } else { + int_status[0] &= ~BMI2_ANY_MOT_INT_MASK; + } + + if ((int_status[0] & BMI2_NO_MOT_INT_MASK) && + (client_data->nomotion_enable == 1)) { + feature = BMI2_NO_MOTION; + err = bmi2_sensor_disable(&feature, 1, + &client_data->device); + if (err == 0) + client_data->nomotion_enable = 0; + } else { + int_status[0] &= ~BMI2_NO_MOT_INT_MASK; + } +#endif + bmi2xy_feat_function_handle(client_data, (u8)int_status[0]); + mutex_unlock(&client_data->lock); + } +} + +/** + * bmi2xy_delay_sigmo_work_func - Bottom half handler for significant motion + * interrupt. + * @work : Work data for the workqueue handler. + */ +static void bmi2xy_delay_sigmo_work_func(struct work_struct *work) +{ + struct bmi2xy_client_data *client_data = container_of(work, + struct bmi2xy_client_data, delay_work_sig.work); + unsigned char int_status[2] = {0, 0}; + int err = 0; + + /* Read the interrupt status two register */ + err = bmi2_get_regs(BMI2_INT_STATUS_0_ADDR, int_status, 2, + &client_data->device); + if (err) + return; + PDEBUG("int_status0 = %x int_status1 =%x", + int_status[0], int_status[1]); + input_event(client_data->feat_input, EV_MSC, REL_FEAT_STATUS, + (u32)(SIG_MOTION_OUT)); + PDEBUG("%x", (u32)(SIG_MOTION_OUT)); + input_sync(client_data->feat_input); +} + +/** + * bmi2xy_irq_handle - IRQ handler function. + * @irq : Number of irq line. + * @handle : Instance of client data. + * + * Return : Status of IRQ function. + */ +static irqreturn_t bmi2xy_irq_handle(int irq, void *handle) +{ + struct bmi2xy_client_data *client_data = handle; + int in_suspend_copy; + int err; + + PERR("In IRQ handle"); + in_suspend_copy = atomic_read(&client_data->in_suspend); + /* For SIG_motion CTS test */ + if ((in_suspend_copy == 1) && + ((client_data->sigmotion_enable == 1) && + (client_data->tilt_enable != 1) && + (client_data->uphold_to_wake != 1) && + (client_data->glance_enable != 1) && + (client_data->wakeup_enable != 1))) { + wake_lock_timeout(&client_data->wakelock, HZ); + err = schedule_delayed_work(&client_data->delay_work_sig, + msecs_to_jiffies(50)); + } else if ((in_suspend_copy == 1) && + ((client_data->sigmotion_enable == 1) || + (client_data->tilt_enable == 1) || + (client_data->uphold_to_wake == 1) || + (client_data->glance_enable == 1) || + (client_data->wakeup_enable == 1))) { + wake_lock_timeout(&client_data->wakelock, HZ); + err = schedule_work(&client_data->irq_work); + } else + err = schedule_work(&client_data->irq_work); + + if (err) + PERR("Work will be scheduled later"); + + return IRQ_HANDLED; +} + +/** + * bmi2xy_request_irq - Allocates interrupt resources and enables the + * interrupt line and IRQ handling. + * + * @client_data: Instance of the client data. + * + * Return : Status of the function. + * * 0 - OK + * * Any Negative value - Error. + */ +static int bmi2xy_request_irq(struct bmi2xy_client_data *client_data) +{ + int err = 0; + + client_data->gpio_pin = of_get_named_gpio_flags( + client_data->dev->of_node, + "bmi2xy,gpio_irq", 0, NULL); + if (!gpio_is_valid(client_data->gpio_pin)) { + PERR("Invalid GPIO: %d\n", client_data->gpio_pin); + return -EINVAL; + } + err = gpio_request_one(client_data->gpio_pin, + GPIOF_IN, "bmi2xy_interrupt"); + if (err < 0) + return err; + err = gpio_direction_input(client_data->gpio_pin); + if (err < 0) + return err; + client_data->IRQ = gpio_to_irq(client_data->gpio_pin); + err = request_irq(client_data->IRQ, bmi2xy_irq_handle, + IRQF_TRIGGER_RISING, + SENSOR_NAME, client_data); + if (err < 0) + return err; + /* Lint -save -e69 */ + INIT_WORK(&client_data->irq_work, bmi2xy_irq_work_func); + INIT_DELAYED_WORK(&client_data->delay_work_sig, + bmi2xy_delay_sigmo_work_func); + /* Lint -restore */ + + return err; +} +#endif + +/** + * bmi2xy_acc_input_init - Register the accelerometer input device in the + * system. + * @client_data : Instance of client data. + * + * Return : Status of the function. + * * 0 - OK + * * Any Negative value - Error. + */ +static int bmi2xy_acc_input_init(struct bmi2xy_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = devm_input_allocate_device(&client_data->i2c->dev); + if (NULL == dev) + return -ENOMEM; + + dev->name = SENSOR_NAME_ACC; + dev->id.bustype = BUS_I2C; + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dev, ABS_Z, ABSMIN, ABSMAX, 0, 0); + input_set_drvdata(dev, client_data); + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + client_data->acc_input = dev; + return 0; +} + +/** + * bmi2xy_acc_input_destroy - Un-register the Accelerometer input device from + * the system. + * + * @client_data :Instance of client data. + */ +static void bmi2xy_acc_input_destroy(struct bmi2xy_client_data *client_data) +{ + struct input_dev *dev = client_data->acc_input; + + input_unregister_device(dev); +} + +//add by liangdi for MT672 20210112 +static int bmi2xy_gyro_input_init(struct bmi2xy_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = devm_input_allocate_device(&client_data->i2c->dev); + if (NULL == dev) + return -ENOMEM; + + dev->name = SENSOR_NAME_GYRO; + dev->id.bustype = BUS_I2C; + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_RX, GYRO_MAX_VALUE, GYRO_MIN_VALUE, 0, 0); + input_set_abs_params(dev, ABS_RY, GYRO_MAX_VALUE, GYRO_MIN_VALUE, 0, 0); + input_set_abs_params(dev, ABS_RZ, GYRO_MAX_VALUE, GYRO_MIN_VALUE, 0, 0); + input_set_drvdata(dev, client_data); + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + client_data->gyro_input = dev; + return 0; +} + +static void bmi2xy_gyro_input_destroy(struct bmi2xy_client_data *client_data) +{ + struct input_dev *dev = client_data->gyro_input; + + input_unregister_device(dev); +} +//add end + +/** + * bmi2xy_feat_input_init - Register the feature input device in the + * system. + * @client_data : Instance of client data. + * + * Return : Status of the function. + * * 0 - OK. + * * Any negative value - Error. + */ +static int bmi2xy_feat_input_init(struct bmi2xy_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + dev = input_allocate_device(); + if (dev == NULL) + return -ENOMEM; + dev->name = SENSOR_NAME_FEAT; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_MSC, REL_FEAT_STATUS); + input_set_drvdata(dev, client_data); + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + client_data->feat_input = dev; + return 0; +} + +/** + * bmi2xy_feat_input_destroy - Un-register the feature input device from the + * system. + * @client_data : Instance of client data. + */ +static void bmi2xy_feat_input_destroy( + struct bmi2xy_client_data *client_data) +{ + struct input_dev *dev = client_data->acc_input; + + input_unregister_device(dev); +} + +//add by liangdi for MT672 20210112 +static int bmi2xy_set_acc_op_mode(struct bmi2xy_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + u8 sens_list = BMI2_ACCEL; + + mutex_lock(&client_data->mutex_op_mode); + + if (op_mode == 0 && + (client_data->sigmotion_enable == 0) && + (client_data->stepdet_enable == 0) && + (client_data->stepcounter_enable == 0) && + (client_data->wakeup_enable == 0) && + (client_data->activity_enable == 0) && + (client_data->anymotion_enable == 0) && + (client_data->nomotion_enable == 0) && + (client_data->orientation_enable == 0) && + (client_data->tap_enable == 0)) { + err = bmi2_sensor_disable(&sens_list, 1, + &client_data->device); + pr_err("acc_disable\n"); + } else if (op_mode == 1) { + err = bmi2_sensor_enable(&sens_list, 1, &client_data->device); + pr_err("acc_enable\n"); + }else { + err = -EINVAL; + } + + if (err) { + PERR("failed"); + mutex_unlock(&client_data->mutex_op_mode); + return err; + } + + client_data->pw.acc_pm = op_mode; + + mutex_unlock(&client_data->mutex_op_mode); + return err; +} + +static int bmi2xy_set_gyro_op_mode(struct bmi2xy_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + u8 sens_list = BMI2_GYRO; + + mutex_lock(&client_data->mutex_op_mode); + if (op_mode == 0) { + err = bmi2_sensor_disable(&sens_list, 1, &client_data->device); + pr_err("gyro_disable\n"); + } else if (op_mode == 1) { + err = bmi2_sensor_enable(&sens_list, 1, &client_data->device); + pr_err("gyro_enable\n"); + } else { + err = -EINVAL; + } + + if (err) { + PERR("failed"); + mutex_unlock(&client_data->mutex_op_mode); + return err; + } + + client_data->pw.gyro_pm = op_mode; + + mutex_unlock(&client_data->mutex_op_mode); + return err; + +} + +static int bmi2xy_power_init(struct bmi2xy_client_data *data) +{ + int ret; + + data->vdd = regulator_get(&data->i2c->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + dev_err(&data->i2c->dev, + "Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + BMI220_VDD_MIN_UV, + BMI220_VDD_MAX_UV); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator set failed vdd ret=%d\n", + ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->i2c->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + dev_err(&data->i2c->dev, + "Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + BMI220_VIO_MIN_UV, + BMI220_VIO_MAX_UV); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, BMI220_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + +static int bmi2xy_power_deinit(struct bmi2xy_client_data *data) +{ + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, + 0, BMI220_VDD_MAX_UV); + + regulator_put(data->vdd); + + if (regulator_count_voltages(data->vio) > 0) + regulator_set_voltage(data->vio, + 0, BMI220_VIO_MAX_UV); + + regulator_put(data->vio); + + return 0; +} + +static int bmi2xy_power_ctl(struct bmi2xy_client_data *data, bool enable) +{ + int ret = 0; + int err = 0; + + if (!enable && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = enable; + pr_err("bmi2xy power off\n"); + } else if (enable && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_enable(data->vio); + if (ret) { + dev_err(&data->i2c->dev, + "Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + data->power_enabled = enable; + pr_err("bmi2xy power on\n"); + } else { + dev_info(&data->i2c->dev, + "Power on=%d. enabled=%d\n", + enable, data->power_enabled); + } + + return ret; +} + +static int bmi2xy_check_chip_id(struct bmi2xy_client_data *client_data) +{ + u8 chip_id[2] = {0}; + uint8_t read_count = 0; + int err; + /* read and check chip id */ + while (read_count++ < 5) { + + err = bmi2_get_regs(BMI2_CHIP_ID_ADDR, chip_id, + 2, &client_data->device); + if (err) { + pr_err("check chip id failed %d\n",err); + mdelay(1); + continue; + } + else + { + if(chip_id[0] == BMI220_CHIP_ID) + { + pr_err("BMI220 sensor detected\n"); + break; + } + else + { + pr_err("BMI229 chip id %d mismatch chip_id:%d\n", BMI220_CHIP_ID, chip_id[0]); + err = -ENODEV; + return err; + } + } + } + + return 0; +} + +static void bmi2xy_set_acc_enable(struct device *dev, unsigned int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bmi2xy_client_data *client_data = i2c_get_clientdata(client); + int acc_pre_enable = atomic_read(&client_data->acc_en); + int gyro_current_enable; + + pr_err("acc_enable enable=%d, pre_enable=%d\n",enable, acc_pre_enable); + + mutex_lock(&client_data->mutex_enable); + if (enable) { + if (acc_pre_enable == 0) { + if (!client_data->power_enabled) { + if (bmi2xy_power_ctl(client_data, true)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + + bmi2xy_set_acc_op_mode(client_data, 1); + schedule_delayed_work(&client_data->work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + atomic_set(&client_data->acc_en, 1); + } + } else { + if ((acc_pre_enable == 1) && client_data->power_enabled) { + bmi2xy_set_acc_op_mode(client_data, 0); + cancel_delayed_work_sync(&client_data->work); + atomic_set(&client_data->acc_en, 0); + gyro_current_enable = atomic_read(&client_data->gyro_en); + if (!gyro_current_enable) { + if (bmi2xy_power_ctl(client_data, false)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + } + } + +mutex_exit: + mutex_unlock(&client_data->mutex_enable); +} + +static void bmi2xy_set_gyro_enable(struct device *dev, unsigned int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bmi2xy_client_data *client_data = i2c_get_clientdata(client); + int gyro_pre_enable = atomic_read(&client_data->gyro_en); + int acc_current_enable; + + pr_err("gyro_enable enable=%d, pre_enable=%d\n",enable, gyro_pre_enable); + mutex_lock(&client_data->mutex_enable); + if (enable) { + if (gyro_pre_enable == 0) { + if (!client_data->power_enabled) { + if (bmi2xy_power_ctl(client_data, true)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + bmi2xy_set_gyro_op_mode(client_data, 1); + schedule_delayed_work(&client_data->gyro_work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + atomic_set(&client_data->gyro_en, 1); + } + } else { + if ((gyro_pre_enable == 1) && client_data->power_enabled) { + bmi2xy_set_gyro_op_mode(client_data, 0); + cancel_delayed_work_sync(&client_data->gyro_work); + atomic_set(&client_data->gyro_en, 0); + acc_current_enable = atomic_read(&client_data->acc_en); + if (!acc_current_enable) { + if (bmi2xy_power_ctl(client_data, false)) { + dev_err(dev, "power up sensor failed.\n"); + goto mutex_exit; + } + } + } + } + +mutex_exit: + mutex_unlock(&client_data->mutex_enable); +} + +static int bmi2xy_accel_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct bmi2xy_client_data *data = container_of(sensors_cdev, + struct bmi2xy_client_data, accel_cdev); + + if (delay_ms < 10) + delay_ms = 10; + if (delay_ms > 10) + delay_ms = 10; + atomic_set(&data->delay, (unsigned int) delay_ms); + return 0; +} + +static int bmi2xy_cdev_enable_accel(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmi2xy_client_data *client_data = container_of(sensors_cdev, + struct bmi2xy_client_data, accel_cdev); + bmi2xy_set_acc_enable(&client_data->i2c->dev, enable); + return 0; +} + +static int bmi2xy_gyro_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct bmi2xy_client_data *data = container_of(sensors_cdev, + struct bmi2xy_client_data, gyro_cdev); + + if (delay_ms < 10) + delay_ms = 10; + if (delay_ms > 10) + delay_ms = 10; + atomic_set(&data->delay, (unsigned int) delay_ms); + return 0; +} + + +static int bmi2xy_cdev_enable_gyro(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmi2xy_client_data *client_data = container_of(sensors_cdev, + struct bmi2xy_client_data, gyro_cdev); + bmi2xy_set_gyro_enable(&client_data->i2c->dev, enable); + return 0; +} + +static void bmi2xy_acc_work_func(struct work_struct *work) +{ + struct bmi2xy_client_data *client_data = + container_of((struct delayed_work *)work, + struct bmi2xy_client_data, work); + unsigned long delay = + msecs_to_jiffies(atomic_read(&client_data->delay)); + struct bmi2_sensor_data sensor_data; + int err; + + sensor_data.type = BMI2_ACCEL; + mutex_lock(&client_data->lock); + err = bmi2_get_sensor_data(&sensor_data, 1, &client_data->device); + mutex_unlock(&client_data->lock); + + if (err < 0) + return; + + sensor_data.sens_data.acc.x = -sensor_data.sens_data.acc.x; + sensor_data.sens_data.acc.y = -sensor_data.sens_data.acc.y; + + /*report current frame via input event*/ + input_event(client_data->acc_input, EV_ABS, ABS_X, sensor_data.sens_data.acc.x); + input_event(client_data->acc_input, EV_ABS, ABS_Y, sensor_data.sens_data.acc.y); + input_event(client_data->acc_input, EV_ABS, ABS_Z, sensor_data.sens_data.acc.z); + input_sync(client_data->acc_input); + + schedule_delayed_work(&client_data->work, delay); +} + +static void bmi2xy_gyro_work_func(struct work_struct *work) +{ + struct bmi2xy_client_data *client_data = container_of( + (struct delayed_work *)work, + struct bmi2xy_client_data, gyro_work); + unsigned long delay = + msecs_to_jiffies(atomic_read(&client_data->delay)); + struct bmi2_sensor_data sensor_data; + int err; + + sensor_data.type = BMI2_GYRO; + mutex_lock(&client_data->lock); + err = bmi2_get_sensor_data(&sensor_data, 1, &client_data->device); + mutex_unlock(&client_data->lock); + + if (err < 0) + return; + + sensor_data.sens_data.gyr.y = -sensor_data.sens_data.gyr.y; + + /*report current frame via input event*/ + input_event(client_data->gyro_input, EV_ABS, ABS_RX, sensor_data.sens_data.gyr.x); + input_event(client_data->gyro_input, EV_ABS, ABS_RY, sensor_data.sens_data.gyr.y); + input_event(client_data->gyro_input, EV_ABS, ABS_RZ, sensor_data.sens_data.gyr.z); + input_sync(client_data->gyro_input); + + schedule_delayed_work(&client_data->gyro_work, delay); +} +//add end + +int bmi2xy_probe(struct bmi2xy_client_data *client_data, struct device *dev) +{ + int err = 0; + struct bmi2_sens_config config; + + pr_err("bmi2xy_probe \n"); + + dev_set_drvdata(dev, client_data); + + client_data->dev = dev; + client_data->device.delay_us = bmi2xy_i2c_delay_us; + + //add by liangdi for MT672 20210112 + err = bmi2xy_power_init(client_data); + if (err) { + dev_err(&client_data->i2c->dev, + "Failed to get sensor regulators\n"); + err = -EINVAL; + goto exit_err_clean; + } + err = bmi2xy_power_ctl(client_data, true); + if (err) { + dev_err(&client_data->i2c->dev, + "Failed to enable sensor power\n"); + err = -EINVAL; + goto deinit_power_exit; + } + + /* check chip id */ + err = bmi2xy_check_chip_id(client_data); + if (err) + goto disable_power_exit; + //add end + + mutex_init(&client_data->lock); + mutex_init(&client_data->mutex_enable); + mutex_init(&client_data->mutex_op_mode); + + /* Accel input device init */ + err = bmi2xy_acc_input_init(client_data); + if (err < 0) + goto exit_err_clean; + + /* Accel input device init */ + err = bmi2xy_gyro_input_init(client_data); + if (err < 0) + goto exit_err_clean; + + /* Sysfs node creation */ + err = sysfs_create_group(&client_data->acc_input->dev.kobj, + &bmi2xy_attribute_group); + if (err < 0) + goto exit_err_clean; + err = bmi2xy_feat_input_init(client_data); + if (err < 0) + goto exit_err_clean; + bmi2xy_i2c_delay_us(MS_TO_US(10)); + client_data->tap_type = 0; + + //add by liangdi for MT672 20210112 + /*to do*/ + client_data->accel_cdev = accel_cdev; + client_data->accel_cdev.sensors_enable = bmi2xy_cdev_enable_accel; + client_data->accel_cdev.sensors_poll_delay = bmi2xy_accel_poll_delay; + //client_data->accel_cdev.sensors_calibrate = bmi2xy_self_calibration_xyz; + err = sensors_classdev_register(&client_data->acc_input->dev, + &client_data->accel_cdev); + if (err) { + dev_err(&client_data->i2c->dev, "sensors class register failed.\n"); + return err; + } + + client_data->gyro_cdev = gyro_cdev; + client_data->gyro_cdev.sensors_enable = bmi2xy_cdev_enable_gyro; + client_data->gyro_cdev.sensors_poll_delay = bmi2xy_gyro_poll_delay; + err = sensors_classdev_register(&client_data->gyro_input->dev, + &client_data->gyro_cdev); + if (err) { + dev_err(&client_data->i2c->dev, "sensors class register failed.\n"); + return err; + } + + /* workqueue init */ + INIT_DELAYED_WORK(&client_data->work, bmi2xy_acc_work_func); + INIT_DELAYED_WORK(&client_data->gyro_work, bmi2xy_gyro_work_func); + atomic_set(&client_data->delay, BMI_DELAY_DEFAULT); + atomic_set(&client_data->acc_en, 0); + atomic_set(&client_data->gyro_en, 0); + //add end + /* Request irq and config*/ + #if defined(BMI2XY_ENABLE_INT1) || defined(BMI2XY_ENABLE_INT2) + err = bmi2xy_request_irq(client_data); + if (err < 0) { + PERR("Request irq failed"); + goto exit_err_clean; + } + #endif + wake_lock_init(&client_data->wakelock, WAKE_LOCK_SUSPEND, "bmi2xy"); + + #ifdef BMI2XY_LOAD_CONFIG_FILE_IN_INIT + err = bmi2xy_update_config_stream(client_data, 3); + if (!err) { + PINFO("Bosch Sensortec Device %s detected", SENSOR_NAME); + } else { + PERR("Bosch Sensortec Device not found"); + goto exit_err_clean; + } + + client_data->config_file_loaded = 1; + #endif + /* Set the self test status */ + client_data->accel_selftest = SELF_TEST_NOT_RUN; + client_data->gyro_selftest = SELF_TEST_NOT_RUN; + + //add by liangdi for MT672 20210112 + //config same to BMI120 + mutex_lock(&client_data->lock); + config.type = BMI2_ACCEL; + err = bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.acc.range = 0;//range 2G + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + + config.type = BMI2_GYRO; + err += bmi2_get_sensor_config(&config, 1, &client_data->device); + config.cfg.gyr.odr = 8;//100 HZ + client_data->gyro_odr = config.cfg.gyr.odr; + err += bmi2_set_sensor_config(&config, 1, &client_data->device); + mutex_unlock(&client_data->lock); + + if (err) { + PERR("failed"); + goto disable_power_exit; + } + + //power off bmi220 for save power + //bmi2xy_power_ctl(client_data, false); + //add end + + pr_err("sensor %s probed successfully", SENSOR_NAME); + return 0; + +disable_power_exit: + bmi2xy_power_ctl(client_data, false); +deinit_power_exit: + bmi2xy_power_deinit(client_data); + +exit_err_clean: + if (err) { + if (client_data != NULL) + kfree(client_data); + return err; + } + return err; +} + +/** + * bmi2xy_suspend - This function puts the driver and device to suspend mode. + * @dev : Instance of the device. + * + * Return : Status of the suspend function. + * * 0 - OK. + * * Negative value : Error. + */ +int bmi2xy_suspend(struct device *dev) +{ + int err = 0; + struct bmi2xy_client_data *client_data = dev_get_drvdata(dev); + + pr_err("bmi2xy_suspend ++"); + if (atomic_read(&client_data->acc_en) == 1) { + bmi2xy_set_acc_op_mode(client_data, 0); + cancel_delayed_work_sync(&client_data->work); + } + + if (atomic_read(&client_data->gyro_en) == 1) { + bmi2xy_set_gyro_op_mode(client_data, 0); + cancel_delayed_work_sync(&client_data->gyro_work); + } + + err = enable_irq_wake(client_data->IRQ); + atomic_set(&client_data->in_suspend, 1); +/* + if (atomic_read(&client_data->acc_en) == 1 || atomic_read(&client_data->gyro_en) == 1) + { + //power off bmi220 for save power + bmi2xy_power_ctl(client_data, false); + } +*/ + pr_err("bmi2xy_suspend --"); + return err; +} +/* Lint -save -e19 */ +EXPORT_SYMBOL(bmi2xy_suspend); +/* Lint -restore */ + +/** + * bmi2xy_resume - This function is used to bring back device from suspend mode + * @dev : Instance of the device. + * + * Return : Status of the suspend function. + * * 0 - OK. + * * Negative value : Error. + */ +int bmi2xy_resume(struct device *dev) +{ + int err = 0; + struct bmi2xy_client_data *client_data = dev_get_drvdata(dev); + + pr_err("bmi2xy_resume ++"); +/* + if (atomic_read(&client_data->acc_en) == 1 || atomic_read(&client_data->gyro_en) == 1) + { + //power on bmi220 + bmi2xy_power_ctl(client_data, true); + } +*/ + if (atomic_read(&client_data->acc_en) == 1) { + bmi2xy_set_acc_op_mode(client_data, 1); + schedule_delayed_work(&client_data->work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + } + + if (atomic_read(&client_data->gyro_en) == 1) { + bmi2xy_set_gyro_op_mode(client_data, 1); + schedule_delayed_work(&client_data->gyro_work, + msecs_to_jiffies(atomic_read(&client_data->delay))); + } + + err = disable_irq_wake(client_data->IRQ); + atomic_set(&client_data->in_suspend, 0); + + pr_err("bmi2xy_resume --"); + return err; +} +/* Lint -save -e19 */ +EXPORT_SYMBOL(bmi2xy_resume); +/* Lint -restore */ + +/** + * bmi2xy_remove - This function removes the driver from the device. + * @dev : Instance of the device. + * + * Return : Status of the suspend function. + * * 0 - OK. + * * Negative value : Error. + */ +int bmi2xy_remove(struct device *dev) +{ + int err = 0; + struct bmi2xy_client_data *client_data = dev_get_drvdata(dev); + + if (client_data != NULL) { + bmi2xy_i2c_delay_us(MS_TO_US(BMI2XY_I2C_WRITE_DELAY_TIME)); + sysfs_remove_group(&client_data->acc_input->dev.kobj, + &bmi2xy_attribute_group); + bmi2xy_acc_input_destroy(client_data); + bmi2xy_gyro_input_destroy(client_data); + bmi2xy_feat_input_destroy(client_data); + wake_unlock(&client_data->wakelock); + wake_lock_destroy(&client_data->wakelock); + kfree(client_data); + } + return err; +} +/* Lint -save -e19 */ +EXPORT_SYMBOL(bmi2xy_remove); +/* Lint -restore */ diff --git a/drivers/input/misc/bmi220/bmi2xy_driver.h b/drivers/input/misc/bmi220/bmi2xy_driver.h new file mode 100755 index 00000000000..1e7ab970c74 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi2xy_driver.h @@ -0,0 +1,288 @@ +/** + * @section LICENSE + * (C) Copyright 2011~2018 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bmi2xy_driver.h + * @date 28/01/2020 + * @version 1.34.0 + * + * @brief BMI2xy Linux Driver + */ + +#ifndef BMI2XY_DRIVER_H +#define BMI2XY_DRIVER_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*********************************************************************/ +/* System header files */ +/*********************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*********************************************************************/ +/* Own header files */ +/*********************************************************************/ +/* BMI2xy variants. Only one should be enabled */ +#include "bmi220.h" +#pragma message("building for bmi220") + +/*********************************************************************/ +/* Macro definitions */ +/*********************************************************************/ +/** Name of the device driver and accel input device*/ +#define SENSOR_NAME "bmi2xy" +/** Name of the feature input device*/ +#define SENSOR_NAME_FEAT "bmi2xy_feat" +/** Name of the gyro input device*/ +#define SENSOR_NAME_ACC "bmi2xy-accel" +/** Name of the gyro input device*/ +#define SENSOR_NAME_GYRO "bmi2xy-gyro" + + +/* Generic */ +#define ANY_NO_MOTION_WORKAROUND (1) +#define BMI2XY_ENABLE_INT1 (0) +#define BMI2XY_MAX_RETRY_I2C_XFER (10) +#define BMI2XY_I2C_WRITE_DELAY_TIME (1) +#define REL_FEAT_STATUS (1) +#define REL_HW_STATUS (2) + +/*fifo definition*/ +#define A_BYTES_FRM (6) +#define G_BYTES_FRM (6) +#define M_BYTES_FRM (8) +#define MA_BYTES_FRM (14) +#define MG_BYTES_FRM (14) +#define AG_BYTES_FRM (12) +#define AMG_BYTES_FRM (20) +#define FIFO_ACC_EN_MSK (0x40) +#define FIFO_GYRO_EN_MSK (0x80) +#define FIFO_MAG_EN_MSK (0x20) +#define BMI2_ANY_MOT_INT_MASK (0x40) +#define BMI2_NO_MOT_INT_MASK (0x20) + +/** + * enum bmi2xy_config_func - Enumerations to select the sensors + */ +enum bmi2xy_config_func { + BMI2XY_SIG_MOTION_SENSOR = 0, + BMI2XY_STEP_DETECTOR_SENSOR = 1, + BMI2XY_STEP_COUNTER_SENSOR = 2, + BMI2XY_TILT_SENSOR = 3, + BMI2XY_PICKUP_SENSOR = 4, + BMI2XY_GLANCE_DETECTOR_SENSOR = 5, + BMI2XY_WAKEUP_SENSOR = 6, + BMI2XY_ANY_MOTION_SENSOR = 7, + BMI2XY_ORIENTATION_SENSOR = 8, + BMI2XY_FLAT_SENSOR = 9, + BMI2XY_HIGH_G_SENSOR = 10, + BMI2XY_LOW_G_SENSOR = 11, + BMI2XY_ACTIVITY_SENSOR = 12, + BMI2XY_NO_MOTION_SENSOR = 13, + BMI2XY_S4S = 14 +}; + +/** + * enum bmi2xy_int_status0 - Enumerations corresponding to status0 registers + */ +enum bmi2xy_int_status0 { + SIG_MOTION_OUT = 0x01, + STEP_DET_OUT = 0x02, + TILT_OUT = 0x04, + PICKUP_OUT = 0x08, + GLANCE_OUT = 0x10, + WAKEUP_OUT = 0x20, + ANY_NO_MOTION_OUT = 0x40, + ORIENTATION_OUT = 0x80 +}; + +/** + * enum bmi2xy_int_status1 - Enumerations corresponding to status1 registers + */ +enum bmi2xy_int_status1 { + FIFOFULL_OUT = 0x01, + FIFOWATERMARK_OUT = 0x02, + MAG_DRDY_OUT = 0x20, + ACC_DRDY_OUT = 0x80 +}; + +/** + * enum bmi2xy_self_test_rslt - Enumerations for Self-test feature + */ +enum bmi2xy_self_test_rslt { + SELF_TEST_PASS, + SELF_TEST_FAIL, + SELF_TEST_NOT_RUN +}; + +/** + * struct pw_mode - Structure for sensor power modes. + */ +struct pw_mode { + u8 acc_pm; + u8 mag_pm; + u8 gyro_pm; +}; + +#define BMI_DELAY_MIN (1) +#define BMI_DELAY_DEFAULT (200) + +/** + * struct bmi2xy_client_data - Client structure which holds sensor-specific + * information. + */ +struct bmi2xy_client_data { + struct bmi2_dev device; + struct i2c_client *i2c; + struct device *dev; + struct input_dev *acc_input; + struct input_dev *gyro_input; + struct input_dev *feat_input; + struct sensors_classdev accel_cdev; + struct sensors_classdev gyro_cdev; + struct regulator *vdd; + struct regulator *vio; + struct delayed_work work; + struct delayed_work gyro_work; + + u8 config_file_loaded; +#ifdef FIFO_LOGGING + struct workqueue_struct *fifo_workqueue; + char *fifo_data_buf; + u16 fifo_data_len; + struct work_struct work; + struct hrtimer timer; + ktime_t ktime; + u8 timer_running; +#endif + u8 fifo_mag_enable; + u8 fifo_gyro_enable; + u8 fifo_acc_enable; + u32 fifo_bytecount; + struct pw_mode pw; + u8 acc_odr; + u8 gyro_odr; + u8 mag_odr; + u8 mag_chip_id; + struct mutex lock; + //add by liangdi for MT672 20210112 + struct mutex mutex_op_mode; + struct mutex mutex_enable; + atomic_t acc_en; /*TO DO acc gyro mag*/ + atomic_t gyro_en; + atomic_t delay; + atomic_t selftest_result; + bool power_enabled; + //add end + + unsigned int IRQ; + u8 gpio_pin; + struct work_struct irq_work; + u16 fw_version; + char *config_stream_name; + unsigned int reg_sel; + unsigned int reg_len; + unsigned int feat_page_sel; + unsigned int feat_page_len; + struct wake_lock wakelock; + struct delayed_work delay_work_sig; + atomic_t in_suspend; + u8 tap_type; + u8 accel_selftest; + u8 gyro_selftest; + u8 sigmotion_enable; + u8 stepdet_enable; + u8 stepcounter_enable; + u8 tilt_enable; + u8 uphold_to_wake; + u8 glance_enable; + u8 wakeup_enable; + u8 anymotion_enable; + u8 nomotion_enable; + u8 orientation_enable; + u8 flat_enable; + u8 tap_enable; + u8 highg_enable; + u8 s4s_enable; + u8 high_g_out; + u8 lowg_enable; + u8 activity_enable; + u8 err_int_trigger_num; + u8 orientation_output; + u8 activity_output; + u32 step_counter_val; + u32 step_counter_temp; +}; + +/*********************************************************************/ +/* Function prototype declarations */ +/*********************************************************************/ + +/** + * bmi2xy_probe - This is the probe function for bmi2xy sensor. + * Called from the I2C driver probe function to initialize the sensor. + * + * @client_data : Structure instance of client data. + * @dev : Structure instance of device. + * + * Return : Result of execution status + * * 0 - Success + * * negative value -> Error + */ +int bmi2xy_probe(struct bmi2xy_client_data *client_data, struct device *dev); + +/** + * bmi2xy_suspend - This function puts the driver and device to suspend mode. + * + * @dev : Structure instance of device. + * + * Return : Result of execution status + * * 0 - Success + * * negative value -> Error + */ +int bmi2xy_suspend(struct device *dev); + +/** + * bmi2xy_resume - This function is used to bring back device from suspend mode. + * + * @dev : Structure instance of device. + * + * Return : Result of execution status + * * 0 - Success + * * negative value -> Error + */ +int bmi2xy_resume(struct device *dev); + +/** + * bmi2xy_remove - This function removes the driver from the device. + * + * @dev : Structure instance of device. + * + * Return : Result of execution status + * * 0 - Success + * * negative value -> Error + */ +int bmi2xy_remove(struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* BMI2XY_DRIVER_H_ */ diff --git a/drivers/input/misc/bmi220/bmi2xy_i2c.c b/drivers/input/misc/bmi220/bmi2xy_i2c.c new file mode 100755 index 00000000000..651cd718b62 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi2xy_i2c.c @@ -0,0 +1,332 @@ +/** + * @section LICENSE + * (C) Copyright 2018~2019 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bmi2xy_i2c.c + * @date 2019/12/26 + * @version 1.0.1 + * + * @brief BMI2xy I2C bus Driver + */ + +/*********************************************************************/ +/* system header files */ +/*********************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +/*********************************************************************/ +/* own header files */ +/*********************************************************************/ +#include "bmi2xy_driver.h" +#include "bs_log.h" + +/*********************************************************************/ +/* global variables */ +/*********************************************************************/ +static struct i2c_client *bmi2xy_i2c_client; + +/** + * bmi2xy_i2c_read - The I2C read function. + * + * @client : Instance of the I2C client + * @reg_addr : The register address from where the data is read. + * @data : The pointer to buffer to return data. + * @len : The number of bytes to be read + * + * Return : Status of the function. + * * 0 - OK + * * negative value - Error. + */ +static s8 bmi2xy_i2c_read(struct i2c_client *client, + u8 reg_addr, u8 *data, u16 len) +{ + s32 retry; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + for (retry = 0; retry < BMI2XY_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)) > 0) + break; + usleep_range(BMI2XY_I2C_WRITE_DELAY_TIME * 1000, + BMI2XY_I2C_WRITE_DELAY_TIME * 1000); + } + + if (retry >= BMI2XY_MAX_RETRY_I2C_XFER) { + pr_err("I2C xfer error\n"); + return -EIO; + } + + return 0; +} + +/** + * bmi2xy_i2c_read - The I2C write function. + * + * @client : Instance of the I2C client + * @reg_addr : The register address to start writing the data. + * @data : The pointer to buffer holding data to be written. + * @len : The number of bytes to write. + * + * Return : Status of the function. + * * 0 - OK + * * negative value - Error. + */ +static s8 bmi2xy_i2c_write(struct i2c_client *client, + u8 reg_addr, const u8 *data, u16 len) +{ + s32 retry; + + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .len = len + 1, + .buf = NULL, + }; + msg.buf = kmalloc(len + 1, GFP_KERNEL); + if (!msg.buf) { + PERR("Allocate memory failed\n"); + return -ENOMEM; + } + msg.buf[0] = reg_addr; + memcpy(&msg.buf[1], data, len); + for (retry = 0; retry < BMI2XY_MAX_RETRY_I2C_XFER; retry++) { + if (i2c_transfer(client->adapter, &msg, 1) > 0) + break; + usleep_range(BMI2XY_I2C_WRITE_DELAY_TIME * 1000, + BMI2XY_I2C_WRITE_DELAY_TIME * 1000); + } + kfree(msg.buf); + if (retry >= BMI2XY_MAX_RETRY_I2C_XFER) { + PERR("I2C xfer error"); + return -EIO; + } + + return 0; +} + +/** + * bmi2xy_i2c_read_wrapper - The I2C read function pointer used by BMI2xy API. + * + * @dev_addr : I2c Device address + * @reg_addr : The register address to read the data. + * @data : The pointer to buffer to return data. + * @len : The number of bytes to be read + * + * Return : Status of the function. + * * 0 - OK + * * negative value - Error. + */ +static s8 bmi2xy_i2c_read_wrapper(u8 dev_addr, + u8 reg_addr, u8 *data, u16 len) +{ + s8 err; + + err = bmi2xy_i2c_read(bmi2xy_i2c_client, reg_addr, data, len); + return err; +} + +/** + * bmi2xy_i2c_write_wrapper - The I2C write function pointer used by BMI2xy API. + * + * @dev_addr : I2c Device address + * @reg_addr : The register address to start writing the data. + * @data : The pointer to buffer which holds the data to be written. + * @len : The number of bytes to be written. + * + * Return : Status of the function. + * * 0 - OK + * * negative value - Error. + */ +static s8 bmi2xy_i2c_write_wrapper(u8 dev_addr, + u8 reg_addr, const u8 *data, u16 len) +{ + s8 err; + + err = bmi2xy_i2c_write(bmi2xy_i2c_client, reg_addr, data, len); + return err; +} + +/** + * bmi2xy_i2c_probe - The I2C probe function called by I2C bus driver. + * + * @client : The I2C client instance + * @id : The I2C device ID instance + * + * Return : Status of the function. + * * 0 - OK + * * negative value - Error. + */ +int bmi2xy_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct bmi2xy_client_data *client_data = NULL; + + //PDEBUG("entrance"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + err = dev_err(&client->dev, "i2c_check_functionality error!"); + PERR("I2C adapter is not supported"); + err = -EIO; + goto exit_err_clean; + } + + if (bmi2xy_i2c_client == NULL) { + bmi2xy_i2c_client = client; + } else { + PERR("this driver does not support multiple clients"); + err = -EBUSY; + goto exit_err_clean; + } + + client_data = kzalloc(sizeof(struct bmi2xy_client_data), + GFP_KERNEL); + if (client_data == NULL) { + PERR("no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + /* h/w init */ + client_data->i2c = client; + client_data->device.read_write_len = 256;//4; + client_data->device.intf = BMI2_I2C_INTERFACE; + client_data->device.read = bmi2xy_i2c_read_wrapper; + client_data->device.write = bmi2xy_i2c_write_wrapper; + return bmi2xy_probe(client_data, &client->dev); + +exit_err_clean: + if (err) + bmi2xy_i2c_client = NULL; + return err; +} + +EXPORT_SYMBOL(bmi2xy_i2c_probe); + +/** + * bmi2xy_i2c_suspend - Callback called when device enter low power state. + * @client : Instance of I2C client device. + * @mesg : Event code passed when device is moved to suspend state. + * + * Return : Status of the suspend function. + * * 0 - OK. + * * Negative value - Error. + */ +int bmi2xy_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int err = 0; + + err = bmi2xy_suspend(&client->dev); + return err; +} +EXPORT_SYMBOL(bmi2xy_i2c_suspend); + +/** + * bmi2xy_i2c_resume - Callback called when device leaves the low power state. + * @client : Instance of I2C client device. + * + * Return : Status of the suspend function. + * * 0 - OK. + * * Negative value - Error. + */ +int bmi2xy_i2c_resume(struct i2c_client *client) +{ + int err = 0; + + err = bmi2xy_resume(&client->dev); + return err; +} +EXPORT_SYMBOL(bmi2xy_i2c_resume); + +/** + * bmi2xy_i2c_remove - Callback called when device is unbinded. + * @client : Instance of I2C client device. + * + * Return : Status of the suspend function. + * * 0 - OK. + * * Negative value - Error. + */ +int bmi2xy_i2c_remove(struct i2c_client *client) +{ + int err = 0; + + err = bmi2xy_remove(&client->dev); + bmi2xy_i2c_client = NULL; + return err; +} +EXPORT_SYMBOL(bmi2xy_i2c_remove); + +static const struct i2c_device_id bmi2xy_id[] = { + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, bmi2xy_id); +static const struct of_device_id bmi2xy_of_match[] = { + { .compatible = "bmi2xy", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bmi2xy_of_match); + +static struct i2c_driver bmi2xy_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = bmi2xy_of_match, + }, + .class = I2C_CLASS_HWMON, + .id_table = bmi2xy_id, + .probe = bmi2xy_i2c_probe, + .remove = bmi2xy_i2c_remove, + .suspend = bmi2xy_i2c_suspend, + .resume = bmi2xy_i2c_resume, +}; + +/** + * BMI2XY_init - I2C driver init function. + * + * Return : Status of the suspend function. + * * 0 - OK. + * * Negative value - Error. + */ +static int __init BMI2XY_init(void) +{ + //PERR("BMI2XY_init"); + return i2c_add_driver(&bmi2xy_driver); +} + +/** + * BMI2XY_exit - I2C driver exit function. + */ +static void __exit BMI2XY_exit(void) +{ + i2c_del_driver(&bmi2xy_driver); +} + +MODULE_AUTHOR("contact@bosch-sensortec.com>"); +MODULE_DESCRIPTION("BMI2XY SENSOR DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(BMI2XY_init); +module_exit(BMI2XY_exit); diff --git a/drivers/input/misc/bmi220/bmi2xy_spi.c b/drivers/input/misc/bmi220/bmi2xy_spi.c new file mode 100755 index 00000000000..764292edc58 --- /dev/null +++ b/drivers/input/misc/bmi220/bmi2xy_spi.c @@ -0,0 +1,204 @@ +/*! + * @section LICENSE + * $license_gpl$ + * + * @filename $filename$ + * @date 2017/06/20 13:44 + * @id $id$ + * @version 1.0.0.0 + * + * @brief bmi2xy SPI bus Driver + */ + +#include +#include +#include + +#include "bmi2xy_driver.h" +#include "bs_log.h" + +#define BMI2XY_MAX_BUFFER_SIZE 32 + +static struct spi_device *bmi2xy_spi_client; + +static s8 bmi2xy_spi_write_block(uint8_t dev_addr, + uint8_t reg_addr, uint8_t *data, uint8_t len) +{ + struct spi_device *client = bmi2xy_spi_client; + uint8_t buffer[BMI2XY_MAX_BUFFER_SIZE + 1]; + struct spi_transfer xfer = { + .tx_buf = buffer, + .len = len + 1, + }; + struct spi_message msg; + + if (len > BMI2XY_MAX_BUFFER_SIZE) + return -EINVAL; + + buffer[0] = reg_addr&0x7F;/* write: MSB = 0 */ + memcpy(&buffer[1], data, len); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + return spi_sync(client, &msg); +} + +static s8 bmi2xy_spi_read_block(uint8_t dev_addr, + uint8_t reg_addr, uint8_t *data, uint16_t len) +{ + struct spi_device *client = bmi2xy_spi_client; + u8 reg = reg_addr | 0x80;/* read: MSB = 1 */ + struct spi_transfer xfer[2] = { + [0] = { + .tx_buf = ®, + .len = 1, + }, + [1] = { + .rx_buf = data, + .len = len, + } + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer[0], &msg); + spi_message_add_tail(&xfer[1], &msg); + return spi_sync(client, &msg); +} + +int bmi2xy_spi_write_config_stream(uint8_t dev_addr, + uint8_t reg_addr, const uint8_t *data, uint8_t len) +{ + struct spi_device *client = bmi2xy_spi_client; + uint8_t buffer[BMI2XY_MAX_BUFFER_SIZE + 1]; + struct spi_transfer xfer = { + .tx_buf = buffer, + .len = len + 1, + }; + struct spi_message msg; + + if (len > BMI2XY_MAX_BUFFER_SIZE) + return -EINVAL; + + buffer[0] = reg_addr&0x7F;/* write: MSB = 0 */ + memcpy(&buffer[1], data, len); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + return spi_sync(client, &msg); +} + +int bmi2xy_write_config_stream(uint8_t dev_addr, + uint8_t reg_addr, const uint8_t *data, uint8_t len) +{ + int err; + + err = bmi2xy_spi_write_config_stream(dev_addr, reg_addr, data, len); + return err; +} + +static int bmi2xy_spi_probe(struct spi_device *client) +{ + int status; + int err = 0; + struct bmi2xy_client_data *client_data = NULL; + + if (NULL == bmi2xy_spi_client) + bmi2xy_spi_client = client; + else{ + PERR("This driver does not support multiple clients!\n"); + return -EBUSY; + } + client->bits_per_word = 8; + status = spi_setup(client); + if (status < 0) { + PERR("spi_setup failed!\n"); + return status; + } + client_data = kzalloc(sizeof(struct bmi2xy_client_data), GFP_KERNEL); + if (NULL == client_data) { + PERR("no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + client_data->device.bus_read = bmi2xy_spi_read_block; + client_data->device.bus_write = bmi2xy_spi_write_block; + + return bmi2xy_probe(client_data, &client->dev); + +exit_err_clean: + if (err) + bmi2xy_spi_client = NULL; + return err; +} + +static int bmi2xy_spi_remove(struct spi_device *client) +{ + int err = 0; + + err = bmi2xy_remove(&client->dev); + bmi2xy_spi_client = NULL; + return err; +} + +static int bmi2xy_spi_suspend(struct spi_device *client, pm_message_t mesg) +{ + int err = 0; + + err = bmi2xy_suspend(&client->dev); + return err; +} + +static int bmi2xy_spi_resume(struct spi_device *client) +{ + int err = 0; + + err = bmi2xy_resume(&client->dev); + return err; +} + +static const struct spi_device_id bmi2xy_id[] = { + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(spi, bmi2xy_id); +static const struct of_device_id bmi2xy_of_match[] = { + { .compatible = "bmi2xy", }, + { } +}; + +MODULE_DEVICE_TABLE(spi, bmi2xy_of_match); + +static struct spi_driver bmi_spi_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = bmi2xy_of_match, + }, + .id_table = bmi2xy_id, + .probe = bmi2xy_spi_probe, + .remove = bmi2xy_spi_remove, + .suspend = bmi2xy_spi_suspend, + .resume = bmi2xy_spi_resume, +}; + +static int __init bmi_spi_init(void) +{ + return spi_register_driver(&bmi_spi_driver); +} + +static void __exit bmi_spi_exit(void) +{ + spi_unregister_driver(&bmi_spi_driver); +} + + +MODULE_AUTHOR("Contact "); +MODULE_DESCRIPTION("BMI2XY SPI DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(bmi_spi_init); +module_exit(bmi_spi_exit); + diff --git a/drivers/input/misc/bmi220/bs_log.c b/drivers/input/misc/bmi220/bs_log.c new file mode 100755 index 00000000000..07b0546e435 --- /dev/null +++ b/drivers/input/misc/bmi220/bs_log.c @@ -0,0 +1,51 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2018 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bs_log.c + * @date "Wed Sep 24 15:27:12 2014 +0800" + * @id "e416c14" + * + * @brief + * The source file of BOSCH SENSOR LOG +*/ + + + +#ifdef __KERNEL__ +#include +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include + +#ifdef BOSCH_DRIVER_LOG_FUNC +#define BSLOG_VAR_DEF +#include "bs_log.h" + +void set_debug_log_level(uint8_t level) +{ + debug_log_level = level; +} + +uint8_t get_debug_log_level(void) +{ + return debug_log_level; +} + +EXPORT_SYMBOL(set_debug_log_level); +EXPORT_SYMBOL(get_debug_log_level); + +#endif/*BOSCH_DRIVER_LOG_FUNC*/ +/*@}*/ diff --git a/drivers/input/misc/bmi220/bs_log.h b/drivers/input/misc/bmi220/bs_log.h new file mode 100755 index 00000000000..5be1868cc0c --- /dev/null +++ b/drivers/input/misc/bmi220/bs_log.h @@ -0,0 +1,169 @@ +/*! + * @section LICENSE + * (C) Copyright 2011~2018 Bosch Sensortec GmbH All Rights Reserved + * + * This software program is licensed subject to the GNU General + * Public License (GPL).Version 2,June 1991, + * available at http://www.fsf.org/copyleft/gpl.html + * + * @filename bs_log.h + * @date "Sat Oct 11 16:12:16 2014 +0800" + * @id "762cc9e" + * + * @brief + * The head file of BOSCH SENSOR LOG +*/ + + +#ifndef __BS_LOG_H +#define __BS_LOG_H + +#include +/*! @ trace functions + @{*/ +/*! ERROR LOG LEVEL */ +#define LOG_LEVEL_E 3 +/*! NOTICE LOG LEVEL */ +#define LOG_LEVEL_N 5 +/*! INFORMATION LOG LEVEL */ +#define LOG_LEVEL_I 6 +/*! DEBUG LOG LEVEL */ +#define LOG_LEVEL_D 7 +/*! DEBUG_FWDL LOG LEVEL */ +#define LOG_LEVEL_DF 10 +/*! DEBUG_DATA LOG LEVEL */ +#define LOG_LEVEL_DA 15 +/*! ALL LOG LEVEL */ +#define LOG_LEVEL_A 20 + +#ifndef MODULE_TAG +/*! MODULE TAG DEFINATION */ +#define MODULE_TAG "" +#endif + +#ifndef LOG_LEVEL +/*! LOG LEVEL DEFINATION */ +#define LOG_LEVEL LOG_LEVEL_A +#endif + +#ifdef BOSCH_DRIVER_LOG_FUNC + #ifdef BSLOG_VAR_DEF + uint8_t debug_log_level = LOG_LEVEL; + #else + extern uint8_t debug_log_level; + #endif + + /*! print error message */ + #define PERR(fmt, args...) do\ + {\ + pr_err("<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print notice message */ + #define PNOTICE(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_N)\ + printk(KERN_INFO "\n" "[N]" KERN_NOTICE MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print information message */ + #define PINFO(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_I)\ + printk(KERN_INFO "\n" "[I]" KERN_INFO MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print debug message */ + #define PDEBUG(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_D)\ + printk(KERN_INFO "\n" "[D]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print debug fw download message */ + #define PDEBUG_FWDL(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_DF)\ + printk(KERN_INFO "\n" "[DF]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + /*! print debug data log message */ + #define PDEBUG_DLOG(fmt, args...) do\ + {\ + if (debug_log_level >= LOG_LEVEL_DA)\ + printk(KERN_INFO "\n" "[DA]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args);\ + } while (0) + + void set_debug_log_level(uint8_t level); + uint8_t get_debug_log_level(void); + +#else + + #if (LOG_LEVEL >= LOG_LEVEL_E) + /*! print error message */ + #define PERR(fmt, args...) \ + printk(KERN_INFO "\n" "[E]" KERN_ERR MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PERR(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_N) + /*! print notice message */ + #define PNOTICE(fmt, args...) \ + printk(KERN_INFO "\n" "[N]" KERN_NOTICE MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PNOTICE(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_I) + /*! print information message */ + #define PINFO(fmt, args...) printk(KERN_INFO "\n" "[I]" KERN_INFO MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PINFO(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_D) + /*! print debug message */ + #define PDEBUG(fmt, args...) printk(KERN_INFO "\n" "[D]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PDEBUG(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_DF) + /*! print debug fw download message */ + #define PDEBUG_FWDL(fmt, args...) printk(KERN_INFO "\n" "[DF]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PDEBUG_FWDL(fmt, args...) + #endif + + #if (LOG_LEVEL >= LOG_LEVEL_DA) + /*! print debug data log message */ + #define PDEBUG_DLOG(fmt, args...) printk(KERN_INFO "\n" "[DA]" KERN_DEBUG MODULE_TAG \ + "<%s><%d>" fmt "\n", __func__, __LINE__, ##args) + #else + /*! invalid message */ + #define PDEBUG_DLOG(fmt, args...) + #endif + + #define set_debug_log_level(level) {} + #define get_debug_log_level() (LOG_LEVEL) + +#endif + +#endif/*__BS_LOG_H*/ +/*@}*/ -- 2.25.1 From 6ad8dcfc142acac85e96a6097537ed83ac112ad7 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Tue, 31 Aug 2021 11:28:34 -0400 Subject: [PATCH 69/76] kernel/msm-3.18: - Google recommends to remove CONFIG_OPTIMIZE_FOR_SIZE Change-Id: I610c84f93d095aadd2a94659e657d0d6a9839f9e --- arch/arm/configs/msm8909_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index 0587cd29f0c..107d6f03ece 100755 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -27,7 +27,7 @@ CONFIG_NAMESPACES=y CONFIG_BLK_DEV_INITRD=y CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=n CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PROFILING=y -- 2.25.1 From 16387154f966030a2ea26821927ca3be24f06819 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 27 Jan 2022 14:17:20 -0700 Subject: [PATCH 70/76] kernel/msm-3.18: MeiG: fuyou: test only for cpu-thermal testing and bt stack Change-Id: I4ed2f180945d06c7241b4500fcadd46de6023927 --- arch/arm/boot/dts/qcom/msm8909.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index ded2c7cee0a..f5a45effe5b 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -562,14 +562,14 @@ compatible = "qcom,msm-thermal"; qcom,sensor-id = <3>; qcom,poll-ms = <250>; - qcom,limit-temp = <70>; + qcom,limit-temp = <85>; qcom,temp-hysteresis = <10>; qcom,freq-step = <2>; - qcom,core-limit-temp = <90>; + qcom,core-limit-temp = <100>; qcom,core-temp-hysteresis = <10>; - qcom,hotplug-temp = <97>; + qcom,hotplug-temp = <107>; qcom,hotplug-temp-hysteresis = <12>; - qcom,freq-mitigation-temp = <97>; + qcom,freq-mitigation-temp = <107>; qcom,freq-mitigation-temp-hysteresis = <12>; qcom,freq-mitigation-value = <400000>; qcom,online-hotplug-core; -- 2.25.1 From 185e69ab3871bf7ca93ec37754b3378f11248cae Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 27 Jan 2022 17:09:41 -0700 Subject: [PATCH 71/76] kernel/msm-3.18: MeiG liangdi:bmp280 gmp102 compatible Change-Id: Ibefd62828b3df2dc600b1072281c6366a57d1adb --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 15 +- arch/arm/boot/dts/qcom/msm8909.dtsi | 2 +- arch/arm/configs/msm8909-perf_defconfig | 1 + drivers/input/misc/Kconfig | 9 + drivers/input/misc/Makefile | 2 +- drivers/input/misc/gmp102-core.c | 1128 ++++++++++++++ drivers/input/misc/gmp102-i2c.c | 331 +++++ drivers/input/misc/gmp102.h | 105 ++ drivers/input/misc/icm42607/ICM-42607.c | 219 +++ drivers/input/misc/icm42607/ICM-42607.h | 94 ++ drivers/input/misc/icm42607/Kconfig | 18 + drivers/input/misc/icm42607/Makefile | 8 + drivers/input/misc/icm42607/icm42607_driver.c | 1294 +++++++++++++++++ drivers/input/misc/icm42607/icm42607_driver.h | 132 ++ drivers/input/misc/icm42607/icm42607_i2c.c | 284 ++++ drivers/input/misc/icm42607/icm42607_spi.c | 288 ++++ .../input/misc/icm42607/qualcomm_example.dts | 23 + 17 files changed, 3950 insertions(+), 3 deletions(-) create mode 100755 drivers/input/misc/gmp102-core.c create mode 100755 drivers/input/misc/gmp102-i2c.c create mode 100755 drivers/input/misc/gmp102.h create mode 100755 drivers/input/misc/icm42607/ICM-42607.c create mode 100755 drivers/input/misc/icm42607/ICM-42607.h create mode 100755 drivers/input/misc/icm42607/Kconfig create mode 100755 drivers/input/misc/icm42607/Makefile create mode 100755 drivers/input/misc/icm42607/icm42607_driver.c create mode 100755 drivers/input/misc/icm42607/icm42607_driver.h create mode 100755 drivers/input/misc/icm42607/icm42607_i2c.c create mode 100755 drivers/input/misc/icm42607/icm42607_spi.c create mode 100755 drivers/input/misc/icm42607/qualcomm_example.dts diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index f3c75fb3fa2..ce0159fc9b6 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -556,7 +556,20 @@ reg = <0x76>; vdd-supply = <&pm8909_l17>; vio-supply = <&pm8909_l6>; - }; + status = "ok"; + }; + + gmp@6c { + compatible = "gmems,gmp102"; + reg = <0x6c>; + gmems,chip-id = <0x2>; + gmems,oversample = <3>; + gmems,period = <200>; + //gmems,sw-oversample; + vdd-supply = <&pm8909_l17>; + vio-supply = <&pm8909_l6>; + status = "ok"; + }; bosch@68 { /* Accelerometer and gyroscope sensor */ compatible = "bosch,bmi160"; diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index f5a45effe5b..df814d8b32d 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -1494,7 +1494,7 @@ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, <&clock_gcc clk_gcc_blsp1_qup1_i2c_apps_clk>; clock-names = "iface_clk", "core_clk"; - qcom,clk-freq-out = <400000>; + qcom,clk-freq-out = <100000>; qcom,clk-freq-in = <19200000>; pinctrl-names = "i2c_active", "i2c_sleep"; pinctrl-0 = <&i2c_1_active>; diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 9b8c576a475..b60a442f779 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -572,3 +572,4 @@ CONFIG_EXTCON=y CONFIG_EXTCON_PTN5150=y CONFIG_FRAME_WARN=2048 +CONFIG_SENSORS_GMP102=y \ No newline at end of file diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 0da921998b0..68bf64a0cf2 100755 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -912,4 +912,13 @@ config SENSORS_BMP280_SPI depends on SENSORS_BMP280 && SPI_MASTER help If you say yes here, you get support Bosch Sensortec's BMP280 pressure sensor hooked to an SPI bus. + +config SENSORS_GMP102 + tristate "GMP102 Sensor Support" + depends on I2C + help + If you say yes here, you get support for gmp102 Sensortec's + sensor driver of GMP102. + endif + diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index ea90b45818b..02530bdc1b9 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -115,4 +115,4 @@ endif endif obj-$(CONFIG_SENSORS_BMI220) += bmi220/ - +obj-$(CONFIG_SENSORS_GMP102) += gmp102-core.o gmp102-i2c.o diff --git a/drivers/input/misc/gmp102-core.c b/drivers/input/misc/gmp102-core.c new file mode 100755 index 00000000000..027f06f49c4 --- /dev/null +++ b/drivers/input/misc/gmp102-core.c @@ -0,0 +1,1128 @@ +/* Copyright (c) 2019 GlobalMEMS Co., Ltd. + + This driver supports the gmp102 digital barometric pressure + and temperature sensors from GlobalMEMS Co., Ltd. (GMEMS). + + A pressure measurement is issued by reading from pressure0_input. + The return value ranges from 30000 to 110000 pascal with a resulution + of 1 pascal (0.01 millibar) which enables measurements from 9000m above + to 500m below sea level. + + The temperature can be read from temp0_input. Values range from + -400 to 850 representing the ambient temperature in degree celsius + multiplied by 10.The resolution is 0.1 celsius. + + Because ambient pressure is temperature dependent, a temperature + measurement will be executed automatically even if the user is reading + from pressure0_input. This happens if the last temperature measurement + has been executed more then one second ago. + + gmp102 has oversampling setting to decrease RMS noise from pressure measurements, + This is set up by writing to the oversampling sysfs file. Accepted values + are 0~7. See the gmp102_set_oversampling function comment for their actual + oversampling ratio representation. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include "gmp102.h" + +#define GMP102_RESET_REG 0x00 +#define GMP102_CHIP_ID_REG 0x01 +#define GMP102_STATUS_REG 0x02 +#define GMP102_PRESSH_REG 0x06 +#define GMP102_TEMPH_REG 0x09 +#define GMP102_CMD_REG 0x30 +#define GMP102_CONFIG1_REG 0xA5 +#define GMP102_CONFIG2_REG 0xA6 +#define GMP102_CALIBRATION_DATA_START 0xAA + +#define GMP102_SW_RST_SET_VALUE 0x24 +#define GMP102_CHIP_ID 0x02 +#define GMP102_CALIBRATION_DATA_OUT 0x00 +#define GMP102_RAW_DATA_OUT 0x02 +#define GMP102_TEMP_MEASUREMENT 0x08 +#define GMP102_PRESSURE_MEASUREMENT 0x09 +#define GMP102_MAX_POSR_SETTING 7 +#define GMP102_DEFAULT_POSR_SETTING 3 //X8192 + +#define ABS_MIN_PRESSURE 30000 +#define ABS_MAX_PRESSURE 120000 +#define GMP_DELAY_DEFAULT 200 + +static struct sensors_classdev sensors_cdev = { + .name = "gmp102-pressure", + .vendor = "GMEMS", + .version = 1, + .handle = SENSORS_PRESSURE_HANDLE, + .type = SENSOR_TYPE_PRESSURE, + .max_range = "1100.0", + .resolution = "0.01", + .sensor_power = "0.67", + .min_delay = 20000, /* microsecond */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, /* millisecond */ + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; + +//add by liangdi for temperature 20210604 +static struct sensors_classdev temp_sensors_cdev = { + .name = "gmp102-temperature", + .vendor = "GMEMS", + .version = 1, + .handle = SENSORS_AMBIENT_TEMPERATURE_HANDLE, + .type = SENSOR_TYPE_AMBIENT_TEMPERATURE, + .max_range = "85.0", + .resolution = "0.1", + .sensor_power = "0.67", + .min_delay = 20000, /* microsecond */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, /* millisecond */ + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; +//add end + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void gmp102_early_suspend(struct early_suspend *h); +static void gmp102_late_resume(struct early_suspend *h); +#endif + +static s32 gmp102_read_calibration_data(struct gmp102_data *data) +{ + s16 i, s16Tmp; + u8 tmp[GMP102_CALIBRATION_DATA_LENGTH]; + struct gmp102_calibration_data *cali = &(data->calibration); + s32 status = data->data_bus.bops->read_block(data->data_bus.client, + GMP102_CALIBRATION_DATA_START, + GMP102_CALIBRATION_DATA_LENGTH, + tmp); + if (status < 0) + return status; + + if (status != GMP102_CALIBRATION_DATA_LENGTH) + return -EIO; + + for(i = 0; i < GMP102_CALIBRATION_PARAM_COUNT; ++i){ + s16Tmp = (tmp[2 * i] << 8) + tmp[2 * i + 1]; + cali->s16Value[i] = (s16Tmp>>2); + cali->u8Power[i] = (s16Tmp & 0x03); + } + + return 0; +} + + +static s32 gmp102_update_raw_temperature(struct gmp102_data *data) +{ + u16 u16Tmp; + s16 s16Tmp; + s32 status; + u8 u8Tmp, u8Tried; + + mutex_lock(&data->lock); + + // Set to calibration data out + status = data->data_bus.bops->write_byte(data->data_bus.client, + GMP102_CONFIG1_REG, + GMP102_CALIBRATION_DATA_OUT); + if (status != 0) { + dev_err(data->dev, "Error set calibration data out.\n"); + goto exit; + } + + // T-forced mode + status = data->data_bus.bops->write_byte(data->data_bus.client, + GMP102_CMD_REG, + GMP102_TEMP_MEASUREMENT); + if (status != 0) { + dev_err(data->dev, "Error while requesting temperature measurement.\n"); + goto exit; + } + + // Wait for DRDY bit set + u8Tried = 0; + do{ + + //wait a while + msleep(5); + + status = data->data_bus.bops->read_byte(data->data_bus.client, GMP102_STATUS_REG); + + if (status < 0) { + dev_err(data->dev, "Error while reading status bit.\n"); + goto exit; + } + + u8Tmp = status; + u8Tried += 1; + + } while( (u8Tried <= 10) && ((u8Tmp & 0x01) != 1)); + + // Read 2 bytes starting from 09h + status = data->data_bus.bops->read_block(data->data_bus.client, + GMP102_TEMPH_REG, + sizeof(u16Tmp), + (u8 *)&u16Tmp); + if (status < 0) + goto exit; + + if (status != sizeof(u16Tmp)) { + dev_err(data->dev, "Error while reading temperature measurement result\n"); + status = -EIO; + goto exit; + } + + // Temperature + s16Tmp = be16_to_cpu(u16Tmp); + data->raw_temperature = s16Tmp; + data->last_temp_measurement = jiffies; + status = 0; /* everything ok, return 0 */ + + exit: + mutex_unlock(&data->lock); + return status; +} + +static s32 gmp102_update_raw_pressure(struct gmp102_data *data) +{ + u32 u32Tmp = 0; + s32 s32Tmp, status; + u8 u8Tmp, u8Tried; + + mutex_lock(&data->lock); + + // Set to raw data out + status = data->data_bus.bops->write_byte(data->data_bus.client, + GMP102_CONFIG1_REG, + GMP102_RAW_DATA_OUT); + if (status != 0) { + dev_err(data->dev, "Error set raw data out.\n"); + goto exit; + } + + // P-forced mode + status = data->data_bus.bops->write_byte(data->data_bus.client, + GMP102_CMD_REG, + GMP102_PRESSURE_MEASUREMENT); + if (status != 0) { + dev_err(data->dev, "Error while requesting pressure measurement.\n"); + goto exit; + } + + // Wait for DRDY bit set + u8Tried = 0; + do{ + + //wait a while + msleep(5); + + status = data->data_bus.bops->read_byte(data->data_bus.client, GMP102_STATUS_REG); + + if (status < 0) { + dev_err(data->dev, "Error while reading status bit.\n"); + goto exit; + } + + u8Tmp = status; + u8Tried += 1; + + } while( (u8Tried <= 10) && ((u8Tmp & 0x01) != 1)); + + + /* copy data into a u32 (4 bytes), but skip the first byte. */ + // Read 3 bytes starting from 06h + status = data->data_bus.bops->read_block(data->data_bus.client, + GMP102_PRESSH_REG, + 3, + ((u8 *)&u32Tmp) + 1); + if (status < 0) + goto exit; + + if (status != 3) { + dev_err(data->dev, "Error while reading pressure measurement results\n"); + status = -EIO; + goto exit; + } + + // Pressure + s32Tmp = be32_to_cpu((u32Tmp)); + data->raw_pressure = (s32Tmp << 8) >> 8; //sign extension + status = 0; /* everything ok, return 0 */ + + exit: + mutex_unlock(&data->lock); + return status; +} + + +/* + * This function starts the temperature measurement and returns the value + * in tenth of a degree celsius. + */ +static s32 gmp102_get_temperature(struct gmp102_data *data, int *temperature) +{ + int status; + static int pre_temp = 0, temp = 0; + static int count = 0; + + status = gmp102_update_raw_temperature(data); + if (status != 0) + goto exit; + + temp = ((data->raw_temperature * 10 + (1 << 7)) >> 8) * 10;//liangdi + if(pre_temp == temp) + { + count ++; + } + else + { + count = 0; + } + + if(count > 3) + { + temp = temp + 1;//not always send same data liangdi + count = 0; + } + + /* if NULL the gmp102_update_raw_temperature call just update data->raw_temperature. + Used for pressure only measurements */ + if (temperature != NULL) //1 Celsius = 256 code + *temperature = temp; + + pre_temp = temp; + exit: + return status; +} + +static const s32 GMP102_POWER_SCALE[] = {1, 10, 100, 1000}; + +#define ShiftRight(v, s) (((v)+(1<<((s)-1)))>>(s)) +#define RoundDivide(v, d) (((v)+((d)/2))/(d)) + +/*! + * @brief gmp102 temperature and pressure compensation, s32 fixed point operation + * + * @param s32T raw temperature in code + * @param s32P raw pressure in code + * @param s16Value[]: array of the value part of the calibration parameter + * @param u8Power[]: array of the power part of the calibration parameter + * @param *ps32P_Pa calibrated pressure in Pa returned to caller + * + * @return None + * + */ +static void gmp102_compensation_fixed_point_s32(s32 s32T, + s32 s32P, + s16 s16Value[], + u8 u8Power[], + s32* ps32P_Pa) +{ + + s32 tmp, val, tmpT1, tmpT3, tmpP4, tmpP10, tmpP12, tmpP13; + + //some temporary variables + tmpT1 = ShiftRight(s32T, 1); + tmpT3 = ShiftRight(s32T, 3); + tmpP4 = ShiftRight(s32P, 4); + tmpP10 = ShiftRight(s32P, 10); + tmpP12 = ShiftRight(s32P, 12); + tmpP13 = ShiftRight(s32P, 13); + + //Pressure + val = 0; + //beta0 + tmp = s16Value[0] * GMP102_POWER_SCALE[u8Power[0]]; + val += tmp; + //beta1*T + tmp = s32T * s16Value[1]; + tmp = ShiftRight(tmp, 5) * GMP102_POWER_SCALE[u8Power[1]]; + tmp = RoundDivide(tmp, 3125); + val += tmp; + //beta2*T*T + tmp = s32T * s16Value[2]; + tmp = ShiftRight(tmp, 8) * tmpT1; + tmp = ShiftRight(tmp, 9) * GMP102_POWER_SCALE[u8Power[2]]; + tmp = RoundDivide(tmp, 38147); + val += tmp; + //beta3*P + tmp = tmpP4 * s16Value[3]; + tmp = ShiftRight(tmp, 5) * GMP102_POWER_SCALE[u8Power[3]]; + tmp = RoundDivide(tmp, 195); + val += tmp; + + //beta4*P*T + tmp = tmpP10 * s16Value[4]; + tmp = ShiftRight(tmp, 13) * tmpT3; + tmp = tmp * GMP102_POWER_SCALE[u8Power[4]]; + tmp = RoundDivide(tmp, 149); + val += tmp; + //beta5*P*T*T + tmp = tmpP13 * s16Value[5]; + tmp = ShiftRight(tmp, 9) * s32T; + tmp = ShiftRight(tmp, 10) * s32T; + tmp = ShiftRight(tmp, 10) * GMP102_POWER_SCALE[u8Power[5]]; + tmp = RoundDivide(tmp, 227); + val += tmp; + //beta6*P*P + tmp = tmpP10 * s16Value[6]; + tmp = ShiftRight(tmp, 2) * tmpP12; + tmp = ShiftRight(tmp, 10) * GMP102_POWER_SCALE[u8Power[6]]; + tmp = RoundDivide(tmp, 58); + val += tmp; + //beta7*P*P*T + tmp = tmpP10 * s16Value[7]; + tmp = ShiftRight(tmp, 1) * tmpP13; + tmp = ShiftRight(tmp, 13) * s32T; + tmp = ShiftRight(tmp, 10) * GMP102_POWER_SCALE[u8Power[7]]; + tmp = RoundDivide(tmp, 711); + val += tmp; + //beta8*P*P*T*T + tmp = tmpP12 * s16Value[8]; + tmp = ShiftRight(tmp, 2) * tmpP12; + tmp = ShiftRight(tmp, 12) * tmpT1; + tmp = ShiftRight(tmp, 12) * tmpT1; + tmp = ShiftRight(tmp, 8) * GMP102_POWER_SCALE[u8Power[8]]; + tmp = RoundDivide(tmp, 867); + val += tmp; + + *ps32P_Pa = val; + + return; +} + +/* + * This function starts the pressure measurement and returns the value + * in millibar. Since the pressure depends on the ambient temperature, + * a temperature measurement is executed according to the given temperature + * measurememt period (default is 1 sec boundary). This period could vary + * and needs to be adjusted accoring to the sensor environment, i.e. if big + * temperature variations then the temperature needs to be read out often. + */ +static s32 gmp102_get_pressure(struct gmp102_data *data, int *pressure) +{ + struct gmp102_calibration_data *cali = &data->calibration; + int status; + int i_loop, i; + u32 p_tmp; + + /* update the ambient temperature according to the given meas. period */ + if (data->last_temp_measurement + + data->temp_measurement_period < jiffies) { + status = gmp102_get_temperature(data, NULL); + if (status != 0) + goto exit; + } + + if ((data->oversampling_setting == GMP102_MAX_POSR_SETTING) + && (data->sw_oversampling_setting == 1)) { + i_loop = 3; + } else { + i_loop = 1; + } + + p_tmp = 0; + for (i = 0; i < i_loop; i++) { + status = gmp102_update_raw_pressure(data); + if (status != 0) + goto exit; + p_tmp += data->raw_pressure; + } + + data->raw_pressure = (p_tmp + (i_loop >> 1)) / i_loop; + + gmp102_compensation_fixed_point_s32(data->raw_temperature, + data->raw_pressure, + cali->s16Value, + cali->u8Power, + pressure); + exit: + return status; +} + +/* + * This function sets the chip-internal oversampling. Valid values are 0..7. + * 0: X1024 + * 1: X2048 + * 2: X4096 + * 3: X8192 + * 4: X256 + * 5: X512 + * 6: X16384 + * 7: X32768 + * This influences the measurement time and the accuracy; larger values + * increase both. The datasheet gives on overview on how measurement time, + * accuracy and noise correlate. + */ +static void gmp102_set_oversampling(struct gmp102_data *data, + unsigned char oversampling) +{ + s32 status; + u8 u8Tmp; + + if (oversampling > GMP102_MAX_POSR_SETTING) + oversampling = GMP102_MAX_POSR_SETTING; + + // Read A6h + status = data->data_bus.bops->read_byte(data->data_bus.client, GMP102_CONFIG2_REG); + + if (status < 0) { + dev_err(data->dev, "Error while reading A6h when set oversampling.\n"); + goto exit; + } + + //Set the A6h[2:0] OSR bits + u8Tmp = ((status & ~0x07) | (oversampling & 0x07)); + status = data->data_bus.bops->write_byte(data->data_bus.client, + GMP102_CONFIG2_REG, + u8Tmp); + + if (status < 0) { + dev_err(data->dev, "Error while writing A6h when set oversampling.\n"); + goto exit; + } + + data->oversampling_setting = oversampling; + + exit: + return; +} + +/* + * Returns the currently selected oversampling. Range: 0..7 + */ +static unsigned char gmp102_get_oversampling(struct gmp102_data *data) +{ + return data->oversampling_setting; +} + +/* sysfs callbacks */ +static ssize_t set_oversampling(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + unsigned long oversampling; + int success = kstrtoul(buf, 10, &oversampling); + if (success == 0) { + mutex_lock(&data->lock); + gmp102_set_oversampling(data, oversampling); + if (data->oversampling_setting != GMP102_MAX_POSR_SETTING) + data->sw_oversampling_setting = 0; + mutex_unlock(&data->lock); + return count; + } + return success; +} + +static ssize_t show_oversampling(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, + "%u\n", gmp102_get_oversampling(data)); +} +static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO, + show_oversampling, set_oversampling); + +static ssize_t set_sw_oversampling(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + unsigned long sw_oversampling; + int success = kstrtoul(buf, 10, &sw_oversampling); + if (success == 0) { + mutex_lock(&data->lock); + data->sw_oversampling_setting = sw_oversampling ? 1 : 0; + mutex_unlock(&data->lock); + return count; + } + return success; +} + +static ssize_t show_sw_oversampling(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, + "%u\n", data->sw_oversampling_setting); +} +static DEVICE_ATTR(sw_oversampling, S_IWUSR | S_IRUGO, + show_sw_oversampling, set_sw_oversampling); + +static ssize_t gmp102_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_msec) +{ + struct gmp102_data *data = container_of(sensors_cdev, + struct gmp102_data, cdev); + mutex_lock(&data->lock); + data->delay = delay_msec; + mutex_unlock(&data->lock); + pr_err("gmp102 pressure delay %d\n", data->delay); + + return 0; +} + +//add by liangdi for temperature 20210604 +static ssize_t gmp102_temp_poll_delay_set(struct sensors_classdev *sensors_cdev, + unsigned int delay_msec) +{ + struct gmp102_data *data = container_of(sensors_cdev, + struct gmp102_data, temp_cdev); + mutex_lock(&data->temp_lock); + data->temp_delay = delay_msec; + mutex_unlock(&data->temp_lock); + pr_err("gmp102 temp delay %d\n", data->temp_delay); + + return 0; +} +//add end + +static ssize_t show_delay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", data->delay); +} + +static ssize_t set_delay(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + unsigned long delay; + int err = kstrtoul(buf, 10, &delay); + if (err < 0) + return err; + + err = gmp102_poll_delay_set(&data->cdev, delay); + if (err < 0) + return err; + + return count; +} + +static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, + show_delay, set_delay); + +static ssize_t gmp102_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enabled) +{ + struct gmp102_data *data = container_of(sensors_cdev, + struct gmp102_data, cdev); + struct device *dev = data->dev; + + enabled = enabled ? 1 : 0; + mutex_lock(&data->lock); + + if (data->enable == enabled) { + dev_warn(dev, "already %s\n", enabled ? "enabled" : "disabled"); + goto out; + } + + data->enable = enabled; + + pr_err("gmp102_enable_set %s\n",enabled ? "enabled" : "disabled"); + if (data->enable) { + gmp102_enable(dev); + schedule_delayed_work(&data->work, + msecs_to_jiffies(data->delay)); + } else { + cancel_delayed_work_sync(&data->work); + gmp102_disable(dev); + } + + out: + mutex_unlock(&data->lock); + return 0; +} + +//add by liangdi for temperature 20210604 +static ssize_t gmp102_temp_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enabled) +{ + struct gmp102_data *data = container_of(sensors_cdev, + struct gmp102_data, temp_cdev); + struct device *dev = data->dev; + + enabled = enabled ? 1 : 0; + mutex_lock(&data->temp_lock); + + if (data->temp_enable == enabled) { + dev_warn(dev, "already %s\n", enabled ? "enabled" : "disabled"); + goto out; + } + + data->temp_enable = enabled; + + pr_err("gmp102_temp_enable_set %s\n",enabled ? "enabled" : "disabled"); + if (data->temp_enable) { + gmp102_enable(dev); + schedule_delayed_work(&data->temp_work, + msecs_to_jiffies(data->temp_delay)); + } else { + cancel_delayed_work_sync(&data->temp_work); + gmp102_disable(dev); + } + + out: + mutex_unlock(&data->temp_lock); + return 0; +} +//add end + +static ssize_t show_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", data->enable); +} + +static ssize_t set_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct gmp102_data *data = dev_get_drvdata(dev); + unsigned long enable; + int err = kstrtoul(buf, 10, &enable); + if (err < 0) + return err; + + err = gmp102_enable_set(&data->cdev, enable); + if (err < 0) + return err; + + return count; +} + +static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, + show_enable, set_enable); + +static ssize_t show_temperature(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int temperature; + int status; + struct gmp102_data *data = dev_get_drvdata(dev); + + status = gmp102_get_temperature(data, &temperature); + if (status != 0) + return status; + else + return snprintf(buf, PAGE_SIZE, + "%d\n", temperature); +} +static DEVICE_ATTR(temp0_input, S_IRUGO, show_temperature, NULL); + + +static ssize_t show_pressure(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int pressure; + int status; + struct gmp102_data *data = dev_get_drvdata(dev); + + status = gmp102_get_pressure(data, &pressure); + if (status != 0) + return status; + else + return snprintf(buf, PAGE_SIZE, "%d\n", pressure); +} +static DEVICE_ATTR(pressure0_input, S_IRUGO, show_pressure, NULL); + + +static struct attribute *gmp102_attributes[] = { + &dev_attr_temp0_input.attr, + &dev_attr_pressure0_input.attr, + &dev_attr_oversampling.attr, + &dev_attr_sw_oversampling.attr, + &dev_attr_poll_delay.attr, + &dev_attr_enable.attr, + NULL +}; + +static const struct attribute_group gmp102_attr_group = { + .attrs = gmp102_attributes, +}; + +static void gmp102_work_func(struct work_struct *work) +{ + struct gmp102_data *client_data = + container_of((struct delayed_work *)work, + struct gmp102_data, work); + unsigned long delay = msecs_to_jiffies(client_data->delay); + unsigned long j1 = jiffies; + int pressure; + int status; + + status = gmp102_get_pressure(client_data, &pressure); + + if (status == 0) { + //input_report_abs(client_data->input, ABS_PRESSURE, pressure); + pr_err("gmp102 pressure value :%d Pa\n", pressure); + input_event(client_data->input, EV_ABS, MSC_RAW, pressure); + + input_sync(client_data->input); + } + + schedule_delayed_work(&client_data->work, delay-(jiffies-j1)); +} + +//add by liangdi for temperature 20210604 +static void gmp102_temp_work_func(struct work_struct *work) +{ + struct gmp102_data *client_data = + container_of((struct delayed_work *)work, + struct gmp102_data, temp_work); + unsigned long delay = msecs_to_jiffies(client_data->temp_delay); + unsigned long j1 = jiffies; + int temperature; + int status; + + status = gmp102_get_temperature(client_data, &temperature); + + if (status == 0) { + pr_err("gmp102 temperature value :%d C\n", temperature); + input_event(client_data->temp_input, EV_ABS, MSC_RAW, temperature); + + input_sync(client_data->temp_input); + } + + schedule_delayed_work(&client_data->temp_work, delay-(jiffies-j1)); +} +//add end + +static int gmp102_input_init(struct gmp102_data *data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + dev->name = "gmp102-pressure";//GMP102_NAME; + dev->id.bustype = BUS_I2C; + + /*input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_PRESSURE, + ABS_MIN_PRESSURE, ABS_MAX_PRESSURE, 0, 0);*/ + input_set_capability(dev, EV_ABS, MSC_RAW); + input_set_drvdata(dev, data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + data->input = dev; + +//add by liangdi for temperature 20210604 + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + dev->name = "gmp102-temperature";//GMP102_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, MSC_RAW); + input_set_drvdata(dev, data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + data->temp_input = dev; +//add end + + return 0; +} + +static void gmp102_input_delete(struct gmp102_data *data) +{ + struct input_dev *dev = data->input; + + input_unregister_device(dev); + input_free_device(dev); +} + +//add by liangdi for temperature 20210604 +static void gmp102_temp_input_delete(struct gmp102_data *data) +{ + struct input_dev *dev = data->temp_input; + + input_unregister_device(dev); + input_free_device(dev); +} +//add end +static int gmp102_init_client(struct gmp102_data *data, + struct gmp102_platform_data *pdata) +{ + int status; + int i; + + //Soft reset by setting 00h = 0x24 + status = data->data_bus.bops->write_byte(data->data_bus.client, + GMP102_RESET_REG, + GMP102_SW_RST_SET_VALUE); + // Just ignore the status. gmp102 will not response the last ACK. + msleep(20); + + // Read calibration parameters + status = gmp102_read_calibration_data(data); + if (status != 0) + goto exit; + + //Set AAh ~ ADh to 0x00 + for(i = 0; i < 4; ++i){ + status = data->data_bus.bops->write_byte(data->data_bus.client, + GMP102_CALIBRATION_DATA_START + i, + 0x00); + if (status != 0) { + dev_err(data->dev, "Error set %02Xh=0x00.\n", GMP102_CALIBRATION_DATA_START + i); + goto exit; + } + } + + // Init private datas + data->last_temp_measurement = 0; + data->temp_measurement_period = + pdata ? (pdata->temp_measurement_period/1000)*HZ : 1*HZ; + + // Init oversampling + gmp102_set_oversampling(data, + pdata ? pdata->default_oversampling : GMP102_DEFAULT_POSR_SETTING); + + if (data->oversampling_setting == GMP102_MAX_POSR_SETTING) + data->sw_oversampling_setting + = pdata ? pdata->default_sw_oversampling : 0; + mutex_init(&data->lock); + mutex_init(&data->temp_lock);//liangdi + exit: + return status; +} + +int gmp102_probe(struct device *dev, struct gmp102_data_bus *data_bus) +{ + struct gmp102_data *data; + struct gmp102_platform_data *pdata = dev->platform_data; + u8 chip_id = pdata && pdata->chip_id ? pdata->chip_id : GMP102_CHIP_ID; + int err = 0; + + if (pdata && pdata->init_hw) { + err = pdata->init_hw(data_bus); + if (err) { + printk(KERN_ERR "%s: init_hw failed!\n", + GMP102_NAME); + goto exit; + } + pr_err("init_hw ok!\n"); + } + + data = kzalloc(sizeof(struct gmp102_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + dev_set_drvdata(dev, data); + data->data_bus = *data_bus; + data->dev = dev; + + if(pdata && pdata->set_power) + pdata->set_power(data, 1); + data->power_enabled = 1; + + if (data_bus->bops->read_byte(data_bus->client, + GMP102_CHIP_ID_REG) != chip_id) { + printk(KERN_ERR "%s: chip_id failed!\n", GMP102_NAME); + err = -ENODEV; + goto exit_free; + } + + /* Initialize the GMP102 chip */ + err = gmp102_init_client(data, pdata); + if (err != 0) + goto exit_free; + + /* Initialize the GMP102 input device */ + err = gmp102_input_init(data); + if (err != 0) + goto exit_free; + + /* Register sysfs hooks */ + err = sysfs_create_group(&data->input->dev.kobj, &gmp102_attr_group); + if (err) + goto error_sysfs; + + data->cdev = sensors_cdev; + data->cdev.sensors_enable = gmp102_enable_set; + data->cdev.sensors_poll_delay = gmp102_poll_delay_set; + err = sensors_classdev_register(&data->input->dev, &data->cdev); + if (err) { + pr_err("class device create failed: %d\n", err); + goto error_class_sysfs; + } + + /* workqueue init */ + INIT_DELAYED_WORK(&data->work, gmp102_work_func); + data->delay = GMP_DELAY_DEFAULT; + data->enable = 0; + + //add by liangdi for temperature 20210604 + data->temp_cdev = temp_sensors_cdev; + data->temp_cdev.sensors_enable = gmp102_temp_enable_set; + data->temp_cdev.sensors_poll_delay = gmp102_temp_poll_delay_set; + err = sensors_classdev_register(&data->temp_input->dev, &data->temp_cdev); + if (err) { + pr_err("class device create failed: %d\n", err); + goto error_class_sysfs; + } + + /* workqueue init */ + INIT_DELAYED_WORK(&data->temp_work, gmp102_temp_work_func); + data->temp_delay = GMP_DELAY_DEFAULT; + data->temp_enable = 0; + //add end +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + data->early_suspend.suspend = gmp102_early_suspend; + data->early_suspend.resume = gmp102_late_resume; + register_early_suspend(&data->early_suspend); +#endif + + dev_info(dev, "Succesfully initialized gmp102!\n"); + return 0; + + error_class_sysfs: + sysfs_remove_group(&data->input->dev.kobj, &gmp102_attr_group); + error_sysfs: + gmp102_input_delete(data); + gmp102_temp_input_delete(data);//add by liangdi for temperature 20210604 + + exit_free: + kfree(data); + exit: + if (pdata && pdata->deinit_hw) + pdata->deinit_hw(data_bus); + return err; +} +EXPORT_SYMBOL(gmp102_probe); + +int gmp102_remove(struct device *dev) +{ + struct gmp102_data *data = dev_get_drvdata(dev); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&data->early_suspend); +#endif + sysfs_remove_group(&data->input->dev.kobj, &gmp102_attr_group); + kfree(data); + + return 0; +} +EXPORT_SYMBOL(gmp102_remove); + +#ifdef CONFIG_PM +int gmp102_disable(struct device *dev) +{ +/* + struct gmp102_platform_data *pdata = dev->platform_data; + struct gmp102_data *data = dev_get_drvdata(dev); + int ret = 0; + + if (pdata && pdata->set_power) + ret = pdata->set_power(data, 0); + + return ret; +*/ + return 0; +} +EXPORT_SYMBOL(gmp102_disable); + +int gmp102_enable(struct device *dev) +{ +/* + struct gmp102_platform_data *pdata = dev->platform_data; + struct gmp102_data *data = dev_get_drvdata(dev); + int ret = 0; + + if (pdata && pdata->set_power) + ret = pdata->set_power(data, 1); + + return ret; +*/ + return 0; +} +EXPORT_SYMBOL(gmp102_enable); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void gmp102_early_suspend(struct early_suspend *h) +{ + struct gmp102_data *data = + container_of(h, struct gmp102_data, early_suspend); + if (data->enable) { + cancel_delayed_work_sync(&data->work); + (void) gmp102_disable(data->dev); + } + //add by liangdi for temperature 20210604 + if (data->temp_enable) { + cancel_delayed_work_sync(&data->temp_work); + (void) gmp102_disable(data->dev); + } + //add end +} + +static void gmp102_late_resume(struct early_suspend *h) +{ + struct gmp102_data *data = + container_of(h, struct gmp102_data, early_suspend); + + if (data->enable) { + (void) gmp102_enable(data->dev); + schedule_delayed_work(&data->work, + msecs_to_jiffies(data->delay)); + } + + //add by liangdi for temperature 20210604 + if (data->temp_enable) { + (void) gmp102_enable(data->dev); + schedule_delayed_work(&data->temp_work, + msecs_to_jiffies(data->temp_delay)); + } + //add end +} +#endif + +MODULE_AUTHOR("GMEMS"); +MODULE_DESCRIPTION("GMP102 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/gmp102-i2c.c b/drivers/input/misc/gmp102-i2c.c new file mode 100755 index 00000000000..b2785723333 --- /dev/null +++ b/drivers/input/misc/gmp102-i2c.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2019 GlobalMEMS Co., Ltd. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include "gmp102.h" + +struct sensor_regulator { + struct regulator *vreg; + const char *name; + u32 min_uV; + u32 max_uV; +}; + +struct sensor_regulator gmp_vreg[] = { + {NULL, "vdd", 2850000, 2850000}, + {NULL, "vio", 1800000, 1800000}, +}; + + +static int gmp102_config_regulator(struct i2c_client *client, bool on) +{ + int rc = 0, i; + int num_vreg = ARRAY_SIZE(gmp_vreg); + + if (on) { + for (i = 0; i < num_vreg; i++) { + gmp_vreg[i].vreg = regulator_get(&client->dev, + gmp_vreg[i].name); + if (IS_ERR(gmp_vreg[i].vreg)) { + rc = PTR_ERR(gmp_vreg[i].vreg); + dev_err(&client->dev, "%s:regulator get failed rc=%d\n", + __func__, rc); + gmp_vreg[i].vreg = NULL; + goto error_vdd; + } + if (regulator_count_voltages(gmp_vreg[i].vreg) > 0) { + rc = regulator_set_voltage(gmp_vreg[i].vreg, + gmp_vreg[i].min_uV, gmp_vreg[i].max_uV); + if (rc) { + dev_err(&client->dev, "%s:set_voltage failed rc=%d\n", + __func__, rc); + regulator_put(gmp_vreg[i].vreg); + gmp_vreg[i].vreg = NULL; + goto error_vdd; + } + } + rc = regulator_enable(gmp_vreg[i].vreg); + if (rc) { + dev_err(&client->dev, "%s: regulator_enable failed rc =%d\n", + __func__, rc); + if (regulator_count_voltages(gmp_vreg[i].vreg) + > 0) { + regulator_set_voltage(gmp_vreg[i].vreg, + 0, gmp_vreg[i].max_uV); + } + regulator_put(gmp_vreg[i].vreg); + gmp_vreg[i].vreg = NULL; + goto error_vdd; + } + } + return rc; + } else { + i = num_vreg; + } + error_vdd: + while (--i >= 0) { + if (!IS_ERR_OR_NULL(gmp_vreg[i].vreg)) { + if (regulator_count_voltages( + gmp_vreg[i].vreg) > 0) { + regulator_set_voltage(gmp_vreg[i].vreg, 0, + gmp_vreg[i].max_uV); + } + regulator_disable(gmp_vreg[i].vreg); + regulator_put(gmp_vreg[i].vreg); + gmp_vreg[i].vreg = NULL; + } + } + return rc; +} + +static int gmp102_init_hw(struct gmp102_data_bus *data_bus) +{ + int ret = 0; + if (data_bus->client) { + ret = gmp102_config_regulator(data_bus->client, 1); + /* The minimum start up time of gmp102 is 10ms */ + usleep_range(15000, 20000); + } + return ret; +} + +static void gmp102_deinit_hw(struct gmp102_data_bus *data_bus) +{ + if (data_bus->client) + gmp102_config_regulator(data_bus->client, 0); +} + +static int gmp102_set_power(struct gmp102_data *data, int on) +{ + int rc = 0; + int num_vreg = ARRAY_SIZE(gmp_vreg); + int i; + + if (!on && data->power_enabled) { + + dev_err(data->dev,"power off\n"); + + for (i = 0; i < num_vreg; i++) { + rc = regulator_disable(gmp_vreg[i].vreg); + if (rc) { + dev_err(data->dev, "Regulator vdd disable failed rc=%d\n", + rc); + return rc; + } + } + data->power_enabled = false; + } else if (on && !data->power_enabled) { + + dev_err(data->dev,"power on\n"); + + for (i = 0; i < num_vreg; i++) { + rc = regulator_enable(gmp_vreg[i].vreg); + if (rc) { + dev_err(data->dev, "Regulator vdd enable failed rc=%d\n", + rc); + return rc; + } + } + /* The minimum start up time of gmp102 is 10ms */ + usleep_range(15000, 20000); + data->power_enabled = true; + } else { + dev_warn(data->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); + } + + return rc; +} + +#ifdef CONFIG_OF +static int gmp102_parse_dt(struct device *dev, + struct gmp102_platform_data *pdata) +{ + int ret = 0; + u32 val; + + ret = of_property_read_u32(dev->of_node, "gmems,chip-id", &val); + if (ret) { + dev_err(dev, "no chip_id from dt\n"); + return ret; + } + pdata->chip_id = (u8)val; + + ret = of_property_read_u32(dev->of_node, "gmems,oversample", &val); + if (ret) { + dev_err(dev, "no default_oversampling from dt\n"); + return ret; + } + pdata->default_oversampling = (u8)val; + + ret = of_property_read_u32(dev->of_node, "gmems,period", + &pdata->temp_measurement_period); + if (ret) { + dev_err(dev, "no temp_measurement_period from dt\n"); + return ret; + } + + pdata->default_sw_oversampling = of_property_read_bool(dev->of_node, + "gmems,sw-oversample"); + return 0; +} +#else +static int gmp102_parse_dt(struct device *dev, + struct gmp102_platform_data *pdata) +{ + return -EINVAL; +} +#endif + +static int gmp102_i2c_read_block(void *client, u8 reg, int len, char *buf) +{ + return i2c_smbus_read_i2c_block_data(client, reg, len, buf); +} + +static int gmp102_i2c_read_byte(void *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int gmp102_i2c_write_byte(void *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +static const struct gmp102_bus_ops gmp102_i2c_bus_ops = { + .read_block = gmp102_i2c_read_block, + .read_byte = gmp102_i2c_read_byte, + .write_byte = gmp102_i2c_write_byte +}; + +static int gmp102_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct gmp102_data_bus data_bus = { + .bops = &gmp102_i2c_bus_ops, + .client = client + }; + struct gmp102_platform_data *pdata; + int ret; + + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct gmp102_platform_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + ret = gmp102_parse_dt(&client->dev, pdata); + if (ret) { + dev_err(&client->dev, "Failed to parse device tree\n"); + return ret; + } + pdata->init_hw = gmp102_init_hw; + pdata->deinit_hw = gmp102_deinit_hw; + pdata->set_power = gmp102_set_power; + client->dev.platform_data = pdata; + } + return gmp102_probe(&client->dev, &data_bus); +} + +static void gmp102_i2c_shutdown(struct i2c_client *client) +{ + gmp102_disable(&client->dev); +} + +static int gmp102_i2c_remove(struct i2c_client *client) +{ + return gmp102_remove(&client->dev); +} + +#ifdef CONFIG_PM +static int gmp102_i2c_suspend(struct device *dev) +{ + int ret = 0; + struct gmp102_data *data = dev_get_drvdata(dev); + + if (data->enable) + ret = gmp102_disable(dev); + + return ret; +} + +static int gmp102_i2c_resume(struct device *dev) +{ + int ret = 0; + struct gmp102_data *data = dev_get_drvdata(dev); + + if (data->enable) + ret = gmp102_enable(dev); + + return ret; +} + +static const struct dev_pm_ops gmp102_i2c_pm_ops = { + .suspend = gmp102_i2c_suspend, + .resume = gmp102_i2c_resume +}; +#endif + +static const struct i2c_device_id gmp102_id[] = { + { GMP102_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, gmp102_id); + +static const struct of_device_id gmp102_of_match[] = { + { .compatible = "gmems,gmp102", }, + { }, +}; + +static struct i2c_driver gmp102_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = GMP102_NAME, +#ifdef CONFIG_PM + .pm = &gmp102_i2c_pm_ops, +#endif + .of_match_table = gmp102_of_match, + }, + .id_table = gmp102_id, + .probe = gmp102_i2c_probe, + .shutdown = gmp102_i2c_shutdown, + .remove = gmp102_i2c_remove +}; + +static int __init gmp102_i2c_init(void) +{ + return i2c_add_driver(&gmp102_i2c_driver); +} + +static void __exit gmp102_i2c_exit(void) +{ + i2c_del_driver(&gmp102_i2c_driver); +} + + +MODULE_AUTHOR("GMEMS"); +MODULE_DESCRIPTION("GMP102 I2C bus driver"); +MODULE_LICENSE("GPL"); + +module_init(gmp102_i2c_init); +module_exit(gmp102_i2c_exit); diff --git a/drivers/input/misc/gmp102.h b/drivers/input/misc/gmp102.h new file mode 100755 index 00000000000..2c148f57e76 --- /dev/null +++ b/drivers/input/misc/gmp102.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2019 GlobalMEMS Co., Ltd. + + 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __GMP102_H__ +#define __GMP102_H__ +#include + +#define GMP102_NAME "gmp102" +#define GMP102_CALIBRATION_DATA_LENGTH 18 +#define GMP102_CALIBRATION_PARAM_COUNT (GMP102_CALIBRATION_DATA_LENGTH/2) + +struct gmp102_bus_ops { + int (*read_block)(void *client, u8 reg, int len, char *buf); + int (*read_byte)(void *client, u8 reg); + int (*write_byte)(void *client, u8 reg, u8 value); +}; + +struct gmp102_data_bus { + const struct gmp102_bus_ops *bops; + void *client; +}; + +struct gmp102_calibration_data { + s16 s16Value[GMP102_CALIBRATION_PARAM_COUNT]; + u8 u8Power[GMP102_CALIBRATION_PARAM_COUNT]; +}; + +/* Each client has this additional data */ +struct gmp102_data { + struct gmp102_data_bus data_bus; + struct device *dev; + struct mutex lock; + struct gmp102_calibration_data calibration; + struct sensors_classdev cdev; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif // CONFIG_HAS_EARLYSUSPEND + struct input_dev *input; + struct delayed_work work; + + u8 oversampling_setting; + u8 sw_oversampling_setting; + s32 raw_temperature; + s32 raw_pressure; + u32 temp_measurement_period; + u32 last_temp_measurement; + u32 delay; + u32 enable; + u32 power_enabled; + //add by liangdi for temperature 20210604 + struct mutex temp_lock; + struct sensors_classdev temp_cdev; + struct input_dev *temp_input; + struct delayed_work temp_work; + u32 temp_delay; + u32 temp_enable; + //add end +}; + +/** + * struct gmp102_platform_data - represents platform data for the gmp102 driver + * @chip_id: Configurable chip id for non-default chip revisions + * @default_oversampling: Default oversampling value to be used at startup, + * value range is 0-7 with rising sensitivity. + * @default_sw_oversampling: Default software oversampling value to be used + * at startup,value range is 0(Disabled) or 1(Enabled). Only take effect + * when default_oversampling is 7. + * @temp_measurement_period: Temperature measurement period (milliseconds), set + * to zero if unsure. + * @init_hw: Callback for hw specific startup + * @deinit_hw: Callback for hw specific shutdown + */ +struct gmp102_platform_data { + u8 chip_id; + u8 default_oversampling; + u8 default_sw_oversampling; + u32 temp_measurement_period; + u32 power_enabled; + int (*init_hw)(struct gmp102_data_bus *); + void (*deinit_hw)(struct gmp102_data_bus *); + int (*set_power)(struct gmp102_data*, int); +}; + +int gmp102_probe(struct device *dev, struct gmp102_data_bus *data_bus); +int gmp102_remove(struct device *dev); +#ifdef CONFIG_PM +int gmp102_enable(struct device *dev); +int gmp102_disable(struct device *dev); +#endif // CONFIG_PM + +#endif // __GMP102_H__ diff --git a/drivers/input/misc/icm42607/ICM-42607.c b/drivers/input/misc/icm42607/ICM-42607.c new file mode 100755 index 00000000000..cc04f864a2c --- /dev/null +++ b/drivers/input/misc/icm42607/ICM-42607.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved. + * + * This software, related documentation and any modifications thereto (collectively "Software") is subject + * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright + * and other intellectual property rights laws. + * + * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software + * and any use, reproduction, disclosure or distribution of the Software without an express license agreement + * from InvenSense is strictly prohibited. + * + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL + * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE SOFTWARE. + * + */ + +#include +//#include +#include +#include "ICM-42607.h" + +struct icm42607_t *p_icm42607; + +void inv_serif_init(struct icm42607_t *icm42607) +{ + /* assign icm42607 ptr */ + p_icm42607 = icm42607; +} + +uint8_t inv_serif_read_1B(uint16_t reg_addr) +{ + u8 tmp_reg_addr, tmp_reg_val; + tmp_reg_addr = reg_addr % 0xFF; + + if (p_icm42607 == 0) { + return -127; + } else { + /* write data from register*/ + p_icm42607->ICM42607_BUS_READ_FUNC(p_icm42607->dev_addr, + tmp_reg_addr, &tmp_reg_val, 1); + } + + p_icm42607->delay_msec(1); + return tmp_reg_val; +} + +uint8_t inv_serif_read(uint16_t reg_addr, uint8_t *buf, int len) +{ + uint8_t tmp_reg_addr; + tmp_reg_addr = reg_addr % 0xFF; + + if (p_icm42607 == 0) { + return -127; + } else { + /* write data from register*/ + p_icm42607->ICM42607_BUS_READ_FUNC(p_icm42607->dev_addr, + tmp_reg_addr, buf, len); + } + + p_icm42607->delay_msec(1); + + return 0; +} + +void inv_serif_write(uint16_t reg_addr, uint8_t *buf, int len) +{ + uint8_t tmp_reg_addr; + + tmp_reg_addr = reg_addr % 0xFF; + + if (p_icm42607 == 0) { + return; + } else { + /* write data from register*/ + p_icm42607->ICM42607_BUS_WRITE_FUNC(p_icm42607->dev_addr, + tmp_reg_addr, buf, len); + } + + p_icm42607->delay_msec(1); +} + +void inv_serif_write_1B(uint16_t reg_addr, uint8_t reg_val) +{ + uint8_t tmp_reg_addr; + + tmp_reg_addr = reg_addr % 0xFF; + + if (p_icm42607 == 0) { + return; + } else { + /* write data from register*/ + p_icm42607->ICM42607_BUS_WRITE_FUNC(p_icm42607->dev_addr, + tmp_reg_addr, ®_val, 1); + } + + p_icm42607->delay_msec(1); +} + +void ICM42607_Accel_on(void) +{ + uint8_t reg_val; + // Enable Accel + reg_val = inv_serif_read_1B(PWR_MGMT0) | (BIT_ACCEL_MODE_LN); // Accel on in LNM + p_icm42607->delay_msec(1); + inv_serif_write_1B(PWR_MGMT0, reg_val); + p_icm42607->delay_msec(1); //workaround 9136 +} + +void ICM42607_Accel_off(void) +{ + uint8_t reg_val; + // Disable Accel + reg_val = inv_serif_read_1B(PWR_MGMT0) & (~BIT_ACCEL_MODE_LN); // Accel off + p_icm42607->delay_msec(1); + inv_serif_write_1B(PWR_MGMT0, reg_val); + p_icm42607->delay_msec(1); //workaround 9136 +} + +void ICM42607_Gyro_on(void) +{ + uint8_t reg_val; + // Enable Gyro + reg_val = inv_serif_read_1B(PWR_MGMT0) | (BIT_GYRO_MODE_LN); // Gyro on in LNM + p_icm42607->delay_msec(1); + inv_serif_write_1B(PWR_MGMT0, reg_val); + p_icm42607->delay_msec(1); //workaround 9136 +} + +void ICM42607_Gyro_off(void) +{ + uint8_t reg_val; + // Disable Gyro + reg_val = inv_serif_read_1B(PWR_MGMT0) & ~(BIT_GYRO_MODE_LN); // Gyro off + p_icm42607->delay_msec(1); + inv_serif_write_1B(PWR_MGMT0, reg_val); + p_icm42607->delay_msec(1); //workaround 9136 +} + +void ICM42607_init(void) +{ + inv_serif_write_1B(SIGNAL_PATH_RESET, BIT_SOFT_RESET); // chip soft reset + p_icm42607->delay_msec(10); +} + +void ICM42607_accel_odr(int odr_idx) +{ + uint8_t reg_val; + if (odr_idx <= 0x0F) { + reg_val = (inv_serif_read_1B(ACCEL_CONFIG0)& 0xF0) | odr_idx; + inv_serif_write_1B(ACCEL_CONFIG0, reg_val); + } +} + +void ICM42607_gyro_odr(int odr_idx) +{ + uint8_t reg_val; + if (odr_idx <= 0x0F) { + reg_val = (inv_serif_read_1B(GYRO_CONFIG0)& 0xF0) | odr_idx; + inv_serif_write_1B(GYRO_CONFIG0, reg_val); + } +} + +void ICM42607_accel_fsr(int fsr_idx) +{ + uint8_t reg_val; + if (fsr_idx < 0x08) { + reg_val = (inv_serif_read_1B(ACCEL_CONFIG0) & 0x1F) | (fsr_idx << 5); + inv_serif_write_1B(ACCEL_CONFIG0, (uint8_t)reg_val); + } +} + +void ICM42607_gyro_fsr(int fsr_idx) +{ + uint8_t reg_val; + if (fsr_idx < 0x08) { + reg_val = (inv_serif_read_1B(GYRO_CONFIG0) & 0x1F) | (fsr_idx << 5); + inv_serif_write_1B(GYRO_CONFIG0, (uint8_t)reg_val); + } +} + +int ICM42607_GetGyroData_UI(struct axis_data *data) +{ + uint8_t buf[6]; + int err; + err = inv_serif_read(GYRO_DATA_X1, buf, 6); +#if 0 // little endian + data->rx = buf[1]<<8 | buf[0]; + data->ry = buf[3]<<8 | buf[2]; + data->rz = buf[5]<<8 | buf[4]; +#else + data->rx = buf[0]<<8 | buf[1]; + data->ry = buf[2]<<8 | buf[3]; + data->rz = buf[4]<<8 | buf[5]; +#endif + return err; +} + +int ICM42607_GetAccelData_UI(struct axis_data *data) +{ + uint8_t buf[6]; + int err; + err = inv_serif_read(ACCEL_DATA_X1, buf, 6); +#if 0 // little endian + data->x = buf[1]<<8 | buf[0]; + data->y = buf[3]<<8 | buf[2]; + data->z = buf[5]<<8 | buf[4]; +#else + data->x = buf[0]<<8 | buf[1]; + data->y = buf[2]<<8 | buf[3]; + data->z = buf[4]<<8 | buf[5]; +#endif + return err; +} \ No newline at end of file diff --git a/drivers/input/misc/icm42607/ICM-42607.h b/drivers/input/misc/icm42607/ICM-42607.h new file mode 100755 index 00000000000..426b28db122 --- /dev/null +++ b/drivers/input/misc/icm42607/ICM-42607.h @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved. + * + * This software, related documentation and any modifications thereto (collectively "Software") is subject + * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright + * and other intellectual property rights laws. + * + * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software + * and any use, reproduction, disclosure or distribution of the Software without an express license agreement + * from InvenSense is strictly prohibited. + * + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL + * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE SOFTWARE. + * + */ + +#ifndef ICM42607_H_ +#define ICM42607_H_ + +#include +struct axis_data { + s16 x; + s16 y; + s16 z; + s16 rx; + s16 ry; + s16 rz; +}; +void ICM42607_init(void); +void ICM42607_Accel_on(void); +void ICM42607_Accel_off(void); +void ICM42607_Gyro_on(void); +void ICM42607_Gyro_off(void); +void ICM42607_accel_odr(int odr_idx); +void ICM42607_gyro_odr(int odr_idx); +void ICM42607_accel_fsr(int fsr_idx); +void ICM42607_gyro_fsr(int fsr_idx); +int ICM42607_GetGyroData_UI(struct axis_data *data); +int ICM42607_GetAccelData_UI(struct axis_data *data); + +uint8_t inv_serif_read_1B(uint16_t reg_addr); +uint8_t inv_serif_read(uint16_t reg_addr, uint8_t *buf, int len); +void inv_serif_write(uint16_t reg_addr, uint8_t *buf, int len); +void inv_serif_write_1B(uint16_t reg_addr, uint8_t reg_val); + +/* BANK0 */ +#define SIGNAL_PATH_RESET 0x02 +#define ACCEL_DATA_X1 0x0B +#define GYRO_DATA_X1 0x11 +#define PWR_MGMT0 0x1F +#define GYRO_CONFIG0 0x20 +#define ACCEL_CONFIG0 0x21 +#define WHO_AM_I 0x75 +#define REG_MAX0 0x7E + +#define BIT_ACCEL_MODE_LN 0x03 +#define BIT_GYRO_MODE_LN 0x0C +#define BIT_SOFT_RESET 0x10 + +#define ICM42607_MDELAY_DATA_TYPE u32 + +#define ICM42607_WR_FUNC_PTR int (*bus_write)(u8, u8, u8 *, u8) + +#define ICM42607_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\ + bus_write(dev_addr, reg_addr, reg_data, wr_len) + +#define ICM42607_RD_FUNC_PTR int (*bus_read)(u8, u8, u8 *, u8) + +#define ICM42607_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, r_len)\ + bus_read(dev_addr, reg_addr, reg_data, r_len) + +struct icm42607_t { + u8 chip_id; + u8 dev_addr; + ICM42607_WR_FUNC_PTR;/**< bus write function pointer */ + ICM42607_RD_FUNC_PTR;/**< bus read function pointer */ + void (*delay_msec)(ICM42607_MDELAY_DATA_TYPE);/**< delay function pointer */ +}; + +enum ICM4x6xx_power { + POWER_OFF = 0, + POWER_ON, +}; + +void inv_serif_init(struct icm42607_t *icm42607); + +#endif /* ICM42607_H_ */ \ No newline at end of file diff --git a/drivers/input/misc/icm42607/Kconfig b/drivers/input/misc/icm42607/Kconfig new file mode 100755 index 00000000000..4a529090be3 --- /dev/null +++ b/drivers/input/misc/icm42607/Kconfig @@ -0,0 +1,18 @@ +# +# Kconfig for InvenSense sensors driver. +# + +config SENSORS_ICM42607 + tristate "ICM42607 Sensor Support" + depends on I2C || SPI_MASTER + help + If you say yes here, you get support for InvenSense's sensor driver of ICM42607. + +config SENSORS_ICM42607_SPI + tristate + +config SENSORS_ICM42607_I2C + tristate "support I2C bus communication" + depends on SENSORS_ICM42607 && I2C + help + If you say yes here, you get support Bosch Sensortec's ICM42607 pressure sensor hooked to an I2C bus. diff --git a/drivers/input/misc/icm42607/Makefile b/drivers/input/misc/icm42607/Makefile new file mode 100755 index 00000000000..e71a9c78bc9 --- /dev/null +++ b/drivers/input/misc/icm42607/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Invensense sensor driver. +# + +obj-$(CONFIG_SENSORS_ICM42607) += icm42607_driver.o ICM-42607.o + +obj-$(CONFIG_SENSORS_ICM42607_SPI) += icm42607_spi.o +obj-$(CONFIG_SENSORS_ICM42607_I2C) += icm42607_i2c.o diff --git a/drivers/input/misc/icm42607/icm42607_driver.c b/drivers/input/misc/icm42607/icm42607_driver.c new file mode 100755 index 00000000000..4a2ae5498e6 --- /dev/null +++ b/drivers/input/misc/icm42607/icm42607_driver.c @@ -0,0 +1,1294 @@ +/* + * + * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved. + * + * This software, related documentation and any modifications thereto (collectively "Software") is subject + * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright + * and other intellectual property rights laws. + * + * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software + * and any use, reproduction, disclosure or distribution of the Software without an express license agreement + * from InvenSense is strictly prohibited. + * + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL + * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE SOFTWARE. + * + */ + +#define DRIVER_VERSION "2.0.01" +#define CONFIG_USE_QUALCOMM_HAL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ICM-42607.h" +#include "icm42607_driver.h" +static struct icm_client_data *icm42607_client_data; + +int icm_power_ctl(struct icm_client_data *sensor, int on); + +/*! icm acc sensor power mode enum */ +enum ICM_ACC_PM_TYPE { + ICM_ACC_PM_NORMAL = 0, + ICM_ACC_PM_LP1, + ICM_ACC_PM_SUSPEND, + ICM_ACC_PM_LP2, + ICM_ACC_PM_MAX +}; + +/*! icm gyro sensor power mode enum */ +enum ICM_GYRO_PM_TYPE { + ICM_GYRO_PM_NORMAL = 0, + ICM_GYRO_PM_FAST_START, + ICM_GYRO_PM_SUSPEND, + ICM_GYRO_PM_MAX +}; + +enum icm_place { + ICM_PLACE_PU = 0, + ICM_PLACE_PR = 1, + ICM_PLACE_LD = 2, + ICM_PLACE_LL = 3, + ICM_PLACE_PU_BACK = 4, + ICM_PLACE_PR_BACK = 5, + ICM_PLACE_LD_BACK = 6, + ICM_PLACE_LL_BACK = 7, + ICM_PLACE_UNKNOWN = 8, + ICM_AXIS_REMAP_TAB_SZ = 8 +}; + +struct icm_place_name { + char name[32]; + enum icm_place place; +}; + +struct icm42607_type_mapping_type { + uint16_t chip_id; + uint16_t revision_id; + const char *sensor_name; +}; + +static const struct icm42607_type_mapping_type sensor_type_map[] = { + {SENSOR_CHIP_ID_ICM, SENSOR_CHIP_REV_ID_ICM, "icm42607"}, +}; + +#if defined(CONFIG_USE_QUALCOMM_HAL) +#define POLL_INTERVAL_MIN_MS 10 +#define POLL_INTERVAL_MAX_MS 4000 +#define POLL_DEFAULT_INTERVAL_MS 200 +#define ICM42607_ACCEL_MIN_VALUE -32768 +#define ICM42607_ACCEL_MAX_VALUE 32767 +#define ICM42607_GYRO_MIN_VALUE -32768 +#define ICM42607_GYRO_MAX_VALUE 32767 +#define ICM42607_ACCEL_DEFAULT_POLL_INTERVAL_MS 700 +#define ICM42607_GYRO_DEFAULT_POLL_INTERVAL_MS 700 +#define ICM42607_ACCEL_MIN_POLL_INTERVAL_MS 10 +#define ICM42607_ACCEL_MAX_POLL_INTERVAL_MS 5000 +#define ICM42607_GYRO_MIN_POLL_INTERVAL_MS 10 +#define ICM42607_GYRO_MAX_POLL_INTERVAL_MS 5000 + +static struct sensors_classdev icm42607_accel_cdev = { + .name = "icm42607-accel", + .vendor = "InvenSense", + .version = 1, + .handle = SENSORS_ACCELERATION_HANDLE, + .type = SENSOR_TYPE_ACCELEROMETER, + .max_range = "156.9064", /* m/s2 16g */ + .resolution = "0.153125", /* m/s2 */ + .sensor_power = "0.2", /* 0.2 mA */ + .min_delay = 1000,//POLL_INTERVAL_MIN_MS * 1000, /* in microseconds */ + //.max_delay = POLL_INTERVAL_MAX_MS, + .delay_msec = POLL_DEFAULT_INTERVAL_MS, /* in millisecond */ + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .max_latency = 0, + .flags = 0, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_set_latency = NULL, + .sensors_flush = NULL, + .sensors_self_test = NULL, +}; + +static struct sensors_classdev icm42607_gyro_cdev = { + .name = "icm42607-gyro", + .vendor = "InvenSense", + .version = 1, + .handle = SENSORS_GYROSCOPE_HANDLE, + .type = SENSOR_TYPE_GYROSCOPE, + .max_range = "34.906585", /* rad/s 2000dps */ + .resolution = "0.0010681152", /* rad/s */ + .sensor_power = "0.42", /* 0.42 mA */ + .min_delay = 2000,//ICM42607_GYRO_MIN_POLL_INTERVAL_MS * 1000, + //.max_delay = ICM42607_GYRO_MAX_POLL_INTERVAL_MS, + .delay_msec = 200,//ICM42607_GYRO_DEFAULT_POLL_INTERVAL_MS, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .max_latency = 0, + .flags = 0, /* SENSOR_FLAG_CONTINUOUS_MODE */ + .sensors_enable = NULL, + .sensors_poll_delay = NULL, + .sensors_enable_wakeup = NULL, + .sensors_set_latency = NULL, + .sensors_flush = NULL, +}; +#endif + + +struct sensor_axis_remap { + /* src means which source will be mapped to target x, y, z axis + * if an target OS axis is remapped from (-)x, + * src is 0, sign_* is (-)1 + * if an target OS axis is remapped from (-)y, + * src is 1, sign_* is (-)1 + * if an target OS axis is remapped from (-)z, + * src is 2, sign_* is (-)1 + */ + int src_x:3; + int src_y:3; + int src_z:3; + + int sign_x:2; + int sign_y:2; + int sign_z:2; +}; + +static const struct sensor_axis_remap +icm_accel_axis_remap_tab[ICM_AXIS_REMAP_TAB_SZ] = { + /* src_x src_y src_z sign_x sign_y sign_z */ + { 0, 1, 2, 1, 1, 1 }, /* P0 */ + { 1, 0, 2, 1, -1, 1 }, /* P1 */ + { 0, 1, 2, -1, -1, 1 }, /* P2 */ + { 1, 0, 2, -1, 1, 1 }, /* P3 */ + + { 0, 1, 2, -1, 1, -1 }, /* P4 */ + { 1, 0, 2, -1, -1, -1 }, /* P5 */ + { 0, 1, 2, 1, -1, -1 }, /* P6 */ + { 1, 0, 2, 1, 1, -1 }, /* P7 */ +}; + +static const struct sensor_axis_remap +icm_gyro_axis_remap_tab[ICM_AXIS_REMAP_TAB_SZ] = { + /* src_x src_y src_z sign_x sign_y sign_z */ + { 0, 1, 2, -1, 1, -1 }, /* P0 */ + { 1, 0, 2, -1, -1, -1 }, /* P1*/ + { 0, 1, 2, 1, -1, -1 }, /* P2 */ + { 1, 0, 2, 1, 1, -1 }, /* P3 */ + + { 0, 1, 2, 1, 1, 1 }, /* P4 */ + { 1, 0, 2, 1, -1, 1 }, /* P5 */ + { 0, 1, 2, -1, -1, 1 }, /* P6 */ + { 1, 0, 2, -1, 1, 1 }, /* P7 */ +}; + +static const struct icm_place_name +icm_place_name2num[ICM_AXIS_REMAP_TAB_SZ] = { + {"Portrait Up", ICM_PLACE_PU}, + {"Landscape Right", ICM_PLACE_PR}, + {"Portrait Down", ICM_PLACE_LD}, + {"Landscape Left", ICM_PLACE_LL}, + {"Portrait Up Back Side", ICM_PLACE_PU_BACK}, + {"Landscape Right Back Side", ICM_PLACE_PR_BACK}, + {"Portrait Down Back Side", ICM_PLACE_LD_BACK}, + {"Landscape Left Back Side", ICM_PLACE_LL_BACK}, +}; + +static int icm42607_accel_set_enable(struct icm_client_data *client_data, bool enable); + +static void icm_delay(u32 msec) +{ + if (msec <= 20) { + usleep_range(msec * 1000, msec * 1000); + } else { + msleep(msec); + } +} + +static void icm_dump_reg(struct icm_client_data *client_data) +{ + u8 i, dbg_buf; + + for (i = 0; i < REG_MAX0; i++) { + client_data->device.bus_read(client_data->device.dev_addr, i, &dbg_buf, 1); + dev_err(client_data->dev, "reg:0x%0x,data:0x%0x\n", i, dbg_buf); + } +} + +#define INPUT_EVENT_STEP_DETECTOR 5 +#define INPUT_EVENT_SGM REL_DIAL/*7*/ +#define INPUT_EVENT_FAST_ACC_CALIB_DONE 6 +#define INPUT_EVENT_FAST_GYRO_CALIB_DONE 4 + +static int icm_input_init(struct icm_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + //dev = input_allocate_device(); + dev = devm_input_allocate_device(&client_data->i2c->dev); + if (NULL == dev) + return -ENOMEM; + + dev->name = "icm42607-accel"; + dev->id.bustype = client_data->bustype; + //input_set_capability(dev, EV_MSC, INPUT_EVENT_SGM); + //input_set_capability(dev, EV_MSC, INPUT_EVENT_STEP_DETECTOR); + //input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_ACC_CALIB_DONE); + //input_set_capability(dev, EV_MSC, INPUT_EVENT_FAST_GYRO_CALIB_DONE); + + //input_set_capability(dev, EV_REL, REL_X); + //input_set_capability(dev, EV_REL, REL_Y); + //input_set_capability(dev, EV_REL, REL_Z); + +#if defined(CONFIG_USE_QUALCOMM_HAL) + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_X, + ICM42607_ACCEL_MIN_VALUE, ICM42607_ACCEL_MAX_VALUE, 0, 0); + input_set_abs_params(dev, ABS_Y, + ICM42607_ACCEL_MIN_VALUE, ICM42607_ACCEL_MAX_VALUE, 0, 0); + input_set_abs_params(dev, ABS_Z, + ICM42607_ACCEL_MIN_VALUE, ICM42607_ACCEL_MAX_VALUE, 0, 0); +#endif + input_set_drvdata(dev, client_data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + dev_err(client_data->dev, "icm42607 input free!\n"); + return err; + } + client_data->input = dev; + dev_err(client_data->dev, + "icm42607 input register successfully, %s!\n", + client_data->input->name); + return err; +} + +#if defined(CONFIG_USE_QUALCOMM_HAL) +static int icm_gyro_input_init(struct icm_client_data *client_data) +{ + struct input_dev *dev; + int err = 0; + + //dev = input_allocate_device(); + dev = devm_input_allocate_device(&client_data->i2c->dev); + if (NULL == dev) + return -ENOMEM; + dev->name = "icm42607-gyro"; + dev->id.bustype = client_data->bustype; + + input_set_capability(dev, EV_ABS, ABS_MISC); + input_set_abs_params(dev, ABS_RX, + ICM42607_GYRO_MIN_VALUE, ICM42607_GYRO_MAX_VALUE, 0, 0); + input_set_abs_params(dev, ABS_RY, + ICM42607_GYRO_MIN_VALUE, ICM42607_GYRO_MAX_VALUE, 0, 0); + input_set_abs_params(dev, ABS_RZ, + ICM42607_GYRO_MIN_VALUE, ICM42607_GYRO_MAX_VALUE, 0, 0); + input_set_drvdata(dev, client_data); + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + dev_err(client_data->dev, "icm42607 input free!\n"); + return err; + } + client_data->gyro_input = dev; + dev_err(client_data->dev, + "icm42607 input register successfully, %s!\n", + client_data->gyro_input->name); + return err; +} +#endif + +static void icm_input_destroy(struct icm_client_data *client_data) +{ + struct input_dev *dev = client_data->input; + + input_unregister_device(dev); + input_free_device(dev); +} + +static int icm_check_chip_id(struct icm_client_data *client_data) +{ + int8_t err = 0; + int8_t i = 0; + uint8_t chip_id = 0; + uint8_t read_count = 0; + uint8_t icm_sensor_cnt = sizeof(sensor_type_map) + / sizeof(struct icm42607_type_mapping_type); + /* read and check chip id */ + while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { + if (client_data->device.bus_read(client_data->device.dev_addr, + WHO_AM_I, &chip_id, 1) < 0) { + + dev_err(client_data->dev, + "InvenSense Device not found" + "read chip_id:%d\n", chip_id); + continue; + } else { + for (i = 0; i < icm_sensor_cnt; i++) { + if (sensor_type_map[i].chip_id == chip_id) { + client_data->chip_id = chip_id; + dev_err(client_data->dev, + "InvenSense Device detected, " + "HW IC name: %s\n", sensor_type_map[i].sensor_name); + break; + } + } + if (i < icm_sensor_cnt) + break; + else { + if (read_count == CHECK_CHIP_ID_TIME_MAX) { + dev_err(client_data->dev, + "Failed! InvenSense Device not found" + " mismatch chip_id:%d\n", chip_id); + err = -ENODEV; + return err; + } + } + icm_delay(1); + } + } + return err; + +} + +static int icm_pmu_set_suspend(struct icm_client_data *client_data) +{ + int err = 0; + if (client_data == NULL) + return -EINVAL; + else { + ICM42607_Accel_off(); + ICM42607_Gyro_off(); + client_data->pw.acc_pm = ICM_ACC_PM_SUSPEND; + client_data->pw.gyro_pm = ICM_GYRO_PM_SUSPEND; + } + + err = icm_power_ctl(client_data, POWER_OFF); + if (err) { + dev_err(client_data->dev, "Failed to power on device\n"); + } + + return err; +} + +static ssize_t icm42607_chip_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct icm_client_data *client_data = icm42607_client_data; + + return snprintf(buf, 16, "0x%x\n", client_data->chip_id); +} + +static int icm42607_set_acc_op_mode(struct icm_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + mutex_lock(&client_data->mutex_op_mode); + + if (op_mode < ICM_ACC_PM_MAX) { + switch (op_mode) { + case ICM_ACC_PM_NORMAL: + ICM42607_Accel_on(); + client_data->pw.acc_pm = ICM_ACC_PM_NORMAL; + icm_delay(10); + break; + case ICM_ACC_PM_SUSPEND: + ICM42607_Accel_off(); + client_data->pw.acc_pm = ICM_ACC_PM_SUSPEND; + icm_delay(10); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + + mutex_unlock(&client_data->mutex_op_mode); + + return err; +} + + +/* + * icm_remap_accel_data() - remap accelerometer raw data to axis data + * @data: data needs remap + * @place: sensor position + */ +static void icm_remap_accel_data(struct axis_data *data, int place) +{ + const struct sensor_axis_remap *remap; + s16 tmp[3]; + /* sensor with place 0 needs not to be remapped */ + if ((place <= 0) || (place >= ICM_AXIS_REMAP_TAB_SZ)) + return; + + remap = &icm_accel_axis_remap_tab[place]; + + tmp[0] = data->x; + tmp[1] = data->y; + tmp[2] = data->z; + data->x = tmp[remap->src_x] * remap->sign_x; + data->y = tmp[remap->src_y] * remap->sign_y; + data->z = tmp[remap->src_z] * remap->sign_z; +} + +/* + * icm_remap_gyro_data() - remap gyroscope raw data to axis data + * @data: data to remap + * @place: sensor position + */ +static void icm_remap_gyro_data(struct axis_data *data, int place) +{ + const struct sensor_axis_remap *remap; + s16 tmp[3]; + /* sensor with place 0 needs not to be remapped */ + if ((place <= 0) || (place >= ICM_AXIS_REMAP_TAB_SZ)) + return; + + remap = &icm_gyro_axis_remap_tab[place]; + tmp[0] = data->rx; + tmp[1] = data->ry; + tmp[2] = data->rz; + data->rx = tmp[remap->src_x] * remap->sign_x; + data->ry = tmp[remap->src_y] * remap->sign_y; + data->rz = tmp[remap->src_z] * remap->sign_z; +} + +static ssize_t icm42607_place_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct icm_client_data *client_data = icm42607_client_data; + int place = 0;//INVN_SENSOR_PLACE_UNKNOWN; + + if (NULL != client_data) + place = client_data->place; + + return snprintf(buf, 16, "%d\n", place); +} + +static ssize_t icm42607_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct icm_client_data *client_data = icm42607_client_data; + + return snprintf(buf, 16, "%d\n", atomic_read(&client_data->delay)); + +} + +static ssize_t icm42607_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct icm_client_data *client_data = icm42607_client_data; + int err; + unsigned long data; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + if (data == 0) { + err = -EINVAL; + return err; + } + + if (data < 1) + data = 1; + + atomic_set(&client_data->delay, (unsigned int)data); + + return count; +} + +static ssize_t icm42607_acc_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct axis_data data; + + ICM42607_GetAccelData_UI(&data); + + return snprintf(buf, 48, "%hd %hd %hd\n", + data.x,data.y, data.z); +} + +static ssize_t icm42607_gyro_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct axis_data data; + + ICM42607_GetGyroData_UI(&data); + + return snprintf(buf, 48, "%hd %hd %hd\n",data.rx,data.ry, data.rz); +} + +static ssize_t icm42607_driver_version_show(struct device *dev + , struct device_attribute *attr, char *buf) +{ + struct icm_client_data *client_data = icm42607_client_data; + int ret; + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + + ret = snprintf(buf, 128, "Driver version: %s\n", + DRIVER_VERSION); + + return ret; +} + + +static ssize_t icm_accel_attr_get_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct icm_client_data *client_data = icm42607_client_data; + + return snprintf(buf, 4, "%d\n", client_data->power_enabled); +} + +/* + * mpu6050_accel_attr_set_enable() - + * Set/get enable function is just needed by sensor HAL. + */ + +static ssize_t icm_accel_attr_set_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long enable; + struct icm_client_data *client_data = icm42607_client_data; + + if (kstrtoul(buf, 10, &enable)) + return -EINVAL; + + if (enable) + ret = icm42607_accel_set_enable(client_data, true); + else + ret = icm42607_accel_set_enable(client_data, false); + + return ret ? -EBUSY : count; +} + +static ssize_t icm42607_reg_show(struct device *dev + , struct device_attribute *attr, char *buf) +{ + struct icm_client_data *client_data = icm42607_client_data; + int ret; + + if (client_data == NULL) { + printk(KERN_ERR "Invalid client_data pointer"); + return -ENODEV; + } + icm_dump_reg(client_data); + + return ret; +} + +static ssize_t icm42607_reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct icm_client_data *client_data = icm42607_client_data; + int err; + unsigned long data; + + err = kstrtoul(buf, 10, &data); + if (err) + return err; + + if (data == 0) { + err = -EINVAL; + return err; + } + client_data->device.bus_read(client_data->device.dev_addr, + data, &client_data->reg_data, 1); + + return count; +} + + +static DEVICE_ATTR(chip_id, S_IRUGO, + icm42607_chip_id_show, NULL); +static DEVICE_ATTR(place, S_IRUGO, + icm42607_place_show, NULL); +static DEVICE_ATTR(delay, S_IRUGO, + icm42607_delay_show, icm42607_delay_store); +static DEVICE_ATTR(acc_value, S_IRUGO, + icm42607_acc_value_show, NULL); +static DEVICE_ATTR(driver_version, S_IRUGO, + icm42607_driver_version_show, NULL); +/* gyro part */ +static DEVICE_ATTR(gyro_value, S_IRUGO, + icm42607_gyro_value_show, NULL); +static DEVICE_ATTR(enable, S_IRUGO, + icm_accel_attr_get_enable,icm_accel_attr_set_enable); +static DEVICE_ATTR(reg_data, S_IRUGO, + icm42607_reg_show,icm42607_reg_store); + +static struct attribute *icm42607_attributes[] = { + &dev_attr_chip_id.attr, + &dev_attr_driver_version.attr, + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_place.attr, + &dev_attr_gyro_value.attr, + &dev_attr_acc_value.attr, + &dev_attr_reg_data.attr, + NULL, +}; + +static struct attribute_group icm42607_attribute_group = { + .attrs = icm42607_attributes +}; + +#if defined(CONFIG_USE_QUALCOMM_HAL) +static void icm42607_accel_work_fn(struct work_struct *work) +{ + struct icm_client_data *sensor; + ktime_t timestamp; + + int err; + sensor = icm42607_client_data; + timestamp = ktime_get(); + err = ICM42607_GetAccelData_UI(&sensor->axis); + if (err) + dev_err(sensor->dev, "read data err"); + + icm_remap_accel_data(&sensor->axis, sensor->place); + + input_report_abs(sensor->input, ABS_X, + sensor->axis.x ); + input_report_abs(sensor->input, ABS_Y, + sensor->axis.y ); + input_report_abs(sensor->input, ABS_Z, + sensor->axis.z ); + input_event(sensor->input, + EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(sensor->input, EV_SYN, + SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); + input_sync(sensor->input); + if (atomic_read(&sensor->accel_en)) + queue_delayed_work(sensor->data_wq, + &sensor->accel_poll_work, + msecs_to_jiffies(sensor->accel_poll_ms)); +} + +static void icm42607_gyro_work_fn(struct work_struct *work) +{ + struct icm_client_data *sensor; + ktime_t timestamp; + int err; + sensor = icm42607_client_data; + timestamp = ktime_get(); + err = ICM42607_GetGyroData_UI(&sensor->axis); + if (err) + dev_err(sensor->dev, "read data err"); + icm_remap_gyro_data(&sensor->axis, sensor->place); + input_report_abs(sensor->gyro_input, ABS_RX, + sensor->axis.rx); + input_report_abs(sensor->gyro_input, ABS_RY, + sensor->axis.ry); + input_report_abs(sensor->gyro_input, ABS_RZ, + sensor->axis.rz); + input_event(sensor->gyro_input, + EV_SYN, SYN_TIME_SEC, + ktime_to_timespec(timestamp).tv_sec); + input_event(sensor->gyro_input, EV_SYN, + SYN_TIME_NSEC, + ktime_to_timespec(timestamp).tv_nsec); + input_sync(sensor->gyro_input); + if (atomic_read(&sensor->gyro_en)) + queue_delayed_work(sensor->data_wq, + &sensor->gyro_poll_work, + msecs_to_jiffies(sensor->gyro_poll_ms)); +} + + +static int icm_dt_get_place(struct device *dev, struct icm_client_data *sensor) +{ + const char *place_name; + int rc; + int i; + rc = of_property_read_string(dev->of_node, "invn,place", &place_name); + if (rc) { + dev_err(dev, "Cannot get place configuration!\n"); + return -EINVAL; + } + + for (i = 0; i < ICM_AXIS_REMAP_TAB_SZ; i++) { + if (!strcmp(place_name, icm_place_name2num[i].name)) { + sensor->place = icm_place_name2num[i].place; + break; + } + } + if (i >= ICM_AXIS_REMAP_TAB_SZ) { + dev_err(dev, "Invalid place parameter, use default value 0\n"); + sensor->place = 0; + } + dev_err(dev, "icm place = %d \n", sensor->place); + return 0; +} + +#define ICM_VDD_MIN_UV 1750000 +#define ICM_VDD_MAX_UV 3600000 +#define ICM_VIO_MIN_UV 1200000 +#define ICM_VIO_MAX_UV 3600000 +static int icm_power_init(struct icm_client_data *sensor) +{ + int ret = 0; + + sensor->vdd = regulator_get(sensor->dev, "vdd"); + if (IS_ERR(sensor->vdd)) { + ret = PTR_ERR(sensor->vdd); + dev_err(sensor->dev, + "Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(sensor->vdd) > 0) { + ret = regulator_set_voltage(sensor->vdd, ICM_VDD_MIN_UV, + ICM_VDD_MAX_UV); + if (ret) { + dev_err(sensor->dev, + "Regulator set_vtg failed vdd ret=%d\n", ret); + goto reg_vdd_put; + } + } + + sensor->vio = regulator_get(sensor->dev, "vio"); + if (IS_ERR(sensor->vio)) { + ret = PTR_ERR(sensor->vio); + dev_err(sensor->dev, + "Regulator get failed vio ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(sensor->vio) > 0) { + ret = regulator_set_voltage(sensor->vio, ICM_VIO_MIN_UV, + ICM_VIO_MAX_UV); + if (ret) { + dev_err(sensor->dev, + "Regulator set_vtg failed vio ret=%d\n", ret); + goto reg_vdd_put; + } + } + + sensor->power_enabled = POWER_OFF; + return 0; + +reg_vdd_put: + regulator_put(sensor->vdd); + regulator_put(sensor->vio); + + return ret; +} + +#define POWER_EN_DELAY_US 10 +#define POWER_UP_TIME_MS 100 +int icm_power_ctl(struct icm_client_data *sensor, int on) +{ + int rc = 0; + + dev_info(sensor->dev, + "power status change from %d to %d\n", + sensor->power_enabled, on); + + if (on && !sensor->power_enabled) { + if(sensor->vdd != NULL){ + rc = regulator_enable(sensor->vdd); + if (rc) { + dev_err(sensor->dev, + "Regulator vdd enable failed rc=%d\n", rc); + return rc; + } + }else{ + dev_err(sensor->dev, + "sensor vdd on but is NULL\n"); + } + + if(sensor->vio != NULL){ + rc = regulator_enable(sensor->vio); + if (rc) { + dev_err(sensor->dev, + "Regulator vio enable failed rc=%d\n", rc); + return rc; + } + }else{ + dev_err(sensor->dev, + "sensor vio on but is NULL\n"); + } + + msleep(POWER_UP_TIME_MS); + + dev_err(sensor->dev,"Regulator power on\n"); + + sensor->power_enabled = 1; + + dev_err(sensor->dev,"Regulator power on power_enabled = %d \n",sensor->power_enabled); + + } else if (!on && sensor->power_enabled) { + + if(sensor->vdd != NULL){ + rc = regulator_disable(sensor->vdd); + if (rc) { + dev_err(sensor->dev, + "Regulator vdd disable failed rc=%d\n", rc); + return rc; + } + }else{ + dev_err(sensor->dev, + "sensor vdd off but is NULL\n"); + } + + if(sensor->vio != NULL){ + rc = regulator_disable(sensor->vio); + if (rc) { + dev_err(sensor->dev, + "Regulator vio disable failed rc=%d\n", rc); + return rc; + } + }else{ + dev_err(sensor->dev, + "sensor vio off but is NULL\n"); + } + + dev_err(sensor->dev,"Regulator power off\n"); + sensor->power_enabled = 0; + } else { + dev_info(sensor->dev, + "Ignore power status change from %d to %d\n", + sensor->power_enabled, on); + } + + return rc; +} +EXPORT_SYMBOL(icm_power_ctl); + +static int icm42607_set_gyro_op_mode(struct icm_client_data *client_data, + unsigned long op_mode) +{ + int err = 0; + mutex_lock(&client_data->mutex_op_mode); + if (op_mode < ICM_GYRO_PM_MAX) { + switch (op_mode) { + case ICM_GYRO_PM_NORMAL: + ICM42607_Gyro_on(); + client_data->pw.gyro_pm = ICM_GYRO_PM_NORMAL; + icm_delay(60); + break; + case ICM_GYRO_PM_SUSPEND: + ICM42607_Gyro_off(); + client_data->pw.gyro_pm = ICM_ACC_PM_SUSPEND; + icm_delay(60); + break; + default: + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + } else { + mutex_unlock(&client_data->mutex_op_mode); + return -EINVAL; + } + mutex_unlock(&client_data->mutex_op_mode); + return err; +} + +static int icm42607_accel_set_enable( + struct icm_client_data *client_data, bool enable) +{ + int ret = 0; + //dev_err(client_data->dev, + // "icm42607_accel_set_enable enable=%d\n", enable); + mutex_lock(&client_data->mutex_enable); + if (enable) { + ret = icm_power_ctl(client_data, POWER_ON); + if (ret) { + dev_err(client_data->dev, "Failed to power on device\n"); + } + ICM42607_Accel_on(); + + queue_delayed_work(client_data->data_wq, + &client_data->accel_poll_work, + msecs_to_jiffies(client_data->accel_poll_ms)); + atomic_set(&client_data->accel_en, 1); + client_data->pw.acc_pm = ICM_ACC_PM_NORMAL; + } else { + atomic_set(&client_data->accel_en, 0); + cancel_delayed_work_sync(&client_data->accel_poll_work); + ICM42607_Accel_off(); + client_data->pw.acc_pm = ICM_ACC_PM_SUSPEND; + } + mutex_unlock(&client_data->mutex_enable); + return ret; +} +static int icm42607_accel_set_poll_delay(struct icm_client_data *client_data, + unsigned long delay) +{ + //dev_err(client_data->dev, + // "icm42607_accel_set_poll_delay delay_ms=%ld\n", delay); + if (delay < ICM42607_ACCEL_MIN_POLL_INTERVAL_MS) + delay = ICM42607_ACCEL_MIN_POLL_INTERVAL_MS; + if (delay > ICM42607_ACCEL_MAX_POLL_INTERVAL_MS) + delay = ICM42607_ACCEL_MAX_POLL_INTERVAL_MS; + client_data->accel_poll_ms = delay; + if (!atomic_read(&client_data->accel_en)) + goto exit; + cancel_delayed_work_sync(&client_data->accel_poll_work); + queue_delayed_work(client_data->data_wq, + &client_data->accel_poll_work, + msecs_to_jiffies(client_data->accel_poll_ms)); +exit: + return 0; +} +static int icm42607_gyro_set_enable( + struct icm_client_data *client_data, bool enable) +{ + int ret = 0; + //dev_err(client_data->dev, + // "icm42607_gyro_set_enable enable=%d\n", enable); + mutex_lock(&client_data->mutex_enable); + if (enable) { + + ret = icm_power_ctl(client_data, POWER_ON); + if (ret) { + dev_err(client_data->dev, "Failed to power on device\n"); + } + + ICM42607_Gyro_on(); + queue_delayed_work(client_data->data_wq, + &client_data->gyro_poll_work, + msecs_to_jiffies(client_data->gyro_poll_ms)); + atomic_set(&client_data->gyro_en, 1); + client_data->pw.gyro_pm = ICM_GYRO_PM_NORMAL; + } else { + atomic_set(&client_data->gyro_en, 0); + cancel_delayed_work_sync(&client_data->gyro_poll_work); + ICM42607_Gyro_off(); + client_data->pw.gyro_pm = ICM_GYRO_PM_SUSPEND; + } + mutex_unlock(&client_data->mutex_enable); + return ret; +} +static int icm42607_gyro_set_poll_delay(struct icm_client_data *client_data, + unsigned long delay) +{ + //dev_err(client_data->dev, + // "icm42607_accel_set_poll_delay delay_ms=%ld\n", delay); + if (delay < ICM42607_GYRO_MIN_POLL_INTERVAL_MS) + delay = ICM42607_GYRO_MIN_POLL_INTERVAL_MS; + if (delay > ICM42607_GYRO_MAX_POLL_INTERVAL_MS) + delay = ICM42607_GYRO_MAX_POLL_INTERVAL_MS; + client_data->gyro_poll_ms = delay; + if (!atomic_read(&client_data->gyro_en)) + goto exit; + cancel_delayed_work_sync(&client_data->gyro_poll_work); + queue_delayed_work(client_data->data_wq, + &client_data->gyro_poll_work, + msecs_to_jiffies(client_data->gyro_poll_ms)); +exit: + return 0; +} +static int icm42607_accel_cdev_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct icm_client_data *sensor = icm42607_client_data; + return icm42607_accel_set_enable(sensor, enable); +} +static int icm42607_accel_cdev_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct icm_client_data *sensor = icm42607_client_data; + + return icm42607_accel_set_poll_delay(sensor, delay_ms); +} + +static int icm42607_gyro_cdev_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct icm_client_data *sensor = icm42607_client_data; + + return icm42607_gyro_set_enable(sensor, enable); +} + +static int icm42607_gyro_cdev_poll_delay(struct sensors_classdev *sensors_cdev, + unsigned int delay_ms) +{ + struct icm_client_data *sensor = icm42607_client_data; + + return icm42607_gyro_set_poll_delay(sensor, delay_ms); +} +#endif + +int icm_probe(struct icm_client_data *client_data, struct device *dev) +{ + int err = 0; + pr_err("icm_probe ++\n"); + icm42607_client_data = client_data; + + dev_set_drvdata(dev, client_data); + client_data->dev = dev; + + mutex_init(&client_data->mutex_enable); + mutex_init(&client_data->mutex_op_mode); + + icm_power_init(client_data); + if (err) { + dev_err(dev, "Failed to init regulator\n"); + } + err = icm_power_ctl(client_data, POWER_ON); + if (err) { + dev_err(dev, "Failed to power on device %s %d\n", __func__, __LINE__); + } + + /* check chip id */ + err = icm_check_chip_id(client_data); + if (err) + goto exit_err_clean; + + icm_dt_get_place(dev, client_data); + if (err) { + dev_err(dev, "Failed to get place %s %d\n", __func__, __LINE__); + return err; + } + + /* input device init */ + err = icm_input_init(client_data); + if (err < 0) + goto exit_err_clean; + + /* sysfs node creation */ + err = sysfs_create_group(&client_data->input->dev.kobj, + &icm42607_attribute_group); + + if (err < 0) { + dev_err(dev, "Failed to create sysfs %s %d\n", __func__, __LINE__); + goto exit_err_sysfs; + } + + /* h/w init */ + client_data->device.delay_msec = icm_delay; + inv_serif_init(&client_data->device); + + /*soft reset*/ + ICM42607_init(); + +#if defined(CONFIG_USE_QUALCOMM_HAL) + ICM42607_gyro_fsr(0); + ICM42607_accel_fsr(3); + ICM42607_accel_odr(9);/*idx=9, odr 100HZ*/ + ICM42607_gyro_odr(9);/*idx=9, odr 100HZ*/ +#endif + + /* now it's power on which is considered as resuming from suspend */ +#if defined(CONFIG_USE_QUALCOMM_HAL) + /* gyro input device init */ + err = icm_gyro_input_init(client_data); + if (err < 0) + goto exit_err_clean; + client_data->input->dev.parent = dev; + client_data->gyro_input->dev.parent = dev; + client_data->accel_poll_ms = ICM42607_ACCEL_DEFAULT_POLL_INTERVAL_MS; + client_data->gyro_poll_ms = ICM42607_GYRO_DEFAULT_POLL_INTERVAL_MS; + client_data->data_wq = create_freezable_workqueue("icm42607_data_work"); + if (!client_data->data_wq) { + dev_err(dev, "Cannot create workqueue!\n"); + goto exit_err_clean; + } + INIT_DELAYED_WORK(&client_data->accel_poll_work, icm42607_accel_work_fn); + client_data->accel_cdev = icm42607_accel_cdev; + client_data->accel_cdev.delay_msec = client_data->accel_poll_ms; + client_data->accel_cdev.sensors_enable = icm42607_accel_cdev_enable; + client_data->accel_cdev.sensors_poll_delay = icm42607_accel_cdev_poll_delay; + err = sensors_classdev_register(&client_data->input->dev, &client_data->accel_cdev); + if (err) { + dev_err(dev, + "create accel class device file failed!\n"); + goto exit_err_clean; + } + INIT_DELAYED_WORK(&client_data->gyro_poll_work, icm42607_gyro_work_fn); + client_data->gyro_cdev = icm42607_gyro_cdev; + client_data->gyro_cdev.delay_msec = client_data->gyro_poll_ms; + client_data->gyro_cdev.sensors_enable = icm42607_gyro_cdev_enable; + client_data->gyro_cdev.sensors_poll_delay = icm42607_gyro_cdev_poll_delay; + err = sensors_classdev_register(&client_data->gyro_input->dev, &client_data->gyro_cdev); + if (err) { + dev_err(dev, + "create accel class device file failed!\n"); + goto exit_err_clean; + } +#endif + /* set sensor PMU into suspend power mode for all */ + if (icm_pmu_set_suspend(client_data) < 0) { + dev_err(dev, "Failed to set icm42607 to suspend power mode\n"); + goto exit_err_sysfs; + } + + //icm_dump_reg(client_data); + dev_err(dev, "sensor %s probed successfully", SENSOR_NAME); + + pr_err("icm_probe --\n"); + return 0; + +exit_err_sysfs: + if (err) + icm_input_destroy(client_data); + +exit_err_clean: +/* + if (err) { + if (client_data != NULL) { + if (NULL != client_data->bst_pd) { + kfree(client_data->bst_pd); + client_data->bst_pd = NULL; + } + } + } +*/ + return err; +} +EXPORT_SYMBOL(icm_probe); + +/*! + * @brief remove icm client + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int icm_remove(struct device *dev) +{ + int err = 0; + struct icm_client_data *client_data = icm42607_client_data; + + pr_err("icm_remove\n"); + if (NULL != client_data) { +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&client_data->early_suspend_handler); +#endif + mutex_lock(&client_data->mutex_enable); + if (ICM_ACC_PM_NORMAL == client_data->pw.acc_pm || + ICM_GYRO_PM_NORMAL == client_data->pw.gyro_pm) { + cancel_delayed_work_sync(&client_data->work); + } + mutex_unlock(&client_data->mutex_enable); + + err = icm_pmu_set_suspend(client_data); + + icm_delay(5); + + sysfs_remove_group(&client_data->input->dev.kobj, + &icm42607_attribute_group); + icm_input_destroy(client_data); +/* + if (NULL != client_data->bst_pd) { + kfree(client_data->bst_pd); + client_data->bst_pd = NULL; + } +*/ + kfree(client_data); + } + + return err; +} +EXPORT_SYMBOL(icm_remove); + +static int icm_post_resume(struct icm_client_data *client_data) +{ + int err = 0; + pr_err("icm_post_resume\n"); + mutex_lock(&client_data->mutex_enable); + + if (atomic_read(&client_data->accel_en) == 1) { + icm42607_set_acc_op_mode(client_data, ICM_ACC_PM_NORMAL); + schedule_delayed_work(&client_data->accel_poll_work, + msecs_to_jiffies( + atomic_read(&client_data->delay))); + } + + if (atomic_read(&client_data->gyro_en) == 1) { + icm42607_set_gyro_op_mode(client_data, ICM_GYRO_PM_NORMAL); + schedule_delayed_work(&client_data->gyro_poll_work, + msecs_to_jiffies( + atomic_read(&client_data->delay))); + } + mutex_unlock(&client_data->mutex_enable); + + return err; +} + + +int icm_suspend(struct device *dev) +{ + int err = 0; + struct icm_client_data *client_data = icm42607_client_data; + + dev_err(client_data->dev, "icm suspend function entrance"); + + pr_err("icm_suspend\n"); + mutex_lock(&client_data->mutex_enable); + if (atomic_read(&client_data->accel_en) == 1) { + icm42607_set_acc_op_mode(client_data, ICM_ACC_PM_SUSPEND); + cancel_delayed_work_sync(&client_data->accel_poll_work); + } + if (atomic_read(&client_data->gyro_en) == 1) { + icm42607_set_gyro_op_mode(client_data, ICM_GYRO_PM_SUSPEND); + cancel_delayed_work_sync(&client_data->gyro_poll_work); + } + err = icm_power_ctl(client_data, POWER_OFF); + if (err) { + dev_err(dev, "Failed to power on device\n"); + } + mutex_unlock(&client_data->mutex_enable); + + return err; +} +EXPORT_SYMBOL(icm_suspend); + +int icm_resume(struct device *dev) +{ + int err = 0; + struct icm_client_data *client_data = icm42607_client_data; + + err = icm_power_ctl(client_data, POWER_ON); + if (err) { + dev_err(client_data->dev, "Failed to power on device\n"); + } + + if (client_data->pw.acc_pm != ICM_ACC_PM_SUSPEND) { + icm42607_set_acc_op_mode(client_data, ICM_ACC_PM_NORMAL); + icm_delay(3); + } + if (client_data->pw.gyro_pm != ICM_GYRO_PM_SUSPEND) { + icm42607_set_gyro_op_mode(client_data, ICM_GYRO_PM_NORMAL); + icm_delay(3); + } + + /* post resume operation */ + err += icm_post_resume(client_data); + + return err; +} +EXPORT_SYMBOL(icm_resume); \ No newline at end of file diff --git a/drivers/input/misc/icm42607/icm42607_driver.h b/drivers/input/misc/icm42607/icm42607_driver.h new file mode 100755 index 00000000000..d71f0f4651e --- /dev/null +++ b/drivers/input/misc/icm42607/icm42607_driver.h @@ -0,0 +1,132 @@ +/* + * + * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved. + * + * This software, related documentation and any modifications thereto (collectively "Software") is subject + * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright + * and other intellectual property rights laws. + * + * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software + * and any use, reproduction, disclosure or distribution of the Software without an express license agreement + * from InvenSense is strictly prohibited. + * + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL + * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE SOFTWARE. + * + */ + + +#ifndef _ICM42607_DRIVER_H +#define _ICM42607_DRIVER_H + +#ifdef __KERNEL__ +#include +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include "ICM-42607.h" + +//#if defined(CONFIG_USE_QUALCOMM_HAL) +#include +//#endif +/* sensor specific */ +#define SENSOR_NAME "icm42607" + +#define SENSOR_CHIP_ID_ICM (0x60) +#define SENSOR_CHIP_ID_ICM_C2 (0x61) +#define SENSOR_CHIP_ID_ICM_C3 (0x62) + +#define SENSOR_CHIP_REV_ID_ICM (0x00) + +#define CHECK_CHIP_ID_TIME_MAX 5 + +/*! +* Bst sensor common definition, +* please give parameters in BSP file. +*/ +struct invn_sensor_specific { + char *name; + /* 0 to 7 */ + unsigned int place:3; + int irq; + int (*irq_gpio_cfg)(void); +}; + +/*! icm42607 sensor spec of power mode */ +struct pw_mode { + u8 acc_pm; + u8 gyro_pm; +}; + +struct icm_client_data { + struct icm42607_t device; + struct device *dev; + struct input_dev *input;/*acc_device*/ +//#if defined(CONFIG_USE_QUALCOMM_HAL) + struct input_dev *gyro_input; + struct sensors_classdev accel_cdev; + struct sensors_classdev gyro_cdev; + struct delayed_work accel_poll_work; + struct delayed_work gyro_poll_work; + u32 accel_poll_ms; + u32 gyro_poll_ms; + atomic_t accel_en; + atomic_t gyro_en; + struct workqueue_struct *data_wq; +//#endif + struct delayed_work work; + u8 chip_id; + u16 bustype; + struct pw_mode pw; + s8 place; + atomic_t delay; + struct mutex mutex_op_mode; + struct mutex mutex_enable; + struct invn_sensor_specific *bst_pd; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend_handler; +#endif + int power_enabled; + u8 reg_data; + struct axis_data axis; + struct regulator *vdd; + struct regulator *vio; + struct i2c_client *i2c; +}; + +int icm_probe(struct icm_client_data *client_data, struct device *dev); +int icm_remove(struct device *dev); +int icm_suspend(struct device *dev); +int icm_resume(struct device *dev); + +#endif/*_ICM42607_DRIVER_H*/ \ No newline at end of file diff --git a/drivers/input/misc/icm42607/icm42607_i2c.c b/drivers/input/misc/icm42607/icm42607_i2c.c new file mode 100755 index 00000000000..a16ff2d5725 --- /dev/null +++ b/drivers/input/misc/icm42607/icm42607_i2c.c @@ -0,0 +1,284 @@ +/* + * + * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved. + * + * This software, related documentation and any modifications thereto (collectively "Software") is subject + * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright + * and other intellectual property rights laws. + * + * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software + * and any use, reproduction, disclosure or distribution of the Software without an express license agreement + * from InvenSense is strictly prohibited. + * + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL + * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE SOFTWARE. + * + */ + + +#include +#include +#include +#include "icm42607_driver.h" + +/*! @defgroup icm42607_i2c_src + * @brief icm42607 i2c driver module + @{*/ + +static struct i2c_client *icm_i2c_client; + +/*! + * @brief define i2c wirte function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +#define ICM_MAX_BUFFER_SIZE 32 +static int icm_i2c_write_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 length) +{ + struct i2c_client *client = icm_i2c_client; + u8 buffer[ICM_MAX_BUFFER_SIZE + 1]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = buffer, + } + }; + + if (length > ICM_MAX_BUFFER_SIZE) + return -EINVAL; + + buffer[0] = reg_addr; + memcpy(&buffer[1], data, length); + + return i2c_transfer(client->adapter, msg, 1); +} + +/*! + * @brief define i2c read function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to read + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int icm_i2c_read_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 length) +{ + struct i2c_client *client = icm_i2c_client; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®_addr, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + }, + }; + + return i2c_transfer(client->adapter, msg, 2); +} + +/*! + * @brief Invensense probe function via i2c bus + * + * @param client the pointer of i2c client + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +int icm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = 0; + struct icm_client_data *client_data = NULL; + + pr_err("icm_i2c_probe ++\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + err = dev_err(&client->dev, "i2c_check_functionality error!"); + pr_err("I2C adapter is not supported"); + err = -EIO; + goto exit_err_clean; + } + + if (NULL == icm_i2c_client) { + icm_i2c_client = client; + } else { + dev_err(&client->dev, "This driver does not support multiple clients!\n"); + return -EBUSY; + } + + client_data = kzalloc(sizeof(struct icm_client_data), GFP_KERNEL); + if (NULL == client_data) { + dev_err(&client->dev, "no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + client_data->device.bus_read = icm_i2c_read_block; + client_data->device.bus_write = icm_i2c_write_block; + client_data->bustype = BUS_I2C; + client_data->i2c = client; + //i2c_set_clientdata(client, client_data); + + return icm_probe(client_data, &client->dev); + +exit_err_clean: + if (err) + icm_i2c_client = NULL; + return err; +} + +EXPORT_SYMBOL(icm_i2c_probe); + +/*! + * @brief shutdown icm device in i2c driver + * + * @param client the pointer of i2c client + * + * @return no return value +*/ +void icm_i2c_shutdown(struct i2c_client *client) +{ +#ifdef CONFIG_PM + icm_suspend(&client->dev); +#endif +} +EXPORT_SYMBOL(icm_i2c_shutdown); + +/*! + * @brief remove icm i2c client + * + * @param client the pointer of i2c client + * + * @return zero + * @retval zero +*/ +int icm_i2c_remove(struct i2c_client *client) +{ + int err = 0; + pr_err("icm_i2c_remove\n"); + err = icm_remove(&client->dev); + icm_i2c_client = NULL; + + return err; +} +EXPORT_SYMBOL(icm_i2c_remove); + +#ifdef CONFIG_PM +/*! + * @brief suspend icm device in i2c driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int icm_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int err = 0; + pr_err("icm_i2c_suspend\n"); + err = icm_suspend(&client->dev); + return err; +} +EXPORT_SYMBOL(icm_i2c_suspend); + +/*! + * @brief resume icm device in i2c driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +int icm_i2c_resume(struct i2c_client *client) +{ + int err = 0; + pr_err("icm_i2c_resume\n"); + /* post resume operation */ + err = icm_resume(&client->dev); + + return err; +} +EXPORT_SYMBOL(icm_i2c_resume); + +#endif + +/*! + * @brief register i2c device id +*/ +static const struct i2c_device_id icm_id[] = { + { SENSOR_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, icm_id); + +static const struct of_device_id icm42607_of_match[] = { + { .compatible = "invn,icm42607", }, + { }, +}; +MODULE_DEVICE_TABLE(of, icm42607_of_match); + +/*! + * @brief register i2c driver hooks +*/ +static struct i2c_driver icm_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = icm42607_of_match, + }, + .class = I2C_CLASS_HWMON, + .id_table = icm_id, + .probe = icm_i2c_probe, + .shutdown = icm_i2c_shutdown, + .remove = icm_i2c_remove, +#ifdef CONFIG_PM + .suspend = icm_i2c_suspend, + .resume = icm_i2c_resume, +#endif +}; + +static int __init icm_i2c_init(void) +{ + return i2c_add_driver(&icm_i2c_driver); +} + +static void __exit icm_i2c_exit(void) +{ + i2c_del_driver(&icm_i2c_driver); +} + +//module_i2c_driver(icm_i2c_driver); + +MODULE_DESCRIPTION("ICM42607 I2C DRIVER"); +MODULE_AUTHOR("carl pt"); +MODULE_LICENSE("GPL v2"); + +module_init(icm_i2c_init); +module_exit(icm_i2c_exit); \ No newline at end of file diff --git a/drivers/input/misc/icm42607/icm42607_spi.c b/drivers/input/misc/icm42607/icm42607_spi.c new file mode 100755 index 00000000000..995c260a772 --- /dev/null +++ b/drivers/input/misc/icm42607/icm42607_spi.c @@ -0,0 +1,288 @@ +/* + * + * Copyright (c) 2018-2019 InvenSense Inc. All rights reserved. + * + * This software, related documentation and any modifications thereto (collectively "Software") is subject + * to InvenSense and its licensors' intellectual property rights under U.S. and international copyright + * and other intellectual property rights laws. + * + * InvenSense and its licensors retain all intellectual property and proprietary rights in and to the Software + * and any use, reproduction, disclosure or distribution of the Software without an express license agreement + * from InvenSense is strictly prohibited. + * + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, THE SOFTWARE IS + * PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * EXCEPT AS OTHERWISE PROVIDED IN A LICENSE AGREEMENT BETWEEN THE PARTIES, IN NO EVENT SHALL + * INVENSENSE BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THE SOFTWARE. + * + */ + + +#include +#include +#include +#include "icm42607_driver.h" + +/*! @defgroup icm42607_spi_src + * @brief icm42607 spi driver module + @{*/ +/*! the maximum of transfer buffer size */ +#define ICM_MAX_BUFFER_SIZE 32 + +static struct spi_device *icm_spi_client; + +/*! + * @brief define spi wirte function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to write + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static char icm_spi_write_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + struct spi_device *client = icm_spi_client; + u8 buffer[ICM_MAX_BUFFER_SIZE + 1]; + struct spi_transfer xfer = { + .tx_buf = buffer, + .len = len + 1, + }; + struct spi_message msg; + + if (len > ICM_MAX_BUFFER_SIZE) + return -EINVAL; + + buffer[0] = reg_addr; + memcpy(&buffer[1], data, len); + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + return spi_sync(client, &msg); +} + +/*! + * @brief define spi read function + * + * @param dev_addr sensor device address + * @param reg_addr register address + * @param data the pointer of data buffer + * @param len block size need to read + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static char icm_spi_read_block(u8 dev_addr, u8 reg_addr, u8 *data, u8 len) +{ + struct spi_device *client = icm_spi_client; + u8 reg = reg_addr | 0x80;/* read: MSB = 1 */ + struct spi_transfer xfer[2] = { + [0] = { + .tx_buf = ®, + .len = 1, + }, + [1] = { + .rx_buf = data, + .len = len, + } + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer[0], &msg); + spi_message_add_tail(&xfer[1], &msg); + return spi_sync(client, &msg); +} + +/*! + * @brief BMI probe function via spi bus + * + * @param client the pointer of spi client + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int icm_spi_probe(struct spi_device *client) +{ + int status; + int err = 0; + struct icm_client_data *client_data = NULL; + + if (NULL == icm_spi_client) + icm_spi_client = client; + else{ + dev_err(&client->dev, "This driver does not support multiple clients!\n"); + return -EBUSY; + } + + client->bits_per_word = 8; + status = spi_setup(client); + if (status < 0) { + dev_err(&client->dev, "spi_setup failed!\n"); + return status; + } + + client_data = kzalloc(sizeof(struct icm_client_data), GFP_KERNEL); + if (NULL == client_data) { + dev_err(&client->dev, "no memory available"); + err = -ENOMEM; + goto exit_err_clean; + } + + client_data->device.bus_read = icm_spi_read_block; + client_data->device.bus_write = icm_spi_write_block; + client_data.bustype = BUS_SPI; + + return icm_probe(client_data, &client->dev); + +exit_err_clean: + if (err) + icm_spi_client = NULL; + return err; +} + +/*! + * @brief shutdown icm device in spi driver + * + * @param client the pointer of spi client + * + * @return no return value +*/ +static void icm_spi_shutdown(struct spi_device *client) +{ +#ifdef CONFIG_PM + icm_suspend(&client->dev); +#endif +} + +/*! + * @brief remove icm spi client + * + * @param client the pointer of spi client + * + * @return zero + * @retval zero +*/ +static int icm_spi_remove(struct spi_device *client) +{ + int err = 0; + err = icm_remove(&client->dev); + icm_spi_client = NULL; + + return err; +} + +#ifdef CONFIG_PM +/*! + * @brief suspend icm device in spi driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int icm_spi_suspend(struct device *dev) +{ + int err = 0; + err = icm_suspend(dev); + return err; +} + +/*! + * @brief resume icm device in spi driver + * + * @param dev the pointer of device + * + * @return zero + * @retval zero +*/ +static int icm_spi_resume(struct device *dev) +{ + int err = 0; + /* post resume operation */ + err = icm_resume(dev); + + return err; +} + +/*! + * @brief register spi device power manager hooks +*/ +static const struct dev_pm_ops icm_spi_pm_ops = { + /**< device suspend */ + .suspend = icm_spi_suspend, + /**< device resume */ + .resume = icm_spi_resume +}; +#endif + +/*! + * @brief register spi device id +*/ +static const struct spi_device_id icm_id[] = { + { SENSOR_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, icm_id); + +static const struct of_device_id icm42607_of_match[] = { + { .compatible = "invn,icm42607", }, + { }, +}; +MODULE_DEVICE_TABLE(of, icm42607_of_match); + +/*! + * @brief register spi driver hooks +*/ +static struct spi_driver icm_spi_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + .of_match_table = icm42607_of_match, +#ifdef CONFIG_PM + .pm = &icm_spi_pm_ops, +#endif + }, + .id_table = icm_id, + .probe = icm_spi_probe, + .shutdown = icm_spi_shutdown, + .remove = icm_spi_remove +}; + +/*! + * @brief initialize icm spi module + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +static int __init icm_spi_init(void) +{ + return spi_register_driver(&icm_spi_driver); +} + +/*! + * @brief remove icm spi module + * + * @return no return value +*/ +static void __exit icm_spi_exit(void) +{ + spi_unregister_driver(&icm_spi_driver); +} + + +MODULE_DESCRIPTION("ICM42607 SPI DRIVER"); +MODULE_LICENSE("GPL v2"); + +module_init(icm_spi_init); +module_exit(icm_spi_exit); \ No newline at end of file diff --git a/drivers/input/misc/icm42607/qualcomm_example.dts b/drivers/input/misc/icm42607/qualcomm_example.dts new file mode 100755 index 00000000000..dbb3437618f --- /dev/null +++ b/drivers/input/misc/icm42607/qualcomm_example.dts @@ -0,0 +1,23 @@ + +&i2c2 { + status = "okay"; + clock-frequency = <400000>; + + icm42607@68{ + compatible = "invn,icm42607"; + reg = <0x68>;//pin 1 ad0 pull down 0x68, pull up 0x69 + invn,place = "Portrait Up"; + }; +}; + +&spi1 { + status = "okay"; + + icm42607@0{ + compatible = "invn,icm42607"; + reg = <0>; + spi-max-frequency = <24000000>; + invn,place = "Portrait Up"; + status = "okay"; + }; +}; \ No newline at end of file -- 2.25.1 From 9a3752cb7bfa1bf2953918b0718259e1c86d2fb0 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 27 Jan 2022 17:22:56 -0700 Subject: [PATCH 72/76] kernel/msm-3.18: MeiG liangdi:Gsenosr icm42607 compatible Change-Id: I9a1aa8d93e88132382e4fdfddb7c6e8f16c3329e --- arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 1 + arch/arm/configs/msm8909-perf_defconfig | 5 +++-- drivers/input/misc/Kconfig | 3 ++- drivers/input/misc/Makefile | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index ce0159fc9b6..5c7f185c317 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -584,6 +584,7 @@ bosch,place = <5>; bosch,gpio-int1 = <&msm_gpio 96 0x2002>; bmi2xy,gpio_irq = <&msm_gpio 96 0x2002>; + invn,place = "Landscape Left"; }; ptn5150@1d { diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index b60a442f779..61ad2bd8ab1 100755 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -571,5 +571,6 @@ CONFIG_NRF_DRIVER=y CONFIG_EXTCON=y CONFIG_EXTCON_PTN5150=y CONFIG_FRAME_WARN=2048 - -CONFIG_SENSORS_GMP102=y \ No newline at end of file +CONFIG_SENSORS_GMP102=y +CONFIG_SENSORS_ICM42607=y +CONFIG_SENSORS_ICM42607_I2C=y \ No newline at end of file diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 68bf64a0cf2..6f6e20218e1 100755 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -919,6 +919,7 @@ config SENSORS_GMP102 help If you say yes here, you get support for gmp102 Sensortec's sensor driver of GMP102. - + +source "drivers/input/misc/icm42607/Kconfig" endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 02530bdc1b9..a998301959f 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -115,4 +115,5 @@ endif endif obj-$(CONFIG_SENSORS_BMI220) += bmi220/ +obj-$(CONFIG_SENSORS_ICM42607) += icm42607/ obj-$(CONFIG_SENSORS_GMP102) += gmp102-core.o gmp102-i2c.o -- 2.25.1 From 3d43e41a4e9457399d611fe4ac971b723420713a Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 27 Jan 2022 17:51:52 -0700 Subject: [PATCH 73/76] kernel/msm-3.18: MeiG liangdi:pannel COM32H3P61ULC COM32H3P68ULC compatible Change-Id: I808fa31291915dd8a69c6cf52541212b0b5dd7bc --- .../dsi-panel-ortustech32-68ulc-video.dtsi | 80 +++++++++++++++++++ .../dts/qcom/dsi-panel-ortustech32-video.dtsi | 4 +- .../boot/dts/qcom/msm8909-mdss-panels.dtsi | 1 + arch/arm/boot/dts/qcom/msm8909-mtp.dtsi | 14 +++- arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi | 13 ++- 5 files changed, 106 insertions(+), 6 deletions(-) create mode 100755 arch/arm/boot/dts/qcom/dsi-panel-ortustech32-68ulc-video.dtsi diff --git a/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-68ulc-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-68ulc-video.dtsi new file mode 100755 index 00000000000..783ffd67364 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-68ulc-video.dtsi @@ -0,0 +1,80 @@ +/* Copyright (c) 2013 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&mdss_mdp { + mdss_dsi_ortustech32_68ulc_video: qcom,mdss_dsi_ortustech32_68ulc_video { + qcom,mdss-dsi-panel-name = "COM32H3P68ULC 480x800 video panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <480>; + qcom,mdss-dsi-panel-height = <800>; + qcom,mdss-dsi-h-front-porch = <16>; + qcom,mdss-dsi-h-back-porch = <16>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-pixel-packing = "tight"; + qcom,mdss-dsi-pixel-alignment = <0>; + qcom,mdss-dsi-on-command = [ + 05 01 00 00 a8 00 02 11 00 + 39 01 00 00 00 00 04 B9 FF 83 63 + 39 01 00 00 00 00 0E BA 80 00 10 08 08 10 7E 6E 6D 0A 01 84 43 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 0e 00 02 3A 70 + 39 01 00 00 00 00 0D B1 78 24 04 03 02 03 10 10 34 3C 3F 3F + 39 01 00 00 00 00 0A B4 00 08 6E 07 01 01 62 01 57 + 15 01 00 00 00 00 02 CC 0B + 39 01 00 00 0e 00 1F E0 01 48 4D 4E 58 F6 0B 4E 12 D5 15 95 55 8E 11 01 48 4D 55 5F FD 0A 4E 51 D3 17 95 96 4E 11 + 05 01 00 00 29 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,mdss-dsi-panel-timings = [7d 12 0C 01 34 38 10 16 0E 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x20>; + qcom,mdss-dsi-t-clk-pre = <0x24>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 120>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi index 1eeb50e3390..dc7c9365c04 100755 --- a/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-ortustech32-video.dtsi @@ -16,8 +16,8 @@ * VERSION = "1.0" *---------------------------------------------------------------------------*/ &mdss_mdp { - dsi_ortustech32_video: qcom,dsi_ortustech32_video { - qcom,mdss-dsi-panel-name = "mdss_dsi_ortustech_video 480x800 video panel"; + mdss_dsi_ortustech32_61ulc_video: qcom,mdss_dsi_ortustech32_61ulc_video { + qcom,mdss-dsi-panel-name = "COM32H3P61ULC 480x800 video panel"; qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; qcom,mdss-dsi-panel-type = "dsi_video_mode"; qcom,mdss-dsi-panel-destination = "display_1"; diff --git a/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi index 714e4dc1667..e04ae1e9c99 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mdss-panels.dtsi @@ -26,6 +26,7 @@ #include "dsi-panel-hx8394f-zzw500hah-720p-video.dtsi" #include "dsi-panel-otm1289a-zzw500hc0-145b-720p-video.dtsi" #include "dsi-panel-ortustech32-video.dtsi" +#include "dsi-panel-ortustech32-68ulc-video.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi index 5c7f185c317..65033bc50e7 100644 --- a/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-mtp.dtsi @@ -773,7 +773,7 @@ }; -&dsi_ortustech32_video { +&mdss_dsi_ortustech32_61ulc_video { qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; qcom,mdss-dsi-bl-pmic-bank-select = <0>; @@ -781,9 +781,19 @@ qcom,cont-splash-enabled; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; + +&mdss_dsi_ortustech32_68ulc_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8909_mpps 2 0>; + qcom,cont-splash-enabled; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &mdss_dsi0 { //qcom,dsi-pref-prim-pan = <&dsi_hx8394d_720_vid>; - qcom,dsi-pref-prim-pan = <&dsi_ortustech32_video>; + qcom,dsi-pref-prim-pan = <&mdss_dsi_ortustech32_68ulc_video>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi index e8ea1797d2b..0d89b7e41db 100755 --- a/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd-skua.dtsi @@ -522,7 +522,16 @@ };*/ -&dsi_ortustech32_video { +&mdss_dsi_ortustech32_61ulc_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <1000>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8909_mpps 2 0>; + qcom,cont-splash-enabled; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&mdss_dsi_ortustech32_68ulc_video { qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; qcom,mdss-dsi-bl-pmic-pwm-frequency = <1000>; qcom,mdss-dsi-bl-pmic-bank-select = <0>; @@ -535,7 +544,7 @@ &mdss_dsi0 { //qcom,dsi-pref-prim-pan = <&dsi_hx8379a_fwvga_skua_vid>; //qcom,dsi-pref-prim-pan = <&dsi_ortustech_video>; - qcom,dsi-pref-prim-pan = <&dsi_ortustech32_video>; + qcom,dsi-pref-prim-pan = <&mdss_dsi_ortustech32_61ulc_video>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; -- 2.25.1 From a4180355e113db456876485031f2f2ed4f43439d Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 9 Feb 2022 07:56:12 -0700 Subject: [PATCH 74/76] kernel/msm-3.18: - add support for missing icm42607 - add bmp220 power manangement - logging cleanup Change-Id: I47daa905a79183a8581802341152985d1bba14c5 --- arch/arm/configs/msm8909-perf_defconfig | 2 +- arch/arm/configs/msm8909_defconfig | 18 +++--- drivers/input/misc/bmi160_i2c.c | 84 ++++++++++++++++++++++++- drivers/input/misc/bmp280_core.c | 73 ++++++++++++++++++--- drivers/input/misc/bmp280_core.h | 2 + drivers/input/misc/bmp280_i2c.c | 2 + drivers/input/misc/gmp102-core.c | 4 +- drivers/power/reset/msm-poweroff.c | 11 ++-- 8 files changed, 170 insertions(+), 26 deletions(-) mode change 100755 => 100644 arch/arm/configs/msm8909-perf_defconfig mode change 100755 => 100644 arch/arm/configs/msm8909_defconfig mode change 100755 => 100644 drivers/input/misc/bmi160_i2c.c mode change 100755 => 100644 drivers/input/misc/bmp280_core.c mode change 100755 => 100644 drivers/input/misc/bmp280_core.h mode change 100755 => 100644 drivers/input/misc/bmp280_i2c.c mode change 100755 => 100644 drivers/input/misc/gmp102-core.c diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig old mode 100755 new mode 100644 index 61ad2bd8ab1..124294ae6fb --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -573,4 +573,4 @@ CONFIG_EXTCON_PTN5150=y CONFIG_FRAME_WARN=2048 CONFIG_SENSORS_GMP102=y CONFIG_SENSORS_ICM42607=y -CONFIG_SENSORS_ICM42607_I2C=y \ No newline at end of file +CONFIG_SENSORS_ICM42607_I2C=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig old mode 100755 new mode 100644 index 107d6f03ece..03721995008 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -27,7 +27,7 @@ CONFIG_NAMESPACES=y CONFIG_BLK_DEV_INITRD=y CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y -CONFIG_CC_OPTIMIZE_FOR_SIZE=n +CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_KALLSYMS_ALL=y CONFIG_EMBEDDED=y CONFIG_PROFILING=y @@ -257,13 +257,13 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y -#CONFIG_SCSI_CONSTANTS=y -#CONFIG_SCSI_LOGGING=y -#CONFIG_SCSI_SCAN_ASYNC=y -#CONFIG_SCSI_UFSHCD=y -#CONFIG_SCSI_UFSHCD_PLATFORM=y -#CONFIG_SCSI_UFS_QCOM=y -#CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -622,4 +622,4 @@ CONFIG_GT9XX_TOUCHPANEL_UPDATE=y CONFIG_GT9XX_TOUCHPANEL_DEBUG=y CONFIG_MG_DRIVER_CONTROL=y CONFIG_LOG_BUF_SHIFT=20 -#CONFIG_NRF_DRIVER=y \ No newline at end of file +CONFIG_NRF_DRIVER=y \ No newline at end of file diff --git a/drivers/input/misc/bmi160_i2c.c b/drivers/input/misc/bmi160_i2c.c old mode 100755 new mode 100644 index d21ac9f70d9..d545772e18a --- a/drivers/input/misc/bmi160_i2c.c +++ b/drivers/input/misc/bmi160_i2c.c @@ -294,6 +294,13 @@ extern int bmi2xy_i2c_probe(struct i2c_client *client,const struct i2c_device_id extern int bmi2xy_i2c_suspend(struct i2c_client *client, pm_message_t mesg); extern int bmi2xy_i2c_resume(struct i2c_client *client); extern int bmi2xy_i2c_remove(struct i2c_client *client); +//for icm42607 +extern int icm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +extern int icm_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +extern int icm_i2c_resume(struct i2c_client *client); +extern int icm_i2c_remove(struct i2c_client *client); +extern void icm_i2c_shutdown(struct i2c_client *client); + static uint8_t gl_chip_id = 0; struct bmi160_type_mapping_type { @@ -314,6 +321,7 @@ static const struct bmi160_type_mapping_type bmi_sensor_type_map[] = { {SENSOR_CHIP_ID_BMI_C2, SENSOR_CHIP_REV_ID_BMI, "BMI160C2"}, {SENSOR_CHIP_ID_BMI_C3, SENSOR_CHIP_REV_ID_BMI, "BMI160C3"}, {0x26, 0x00, "BMI220"}, + {0x60, 0x00, "icm42607"}, }; static int check_chip_id(struct i2c_client *client) @@ -328,7 +336,7 @@ static int check_chip_id(struct i2c_client *client) while (read_count++ < CHECK_CHIP_ID_TIME_MAX) { if (bmi_i2c_read_wrapper(client->addr,BMI_REG_NAME(USER_CHIP_ID), &chip_id, 1) < 0) { - pr_err("Bosch Sensortec Device not found""read chip_id:%d\n", chip_id); + pr_err("1Bosch Sensortec Device not found""read chip_id:%d\n", chip_id); continue; } else { @@ -336,10 +344,34 @@ static int check_chip_id(struct i2c_client *client) if (bmi_sensor_type_map[i].chip_id == chip_id) { gl_chip_id = chip_id; pr_err( - "Bosch Sensortec Device detected,HW IC name: %s\n", bmi_sensor_type_map[i].sensor_name); + "1Bosch Sensortec Device detected,HW IC name: %s\n", bmi_sensor_type_map[i].sensor_name); break; } } + + //add for icm42607 + if(i == bmi_sensor_cnt) + { + if (bmi_i2c_read_wrapper(client->addr,0x75, &chip_id, 1) < 0) { + + pr_err("2Bosch Sensortec Device not found""read chip_id:%d\n", chip_id); + continue; + + } + else + { + for (i = 0; i < bmi_sensor_cnt; i++) { + if (bmi_sensor_type_map[i].chip_id == chip_id) { + gl_chip_id = chip_id; + pr_err( + "2Bosch Sensortec Device detected,HW IC name: %s\n", bmi_sensor_type_map[i].sensor_name); + break; + } + } + } + } + //add end + if (i < bmi_sensor_cnt) break; else { @@ -385,6 +417,12 @@ static int bmi_i2c_compatible_probe(struct i2c_client *client, err = -EIO; goto exit_err_clean; } + else if(gl_chip_id == 0x60) + { + //icm42607 + err = -EIO; + goto exit_err_clean; + } else { bmi_i2c_probe(client, id); @@ -398,6 +436,7 @@ exit_err_clean: return err; } +//for bim220 static const struct i2c_device_id bmi2xy_id[] = { { SENSOR_NAME, 0 }, { } @@ -424,6 +463,41 @@ static struct i2c_driver bmi2xy_driver = { .suspend = bmi2xy_i2c_suspend, .resume = bmi2xy_i2c_resume, }; + +//for icm42607 +static const struct i2c_device_id icm_id[] = { + { SENSOR_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, icm_id); + +static const struct of_device_id icm42607_of_match[] = { + { .compatible = "bosch,bmi160", }, + { .compatible = "invn,icm42607", }, + { }, +}; +MODULE_DEVICE_TABLE(of, icm42607_of_match); + +/*! + * @brief register i2c driver hooks +*/ +static struct i2c_driver icm_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "icm42607", + .of_match_table = icm42607_of_match, + }, + .class = I2C_CLASS_HWMON, + .id_table = icm_id, + .probe = icm_i2c_probe, + .shutdown = icm_i2c_shutdown, + .remove = icm_i2c_remove, +#ifdef CONFIG_PM + .suspend = icm_i2c_suspend, + .resume = icm_i2c_resume, +#endif +}; + //add end static int bmi_i2c_suspend(struct i2c_client *client, pm_message_t mesg) @@ -495,6 +569,12 @@ static int __init BMI_i2c_init(void) i2c_del_driver(&bmi_i2c_driver); return i2c_add_driver(&bmi2xy_driver); } + else if(gl_chip_id == 0x60) + { + pr_err("i2c add icm42607 driver\n"); + i2c_del_driver(&bmi_i2c_driver); + return i2c_add_driver(&icm_i2c_driver); + } return err; } diff --git a/drivers/input/misc/bmp280_core.c b/drivers/input/misc/bmp280_core.c old mode 100755 new mode 100644 index b2e77013fc8..42e118b5c2e --- a/drivers/input/misc/bmp280_core.c +++ b/drivers/input/misc/bmp280_core.c @@ -122,6 +122,7 @@ struct bmp_client_data { uint32_t delay; /*!enable/disable sensor output */ uint32_t enable; + uint32_t temp_enable; /*! indicate selftest status * -1: no action * 0: failed @@ -789,7 +790,7 @@ static ssize_t bmp280_poll_delay_set(struct sensors_classdev *sensors_cdev, mutex_lock(&data->lock); data->delay = delay_msec; mutex_unlock(&data->lock); - pr_err("bmp280_poll_delay_set delay=%d\n",data->delay); + pr_err("bmp280_poll_delay_set pressure delay=%d\n",data->delay); return 0; } //add end @@ -803,7 +804,7 @@ static ssize_t bmp280_temp_poll_delay_set(struct sensors_classdev *sensors_cdev, mutex_lock(&data->lock); data->delay = delay_msec; mutex_unlock(&data->lock); - pr_err("bmp280_poll_delay_set delay=%d\n",data->delay); + pr_err("bmp280_poll_delay_set temp delay=%d\n",data->delay); return 0; } //add end @@ -1215,7 +1216,7 @@ static ssize_t bmp280_enable_set(struct sensors_classdev *sensors_cdev, data->enable = enable; } mutex_unlock(&data->lock); - pr_err("bmp280_enable_set en_state=%d\n",data->enable); + pr_err("bmp280_enable_set pressure en_state=%d\n",data->enable); return 0; } @@ -1232,7 +1233,7 @@ static ssize_t bmp280_enable_set_temp(struct sensors_classdev *sensors_cdev, enable = enable ? 1 : 0; mutex_lock(&data->lock); - if (data->enable != enable) { + if (data->temp_enable != enable) { if (enable) { #ifdef CONFIG_PM bmp_enable(dev); @@ -1249,10 +1250,10 @@ static ssize_t bmp280_enable_set_temp(struct sensors_classdev *sensors_cdev, bmp_disable(dev); #endif } - data->enable = enable; + data->temp_enable = enable; } mutex_unlock(&data->lock); - pr_err("bmp280_enable_set en_state=%d\n",data->enable); + pr_err("bmp280_enable_set temp en_state=%d\n",data->temp_enable); return 0; } @@ -1529,6 +1530,8 @@ static void bmp_temp_work_func(struct work_struct *work) struct bmp_client_data *client_data = container_of((struct delayed_work *)work, struct bmp_client_data, temp_work); + uint32_t delay = msecs_to_jiffies(client_data->delay); + uint32_t j1 = jiffies; uint32_t temperature; int status; @@ -1536,12 +1539,12 @@ static void bmp_temp_work_func(struct work_struct *work) status = bmp_get_temperature(client_data, &temperature); mutex_unlock(&client_data->lock); if (status == 0) { - pr_info("bmp280 temperature value :%d /100 C\n", temperature); + //pr_err("bmp280 temperature value :%d Pa\n", temperature); input_event(client_data->input_temp, EV_ABS, MSC_RAW, temperature); input_sync(client_data->input_temp); } - schedule_delayed_work(&client_data->temp_work, msecs_to_jiffies(2000)); + schedule_delayed_work(&client_data->temp_work, delay-(jiffies-j1)); } //add end /*! @@ -1633,6 +1636,7 @@ static int bmp_init_client(struct bmp_client_data *data) data->delay = BMP_DELAY_DEFAULT; data->enable = 0; + data->temp_enable = 0; data->selftest = BMP_SELFTEST_NO_ACTION;/* no action to selftest */ status = bmp_set_op_mode(data, BMP_VAL_NAME(SLEEP_MODE)); @@ -1807,6 +1811,59 @@ int bmp_enable(struct device *dev) EXPORT_SYMBOL(bmp_enable); #endif +//add by liangdi for bmp280 suspend issue 20201230 +void bmp_suspend(struct device *dev) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + + pr_err("bmp_suspend enable %d, %d ++\n",data->enable,data->temp_enable); + if (data->enable) + { + cancel_delayed_work_sync(&data->work); + } + + if(data->temp_enable) + { + cancel_delayed_work_sync(&data->temp_work); + } + + if(data->enable || data->temp_enable) + { + mutex_lock(&data->lock); + bmp_set_op_mode(data, BMP_VAL_NAME(SLEEP_MODE)); + mutex_unlock(&data->lock); + } + pr_err("bmp_suspend --\n"); +} + +void bmp_resume(struct device *dev) +{ + struct bmp_client_data *data = dev_get_drvdata(dev); + + pr_err("bmp_resume enable %d, %d ++\n",data->enable, data->temp_enable); + + if(data->enable || data->temp_enable) + { + mutex_lock(&data->lock); + bmp_set_op_mode(data, BMP_VAL_NAME(NORMAL_MODE)); + mutex_unlock(&data->lock); + } + + if (data->enable) + { + schedule_delayed_work(&data->work, + msecs_to_jiffies(data->delay)); + } + + if(data->temp_enable) + { + schedule_delayed_work(&data->temp_work, + msecs_to_jiffies(data->delay)); + } + pr_err("bmp_resume --\n"); +} +//add end + #ifdef CONFIG_HAS_EARLYSUSPEND /*! * @brief early suspend function of bmp sensor diff --git a/drivers/input/misc/bmp280_core.h b/drivers/input/misc/bmp280_core.h old mode 100755 new mode 100644 index 69cd5334027..ac200b0d3ee --- a/drivers/input/misc/bmp280_core.h +++ b/drivers/input/misc/bmp280_core.h @@ -62,6 +62,8 @@ struct bmp_data_bus { int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus); int bmp_remove(struct device *dev); +void bmp_suspend(struct device *dev); +void bmp_resume(struct device *dev); #ifdef CONFIG_PM int bmp_enable(struct device *dev); int bmp_disable(struct device *dev); diff --git a/drivers/input/misc/bmp280_i2c.c b/drivers/input/misc/bmp280_i2c.c old mode 100755 new mode 100644 index 196c45a8265..49a98079719 --- a/drivers/input/misc/bmp280_i2c.c +++ b/drivers/input/misc/bmp280_i2c.c @@ -393,6 +393,7 @@ static int bmp_i2c_remove(struct i2c_client *client) */ static int bmp_i2c_suspend(struct device *dev) { + bmp_suspend(dev); return bmp_disable(dev); } @@ -406,6 +407,7 @@ static int bmp_i2c_suspend(struct device *dev) */ static int bmp_i2c_resume(struct device *dev) { + bmp_resume(dev); return bmp_enable(dev); } diff --git a/drivers/input/misc/gmp102-core.c b/drivers/input/misc/gmp102-core.c old mode 100755 new mode 100644 index 027f06f49c4..025dd297dc0 --- a/drivers/input/misc/gmp102-core.c +++ b/drivers/input/misc/gmp102-core.c @@ -789,7 +789,7 @@ static void gmp102_work_func(struct work_struct *work) if (status == 0) { //input_report_abs(client_data->input, ABS_PRESSURE, pressure); - pr_err("gmp102 pressure value :%d Pa\n", pressure); + //pr_err("gmp102 pressure value :%d Pa\n", pressure); input_event(client_data->input, EV_ABS, MSC_RAW, pressure); input_sync(client_data->input); @@ -812,7 +812,7 @@ static void gmp102_temp_work_func(struct work_struct *work) status = gmp102_get_temperature(client_data, &temperature); if (status == 0) { - pr_err("gmp102 temperature value :%d C\n", temperature); + //pr_err("gmp102 temperature value :%d C\n", temperature); input_event(client_data->temp_input, EV_ABS, MSC_RAW, temperature); input_sync(client_data->temp_input); diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 27711ad7e19..0c66b2eb576 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -293,8 +293,10 @@ static void msm_restart_prepare(const char *cmd) /* Hard reset the PMIC unless memory contents must be maintained. */ if (need_warm_reset) { + pr_err("system warm restart\n"); qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET); } else { + pr_err("system hard restart\n"); qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); } @@ -370,9 +372,9 @@ static void deassert_ps_hold(void) __raw_writel(0, msm_ps_hold); } -static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) +void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) { - pr_notice("Going down for restart now\n"); + pr_err("Going down for restart now\n"); msm_restart_prepare(cmd); @@ -392,11 +394,12 @@ static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd) mdelay(10000); } +EXPORT_SYMBOL(do_msm_restart); static void do_msm_poweroff(void) { - pr_notice("Powering off the SoC\n"); - + pr_err("Powering off the SoC\n"); + set_dload_mode(0); scm_disable_sdi(); qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN); -- 2.25.1 From 0ed265de0cdc09617eda065f04ad66f10c54d09d Mon Sep 17 00:00:00 2001 From: vipinbb Date: Wed, 16 Feb 2022 06:20:44 -0800 Subject: [PATCH 75/76] kernel/msm-3.18: - Integrate latest bmp280 kernel driver from kernel-5.x Change-Id: I5cd6444cb205ab5f199d76497ac88aaf2ebbd357 --- drivers/input/misc/Makefile | 10 +- drivers/input/misc/bmp280/Kconfig | 20 ++ drivers/input/misc/bmp280/Makefile | 12 + drivers/input/misc/{ => bmp280}/bmp280.c | 0 drivers/input/misc/{ => bmp280}/bmp280.h | 0 drivers/input/misc/bmp280/bmp280_algo.c | 320 ++++++++++++++++++ drivers/input/misc/bmp280/bmp280_algo.h | 38 +++ drivers/input/misc/{ => bmp280}/bmp280_core.c | 316 ++++++----------- drivers/input/misc/bmp280/bmp280_core.h | 152 +++++++++ drivers/input/misc/{ => bmp280}/bmp280_i2c.c | 1 + drivers/input/misc/{ => bmp280}/bmp280_spi.c | 1 + drivers/input/misc/bmp280/bmp280_sysfs.c | 93 +++++ drivers/input/misc/bmp280/bmp280_sysfs.h | 39 +++ drivers/input/misc/bmp280_core.h | 73 ---- 14 files changed, 774 insertions(+), 301 deletions(-) create mode 100755 drivers/input/misc/bmp280/Kconfig create mode 100755 drivers/input/misc/bmp280/Makefile rename drivers/input/misc/{ => bmp280}/bmp280.c (100%) rename drivers/input/misc/{ => bmp280}/bmp280.h (100%) create mode 100644 drivers/input/misc/bmp280/bmp280_algo.c create mode 100644 drivers/input/misc/bmp280/bmp280_algo.h rename drivers/input/misc/{ => bmp280}/bmp280_core.c (92%) create mode 100644 drivers/input/misc/bmp280/bmp280_core.h rename drivers/input/misc/{ => bmp280}/bmp280_i2c.c (99%) rename drivers/input/misc/{ => bmp280}/bmp280_spi.c (99%) create mode 100644 drivers/input/misc/bmp280/bmp280_sysfs.c create mode 100644 drivers/input/misc/bmp280/bmp280_sysfs.h delete mode 100644 drivers/input/misc/bmp280_core.h diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a998301959f..f792a2c03a5 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -105,15 +105,9 @@ endif obj-$(CONFIG_SENSORS_BMI160_I2C) += bmi160_i2c.o ifeq ($(CONFIG_SENSORS_BMI160_I2C),y) EXTRA_CFLAGS += -DBMI_USE_BASIC_I2C_FUNC - -obj-$(CONFIG_SENSORS_BMP280) += bmp280_core.o bmp280.o -obj-$(CONFIG_SENSORS_BMP280_I2C) += bmp280_i2c.o -obj-$(CONFIG_SENSORS_BMP280_SPI) += bmp280_spi.o -ifeq ($(CONFIG_SENSORS_BMP280_I2C),y) - EXTRA_CFLAGS += -DBMP_USE_BASIC_I2C_FUNC -endif endif - + obj-$(CONFIG_SENSORS_BMI220) += bmi220/ +obj-$(CONFIG_SENSORS_BMP280) += bmp280/ obj-$(CONFIG_SENSORS_ICM42607) += icm42607/ obj-$(CONFIG_SENSORS_GMP102) += gmp102-core.o gmp102-i2c.o diff --git a/drivers/input/misc/bmp280/Kconfig b/drivers/input/misc/bmp280/Kconfig new file mode 100755 index 00000000000..5829215371f --- /dev/null +++ b/drivers/input/misc/bmp280/Kconfig @@ -0,0 +1,20 @@ +# +# Makefile for BMPXXX driver. +# +config SENSORS_BMP280 + tristate "BMP280 digital Pressure Sensor" + depends on (I2C || SPI_MASTER) && SYSFS + help + If you say yes here, you get support for Bosch Sensortec's BMP280 digital pressure sensors. + +config SENSORS_BMP280_I2C + tristate "support I2C bus communication" + depends on SENSORS_BMP280 && I2C + help + If you say yes here, you get support Bosch Sensortec's BMP280 pressure sensor hooked to an I2C bus. + +config SENSORS_BMP280_SPI + tristate "support SPI bus communication" + depends on SENSORS_BMP280 && SPI_MASTER + help + If you say yes here, you get support Bosch Sensortec's BMP280 pressure sensor hooked to an SPI bus. diff --git a/drivers/input/misc/bmp280/Makefile b/drivers/input/misc/bmp280/Makefile new file mode 100755 index 00000000000..672b9ce1ff4 --- /dev/null +++ b/drivers/input/misc/bmp280/Makefile @@ -0,0 +1,12 @@ + +# +# Makefile for BMP Environment Driver +# + +obj-$(CONFIG_SENSORS_BMP280) += bmp280_sysfs.o bmp280_core.o bmp280.o bmp280_algo.o +obj-$(CONFIG_SENSORS_BMP280_I2C) += bmp280_i2c.o +obj-$(CONFIG_SENSORS_BMP280_SPI) += bmp280_spi.o +ifeq ($(CONFIG_SENSORS_BMP280_I2C),y) + EXTRA_CFLAGS += -DBMP_USE_BASIC_I2C_FUNC +endif + diff --git a/drivers/input/misc/bmp280.c b/drivers/input/misc/bmp280/bmp280.c similarity index 100% rename from drivers/input/misc/bmp280.c rename to drivers/input/misc/bmp280/bmp280.c diff --git a/drivers/input/misc/bmp280.h b/drivers/input/misc/bmp280/bmp280.h similarity index 100% rename from drivers/input/misc/bmp280.h rename to drivers/input/misc/bmp280/bmp280.h diff --git a/drivers/input/misc/bmp280/bmp280_algo.c b/drivers/input/misc/bmp280/bmp280_algo.c new file mode 100644 index 00000000000..5c5bc5cf635 --- /dev/null +++ b/drivers/input/misc/bmp280/bmp280_algo.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2010 Christoph Mair + * Copyright (c) 2012 Bosch Sensortec GmbH + * Copyright (c) 2012 Unixphere AB + * Copyright (c) 2014 Intel Corporation + * Copyright (c) 2016 Linus Walleij + * + * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor. + * + * Datasheet: + * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf + * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf + * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf + */ + +/* +* Copyright (c) Hammerhead Navigation Inc. 2021 +* All Rights Reserved +*/ + + +#include "bmp280_algo.h" +#include "bmp280.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For irq_get_irq_data() */ +#include +#include +#include + +/* BMP280 specific registers */ +#define BMP280_REG_HUMIDITY_LSB 0xFE +#define BMP280_REG_HUMIDITY_MSB 0xFD +#define BMP280_REG_TEMP_XLSB 0xFC +#define BMP280_REG_TEMP_LSB 0xFB +#define BMP280_REG_TEMP_MSB 0xFA +#define BMP280_REG_PRESS_XLSB 0xF9 +#define BMP280_REG_PRESS_LSB 0xF8 +#define BMP280_REG_PRESS_MSB 0xF7 + +#define BMP280_REG_CONFIG 0xF5 +#define BMP280_REG_CTRL_MEAS 0xF4 +#define BMP280_REG_STATUS 0xF3 +#define BMP280_REG_CTRL_HUMIDITY 0xF2 + +/* Due to non linear mapping, and data sizes we can't do a bulk read */ +#define BMP280_REG_COMP_H1 0xA1 +#define BMP280_REG_COMP_H2 0xE1 +#define BMP280_REG_COMP_H3 0xE3 +#define BMP280_REG_COMP_H4 0xE4 +#define BMP280_REG_COMP_H5 0xE5 +#define BMP280_REG_COMP_H6 0xE7 + +#define BMP280_REG_COMP_TEMP_START 0x88 +#define BMP280_COMP_TEMP_REG_COUNT 6 + +#define BMP280_REG_COMP_PRESS_START 0x8E +#define BMP280_COMP_PRESS_REG_COUNT 18 + +#define BMP280_FILTER_MASK (BIT(4) | BIT(3) | BIT(2)) +#define BMP280_FILTER_OFF 0 +#define BMP280_FILTER_2X BIT(2) +#define BMP280_FILTER_4X BIT(3) +#define BMP280_FILTER_8X (BIT(3) | BIT(2)) +#define BMP280_FILTER_16X BIT(4) + +#define BMP280_OSRS_HUMIDITY_MASK (BIT(2) | BIT(1) | BIT(0)) +#define BMP280_OSRS_HUMIDITIY_X(osrs_h) ((osrs_h) << 0) +#define BMP280_OSRS_HUMIDITY_SKIP 0 +#define BMP280_OSRS_HUMIDITY_1X BMP280_OSRS_HUMIDITIY_X(1) +#define BMP280_OSRS_HUMIDITY_2X BMP280_OSRS_HUMIDITIY_X(2) +#define BMP280_OSRS_HUMIDITY_4X BMP280_OSRS_HUMIDITIY_X(3) +#define BMP280_OSRS_HUMIDITY_8X BMP280_OSRS_HUMIDITIY_X(4) +#define BMP280_OSRS_HUMIDITY_16X BMP280_OSRS_HUMIDITIY_X(5) + +#define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5)) +#define BMP280_OSRS_TEMP_SKIP 0 +#define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5) +#define BMP280_OSRS_TEMP_1X BMP280_OSRS_TEMP_X(1) +#define BMP280_OSRS_TEMP_2X BMP280_OSRS_TEMP_X(2) +#define BMP280_OSRS_TEMP_4X BMP280_OSRS_TEMP_X(3) +#define BMP280_OSRS_TEMP_8X BMP280_OSRS_TEMP_X(4) +#define BMP280_OSRS_TEMP_16X BMP280_OSRS_TEMP_X(5) + +#define BMP280_OSRS_PRESS_MASK (BIT(4) | BIT(3) | BIT(2)) +#define BMP280_OSRS_PRESS_SKIP 0 +#define BMP280_OSRS_PRESS_X(osrs_p) ((osrs_p) << 2) +#define BMP280_OSRS_PRESS_1X BMP280_OSRS_PRESS_X(1) +#define BMP280_OSRS_PRESS_2X BMP280_OSRS_PRESS_X(2) +#define BMP280_OSRS_PRESS_4X BMP280_OSRS_PRESS_X(3) +#define BMP280_OSRS_PRESS_8X BMP280_OSRS_PRESS_X(4) +#define BMP280_OSRS_PRESS_16X BMP280_OSRS_PRESS_X(5) + +#define BMP280_MODE_MASK (BIT(1) | BIT(0)) +#define BMP280_MODE_SLEEP 0 +#define BMP280_MODE_FORCED BIT(0) +#define BMP280_MODE_NORMAL (BIT(1) | BIT(0)) + +/* BMP180 specific registers */ +#define BMP180_REG_OUT_XLSB 0xF8 +#define BMP180_REG_OUT_LSB 0xF7 +#define BMP180_REG_OUT_MSB 0xF6 + +#define BMP180_REG_CALIB_START 0xAA +#define BMP180_REG_CALIB_COUNT 22 + +#define BMP180_MEAS_SCO BIT(5) +#define BMP180_MEAS_TEMP (0x0E | BMP180_MEAS_SCO) +#define BMP180_MEAS_PRESS_X(oss) ((oss) << 6 | 0x14 | BMP180_MEAS_SCO) +#define BMP180_MEAS_PRESS_1X BMP180_MEAS_PRESS_X(0) +#define BMP180_MEAS_PRESS_2X BMP180_MEAS_PRESS_X(1) +#define BMP180_MEAS_PRESS_4X BMP180_MEAS_PRESS_X(2) +#define BMP180_MEAS_PRESS_8X BMP180_MEAS_PRESS_X(3) + +/* BMP180 and BMP280 common registers */ +#define BMP280_REG_CTRL_MEAS 0xF4 +#define BMP280_REG_RESET 0xE0 +#define BMP280_REG_ID 0xD0 + +#define BMP180_CHIP_ID 0x55 +#define BMP280_CHIP_ID 0x58 +#define BME280_CHIP_ID 0x60 +#define BMP280_SOFT_RESET_VAL 0xB6 + +/* BMP280 register skipped special values */ +#define BMP280_TEMP_SKIPPED 0x80000 +#define BMP280_PRESS_SKIPPED 0x80000 +#define BMP280_HUMIDITY_SKIPPED 0x8000 + +/* + * These enums are used for indexing into the array of compensation + * parameters for BMP280. + */ +enum { T1, T2, T3 }; +enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 }; + +/* + * Returns temperature in DegC, resolution is 0.01 DegC. Output value of + * "5123" equals 51.23 DegC. t_fine carries fine temperature as global + * value. + * + * Taken from datasheet, Section 3.11.3, "Compensation formula". + */ +static s32 bmp_algo_getCTemp(struct bmp_client_data *data, s32 adc_temp) +{ + s32 var1, var2; + struct bmp280_calibration_param_t *calib = &data->device.cal_param; + + var1 = (((adc_temp >> 3) - ((s32)calib->dig_T1 << 1)) * + ((s32)calib->dig_T2)) >> + 11; + var2 = (((((adc_temp >> 4) - ((s32)calib->dig_T1)) * + ((adc_temp >> 4) - ((s32)calib->dig_T1))) >> + 12) * + ((s32)calib->dig_T3)) >> + 14; + calib->t_fine = var1 + var2; + + return (calib->t_fine * 5 + 128) >> 8; +} + +/* + * Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 + * integer bits and 8 fractional bits). Output value of "24674867" + * represents 24674867/256 = 96386.2 Pa = 963.862 hPa + * + * Taken from datasheet, Section 3.11.3, "Compensation formula". + */ +static u32 bmp_algo_getCPressure(struct bmp_client_data *data, s32 adc_press) +{ + s64 var1, var2, p; + struct bmp280_calibration_param_t *calib = &data->device.cal_param; + + if (!data) + return -EIO; + + var1 = ((s64)calib->t_fine) - 128000; + var2 = var1 * var1 * (s64)calib->dig_P6; + var2 += (var1 * (s64)calib->dig_P5) << 17; + var2 += ((s64)calib->dig_P4) << 35; + var1 = ((var1 * var1 * (s64)calib->dig_P3) >> 8) + + ((var1 * (s64)calib->dig_P2) << 12); + var1 = ((((s64)1) << 47) + var1) * ((s64)calib->dig_P1) >> 33; + + if (var1 == 0) + return 0; + + p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125; + p = div64_s64(p, var1); + var1 = (((s64)calib->dig_P9) * (p >> 13) * (p >> 13)) >> 25; + var2 = ((s64)(calib->dig_P8) * p) >> 19; + p = ((p + var1 + var2) >> 8) + (((s64)calib->dig_P7) << 4); + + return (u32)p; +} + +int bmp_algo_calibrate(struct bmp_client_data *data) +{ + int ret; + __le16 t_buf[BMP280_COMP_TEMP_REG_COUNT / 2]; + __le16 p_buf[BMP280_COMP_PRESS_REG_COUNT / 2]; + + if (!data) + return -EIO; + + /* Read temperature calibration values. */ + ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_COMP_TEMP_START, (u8*)t_buf, BMP280_COMP_TEMP_REG_COUNT); + if (ret < 0) { + pr_err("failed to read temperature calibration parameters\n"); + return ret; + } + + /* Toss the temperature calibration data into the entropy pool */ + add_device_randomness(t_buf, sizeof(t_buf)); + + data->device.cal_param.dig_T1 = le16_to_cpu(t_buf[T1]); + data->device.cal_param.dig_T2 = le16_to_cpu(t_buf[T2]); + data->device.cal_param.dig_T3 = le16_to_cpu(t_buf[T3]); + + /* Read pressure calibration values. */ + ret = data->device.bus_read(data->device.dev_addr, + BMP280_REG_COMP_PRESS_START, (u8*)p_buf, + BMP280_COMP_PRESS_REG_COUNT); + if (ret < 0) { + pr_err("failed to read pressure calibration parameters\n"); + return ret; + } + + /* Toss the pressure calibration data into the entropy pool */ + add_device_randomness(p_buf, sizeof(p_buf)); + + data->device.cal_param.dig_P1 = le16_to_cpu(p_buf[P1]); + data->device.cal_param.dig_P2 = le16_to_cpu(p_buf[P2]); + data->device.cal_param.dig_P3 = le16_to_cpu(p_buf[P3]); + data->device.cal_param.dig_P4 = le16_to_cpu(p_buf[P4]); + data->device.cal_param.dig_P5 = le16_to_cpu(p_buf[P5]); + data->device.cal_param.dig_P6 = le16_to_cpu(p_buf[P6]); + data->device.cal_param.dig_P7 = le16_to_cpu(p_buf[P7]); + data->device.cal_param.dig_P8 = le16_to_cpu(p_buf[P8]); + data->device.cal_param.dig_P9 = le16_to_cpu(p_buf[P9]); + + return 0; +} + +int bmp_algo_getTemp(struct bmp_client_data *data, s32 *temp) +{ + int ret; + __be32 tmp = 0; + s32 adc_temp, comp_temp; + + if (!data) + return -EIO; + + ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_TEMP_MSB, + (u8*)&tmp, 3); + if (ret < 0) { + pr_err("failed to read temperature\n"); + return ret; + } + + adc_temp = be32_to_cpu(tmp) >> 12; + if (adc_temp == BMP280_TEMP_SKIPPED) { + /* reading was skipped */ + pr_err("reading temperature skipped\n"); + return -EIO; + } + + comp_temp = bmp_algo_getCTemp(data, adc_temp); + + if (temp) { + *temp = comp_temp; + } + + return 0; +} + +int bmp_algo_getPressure(struct bmp_client_data *data, u32 *pressure) +{ + int ret; + __be32 tmp = 0; + s32 adc_press, comp_press; + + if (!data) + return -EIO; + + /* Read and compensate temperature so we get a reading of t_fine. */ + ret = bmp_algo_getTemp(data, NULL); + if (ret < 0) + return ret; + + ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_PRESS_MSB, (u8*)&tmp, 3); + if (ret < 0) { + pr_err("failed to read pressure\n"); + return ret; + } + + adc_press = be32_to_cpu(tmp) >> 12; + if (adc_press == BMP280_PRESS_SKIPPED) { + /* reading was skipped */ + pr_err("reading pressure skipped\n"); + return -EIO; + } + + comp_press = bmp_algo_getCPressure(data, adc_press); + + if (pressure) { + *pressure = comp_press; + } + + return 0; +} diff --git a/drivers/input/misc/bmp280/bmp280_algo.h b/drivers/input/misc/bmp280/bmp280_algo.h new file mode 100644 index 00000000000..319af6d9cb3 --- /dev/null +++ b/drivers/input/misc/bmp280/bmp280_algo.h @@ -0,0 +1,38 @@ +/* +* Copyright (c) Hammerhead Navigation Inc. 2021 +* All Rights Reserved +*/ + +#ifndef __BMP280_ALGO_H__ +#define __BMP280_ALGO_H__ + +#include "bmp280_core.h" + +/* +* @brief Gather calibration parameters from bmp280 +* @param inout data: pointer to store calibration results +* @retval 0 on success, < 0 on failure. +**/ +int bmp_algo_calibrate(struct bmp_client_data *data); + +/* +* @brief Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 +* integer bits and 8 fractional bits). Output value of "24674867" +* represents 24674867/256 = 96386.2 Pa = 963.862 hPa +* @param in data: Pointer to bmp_client_data structure containing +* @param out pressure: pointer to computed pressure in Q24.8 format +* @retval 0 on success, < 0 on failure. +*/ +int bmp_algo_getPressure(struct bmp_client_data *data, u32* pressure); + +/* +* @brief Returns temperature in DegC, resolution is 0.01 DegC. Output value of +* "5123" equals 51.23 DegC. t_fine carries fine temperature as global +* value. +* @param in data: Pointer to bmp_client_data structure containing +* @param out pressure: pointer to computed temperature +* @retval 0 on success, < 0 on failure. +*/ +int bmp_algo_getTemp(struct bmp_client_data *data, s32* temp); + +#endif // __BMP280_ALGO_H__ \ No newline at end of file diff --git a/drivers/input/misc/bmp280_core.c b/drivers/input/misc/bmp280/bmp280_core.c similarity index 92% rename from drivers/input/misc/bmp280_core.c rename to drivers/input/misc/bmp280/bmp280_core.c index 42e118b5c2e..12067f56bd5 100644 --- a/drivers/input/misc/bmp280_core.c +++ b/drivers/input/misc/bmp280/bmp280_core.c @@ -21,6 +21,11 @@ * V1.4 --- API Update to 2.0 */ +/* +* Copyright (c) Hammerhead Navigation Inc. 2021 +* All Rights Reserved +*/ + #include #include #include @@ -33,6 +38,8 @@ #endif #include #include "bmp280_core.h" +#include "bmp280_sysfs.h" +#include "bmp280_algo.h" /*! @defgroup bmp280_core_src * @brief The core code of BMP280 device driver @@ -72,67 +79,7 @@ /*! selftest success */ #define BMP_SELFTEST_SUCCESS 1 -/*! - * @brief Each client has this additional data, this particular - * data structure is defined for bmp280 client -*/ -struct bmp_client_data { - /*!data bus for hardware communication */ - struct bmp_data_bus data_bus; - /*!device information used by sensor API */ - struct bmp280_t device; - /*!device register to kernel device model */ - struct device *dev; - /*!mutex lock variable */ - struct mutex lock; - - /*!temperature oversampling variable */ - uint8_t oversampling_t; - /*!pressure oversampling variable */ - uint8_t oversampling_p; - /*!indicate operation mode */ - uint8_t op_mode; - /*!indicate filter coefficient */ - uint8_t filter; - /*!indicate standby duration */ - uint32_t standbydur; - /*!indicate work mode */ - uint8_t workmode; - //add by liangdi - struct sensors_classdev cdev; - //add end - //add by huangshifang - struct sensors_classdev temp_cdev; - //add end -#ifdef CONFIG_HAS_EARLYSUSPEND - /*!early suspend variable */ - struct early_suspend early_suspend; -#endif - /*!indicate input device; register to input core in kernel */ - struct input_dev *input; - //add by huangshifang - struct input_dev *input_temp; - //add end - /*!register to work queue */ - struct delayed_work work; - //add by huangshifang - struct delayed_work temp_work; - //add end - /*!delay time used by input event */ - uint32_t delay; - /*!enable/disable sensor output */ - uint32_t enable; - uint32_t temp_enable; - /*! indicate selftest status - * -1: no action - * 0: failed - * 1: success - */ - int8_t selftest; -}; - -//add by liangdi -static struct sensors_classdev press_cdev = { +struct sensors_classdev p_cdev = { .name = "bmp280-pressure", .vendor = "Bosch", .version = 1, @@ -141,18 +88,16 @@ static struct sensors_classdev press_cdev = { .max_range = "1100.0", .resolution = "0.01", .sensor_power = "0.67", - .min_delay = 20000, /* microsecond */ + .min_delay = 20000, /* microsecond */ .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, .enabled = 0, - .delay_msec = 200, /* millisecond */ + .delay_msec = 200, /* millisecond */ .sensors_enable = NULL, .sensors_poll_delay = NULL, }; -//add end -//add by huangshifang -static struct sensors_classdev temper_cdev = { +struct sensors_classdev t_cdev = { .name = "bmp280-temperature", .vendor = "Bosch", .version = 1, @@ -161,15 +106,14 @@ static struct sensors_classdev temper_cdev = { .max_range = "65.0", .resolution = "0.01", .sensor_power = "0.67", - .min_delay = 20000, /* microsecond */ + .min_delay = 20000, /* microsecond */ .fifo_reserved_event_count = 0, .fifo_max_event_count = 0, .enabled = 0, - .delay_msec = 200, /* millisecond */ + .delay_msec = 200, /* millisecond */ .sensors_enable = NULL, .sensors_poll_delay = NULL, }; -//add end #ifdef CONFIG_HAS_EARLYSUSPEND static void bmp_early_suspend(struct early_suspend *h); @@ -1186,78 +1130,6 @@ static ssize_t store_workmode(struct device *dev, return status; } -//add by liangdi -static ssize_t bmp280_enable_set(struct sensors_classdev *sensors_cdev, - unsigned int enable) -{ - struct bmp_client_data *data = container_of(sensors_cdev, - struct bmp_client_data, cdev); - struct device *dev = data->dev; - - enable = enable ? 1 : 0; - mutex_lock(&data->lock); - if (data->enable != enable) { - if (enable) { - #ifdef CONFIG_PM - bmp_enable(dev); - #endif - bmp_set_op_mode(data, \ - BMP_VAL_NAME(NORMAL_MODE)); - schedule_delayed_work(&data->work, - msecs_to_jiffies(data->delay)); - } else{ - cancel_delayed_work_sync(&data->work); - bmp_set_op_mode(data, \ - BMP_VAL_NAME(SLEEP_MODE)); - #ifdef CONFIG_PM - bmp_disable(dev); - #endif - } - data->enable = enable; - } - mutex_unlock(&data->lock); - pr_err("bmp280_enable_set pressure en_state=%d\n",data->enable); - - return 0; -} - -//add end - -//add by huangshifang -static ssize_t bmp280_enable_set_temp(struct sensors_classdev *sensors_cdev, - unsigned int enable) -{ - struct bmp_client_data *data = container_of(sensors_cdev, - struct bmp_client_data, temp_cdev); - struct device *dev = data->dev; - - enable = enable ? 1 : 0; - mutex_lock(&data->lock); - if (data->temp_enable != enable) { - if (enable) { - #ifdef CONFIG_PM - bmp_enable(dev); - #endif - bmp_set_op_mode(data, \ - BMP_VAL_NAME(NORMAL_MODE)); - schedule_delayed_work(&data->temp_work, - msecs_to_jiffies(data->delay)); - } else{ - cancel_delayed_work_sync(&data->temp_work); - bmp_set_op_mode(data, \ - BMP_VAL_NAME(SLEEP_MODE)); - #ifdef CONFIG_PM - bmp_disable(dev); - #endif - } - data->temp_enable = enable; - } - mutex_unlock(&data->lock); - pr_err("bmp280_enable_set temp en_state=%d\n",data->temp_enable); - - return 0; -} -//add end /*! * @brief get sensor work state via sysfs node * @@ -1513,18 +1385,17 @@ static void bmp_work_func(struct work_struct *work) int status; mutex_lock(&client_data->lock); - status = bmp_get_pressure(client_data, &pressure); + status = bmp_algo_getPressure(client_data, &pressure); mutex_unlock(&client_data->lock); if (status == 0) { - //pr_err("bmp280 pressure value :%d Pa\n", pressure); - input_event(client_data->input, EV_ABS, MSC_RAW, pressure); + pr_err("bmp280 pressure value :%d Pa\n", pressure/256); + input_event(client_data->input, EV_ABS, MSC_RAW, pressure/256); input_sync(client_data->input); } schedule_delayed_work(&client_data->work, delay-(jiffies-j1)); } -//add by huangshifang static void bmp_temp_work_func(struct work_struct *work) { struct bmp_client_data *client_data = @@ -1536,80 +1407,16 @@ static void bmp_temp_work_func(struct work_struct *work) int status; mutex_lock(&client_data->lock); - status = bmp_get_temperature(client_data, &temperature); + status = bmp_algo_getTemp(client_data, &temperature); mutex_unlock(&client_data->lock); if (status == 0) { - //pr_err("bmp280 temperature value :%d Pa\n", temperature); + pr_err("bmp280 temperature value :%d hC\n", temperature); input_event(client_data->input_temp, EV_ABS, MSC_RAW, temperature); input_sync(client_data->input_temp); } schedule_delayed_work(&client_data->temp_work, delay-(jiffies-j1)); } -//add end -/*! - * @brief initialize input device - * - * @param data the pointer of bmp client data - * - * @return zero success, non-zero failed - * @retval zero success - * @retval non-zero failed -*/ -static int bmp_input_init(struct bmp_client_data *data) -{ - struct input_dev *dev; - int err; - - dev = input_allocate_device(); - if (!dev) - return -ENOMEM; - dev->name = BMP_PRESS_NAME; - dev->id.bustype = BUS_I2C; - - input_set_capability(dev, EV_ABS, MSC_RAW); - input_set_drvdata(dev, data); - - err = input_register_device(dev); - if (err < 0) { - input_free_device(dev); - return err; - } - data->input = dev; - //add by huangshifang - dev = input_allocate_device(); - if (!dev) - return -ENOMEM; - dev->name = BMP_TEMPER_NAME; - dev->id.bustype = BUS_I2C; - - input_set_capability(dev, EV_ABS, MSC_RAW); - input_set_drvdata(dev, data); - - err = input_register_device(dev); - if (err < 0) { - input_free_device(dev); - return err; - } - data->input_temp = dev; - //add end - return 0; -} - -/*! - * @brief delete input device - * - * @param data the pointer of bmp client data - * - * @return no return value -*/ -static void bmp_input_delete(struct bmp_client_data *data) -{ - struct input_dev *dev = data->input; - - input_unregister_device(dev); - input_free_device(dev); -} /*! * @brief initialize bmp client @@ -1655,6 +1462,74 @@ static int bmp_init_client(struct bmp_client_data *data) return status; } +static ssize_t bmp280_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmp_client_data *data = container_of(sensors_cdev, + struct bmp_client_data, cdev); + struct device *dev = data->dev; + + enable = enable ? 1 : 0; + mutex_lock(&data->lock); + if (data->enable != enable) { + if (enable) { + #ifdef CONFIG_PM + bmp_enable(dev); + #endif + bmp_set_op_mode(data, \ + BMP_VAL_NAME(NORMAL_MODE)); + schedule_delayed_work(&data->work, + msecs_to_jiffies(data->delay)); + } else{ + cancel_delayed_work_sync(&data->work); + bmp_set_op_mode(data, \ + BMP_VAL_NAME(SLEEP_MODE)); + #ifdef CONFIG_PM + bmp_disable(dev); + #endif + } + data->enable = enable; + } + mutex_unlock(&data->lock); + pr_err("bmp280_enable_set pressure en_state=%d\n",data->enable); + + return 0; +} + +static ssize_t bmp280_enable_set_temp(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct bmp_client_data *data = container_of(sensors_cdev, + struct bmp_client_data, temp_cdev); + struct device *dev = data->dev; + + enable = enable ? 1 : 0; + mutex_lock(&data->lock); + if (data->temp_enable != enable) { + if (enable) { + #ifdef CONFIG_PM + bmp_enable(dev); + #endif + bmp_set_op_mode(data, \ + BMP_VAL_NAME(NORMAL_MODE)); + schedule_delayed_work(&data->temp_work, + msecs_to_jiffies(data->delay)); + } else{ + cancel_delayed_work_sync(&data->temp_work); + bmp_set_op_mode(data, \ + BMP_VAL_NAME(SLEEP_MODE)); + #ifdef CONFIG_PM + bmp_disable(dev); + #endif + } + data->temp_enable = enable; + } + mutex_unlock(&data->lock); + pr_err("bmp280_enable_set temp en_state=%d\n",data->temp_enable); + + return 0; +} + /*! * @brief probe bmp sensor * @@ -1670,7 +1545,6 @@ int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus) struct bmp_client_data *data; int err = 0; - if (!dev || !data_bus) { err = -EINVAL; goto exit; @@ -1710,8 +1584,7 @@ int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus) if (err) goto error_sysfs; - //add by liangdi - data->cdev = press_cdev; + data->cdev = p_cdev; data->cdev.sensors_enable = bmp280_enable_set; data->cdev.sensors_poll_delay = bmp280_poll_delay_set; err = sensors_classdev_register(&data->input->dev, &data->cdev); @@ -1719,10 +1592,8 @@ int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus) pr_err("class device create failed: %d\n", err); goto error_class_sysfs; } - //add end - - //add by huangshifang - data->temp_cdev = temper_cdev; + + data->temp_cdev = t_cdev; data->temp_cdev.sensors_enable = bmp280_enable_set_temp; data->temp_cdev.sensors_poll_delay = bmp280_temp_poll_delay_set; err = sensors_classdev_register(&data->input_temp->dev, &data->temp_cdev); @@ -1730,8 +1601,13 @@ int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus) pr_err("class device create failed: %d\n", err); goto error_class_sysfs; } - //add end - + + // Initialize the algo module. + if (bmp_algo_calibrate(data) < 0) { + pr_err("Failed to calibrate bmp device"); + goto error_class_sysfs; + } + /* workqueue init */ INIT_DELAYED_WORK(&data->work, bmp_work_func); //add by huangshifang diff --git a/drivers/input/misc/bmp280/bmp280_core.h b/drivers/input/misc/bmp280/bmp280_core.h new file mode 100644 index 00000000000..d9f7fbe3c86 --- /dev/null +++ b/drivers/input/misc/bmp280/bmp280_core.h @@ -0,0 +1,152 @@ +/*! + * @section LICENSE + * $license$ + * + * @filename $filename$ + * @date $date$ + * @id $id$ + * + * @brief + * The head file of BMP280 device driver core code +*/ + +/* +* Copyright (c) Hammerhead Navigation Inc. 2021 +* All Rights Reserved +*/ + +#ifndef _BMP280_CORE_H +#define _BMP280_CORE_H + +#include "bmp280.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include "bmp280_core.h" +#include "bmp280_sysfs.h" +//#include "bs_log.h" + +/*! @defgroup bmp280_core_inc + * @brief The head file of BMP280 device driver core code + @{*/ +/*! define BMP device name */ +#define BMP_NAME "bmp280" + +//add by huangshifang +#define BMP_PRESS_NAME "bmp280-pressure" +#define BMP_TEMPER_NAME "bmp280-temperature" +//add end +/*! define BMP register name according to API */ +#define BMP_REG_NAME(name) BMP280_##name +/*! define BMP value name according to API */ +#define BMP_VAL_NAME(name) BMP280_##name +/*! define BMP hardware-related function according to API */ +#define BMP_CALL_API(name) bmp280_##name +/*! only for debug */ +/*#define DEBUG_BMP280*/ + +/*! + * @brief bus communication operation +*/ +struct bmp_bus_ops { + /*!write pointer */ + BMP280_WR_FUNC_PTR; + /*!read pointer */ + BMP280_RD_FUNC_PTR; +}; + +/*! + * @brief bus data client +*/ +struct bmp_data_bus { + /*!bus communication operation */ + const struct bmp_bus_ops *bops; + /*!bmp client */ + //void *client; + struct i2c_client *client; + //add by liangdi 20190817 + struct regulator *vdd; + struct regulator *vio; + bool power_enabled; + //add end +}; + +/*! + * @brief Each client has this additional data, this particular + * data structure is defined for bmp280 client +*/ +struct bmp_client_data { + /*!data bus for hardware communication */ + struct bmp_data_bus data_bus; + /*!device information used by sensor API */ + struct bmp280_t device; + /*!device register to kernel device model */ + struct device *dev; + /*!mutex lock variable */ + struct mutex lock; + + /*!temperature oversampling variable */ + uint8_t oversampling_t; + /*!pressure oversampling variable */ + uint8_t oversampling_p; + /*!indicate operation mode */ + uint8_t op_mode; + /*!indicate filter coefficient */ + uint8_t filter; + /*!indicate standby duration */ + uint32_t standbydur; + /*!indicate work mode */ + uint8_t workmode; + //add by liangdi + struct sensors_classdev cdev; + //add end + //add by huangshifang + struct sensors_classdev temp_cdev; + //add end +#ifdef CONFIG_HAS_EARLYSUSPEND + /*!early suspend variable */ + struct early_suspend early_suspend; +#endif + /*!indicate input device; register to input core in kernel */ + struct input_dev *input; + //add by huangshifang + struct input_dev *input_temp; + //add end + /*!register to work queue */ + struct delayed_work work; + //add by huangshifang + struct delayed_work temp_work; + //add end + /*!delay time used by input event */ + uint32_t delay; + /*!enable/disable sensor output */ + uint32_t enable; + uint32_t temp_enable; + /*! indicate selftest status + * -1: no action + * 0: failed + * 1: success + */ + int8_t selftest; +}; + +int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus); +int bmp_remove(struct device *dev); +void bmp_suspend(struct device *dev); +void bmp_resume(struct device *dev); +#ifdef CONFIG_PM +int bmp_enable(struct device *dev); +int bmp_disable(struct device *dev); +#endif + +#endif/*_BMP280_CORE_H*/ +/*@}*/ diff --git a/drivers/input/misc/bmp280_i2c.c b/drivers/input/misc/bmp280/bmp280_i2c.c similarity index 99% rename from drivers/input/misc/bmp280_i2c.c rename to drivers/input/misc/bmp280/bmp280_i2c.c index 49a98079719..7a07a4a3ed3 100644 --- a/drivers/input/misc/bmp280_i2c.c +++ b/drivers/input/misc/bmp280/bmp280_i2c.c @@ -11,6 +11,7 @@ * the driver to I2C core. */ + #include #include #include diff --git a/drivers/input/misc/bmp280_spi.c b/drivers/input/misc/bmp280/bmp280_spi.c similarity index 99% rename from drivers/input/misc/bmp280_spi.c rename to drivers/input/misc/bmp280/bmp280_spi.c index aeb54e1a0ac..47d75caa3b0 100755 --- a/drivers/input/misc/bmp280_spi.c +++ b/drivers/input/misc/bmp280/bmp280_spi.c @@ -11,6 +11,7 @@ * the driver to SPI core. */ + #include #include #include diff --git a/drivers/input/misc/bmp280/bmp280_sysfs.c b/drivers/input/misc/bmp280/bmp280_sysfs.c new file mode 100644 index 00000000000..d09f0c8fa30 --- /dev/null +++ b/drivers/input/misc/bmp280/bmp280_sysfs.c @@ -0,0 +1,93 @@ +/*! + * @section LICENSE + * $license$ + * + * @filename $filename$ + * @date 2014/08/26 + * @id $id$ + * @version 1.4 + * + * @brief + * The core code of BMP280 device driver + * + * @detail + * This file implements the core code of BMP280 device driver, + * which includes hardware related functions, input device register, + * device attribute files, etc. + * This file calls some functions defined in BMP280.c and could be + * called by bmp280_i2c.c and bmp280_spi.c separately. + * REVISION: V1.4 + * HISTORY: V1.3.5 --- Driver code history + * V1.4 --- API Update to 2.0 +*/ + +/* +* Copyright (c) Hammerhead Navigation Inc. 2021 +* All Rights Reserved +*/ + +#include "bmp280_sysfs.h" + +/*! + * @brief initialize input device + * + * @param data the pointer of bmp client data + * + * @return zero success, non-zero failed + * @retval zero success + * @retval non-zero failed +*/ +int bmp_input_init(struct bmp_client_data *data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + dev->name = BMP_PRESS_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, MSC_RAW); + input_set_drvdata(dev, data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + data->input = dev; + //add by huangshifang + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + dev->name = BMP_TEMPER_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_ABS, MSC_RAW); + input_set_drvdata(dev, data); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + data->input_temp = dev; + //add end + return 0; +} + +/*! + * @brief delete input device + * + * @param data the pointer of bmp client data + * + * @return no return value +*/ +void bmp_input_delete(struct bmp_client_data *data) +{ + struct input_dev *dev = data->input; + + input_unregister_device(dev); + input_free_device(dev); +} diff --git a/drivers/input/misc/bmp280/bmp280_sysfs.h b/drivers/input/misc/bmp280/bmp280_sysfs.h new file mode 100644 index 00000000000..a4433205c51 --- /dev/null +++ b/drivers/input/misc/bmp280/bmp280_sysfs.h @@ -0,0 +1,39 @@ +/*! + * @section LICENSE + * $license$ + * + * @filename $filename$ + * @date 2014/08/26 + * @id $id$ + * @version 1.4 + * + * @brief + * The core code of BMP280 device driver + * + * @detail + * This file implements the core code of BMP280 device driver, + * which includes hardware related functions, input device register, + * device attribute files, etc. + * This file calls some functions defined in BMP280.c and could be + * called by bmp280_i2c.c and bmp280_spi.c separately. + * REVISION: V1.4 + * HISTORY: V1.3.5 --- Driver code history + * V1.4 --- API Update to 2.0 +*/ + +/* +* Copyright (c) Hammerhead Navigation Inc. 2021 +* All Rights Reserved +*/ + +#ifndef _BMP280_SYSFS_H__ +#define _BMP280_SYSFS_H__ + +#include "bmp280_core.h" +#include + +struct bmp_client_data; +int bmp_input_init(struct bmp_client_data *data); +void bmp_input_delete(struct bmp_client_data *data); + +#endif // _BMP280_SYSFS_H__ \ No newline at end of file diff --git a/drivers/input/misc/bmp280_core.h b/drivers/input/misc/bmp280_core.h deleted file mode 100644 index ac200b0d3ee..00000000000 --- a/drivers/input/misc/bmp280_core.h +++ /dev/null @@ -1,73 +0,0 @@ -/*! - * @section LICENSE - * $license$ - * - * @filename $filename$ - * @date $date$ - * @id $id$ - * - * @brief - * The head file of BMP280 device driver core code -*/ -#ifndef _BMP280_CORE_H -#define _BMP280_CORE_H - -#include "bmp280.h" -//#include "bs_log.h" - -/*! @defgroup bmp280_core_inc - * @brief The head file of BMP280 device driver core code - @{*/ -/*! define BMP device name */ -#define BMP_NAME "bmp280" - -//add by huangshifang -#define BMP_PRESS_NAME "bmp280-pressure" -#define BMP_TEMPER_NAME "bmp280-temperature" -//add end -/*! define BMP register name according to API */ -#define BMP_REG_NAME(name) BMP280_##name -/*! define BMP value name according to API */ -#define BMP_VAL_NAME(name) BMP280_##name -/*! define BMP hardware-related function according to API */ -#define BMP_CALL_API(name) bmp280_##name -/*! only for debug */ -/*#define DEBUG_BMP280*/ - -/*! - * @brief bus communication operation -*/ -struct bmp_bus_ops { - /*!write pointer */ - BMP280_WR_FUNC_PTR; - /*!read pointer */ - BMP280_RD_FUNC_PTR; -}; - -/*! - * @brief bus data client -*/ -struct bmp_data_bus { - /*!bus communication operation */ - const struct bmp_bus_ops *bops; - /*!bmp client */ - //void *client; - struct i2c_client *client; - //add by liangdi 20190817 - struct regulator *vdd; - struct regulator *vio; - bool power_enabled; - //add end -}; - -int bmp_probe(struct device *dev, struct bmp_data_bus *data_bus); -int bmp_remove(struct device *dev); -void bmp_suspend(struct device *dev); -void bmp_resume(struct device *dev); -#ifdef CONFIG_PM -int bmp_enable(struct device *dev); -int bmp_disable(struct device *dev); -#endif - -#endif/*_BMP280_CORE_H*/ -/*@}*/ -- 2.25.1 From 9a9ecbb8f51f7cc9772e4333beb8c032acbea4a4 Mon Sep 17 00:00:00 2001 From: vipinbb Date: Thu, 3 Mar 2022 09:57:09 -0700 Subject: [PATCH 76/76] kernel/msm-3.18: - update copyright and licensing from BMP280 Change-Id: I9fb39093b633e3ac32770e6c28737a2e3a5d8782 --- drivers/input/misc/bmp280/COPYING | 674 +++++++++++++++++++++++ drivers/input/misc/bmp280/bmp280_algo.c | 331 +++++------ drivers/input/misc/bmp280/bmp280_algo.h | 13 + drivers/input/misc/bmp280/bmp280_core.c | 17 +- drivers/input/misc/bmp280/bmp280_core.h | 16 +- drivers/input/misc/bmp280/bmp280_sysfs.c | 17 +- drivers/input/misc/bmp280/bmp280_sysfs.h | 17 +- 7 files changed, 902 insertions(+), 183 deletions(-) create mode 100644 drivers/input/misc/bmp280/COPYING diff --git a/drivers/input/misc/bmp280/COPYING b/drivers/input/misc/bmp280/COPYING new file mode 100644 index 00000000000..e72bfddabc1 --- /dev/null +++ b/drivers/input/misc/bmp280/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/drivers/input/misc/bmp280/bmp280_algo.c b/drivers/input/misc/bmp280/bmp280_algo.c index 5c5bc5cf635..537911ff940 100644 --- a/drivers/input/misc/bmp280/bmp280_algo.c +++ b/drivers/input/misc/bmp280/bmp280_algo.c @@ -14,28 +14,34 @@ * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf */ -/* -* Copyright (c) Hammerhead Navigation Inc. 2021 -* All Rights Reserved -*/ - - +/////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Hammerhead Navigation Inc. 2022 +// 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. +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////// #include "bmp280_algo.h" #include "bmp280.h" -#include -#include -#include +#include #include +#include +#include #include #include -#include -#include #include #include /* For irq_get_irq_data() */ -#include +#include #include #include +#include +#include /* BMP280 specific registers */ #define BMP280_REG_HUMIDITY_LSB 0xFE @@ -150,22 +156,21 @@ enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 }; * * Taken from datasheet, Section 3.11.3, "Compensation formula". */ -static s32 bmp_algo_getCTemp(struct bmp_client_data *data, s32 adc_temp) -{ - s32 var1, var2; - struct bmp280_calibration_param_t *calib = &data->device.cal_param; - - var1 = (((adc_temp >> 3) - ((s32)calib->dig_T1 << 1)) * - ((s32)calib->dig_T2)) >> - 11; - var2 = (((((adc_temp >> 4) - ((s32)calib->dig_T1)) * - ((adc_temp >> 4) - ((s32)calib->dig_T1))) >> - 12) * - ((s32)calib->dig_T3)) >> - 14; - calib->t_fine = var1 + var2; - - return (calib->t_fine * 5 + 128) >> 8; +static s32 bmp_algo_getCTemp(struct bmp_client_data *data, s32 adc_temp) { + s32 var1, var2; + struct bmp280_calibration_param_t *calib = &data->device.cal_param; + + var1 = + (((adc_temp >> 3) - ((s32)calib->dig_T1 << 1)) * ((s32)calib->dig_T2)) >> + 11; + var2 = (((((adc_temp >> 4) - ((s32)calib->dig_T1)) * + ((adc_temp >> 4) - ((s32)calib->dig_T1))) >> + 12) * + ((s32)calib->dig_T3)) >> + 14; + calib->t_fine = var1 + var2; + + return (calib->t_fine * 5 + 128) >> 8; } /* @@ -175,146 +180,144 @@ static s32 bmp_algo_getCTemp(struct bmp_client_data *data, s32 adc_temp) * * Taken from datasheet, Section 3.11.3, "Compensation formula". */ -static u32 bmp_algo_getCPressure(struct bmp_client_data *data, s32 adc_press) -{ - s64 var1, var2, p; - struct bmp280_calibration_param_t *calib = &data->device.cal_param; - - if (!data) - return -EIO; - - var1 = ((s64)calib->t_fine) - 128000; - var2 = var1 * var1 * (s64)calib->dig_P6; - var2 += (var1 * (s64)calib->dig_P5) << 17; - var2 += ((s64)calib->dig_P4) << 35; - var1 = ((var1 * var1 * (s64)calib->dig_P3) >> 8) + - ((var1 * (s64)calib->dig_P2) << 12); - var1 = ((((s64)1) << 47) + var1) * ((s64)calib->dig_P1) >> 33; - - if (var1 == 0) - return 0; - - p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125; - p = div64_s64(p, var1); - var1 = (((s64)calib->dig_P9) * (p >> 13) * (p >> 13)) >> 25; - var2 = ((s64)(calib->dig_P8) * p) >> 19; - p = ((p + var1 + var2) >> 8) + (((s64)calib->dig_P7) << 4); - - return (u32)p; +static u32 bmp_algo_getCPressure(struct bmp_client_data *data, s32 adc_press) { + s64 var1, var2, p; + struct bmp280_calibration_param_t *calib = &data->device.cal_param; + + if (!data) + return -EIO; + + var1 = ((s64)calib->t_fine) - 128000; + var2 = var1 * var1 * (s64)calib->dig_P6; + var2 += (var1 * (s64)calib->dig_P5) << 17; + var2 += ((s64)calib->dig_P4) << 35; + var1 = ((var1 * var1 * (s64)calib->dig_P3) >> 8) + + ((var1 * (s64)calib->dig_P2) << 12); + var1 = ((((s64)1) << 47) + var1) * ((s64)calib->dig_P1) >> 33; + + if (var1 == 0) + return 0; + + p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125; + p = div64_s64(p, var1); + var1 = (((s64)calib->dig_P9) * (p >> 13) * (p >> 13)) >> 25; + var2 = ((s64)(calib->dig_P8) * p) >> 19; + p = ((p + var1 + var2) >> 8) + (((s64)calib->dig_P7) << 4); + + return (u32)p; } -int bmp_algo_calibrate(struct bmp_client_data *data) -{ - int ret; - __le16 t_buf[BMP280_COMP_TEMP_REG_COUNT / 2]; - __le16 p_buf[BMP280_COMP_PRESS_REG_COUNT / 2]; - - if (!data) - return -EIO; - - /* Read temperature calibration values. */ - ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_COMP_TEMP_START, (u8*)t_buf, BMP280_COMP_TEMP_REG_COUNT); - if (ret < 0) { - pr_err("failed to read temperature calibration parameters\n"); - return ret; - } - - /* Toss the temperature calibration data into the entropy pool */ - add_device_randomness(t_buf, sizeof(t_buf)); - - data->device.cal_param.dig_T1 = le16_to_cpu(t_buf[T1]); - data->device.cal_param.dig_T2 = le16_to_cpu(t_buf[T2]); - data->device.cal_param.dig_T3 = le16_to_cpu(t_buf[T3]); - - /* Read pressure calibration values. */ - ret = data->device.bus_read(data->device.dev_addr, - BMP280_REG_COMP_PRESS_START, (u8*)p_buf, - BMP280_COMP_PRESS_REG_COUNT); - if (ret < 0) { - pr_err("failed to read pressure calibration parameters\n"); - return ret; - } - - /* Toss the pressure calibration data into the entropy pool */ - add_device_randomness(p_buf, sizeof(p_buf)); - - data->device.cal_param.dig_P1 = le16_to_cpu(p_buf[P1]); - data->device.cal_param.dig_P2 = le16_to_cpu(p_buf[P2]); - data->device.cal_param.dig_P3 = le16_to_cpu(p_buf[P3]); - data->device.cal_param.dig_P4 = le16_to_cpu(p_buf[P4]); - data->device.cal_param.dig_P5 = le16_to_cpu(p_buf[P5]); - data->device.cal_param.dig_P6 = le16_to_cpu(p_buf[P6]); - data->device.cal_param.dig_P7 = le16_to_cpu(p_buf[P7]); - data->device.cal_param.dig_P8 = le16_to_cpu(p_buf[P8]); - data->device.cal_param.dig_P9 = le16_to_cpu(p_buf[P9]); - - return 0; +int bmp_algo_calibrate(struct bmp_client_data *data) { + int ret; + __le16 t_buf[BMP280_COMP_TEMP_REG_COUNT / 2]; + __le16 p_buf[BMP280_COMP_PRESS_REG_COUNT / 2]; + + if (!data) + return -EIO; + + /* Read temperature calibration values. */ + ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_COMP_TEMP_START, + (u8 *)t_buf, BMP280_COMP_TEMP_REG_COUNT); + if (ret < 0) { + pr_err("failed to read temperature calibration parameters\n"); + return ret; + } + + /* Toss the temperature calibration data into the entropy pool */ + add_device_randomness(t_buf, sizeof(t_buf)); + + data->device.cal_param.dig_T1 = le16_to_cpu(t_buf[T1]); + data->device.cal_param.dig_T2 = le16_to_cpu(t_buf[T2]); + data->device.cal_param.dig_T3 = le16_to_cpu(t_buf[T3]); + + /* Read pressure calibration values. */ + ret = + data->device.bus_read(data->device.dev_addr, BMP280_REG_COMP_PRESS_START, + (u8 *)p_buf, BMP280_COMP_PRESS_REG_COUNT); + if (ret < 0) { + pr_err("failed to read pressure calibration parameters\n"); + return ret; + } + + /* Toss the pressure calibration data into the entropy pool */ + add_device_randomness(p_buf, sizeof(p_buf)); + + data->device.cal_param.dig_P1 = le16_to_cpu(p_buf[P1]); + data->device.cal_param.dig_P2 = le16_to_cpu(p_buf[P2]); + data->device.cal_param.dig_P3 = le16_to_cpu(p_buf[P3]); + data->device.cal_param.dig_P4 = le16_to_cpu(p_buf[P4]); + data->device.cal_param.dig_P5 = le16_to_cpu(p_buf[P5]); + data->device.cal_param.dig_P6 = le16_to_cpu(p_buf[P6]); + data->device.cal_param.dig_P7 = le16_to_cpu(p_buf[P7]); + data->device.cal_param.dig_P8 = le16_to_cpu(p_buf[P8]); + data->device.cal_param.dig_P9 = le16_to_cpu(p_buf[P9]); + + return 0; } -int bmp_algo_getTemp(struct bmp_client_data *data, s32 *temp) -{ - int ret; - __be32 tmp = 0; - s32 adc_temp, comp_temp; - - if (!data) - return -EIO; - - ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_TEMP_MSB, - (u8*)&tmp, 3); - if (ret < 0) { - pr_err("failed to read temperature\n"); - return ret; - } - - adc_temp = be32_to_cpu(tmp) >> 12; - if (adc_temp == BMP280_TEMP_SKIPPED) { - /* reading was skipped */ - pr_err("reading temperature skipped\n"); - return -EIO; - } - - comp_temp = bmp_algo_getCTemp(data, adc_temp); - - if (temp) { - *temp = comp_temp; - } - - return 0; +int bmp_algo_getTemp(struct bmp_client_data *data, s32 *temp) { + int ret; + __be32 tmp = 0; + s32 adc_temp, comp_temp; + + if (!data) + return -EIO; + + ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_TEMP_MSB, + (u8 *)&tmp, 3); + if (ret < 0) { + pr_err("failed to read temperature\n"); + return ret; + } + + adc_temp = be32_to_cpu(tmp) >> 12; + if (adc_temp == BMP280_TEMP_SKIPPED) { + /* reading was skipped */ + pr_err("reading temperature skipped\n"); + return -EIO; + } + + comp_temp = bmp_algo_getCTemp(data, adc_temp); + + if (temp) { + *temp = comp_temp; + } + + return 0; } -int bmp_algo_getPressure(struct bmp_client_data *data, u32 *pressure) -{ - int ret; - __be32 tmp = 0; - s32 adc_press, comp_press; - - if (!data) - return -EIO; - - /* Read and compensate temperature so we get a reading of t_fine. */ - ret = bmp_algo_getTemp(data, NULL); - if (ret < 0) - return ret; - - ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_PRESS_MSB, (u8*)&tmp, 3); - if (ret < 0) { - pr_err("failed to read pressure\n"); - return ret; - } - - adc_press = be32_to_cpu(tmp) >> 12; - if (adc_press == BMP280_PRESS_SKIPPED) { - /* reading was skipped */ - pr_err("reading pressure skipped\n"); - return -EIO; - } - - comp_press = bmp_algo_getCPressure(data, adc_press); - - if (pressure) { - *pressure = comp_press; - } - - return 0; +int bmp_algo_getPressure(struct bmp_client_data *data, u32 *pressure) { + int ret; + __be32 tmp = 0; + s32 adc_press, comp_press; + + if (!data) + return -EIO; + + /* Read and compensate temperature so we get a reading of t_fine. */ + ret = bmp_algo_getTemp(data, NULL); + if (ret < 0) + return ret; + + ret = data->device.bus_read(data->device.dev_addr, BMP280_REG_PRESS_MSB, + (u8 *)&tmp, 3); + if (ret < 0) { + pr_err("failed to read pressure\n"); + return ret; + } + + adc_press = be32_to_cpu(tmp) >> 12; + if (adc_press == BMP280_PRESS_SKIPPED) { + /* reading was skipped */ + pr_err("reading pressure skipped\n"); + return -EIO; + } + + comp_press = bmp_algo_getCPressure(data, adc_press); + + if (pressure) { + *pressure = comp_press; + } + + return 0; } diff --git a/drivers/input/misc/bmp280/bmp280_algo.h b/drivers/input/misc/bmp280/bmp280_algo.h index 319af6d9cb3..6f09b871722 100644 --- a/drivers/input/misc/bmp280/bmp280_algo.h +++ b/drivers/input/misc/bmp280/bmp280_algo.h @@ -3,6 +3,19 @@ * All Rights Reserved */ +/////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Hammerhead Navigation Inc. 2022 +// 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. +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////// + #ifndef __BMP280_ALGO_H__ #define __BMP280_ALGO_H__ diff --git a/drivers/input/misc/bmp280/bmp280_core.c b/drivers/input/misc/bmp280/bmp280_core.c index 12067f56bd5..ef75ae8c70c 100644 --- a/drivers/input/misc/bmp280/bmp280_core.c +++ b/drivers/input/misc/bmp280/bmp280_core.c @@ -20,11 +20,18 @@ * HISTORY: V1.3.5 --- Driver code history * V1.4 --- API Update to 2.0 */ - -/* -* Copyright (c) Hammerhead Navigation Inc. 2021 -* All Rights Reserved -*/ +/////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Hammerhead Navigation Inc. 2022 +// 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. +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////// #include #include diff --git a/drivers/input/misc/bmp280/bmp280_core.h b/drivers/input/misc/bmp280/bmp280_core.h index d9f7fbe3c86..b146c5cdccb 100644 --- a/drivers/input/misc/bmp280/bmp280_core.h +++ b/drivers/input/misc/bmp280/bmp280_core.h @@ -10,10 +10,18 @@ * The head file of BMP280 device driver core code */ -/* -* Copyright (c) Hammerhead Navigation Inc. 2021 -* All Rights Reserved -*/ +/////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Hammerhead Navigation Inc. 2022 +// 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. +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////// #ifndef _BMP280_CORE_H #define _BMP280_CORE_H diff --git a/drivers/input/misc/bmp280/bmp280_sysfs.c b/drivers/input/misc/bmp280/bmp280_sysfs.c index d09f0c8fa30..08a106801c1 100644 --- a/drivers/input/misc/bmp280/bmp280_sysfs.c +++ b/drivers/input/misc/bmp280/bmp280_sysfs.c @@ -20,11 +20,18 @@ * HISTORY: V1.3.5 --- Driver code history * V1.4 --- API Update to 2.0 */ - -/* -* Copyright (c) Hammerhead Navigation Inc. 2021 -* All Rights Reserved -*/ +/////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Hammerhead Navigation Inc. 2022 +// 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. +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////// #include "bmp280_sysfs.h" diff --git a/drivers/input/misc/bmp280/bmp280_sysfs.h b/drivers/input/misc/bmp280/bmp280_sysfs.h index a4433205c51..6d35bd0bfcf 100644 --- a/drivers/input/misc/bmp280/bmp280_sysfs.h +++ b/drivers/input/misc/bmp280/bmp280_sysfs.h @@ -20,11 +20,18 @@ * HISTORY: V1.3.5 --- Driver code history * V1.4 --- API Update to 2.0 */ - -/* -* Copyright (c) Hammerhead Navigation Inc. 2021 -* All Rights Reserved -*/ +/////////////////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Hammerhead Navigation Inc. 2022 +// 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. +// You should have received a copy of the GNU General Public License along with +// this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////// #ifndef _BMP280_SYSFS_H__ #define _BMP280_SYSFS_H__ -- 2.25.1